Advertisement

北航操作系统实验lab5总结

阅读量:

磁盘文件系统是一种设计用于利用数据存储设备以保存计算机文件的组织结构,在现代计算机系统中最常见的数据存储设备通常是磁盘驱动器。这种组织方式既可以连接又可以间接连接到计算机系统中使用。相比之下,在微内核架构中使用的另一种类型是基于用户空间的文件系统。在这种情况下,文件系统本身位于用户空间中,并通过专用的操作系统调用接口或者通用机制为其他应用程序提供服务。

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

  1. 外部存储设备的驱动 一般情况下, 外部设备的操作过程通常涉及读取和写入特定寄存器以完成任务。为了将这种操作转化为具有通用性且具明确语义的操作界面, 我们必须开发相应的驱动程序。在此部分中, 我们实现了 IDE 磁盘上的用户态驱动程序。
  2. 文件系统的结构 在本部分中, 我们完成了磁盘上以及操作系统内部的文件系统结构设计与实现工作, 并基于此开发了用于完成相关功能调用的操作驱动程序。
  3. 文件系统的用户接口 为此设计并实现了用于访问 files 的接口机制。在此过程中, 引入了如 file descriptor 等结构体以简化操作系统与应用程序之间的交互逻辑。同时, 该模块还提供了必要的 hook 点供其他组件进行扩展性配置与功能扩展。

在MIPS的地址空间中,在内核内存区域(分为kseg0和kseg1)实现了物理到虚拟地址转换。因为我们在模拟器环境中运行操作系统,在这种情况下I/O设备的物理内存位置是固定的。这样一来我们的驱动程序任务就将被简化为直接操作固定内存块。

我们采用 C 语言程序(fs/fsformat.c)来进行磁盘操作的复制。学习将文件及文件夹按照其 filesystem 格式复制到磁盘上。同时,我们借助 fsformat 程序生成了一个名为 fs/fs.img 的磁盘 filesystem 文件以供 kernel 使用。

块缓存采用虚拟内存技术以实现磁盘块缓存机制。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();
    }
    
    
    c
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/OtGWSsRzc3pAovQYJhPlyeBIFrmZ.png)

下面以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);
        }
    
    
    c

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;
        }
    }
    
    
    c
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/CsE5MTxuBzKR3pSQOqrP7y1oZ9WI.png)

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

在赋值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();
    }
    
    
    c
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/4eWZQ91I6XJjtPv5HRLhrMiw7nSD.png)

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

  • 将block1加载至内存中(read_block),并将该块的地址赋值给全局变量super。
  • 验证global variable 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根目录
    };
    
    
    c
复制代码
    struct Super *super;
    
    
    c

这个超类结构体的实例可以被用作一个指向该结构体数据的一个通用指针实例。这种实例不仅可以标识块1所在的内存中的虚拟起始位置(即通过"即"来强调其含义),还可以直接用于访问该结构体内存储的具体数据字段。
为了将磁盘上指定位置的数据加载到目标虚拟地址中进行处理,block主要依赖于特定的功能函数。

复制代码
    ide_read(0, blockno * SECT2BLK, (void *)va, SECT2BLK);
    
    
    c

check_write_block()
Verify if write_block functions correctly by disassembling the superblock and reconstructing it.
这相当于将文件系统进行断开操作以查看效果后再重新连接起来。
read_bitmap()
Construct a bitmap from a block of data into memory.

3.fs_test

全部评论 (0)

还没有任何评论哟~