BUAA_OS_lab5

BUAA_OS_lab5学习日记

Thinking

Thinking 5.1

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

缓存数据可能不及时导致出现一些不可预知错误,对于串口设备等读写频繁的设备出现的问题可能也对应更频繁。

Exercise 5.4

文件系统需要负责维护磁盘块的申请和释放,在回收一个磁盘块时,需要更 改位图中的标志位。如果要将一个磁盘块设置为free,只需要将位图中对应位的值设置 为1即可。请完成fs/fs.c中的free_block函数,实现这一功能。同时思考为什么参数 blockno的值不能为0?

MOS 操作系统把磁盘最开始的一个磁盘块(4096字节)当作引导扇区和分区表使用,不可以当作常规超级块使用

Thinking 5.2

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

File结构体256B对齐,一个磁盘块4KB,可以容纳16个File,一个File最多有1024个指针,最多可以指向16K个文件。

文件最大为1024*4KB = 4MB

Thinking 5.3

DISKMAX = 0x40000000,最多处理1GB

Thinking 5.4

fs/serv.h

1
2
3
4
#define PTE_DIRTY 0x0004 // 文件系统块脏位

#define SECT_SIZE 512 //扇区大小
#define SECT2BLK (BLOCK_SIZE / SECT_SIZE) //将扇区转化为磁盘块

user/include/fs.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Bytes per file system block - same as page size
#define BLOCK_SIZE PAGE_SIZE
#define BLOCK_SIZE_BIT (BLOCK_SIZE * 8)

// Maximum size of a filename (a single path component), including null
#define MAXNAMELEN 128

// Maximum size of a complete pathname, including null
#define MAXPATHLEN 1024

// Number of (direct) block pointers in a File descriptor
#define NDIRECT 10
#define NINDIRECT (BLOCK_SIZE / 4)

#define MAXFILESIZE (NINDIRECT * BLOCK_SIZE)

#define FILE_STRUCT_SIZE 256
// File types
#define FTYPE_REG 0 // Regular file
#define FTYPE_DIR 1 // Directory

// File system super-block (both in-memory and on-disk)

#define FS_MAGIC 0x68286097 // Everyone's favorite OS class

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include "lib.h"

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

void umain()
{
int r;
int fdnum;
char buf[512];
int n;

if ((r = open("/newmotd", O_RDWR)) < 0) {
user_panic("open /newmotd: %d", r);
}
fdnum = r;
writef("open is good\n");

if ((n = read(fdnum, buf, 511)) < 0) {
user_panic("read /newmotd: %d", r);
}
if (strcmp(buf, diff_msg) != 0) {
user_panic("read returned wrong data");
}
writef("read is good\n");

int id;

if ((id = fork()) == 0) {
if ((n = read(fdnum, buf, 511)) < 0) {
user_panic("child read /newmotd: %d", r);
}
if (strcmp(buf, diff_msg) != 0) {
user_panic("child read returned wrong data");
}
writef("child read is good && child_fd == %d\n",r);
struct Fd *fdd;
fd_lookup(r,&fdd);
writef("child_fd's offset == %d\n",fdd->fd_offset);
}
else {
if((n = read(fdnum, buf, 511)) < 0) {
user_panic("father read /newmotd: %d", r);
}
if (strcmp(buf, diff_msg) != 0) {
user_panic("father read returned wrong data");
}
writef("father read is good && father_fd == %d\n",r);
struct Fd *fdd;
fd_lookup(r,&fdd);
writef("father_fd's offset == %d\n",fdd->fd_offset);
}
}

