BUAA操作系统lab5

Cdostan MVP++

Lab5实验报告

一、思考题

Thinking 5.1

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

答:如果设备的数据缓存到Cache之后发生了更改或是触发了中断,Cache里的数据可能来不及进行修改,导致从Cache中获取的数据可能是过时的,发生错误。
对于串口设备来说,其发生的读写操作更为频繁,信号量也众多,因此发生错误的概率会更高。

Thinking 5.2

查找代码中的相关定义,试回答一个磁盘块中最多能存储多少个文件控制块?一个目录下最多能有多少个文件?我们的文件系统支持的单个文件最大为多大?

答:如图:

可知一个文件控制块的大小是256字节,而一个磁盘块为4KB,所以一个磁盘块最多能存储16个文件控制块。
一个目录最多有1024个目录项,每个目录项对应一个磁盘块,所以一个目录下最多能有16384个文件。

由该图可以知道,文件系统支持的单个文件最大为1024*4KB=4MB。

Thinking 5.3

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

DISKMAX=0x40000000,所以在满足磁盘块缓存设计的前提下,内核支持的最大磁盘大小为1GB。

Thinking 5.4

在本实验中,fs/serv.h、user/include/fs.h 等文件中出现了许多宏定义,试列举你认为较为重要的宏定义,同时进行解释,并描述其主要应用之处

1
2
3
4
5
6
7
#define NDIRECT 10
#define NINDIRECT (BLOCK_SIZE / 4)
#define MAXFILESIZE (NINDIRECT * BLOCK_SIZE)
#define FILE2BLK (BLOCK_SIZE / sizeof(struct File))
#define SECT2BLK (BLOCK_SIZE / SECT_SIZE)
#define DISKMAP 0x10000000
#define DISKMAX 0x40000000

我认为比较重要的宏有以上:

  • NDIRECT:文件控制块中文件的直接指针个数
  • NINDIRECT:文件控制块中文件的间接指针个数
  • MAXFILESIZE:文件最大大小
  • FILE2BLK:将文件转化为磁盘块
  • SECT2BLK:将扇区转化为磁盘块
  • DISKMAP:块缓存起始地址
  • DISKMAX:最大块缓存大小

Thinking 5.5

在Lab4“系统调用与fork”的实验中我们实现了极为重要的fork函数。那么fork前后的父子进程是否会共享文件描述符和定位指针呢?请在完成上述练习的基础上编写一个程序进行验证。

我编写了下面一个简易程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <lib.h>

static char *msg = "This is the NEW message of the day!\n";
static char *diff_msg = "This is a different message of the day!\n";

int main() {
int r;
int fdnum;
char buf[512];
int n;
int id;
if ((id = fork()) == 0) {
if ((r = open("/newmotd", O_RDWR)) < 0) {
user_panic("child cannot open /newmotd: %d", r);
}
fdnum = r;
debugf("child_open is good and the fdnum is %d\n",fdnum);
} else {
if ((r = open("/newmotd", O_RDWR)) < 0) {
user_panic("parent cannot open /newmotd: %d", r);
}
fdnum = r;
debugf("parent_open is good and the fdnum is %d\n",fdnum);
}
}

输出如下:

1
2
parent_open is good and the fdnum is 0
child_open is good and the fdnum is 0

所以父子进程是会共享文件描述符和定位指针的。

Thinking 5.6

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct File {
char f_name[MAXNAMELEN];//文件名
uint32_t f_size; //文件大小
uint32_t f_type; //文件类型
uint32_t f_direct[NDIRECT];//文件直接指针
uint32_t f_indirect;//间接磁盘块

struct File *f_dir;//文件所属目录
char f_pad[FILE_STRUCT_SIZE-MAXNAMELEN-(3 + NDIRECT)* 4-sizeof(void *)];//填充空余空间
}__attribute__((aligned(4),packed));

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;//文件id
struct File f_file;//文件控制块
};

Thinking 5.7

图 5.9 中有多种不同形式的箭头,请解释这些不同箭头的差别,并思考我们的操作系统是如何实现对应类型的进程间通信的。


根据UML时序图相关知识可知,图中有同步和异步两种箭头。
ENV_CREATE()是异步操作,init()发出消息后继续执行不必阻塞,之后fs和user开始初始化。再之后fs进入serv函数,同时在未接收到user发来的请求信息时,由ipc_receive()将自身状态修改为ENV_NOT_RUNNABLE进行阻塞,等到user发送信息后fs再开始进行服务,与此同时user进程被阻塞,fs服务完成后将相应信息发送给user,然后等待下一个请求,user执行之后的操作。

二、难点分析

本次实验是实现文件系统,文件系统本身就是操作系统里面一个重要的部分,实现文件系统才能方便操作系统的管理。文件系统与IO有很强的关联,所以完成本次实验需要对IO和文件系统都有较深的理解,而这两部分的内容都是庞大的,所以本次实验难度较大。具体分析,我认为有以下难点:

  • 对外设与操作系统连接的认识与理解
  • 对文件系统整体实现的理解
  • 对外设驱动的认识
  • 对磁盘结构以及如何读写的认识
  • 对微内核实现文件系统的认识
  • 对磁盘块缓存的认识
  • 对文件系统下如何查找文件的认识
  • 对文件描述符的理解
  • 对文件系统服务整体流程的理解

三、心得体会

在lab5中,我跟着指导书以及实验代码的提示跌跌撞撞完成了本次实验,本次实验代码的难度并不大,按照提示来编写几乎遇不到什么坎,最可能出现的是一些小问题,所以细心编写还是花不了太多时间就能完成代码的。但本次的内容同样也十分庞杂,与理论课上讲的IO以及文件系统不同,指导书从操作系统具体是怎么从代码上去实现整个文件系统的入手,这会变得更加具象,比理论课上的一些知识更加难以理解。因此需要花费较多时间去细啃指导书,但通过仔细阅读指导书,同时对照着跳板机上的代码实现,我的确感受到了文件系统设计的精妙。

  • Title: BUAA操作系统lab5
  • Author: Cdostan
  • Created at : 2025-05-20 19:00:00
  • Updated at : 2025-06-05 19:57:13
  • Link: https://cdostan.github.io/2025/05/20/OS/Lab5实验报告/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments