xfs_repair 报元数据损坏但 xfs_db 检查正常的紧急数据抢救

6次阅读

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

xfs_repair 报元数据损坏但 xfs_db 检查正常的紧急数据抢救

为什么 xfs_repair 报元数据损坏而 xfs_db 却显示正常

xfs_repairxfs_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_CtCurrent_Pending_Sector 是否非零;若存在,先用 ddrescue 克隆出镜像再操作

绕过自动修复、用 xfs_db 手动提取关键数据的实操路径

xfs_repair -n(dry-run)反复报类似 agi block 0x12345678 points to bad agfinode 123456 has bad extent list,说明 AG 结构已断裂,此时强行 -L 清日志大概率让 root Directory(inode 128)不可达。更稳妥的做法是:

  • 启动 xfs_db -r -f /dev/sdX(-r 强制只读,-f 跳过设备打开校验)
  • 定位根目录:输入 sb 0printrootino 值(通常是 128),再 inode 128printcore.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 /mntInvalid argument 或卡在 XFS: failed to read root inode,大概率是 superblock 中的 sb_inopblogsb_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 0print 记下 sb_versionnumsb_sectsize,再手工修正:例如 sb 0write sb_versionnum 5(XFS v5 格式)→ write sb_sectsize 512quit

真正棘手的是 AGF 中的 agf_roots 数组指向了非法 btree root block,这种损坏往往需要按 AG 逐个重建 free space btree,没有通用脚本可抄——这时候该考虑专业恢复服务了。

text=ZqhQzanResources