e2fsck: fix incorrect interior node logical start values

An index node's logical start (ei_block) should
match the logical start of the first node (index
or leaf) below it.  If we find a node whose start
does not match its parent, fix all of its parents
accordingly.

If it finds such a problem, we'll see:

Pass 1: Checking inodes, blocks, and sizes
Interior extent node level 0 of inode 274258:
Logical start 3666 does not match logical start 4093 at next level.  Fix<y>?

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
debian-1.42.9
Eric Sandeen 2012-12-20 14:05:01 -05:00 committed by Theodore Ts'o
parent dbe5c43b2e
commit 789bd401c3
5 changed files with 29 additions and 3 deletions

View File

@ -1797,7 +1797,7 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
problem = PR_1_EXTENT_ENDS_BEYOND;
if (problem) {
report_problem:
report_problem:
pctx->blk = extent.e_pblk;
pctx->blk2 = extent.e_lblk;
pctx->num = extent.e_len;
@ -1822,7 +1822,10 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
}
if (!is_leaf) {
blk64_t lblk;
blk = extent.e_pblk;
lblk = extent.e_lblk;
pctx->errcode = ext2fs_extent_get(ehandle,
EXT2_EXTENT_DOWN, &extent);
if (pctx->errcode) {
@ -1832,6 +1835,18 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
goto report_problem;
return;
}
/* The next extent should match this index's logical start */
if (extent.e_lblk != lblk) {
struct ext2_extent_info info;
ext2fs_extent_get_info(ehandle, &info);
pctx->blk = lblk;
pctx->blk2 = extent.e_lblk;
pctx->num = info.curr_level - 1;
problem = PR_1_EXTENT_INDEX_START_INVALID;
if (fix_problem(ctx, problem, pctx))
ext2fs_extent_fix_parents(ehandle);
}
scan_extent_node(ctx, pctx, pb, extent.e_lblk, ehandle);
if (pctx->errcode)
return;

View File

@ -946,6 +946,14 @@ 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 },
/*
* Interior extent node logical offset doesn't match first node below it
*/
{ PR_1_EXTENT_INDEX_START_INVALID,
N_("Interior @x node level %N of @i %i:\n"
"Logical start %b does not match logical start %c at next level. "),
PROMPT_FIX, 0 },
/* Pass 1b errors */
/* Pass 1B: Rescan for duplicate/bad blocks */

View File

@ -558,6 +558,9 @@ struct problem_context {
/* Extent has zero length */
#define PR_1_EXTENT_LENGTH_ZERO 0x010066
/* Index start doesn't match start of next extent down */
#define PR_1_EXTENT_INDEX_START_INVALID 0x01006D
/*
* Pass 1b errors
*/
@ -586,7 +589,6 @@ struct problem_context {
/* Error adjusting EA refcount */
#define PR_1B_ADJ_EA_REFCOUNT 0x011007
/* Pass 1C: Scan directories for inodes with dup blocks. */
#define PR_1C_PASS_HEADER 0x012000

View File

@ -1082,6 +1082,7 @@ extern errcode_t ext2fs_extent_get_info(ext2_extent_handle_t handle,
struct ext2_extent_info *info);
extern errcode_t ext2fs_extent_goto(ext2_extent_handle_t handle,
blk64_t blk);
extern errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle);
/* fileio.c */
extern errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,

View File

@ -706,7 +706,7 @@ errcode_t ext2fs_extent_goto(ext2_extent_handle_t handle,
* Safe to call for any position in node; if not at the first entry,
* will simply return.
*/
static errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle)
errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle)
{
int retval = 0;
blk64_t start;