From e1f43b4c701b24d9b5bc85df858a8c36f0f0723b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 2 Feb 2012 07:39:10 -0500 Subject: [PATCH] repair: update extent count after zapping duplicate blocks When we find a duplicate extent in an extern format inode we do not zap the whole inode, but just truncate it to the point where the duplicate extent was found. But the current code only updates di_nblocks for the new size, but no di_nextents/di_anextents. In most cases this isn't noticed, but when moving such an inode to the lost+found directoy the consistency check in xfs_iformat trips over it. Fix this by updating the on-disk extent count as part of the inode repair. Note that we zap btree format inodes with duplicate block completely at this point, so this fix doesn't apply to them. Reviewed-by: Mark Tinguely Reported-by: Arkadiusz Mi??kiewicz Tested-by: Arkadiusz Mi??kiewicz Signed-off-by: Christoph Hellwig --- repair/dinode.c | 42 +++++++++++++++++++++++++++++++++--------- repair/dinode.h | 4 ++-- repair/scan.c | 19 ++++++++++--------- 3 files changed, 45 insertions(+), 20 deletions(-) diff --git a/repair/dinode.c b/repair/dinode.c index effed7847..16dfdb930 100644 --- a/repair/dinode.c +++ b/repair/dinode.c @@ -538,7 +538,7 @@ static int process_bmbt_reclist_int( xfs_mount_t *mp, xfs_bmbt_rec_t *rp, - int numrecs, + int *numrecs, int type, xfs_ino_t ino, xfs_drfsbno_t *tot, @@ -574,7 +574,7 @@ process_bmbt_reclist_int( else ftype = _("regular"); - for (i = 0; i < numrecs; i++) { + for (i = 0; i < *numrecs; i++) { libxfs_bmbt_disk_get_all(rp + i, &irec); if (i == 0) *last_key = *first_key = irec.br_startoff; @@ -763,6 +763,13 @@ _("illegal state %d in block map %" PRIu64 "\n"), done: if (locked_agno != -1) pthread_mutex_unlock(&ag_locks[locked_agno]); + + if (i != *numrecs) { + ASSERT(i < *numrecs); + do_warn(_("correcting nextents for inode %" PRIu64 "\n"), ino); + *numrecs = i; + } + return error; } @@ -774,7 +781,7 @@ int process_bmbt_reclist( xfs_mount_t *mp, xfs_bmbt_rec_t *rp, - int numrecs, + int *numrecs, int type, xfs_ino_t ino, xfs_drfsbno_t *tot, @@ -795,7 +802,7 @@ int scan_bmbt_reclist( xfs_mount_t *mp, xfs_bmbt_rec_t *rp, - int numrecs, + int *numrecs, int type, xfs_ino_t ino, xfs_drfsbno_t *tot, @@ -1286,23 +1293,29 @@ process_exinode( xfs_bmbt_rec_t *rp; xfs_dfiloff_t first_key; xfs_dfiloff_t last_key; + int numrecs; + int ret; lino = XFS_AGINO_TO_INO(mp, agno, ino); rp = (xfs_bmbt_rec_t *)XFS_DFORK_PTR(dip, whichfork); *tot = 0; - *nex = XFS_DFORK_NEXTENTS(dip, whichfork); + numrecs = XFS_DFORK_NEXTENTS(dip, whichfork); + /* * XXX - if we were going to fix up the btree record, * we'd do it right here. For now, if there's a problem, * we'll bail out and presumably clear the inode. */ if (check_dups == 0) - return(process_bmbt_reclist(mp, rp, *nex, type, lino, + ret = process_bmbt_reclist(mp, rp, &numrecs, type, lino, tot, blkmapp, &first_key, &last_key, - whichfork)); + whichfork); else - return(scan_bmbt_reclist(mp, rp, *nex, type, lino, tot, - whichfork)); + ret = scan_bmbt_reclist(mp, rp, &numrecs, type, lino, tot, + whichfork); + + *nex = numrecs; + return ret; } /* @@ -1993,6 +2006,17 @@ _("bad anextents %d for inode %" PRIu64 ", would reset to %" PRIu64 "\n"), lino, anextents); } } + + /* + * We are comparing different units here, but that's fine given that + * an extent has to have at least a block in it. + */ + if (nblocks < nextents + anextents) { + do_warn( +_("nblocks (%" PRIu64 ") smaller than nextents for inode %" PRIu64 "\n"), nblocks, lino); + return 1; + } + return 0; } diff --git a/repair/dinode.h b/repair/dinode.h index 43e36a7eb..d9197c1da 100644 --- a/repair/dinode.h +++ b/repair/dinode.h @@ -42,7 +42,7 @@ convert_extent( int process_bmbt_reclist(xfs_mount_t *mp, xfs_bmbt_rec_t *rp, - int numrecs, + int *numrecs, int type, xfs_ino_t ino, xfs_drfsbno_t *tot, @@ -55,7 +55,7 @@ int scan_bmbt_reclist( xfs_mount_t *mp, xfs_bmbt_rec_t *rp, - int numrecs, + int *numrecs, int type, xfs_ino_t ino, xfs_drfsbno_t *tot, diff --git a/repair/scan.c b/repair/scan.c index 2b1b9b4b5..5345094e7 100644 --- a/repair/scan.c +++ b/repair/scan.c @@ -348,12 +348,12 @@ _("inode %" PRIu64 " bad # of bmap records (%u, min - %u, max - %u)\n"), * we'll bail out and presumably clear the inode. */ if (check_dups == 0) { - err = process_bmbt_reclist(mp, rp, numrecs, - type, ino, tot, blkmapp, - &first_key, &last_key, - whichfork); + err = process_bmbt_reclist(mp, rp, &numrecs, type, ino, + tot, blkmapp, &first_key, + &last_key, whichfork); if (err) - return(1); + return 1; + /* * check that key ordering is monotonically increasing. * if the last_key value in the cursor is set to @@ -377,10 +377,11 @@ _("out-of-order bmap key (file offset) in inode %" PRIu64 ", %s fork, fsbno %" P bm_cursor->level[level].first_key = first_key; bm_cursor->level[level].last_key = last_key; - return(0); - } else - return(scan_bmbt_reclist(mp, rp, numrecs, - type, ino, tot, whichfork)); + return 0; + } else { + return scan_bmbt_reclist(mp, rp, &numrecs, type, ino, + tot, whichfork); + } } if (numrecs > mp->m_bmap_dmxr[1] || (isroot == 0 && numrecs < mp->m_bmap_dmnr[1])) { -- 2.47.2