BUAA OS——Lab5实验报告

lab5实验报告

思考题

5.1 查阅资料,了解 Linux/Unix 的 /proc 文件系统是什么?有什么作用?Windows 操作系统又是如何实现这些功能的?proc 文件系统的设计有哪些好处和不足?

与其它常见的文件系统不同的是,/proc是一种伪文件系统(也即虚拟文件系统)。

存储的是当前内核运行状态的一系列特殊文件,用户可以通过这些文件查看有关系统硬件及当前正在运行进程的信息,甚至可以通过更改其中某些文件来改变内核的运行状态。

Windows通过提供相关的系统调用改变内核运行状态和查看进程信息。

好处:对系统调用进行了更多的抽象,并将其整合到了文件操作上,降低操作的复杂度。

缺点:需要在内存中实现,占用内存空间。

5.2 如果通过kseg0读写设备,那么对于设备的写入会缓存到Cache中。 通过kseg0访问设备是一种错误的行为,在实际编写代码的时候这么做会引发不可 预知的问题。请思考:这么做这会引发什么问题?对于不同种类的设备(如我们提到的串口设备和IDE磁盘)的操作会有差异吗?可以从缓存的性质和缓存更新的策略来考虑。

当外部设备产生中断信号或者更新数据时,此时Cache中之前旧的数据可能刚完成缓存,那么完成缓存的这一部分无法完成更新,则会发生错误的行为。

对于串口设备来说,读写频繁,信号多,在相同的时间内发生错误的概论远高于IDE磁盘。

5.3 一个磁盘块最多存储 1024 个指向其他磁盘块的指针,试计算,我们的文件系统支持的单个文件最大为多大?

一个磁盘块大小为4KB。单个文件有10个直接指针,最多1024个间接指针,那么单个文件最大为\((1024+4)*4KB=4112KB\)

5.4 查找代码中的相关定义,试回答一个磁盘块中最多能存储多少个文件控制块?一个目录下最多能有多少个文件?

u_char f_pad[BY2FILE - MAXNAMELEN - 4 - 4 - NDIRECT * 4 - 4 - 4 - 4 - 4];

文件控制块结构体中,有这样的一个属性f_pad,大小为BY2FILE即256B,则代表一个文件控制块的大小为256B,那么一个磁盘块4KB最多存储\(4KB/256B=16\)个文件控制块。一个目录最大为4112KB,则最多能有\(4112KB/256B=16448\)个。

5.5 请思考,在满足磁盘块缓存的设计的前提下,实验使用的内核支持的最大磁盘大小是多少?

用kseg1区域映射磁盘,因此最多处理1GB。

5.6 如果将 DISKMAX 改成 0xC0000000, 超过用户空间,我们的文件系统还能正常工作吗?为什么?

我们的文件系统是放在用户态而不是内核态,而用户态不能访问用户空间以上的内核间,因此文件系统不能正常工作。

5.7 阅读 user/file.c,思考文件描述符和打开的文件分别映射到了内存的哪一段空间。

查看fd_alloc函数

#define FILEBASE 0x60000000
#define FDTABLE (FILEBASE-PDMAP)

#define INDEX2FD(i)	(FDTABLE+(i)*BY2PG)
#define INDEX2DATA(i)	(FILEBASE+(i)*PDMAP)

int
fd_alloc(struct Fd **fd)
{
	u_int va;
	u_int fdno;

	for (fdno = 0; fdno < MAXFD - 1; fdno++) {
		va = INDEX2FD(fdno);

		if (((* vpd)[va / PDMAP] & PTE_V) == 0) {
			*fd = (struct Fd *)va;
			return 0;
		}

		if (((* vpt)[va / BY2PG] & PTE_V) == 0) {	//the fd is not used
			*fd = (struct Fd *)va;
			return 0;
		}
	}

	return -E_MAX_OPEN;
}

可以看出,文件描述符fd指针被映射到0x5ffc0000~0x60000000之间。打开的文件与其对应的文件描述符同处于一个 Filefd 结构体中,即被映射于文件描述符对应的那一页中。

5.8 阅读 user/file.c,大家会发现很多函数中都会将一个 struct Fd * 型的 指针转换为 struct Filefd * 型的指针,请解释为什么这样的转换可行。

结构体 Filefd 的第一个成员就是结构体 Fd 的变量。因此每个Fd对应一个Filefd,而Filefd其他成员变量在内存上紧跟着Fd,因此转换可行。

5.9 请解释 Fd, Filefd, Open 结构体及其各个域的作用。比如各个结构体会在哪些过程中被使用,是否对应磁盘上的物理实体还是单纯的内存数据等。说明形式自定,要求简洁明了,可大致勾勒出文件系统数据结构与物理实体的对应关系与设计框架。

struct Fd { //文件描述符;打开文件时用于找到对应文件;单纯的内存数据;
u_int fd_dev_id; //该文件对应的设备id
u_int fd_offset; //读写偏移量
u_int fd_omode; //允许用户进程对文件的操作权限
};

struct Filefd { //单纯的内存数据;
struct Fd f_fd; //文件描述符
u_int f_fileid; //文件系统为打开的文件进行的编号
struct File f_file; //对应文件的文件控制块
};

struct Open { //文件系统用来保存已打开的文件信息;仅供文件系统进程使用;单纯的内存数据;
struct File *o_file; //指向该文件的文件控制块的指针
u_int o_fileid; //文件的编号
int o_mode; //允许用户进程对文件的操作权限
struct Filefd *o_ff; //指向该文件描述符的指针
};

Filefd以及Open中的指向的文件控制块File中记录的磁盘指针对应物理实体。

5.10 阅读serv.c/serve函数的代码,我们注意到函数中包含了一个死循环for (;;) {...},为什么这段代码不会导致整个内核进入 panic 状态?

serve进程随着系统运行开始时开始执行,每次循环都调用了 ipc_recv,该进程会进入 NOT_RUNNABLE 状态,随时相应用户进程发出的文件请求,不会一直占用CPU,直到结束系统杀死进程。此进程为用户态进程,不会导致内核进程陷入panic。

5.11 观察 user/fd.h 中结构体 Dev 及其调用方式。综合此次实验的全部代码,思考这样的定义和使用有什么好处。

struct Dev
{
	int dev_id;
	char *dev_name;
	int (*dev_read)(struct Fd*, void*, u_int, u_int);
	int (*dev_write)(struct Fd*, const void*, u_int, u_int);
	int (*dev_close)(struct Fd*);
	int (*dev_stat)(struct Fd*, struct Stat*);
	int (*dev_seek)(struct Fd*, u_int);
};

可以看到,成员变量基本上都是函数指针,这样可以灵活改变对应的函数名称以及函数内容,提高可移植性。

实验难点

本次实验填写代码部分个人认为没有lab4难,根据注释以及现有的代码可以轻松的完成,bug部分随着时间的增加,通过测试程序定位bug的能力也越来越好。并且此次实验有补充指导书,很好的梳理了有关.c文件的关系以及定义函数之间的调用关系。

难的部分还是充分阅读和理解写好的代码,并且在课上的时候能够很好的利用已有的代码完成更多的功能。

感想

lab5的结束也代表着os实验部分进入了尾声,通过这段时间的学习,让我收获最大的就是对C语言的了解更加充分、更加透彻,其次就是对操作系统的工作原理有了具体的理解,而不是最开始简单的几行文字。

上一篇:linux jdk安装


下一篇:kylin3.1基于ambari2.7.5部署总结