文件系统:统一用户使用的各种文件的管理机制,构筑用户文件和底层硬盘的中间接口,使我们读写数据文件时不必去关心实际存放的block。
---全文来源于互联网笔记,非原创。
硬盘分区
分区结构
整个分区大概会这样划分:

inode table
- 主要记录文件的属性以及该文件实际数据是放置在哪些block中,它记录的信息至少有这些:
- 大小、真正内容的block号码(一个或多个)
- 访问模式(read/write/excute)
- 拥有者与群组(owner/group)
- 各种时间:建立或状态改变的时间、最近一次的读取时间、最近修改的时间
- 没有文件名!文件名在目录的block中!
- 一个文件占用一个 inode,每个inode有编号
- Linux 系统存在 inode 号被用完但磁盘空间还有剩余的情况
- 注意,这里的文件不单单是普通文件,目录文件也就是文件夹其实也是一个文件,还有其他的也是
- inode 的数量与大小在格式化时就已经固定了,每个inode 大小均固定为128 bytes (新的ext4 与xfs 可设定到256 bytes)
- 文件系统能够建立的文件数量与inode 的数量有关,存在空间还够但inode不够的情况
- 系统读取文件时需要先找到inode,并分析inode 所记录的权限与使用者是否符合,若符合才能够开始实际读取 block 的内容
- inode 要记录的资料非常多,但偏偏又只有128bytes , 而inode 记录一个block 号码要花掉4byte ,假设我一个文件有400MB 且每个block 为4K 时, 那么至少也要十万条block 号码的记录!inode 哪有这么多空间来存储?为此我们的系统很聪明的将inode 记录block 号码的区域定义为12个直接,一个间接, 一个双间接与一个三间接记录区
data block
- 放置文件内容数据的地方
- 在格式化时block的大小就固定了,且每个block都有编号,以方便inode的记录
- 原则上,block 的大小与数量在格式化完就不能够再改变了(除非重新格式化)
- 在Ext2文件系统中所支持的block大小有1K, 2K及4K三种,由于block大小的区别,会导致该文件系统能够支持的最大磁盘容量与最大单一文件容量各不相同:
- Block 大小 1KB 2KB 4KB
- 最大单一档案限制 16GB 256GB 2TB
- 最大档案系统总容量 2TB 8TB 16TB
- 每个block 内最多只能够放置一个文件的资料,但一个文件可以放在多个block中(大的话)
- 若文件小于block ,则该block 的剩余容量就不能够再被使用了(磁盘空间会浪费)
- 所以如果你的档案都非常小,但是你的block 在格式化时却选用最大的4K 时,可能会产生容量的浪费
- 既然大的block 可能会产生较严重的磁碟容量浪费,那么我们是否就将block 大小定为1K ?这也不妥,因为如果block 较小的话,那么大型档案将会占用数量更多的block ,而inode 也要记录更多的block 号码,此时将可能导致档案系统不良的读写效能
- 事实上现在的磁盘容量都太大了,所以一般都会选择4K 的block 大小
superblock
- 记录整个文件系统相关信息的地方,一般大小为1024bytes,记录的信息主要有:
- block 与inode 的总量
- 未使用与已使用的inode / block 数量
- 一个valid bit 数值,若此文件系统已被挂载,则valid bit 为0 ,若未被挂载,则valid bit 为1
- block 与inode 的大小 (block 为1, 2, 4K,inode 为128bytes 或256bytes);
- 其他各种文件系统相关信息:filesystem 的挂载时间、最近一次写入资料的时间、最近一次检验磁碟(fsck) 的时间
- Superblock是非常重要的, 没有Superblock ,就没有这个文件系统了,因此如果superblock死掉了,你的文件系统可能就需要花费很多时间去挽救
- 每个块都可能含有superblock,但是我们也说一个文件系统应该仅有一个superblock 而已,那是怎么回事?事实上除了第一个块内会含有superblock 之外,后续的块不一定含有superblock,而若含有superblock则该superblock主要是做为第一个块内superblock的备份,这样可以进行superblock的救援
Filesystem Description
- 文件系统描述
- 这个区段可以描述每个block group的开始与结束的block号码,以及说明每个区段(superblock, bitmap, inodemap, data block)分别介于哪一个block号码之间
block bitmap
- 块对照表
- 如果你想要新增文件时要使用哪个block 来记录呢?当然是选择「空的block」来记录。那你怎么知道哪个block 是空的?这就得要通过block bitmap了,它会记录哪些block是空的,因此我们的系统就能够很快速的找到可使用的空间来记录
- 同样在你删除某些文件时,那些文件原本占用的block号码就得要释放出来, 此时在block bitmap 中对应该block号码的标志位就得要修改成为「未使用中」
inode bitmap
- 与block bitmap 是类似的功能,只是block bitmap 记录的是使用与未使用的block 号码, 至于inode bitmap 则是记录使用与未使用的inode 号码
挂载
在一个区被格式化为一个文件系统之后,它就可以被Linux操作系统使用了,只是这个时候Linux操作系统还找不到它,所以我们还需要把这个文件系统「注册」进Linux操作系统的文件体系里,这个操作就叫「挂载」 (mount)。
挂载是利用一个目录当成进入点(类似选一个现成的目录作为代理),将文件系统放置在该目录下,也就是说,进入该目录就可以读取该文件系统的内容,类似整个文件系统只是目录树的一个文件夹(目录)。
这个进入点的目录我们称为「挂载点」。
由于整个 Linux 系统最重要的是根目录,因此根目录一定需要挂载到某个分区。 而其他的目录则可依用户自己的需求来给予挂载到不同的分去。
到这里Linux的文件体系的构建过程其实已经大体讲完了,总结一下就是:硬盘经过分区和格式化,每个区都成为了一个文件系统,挂载这个文件系统后就可以让Linux操作系统通过VFS访问硬盘时跟访问一个普通文件夹一样。这里通过一个在目录树中读取文件的实际例子来细讲一下目录文件和普通文件。
目录树的读取过程
首先我们要知道
- 每个文件(不管是一般文件还是目录文件)都会占用一个inode
- 依据文件内容的大小来分配一个或多个block给该文件使用
- 创建一个文件后,文件完整信息分布在3处地方,生成2个新文件:
- 文件名记录在该文件所在目录的目录文件的block中,没有新文件生成
- 文件属性、权限信息、记录具体内容的block编号记录在inode中,inode是新生成文件
- 文件具体内存记录在block中,block是新生成文件
- 因为文件名的记录是在目录的block当中,「新增/删除/更名文件名」与目录的w权限有关
所以在Linux/Unix中,文件名称只是文件的一个属性,叫别名也好,叫绰号也罢,仅为了方便用户记忆和使用,但系统内部并不需要用文件名来定为文件位置,这样处理最直观的好处就是,你可以对正在使用的文件改名,换目录,甚至放到废纸篓,都不会影响当前文件的使用,这在Windows里是无法想象的。比如你打开个Word文件,然后对其进行重命名操作,Windows会告诉你门儿都没有,关闭文件先!但在Mac里就毫无压力,因为Mac的操作系统同样采用了inode的设计。
创建文件过程
当在ext2下建立一个一般文件时, ext2 会分配一个inode 与相对于该文件大小的block 数量给该文件
- 例如:假设我的一个block 为4 Kbytes ,而我要建立一个100 KBytes 的文件,那么linux 将分配一个inode 与25 个block 来储存该文件
- 但同时请注意,由于inode 仅有12 个直接指向,因此还要多一个block 来作为区块号码的记录
创建目录过程
当在ext2文件系统建立一个目录时(就是新建了一个目录文件),文件系统会分配一个inode与至少一块block给该目录
- inode记录该目录的相关权限与属性,并记录分配到的那块block号码
- 而block则是记录在这个目录下的文件名与该文件对应的inode号
- block中还会自动生成两条记录,一条是.文件夹记录,inode指向自身,另一条是..文件夹记录,inode指向父文件夹
从目录树中读取某个文件过程
- 因为文件名是记录在目录的block当中,因此当我们要读取某个文件时,就一定会经过目录的inode与block ,然后才能够找到那个待读取文件的inode号码,最终才会读到正确的文件的block内的资料。
- 由于目录树是由根目录开始,因此操作系统先通过挂载信息找到挂载点的inode号,由此得到根目录的inode内容,并依据该inode读取根目录的block信息,再一层一层的往下读到正确的文件。
举例来说,如果我想要读取/etc/passwd 这个文件时,系统是如何读取的呢?
先看一下这个文件以及有关路径文件夹的信息:
$ ll -di / /etc /etc/passwd
128 dr-xr-x r-x . 17 root root 4096 May 4 17:56 /
33595521 drwxr-x r-x . 131 root root 8192 Jun 17 00:20 /etc
36628004 -rw-r-- r-- . 1 root root 2092 Jun 17 00:20 /etc/passwd
于是该文件的读取流程为:
- /的inode:
- 通过挂载点的信息找到inode号码为128的根目录inode,且inode规定的权限让我们可以读取该block的内容(有r与x)
- /的block:
- 经过上个步骤取得block的号码,并找到该内容有etc/目录的inode号码(33595521)
- etc/的inode:
- 读取33595521号inode得知具有r与x的权限,因此可以读取etc/的block内容
- etc/的block:
- 经过上个步骤取得block号码,并找到该内容有passwd文件的inode号码(36628004)
- passwd的inode:
- 读取36628004号inode得知具有r的权限,因此可以读取passwd的block内容
- passwd的block:
- 最后将该block内容的资料读出来
其他分区类型
连续分配
顾名思义, 就是创建文件的时候, 给分配一组连续的块。在单独拿出一块地方存储各个文件的meta信息, meta信息也很简单, 包含文件名, 起始位置和长度即可, 这个存放meta信息的地方也叫做FAT(文档分配表)。
如下图:
该方案的优点:
- 简便, 适用于一次性写入操作;
- 所需磁盘寻道次数和寻道时间最少;
缺点也很明显:
- 文件不能动态增长, 因为后面的块可能已经分配给别人了;
- 不利于文件的插入和删除, 插入文件之前需要声明文件大小;
- 外部碎片问题;
链式分配
链式分配即将文件块像链表一样管理起来, 每个块中放一个指针, 指针指向下一个文件块所在的位置。这样在FAT中存储也很简单, 只需要存储文件名, 起始块号和结束块号(都可以不存)。
如下图:
该方案的优点:
- 提高磁盘利用率, 没有碎片问题
- 有利于文件的插入, 删除
缺点:
- 存取速度慢, 需要移动的磁道次数多, 寻道时间长;
- 读写任何一个地方都需要沿着指针前进直到找到对应块为止;
- 链接占据了一定的磁盘空间, 数据不是严格按照块大小分配;
索引分配
这是一个折衷方案, 也是现在大部分文件系统采用的方案, 他综合了连续分配和链式分配的好处。
该方案会在FAT中保存所有文件块的位置, 各文件系统都有一套自己对应的细节分配策略, 会保证一个文件尽量连续的同时, 又避免出现大量的磁盘碎片。
如下图:
该方案的优点是:
- 能够保持好大部分文件的局部性
- 满足文件插入, 删除的高效
- 随机读写不需要沿着指针前进
缺点:
- 会有较多的磁盘寻道次数
- 索引表本身管理复杂, 也会带来额外的系统开销