---
layout: post.njk
source: https://yage.ai/share/btrfs-design-story-20260818.html
speaker: yage.ai
title: Btrfs 从零讲起：一个写盘动作换来的能力和账单
date: '2026-08-18'
summary: 文章深入探讨了 Btrfs 文件系统从底层写盘动作（写时复制）如何决定其特性，并分析了这种机制带来的能力与代价。它对比了 Btrfs 与传统文件系统（如 ext4）在快照、数据校验、空间管理等方面的差异，阐述了 Btrfs 如何通过统一的写路径实现多项高级功能，同时也指出了其在磁盘碎片、空间计算和断电恢复等方面的具体账单和潜在风险。
area: tech-engineering
category: software-development
tags:
  - btrfs
  - cow
  - snapshot
  - data-integrity
  - storage-architecture
people: []
companies_orgs: []
products_models: []
media_books: []
draft: true
status: evergreen
---

装系统走到磁盘分区格式化那一步，满屏幕文件系统列出来，大部分人习惯性敲回车选
ext4。旁边其实一直趴着个
Btrfs，很多人扫一眼就直接跳过。它同样是负责把数据落进物理磁盘，脾气却跟老牌文件系统大相径庭。

说白了，这份脾气全由底层的一个写盘动作决定。Btrfs
改文件从来不在原地覆盖，而是先找一处空白盘区把新内容写好，再把上层的指针移过去，老内容安稳留在原地。就这么一个简单的动作，既买来了它所有的看家本领，也欠下了后面的全部账单。琢磨透这笔交换，一行命令都不用记，就能看明白它怎么一步步演进到现在的形态，2026
年手头的机器到底该不该选它，心里自然有数。

## 2007 年，Linux 存储卡在哪

看懂 Btrfs 得把视线拉回 2007 年，看看当年 Linux
存储到底在为哪些麻烦事发愁。那时候整个社区眼前摆着几块难啃的心病。

最直接的刺激来自隔壁阵营。2005 年 Sun 推出
ZFS，把快照、数据校验、多盘存储池这几项分散的功能整合成一层，整个存储业界为之震动。Linux
这边眼馋归眼馋，偏偏 ZFS
的许可证和 Linux
内核不兼容，代码没法并入主线，头顶还顶着专利风险。当时内核核心开发者
Andrew Morton 甚至公开批评这种设计是层次违规，这句话经 OSNews
转述才流传开来。想要类似的本领，Linux 只能挽起袖子自己从零造。

另一块心病是全盘检查太耗时间。文件系统在磁盘上记账，突发断电容易把账目搞乱，重启就必须跑一遍全盘检查才敢继续用。磁盘容量年年见涨，检查耗时跟着水涨船高。这亏
Linux 社区早就吃过一次：后来主导 ext4 开发的 Ted Ts’o 回忆，早在
2000、2001 年，40 到 80GB
的磁盘就扫得人发狂，社区的一片呼声直接催生出带日志的
ext3，断电后靠回放日志省去全盘检查。可这招只省掉了检查这一步，更深处的问题没动：ext
家族只负责账本元数据对不对，从不管文件内容本身；硬盘要是悄悄吐出损坏的数据，只要格式合规，系统完全没有手段察觉。

还有一套折磨人的麻烦是积木拼装。想用快照得靠 LVM
在底层划逻辑卷，想做多盘冗余又得加一层 md
组阵列，文件系统再扣在最上面。三层各自为政，互相并不知情。当时论坛评论留着一份操作清单：日常调个分区大小，得先卸载、跑检查，接着缩文件系统、缩逻辑卷，连敲四五个命令，还得祈祷两个工具对容量数字的换算别打架。

