lab5实验报告
一、实验思考题
Thinking 5.1
查阅资料,了解 Linux/Unix 的 /proc 文件系统是什么?有什么作用? Windows 操作系统又是如何实现这些功能的?proc 文件系统这样的设计有什么好处和可以改进的地方?
- Linux系统上的/proc目录是一种文件系统,即proc文件系统。与其它常见的文件系统不同的是,/proc是一种伪文件系统(也即虚拟文件系统)。
- /proc存储的是当前内核运行状态的一系列特殊文件,用户可以通过这些文件查看有关系统硬件及当前正在运行进程的信息,甚至可以通过更改其中某些文件来改变内核的运行状态。
- Windows系统通过
Win32 API
的函数调用来实现这些功能。 - 这样的设计将对内核信息的访问交互抽象成了对文件的访问修改,简化了交互过程。缺点在于其长期驻留内存,占据内存空间。
Thinking 5.2
如果我们通过 kseg0 读写设备,我们对于设备的写入会缓存到 Cache 中。通过 kseg0 访问设备是一种错误的行为,在实际编写代码的时候这么做会引发不可预知的问题。请你思考:这么做这会引起什么问题?对于不同种类的设备(如我们提到的串口设备和 IDE 磁盘)的操作会有差异吗?可以从缓存的性质和缓存刷新的策略来考虑。
- 缓存内存中映射的外部设备内容时,可能外部设备更新后对内存进行了更新,但已经被缓存的部分没有被更新。
- 这种错误对于磁盘概率较小,串口设备则很容易出现。
Thinking 5.3
一个磁盘块最多存储 1024 个指向其他磁盘块的指针,试计算我们的文件系统支持的单个文件的最大大小为多大?
- 4KB * 1024 = 4MB
Thinking 5.4
查找代码中的相关定义,试回答一个磁盘块中最多能存储多少个文件控制块?一个目录下最多能有多少个文件?
- 一个磁盘块4KB,一个文件控制块256B,一个磁盘块中最多能够存储4KB / 256B = 16个文件控制块。
- 一个目录最多能够指向1024个磁盘块,每个磁盘块能够存储16个文件控制块,一个目录下最多能够有1024 * 16 = 16K个文件。
Thinking 5.5
请思考,在满足磁盘块缓存的设计的前提下,我们实验使用的内核支持的最大磁盘大小是多少?
- 最大磁盘大小为
DISKMAX
= 0x40000000,即1GB。
Thinking 5.6
如果将 DISKMAX 改成 0xC0000000, 超过用户空间,我们的文件系统还能正常工作吗?为什么?
- 不能正常工作
- 因为可能出现写磁盘块时覆盖掉内核的内容的情况,导致操作系统运行异常。
Thinking 5.7
阅读 user/file.c,思考文件描述符和打开的文件分别映射到了内存的哪一段空间。
-
文件描述符被
fd_alloc
函数映射到FDTABLE
与FILEBASE
之间的空间内。 -
文件描述符与打开的文件保存在同一个
Filefd
当中,位于文件描述符所在的页面。// file descriptor + file struct Filefd { struct Fd f_fd; u_int f_fileid; struct File f_file; };
Thinking 5.8
阅读 user/file.c,你会发现很多函数中都会将一个 struct Fd* 型的 指针转换为 struct Filefd* 型的指针,请解释为什么这样的转换可行。
-
Filefd
结构体中第一个元素就是一个Fd
结构体,所以做这样的强制转换,就相当于对一个Filefd
里面的Fd
进行赋值。 -
按照C语言的内存分配,只要能够从指针指向的地址取出合法的元素,就可以进行强制类型转换。
// file descriptor + file struct Filefd { struct Fd f_fd; u_int f_fileid; struct File f_file; };
Thinking 5.9
请解释 Fd, Filefd, Open 结构体及其各个域的作用。比如各个结构体会在哪些过程中被使用,是否对应磁盘上的物理实体还是单纯的内存数据等。说明形式自定,要求简洁明了,可大致勾勒出文件系统数据结构与物理实体的对应关系与设计框架。
-
Fd
结构体// file descriptor struct Fd { //文件描述符,用来描述一个文件的基本信息,独占一页 u_int fd_dev_id; //外设id,表明外设类型 u_int fd_offset; //表示读或者写文件的时候,距离文件开头的偏移量 u_int fd_omode; //描述文件打开的读写模式,如只读,只写,读写 };
-
Filefd
结构体// file descriptor + file struct Filefd { //描述一个文件的详细信息,位置就在Fd独占的一页 struct Fd f_fd; //文件描述符 u_int f_fileid; //文件的id struct File f_file; //对应文件的文件控制块 };
-
Open
结构体struct Open { struct File *o_file; //指向该文件的文件控制块的指针 u_int o_fileid; //文件的id int o_mode; //描述文件打开的读写模式,如只读,只写,读写 struct Filefd *o_ff; //打开位置的偏移量 };
Thinking 5.10
阅读serv.c/serve函数的代码,我们注意到函数中包含了一个死循环for (;