简易文件系统 easy-fs ======================================= 本节导读 --------------------------------------- 本节我们介绍一个简易文件系统实现 easy-fs。作为一个文件系统而言,它的磁盘布局体现在磁盘上各扇区的内容上,而它解析磁盘布局得到的逻辑目录树结构则是通过内存上的数据结构来访问的,这意味着它要同时涉及到对磁盘和对内存的访问。它们的访问方式是不同的,对于内存直接通过一条指令即可直接读写内存相应的位置,而磁盘的话需要用软件的方式向磁盘发出请求来间接进行读写。此外,我们也要特别注意哪些数据结构是存储在磁盘上,哪些数据结构是存储在内存中的,这样在实现的时候才不会引起混乱。 easy-fs 被从内核中分离出来,它的实现分成两个不同的 crate : - ``easy-fs`` 为简易文件系统的本体,它是一个库形式 crate,实现一种我们设计的简单磁盘布局; - ``easy-fs-fuse`` 是一个能在开发环境(如 Ubuntu)中运行的应用程序,它可以对 ``easy-fs`` 进行测试,或者将为我们内核开发的应用打包为一个 easy-fs 格式的文件系统镜像。 块设备接口层 --------------------------------------- 在 ``easy-fs`` 库的最底层声明了一个块设备的抽象接口 ``BlockDevice`` : .. code-block:: rust // easy-fs/src/block_dev.rs pub trait BlockDevice : Send + Sync + Any { fn read_block(&self, block_id: usize, buf: &mut [u8]); fn write_block(&self, block_id: usize, buf: &[u8]); } 它需要实现两个抽象方法: - ``read_block`` 可以将编号为 ``block_id`` 的块从磁盘读入内存中的缓冲区 ``buf`` ; - ``write_block`` 可以内存中的缓冲区 ``buf`` 中的数据写入磁盘编号为 ``block_id`` 的块。 这是因为,之前提到过,块设备仅支持以块为单位进行随机读写,由此才有了这两个抽象方法。在 ``easy-fs`` 中并没有一个实现了 ``BlockDevice`` Trait 的具体类型,实际上这是需要由库的使用者提供并接入到 ``easy-fs`` 库的。这也体现了 ``easy-fs`` 的泛用性:它可以用于管理任何实现了 ``BlockDevice`` Trait 的块设备。 .. note:: **块与扇区** 实际上,块和扇区是两个不同的概念。 **扇区** (Sector) 是块设备随机读写的大小单位,通常每个扇区为 512 字节。而块是文件系统存储文件时的大小单位,每个块的大小等同于一个或多个扇区。之前提到过 Linux 默认文件系统的单个块大小为 4096 字节。在我们的实现中一个块的大小和扇区相同为 512 字节,因此在后面的讲解中我们不再区分扇区和块的概念。 块缓存层 --------------------------------------- 磁盘布局及磁盘上数据结构 --------------------------------------- 磁盘块管理器 --------------------------------------- 索引节点 --------------------------------------- 测试 easy-fs --------------------------------------- 将应用打包为 easy-fs 镜像 ---------------------------------------