该方案的优点:
- 简便, 适用于一次性写入操作;
- 所需磁盘寻道次数和寻道时间最少;
缺点也很明显:
- 文件不能动态增长, 因为后面的块可能已经分配给别人了;
- 不利于文件的插入和删除, 插入文件之前需要声明文件大小;
- 外部碎片问题;
为了克服连续分配的问题, 又进化出来了链式分配方案。
链式分配
链式分配即将文件块像链表一样管理起来, 每个块中放一个指针, 指针指向下一个文件块所在的位置。这样在FAT中存储也很简单, 只需要存储文件名, 起始块号和结束块号(都可以不存)。
如下图:

该方案的优点:
- 提高磁盘利用率, 没有碎片问题
- 有利于文件的插入, 删除
缺点:
- 存取速度慢, 需要移动的磁道次数多, 寻道时间长;
- 读写任何一个地方都需要沿着指针前进直到找到对应块为止;
- 链接占据了一定的磁盘空间, 数据不是严格按照块大小分配;
索引分配
这是一个折衷方案, 也是现在大部分文件系统采用的方案, 他综合了连续分配和链式分配的好处。
该方案会在FAT中保存所有文件块的位置, 各文件系统都有一套自己对应的细节分配策略, 会保证一个文件尽量连续的同时, 又避免出现大量的磁盘碎片。
如下图:

该方案的优点是:
- 能够保持好大部分文件的局部性
- 满足文件插入, 删除的高效
- 随机读写不需要沿着指针前进
缺点:
- 会有较多的磁盘寻道次数
- 索引表本身管理复杂, 也会带来额外的系统开销
基本概念
- 块. 即Block, 数据存储的最小单元, 每个块都有一个唯一的地址, 从0开始, 起源于第一个可以用来存储数据的扇区;
- 超级块. 超级块保存了各种文件系统的meta信息, 比如块大小信息。他位于文件系统的2号和3号扇区(物理地址), 占用两个扇区大小;
- 块组. 所有的块会划分成多个块组, 每个块组包含同样多个块, 但是可能整个文件系统整个块数不是块组的整数倍, 所以最后一个块组包含的个数可能会小于其他块;
总体结构
一个ext文件系统分成多个块组, 每个块组的结构基本相同, 如下:

解释如下:
- 0~1号扇区: 引导扇区. 如果没有引导代码, 则这两个扇区为空, 全部用0填充;
- 2~3号扇区: 超级块, 超级块包含各种meta信息:
- 块大小, 每个块组包含块数, 总块数, 第一个块前保留块数, inode节点数, 每个块组的inode节点数
- 卷名, 最后挂载时间, 挂载路径, 文件系统是否干净, 是否要调用一致性检查标识
- 空间inode节点和空闲块的记录信息, 在分配inode节点和新块的时候使用
- 组描述符表:
- 位于超级块后面的一个块, 注意在超级块之前只占用了4个扇区, 如果一个块大小超过4个扇区的话, 这里就会有空的扇区。
- 组描述符表中包含了所有块组的描述信息, 每个块组占据32个字节(差不多是8个整数的大小)。如果格式化使用默认参数, 那么组描述符表不会超过一块块组。
- 组描述符和超级块在每个块组中都有一个备份, 但是激活了稀疏超级块特征的情况除外。
- 稀疏超级块即不是在所有块组中都存储超级块和组描述符的备份, 默认该策略被激活, 其策略类似当块组号是3,5,7的幂的块组才存副本。
- 块位图表
- 每个块对应一个bit, 只包含了本块组的信息。而文件系统创建的时候, 默认每个块组包含的块数跟每个块包含的bit数是一样的, 这种情况下每个块位图表正好等于一个块的大小。
- 而该位图表的块的起始位置会在组描述符表中指定, 大小则为块组中包含块数个bit。
- inode位图块
- 跟块位图表类似, 通常情况他也只占用一个块。通常一个块组中的inode节点数会小于block数量, 所以其不会超过一个块大小。
- inode节点表
- 每个inode都占用128位的一个描述信息, 起始位置在组描述符中表示, 大小为inode节点数*128。
- 数据区
- 这就是真正存储数据的区域。
块大小为4096的时候, 各部分和扇区对应关系如下图:
