From b9cde40d4d1119a16ced92b83b85af0587b52215 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Mon, 30 Jul 2012 18:52:04 -0400 Subject: [PATCH] e2fsck: verify and correct inode checksums Detect mismatches of the inode and checksum, and prompt the user to fix the situation. Signed-off-by: Darrick J. Wong Signed-off-by: Theodore Ts'o --- e2fsck/pass1.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- e2fsck/problem.c | 10 ++++++++++ e2fsck/problem.h | 6 ++++++ 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index cb56d92..0aa9356 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -541,6 +541,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; @@ -562,6 +596,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); @@ -741,7 +776,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; @@ -751,6 +787,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); @@ -1147,6 +1191,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 977a4c8..8a29e34 100644 --- a/e2fsck/problem.c +++ b/e2fsck/problem.c @@ -946,6 +946,16 @@ static struct e2fsck_problem problem_table[] = { N_("@i %i has zero length extent\n\t(@n logical @b %c, physical @b %b)\n"), PROMPT_CLEAR, 0 }, + /* 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 }, + /* Pass 1b errors */ /* Pass 1B: Rescan for duplicate/bad blocks */ diff --git a/e2fsck/problem.h b/e2fsck/problem.h index 1b5815b..3a0c025 100644 --- a/e2fsck/problem.h +++ b/e2fsck/problem.h @@ -558,6 +558,12 @@ struct problem_context { /* Extent has zero length */ #define PR_1_EXTENT_LENGTH_ZERO 0x010066 +/* inode checksum does not match inode */ +#define PR_1_INODE_CSUM_INVALID 0x010067 + +/* inode passes checks, but checksum does not match inode */ +#define PR_1_INODE_ONLY_CSUM_INVALID 0x010068 + /* * Pass 1b errors */ -- 1.8.3.1