Detect mismatches of the inode and checksum, and prompt the user to fix the situation. Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> --- e2fsck/pass1.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++- e2fsck/problem.c | 10 +++++++++ e2fsck/problem.h | 6 +++++ 3 files changed, 75 insertions(+), 1 deletions(-) diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index c31e073..471e3e0 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -540,6 +540,40 @@ extern void e2fsck_setup_tdb_icount(e2fsck_t ctx, int flags, *ret = 0; } +static errcode_t recheck_bad_inode_checksum(ext2_filsys fs, ext2_ino_t ino, + e2fsck_t ctx, + struct problem_context *pctx) +{ + errcode_t retval; + struct ext2_inode_large inode; + + /* + * Reread inode. If we don't see checksum error, then this inode + * has been fixed elsewhere. + */ + retval = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, + sizeof(inode)); + if (retval && retval != EXT2_ET_INODE_CSUM_INVALID) + return retval; + if (!retval) + return 0; + + /* + * Checksum still doesn't match. That implies that the inode passes + * all the sanity checks, so maybe the checksum is simply corrupt. + * See if the user will go for fixing that. + */ + if (!fix_problem(ctx, PR_1_INODE_ONLY_CSUM_INVALID, pctx)) + return 0; + + retval = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, + sizeof(inode)); + if (retval) + return retval; + + return 0; +} + void e2fsck_pass1(e2fsck_t ctx) { int i; @@ -561,6 +595,7 @@ void e2fsck_pass1(e2fsck_t ctx) int imagic_fs, extent_fs; int busted_fs_time = 0; int inode_size; + int failed_csum = 0; init_resource_track(&rtrack, ctx->fs->io); clear_problem_context(&pctx); @@ -740,7 +775,8 @@ void e2fsck_pass1(e2fsck_t ctx) ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); continue; } - if (pctx.errcode) { + if (pctx.errcode && + pctx.errcode != EXT2_ET_INODE_CSUM_INVALID) { fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx); ctx->flags |= E2F_FLAG_ABORT; return; @@ -750,6 +786,14 @@ void e2fsck_pass1(e2fsck_t ctx) pctx.ino = ino; pctx.inode = inode; ctx->stashed_ino = ino; + + /* Clear corrupt inode? */ + if (pctx.errcode == EXT2_ET_INODE_CSUM_INVALID) { + if (fix_problem(ctx, PR_1_INODE_CSUM_INVALID, &pctx)) + goto clear_inode; + failed_csum = 1; + } + if (inode->i_links_count) { pctx.errcode = ext2fs_icount_store(ctx->inode_link_info, ino, inode->i_links_count); @@ -1146,6 +1190,20 @@ void e2fsck_pass1(e2fsck_t ctx) } else check_blocks(ctx, &pctx, block_buf); + /* + * If the inode failed the checksum and the user didn't + * clear the inode, test the checksum again -- if it still + * fails, ask the user if the checksum should be corrected. + */ + if (failed_csum) { + pctx.errcode = recheck_bad_inode_checksum(fs, ino, ctx, + &pctx); + if (pctx.errcode) { + ctx->flags |= E2F_FLAG_ABORT; + return; + } + } + if (ctx->flags & E2F_FLAG_SIGNAL_MASK) return; diff --git a/e2fsck/problem.c b/e2fsck/problem.c index 579c838..a6dd88a 100644 --- a/e2fsck/problem.c +++ b/e2fsck/problem.c @@ -929,8 +929,18 @@ static struct e2fsck_problem problem_table[] = { /* Quota inode is user visible */ { PR_1_QUOTA_INODE_NOT_HIDDEN, N_("@q @i is visible to the user. "), + PROMPT_FIX, PR_PREEN_OK }, + + /* inode checksum does not match inode */ + { PR_1_INODE_CSUM_INVALID, + N_("@i %i checksum does not match @i. "), PROMPT_CLEAR, PR_PREEN_OK }, + /* inode passes checks, but checksum does not match inode */ + { PR_1_INODE_ONLY_CSUM_INVALID, + N_("@i %i passes checks, but checksum does not match @i. "), + PROMPT_FIX, PR_PREEN_OK }, + /* Invalid bad inode */ { PR_1_INVALID_BAD_INODE, N_("The bad @b @i looks @n. "), diff --git a/e2fsck/problem.h b/e2fsck/problem.h index 3fabc90..5797fe2 100644 --- a/e2fsck/problem.h +++ b/e2fsck/problem.h @@ -550,6 +550,12 @@ struct problem_context { /* Invalid bad inode */ #define PR_1_INVALID_BAD_INODE 0x010065 +/* inode checksum does not match inode */ +#define PR_1_INODE_CSUM_INVALID 0x010066 + +/* inode passes checks, but checksum does not match inode */ +#define PR_1_INODE_ONLY_CSUM_INVALID 0x010067 + /* * Pass 1b errors */ -- To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html