Linux文件系统[apue]那些事儿,都有哪些细节我不懂?
摘要:本文尝试通过解释 api 接口底层做了什么来阐释 linux 文件系统在设计层面的一些考虑,配合通俗易懂的日常命令和简单程序来进行验证,践行“纸上得来终觉浅,绝知此事要躬行”的理念,目的是做一个 linux 文件系统的引入…
前言
说到 linux 的文件系统,好多人第一印象是 ext2/ext3/ext4 等具体的文件系统,本文不涉及这些,因为研究具体的文件系统难免会陷入细节,甚至拉大段的源码做分析,反而不能从宏观的角度把握文件系统要解决的问题。一个通用的 linux 文件系统都包含哪些概念?接口如何使用?设计层面需要考虑什么问题?这都在本文的讨论范围。当然了,内容都是从 apue 搬运过来的,经过了一点点梳理加工,原书还是基于比较老的 UFS (Unix File System) 进行说明的,有些东西可能已经过时了,不过原理层面的东西还是相通的,看过之后举一反三就好。
文件系统总览
开始详细说明之前,先看下文件系统的总体结构,对一些基本的概念有个大体印象。书上有个不错的图直接盗过来:
从图中可以看出,磁盘可以由多个分区组成,每个分区可以设置不同格式的文件系统。分区在 windows 上比较容易观察,就是常说的 C/D/E/F……这些,一块磁盘也可以只设置一个分区,不过一但系统重装时,用户数据就容易丢失,从这里可以看出,分区及其上的文件系统是可以跨操作系统存在的。把系统分区从 windows 重装成 linux,数据分区也能正常读取 (linux 也能识别 NTFS),说明文件系统是独立于操作系统的。
一个分区由多个柱面组成,柱面是多个盘片在同一个磁道上形成的存储面,这样设计是为了减少寻道时间提高性能。每个柱面存储了若干数据块与对应的 inode 节点,它们都是固定长度的。inode 可以看作是文件的元数据,存放了与文件的大部分关键信息,它们连续存放在一起形成 inode 表,这主要是为了提高读取大量文件信息的性能,另外也简化了 inode 的定位过程,直接使用下标就可以了,一般称之为 inode 编号。每个柱面还存放了 inode 位图与块位图,方便查找空闲的 inode 节点或数据块。
inode 存放的信息包括:
文件类型
文件长度
文件权限位
文件链接数
文件时间
文件数据块编号
设备号
……
注意文件名是不存放在 inode 中的,文件名是变长的,最长的文件名 (255) 可能都要超过 inode 的固定长度了,不适合存储在 inode 中。文件是包含在目录中的,所以文件名与其对应的 inode 编号都存放在目录的数据块中,目录是一种特殊的文件,其数据块由系统维护,用户不能直接读写它的内容。
从上图可以看到,目录 inode -> 目录数据块 -> 文件 inode -> 文件/子目录数据块 形成了一个闭环,通过这样不断迭代可以读取到文件系统中的任意文件。
对于这个过程,可能有人会问了,inode 不是固定长度的吗,如何保存一个文件的所有数据块编号呢?这就涉及到数据块寻址了,当文件比较大的时候,光编号占用的空间就直接超过 inode 本身的长度了,所以不能直接存储在 inode 中,而要通过二级甚至三级寻址来查找全部的数据块,过程和内存的多级寻址有异曲同工之处,受主题限制就不深入展开了,感兴趣的读者可以参考文末链接。
inode 与数据块数量比例如何分配是另外一个问题,通常它们不是 1:1 的关系,这样当 inode 消耗光的时候,即使还有数据块,文件系统也不能创建新的文件了,这方面的案例可以参考这篇文章《[apue] Linux / Windows 系统上只能建立不超过 PATH_MAX / MAX_PATH 长度的路径吗? 》;但 inode 节点太多也会造成可观的容量损失,一般没有大量小文件的应用场景是不会将 inode 比例设置太多的。