2007 年 11
月，各家公司的文件系统工程师坐到一起开工作坊，台上的直接由头就是 ZFS
铺天盖地的营销攻势。大家当场定了两条路：短期给 ext3
加扩展，做成次年才转为稳定版本的
ext4；长期另起炉灶，做支持快照和校验的新文件系统。短期这条路后来确实兑现了：ext4
能把 ext3 上要跑 45 分钟的检查压到 4 到 5
分钟，可文件内容本身依旧没人看管，这正是长期路线要补的洞。选来选去，挑中了
Oracle 工程师 Chris Mason 刚刚起步的 Btrfs。Ts’o
在会上给所有人泼了冷水，直言一个企业级文件系统要
50 到 200 人年、五年日历时间，ZFS 本身也是 2001 年动工、2006
年才端出来的。当时大家生怕吓跑金主投资，都拍胸脯说两三年就能搞定。后来
Ts’o 回顾结果，各发行版直到 2012
年秋天核准消费级可用，算下来一天没少，正好五年。

## 一个写盘动作定了它的性格

Btrfs 所有的机制都从一个动作起步：改文件，不去覆盖硬盘上的旧数据。它每次修改，都是先把改动后的内容写进空白位置，等数据全部落盘，再把指向它的入口指针改过去。这种写法叫写时复制，先写新的，再移指针。指针没挪过去之前，原先的数据原封不动；指针一旦切过去，新内容立刻生效。旧数据就安稳留在原处，直到再也没有任何地方引用它。

写入方式这么一变，快照立刻变得跟白送一样轻松。所谓快照，无非是给文件系统在某一瞬间存个状态，方便以后随时跳回来。传统的做法要么把数据硬拷贝一份，要么靠
LVM 在底层战战兢兢预留空间切卷。Btrfs
做快照只需要新建一个索引入口，指向现成的数据块，盘上的实体数据一个字节都不用搬。官方文档原话就是：the
snapshot is instantaneous and only creates a new tree root
copy。

伴随这个写盘动作，坏数据当场暴露。每个数据块落盘前都会算出一串校验值，如同给内容盖上钢印；读数据时重新算一遍，数值对不上马上报错。老
ext
家族没有这套机制，硬盘默默返回损坏的数据，系统会毫无知觉收下，甚至顺手打包进备份文件。有了钢印，脏数据就休想混进备份链条。不过要想把坏块修好，手里得有另一份完好的副本；单盘环境只有一份数据，校验机制负责把问题大声喊出来，修复则必须等冗余副本就位。

在线挪动磁盘也顺理成章。它的索引结构里自带反向引用，文件系统随时清楚每个数据块具体躺在哪块物理盘上。日常想加盘、拔盘、扩容或者缩小分区，直接在线执行就行，不需要折腾三层工具费力接力。

妙处在于，快照、校验、压缩和多盘管理这些特性全部挂在同一条写入路径上。这正是它跟老式拼装方案的分水岭：拼装方案是三套工具各管一段，Btrfs
则是一层统管，所有能力全从同一个写盘动作里流淌出来。

回头看 2007
年那三个卡点，病根全是原地覆盖写：新内容一落盘，旧状态就没了。旧状态留不住，快照只能靠外层工具先抄一份；校验找不着统一点，只能各做各的；分配权不在手里，多盘只能外面再包一层。Btrfs
改掉了这个默认行为。旧数据不销毁，旧状态仍躺在盘上，快照只需新建入口指过去；所有对象走同一条写路径，校验一次挂上全局生效；分配权收归自身，加盘拔盘在线就能做；突发断电后账本要么停在旧入口、要么切到新入口，理论上不存在半新半旧，ext2
时代那种全盘检查从原理上不再需要。三个解法全来自这同一个动作的兑现。

别把这笔交换记成 Btrfs 优化写、ext4 优化读的对称。准确的账是：Btrfs
用读取的局部性，换落盘的历史。写入当下反而更快，因为永远挑连续空位落笔；吃亏的是反复修改的大文件回头读，数据块散落一盘。ext4
并未参与这笔交易：原地覆盖，文件落在哪就待在哪，两头都不付账，它没有校验、快照与内置多盘，当年也未曾竞标这些。这也解释了为什么数据库跑在
Btrfs
上最吃力：数据库自己管页的物理布局，写时复制偏偏冲散了这套布局，后面的性能开关
+C 就是为此准备的豁免通道。

## 同一个动作签下的账单

