Thinking

Thinking 5.1

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

由于cache更新不及时等问题,可能在访问内核时错误读取到设备内容

例如外设发生内容改变,但是cpu不会吧这个改变直接写入cache,导致下一次从cache读取设备内容读取到未更新的值而错误

串口设备由于即时性与高使用频率,比IDE设备更加可能出现此类错误

Thinking 5.2

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

1
2
3
#define PAGE_SIZE 4096
#define FILE_STRUCT_SIZE 256
#define BLOCK_SIZE PAGE_SIZE

一个磁盘块最多能容纳文件控制块 4096/256 = 16个

f_direct[NDIRECT] 可以存储10个磁盘块指针,f_indirect指向的间接磁盘块可以存储4096/4=1024个磁盘块,除去其中闲置不用的10个指针,所以一共有1024个磁盘块指针可用

一个目录下最多能有1024*16=16384个文件控制块,即该目录下可以有16384个文件

单个文件最大为1024*4096 = 4194304MB = 4MB

Thinking 5.3

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

虚拟地址范围为DISKMAP-DISKMAP+DISKMAX,所以最大磁盘大小为DISKMAX=0X40000000字节大小,也就是1GB

Thinking 5.4

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

1
2
3
4
5
6
7
8
9
10
11
12
#define SECT_SIZE 512	// 定义了扇区大小
#define SECT2BLK (BLOCK_SIZE / SECT_SIZE) // 定义了一个磁盘块中扇区的数量(好奇为什么不写成BLK2SECT)
#define DISKMAP 0x10000000 // 磁盘映射虚拟地址空间起始地址
#define DISKMAX 0x40000000 // 磁盘映射虚拟地址空间大小
#define BLOCK_SIZE PAGE_SIZE // 磁盘块大小,与页面大小相同,便于换进换出
#define MAXNAMELEN 128 // 文件名的最大长度,类似的还有最长路径的名字长度
#define NDIRECT 10 // 文件控制块直接指向磁盘块指针数量
#define NINDIRECT (BLOCK_SIZE / 4) // 一个文件所能指向的最大磁盘块数量,即f_indirect指向的磁盘块能容纳BLOCK_SIZE / 4个指针
#define MAXFILESIZE (NINDIRECT * BLOCK_SIZE) // 文件最大大小
#define FILE_STRUCT_SIZE 256 //文件控制块大小(填空对齐使整数个文件控制块占满一个磁盘块)
#define FILE2BLK (BLOCK_SIZE / sizeof(struct File)) // 一个磁盘块可以存储多少文件控制块

Thinking 5.5

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

会。进程的文件描述符表存储在[FDTAVLE,FILEBASE]这一虚拟地址空间中。在fork函数执行时。会将父进程中该部分地址空间对应页表拷贝到子进程页表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int main(){
int fd;
int r;
char buf[128];
fd = open("/test",O_RDONLY);
r = fork();
if(r < 0){
user_panic("fork error");
}else if(r == 0){
if((r = read(fd,buf,9))!=9){
user_panic("read error");
}
debugf("child read: \"%s\"\n",buf);
}else{
if((r = read(fd,buf,9))!=9){
user_panic("read error");
}
debugf("father read: \"%s\"\n",buf);
}
return 0;
}

test文件内容为

123456789987654321

输出为

father read:”123456789”

child read: “987654321”

Thinking 5.6

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

1
2
3
4
5
6
7
8
9
10
11
// 1.文件控制块————对应磁盘实体
struct File {
char f_name[MAXNAMELEN]; // 文件名
uint32_t f_size; // 文件大小
uint32_t f_type; // 文件类型,目录或者文件
uint32_t f_direct[NDIRECT];//直接索引的10个磁盘块指针
uint32_t f_indirect;//间接块索引的磁盘块指针

struct File *f_dir; // 文件目录指针
char f_pad[FILE_STRUCT_SIZE - MAXNAMELEN - (3 + NDIRECT) * 4 - sizeof(void *)];//空白填补,使得File结构体对齐为FILE_STRUCT_SIZE大小
} __attribute__((aligned(4), packed));
1
2
3
4
5
6
// 2.文件描述符————仅为内存数据
struct Fd {
u_int fd_dev_id;//文件对应的设备id
u_int fd_offset;//文件读写的偏移量
u_int fd_omode;//文件读写模式
};
1
2
3
4
5
6
//3.文件描述符And文件控制块————其中f_fd仅为内存数据,f_file磁盘块中也有对应
struct Filefd {
struct Fd f_fd;//文件描述符结构体
u_int f_fileid;//文件id,表示该文件在opentab中的位置
struct File f_file; //文件控制块
};

Thinking 5.7

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

image-20250523213705376

黑实线&&黑闭三角 虚线&&开三角
同步消息 异步消息

通过IPC来实现进程间通信的,发送方先调用ipc_send函数,当接收方成功接收到消息时,ipc_send函数跳出循环结束,这时发送方再调用ipc_recv函数等待接返回信息。

实验难点

我认为此次实验的一大难点是理解用户进程与文件系统服务进程间的交互

以remove的实现流程为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 1.用户进程调用remove,删除一个文件或者目录
// --- user/lib/file.c ,其中调用fsipc中服务
int remove(const char*path){
return fsipc_remove(path);
}

// 2.fsipc_remove 调用fsipc,其中请求类型参数为FSREQ_REMOVE
// --- user/lib/fsipc.c
int fspic_remove(const char *path);

// 3.fspic 调用了ipc_send文件系统服务进程通信

// 4.文件系统服务进程通过ipc_recv接收到传来信息,通过请求类型将其分发至serve_remove
// ---fs/serve.c

// 5.serve_remove中实现文件删除,并通过ipc_send向用户进程发送消息

// 6.用户进程在fsipc处通过ipc_recv接收到文件系统服务进程传来的消息
// ---user/lib/fsipc.c

实验体会

本单元是我目前经历过的lab中最难的一个,内容较为繁杂。我对于文件描述符等数据结构的实现与管理并不清楚,并且对于众多open,close,read,write操作仅通过某一个操作作为样例去学习,学习并不扎实。但是在学习过程中发现许多函数非常值得学习,等忙完考试希望能有机会再好好学习一下。

实验参考

我再完成实验过程中参考了https://seafoodfat1ger.github.io/2024/05/29/OS/OS_Lab5/的博客,对于我实验理解与思考题解答方面帮助良多