]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
repair: Repair directory block CRC mismatches
authorJan Kara <jack@suse.cz>
Tue, 8 Jul 2014 00:30:28 +0000 (10:30 +1000)
committerDave Chinner <david@fromorbit.com>
Tue, 8 Jul 2014 00:30:28 +0000 (10:30 +1000)
It can happen that just CRC doesn't match for directory blocks. In that
case xfs_repair will just report the error but won't fix anything (as
further checking of the block doesn't reveal any problems). Make sure we
recompute and write out new CRC when we failed verification during
reading.

Signed-off-by: Jan Kara <jack@suse.cz>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
repair/dir2.c

index 14c1435f50776da40965d24f00a72c7043fdc0e3..a189c161e5691d5eff88aeab883a4e8113eecb1f 100644 (file)
@@ -596,7 +596,13 @@ _("bad level %d in block %u for directory inode %" PRIu64 "\n"),
                 */
                ASSERT(cursor->level[this_level].dirty == 0 ||
                        (cursor->level[this_level].dirty && !no_modify));
-
+               /*
+                * If block looks ok but CRC didn't match, make sure to
+                * recompute it.
+                */
+               if (!no_modify &&
+                   cursor->level[this_level].bp->b_error == EFSBADCRC)
+                       cursor->level[this_level].dirty = 1;
                if (cursor->level[this_level].dirty && !no_modify)
                        libxfs_writebuf(cursor->level[this_level].bp, 0);
                else
@@ -1621,6 +1627,9 @@ _("bad directory block magic # %#x in block %u for directory inode %" PRIu64 "\n
                blp = (xfs_dir2_leaf_entry_t *)btp;
        rval = process_dir2_data(mp, ino, dip, ino_discovery, dirname, parent,
                bp, dot, dotdot, mp->m_dirdatablk, (char *)blp, &dirty);
+       /* If block looks ok but CRC didn't match, make sure to recompute it. */
+       if (!rval && bp->b_error == EFSBADCRC)
+               dirty = 1;
        if (dirty && !no_modify) {
                *repair = 1;
                libxfs_writebuf(bp, 0);
@@ -1784,6 +1793,12 @@ _("bad sibling back pointer for block %u in directory inode %" PRIu64 "\n"),
                        }
                }
                current_hashval = greatest_hashval;
+               /*
+                * If block looks ok but CRC didn't match, make sure to
+                * recompute it.
+                */
+               if (!no_modify && bp->b_error == EFSBADCRC)
+                       buf_dirty = 1;
                ASSERT(buf_dirty == 0 || (buf_dirty && !no_modify));
                if (buf_dirty && !no_modify) {
                        *repair = 1;
@@ -1927,8 +1942,12 @@ _("bad directory block magic # %#x in block %" PRIu64 " for directory inode %" P
                i = process_dir2_data(mp, ino, dip, ino_discovery, dirname,
                        parent, bp, dot, dotdot, (xfs_dablk_t)dbno,
                        (char *)data + mp->m_dirblksize, &dirty);
-               if (i == 0)
+               if (i == 0) {
                        good++;
+                       /* Maybe just CRC is wrong. Make sure we correct it. */
+                       if (bp->b_error == EFSBADCRC)
+                               dirty = 1;
+               }
                if (dirty && !no_modify) {
                        *repair = 1;
                        libxfs_writebuf(bp, 0);