banner
Hi my new friend!

OS-Lab5

Scroll down

OS-Lab5

一、思考题

Thinking 5.1

  • 由于外部设备会更改自己对应地址空间的数据,CPU写入外设的数据存入Cache中,若在此时访问Cache,由于缓存内容只有在被新数据换出时才会被写入内存,因此会导致缓存内容覆盖了之前的操作,这相当于只进行最后一次操作,即操作覆盖。
  • 串口访问频繁,而IDE磁盘访问频率较小,因此串口出错概率更高。

Thinking 5.2

  • 由File文件控制块定义可知,文件控制块被f_pad限制对齐为256B,而一个磁盘块大小为4KB,因此一个磁盘块最多存储16个文件控制块。
  • 目录文件最多用1024个磁盘块存储数据,因此最多有1024 * 16 = 16384个文件。
  • 一个文件最多用1024个磁盘块存储数据,因此单个文件最大为1024 * 4KB = 4MB。

Thinking 5.3

内核支持最大磁盘大小为DISKMAX即0x40000000B = 1GB。

Thinking 5.4

fs/serv.h:

1
2
3
4
5
6
7
8
9
#define BY2SECT 512		    /* Bytes per disk sector */
#define SECT2BLK (BY2BLK / BY2SECT) /* sectors to a block */

/* Disk block n, when in memory, is mapped into the file system
* server's address space at DISKMAP+(n*BY2BLK). */
#define DISKMAP 0x10000000

/* Maximum disk size we can handle (1GB) */
#define DISKMAX 0x40000000

这些宏标记了扇区大小以及diskmap的地址范围。

user/include/fs.h:

1
2
3
4
5
6
7
8
9
10
11
12
// Bytes per file system block - same as page size
#define BY2BLK BY2PG

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

#define FILE2BLK (BY2BLK / sizeof(struct File))

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

这些宏定义了各种关于文件结构体的信息,比如文件直接指针数以及文件类型。

Thinking 5.5

由于文件描述符以及定位指针都存在于用户空间内,因此fork前后的父子进程会共享文件描述符和定位指针。

程序代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "lib.h"

void test()
{
int r;
int fdnum;
int num;
char buf[100];
fdnum = open("/newmotd", O_RDWR);
if((r = fork()) == 0)
{
num = read(fdnum, buf, 10);
debugf("this is child buf : %s\n", buf);
}
else
{
num = read(fdnum, buf, 10);
debugf("this is father buf : %s\n", buf);
}
return;
}

Thinking 5.6

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[BY2FILE - MAXNAMELEN - (3 + NDIRECT) * 4 - sizeof(void *)];
} __attribute__((aligned(4), packed));

File结构体在描述以及管理文件时使用,主要作用是获得文件的各种属性以及文件内容在磁盘上的位置,File结构体是物理实体。

Fd:

1
2
3
4
5
struct Fd {
u_int fd_dev_id; //文件对应外设id
u_int fd_offset; //读写偏移量
u_int fd_omode; //文件的打开方式
};

Fd结构体记录已打开文件的状态,便于用户直接使用其对文件进行操作。该结构体是内存数据。

Filefd:

1
2
3
4
5
struct Filefd {
struct Fd f_fd; //文件描述符
u_int f_fileid; //文件的id
struct File f_file; //文件控制块
};

Filefd结构体是对文件描述符的扩展,便于获得更多文件描述信息。该结构体是内存数据。

Thinking 5.7

  • ENV_CREATE(user_env)ENV_CREATE(fs_env)是同步消息,表示两种进程的创建,在结束创建过程后init才会向下执行。
  • fs进程在执行完初始化后,就进入serv()函数,调用ipc_receive()函数将自身阻塞,等待用户进程发送请求,直到收到用户进程的ipc_send同步信息被唤醒。
  • fs进程服务结束,通过ipc_send发送一个同步的返回信息,唤醒用户进程继续执行,而自身继续阻塞等待下次请求服务。

二、实验难点

1.文件数据块定位

文件的数据离散地存放在不同的磁盘块中,而在文件控制块内,存在指针指向这些存放数据的磁盘块。在f_direct数组中存在十个直接指针,这些指针直接指向磁盘块,还有存在于f_indirect指针指向的磁盘块中的1024个指针,由于前十个指针不使用,因此存在1014个间接指针,因此一个文件最大可以有1024个磁盘块保存数据,一个目录也可以最多有1024个磁盘块保存子文件或子目录。

2.用户进程与文件系统服务进程交互流程

用户进程通过用户接口申请文件服务,这些服务都定义在file.c中,之后请求会通过fsipc.c中的函数利用IPC机制将请求发送至文件系统服务进程。文件系统服务进程接收到请求后摆脱阻塞态,使用serv.c中的函数调用fs.c中的服务函数解决请求,之后通过serv.c中的函数向用户进程发出返回信息,交互结束。

三、心得体会

本次实验逻辑比较清晰,因为有请求服务->发出信号->服务进程处理->返回信号这一过程,因此代码实现目的性强。但本次实验代码量很大,需要一定时间阅读理解。总体而言加深了我对外设以及文件系统管理与服务的理解,收获很多。

其他文章