一个写盘动作的两侧：买到与签下

天下没有免费的午餐。换来这些好处的同时，写盘动作也签下了一串账单，每一笔都是这个机制带来的直接后果，可别把它们看成孤立的偶发毛病。

最先找上门的是磁盘碎片。旧数据不覆盖，新数据落新地，频繁改动的文件切片很快就七零八落散在盘上各处。官方手册自己承认：In
COW filesystems, files tend to fragment as they are modified。Mason
自己给过解释（2015 年 NYLUG 演讲的 YouTube
自动字幕）：写入因为只挑连续空地反而更快，但代价全压给了后续的读取；数据库原本为顺序读精心规划的物理布局，全搅成一团乱麻。虚拟机镜像、数据库还有经常原地改写的大文件，都是替这笔账买单的常客。

再看空间管理，它把磁盘分成了两本账。放文件实体的块组一块大约
1GiB，放目录结构的块组一块大约
256MiB，彼此分开核算。这就会引发一种让人摸不着头脑的怪事：明明显示磁盘还有剩余空间，存东西却报空间不足，原因其实是目录结构那本账先用光了。这时候想删几个大文件腾地方，偏偏删除操作也得写目录，结果连删文件都删不掉。这属于机制带来的正常逻辑，官方文档至今建议每卷留出 10GB
余量，快照控制在 12 个以内。

断电后的表现形式同样棘手。写时复制能保证账本完整，前提是物理硬盘按部就班遵守写入顺序。账本不乱并不代表开机就能顺顺当当：要是索引树出了差错，开机直接挂载失败跌进救援终端，需要输入专门的命令去修复。平时大家几乎不接触救援环境，真遇到了容易抓瞎。2025
年夏天出现过一波集中踩坑，一个潜伏挺久的 bug 在内核 6.15.3
变得非常容易触发，断电重启卡死在日志回放阶段。维护者确认了问题，主线修复排进
6.17，Fedora 也在 6.15.9
的补丁包里关闭了对应工单。这类问题露在用户眼前的样子足够反常：硬件和性能看着都好好的，偏偏就是进不去系统。

性能调节开关也是个暗坑。针对数据库或虚拟机文件打上 +C
属性，能关闭写时复制，随机写入性能马上回血。官方文档明确注明：加了这个标记，系统会连带停掉这批文件的数据校验。你想，为了抢性能，反而在最怕静默损坏的大文件上把刚换来的钢印给摘了。systemd
默认给系统日志目录加 +C，虚拟化组件 libvirt
也常给虚拟机镜像加，好多人对此浑然不觉。

至于多盘阵列欠下的那笔债，牵涉更多，得单独拉出来细说。里面的坑到现在都没能填平。

## 多盘的野心，和还没还清的债

卷管理和文件系统合体之后，Btrfs
顺理成章获得了统领多块磁盘的权力。两块盘做镜像，两边各自留一份完整数据，哪边读出坏块就从另一边拉数据修复，校验机制在这里才算实现了完整的自愈闭环；多块盘也能切片条带化，把读写吞吐拉上去。然而它的野心不止于此，它还想把
RAID5/6
收入囊中，也就是通过奇偶校验让挂掉一块盘时能靠剩下的算回数据。偏偏这块硬骨头，到现在都没能啃利索。

翻开官方状态页（对应内核
7.1），RAID5/6 的栏目依然赫然写着 unstable，手册也直言 should not be
used in production。问题的核心在 write hole
这个老毛病。遭遇意外断电，一条数据可能处于新旧各写了一半的状态，底层的校验码到底锚定哪一半谁也说不清。系统重新开机，很可能拿损坏的脏数据当成参考标准，反手把完好的数据给覆盖修坏了。想堵住这个漏洞，要么引入写日志，要么每次老老实实做全量读改写。当年全量读改写因为性能太差落选，写日志机制又迟迟没做出来。两头落空，漏洞便一直留到了现在。

