btrfs快照必须在同一子卷内创建,不可跨子卷、设备或挂载点;源须为已存在子卷,目标父目录需有写权限且预先创建;命令格式为btrfs subvolume snapshot ,顺序不可颠倒。

快照必须在同一个Btrfs子卷内创建
你不能跨子卷、跨设备、甚至不能跨挂载点做快照。比如 /mnt/data 是一个独立挂载的 Btrfs 子卷,而 / 是另一个,那从 / 下执行 btrfs subvolume snapshot /mnt/data /backup 会报错 Invalid cross-device link —— 这不是权限问题,是设计限制。
实操建议:
- 先确认目标路径属于哪个子卷:
btrfs subvolume list -a /或btrfs filesystem show - 快照源和目标必须在同一个挂载点下,且目标父目录需有写权限
- 快照本身是只读还是可写,取决于是否加
-r参数;不加默认可写,但修改它不会影响原数据(COW 机制保证)
btrfs subvolume snapshot 命令的路径参数容易搞反
命令格式是 btrfs subvolume snapshot <source><dest></dest></source>,但很多人把顺序记成「目标在前、源在后」,结果报错 No such file or directory —— 实际上是 <source></source> 找不到,因为输反了。
常见错误现象:
- 输入
btrfs subvolume snapshot /snap/my-snap /data,提示/snap/my-snap: No such file or directory(其实是把快照名当源了) - 目标路径的父目录不存在,也会报同个错误,需提前
mkdir -p -
<source></source>必须是已存在的子卷(btrfs subvolume list能列出来),普通目录不行
正确示例:btrfs subvolume snapshot /data /data/snap-20240520
快照不等于备份:删原卷后快照还能用吗?
能,但有前提。Btrfs 快照共享底层 extent,只要没执行 btrfs subvolume delete 且没触发自动清理(如启用 space_cache=v2 且反复写满又清空),快照里的文件就还在。
不过要注意:
- 如果原子卷被
delete,快照仍可访问,但无法再通过subvolume sync强制刷新其引用计数,极端空间压力下可能被误回收(罕见但可能) - 快照本身也是子卷,要长期保留就得单独备份(比如用
btrfs send+btrfs receive流式导出到另一设备) - 别依赖快照防误删:用户 rm -rf 快照目录,就真没了;它不是回收站
只读快照 + 定时清理是生产环境常见组合
日常做系统更新或配置变更前打个只读快照,既避免意外写入污染,也方便比对差异。但没人手动删旧快照,所以得脚本化清理。
实操要点:
- 创建只读快照:
btrfs subvolume snapshot -r / /snap/root-$(date +%Y%m%d-%H%M) - 按时间排序并保留最近 7 个:
btrfs subvolume list -t / | awk '$4 ~ /^root-/ {print $4}' | sort | head -n -7 | xargs -r -I{} btrfs subvolume delete "/snap/{}" - 注意
btrfs subvolume delete是同步阻塞操作,大快照可能卡几秒到几分钟,别在 cron 里高频跑 - 某些发行版(如 openSUSE)的 Snapper 已封装好这套逻辑,但底层仍是调
btrfs subvolume系列命令
最易被忽略的一点:快照目录的挂载选项不影响其内容一致性——哪怕源子卷正在被 rsync 或数据库写入,快照那一刻的状态就是原子的;但如果你在快照过程中 umount 源,就可能中断 COW 导致损坏。










