Whamcloud - gitweb
e2fsck: try to salvage extent blocks with bad checksums
authorDarrick J. Wong <darrick.wong@oracle.com>
Sun, 3 Aug 2014 02:32:11 +0000 (22:32 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Sun, 3 Aug 2014 02:32:11 +0000 (22:32 -0400)
Remove the code that would zap an extent block immediately if the
checksum failed (i.e. strict_csums).  Instead, we'll only do that if
the extent block header shows obvious structural problems; if the
header checks out, then we'll iterate the block and see if we can
recover some extents.

Requires a minor modification to ext2fs_extent_get such that the
extent block will be returned in the buffer even if the return code
indicates a checksum error.  This brings its behavior in line with
the rest of libext2fs.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
e2fsck/pass1.c
e2fsck/problem.c
e2fsck/problem.h
lib/ext2fs/extent.c

index 02683d3..283b0b1 100644 (file)
@@ -2001,7 +2001,10 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
        int                     is_dir, is_leaf;
        problem_t               problem;
        struct ext2_extent_info info;
-       int                     failed_csum;
+       int                     failed_csum = 0;
+
+       if (pctx->errcode == EXT2_ET_EXTENT_CSUM_INVALID)
+               failed_csum = 1;
 
        pctx->errcode = ext2fs_extent_get_info(ehandle, &info);
        if (pctx->errcode)
@@ -2012,7 +2015,6 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
        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);
                last_lblk = extent.e_lblk + extent.e_len - 1;
@@ -2023,15 +2025,6 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
                pctx->num = extent.e_len;
                pctx->blkcount = extent.e_lblk + extent.e_len;
 
-               /* Ask to clear a corrupt extent block */
-               if (try_repairs &&
-                   pctx->errcode == EXT2_ET_EXTENT_CSUM_INVALID) {
-                       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))
@@ -2069,16 +2062,6 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
                        failed_csum = 0;
                }
 
-               /* Failed csum but passes checks?  Ask to fix checksum. */
-               if (try_repairs && failed_csum && problem == 0 &&
-                   fix_problem(ctx, PR_1_EXTENT_ONLY_CSUM_INVALID, pctx)) {
-                       pb->inode_modified = 1;
-                       pctx->errcode = ext2fs_extent_replace(ehandle,
-                                                       0, &extent);
-                       if (pctx->errcode)
-                               return;
-               }
-
                if (try_repairs && problem) {
 report_problem:
                        if (fix_problem(ctx, problem, pctx)) {
@@ -2124,6 +2107,7 @@ fix_problem_now:
                                        pctx->errcode = 0;
                                        break;
                                }
+                               failed_csum = 0;
                                continue;
                        }
                        goto next;
@@ -2152,15 +2136,13 @@ fix_problem_now:
                        }
                        pctx->errcode = ext2fs_extent_get(ehandle,
                                                  EXT2_EXTENT_DOWN, &extent);
-                       if (pctx->errcode) {
+                       if (pctx->errcode &&
+                           pctx->errcode != EXT2_ET_EXTENT_CSUM_INVALID) {
                                pctx->str = "EXT2_EXTENT_DOWN";
                                problem = PR_1_EXTENT_HEADER_INVALID;
                                if (!next_try_repairs)
                                        return;
-                               if (pctx->errcode ==
-                                       EXT2_ET_EXTENT_HEADER_BAD ||
-                                   pctx->errcode ==
-                                       EXT2_ET_EXTENT_CSUM_INVALID)
+                               if (pctx->errcode == EXT2_ET_EXTENT_HEADER_BAD)
                                        goto report_problem;
                                return;
                        }
@@ -2256,6 +2238,7 @@ fix_problem_now:
                                if (pctx->errcode)
                                        goto failed_add_dir_block;
                                last_lblk = extent.e_lblk + extent.e_len - 1;
+                               failed_csum = 0;
                        }
                }
 alloc_later:
@@ -2323,6 +2306,16 @@ alloc_later:
                                                  EXT2_EXTENT_NEXT_SIB,
                                                  &extent);
        }
+
+       /* Failed csum but passes checks?  Ask to fix checksum. */
+       if (failed_csum &&
+           fix_problem(ctx, PR_1_EXTENT_ONLY_CSUM_INVALID, pctx)) {
+               pb->inode_modified = 1;
+               pctx->errcode = ext2fs_extent_replace(ehandle, 0, &extent);
+               if (pctx->errcode)
+                       return;
+       }
+
        if (pctx->errcode == EXT2_ET_EXTENT_NO_NEXT)
                pctx->errcode = 0;
 }
index dc094ed..1b6bdb0 100644 (file)
@@ -977,12 +977,6 @@ 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
index af7a73e..89db5f3 100644 (file)
@@ -577,9 +577,6 @@ 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
 
index c0b34a7..c9ef701 100644 (file)
@@ -313,6 +313,7 @@ errcode_t ext2fs_extent_get(ext2_extent_handle_t handle,
        blk64_t                         blk;
        blk64_t                         end_blk;
        int                             orig_op, op;
+       int                             failed_csum = 0;
 
        EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
 
@@ -487,10 +488,8 @@ retry:
 
                if (!(handle->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
                    !ext2fs_extent_block_csum_verify(handle->fs, handle->ino,
-                                                    eh)) {
-                       handle->level--;
-                       return EXT2_ET_EXTENT_CSUM_INVALID;
-               }
+                                                    eh))
+                       failed_csum = 1;
 
                newpath->left = newpath->entries =
                        ext2fs_le16_to_cpu(eh->eh_entries);
@@ -570,6 +569,9 @@ retry:
             (path->left != 0)))
                goto retry;
 
+       if (failed_csum)
+               return EXT2_ET_EXTENT_CSUM_INVALID;
+
        return 0;
 }