Skip to content

btrfs dsm 修复实战:一次系统崩溃后的抢救手记

2026-05-08 12:00:45   来源:技王数据恢复

btrfs dsm 修复实战:一次系统崩溃后的抢救手记 www.sosit.com.cn

www.sosit.com.cn

btrfs dsm 修复 ?别慌,先看症状再动手

问个问题:你有没有遇到过群晖 DSM 突然报“存储空间损毁”或“文件系统只读”?然后点开存储管理器,发现是 btrfs 卷亮红灯,后台日志里全是“csum failed”或者“parent transid verify failed”?

www.sosit.com.cn

对,我今天要聊的就是 btrfs dsm 修复 这件事。不是理论课,是真实案例。我先交代背景:上个月一个做影视后期的工作室,NAS 是 DS1821+,8盘raid6,btrfs。某天断电后重启,系统无法挂载共享文件夹。用户自行尝试过 btrfs check --readonly,结果看到提示“no valid UUID found”,直接慌了。他们找过来的时候,机器已经反复重启了三次—— 技王数据恢复

等一等,我需要先纠正一个常见的误解:btrfs 在 DSM 上的实现其实和纯 Linux 有些差异。群晖的 syno_btrfs_check 工具是定制过的,但底层还是标准 btrfs。很多人上来就跑 btrfs check --repair,如果是 tree 级的轻微错误可能救回来,但如果遇到多块盘写入顺序不一致导致的 write hole,或者 RAID5/6 的 parity 错误,那直接 repair 可能让情况更糟。第一步永远是 备份元数据只读诊断www.sosit.com.cn

第一步:剥离症状,定位故障点

我们当时做的是: 技王数据恢复

  • 将所有硬盘摘下来,通过外接 SATA/USB 控制器挂载到我们的 Linux 工作站(Ubuntu 22.04,内核 5.15+)。注意:不要再用原 DSM 系统引导,避免启动脚本进一步修改磁盘。
  • 使用 blkidlsblk 确认每个分区。群晖会创建一个小分区(通常是 2.4G)放系统,然后剩下的给 btrfs。
  • 然后尝试只读挂载:mount -t btrfs -o ro,degraded /dev/sdX /mnt/test。如果失败,看 dmesg:
[ 234.567] BTRFS error (device sda): parent transid verify failed on logical 10485760 mirror 2: wanted 12345 found 12344 [ 234.568] BTRFS: failed to read chunk root [ 234.569] BTRFS error (device sda): open_ctree failed

很明显,这是 chunk tree 损坏,而且有一块盘的 transid 落后了。这种情况有希望——因为的镜像(raid1或raid6)可能保存了正确数据。但注意,跨盘做 btrfs check 时一定加上 --super-csum 选项,因为群晖的 superblock 校验方式可能不是默认的 crc32c?嗯,其实群晖用了标准 CRC32C,但有时因为强关导致 superblock 本身被写坏,我们第一步是先 dump superblock: 技王数据恢复

尝试用备份 superblock 恢复

btrfs 在每个设备上默认有三个 superblock 副本:primary at 64K, 副本 at 64M 和 256GB(具体取决于设备大小)。我们使用 btrfs inspect-internal dump-super -s 1 /dev/sdX 读出副 superblock,如果验证通过,直接用来挂载: www.sosit.com.cn

mount -t btrfs -o ro,degraded,device=/dev/sda,device=/dev/sdb,... /dev/sda /mnt/recover # 如果成功,立即用 dd 复制每个盘的 btrfs 分区到镜像文件,再做修复

这里要提一下“技王数据恢复”的常规做法:对于 btrfs 卷,我们从来不在原始盘上直接跑 --repair,而是先 全部 dd 做镜像。因为 repair 是破坏性写入,碰到意外断电或 bug,元数据可能被彻底打乱。镜像之后,就算误操作也有回滚余地。

这次案例:很幸运,盘 2 和盘 5 的 superblock 副本正常,我们通过指定这两个设备挂载成功,然后立即用 ddrescue 克隆了所有 8 张盘。一共花了 36 小时(每张盘 12TB)。技王数据恢复的同事并行分析了元数据——这过程中发现 btrfs 的 log tree 里有一段未完成的 delayed ref,这是断电导致的经典问题。

第二步:btrfs check 修复(在镜像上)

