ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

BUAA OS Lab5-2分析

2022-06-07 10:34:52  阅读:162  来源: 互联网

标签:文件 Lab5 BUAA dev file 进程 OS Block


BUAA OS Lab5-2分析

前言

说实话,当我做完Lab5-1,我以为Lab5仅仅如此,后面又看到Lab5-2的指导书部分内容比较少,使我更坚信了Lab5是一个轻松的Lab,然而当我读完指导书,对后面几个exercise无从入手时,我才知道我错了。。。

Lab5的代码填写量非常少,但是需要自己阅读数量巨大的代码,同时还要理解各个文件的关系。我尝试着梳理了一下Lab5中几个文件和主要函数的调用关系,尽量从一个比较宏观的视角来看待整个文件系统,希望能够对大家理解Lab5有帮助。

当然,其中很多内容仅仅是基于我自己的理解,可能有错误之处,希望能够谅解并指正!

一、总览

我们实现的文件系统主要由三部分组成:用户进程部分user、服务进程部分serv、底层部分fs。这些部分之间具有明显的抽象层次,每一部分都是对较低一个部分的抽象和封装。其中,用户进程部分是最高级的抽象。每个部分由于其抽象程度不同,文件的抽象形式也不同,因此需要比较清楚地理解文件在各个部分的抽象形式。我们从高级抽象一步步向下展开。

(一)用户进程 user

用户进程部分封装了一系列常见的操作文件的接口(user/fd.c 和部分user/file.c),如open、close、read、write、seek等,这些是最高级的抽象。实际上,这些操作的对象都是文件描述符,因为在用户进程中,文件的抽象形式就是文件描述符Fd。这些顶级抽象接口需要依赖低级一些的抽象(user/file.c),因为他们会调到对应的文件控制符Fd中的dev_id的dev的对应函数,在文件系统中也就是file_close、file_write等等。

需要注意的是,该部分文件的抽象形式就是文件描述符Fd,因此内存空间中有专门的地址存放文件描述符,也就是FDTABLE,这里可以看成一个数组,每个Fd占一个Page大小,可以直接用fdnum作为下标获得;此外,文件的具体数据存在FILEBASE部分的内存空间,每个文件的数据最多占PDMAP大小,也可以实现fdnum到文件数据的一一映射(FILEBASE + PDMAP * fdnum)。

struct Fd {
    u_int fd_dev_id;
    u_int fd_offset; // 定位指针
    u_int fd_omode; // 打开形式
};

struct Dev devfile = {
    .dev_id =   'f',
    .dev_name = "file",
    .dev_read = file_read,
    .dev_write =    file_write,
    .dev_close =    file_close,
    .dev_stat = file_stat,
};

而这些file_xxx中,file_open和file_close需要涉及到和文件服务进程的交互。因为当打开一个文件时,需要从服务进程中读取相应的文件描述符到用户空间,此时要调用fsipc_open;而当file_close时,需要fsipc_close来写回服务进程和磁盘。当然在其他的file_xxx,如file_remove,file_sync中,由于这些函数直接涉及了文件内容的修改,因此需要写回,从而同样要调用fsipc_xxx来与服务进程交互。

那么,fsipc_xxx又干什么呢?fsipc_xxx其实就是找到相应的文件描述符Fd(毕竟这时还在用户进程中),然后构造相应类别的请求req,再通过ipc将该req发送给服务进程(其实就是把req的页面共享给服务进程),最后通过ipc_recv从服务进程中收到相应的结果,以及一些额外的页面映射,如对于fsipc_open,会将服务进程中的文件描述符共享映射给用户空间的文件描述符;fsipc_map则会将服务进程中相应的Block映射给用户进程。

此外,虽然文件的抽象形式是Fd,但是在与serve交互时,会把整个Filefd映射过来,因此可以直接用一个Filefd的指针指过去,从而获取更多Filefd的信息。

(二)服务进程 serve

首先我们需要明确,文件在服务进程抽象存在形式是Open,其中有一个Filefd的指针,也存储了文件的相关信息。而在fs/serv.c中,有一个Open的数组opentable,这正是服务进程中的关键。

其次需要明确,文件的数据在服务进程中是以块缓存的形式存储的(也就是Block和va的映射)。

struct Open {
    struct File *o_file;    // 对应的文件控制块
    u_int o_fileid;     // 文件id(可以看做当前打开的文件,每个都有个id)
    int o_mode;     // 打开形式
    struct Filefd *o_ff;    // Filefd
};
struct Filefd {
    struct Fd f_fd; // 文件描述符
    u_int f_fileid; // 文件id(同上)
    struct File f_file; // 文件控制块
};
struct Fd {
    u_int fd_dev_id;
    u_int fd_offset; // 定位指针
    u_int fd_omode; // 打开形式
};

[lab5-快缓存示意图]

服务进程中除了对Open最基本的操作,如open_alloc和open_lookup外,最主要的部分就是各个serve_xxx函数。这些正是接收到用户进程请求时需要进行的操作。serve_xxx首先是从请求req中提取有关信息,如fileid等,从而找到对应的Open(如果是serve_open则是分配Open)。找到对应的Open,就相当于找到了服务进程中对应的文件,这时候就可以调用底层的函数(fs/fs.c)中来把相应的Block从磁盘读入服务进程的内存空间中(也就是上图的内存分布)或对相应的Block进行操作。

(三)底层部分 fs

上面我们提到,服务进程需要通过调用底层函数来操作文件对应的Block。而在fs/fs.c中,也就是本文说的底层部分,这里封装了许多可以直接根据文件修改对应的Block的函数,如file_get_block、file_flush、file_set_size等,这些使得我们可以很方便地迅速获得文件的某一Block,或直接对该文件的Block进行操作,以及和磁盘的交互(如磁盘的读取与回写)。

在这一部分,文件的抽象形式是文件控制块File,文件数据则是存在Block中。

需要注意的是,这部分其实也属于文件系统的服务进程,只是在抽象层面上划分开了,因此这部分实现的Block的读入等同样修改的是服务进程的内存空间。

二、函数关系

lab5涉及到的函数数量巨大,这里只给出部分主要函数之间的调用关系以及对应的功能。从整个文件系统的更高层面上看待这些函数之间的协作、封装,可以避免纠结于某个文件或者某个函数。或许先从宏观上了解了整个结构,再去了解具体的细节实现,能够更好地理解文件系统。

当然,如果要深入理解每个函数的功能,还是需要好好读代码的(尽管一下子读这么多代码确实挺恶心的

(该图的结构参考了博客:https://hyggge.github.io/2022/05/30/OS-Lab5函数解读/)

其中,箭头上的注释主要表示调用这个函数的主要作用是什么,或许可以对理解函数的功能起到一定帮助。

标签:文件,Lab5,BUAA,dev,file,进程,OS,Block
来源: https://www.cnblogs.com/Charles-Booomb/p/16350857.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有