OS_lab5
思考题
Thinking 5.1
如果通过 kseg0 读写设备,那么对于设备的写入会缓存到 Cache 中。这是 一种错误的行为,在实际编写代码的时候这么做会引发不可预知的问题。请思考:这么做 这会引发什么问题?对于不同种类的设备(如我们提到的串口设备和IDE磁盘)的操作会 有差异吗?可以从缓存的性质和缓存更新的策略来考虑。
- 当外部设备产生中断信号或者更新数据时,此时Cache中之前旧的数据可能刚完成缓存,那么完成缓存的这一部分无法完成更新,则会发生错误的行为。
- 对于串口设备来说,读写频繁,信号多,在相同的时间内发生错误的概论远高于IDE磁盘。
Thinking 5.2
查找代码中的相关定义,试回答一个磁盘块中最多能存储多少个文件控制块?一个目录下最多能有多少个文件?我们的文件系统支持的单个文件最大为多大?
在user/include/fs.h中,有如下定义
1 |
从宏定义可以看出:磁盘块的大小和页大小一样,都是4KB;文件控制块的大小 FILE_STRUCT_SIZE 是256B;故==⼀个磁盘块最多能存储 4K / 256 = 16 个⽂件控制块==
目录文件也是一种文件,会对应一个文件控制块,这一个文件控制块会占用一个磁盘块,那么作为目录的文件控制块最多拥有 BLOCK_SIZE / 4 = 1024个指向磁盘块的指针,也就是管理1024个磁盘的空间;而每个磁盘最多可以存储 16 个文件控制块,则==一个目录最多可以容纳 1024 * 16 = 16K个文件==
单个文件最大与上述分析同理,一个文件控制块最多管理1024个磁盘,如果全部用于存储文件内容的话,文件的大小为:1024 * BLOCK_SIZE = 4M ,即==单个文件最大为4M==
Thinking 5.3
请思考,在满足磁盘块缓存的设计的前提下,我们实验使用的内核支持的最大磁盘大小是多少?
实验使用的内核将将 DISKMAP ~ DISKMAP+DISKMAX 这一段虚存地址空间作为缓冲区,缓冲区大小为DISKMAX,因此最⼤磁盘⼤⼩为 DISKMAX = 0x40000000 ,即 ==1GB== 。
Thinking 5.4
在本实验中,fs/serv.h、user/include/fs.h 等文件中出现了许多宏定义, 试列举你认为较为重要的宏定义,同时进行解释,并描述其主要应用之处。
#define BLOCK_SIZE PAGE_SIZE
磁盘块大小 4096B
#define NDIRECT 10
直接索引磁盘块的数量 10
#define NINDIRECT (BLOCK_SIZE / 4)
间接索引磁盘块的数量 1024
#define FILE_STRUCT_SIZE 256
文件控制块大小 256
#define FILE2BLK (BLOCK_SIZE / sizeof(struct File))
Thinking 5.5
在Lab4“系统调用与fork”的实验中我们实现了极为重要的fork函数。那 么fork前后的父子进程是否会共享文件描述符和定位指针呢?请在完成上述练习的基础上 编写一个程序进行验证。
会共享文件描述符和定位指针
验证程序:
1 |
|
输出结果
1 | main.c: main is start ... |
Thinking 5.6
请解释File,Fd,Filefd结构体及其各个域的作用。比如各个结构体会在哪些过程中被使用,是否对应磁盘上的物理实体还是单纯的内存数据等。说明形式自定,要求简洁明了,可大致勾勒出文件系统数据结构与物理实体的对应关系与设计框架。
File 文件
1 | // user/include/fs.h 中 |
用处:作为文件控制块,记录的文件的信息
对应了磁盘的物理实体
Fd 文件描述符
1 | // user/include/fd.h 中 |
用处:用于存储文件的基本信息和用户进程中关于文件的状态
不对应物理实体,是单纯的内存数据
FileFd 文件+描述符
1 | // file descriptor + file |
对应了磁盘的物理实体,也包含内存数据
Thinking 5.7
图 5.9 中有多种不同形式的箭头,请解释这些不同箭头的差别,并思考我们的操作系统是如何实现对应类型的进程间通信的。

起点为圆点的实线箭头表示进程创建;起点没有点的实线箭头表示用户进程向文件系统服务进程发送信息,虚线箭头表示文件服务进程向用户进程发送信息
- ENV_CREATE(user_env)和ENV_CREATE(fs_serv)都是异步消息,由init()发出创建消息后,init()函数即可返回执行后续步骤,由fs和user线程执行自己的初始化工作。
- fs线程初始化serv_init()和fs_init()完成后,进入serv()函数,被ipc_receive()阻塞为ENV_NOT_RUNNABLE,直到收到User线程的ipc_send(fsreq)被唤醒。
- User线程向fs线程ipc_send(fsreq)发送请求为同步消息,发送后自身进入阻塞ENV_NOT_RUNNABLE等待被唤醒的fs线程服务结束时ipc_send(dst_va),用户线程接收到数据后继续运行,此后fs线程进入阻塞,等待下次被用户唤醒。
实验难点
磁盘空间

结构整理
File相关见上方思考题
Open
1 | // user/fs/serv.c |
实验心得
虽然课下实现的代码量减小了,但是要理解整个文件系统要阅读的代码量真的很大 x
磁盘的引入也让我重新审视了自己对内存空间的理解,文件系统服务进程和用户进程之间的ipc通信也让我更加深入的理解了ipc的机制
爆夸指导书绘图,拯救了我糊糊的层次结构理解
不过如果能对课下以外的代码多加入一些讲解就好了