e2fsck: ignore badblocks if it says badblocks inode is bad

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>
crypto
Darrick J. Wong 2014-09-11 12:44:49 -07:00 committed by Theodore Ts'o
parent 3f4c407997
commit c6c681632e
7 changed files with 64 additions and 0 deletions

View 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);

View 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 */

View 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
*/

17
tests/f_bb_in_bb/expect.1 Normal file
View File

@ -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

View File

@ -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

BIN
tests/f_bb_in_bb/image.gz Normal file

Binary file not shown.

1
tests/f_bb_in_bb/name Normal file
View File

@ -0,0 +1 @@
bad block inode table block in bad block list