输出

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
26
27
28
29
30
31
32
33
34
35
36
37
main.c: main is start ...
init.c: mips_init() is called
Physical memory: 65536K available, base = 65536K, extended = 0K
to memory 80401000 for struct page directory.
to memory 80431000 for struct Pages.
pmap.c: mips vm init success
pageout: @@@___0x7f3fe000___@@@ ins a page
pageout: @@@___0x40d000___@@@ ins a page
FS is running
FS can do I/O
pageout: @@@___0x7f3fe000___@@@ ins a page
pageout: @@@___0x407000___@@@ ins a page
superblock is good
diskno: 0
diskno: 0
read_bitmap is good
diskno: 0
alloc_block is good
file_open is good
file_get_block is good
file_flush is good
file_truncate is good
diskno: 0
file rewrite is good
serve_open 00000400 ffff000 0x2
open is good
read is good
father read is good && father_fd == 0
father_fd's offset == 41
[00000400] destroying 00000400
[00000400] free env 00000400
i am killed ...
child read is good && child_fd == 0
child_fd's offset == 41
[00001402] destroying 00001402
[00001402] free env 00001402
i am killed ...

Thinking 5.6

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

Thinking 5.7

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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; //对应文件的文件控制块
};

struct File {
char f_name[MAXNAMELEN]; // filename
uint32_t f_size; // file size in bytes
uint32_t f_type; // file type
uint32_t f_direct[NDIRECT]; //文件的直接指针数组
uint32_t f_indirect; //间接指针,用来存储指向文件内容的磁盘块的指针

struct File *f_dir; // the pointer to the dir where this file is in, valid only in memory. 文件目录指针
char f_pad[FILE_STRUCT_SIZE - MAXNAMELEN - (3 + NDIRECT) * 4 - sizeof(void *)]; //填充块保证256字节对齐
} __attribute__((aligned(4), packed));

Thinking 5.7

sxt

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

  • ENV_CREATE(user_env) 和 ENV_CREATE(fs_serv) 都是异步消息,由 init() 发出创建消息后, init() 函数即可返回执行后续步骤,由 fs 和 user 线程执行自己的初始化工作
  • fs线程向user线程ipcsend(fsreq)是同步消息,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 线程进入阻塞,等待下次被用户唤醒。

实验难点感想与总结

内存映射实现I/O串口操作

sys_write_dev和 sys_read_dev 两个系统调用来实现设备的读写操作

写的位置分为console和disk,只需要分别在满足地址合理的情况下利用memcpy实现物理地址和虚拟地址之间的读写即可

I/O磁盘关键寄存器映射

temp

设置IDE为读写状态之前需要设置操作扇区号的[7:0]、[15:8]、[23:16]、[27:24]位(用户态)

文件系统结构

磁盘空间布局:

diskLayOut

磁盘块只是一个虚拟概念,是操作系统与磁盘交互的最小单位

文件访问:

如果直接指针访问不到需要先通过间接指针访问磁盘,才能继续通过bno(磁盘块号)访问到对应的directory block

块操作

块地址:return (void *)(DISKMAP + blockno * BLOCK_SIZE);

块映射

dir_lookup:查找某个目录下是否存在指定的文件

先找到目录下block的个数在遍历内部的file

文件系统服务

1
2
3
4
5
6
7
8
9
10
struct File {
char f_name[MAXNAMELEN]; // filename
uint32_t f_size; // file size in bytes
uint32_t f_type; // file type
uint32_t f_direct[NDIRECT];
uint32_t f_indirect;

struct File *f_dir; // the pointer to the dir where this file is in, valid only in memory.
char f_pad[FILE_STRUCT_SIZE - MAXNAMELEN - (3 + NDIRECT) * 4 - sizeof(void *)];
}

本次lab以删除文件为例,实现了用户和内核态的文件删除,一定要留意彼此之间的IPC的通信操作

1
2
3
4
5
6
7
8
9
10
enum {
FSREQ_OPEN,
FSREQ_MAP,
FSREQ_SET_SIZE,
FSREQ_CLOSE,
FSREQ_DIRTY,
FSREQ_REMOVE,
FSREQ_SYNC,
MAX_FSREQNO,
};

总的来说,lab5的实现难度相比前面有所下降,理解好文件和磁盘系统就可以顺利完成


BUAA_OS_lab5
https://fantasylee21.github.io/2024/05/14/BUAA-OS-lab5/
作者
Fantasylee
发布于
2024年5月14日
更新于
2024年6月11日
许可协议