The sparse inode chunk feature introduces a new inobt record format that converts ir_freecount from 4 bytes to 1 byte. ir_freecount references throughout repair currently assume the 'full' format and endian-convert from the 32-bit value. Update the xfs_repair inobt scan and tree rebuild codepaths to use the correct record format for ir_freecount when sparse inodes is enabled. Signed-off-by: Brian Foster <bfoster@xxxxxxxxxx> --- repair/phase5.c | 6 +++++- repair/scan.c | 37 +++++++++++++++++++++++++------------ 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/repair/phase5.c b/repair/phase5.c index d01e72b..04bf049 100644 --- a/repair/phase5.c +++ b/repair/phase5.c @@ -1240,7 +1240,11 @@ build_ino_tree(xfs_mount_t *mp, xfs_agnumber_t agno, inocnt += is_inode_free(ino_rec, k); } - bt_rec[j].ir_u.f.ir_freecount = cpu_to_be32(inocnt); + if (xfs_sb_version_hassparseinodes(&mp->m_sb)) + bt_rec[j].ir_u.sp.ir_freecount = inocnt; + else + bt_rec[j].ir_u.f.ir_freecount = + cpu_to_be32(inocnt); freecount += inocnt; count += XFS_INODES_PER_CHUNK; diff --git a/repair/scan.c b/repair/scan.c index e64d0e5..f42459c 100644 --- a/repair/scan.c +++ b/repair/scan.c @@ -751,11 +751,16 @@ scan_single_ino_chunk( int off; int state; ino_tree_node_t *ino_rec, *first_rec, *last_rec; + int freecount; ino = be32_to_cpu(rp->ir_startino); off = XFS_AGINO_TO_OFFSET(mp, ino); agbno = XFS_AGINO_TO_AGBNO(mp, ino); lino = XFS_AGINO_TO_INO(mp, agno, ino); + if (xfs_sb_version_hassparseinodes(&mp->m_sb)) + freecount = rp->ir_u.sp.ir_freecount; + else + freecount = be32_to_cpu(rp->ir_u.f.ir_freecount); /* * on multi-block block chunks, all chunks start @@ -890,10 +895,10 @@ _("inode rec for ino %" PRIu64 " (%d/%d) overlaps existing rec (start %d/%d)\n") } } - if (nfree != be32_to_cpu(rp->ir_u.f.ir_freecount)) { - do_warn(_("ir_freecount/free mismatch, inode " - "chunk %d/%u, freecount %d nfree %d\n"), - agno, ino, be32_to_cpu(rp->ir_u.f.ir_freecount), nfree); + if (nfree != freecount) { + do_warn( +_("ir_freecount/free mismatch, inode chunk %d/%u, freecount %d nfree %d\n"), + agno, ino, freecount, nfree); } return suspect; @@ -913,11 +918,16 @@ scan_single_finobt_chunk( int off; int state; ino_tree_node_t *first_rec, *last_rec, *ino_rec; + int freecount; ino = be32_to_cpu(rp->ir_startino); off = XFS_AGINO_TO_OFFSET(mp, ino); agbno = XFS_AGINO_TO_AGBNO(mp, ino); lino = XFS_AGINO_TO_INO(mp, agno, ino); + if (xfs_sb_version_hassparseinodes(&mp->m_sb)) + freecount = rp->ir_u.sp.ir_freecount; + else + freecount = be32_to_cpu(rp->ir_u.f.ir_freecount); /* * on multi-block block chunks, all chunks start at the beginning of the @@ -1089,10 +1099,10 @@ check_freecount: * corruption). Issue a warning and continue the scan. The final btree * reconstruction will correct this naturally. */ - if (nfree != be32_to_cpu(rp->ir_u.f.ir_freecount)) { + if (nfree != freecount) { do_warn( _("finobt ir_freecount/free mismatch, inode chunk %d/%u, freecount %d nfree %d\n"), - agno, ino, be32_to_cpu(rp->ir_u.f.ir_freecount), nfree); + agno, ino, freecount, nfree); } if (!nfree) { @@ -1137,6 +1147,7 @@ scan_inobt( xfs_inobt_ptr_t *pp; xfs_inobt_rec_t *rp; int hdr_errors; + int freecount; hdr_errors = 0; @@ -1210,14 +1221,17 @@ _("inode btree block claimed (state %d), agno %d, bno %d, suspect %d\n"), * the block. skip processing of bogus records. */ for (i = 0; i < numrecs; i++) { + if (xfs_sb_version_hassparseinodes(&mp->m_sb)) + freecount = rp[i].ir_u.sp.ir_freecount; + else + freecount = be32_to_cpu(rp[i].ir_u.f.ir_freecount); + if (magic == XFS_IBT_MAGIC || magic == XFS_IBT_CRC_MAGIC) { agcnts->agicount += XFS_INODES_PER_CHUNK; agcnts->icount += XFS_INODES_PER_CHUNK; - agcnts->agifreecount += - be32_to_cpu(rp[i].ir_u.f.ir_freecount); - agcnts->ifreecount += - be32_to_cpu(rp[i].ir_u.f.ir_freecount); + agcnts->agifreecount += freecount; + agcnts->ifreecount += freecount; suspect = scan_single_ino_chunk(agno, &rp[i], suspect); @@ -1227,8 +1241,7 @@ _("inode btree block claimed (state %d), agno %d, bno %d, suspect %d\n"), * so only the free inode count is expected to be * consistent with the agi */ - agcnts->fibtfreecount += - be32_to_cpu(rp[i].ir_u.f.ir_freecount); + agcnts->fibtfreecount += freecount; suspect = scan_single_finobt_chunk(agno, &rp[i], suspect); -- 1.9.3 _______________________________________________ xfs mailing list xfs@xxxxxxxxxxx http://oss.sgi.com/mailman/listinfo/xfs