Whamcloud - gitweb
e2fsck: Fix an unhandled corruption case in scan_extent_node()
authorTheodore Ts'o <tytso@mit.edu>
Fri, 26 Dec 2008 03:42:38 +0000 (22:42 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Fri, 26 Dec 2008 03:42:38 +0000 (22:42 -0500)
A corrupted interior node in an extent tree would cause e2fsck to
crash with the error message:

Error1: Corrupt extent header on inode 107192
Aborted (core dumped)

Handle this and related failures when scanning an inode's extent tree
more robustly.

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
e2fsck/pass1.c
e2fsck/problem.c
e2fsck/problem.h
lib/ext2fs/extent.c

index 2619272..04aeb26 100644 (file)
@@ -1655,6 +1655,7 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
                        problem = PR_1_EXTENT_ENDS_BEYOND;
 
                if (problem) {
+               report_problem:
                        pctx->blk = extent.e_pblk;
                        pctx->blk2 = extent.e_lblk;
                        pctx->num = extent.e_len;
@@ -1662,11 +1663,7 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
                                pctx->errcode =
                                        ext2fs_extent_delete(ehandle, 0);
                                if (pctx->errcode) {
-                                       fix_problem(ctx,
-                                                   PR_1_EXTENT_DELETE_FAIL,
-                                                   pctx);
-                                       /* Should never get here */
-                                       ctx->flags |= E2F_FLAG_ABORT;
+                                       pctx->str = "ext2fs_extent_delete";
                                        return;
                                }
                                pctx->errcode = ext2fs_extent_get(ehandle,
@@ -1682,23 +1679,27 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
                }
 
                if (!is_leaf) {
-                       mark_block_used(ctx, extent.e_pblk);
-                       pb->num_blocks++;
+                       blk = extent.e_pblk;
                        pctx->errcode = ext2fs_extent_get(ehandle,
                                                  EXT2_EXTENT_DOWN, &extent);
                        if (pctx->errcode) {
-                               printf("Error1: %s on inode %u\n",
-                                       error_message(pctx->errcode), pctx->ino);
-                               abort();
+                               pctx->str = "EXT2_EXTENT_DOWN";
+                               problem = PR_1_EXTENT_HEADER_INVALID;
+                               if (pctx->errcode == EXT2_ET_EXTENT_HEADER_BAD)
+                                       goto report_problem;
+                               return;
                        }
                        scan_extent_node(ctx, pctx, pb, extent.e_lblk, ehandle);
+                       if (pctx->errcode)
+                               return;
                        pctx->errcode = ext2fs_extent_get(ehandle,
                                                  EXT2_EXTENT_UP, &extent);
                        if (pctx->errcode) {
-                               printf("Error1: %s on inode %u\n",
-                                       error_message(pctx->errcode), pctx->ino);
-                               abort();
+                               pctx->str = "EXT2_EXTENT_UP";
+                               return;
                        }
+                       mark_block_used(ctx, blk);
+                       pb->num_blocks++;
                        goto next;
                }
 
@@ -1780,7 +1781,14 @@ static void check_blocks_extents(e2fsck_t ctx, struct problem_context *pctx,
        }
 
        scan_extent_node(ctx, pctx, pb, 0, ehandle);
-
+       if (pctx->errcode &&
+           fix_problem(ctx, PR_1_EXTENT_ITERATE_FAILURE, pctx)) {
+               pb->num_blocks = 0;
+               inode->i_blocks = 0;
+               e2fsck_clear_inode(ctx, ino, inode, E2F_FLAG_RESTART,
+                                  "check_blocks_extents");
+               pctx->errcode = 0;
+       }
        ext2fs_extent_free(ehandle);
 }
 
index 19e8719..9cb3094 100644 (file)
@@ -823,10 +823,11 @@ static struct e2fsck_problem problem_table[] = {
          N_("Error while reading over @x tree in @i %i: %m\n"),
          PROMPT_CLEAR_INODE, 0 },
 
-       /* Error deleting a bogus extent */
-       { PR_1_EXTENT_DELETE_FAIL,
-         N_("Error while deleting extent: %m\n"),
-         PROMPT_ABORT, 0 },
+       /* Failure to iterate extents */
+       { PR_1_EXTENT_ITERATE_FAILURE,
+         N_("Failed to iterate extents in @i %i\n"
+            "\t(op %s, blk %b, lblk %c): %m\n"),
+         PROMPT_CLEAR_INODE, 0 },
 
        /* Bad starting block in extent */
        { PR_1_EXTENT_BAD_START_BLK,
@@ -863,6 +864,10 @@ static struct e2fsck_problem problem_table[] = {
          N_("@i %i has out of order extents\n\t(@n logical @b %c, physical @b %b, len %N)\n"),
          PROMPT_CLEAR, 0 },
 
+       { PR_1_EXTENT_HEADER_INVALID,
+         N_("@i %i has an invalid extent node (blk %b, lblk %c)\n"),
+         PROMPT_CLEAR, 0 },
+
        /* Pass 1b errors */
 
        /* Pass 1B: Rescan for duplicate/bad blocks */
index 815b37c..1cb054c 100644 (file)
@@ -479,8 +479,8 @@ struct problem_context {
 /* Error while reading extent tree */
 #define PR_1_READ_EXTENT               0x010056
 
-/* Error deleting a bogus extent */
-#define PR_1_EXTENT_DELETE_FAIL                0x010057
+/* Failure to iterate extents */
+#define PR_1_EXTENT_ITERATE_FAILURE    0x010057
 
 /* Bad starting block in extent */
 #define PR_1_EXTENT_BAD_START_BLK      0x010058
@@ -503,6 +503,9 @@ struct problem_context {
 /* Extents are out of order */
 #define PR_1_OUT_OF_ORDER_EXTENTS      0x01005E
 
+/* Extent node header invalid */
+#define PR_1_EXTENT_HEADER_INVALID     0x01005F
+
 /*
  * Pass 1b errors
  */
index 929e5cd..5545a94 100644 (file)
@@ -441,8 +441,10 @@ retry:
                eh = (struct ext3_extent_header *) newpath->buf;
 
                retval = ext2fs_extent_header_verify(eh, handle->fs->blocksize);
-               if (retval)
+               if (retval) {
+                       handle->level--;
                        return retval;
+               }
 
                newpath->left = newpath->entries =
                        ext2fs_le16_to_cpu(eh->eh_entries);