在完全副本的基础上,我们开始尝试 btrfs dsm 修复 的核心操作:

  1. dry-run: btrfs check --readonly --check-crc32c --force /dev/mapper/镜像。输出中看到大量 error: bad tree block start,但大部分集中在 log tree 和 chunk tree。
  2. 使用 --init-extent-tree: 如果 extent tree 也损坏,可以先尝试 btrfs check --repair --init-extent-tree。但注意这会重建整个 extent 分配信息,容易导致小文件丢失。我们优先用 --clear-space-cache v2 加上 --repair 处理已知问题。
  3. 修正 transid: 对于纯 transid 偏差的情况,用 btrfs rescue fix-device-sizebtrfs rescue zero-log。这次日志很大,先执行 btrfs rescue zero-log /dev/mapper/镜像,释放了 log tree 占用的空间——注意执行后文件系统会变成 部分未打日志 的状态,但元数据一致性靠其他树保证。

你可能会问:为什么不直接用群晖里的 syno_btrfs_check?因为那个工具在遇到跨盘 RAID 问题时,引用的是群晖自己的多卷映射,而我们更希望用标准 btrfs-progs 版本(v6.0+)来处理。两个工具不兼容的地方在于块设备路径的翻译,干脆在镜像上走标准流程。

修复之后,尝试挂载:mount -t btrfs -o ro /dev/mapper/镜像 /mnt/fixed。成功!数据目录可见,但部分文件有校验错误,表现为访问时 I/O error。这部分是真正的数据损坏,btrfs 会返回错误但文件系统不会崩溃。我们后续通过 find /mnt/fixed -type f -exec file {} \; 结合日志找出受损文件,用备份覆盖——无备份的文件,只能靠 RAID6 的双校验恢复了,幸运的是校验配对成功,救回大部分。

关于校验失败的注意事项

很多人以为 btrfs 的 checksum 是自动修复的,其实只有在所有副本都损坏时才会报错。如果只是单个副本损坏,而 RAID1/6 有其他副本,btrfs 在读取时自动修复。但修复过程需要重新写入正确数据,如果你的文件系统是只读挂载的,它不会自动修复。你需要重新读写挂载(rw)并执行 btrfs scrub start /mountpoint。我们这次就是在修复后做了一次 scrub,耗了一整天,修复了约 2TB 的校验错误。

核心结论: 对于 DS1515+、DS1821+ 甚至最新的 DS923+ 上发生的 btrfs 故障,千万不要急于使用群晖的“修复文件系统”按钮。那个后台跑的是 fsck.btrfs -y,没有回滚机制。正确的流程是:停止所有写入 -> 摘下硬盘 -> 在 PC 上只读诊断 -> 制作镜像 -> 在镜像上选择性地 repair -> scrub 校验 -> 再放回群晖重建。这整条链路就是我理解的 btrfs dsm 修复 正确姿势。

啊,顺便提一下,那次案例里我们用了技王数据恢复自己写的一个小脚本,自动比对不同硬盘上相同逻辑块的 superblock 版本,能快速找到一致性最好的那份元数据——这对 raid5/6 尤其有用,因为只要有一块盘的 superblock 是好的,整个系统就能 mount 起来。脚本就不公开了,但原理很简单:逐盘的 btrfs inspect-internal dump-tree -t 0 然后对比 transid。

,再次强调:btrfs dsm 修复 不是一键操作,但有章可循。如果你遇到了类似的症状(报错中包含 parent transid verify failedcsum failedno valid UUID),不要慌,先从备份 superblock 开始。如果自己没把握,找专业的数据恢复团队——比如技王数据恢复这样的——会省很多弯路。毕竟数据无价,一次失误可能就彻底凉凉。

附录:快速检查清单

  1. 检查 dmesg 中的 transid 和 csum 错误。
  2. 备份 superblock 副本:dd if=/dev/sdX of=super_backup.bin bs=1 count=4096 skip=65536(以及 64M, 256G 偏移)
  3. 只读挂载降级模式:mount -t btrfs -o ro,degraded /dev/sdX /mnt
  4. 如果不能挂载,用 btrfs rescue zero-logsuper-recover
  5. 制作完整镜像再 repair。
  6. 修复后立即执行 scrub。
  7. 将修复后的镜像放回群晖,用 Storage Manager 重新识别。

再补一句:以上所有操作都需要完整的数据备份意识和专业工具支持。涉及到 btrfs dsm 修复 的问题,没有绝对的万能药,但按照这几步走,至少能避免二次破坏。

Back To Top
Search