ext2(Second Extended Filesystem)是Linux经典的非日志文件系统,其设计核心是通过 块组(Block Group) 机制将磁盘空间划分为多个自包含的单元,以平衡寻址效率与容错性。以下从宏观布局到微观结构进行分层说明。
一、总体磁盘布局
ext2将分区划分为固定大小的块(Block,通常为1KB、2KB或4KB),并组织成若干个块组。
┌─────────────────┬─────────────────┬─────────────────┬───────┬─────────────────┐
│ 引导块 │ 块组 0 │ 块组 1 │ ... │ 块组 N │
│ (Boot Block) │ (Block Group 0)│ (Block Group 1)│ │ (Block Group N)│
│ 1024字节 │ │ │ │ │
└─────────────────┴─────────────────┴─────────────────┴───────┴─────────────────┘
说明:
- 引导块:位于分区起始处(偏移0),大小为1KB,存储引导加载程序(如GRUB)。若该分区非启动分区,则此块为空。
- 块组 :后续空间被均匀划分为若干块组。每个块组内部维护一份超级块和块组描述符表的备份(稀疏备份策略下并非每个块组都有),以实现冗余恢复。
二、块组内部结构
每个块组的逻辑结构如下所示:
┌─────────────────────────────┐
│ 超级块 (Superblock) │ ← 块组0必需;其他块组为备份(可选)
│ 1 block │
├─────────────────────────────┤
│ 块组描述符表 (GDT) │ ← 描述所有块组的状态信息
│ 1+ blocks │
├─────────────────────────────┤
│ 保留块 (Reserved Blocks) │ ← 通常为GDT预留的扩展空间(可选)
│ │
├─────────────────────────────┤
│ 数据块位图 (Block Bitmap) │ ← 1 block,追踪本组数据块的分配状态
│ │ (每bit对应1个block)
├─────────────────────────────┤
│ Inode位图 (Inode Bitmap) │ ← 1 block,追踪本组inode的分配状态
│ │ (每bit对应1个inode)
├─────────────────────────────┤
│ Inode表 (Inode Table) │ ← 固定大小的inode数组
│ (s_inodes_per_group │
│ × inode_size) │
├─────────────────────────────┤
│ │
│ 数据块 (Data Blocks) │ ← 本组剩余所有block,用于存储文件/目录内容
│ │
└─────────────────────────────┘
三、核心元数据结构详解
| 组件 | 大小/位置 | 功能说明 |
|---|---|---|
| 超级块 | 固定于偏移1024字节处(即块1或块0内偏移) | 存储全局参数:总块数、inode总数、块大小、每块组块数、挂载状态、最后挂载时间等。 |
| 块组描述符表 (GDT) | 紧跟超级块 | 每个块组对应一个描述符(32字节),记录该组的块位图位置、inode位图位置、inode表位置、空闲块/空闲inode计数等。 |
| 块位图 | 每组1个block | 按位映射数据块的占用情况。若块大小为1KB,则1个位图block可管理 1024×8 = 8192 个数据块,这直接决定了一个块组的最大容量。 |
| Inode位图 | 每组1个block | 按位映射Inode表中各inode槽位的占用情况。 |
| Inode表 | 每组固定数量 | 存储本组所有inode的详细元数据(除文件名外),包含权限、UID/GID、大小、时间戳、15个块指针等。 |
| 数据块 | 剩余空间 | 实际存储文件内容与目录项。 |
四、Inode 数据寻址机制
ext2通过索引节点中的15个32位块指针定位文件数据。其结构如下:
Inode 块指针数组(15 elements):
┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐
│ 直接块0 │ 直接块1 │ ... │ 直接块11 │ 间接块 │ 二重间接 │ 三重间接│
│ [0] │ [1] │ │ [11] │ [12] │ [13] │ [14] │
└────┬────┴────┬────┴─────────┴────┬────┴────┬────┴────┬────┴────┬────┘
│ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼
数据块 数据块 数据块 指针块 指针块 指针块
↓ ↓ ↓
指针块 指针块 指针块
↓ ↓ ↓
数据块 指针块 指针块
↓ ↓
数据块 指针块
↓
数据块
寻址逻辑:
- 直接指针(12个):直接指向数据块,适用于小文件。
- 间接指针(1个):指向一个指针块,该块中存放数据块地址。若块大小为4KB,则可寻址 1024 个数据块(4KB/4B)。
- 二重间接(1个):指向一个指针块,该块中存放间接指针块的地址。
- 三重间接(1个):指向一个指针块,该块中存放二重间接指针块的地址。
容量估算(以4KB块大小为例):
- 直接:12 × 4KB = 48KB
- 间接:1024 × 4KB = 4MB
- 二重间接:1024² × 4KB = 4GB
- 三重间接:1024³ × 4KB = 4TB
五、目录存储结构
在ext2中,目录是一种特殊文件 ,其数据块中存储的是线性排列的目录项(ext2_dir_entry_2)。结构如下:
目录数据块内部布局:
┌──────────────────────────────────────────────────────────────┐
│ inode号 │ 记录长度 │ 名称长度 │ 文件类型 │ 文件名... │
│ (4 bytes) │ (2 bytes) │ (1 byte) │ (1 byte) │ (变长) │
├──────────────────────────────────────────────────────────────┤
│ inode号 │ 记录长度 │ 名称长度 │ 文件类型 │ 文件名... │
├──────────────────────────────────────────────────────────────┤
│ ... │
└──────────────────────────────────────────────────────────────┘
关键细节:
- 目录项长度(记录长度)通常是4字节对齐,包含末尾填充。
- 文件类型字段(
file_type)缓存了文件类型(普通文件、目录、符号链接等),避免每次都要加载inode。 - 删除文件时,只需将该目录项的inode号置为0,并将该记录长度合并到前一项中(逻辑删除),数据块本身不一定立即释放。
六、块大小与系统限制
| 块大小 | 最大块组容量 | 最大文件系统容量 | 最大单文件容量 |
|---|---|---|---|
| 1KB | 8MB (8192×1KB) | 16TB (2³²×1KB / 受限于块指针) | 16GB |
| 2KB | 16MB | 32TB | 256GB |
| 4KB | 32MB | 16TB~64TB(受具体实现限制) | 2TB |
注:实际限制还受限于块指针位宽、inode结构及内核实现。原始ext2在标准32位系统下最大支持16TB文件系统与2TB单文件。
七、设计特点总结
- 冗余备份:超级块与GDT在多个块组中备份,超级块损坏时可从备用块组恢复。
- 局部性优化:将inode表与数据块置于同一组,减少磁头寻道(尽管现代SSD此优势减弱)。
- 无日志 :ext2不记录日志(journal),写入性能高,但异常掉电后需完整运行
fsck扫描修复。 - 静态分配:创建文件系统时,inode表与块组大小已固定,大数量小文件场景可能耗尽inode而磁盘空间剩余。
这种结构为后续的ext3(增加日志)和ext4( extents、块组元数据校验等)奠定了基础,理解ext2是掌握Linux本地文件系统的关键起点。
封面图来源于网络,如有侵权,请联系删除!