Linux 文件系统和磁盘结构是一个非常核心且底层的话题。下面从物理磁盘结构开始,一步步讲到Linux 如何组织文件系统,最后重点讲解目前最常用的 ext4 文件系统结构。
1. 磁盘的物理结构(从最底层看起)
现代磁盘(HDD 或 SSD)的最小读写单位已经演变,但传统机械硬盘的结构仍然是理解基础:
- 扇区 (Sector):磁盘最小的物理读写单位
- 传统:512 字节
- 现代(4Kn / Advanced Format):4096 字节(4KB)
- 块 (Block):文件系统层面的最小分配单位
- Linux 常用:1KB、2KB、4KB(最常见是 4KB)
- 柱面-磁头-扇区 (CHS) → 现代基本不用了,被 LBA(Logical Block Addressing) 取代
- LBA:逻辑块寻址,从 0 开始编号的连续逻辑扇区
一个典型的机械硬盘物理结构示意:
盘片(一面或多面)
↓
磁道(Track,同心圆)
↓
扇区(Sector,磁道被切分成的小段)
2. 分区表(MBR vs GPT)
磁盘在使用前必须分区,分区表记录每个分区的起止位置。
| 类型 | 最大分区数 | 最大单分区容量 | 特点 |
|---|---|---|---|
| MBR | 4 主分区 | 2TB | 老旧,兼容性好 |
| GPT | 128+ | 很大(理论9.4ZB) | 现代标准,支持大盘,UEFI 首选 |
Linux 下常见设备名:
/dev/sda、/dev/nvme0n1(整块盘)/dev/sda1、/dev/nvme0n1p1(分区)
3. 文件系统在磁盘上的整体布局(以 ext4 为例)
Linux 最经典的文件系统是 ext 家族(ext2 → ext3 → ext4),目前 ext4 仍是默认选择。
一个 ext4 文件系统的磁盘布局大致如下:
Block Group 0
├── 引导扇区(可选,1 sector,通常不属于文件系统)
├── 超级块 (Superblock) 1024 字节,从 1KB 偏移开始
├── 块组描述符表 (Group Descriptor Table, GDT)
├── 预留 GDT 块(用于在线扩展)
├── Block Bitmap(本组数据块使用位图)
├── Inode Bitmap(本组 inode 使用位图)
├── Inode Table(inode 表)
└── Data Blocks(真正存放文件数据)
Block Group 1、2、3 …… (结构类似,但超级块和 GDT 只有部分组有备份)
重要概念:Block Group
- ext4 把整个分区划分成多个 Block Group(块组)
- 每个块组大小通常是 128MB(当 block size = 4KB 时)
- 为什么分块组?为了减少寻道时间,提高局部性
超级块和 GDT 的备份策略(稀疏备份):
- 块组编号为 0、3、5、7、9、… 的幂次或特定组才会备份超级块和 GDT
- 防止单个超级块损坏导致整个文件系统崩溃
4. ext4 核心数据结构详解
4.1 超级块 (Superblock)
存放全局信息,大小 1024 字节,主要字段:
- 文件系统块大小(1KB~64KB,通常 4KB)
- 总块数、总 inode 数
- 每组块数、每组 inode 数
- 空闲块数、空闲 inode 数
- 挂载次数、最后写入时间
- 文件系统 UUID、卷标
- 特性标志(extent、journal、flex_bg 等)
4.2 块组描述符 (Group Descriptor)
每个块组一个,描述本组情况:
- 本组 block bitmap 位置
- 本组 inode bitmap 位置
- 本组 inode table 起始块
- 本组空闲块数、空闲 inode 数、已用目录数
4.3 inode(最重要的结构!)
Linux 中“一切皆文件”,而 inode 就是文件的“身份证”。
每个文件(包括目录、设备文件、符号链接等)都有一个 inode。
一个 inode 大小通常 256 字节(ext4 默认)。
inode 包含的内容(不包含文件名!):
- 文件类型(普通文件、目录、符号链接、块设备、字符设备、管道、socket…)
- 权限(rwxrwxrwx + setuid/setgid/sticky)
- 拥有者 UID、GID
- 文件大小(字节数)
- 时间戳(mtime、atime、ctime、crtime)
- 链接计数(硬链接数)
- 数据块指针(ext4 使用 extent tree)
注意:文件名 存储在父目录的数据块中,而不是 inode 里。
4.4 数据存储方式对比(ext2/3 vs ext4)
| 文件系统 | 直接指针 | 单间接 | 双间接 | 三间接 | 最大文件大小(4KB block) |
|---|---|---|---|---|---|
| ext2/3 | 12 | 1 | 1 | 1 | ≈ 2TB |
| ext4 | Extent 树 | — | — | — | 很大(单文件最大 16TB+) |
ext4 使用 extent(连续区段)代替传统的指针链表,大幅减少碎片,提高大文件性能。
5. 文件 → inode → 数据块 的查找流程
举例:你要打开 /etc/passwd
- 从根目录
/开始 → 找到根 inode(通常是 inode 2) - 读取根 inode → 找到它的数据块(里面存的是根目录项)
- 在根目录数据块中找到
"etc"的目录项 → 得到 etc 的 inode 号 - 根据 inode 号定位到对应的 inode
- 读取 etc 的 inode → 找到它的数据块
- 在 etc 数据块中找到
"passwd"的目录项 → 得到 passwd 的 inode 号 - 读取 passwd 的 inode → 找到数据块位置
- 读取数据块 → 得到文件内容
这就是为什么删除文件后数据不一定立刻消失,但inode 被清空后就找不到了(除非有硬链接)。
6. 常见 Linux 文件系统对比(2025–2026 视角)
| 文件系统 | 日志 | 最大文件 | 最大分区 | 快照 | 校验和 | 主流发行版默认 |
|---|---|---|---|---|---|---|
| ext4 | 有 | 16TB | 1EB | 无 | 无 | 大多数 |
| XFS | 有 | 8EB | 8EB | 无 | 元数据 | RHEL/CentOS |
| Btrfs | 有 | 16EB | 16EB | 有 | 有 | openSUSE、Fedora |
| ZFS | 有 | 16EB | 16EB | 有 | 有 | 不原生 |
| f2fs | 有 | — | — | 无 | 无 | 手机闪存 |
小结:从磁盘到文件名的一条完整链路
物理磁盘 → 分区表(MBR/GPT) → 文件系统(ext4) → 超级块 → 块组 → inode 表 → inode → 数据块指针(extent) → 文件内容
文件名存在父目录的数据块里,而不是 inode 里。
如果你对某一部分想更深入(例如 extent 树结构、日志机制、目录项格式、debugfs 使用、btrfs vs ext4 对比等),可以告诉我,我可以继续展开讲解。