本页目录
文件系统实现
覆盖: ext4 (extent tree/jbd2/delayed allocation) → XFS (AG/B+tree/reflink) → Btrfs (COW/subvolume/snapshot/checksum) → bcachefs (6.7+) 内核版本: 2.6 ~ 6.x
概述
Linux 支持的本地文件系统各有不同的设计哲学:
- ext4: 稳定性优先,journal + delayed allocation,适合通用场景
- XFS: 大规模并行 IO,分配组 (AG) 设计,适合大文件和高并发
- Btrfs: COW + checksum + snapshot,适合 NAS 和需要数据完整性保障的场景
- bcachefs: 新生代 COW 文件系统 (6.7+),copygc + multiple devices + compression
ext4: 稳定的通用方案
Extent Tree
// ext4 使用 extent tree 替代间接块 (ext2/3 的间接/双间接/三间接)
// 一个 extent 描述: "文件偏移 X ~ X+LEN 映射到磁盘块 Y ~ Y+LEN"
;
// extent tree 是一棵 B-tree (在 inode 内或额外的块中)
// ext4_inode->i_data[60] = 4 个 ext4_extent + 1 个 header
// → 前 4 个 extent 直接存在于 inode 中 (无需额外的块读取!)
// → 超过 4 个 → 分裂为 B-tree 节点
// 为什么比间接块更好?
// 间接块: N 个块 → O(N) 查找 (每个块一个指针)
// extent: N 个块 → O(1) extent 覆盖 (连续块用一条记录)
// 碎片化文件: extent tree 可能会有多个节点 → 仍是 O(log N)
jbd2: Journal
// 写操作在 ext4 中的路径:
// 1. 写数据到磁盘 (data)
// 2. 写元数据变更到 journal (metadata)
// 3. 标记 journal commit 完成
// 4. checkpoint: 将 journal 中的元数据写回实际位置
//
// mount 时:
// 检查 journal → replay 已 commit 但未 checkpoint 的事务
// → 恢复一致性 (fsck 很少需要)
// data=ordered (默认):
// 先写数据 → 再写 journal → 数据不会在元数据之前可见
// → 崩溃后文件数据完整 (元数据可能不完整但不会指向垃圾)
// data=writeback:
// 数据可以乱序 → 更快, 但崩溃后可能看到旧数据
Delayed Allocation
ext4 延迟分配:
写操作 → 先在 page cache 中积累 → 不立即分配磁盘块
→ writeback 时 (积累了几秒) → 分配大段连续 extent
→ 减少碎片, 提高顺序写性能
代价:
1. write() 返回成功不代表磁盘空间已分配 → ENOSPC 延迟到回写
2. 崩溃时丢失更多数据 (page cache 中的脏页, 还没分配磁盘块)
fallocate 可以预先分配空间, 避免 ENOSPC 延迟
XFS: 大规模并行
分配组 (Allocation Group)
XFS 将文件系统切分为多个 AG (Administrative Group)
每个 AG 独立管理自己的 inode 和空闲空间 B+tree
→ 多线程可以并行分配 → 避免全局锁
→ 高并发场景 (如多路数据库) 优于 ext4
AGs: [AG 0] [AG 1] [AG 2] ... [AG N]
每个 AG: 有自己的 superblock 副本, inode B+tree, free space B+tree
B+tree 元数据
// XFS 几乎所有的元数据都组织为 B+tree:
// inode B+tree: inode number → inode 数据
// free space B+tree: offset → 空闲 extent
// extent B+tree: file offset → disk extent (per-inode)
//
// B+tree 的通用实现: fs/xfs/libxfs/xfs_btree.c
Reflink 与 COW
XFS 5.x+ 支持 reflink (共享数据块, COW):
cp --reflink=always a b
→ a 和 b 共享相同的数据 extent
→ 任一方修改 → COW → 复制被修改的块 → 各自独立
与 Btrfs 的区别:
XFS reflink 是 extent 级 COW — 不复制整个文件
Btrfs 是文件级 COW — 每个快照/子卷独立写
Btrfs: COW 与数据完整性
COW 架构
Btrfs 的 COW:
所有写操作都写新位置 → 不覆盖旧数据
1. 分配新的 extent 到空闲空间
2. 写入新数据
3. 更新元数据 B-tree 指向新 extent
4. 旧 extent 变为空闲
崩溃安全性:
因为是 COW → 旧数据总是在原地
→ 不需要 journal (快照和 reflink 天然支持)
→ transaction commit = 写 superblock 新根
代价:
碎片化 (频繁 COW → 逻辑连续的数据物理上散布)
写放大 (小修改 → 整个 extent 复制)
核心特性
Snapshots (快照):
btrfs subvolume snapshot . snapshots/$(date +%Y%m%d)
→ O(1) 创建, 不复制数据
→ COW 保证: 修改原始子卷不影响快照
Subvolumes (子卷):
独立的命名空间, 可以单独挂载
类 ZFS 的 dataset 概念
Checksum (校验和):
每个数据块和元数据块都有 checksum (crc32c)
读时自动校验 → 检测 bit rot / 静默损坏
与 RAID1 profile 配合: 检测到损坏 → 从镜像自动修复
Compression:
mount -o compress=zstd → 按 extent 压缩 (zlib/lzo/zstd)
B-tree 森林
Btrfs 的元数据组织:
多种 B-tree (共享 B-tree 代码):
Root tree → 指向其他树的根
FS tree → 文件/目录的 inode (每个子卷一个)
Extent tree → extent 分配情况
Chunk tree → 块组到物理块的映射
Device tree → 设备信息
Csum tree → extent checksum
bcachefs: 新生代 (6.7+)
设计目标: "btrfs 的功能 + ext4/xfs 的性能 + ZFS 的数据可靠性"
作者: Kent Overstreet (bcache 的原作者)
核心特性:
- COW 为主, 可选 journal
- 多设备: 不同磁盘可以承担不同角色
(SSD 做前台/缓存, HDD 做冷数据存储)
- 内建压缩 (zstd/lz4/gzip) + checksum
- 内建加密 (per-extent)
- 子卷 / snapshot
- 磁盘格式稳定 (已合入 mainline 6.7)
与 Btrfs 的区别:
bcachefs 从设计之初就考虑多设备分层
Btrfs 的 RAID 配置文件系统层面, bcachefs 更灵活
文件系统选择
| 特性 | ext4 | XFS | Btrfs | bcachefs |
|---|---|---|---|---|
| 最大卷 | 1EB | 8EB | 16EB | 8EB |
| 最大文件 | 16TB | 8EB | 16EB | 8EB |
| COW | 否 | reflink only | 是 | 是 |
| 快照 | 否 | 否 | 是 | 是 |
| 内建压缩 | 否 | 否 | 是 | 是 |
| 内建 RAID | 否 | 否 | 是 | 是 |
| 校验和 | journal only | journal only | metadata+data | metadata+data |
| 适合场景 | 通用 | 大文件/数据库 | NAS | 实验/多设备 |
参考与延伸
- 内核文档:
Documentation/filesystems/ext4/,Documentation/filesystems/xfs/,Documentation/filesystems/btrfs.rst - LWN:
- "bcachefs merged" (lwn.net/Articles/947587/)
- "Btrfs: design and implementation" 系列
- 源码:
fs/ext4/,fs/xfs/,fs/btrfs/,fs/bcachefs/
关键词: ext4, extent tree, jbd2, delayed allocation, XFS, allocation group, B+tree, Btrfs, COW, checksum, bcachefs