Btrfs 快照是带有源初始内容的新子卷,通过共享已有文件 extent 保留视图,而不是逐块复制全部数据。创建会复制根部元数据,也可能等待源中的脏数据刷出,因此不能承诺无论大小都在毫秒内完成。同一 extent 还可能同时被多个快照或 reflink 引用,不存在固定只能引用两次的规则。共享数据与完全没有创建成本,是不同的判断。
快照让本地恢复点较为经济,但成本包含元数据以及后续分岔保留下来的旧块。它与源共用整个文件系统的存储池,而文件系统可能跨多块设备,并不一定只在一块磁盘上。快照数量持续增加时,已删除或覆盖的数据仍可能被保留。即使设置为只读,同一文件系统内的快照也不是独立备份,不能把版本数量当作故障隔离程度。
共享 extent,而不是复制数据块
快照是有独立根的子卷。示例 btrfs subvolume snapshot -r "$src" "$snap" 请求只读快照,普通快照则可以写入。只读标志限制通过这个子卷进行的普通修改,不防管理员删除或底层损坏。快照不是递归操作:嵌套子卷在其中只是空的占位目录,其内部文件不会自动包含进来。恢复计划必须另行处理这些子卷,不能只检查顶层目录是否存在。
共享 extent 被修改时,写时复制为其余引用保留旧内容。实际分配受到 extent 布局、压缩、元数据和后续快照影响,不能简单等同于应用写了多少字节。原文中的 APFS 克隆数字不是 Btrfs 测量,本次也没有找到其原始轨迹;不能用它们证明创建零成本,或同一范围第二次覆盖时 Btrfs 一定不再分配。跨文件系统类比只能解释思路,不能替代本系统验证。
空间到底去了哪里
btrfs filesystem du 通过 FIEMAP 报告文件 extent 的 Total、Exclusive 和 Set shared。每个参数各自定义递归扫描的文件集合,Set shared 统计该集合引用的共享范围并处理重叠,并非只统计与其他命令行参数之间的共享。compsize 显示面向压缩的 Disk Usage、Uncompressed 与 Referenced,不是相同三列。qgroup 则要求先启用配额并保持统计一致,不能把缺失统计解释成零占用。
删除源不会释放仍由快照或 reflink 引用的 extent;只有其他引用都消失时,它才可能成为某个快照的独占数据。删除子卷还分为移除目录和后台清理两个阶段,所以空间不一定立即归还。df 反映文件系统整体容量,不能把每个未释放字节精确归到某一份快照。设计保留周期时,需要同时考虑共享关系与后台回收,而不是只数目录数量。
还原点不是副本
本地快照可以保留有用的文件系统视图,却不自动保证应用一致性。数据库可能需要协调备份步骤、保留日志,并在还原后执行恢复;应用尚未交给文件系统的缓冲内容不在快照里。源与快照也共享底层故障风险。回滚并非固定时间完成的保证,更不能替代应用启动及内容正确性的验证;文件能列出和业务能恢复,应分别记录。
btrfs send 生成供另一个文件系统的 btrfs receive 使用的数据流。增量 -p 依赖两端都存在且未被改变的合适父快照,参与发送的所有快照都必须只读。独立存储只能隔离它没有共同承受的故障,还要验证接收成功、保留策略和还原内容。快照频率更高也不保证每次传输都按固定比例缩小,变化模式和参考快照同样影响结果。
坏掉的样子
删除大目录后空间几乎不变,应先检查快照及 reflink 引用,再决定是否继续删除。btrfs filesystem du -s 与 qgroup 提供不同口径,某一个 Exclusive 值不一定解释全部差额。清理恢复点之前还要核对保留要求和发送依赖。多个快照可能共同保留某些块,即使没有任何一份单独独占它们,所以不能仅按最大独占值猜测可释放容量。
写时复制需要为数据及元数据保留分配余量。用 btrfs filesystem usage 分别观察两者;设备尚未分配的空间,与已分配块组内部仍空闲的空间不是同一指标。不能从这些计数推出统一百分之五余量就足够,也不能断言两种空间总按固定顺序耗尽。一次分配失败本身同样不证明文件系统已切成只读,应结合真实错误与状态判断。
快速验证
以下是尚未执行的有限检查。它要求已授权的一次性源子卷 /mnt/btrfs-lab/data、同一 Btrfs 文件系统中已存在的 snapshots 父目录,以及所需工具和权限。所有路径组件必须无符号链接,并在整个检查与创建过程中由本实验独占控制。目标若已是目录,Btrfs 会改变实际创建位置;下方检查拒绝已存在的路径,也拒绝悬空符号链接。这个检查不是防竞态的锁,无法保证独占控制时应停止,不能把示例默默套到生产路径。
(
set -eu
src='/mnt/btrfs-lab/data'
snap='/mnt/btrfs-lab/snapshots/data-2026-09-16'
if [ -e "$snap" ] || [ -L "$snap" ]; then
printf '%s\n' 'Refusing an existing snapshot destination.' >&2
exit 1
fi
btrfs subvolume snapshot -r "$src" "$snap"
btrfs filesystem du -s "$src" "$snap"
compsize "$snap"
btrfs filesystem usage "$src"
)
快照创建与随后的 du、compsize 使用绑定的同一目标;重复运行会拒绝该目标,不会自动删除快照。文件 extent 计数不测量全部快照元数据。Exclusive 等于 Total,只说明当前 extent 不再共享,不能证明该子卷从来不是快照。这不是分岔或还原实验:后续仍须记录已知测试文件的原始字节,确认源与快照起初相同,仅修改源,再确认快照保留旧字节、源包含新字节。相关存储检查及应用恢复仍暂缓,不能把语法通过视为运行通过。
来源
- btrfs 子卷文档,子卷与快照语义,含只读快照,已核验 2026-09-16。
- btrfs filesystem 文档,定义上文所用的
duExclusive 与 Set shared 列,已核验 2026-09-16。 - btrfs qgroup 文档,按 qgroup 统计 exclusive 与 referenced 字节,已核验 2026-09-16。
- btrfs send 文档,发送流生成与只读增量基线要求,已核验 2026-09-16。
- compsize upstream manual,压缩与引用尺寸统计不同于 filesystem du,已核验 2026-10-18。
- PostgreSQL filesystem backup,一致快照范围、WAL 与多卷恢复要求,已核验 2026-10-18。