]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_repair: fix missing dir buffer corruption checks
authorDarrick J. Wong <darrick.wong@oracle.com>
Fri, 10 Jul 2020 19:34:36 +0000 (15:34 -0400)
committerEric Sandeen <sandeen@sandeen.net>
Fri, 10 Jul 2020 19:34:36 +0000 (15:34 -0400)
The da_read_buf() function operates in "salvage" mode, which means that
if the verifiers fail, it will return a buffer with b_error set.  The
callers of da_read_buf, however, do not adequately check for verifier
errors, which means that repair can fail to flag a corrupt filesystem.

Fix the callers to do this properly.  The dabtree block walker and the
dabtree path checker functions to complain any time the da node / leafn
verifiers fail.  Fix the directory block walking functions to complain
about EFSCORRUPTED, since they already dealt with EFSBADCRC.

Found by running xfs/496 against lhdr.stale = middlebit.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
repair/da_util.c
repair/dir2.c

index 5061880fbab2cd3057440882babc0b8c7fc48121..7239c2e2c64fed086c853993e6f6e8579a3195a4 100644 (file)
@@ -134,6 +134,15 @@ _("can't read %s block %u for inode %" PRIu64 "\n"),
                        goto error_out;
                }
 
+               /* corrupt leafn/node; rebuild the dir. */
+               if (bp->b_error == -EFSBADCRC || bp->b_error == -EFSCORRUPTED) {
+                       do_warn(
+_("corrupt %s tree block %u for inode %" PRIu64 "\n"),
+                               FORKNAME(whichfork), bno, da_cursor->ino);
+                       libxfs_buf_relse(bp);
+                       goto error_out;
+               }
+
                node = bp->b_addr;
                libxfs_da3_node_hdr_from_disk(mp, &nodehdr, node);
 
@@ -160,15 +169,6 @@ _("bad %s magic number 0x%x in inode %" PRIu64 " bno = %u\n"),
                        goto error_out;
                }
 
-               /* corrupt node; rebuild the dir. */
-               if (bp->b_error == -EFSBADCRC || bp->b_error == -EFSCORRUPTED) {
-                       libxfs_buf_relse(bp);
-                       do_warn(
-_("corrupt %s tree block %u for inode %" PRIu64 "\n"),
-                               FORKNAME(whichfork), bno, da_cursor->ino);
-                       goto error_out;
-               }
-
                if (nodehdr.count > geo->node_ents) {
                        do_warn(
 _("bad %s record count in inode %" PRIu64 ", count = %d, max = %d\n"),
@@ -562,6 +562,13 @@ _("can't read %s block %u for inode %" PRIu64 "\n"),
                                FORKNAME(whichfork), dabno, cursor->ino);
                        return 1;
                }
+               if (bp->b_error == -EFSCORRUPTED || bp->b_error == -EFSBADCRC) {
+                       do_warn(
+_("corrupt %s tree block %u for inode %" PRIu64 "\n"),
+                               FORKNAME(whichfork), dabno, cursor->ino);
+                       libxfs_buf_relse(bp);
+                       return 1;
+               }
 
                newnode = bp->b_addr;
                libxfs_da3_node_hdr_from_disk(mp, &nodehdr, newnode);
index cbbce60188d6baf61a74a00b01a30be32866054d..b374bc7b193f4197ecc316a7d4586b3a919df60f 100644 (file)
@@ -983,6 +983,13 @@ _("can't read block %u for directory inode %" PRIu64 "\n"),
                        mp->m_dir_geo->datablk, ino);
                return 1;
        }
+       if (bp->b_error == -EFSCORRUPTED) {
+               do_warn(
+_("corrupt directory block %u for inode %" PRIu64 "\n"),
+                       mp->m_dir_geo->datablk, ino);
+               libxfs_buf_relse(bp);
+               return 1;
+       }
        /*
         * Verify the block
         */
@@ -1122,6 +1129,13 @@ _("can't read file block %u for directory inode %" PRIu64 "\n"),
                                da_bno, ino);
                        goto error_out;
                }
+               if (bp->b_error == -EFSCORRUPTED) {
+                       do_warn(
+_("corrupt directory leafn block %u for inode %" PRIu64 "\n"),
+                               da_bno, ino);
+                       libxfs_buf_relse(bp);
+                       goto error_out;
+               }
                leaf = bp->b_addr;
                libxfs_dir2_leaf_hdr_from_disk(mp, &leafhdr, leaf);
                /*
@@ -1324,6 +1338,13 @@ _("can't read block %" PRIu64 " for directory inode %" PRIu64 "\n"),
                                dbno, ino);
                        continue;
                }
+               if (bp->b_error == -EFSCORRUPTED) {
+                       do_warn(
+_("corrupt directory data block %lu for inode %" PRIu64 "\n"),
+                               dbno, ino);
+                       libxfs_buf_relse(bp);
+                       continue;
+               }
                data = bp->b_addr;
                if (!(be32_to_cpu(data->magic) == XFS_DIR2_DATA_MAGIC ||
                      be32_to_cpu(data->magic) == XFS_DIR3_DATA_MAGIC))