TLPI:文件系统
1. 基本原理
磁盘可以被划分成互不重叠的分区,每个分区可以容纳任何类型的信息,但通常只会包含以下其一。
文件系统(FS):存放常规文件
数据区域:可作为裸设备访问,一些 DBMS 会使用该技术
交换区域:用于内核的内存管理
下面我们介绍文件系统。Linux 支持种类繁多的文件系统,包括 Windows 的 FAT/FAT32/NTFS 文件系统,我的 Debian 12 虚拟机上的磁盘为 ext4 文件系统。
ext2 是一款经典的 Linux 文件系统,我们以 ext2 为例说明文件系统的基本原理。在 ext2 上,分配空间的基本单位——逻辑块的大小为 1024、2048 或 4096 字节,可以在创建文件系统的时候指定(mkfs 命令)。一般文件系统的组成如下图所示。
引导块:包含引导 OS 的信息,OS 实际上只需要一个引导块,但所有 FS 都设有引导块(因此绝大多数都未使用)
超级块:包含与 FS 有关的参数信息,如 i-node 表容量、逻辑块的大小、文件系统的大小
i-node 表:FS 中的每个文件和目录都有一条唯一的 i-node 记录
数据块:用于存放数据
这里不详细列举 i-node 记录中的具体信息,我们主要关注数据块索引的设计。
i-node 记录中除了文件的基本信息外,最重要的就是文件块指针了。在 ext2 中,每个 i-node 记录中包含 15 个指针,前 12 个是直接指针,或者叫一级指针,它们直接指向数据块;第 13~15 个是间接指针,分别为二、三、四级指针,它们指向的是指针块。大致做一个估计,假设指针占用 4 字节,每个逻辑块为 4096 字节,那么一个指针块中可以存放 1024 个指针。如果只关注四级指针,那么 ext2 文件系统支持的存储空间大约为 1024*1024*1024*4096 byte = 4TB。
2. 挂载与卸载
挂载就是把一个文件系统关联到某个目录,这样用户就可以通过访问该目录来访问文件系统中的文件和目录。如果文件系统中有文件被打开,或者有进程的工作目录驻留在此文件系统上,将无法通过系统调用卸载该目录。这里暂不深究相关系统调用,简单了解 mount、unmount 命令的用法即可,参见 [2]。
3. 目录与链接
目录也是一种文件,它的内容就是一张该目录下所有目录与文件名到各自 i-node 号码的映射表,如下图所示。
一般来说,i-node 与文件名是一一对应的。但“硬链接”是一个例外,它允许多个文件名对应到同一个 i-node。下图展示了创建硬链接的过程,ls -li
的第一列展示了文件名对应的 i-node 号码,第三列是 i-node 的链接计数。当我们删除一个文件时,首先会减少 i-node 的链接计数,当该计数降为 0 时才会真正删除 i-node 与对应的数据块。因此,我们可以认为 i-node 才真正对应到底层的文件。事实上,Linux/Unix 系统内部只使用 i-node 号码而不是文件名来识别文件 [3]。也正是因为这个缘故,i-node 中并没有存储文件名信息。
“软链接”(符号链接)会创建出独立的 i-node 和数据块,它类似 Windows 上的“快捷方式”,是一个实实在在独立存在的文件,只是其文件内容中包含了另一个文件或目录的路径名。cat 等命令可以自动找到其指向的文件并做处理。从下图可以看到,软链接文件有自己的 i-node 号码。
4. 参考资料
《Linux/Unix 系统编程手册》Ch14、Ch18
《鸟哥的 Linux 私房菜》