]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
e2fsck: ignore badblocks if it says badblocks inode is bad
authorDarrick J. Wong <darrick.wong@oracle.com>
Thu, 11 Sep 2014 19:44:49 +0000 (12:44 -0700)
committerTheodore Ts'o <tytso@mit.edu>
Thu, 11 Sep 2014 22:08:26 +0000 (18:08 -0400)
If the badblocks list says that the badblocks inode is bad, it's quite
likely that badblocks is broken.  Worse yet, if the root inode is in
the same block as the badblocks inode (likely since they're adjacent),
the filesystem becomes unfixable because pass3 notices the bad root
inode and exits.

So... if we encounter this case, just kill the badblocks inode.

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
tests/f_bb_in_bb/expect.1 [new file with mode: 0644]
tests/f_bb_in_bb/expect.2 [new file with mode: 0644]
tests/f_bb_in_bb/image.gz [new file with mode: 0644]
tests/f_bb_in_bb/name [new file with mode: 0644]

index 4fc53112770b596e20c3796cb300a890420ed375..7175c771c70a97191845de3a5835509c0fdc152d 100644 (file)
@@ -1076,6 +1076,37 @@ void e2fsck_pass1(e2fsck_t ctx)
                if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
                        return;
                if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) {
+                       /*
+                        * If badblocks says badblocks is bad, offer to clear
+                        * the list, update the in-core bb list, and restart
+                        * the inode scan.
+                        */
+                       if (ino == EXT2_BAD_INO &&
+                           fix_problem(ctx, PR_1_BADBLOCKS_IN_BADBLOCKS,
+                                       &pctx)) {
+                               errcode_t err;
+
+                               e2fsck_clear_inode(ctx, ino, inode, 0, "pass1");
+                               ext2fs_badblocks_list_free(ctx->fs->badblocks);
+                               ctx->fs->badblocks = NULL;
+                               err = ext2fs_read_bb_inode(ctx->fs,
+                                                       &ctx->fs->badblocks);
+                               if (err) {
+                                       fix_problem(ctx, PR_1_ISCAN_ERROR,
+                                                   &pctx);
+                                       ctx->flags |= E2F_FLAG_ABORT;
+                                       goto endit;
+                               }
+                               err = ext2fs_inode_scan_goto_blockgroup(scan,
+                                                                       0);
+                               if (err) {
+                                       fix_problem(ctx, PR_1_ISCAN_ERROR,
+                                                   &pctx);
+                                       ctx->flags |= E2F_FLAG_ABORT;
+                                       goto endit;
+                               }
+                               continue;
+                       }
                        if (!ctx->inode_bb_map)
                                alloc_bb_map(ctx);
                        ext2fs_mark_inode_bitmap2(ctx->inode_bb_map, ino);
index 4b41a2179c1e2581c61d090b27703e7ca71c7fcc..9818539b55aa5c61e8d2d956b2c050c15f09d84c 100644 (file)
@@ -1086,6 +1086,11 @@ static struct e2fsck_problem problem_table[] = {
          N_("@i %i has inline data and @x flags set but i_block contains junk.\n"),
          PROMPT_CLEAR_INODE, 0 },
 
+       /* Bad block list says the bad block list inode is bad */
+       { PR_1_BADBLOCKS_IN_BADBLOCKS,
+         N_("Bad block list says the bad block list @i is bad.  "),
+         PROMPT_CLEAR_INODE, 0 },
+
        /* Pass 1b errors */
 
        /* Pass 1B: Rescan for duplicate/bad blocks */
index f86c531debfc5038326080ca3ae13fd2feeff239..5b32aeb45c2febd57b5e4af19e2556080759e104 100644 (file)
@@ -632,6 +632,9 @@ struct problem_context {
 /* inlinedata/extent set, clear inode */
 #define PR_1_CLEAR_EXTENT_INLINE_DATA_INODE    0x01007A
 
+/* badblocks is in badblocks */
+#define PR_1_BADBLOCKS_IN_BADBLOCKS            0x01007B
+
 /*
  * Pass 1b errors
  */
diff --git a/tests/f_bb_in_bb/expect.1 b/tests/f_bb_in_bb/expect.1
new file mode 100644 (file)
index 0000000..1d719e5
--- /dev/null
@@ -0,0 +1,17 @@
+Pass 1: Checking inodes, blocks, and sizes
+Bad block list says the bad block list inode is bad.  Clear inode? yes
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+Free blocks count wrong for group #0 (493, counted=494).
+Fix? yes
+
+Free blocks count wrong (493, counted=494).
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 11/128 files (0.0% non-contiguous), 18/512 blocks
+Exit status is 1
diff --git a/tests/f_bb_in_bb/expect.2 b/tests/f_bb_in_bb/expect.2
new file mode 100644 (file)
index 0000000..411e656
--- /dev/null
@@ -0,0 +1,7 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 11/128 files (0.0% non-contiguous), 18/512 blocks
+Exit status is 0
diff --git a/tests/f_bb_in_bb/image.gz b/tests/f_bb_in_bb/image.gz
new file mode 100644 (file)
index 0000000..e2c46c0
Binary files /dev/null and b/tests/f_bb_in_bb/image.gz differ
diff --git a/tests/f_bb_in_bb/name b/tests/f_bb_in_bb/name
new file mode 100644 (file)
index 0000000..88727e1
--- /dev/null
@@ -0,0 +1 @@
+bad block inode table block in bad block list