官方版本史里关于
6.2
的复盘讲得直白：当年为了抢性能把读改写步骤直接砍掉，成了日后所有可靠性隐患的源头。2023
年发布的 6.2 内核合入了一部分补丁，但 RAID6 仍有大量工作待完成；新的
stripe tree
架构已经进入实验分支，官方口径认为这条路线最终会解决现有问题。这笔设计初期欠下的技术债，到今天依然在分期偿还。

## 十九年补课，补到了哪

算上 2009 年合并进 Linux 主线的时间，Btrfs
这十几年走过的路活脱脱就是一张长长的补课单。断电时空间写满报错的问题，2010
年才收尾第一轮修复；管理空闲空间的缓存机制，2011 年拿出第一版，2016
年推倒重写成 B 树，到 2021 年才扶正为默认配置，最早的那套实现直到 2024
年才正式标为废弃。据双源转述，磁盘物理格式在 2013 年 11
月宣布稳定，自那之后创建的分区，后续新内核都能直接挂载。2023
年它在修多盘读改写逻辑，2025 年还在排查 6.15.3 的日志回放故障。

对照着这条时间线，也能明白为什么它早年口碑相当糟糕。2011
年前后，论坛上时不时能看到笔记本用户丢光整盘数据、或者空闲空间充足却写不进数据的求助。这些风波大部分集中在物理格式冻结的前后几年。2017 年 Red Hat 宣布把
Btrfs 挡在转正门外，到 RHEL 8
干脆整棵剔除，官方给出的口径是技术预览功能从未打算转正，通篇没提一句丢数据。早年那些糟糕体验确实存在过，只不过那些血泪史对应的旧代码，跟今天大家手头跑的版本隔了十多年的密集修补。

## 2026 年，谁适合用它

2026 年 Btrfs 使用面板

要拿捏选型尺度，还是得回到那个写盘动作。它的长处和短板本就是一枚硬币的两面，到底合不合适，全看日常需求是恰好用上它的特性，还是迎头撞上它的账单。

真能发挥它长处、可以闭眼选的，首推单盘系统盘。两大发行版已经用默认配置帮大家站台多年：SUSE
系列把系统盘默认设为
Btrfs，配合自动化快照，系统更新翻车了开机选前一天的镜像就能回滚，属于开箱即用的完整体验；Fedora
桌面版也默认使用
Btrfs，不过官方写得很清楚，系统不自带自动快照回滚，想用得手动配工具。发行版的默认选型往往最能说明问题。对那些经常折腾内核、驱动或者频繁大版本升级的机器，快照回滚能省下大把时间。两块盘组镜像同样省心，官方给的评级是
OK，坏块能靠镜像自动补全，自愈闭环这才完整。

容易踩雷、建议绕着走的场景也要心里有数。想搭 RAID5/6
阵列，踏踏实实用底层传统阵列工具组好，上层直接格式化成普通文件系统，避开
Btrfs
原生阵列。承载数据库和虚拟机镜像的目录，要么默默承受碎片折磨，要么手动加上
+C 属性；顺便提醒一句，加了 +C
之后这部分文件就享受不到校验保护了。跑容器服务也没必要折腾存储驱动，官方文档写明即使底层在
Btrfs 上也建议继续用
overlay2。要是不想花心思理解两本空间账，日常使用也要留神，剩余容量读数容易产生误导，快照也会在后台不知不觉占满磁盘。

最后交代两句关于技术边界的实话。快照算不上备份，快照和原本的数据共用一套底层存储块，物理硬件损坏两边一起遭殃，官方文档一句话收尾：A
snapshot is not a
backup。校验码确实能揪出硬盘悄悄吐出的损坏数据，在有多余副本时把它救回来；但它拯救不了一块硬件故障无法读取的坏盘，更没法代替异地容灾；把错误找出来跟把数据修好，是两码事。

想通了底层写盘的这一笔交换，比死记硬背任何功能清单都管用。以后 Btrfs
再出新功能或者爆出新隐患，顺着这个核心动作一推就能明白原委。这个琢磨方式看别的底层软件同样行得通：摸清它最底层的那个关键动作，看它换来了什么本领、欠下了什么代价，后面的所有设计取舍自然一清二楚。