]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
repair: update extent count after zapping duplicate blocks
authorChristoph Hellwig <hch@infradead.org>
Thu, 2 Feb 2012 12:39:10 +0000 (07:39 -0500)
committerChristoph Hellwig <hch@lst.de>
Sun, 5 Feb 2012 14:00:34 +0000 (14:00 +0000)
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 <tinguely@sgi.com>
Reported-by: Arkadiusz Mi??kiewicz <arekm@maven.pl>
Tested-by: Arkadiusz Mi??kiewicz <arekm@maven.pl>
Signed-off-by: Christoph Hellwig <hch@lst.de>
repair/dinode.c
repair/dinode.h
repair/scan.c

index effed7847a0cdb5cab131547a2e757682c9cabad..16dfdb93060bd00936c3db6cb690f405c1d3aa34 100644 (file)
@@ -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;
 }
 
index 43e36a7eba607b0151119f4fe555a2e0490ecd31..d9197c1da6bd178867a3e302870d6d404fb6ca20 100644 (file)
@@ -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,
index 2b1b9b4b5f6b0d067a7a5b7aadbd5eecc6376811..5345094e7f978c4b28a27fdd79b281f9609df7d4 100644 (file)
@@ -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])) {