]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
e2fsck: verify extent tree blocks and clear the bad ones
authorDarrick J. Wong <djwong@us.ibm.com>
Mon, 30 Jul 2012 23:18:04 +0000 (19:18 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Mon, 30 Jul 2012 23:18:04 +0000 (19:18 -0400)
When we encounter an extent tree block that passes the header check
but fails the checksum, offer to clear just that extent block instead
of failing the whole tree, which results in the entire inode being
wiped out.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
e2fsck/pass1.c
e2fsck/problem.c
e2fsck/problem.h

index 0aa93563d23f409c82f8fb37311f8c3c1bfb4b15..9399ef431e9355a3efade609a1125759d417a773 100644 (file)
@@ -1820,6 +1820,7 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
        int                     is_dir, is_leaf;
        errcode_t               problem;
        struct ext2_extent_info info;
+       int                     failed_csum;
 
        pctx->errcode = ext2fs_extent_get_info(ehandle, &info);
        if (pctx->errcode)
@@ -1827,11 +1828,25 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
 
        pctx->errcode = ext2fs_extent_get(ehandle, EXT2_EXTENT_FIRST_SIB,
                                          &extent);
-       while (!pctx->errcode && info.num_entries-- > 0) {
+       while ((pctx->errcode == 0 ||
+               pctx->errcode == EXT2_ET_EXTENT_CSUM_INVALID) &&
+              info.num_entries-- > 0) {
+               failed_csum = 0;
                is_leaf = extent.e_flags & EXT2_EXTENT_FLAGS_LEAF;
                is_dir = LINUX_S_ISDIR(pctx->inode->i_mode);
 
                problem = 0;
+               /* Ask to clear a corrupt extent block */
+               if (pctx->errcode == EXT2_ET_EXTENT_CSUM_INVALID) {
+                       pctx->blk = extent.e_pblk;
+                       pctx->blk2 = extent.e_lblk;
+                       pctx->num = extent.e_len;
+                       problem = PR_1_EXTENT_CSUM_INVALID;
+                       if (fix_problem(ctx, problem, pctx))
+                               goto fix_problem_now;
+                       failed_csum = 1;
+               }
+
                if (extent.e_pblk == 0 ||
                    extent.e_pblk < ctx->fs->super->s_first_data_block ||
                    extent.e_pblk >= ext2fs_blocks_count(ctx->fs->super))
@@ -1845,12 +1860,24 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
                         ext2fs_blocks_count(ctx->fs->super))
                        problem = PR_1_EXTENT_ENDS_BEYOND;
 
+               /* Corrupt but passes checks?  Ask to fix checksum. */
+               if (failed_csum) {
+                       pctx->blk = extent.e_pblk;
+                       pctx->blk2 = extent.e_lblk;
+                       pctx->num = extent.e_len;
+                       problem = 0;
+                       if (fix_problem(ctx, PR_1_EXTENT_ONLY_CSUM_INVALID,
+                                       pctx))
+                               ext2fs_extent_replace(ehandle, 0, &extent);
+               }
+
                if (problem) {
                report_problem:
                        pctx->blk = extent.e_pblk;
                        pctx->blk2 = extent.e_lblk;
                        pctx->num = extent.e_len;
                        if (fix_problem(ctx, problem, pctx)) {
+fix_problem_now:
                                e2fsck_read_bitmaps(ctx);
                                pctx->errcode =
                                        ext2fs_extent_delete(ehandle, 0);
@@ -1877,7 +1904,10 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
                        if (pctx->errcode) {
                                pctx->str = "EXT2_EXTENT_DOWN";
                                problem = PR_1_EXTENT_HEADER_INVALID;
-                               if (pctx->errcode == EXT2_ET_EXTENT_HEADER_BAD)
+                               if (pctx->errcode ==
+                                       EXT2_ET_EXTENT_HEADER_BAD ||
+                                   pctx->errcode ==
+                                       EXT2_ET_EXTENT_CSUM_INVALID)
                                        goto report_problem;
                                return;
                        }
index 221d1204b6f660b7cac2704127c58cded30b2331..b50bdae733eb824b942beb92059d200b743f0ec3 100644 (file)
@@ -956,6 +956,21 @@ static struct e2fsck_problem problem_table[] = {
          N_("@i %i passes checks, but checksum does not match @i.  "),
          PROMPT_FIX, PR_PREEN_OK },
 
+       /* Inode extent block checksum does not match extent */
+       { PR_1_EXTENT_CSUM_INVALID,
+         N_("@i %i extent block checksum does not match extent\n\t(logical @b "
+            "%c, @n physical @b %b, len %N)\n"),
+         PROMPT_CLEAR, 0 },
+
+       /*
+        * Inode extent block passes checks, but checksum does not match
+        * extent
+        */
+       { PR_1_EXTENT_ONLY_CSUM_INVALID,
+         N_("@i %i extent block passes checks, but checksum does not match "
+            "extent\n\t(logical @b %c, @n physical @b %b, len %N)\n"),
+         PROMPT_FIX, 0 },
+
        /* Pass 1b errors */
 
        /* Pass 1B: Rescan for duplicate/bad blocks */
index 200ef3bf392d796f76dd26b721469019f1ecfefd..ff9a3e100e04ba1cf3eb8478d090e364ba7faad8 100644 (file)
@@ -564,6 +564,12 @@ struct problem_context {
 /* inode passes checks, but checksum does not match inode */
 #define PR_1_INODE_ONLY_CSUM_INVALID   0x010068
 
+/* extent block checksum does not match extent block */
+#define PR_1_EXTENT_CSUM_INVALID       0x010069
+
+/* extent block passes checks, but checksum does not match extent block */
+#define PR_1_EXTENT_ONLY_CSUM_INVALID  0x01006A
+
 /*
  * Pass 1b errors
  */