Lab5实验报告
一、思考题
Thinking 5.1
查阅资料,了解 Linux/Unix 的 /proc 文件系统是什么?有什么作用? Windows 操作系统又是如何实现这些功能的?proc 文件系统这样的设计有什么好处和可以改进的地方?
/proc
文件系统是一个虚拟文件系统,它只存在内存当中,而不占用外存空间。
Linux
内核提供了一种通过/proc
文件系统,在运行时访问内核内部数据结构、改变内核设置的机制。用户和应用程序可以通过/proc
得到系统的信息,并可以改变内核的某些参数。由于系统的信息,如进程,是动态改变的,所以用户或应用程序读取proc
文件时,proc
文件系统是动态从系统内核读出所需信息并提交的。(参考网上资料)
在windows
系统中是通过Win32 API
函数的调用完成与内核的交互的。
/proc
文件系统的设计将对内核信息的访问交互抽象为对文件的访问修改,简化了交互过程。
Thinking 5.2
如果我们通过 kseg0 读写设备,我们对于设备的写入会缓存到 Cache 中。通过 kseg0 访问设备是一种错误的行为,在实际编写代码的时候这么做会引发不可预知的问题。请你思考:这么做这会引起什么问题?对于不同种类的设备(如我们提到的串口设备和 IDE 磁盘)的操作会有差异吗?可以从缓存的性质和缓存刷新的策略来考虑。
可能会导致访问错误。kseg0
是存放内核的区域,通过cache
访问,但是如果在写入设备时将写入缓存到cache
,就会导致想访问内核时,错误的访问cache
中写入的内容。
对不同种类的设备的操作会有差异。比如串口相对于IDE
磁盘速度会更快,所以操作串口时要提高刷新的频率。而IDE
涉及到多个线路的数据冲突问题,操作会更为复杂。
Thinking 5.3
比较 MOS 操作系统的文件控制块和 Unix/Linux 操作系统的 inode 及相关概念,试述二者的不同之处。
MOS
操作系统的文件控制块是将文件名和文件物理地址一同放入文件控制块中。
Unix/Linux
操作系统的inode
是索引节点,用来存放档案及目录的基本信息,为了提高索引的速度,Unix/Linux
只将文件名与指向inode
的指针放入目录项里面,但是文件的物理地址 放在了inode
里,这一点和MOS
操作系统有差别。
Thinking 5.4
查找代码中的相关定义,试回答一个磁盘块中最多能存储多少个文件控制块?一个目录下最多能有多少个文件?我们的文件系统支持的单个文件最大为多大?
一个磁盘块中最多能存储16
个文件控制块。
一个目录下最多能有1024*16=16384
个文件。
我们的文件系统支持的单个文件最大为1024*4KB = 4MB
。
Thinking 5.5
请思考,在满足磁盘块缓存的设计的前提下,我们实验使用的内核支持的最大磁盘大小是多少?
最大磁盘大小是0x6f3fd000
Thinking 5.6
如果将 DISKMAX 改成 0xC0000000, 超过用户空间,我们的文件系统还能正常工作吗?为什么?
不能正常工作。
因为这样的话会导致缓存磁盘块将内核的内容覆盖掉,从而导致异常,文件系统就无法正常工作。
Thinking 5.7
在 lab5 中,fs/fs.h、include/fs.h 等文件中出现了许多结构体和宏定 义,写出你认为比较重要或难以理解的部分,并进行解释。
我认为比较难理解的部分主要是几个宏定义部分,如下:
#define BY2BLK BY2PG //相当于一个磁盘块的大小,在大小上等于一页的大小
#define BIT2BLK (BY2BLK*8) //将单位从字节转化为位,因为位图法记录一个磁盘块是否被被分配出去只需要1位
#define BY2FILE 256 //记录一个文件控制块的大小
#define FILE2BLK (BY2BLK/sizeof(struct File)) //记录一个磁盘块能存放的文件控制块的个数,当需要遍历磁盘块中的所有文件时使用它
Thinking 5.8
阅读 user/file.c,你会发现很多函数中都会将一个 struct Fd* 型的 指针转换为 struct Filefd* 型的指针,请解释为什么这样的转换可行。
可以观察得出,两个结构体的定义如下:
第一个是:
struct Fd {
u_int fd_dev_id;
u_int fd_offset;
u_int fd_omode;
};
第二个是:
struct Fd {
u_int fd_dev_id;
u_int fd_offset;
u_int fd_omode;
};
由以上对比可以看出,Filefd结构体的第一个成员就是Fd,所以经过强制转换之后,指向Filefd的指针同样指向Fd的起始位置,并没有造成错误,所以转换可行。
Thinking 5.9
在lab4 的实验中我们实现了极为重要的fork 函数。那么fork 前后的父子进程是否会共享文件描述符和定位指针呢?请在完成练习5.8和5.9的基础上编写一个程序进行验证。
部分关键测试程序如下:
//省略若干宏定义
int main(void) {
int fd = open("./test.cap", O_RDWR);
if(-1 == fd) {
printf("file openerror\n");
return -1;
}
pid_t pid;
if((pid = fork()) < 0) {
printf("fork error");
}else if(pid == 0) {
printf("child\n");
printFdInfo(fd);
printf("chiled seek %d\n", lseek(fd, 3, SEEK_CUR));
printf("child\n");
}else {
sleep(2);
printf("child\n");
printFdInfo(fd);
printf("parent seek cur %d\n", lseek(fd, 0, SEEK_CUR));
printf("child\n");
}
return 0;
}
//省略printFdInfo函数,主要用于判断作用
Thinking 5.10
请解释Fd, Filefd, Open 结构体及其各个域的作用。比如各个结构体会在哪些过程中被使用,是否对应磁盘上的物理实体还是单纯的内存数据等。说明形式自定,要求简洁明了,可大致勾勒出文件系统数据结构与物理实体的对应关系与设计框架。
Fd
结构体如下:
struct Fd {
u_int fd_dev_id;
u_int fd_offset;
u_int fd_omode;
};
其中Fd用于记录文件的基本信息。其中的定义fd_dev_id
指的是外设的id
,fd_offset
指的是读写的偏移量,fd_omode
指的是打开方式,包括只读、只写、读写等在内。
FileFd
的结构体如下:
struct Filefd {
struct Fd f_fd;
u_int f_fileid;
struct File f_file;
};
其中FileFd用于记录文件的详细信息。其中的f_fd
指的是file descriptor
,f_fileid
指的是文件的id
,f_file
指的是真正的文件本身。
Open
的结构体如下:
struct Open {
struct File *o_file;
u_int o_fileid;
int o_mode;
struct Filefd *o_ff;
};
其中Open
结构体是打开文件行为的抽象。其中的o_file
指的是打开的文件的指针,o_fileid
指的是打开的文件的id
,o_mode
指的是打开方式,o_ff
指的是指向读写位置的指针。
Thinking 5.11
UML时序图中有多种不同形式的箭头,请结合UML 时序图的规范,解释这些不同箭头的差别,并思考我们的操作系统是如何实现对应类型的进程间通信的。
黑三角箭头搭配黑实线表示的是同步消息,是消息的发送者把进程控制传递给消息的接收者,然后暂停活动等待回应;
两条小线的开箭头和黑色实线表示的是异步消息,不需要等待;
开三角箭头搭配黑色虚线表示的是返回消息,与同步消息结合使用的;
用开三角箭头搭配黑实线表示的是创建消息,其下面特别注明create
;
用黑三角箭头搭配黑实线表示的是摧毁消息,其下面特别注明destroy
;
操作系统利用env_ipc_recving
实现进程的同步。
Thinking 5.12
阅读serv.c/serve函数的代码,我们注意到函数中包含了一个死循环for (; ; ) {…},为什么这段代码不会导致整个内核进入panic 状态?
serve
在调用ipc_recv
函数之后会将自身状态变为ENV_NOT_RUNNABLE
,从而进入等待状态,它像一个后台程序,在其他进程发出文件系统请求后才被唤醒并开始服务,因此这段代码不会导致整个内核进入panic
状态。
二、实验难点图示
文件系统层次关系
文件系统之间的逐级调用在我看来是比较难得一个地方:
文件系统有四个层次:用户接口,抽象层,具体实现,设备接口。
IDE磁盘驱动
关于驱动程序的编写需要知道我们都需要进行哪些操作:
文件系统用户接口
文件系统的用户请求IPC主要有以下几种:
#define FSREQ_OPEN 1
#define FSREQ_MAP 2
#define FSREQ_SET_SIZE 3
#define FSREQ_CLOSE 4
#define FSREQ_DIRTY 5
#define FSREQ_REMOVE 6
#define FSREQ_SYNC 7
操作如下:
三、体会与感想
lab5难度上比起lab4感觉小了一点,但是难度还是有的,代码量也比较大,总花费了两三天的时间。但是说实话lab5实验做到了十五周,感觉还是时间挺紧张的,毕竟最近一直在复习理论,所以实验也没有敢给太多的时间,这次的实验报告写的也比较草,因为时间真的不够了……
不过lab5的两次上机都还算有惊无险地过了,因为lab2挂的太惨了,所以导致最后离申优线还是有一定的差距,不过也不算遗憾啦,经过一学期的os学习,尤其是实验部分的学习,感觉自己代码水平相比大一时已经有了很大的进步了。
OS实验上机到此就圆满结束了,前期过的很艰难,但还好自己没有放弃,后来慢慢找到感觉了,写的也顺利了起来,之后还有lab6的部分,希望等到自己考完其他学科的考试再慢慢完成吧,很感谢助教gg们细心的指导与帮助,也很感谢身边一起分享bug的同学,6系是个很温暖的大家庭。