Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions source/chapter6/0intro.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

.. note::

文件系统在UNIX操作系统有着特殊的地位,根据史料《UNIX: A History and a Memoir》记载,1969年,Ken Thompson(UNIX的作者)在贝尔实验室比较闲,写了PDP-7计算机的磁盘调度算法来提高磁盘的吞吐量。为了测试这个算法,他本来想写一个批量读写数据的测试程序。但写着写着,他在某一时刻发现,这个测试程序再扩展一下,就是一个文件,再扩展一下,就是一个操作系统了。他的自觉告诉他,他离实现一个操作系统仅有 **三周之遥** 。一周:写代码编辑器;一周:写汇编器;一周写shell程序,在写这些程序的同时,需要添加操作系统的功能(如 exec等系统调用)以支持这些应用。结果三周后,为测试磁盘调度算法性能的UNIX雏形诞生了。
文件系统在UNIX操作系统有着特殊的地位,根据史料《UNIX: A History and a Memoir》记载,1969年,Ken Thompson(UNIX的作者)在贝尔实验室比较闲,写了PDP-7计算机的磁盘调度算法来提高磁盘的吞吐量。为了测试这个算法,他本来想写一个批量读写数据的测试程序。但写着写着,他在某一时刻发现,这个测试程序再扩展一下,就是一个文件,再扩展一下,就是一个操作系统了。他的直觉告诉他,他离实现一个操作系统仅有 **三周之遥** 。一周:写代码编辑器;一周:写汇编器;一周写shell程序,在写这些程序的同时,需要添加操作系统的功能(如 exec等系统调用)以支持这些应用。结果三周后,为测试磁盘调度算法性能的UNIX雏形诞生了。


.. chyyuu 可以介绍文件系统 ???
Expand Down Expand Up @@ -291,14 +291,14 @@ easyfs文件系统中管理这些磁盘数据的控制逻辑主要集中在 **

第二件事情是把文件访问相关的系统调用与easyfs文件系统连接起来。在easfs文件系统中是没有进程的概念的。而进程是程序运行过程中访问资源的管理实体,而之前的进程没有管理文件这种资源。
为此我们需要扩展进程的管理范围,把文件也纳入到进程的管理之中。
由于我们希望多个进程都能访问文件,这意味着文件有着共享的天然属性,这样自然就有了``open/close/read/write``这样的系统调用,便于进程通过互斥或共享方式访问文件。
由于我们希望多个进程都能访问文件,这意味着文件有着共享的天然属性,这样自然就有了 ``open/close/read/write`` 这样的系统调用,便于进程通过互斥或共享方式访问文件。

内核中的进程看到的文件应该是一个便于访问的Inode,这就要对 ``easy-fs`` crate 提供的 ``Inode`` 结构进一步封装,形成 ``OSInode`` 结构,以表示进程中一个打开的常规文件。文件的抽象 Trait ``File`` 声明在 ``os/src/fs/mod.rs`` 中,它提供了 ``read/write`` 两个接口,可以将数据写入应用缓冲区抽象 ``UserBuffer`` ,或者从应用缓冲区读取数据。应用缓冲区抽象类型 ``UserBuffer`` 来自 ``os/src/mm/page_table.rs`` 中,它将 ``translated_byte_buffer`` 得到的 ``Vec<&'static mut [u8]>`` 进一步包装,不仅保留了原有的分段读写能力,还可以将其转化为一个迭代器逐字节进行读写。

而进程为了进一步管理多个文件,需要扩展文件描述符表。这样进程通过系统调用打开一个文件后,会将文件加入到自身的文件描述符表中,并进一步通过文件描述符(也就是某个特定文件在自身文件描述符表中的下标)来读写该文件( 即``OSInode`` 结构)。
而进程为了进一步管理多个文件,需要扩展文件描述符表。这样进程通过系统调用打开一个文件后,会将文件加入到自身的文件描述符表中,并进一步通过文件描述符(也就是某个特定文件在自身文件描述符表中的下标)来读写该文件( 即 ``OSInode`` 结构)。

在具体实现上,在进程控制块 ``TaskControlBlock`` 中需要加入文件描述符表字段 ``fd_table`` ,可以看到它是一个向量,里面保存了若干实现了 ``File`` Trait 的文件,由于采用Rust的 ``Trait Object`` 动态分发,文件的类型可能各不相同。 ``os/src/syscall/fs.rs`` 的 ``sys_read/write`` 两个读写文件的系统调用需要访问当前进程的文件描述符表,用应用传入内核的文件描述符来索引对应的已打开文件,并调用 ``File`` Trait 的 ``read/write`` 接口; ``sys_close`` 这可以关闭一个文件。调用 ``TaskControlBlock`` 的 ``alloc_fd`` 方法可以在文件描述符表中分配一个文件描述符。进程控制块的其他操作也需要考虑到新增的文件描述符表字段的影响,如 ``TaskControlBlock::new`` 的时候需要对 ``fd_table`` 进行初始化, ``TaskControlBlock::fork`` 中则需要将父进程的 ``fd_table`` 复制一份给子进程。

对于应用程序而言,它理解的磁盘数据是常规的文件和目录,不是 ``OSInode`` 这样相对复杂的结构。其实常规文件对应的 OSInode 是操作系统内核中的文件控制块数据结构的实例,它实现了 File Trait 定义的函数接口。这些 OSInode 实例会放入到进程文件描述符表中,并通过 sys_read/write 系统调用来完成读写文件的服务。这样就建立了文件与 ``OSInode`` 的对应关系,通过上面描述的三个开发步骤将形成包含文件系统的操作系统内核,可给应用提供基于文件的系统调用服务。

.. [#rex] 霸王龙是最广为人知的恐龙,生存于约6850万年到6500万年的白垩纪最末期, 位于白垩纪晚期的食物链顶端。
.. [#rex] 霸王龙是最广为人知的恐龙,生存于约6850万年到6500万年的白垩纪最末期, 位于白垩纪晚期的食物链顶端。
Loading