问题症状
系统运行中,Btrfs 文件系统突然变为只读,所有写入操作失败。查看 dmesg 发现以下关键错误:
BTRFS error: metadata reservation failed for delayed dir item deletion, error: -28
BTRFS: Transaction aborted (error -28)
BTRFS error: level verify failed on logical 1079556358144 mirror 1 wanted 1 found 2
随后文件系统自我保护,强制挂载为只读。
空间使用情况
Overall:
Device size: 953.87GiB
Device allocated: 663.06GiB
Device unallocated: 290.81GiB
Used: 649.06GiB
Data,single: Size:641.00GiB, Used:632.19GiB (98.63%)
Metadata,DUP: Size:11.00GiB, Used:8.43GiB (76.65%)
System,DUP: Size:32.00MiB, Used:112.00KiB(0.34%)
虽然整体空间未满(未分配 290GiB),但因元数据操作碎片化导致预留失败,触发事务中止,进而引发元数据树校验错误。
排查过程
umount失败 —— 大量 Docker 进程占用,设备 busy,无法直接卸载。- 尝试
btrfs rescue zero-log失败 —— 即使卸载后,内核仍持有设备引用,无法以独占方式打开。 - 尝试释放内核引用 —— 通过
rmmod btrfs、sysfs delete等方式均失败(内核 Lockdown 或其他安全策略不适用)。 - 决定重启 —— 最终选择修改
/etc/fstab注释掉对应挂载条目后重启系统。
最终解决方案
步骤一:注释 fstab 避免启动时自动挂载
sudo nano /etc/fstab
# 将对应 UUID 或设备行前加 # 注释
步骤二:重启系统
sudo reboot
步骤三:只读挂载并备份数据(可选)
sudo mount -o ro /dev/nvme0n1p1 /mnt
sudo rsync -av /mnt/重要目录 /备份路径
步骤四:清除损坏的事务日志
sudo umount /mnt
sudo btrfs rescue zero-log /dev/nvme0n1p1
步骤五:重新挂载为读写
sudo mount -o rw /dev/nvme0n1p1 /mnt
步骤六:验证文件系统健康
sudo btrfs scrub start -B /mnt
sudo btrfs balance start -dusage=5 -musage=5 /mnt
原因分析
内核在元数据碎片化严重时,对 ENOSPC(Error -28)的处理存在缺陷,导致事务中止后无法正确回滚,引发元数据树层级校验失败(level verify failed)。Btrfs 检测到元数据不一致后强制只读保护数据。
预防措施
- 定期 balance,避免元数据严重碎片化:
btrfs balance start -dusage=10 -musage=10 /挂载点 - 保持内核更新,尽早使用修复了相关 bug 的长期支持版本(建议 5.15+ 或 6.1+)。
- 监控空间使用,避免数据块组长期处于高位使用率。
遇到类似问题的读者请优先备份数据,再尝试修复。