北航操作系统实验lab5总结

磁盘文件系统是一种设计用来利用数据存储设备来保存计算机文件的文件系统,最
常用的数据存储设备是磁盘驱动器,可以直接或者间接地连接到计算机上。
与此相对的是众多微内核中使用的用户空间文件系统,其特点是文件系统在用户空间中实现,通过特殊的系统调用接口或者通用机制为其他用户程序提供服务。

整个文件系统包括以下几个部分:

  1. 外部储存设备驱动 通常,外部设备的操作需要通过按照一定操作序列读写特定的寄存器来实现。为了将这种操作转化为具有通用、明确语义的接口,我们必须实现相应的驱动程序。在本部分,我们实现了 IDE 磁盘的用户态驱动程序。
  2. 文件系统结构 在本部分,我们实现磁盘上和操作系统中的文件系统结构,并通过驱动程序实现文件系统操作相关函数。
  3. 文件系统的用户接口 在本部分,我们提供接口和机制使得用户程序能够使用文件系统,这主要通过一个用户态的文件系统服务来实现。同时,我们引入了文件描述符等结构使操作系统和用户程序可以抽象地操作文件而忽略其实际的物理表示。

MIPS 的地址空间中,其在内核地址空间中(kseg0 和 kseg1段)实现了硬件级别的物理地址和内核虚拟地址的转换机制。由于我们在模拟器上运行操作系统,I/O 设备的物理地址是完全固定的。这样一来我们的驱动程序任务就转变成了简单的读写某些固定的内核虚拟地址。

我们使用 C 语言程序(fs/fsformat.c)来模拟对磁盘的操作,掌握如何将文件和文件夹按照文件系统的格式写入磁盘,我们也正是通过 fsformat 程序来创建一个磁盘文件 fs/fs.img 供内核使用。

块缓存指的是借助虚拟内存来实现磁盘块缓存的设计。read_block 函数将指定编号的磁盘块都入到内存中,首先检查这块磁盘块是否已经在内存中,如果不在,先分配一页物理内存,然后调用 ide_read 函数来读取磁盘上的数据到对应的虚存地址处。

文件系统属于用户态进程,以服务的形式供其他进程调用。这个过程中,不仅涉及了不同进程之间通信的问题,也涉及了文件系统如何隔离底层的文件系统实现,抽象地表示一个文件的问题。

当用户进程向文件系统发送打开文件的请求时,文件系统进程会将这些基本信息记录在内存中,然后由操作系统将用户进程请求的地址映射到同一个物理页上,因此一个文件描述符至少需要独占一页的空间。当用户进程获取了文件大小等基本信息后,再次向文件系统发送请求将文件内容映射到指定内存空间中。

文件和目录逻辑上都是由一系列数据块构成,可以像进程那样将虚拟地址空间映射到物理内存,文件系统需要隐藏数据块分布细节,对外只需要提供文件操作方法即可,如open,read,write,close等。我们的文件系统它没有使用系统调用实现,而是通过我们之前完成的IPC功能来实现文件操作的。系统会在启动时运行一个文件系统进程,该进程接收用户进程的IPC请求并完成文件的各种操作。

init/init.c里面,我们创建了两个进程。其中一个调用了umain/serv.c

void
umain(void)
{
        user_assert(sizeof(struct File) == BY2FILE);
        writef("FS is running\n");
        writef("FS can do I/O\n");
        
        serve_init();
        fs_init();
        fs_test();
        serve();
}

下面以fstest的两个语句为例,梳理一下思路。

		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);
        }

1. 调用serve_init/serv.c
进行opentab的初始化。

void
serve_init(void)
{
        int i;
        u_int va;

        // Set virtual address to map.
        // #define FILEVA  0x60000000
        va = FILEVA;

        // Initial array opentab.
        // MAXOPEN=1024
        for (i = 0; i < MAXOPEN; i++) {
                opentab[i].o_fileid = i;
                opentab[i].o_ff = (struct Filefd *)va;
                va += BY2PG;
        }
}

opentab里管理的是打开的文件,其定义为

struct Open {
        struct File *o_file;    // mapped descriptor for open file
        u_int o_fileid;         // file id
        int o_mode;             // open mode
        struct Filefd *o_ff;    // va of filefd page
};
struct Open opentab[MAXOPEN] = { { 0, 0, 1 } };

在赋值opentab[0]的前三个成员,第一个是地址。o_mode打开方式

2.fs_init/fs.c

void
fs_init(void)
{
//      1. read super block.
        read_super();
//      2. check if the disk can work.
        check_write_block();
//      3. read bitmap blocks from disk to memory.
        read_bitmap();
}

这几个函数的用处大概能从名字看出来。
read_super()

  • 把block1读入内存(read_block),把地址给全局变量super。
  • 检查super的magic和s_nblocks是否符合规范。
 struct Super {
        u_int s_magic;          // Magic number: FS_MAGIC
        u_int s_nblocks;        // Total number of blocks on disk
        struct File s_root;     // Root directory node根目录
};
struct Super *super;

super是一个Super类型的结构体指针,它既可以表示地址(即block1所在内存的虚拟地址),也可以作为结构体指针访问结构体里的数据。
block读到内存主要是靠以下的函数,把磁盘指定位置的内容读进目标虚拟地址。

ide_read(0, blockno * SECT2BLK, (void *)va, SECT2BLK);

check_write_block()
Test that write_block works, by smashing the superblock and reading it back.
就是把它解绑以后看看变化,再绑回去。
read_bitmap()
建立bitmap,把相应大小的bitmap从block读入内存

3.fs_test

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值