xfs_repair报元数据损坏而xfs_db显示正常,因其检查逻辑不同:xfs_repair强制验证AG结构与跨对象引用一致性,xfs_db默认只读扫描且深度校验不足。

为什么 xfs_repair 报元数据损坏而 xfs_db 却显示正常
xfs_repair 和 xfs_db 的检查逻辑完全不同:xfs_repair 会尝试重建 AG(allocation group)结构、验证所有元数据对象的交叉引用关系(比如 inobt 指向的 inode 是否真在 inobt 中被标记为已用),并强制执行一致性修复;而 xfs_db -r 默认只做只读扫描,不校验跨结构依赖,xfs_db -c "check" 虽然能做部分一致性检查,但跳过大量深度验证(如 reverse-mapping tree、reflink 树、log replay 模拟等)。所以常见现象是:xfs_db 看起来“没报错”,但 xfs_repair 在加载 AGF/AGI/AGFL 或遍历 inobt 时发现块号冲突、空闲位图与实际 inodes 不匹配、或 CRC 校验通过但逻辑引用断裂。
抢救前必须确认的三个硬性前提
不做这些,直接跑 xfs_repair -L 可能永久丢数据:
- 确保文件系统当前未挂载(包括 read-only 挂载也不行)——
mount | grep xfs必须无输出 - 用
dd if=/dev/zero of=/path/to/backup.img bs=1M count=1024预留至少 1GB 空间用于临时日志和修复缓存,否则xfs_repair可能在中途因 tmpdir 空间不足 abort - 确认磁盘底层无硬件故障:运行
smartctl -a /dev/sdX查看Reallocated_Sector_Ct、Current_Pending_Sector是否非零;若存在,先用ddrescue克隆出镜像再操作
绕过自动修复、用 xfs_db 手动提取关键数据的实操路径
当 xfs_repair -n(dry-run)反复报类似 agi block 0x12345678 points to bad agf 或 inode 123456 has bad extent list,说明 AG 结构已断裂,此时强行 -L 清日志大概率让 root directory(inode 128)不可达。更稳妥的做法是:
- 启动
xfs_db -r -f /dev/sdX(-r 强制只读,-f 跳过设备打开校验) - 定位根目录:输入
sb 0→print查rootino值(通常是128),再inode 128→print看core.mode是否为040755(确认是目录) - 导出目录项:用
write -o /tmp/dirlist.txt dir 128将根目录所有 dentry 名称 dump 出来(注意:这不读取文件内容,只读 name + inode number) - 对关键 inode(如用户主目录对应的 inode 号),用
write -o /tmp/file.data -d 123456提取原始数据块(-d 表示 raw data mode,绕过 extent 解析,适合 extent tree 已损时抢救)
修复后仍无法 mount 的典型补救动作
xfs_repair -L 成功后 mount -t xfs /dev/sdX /mnt 报 Invalid argument 或卡在 XFS: failed to read root inode,大概率是 superblock 中的 sb_inopblog、sb_agcount 等字段被写坏。此时不要重复 repair:
- 用
xfs_info /dev/sdX查原始参数(若还能读),对比修复前后是否变化 - 尝试指定备用 superblock:找第 2 个 AG 的 superblock(通常是 offset
0x400000),执行mount -t xfs -o sb=0x400000 /dev/sdX /mnt - 若仍失败,用
xfs_db -r -f /dev/sdX进入后执行sb 0→print记下sb_versionnum和sb_sectsize,再手工修正:例如sb 0→write sb_versionnum 5(XFS v5 格式)→write sb_sectsize 512→quit
真正棘手的是 AGF 中的 agf_roots 数组指向了非法 btree root block,这种损坏往往需要按 AG 逐个重建 free space btree,没有通用脚本可抄——这时候该考虑专业恢复服务了。










