diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index cc00e0ff..2acbb53f 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -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; diff --git a/e2fsck/problem.c b/e2fsck/problem.c index 977a4c81..ab67cff6 100644 --- a/e2fsck/problem.c +++ b/e2fsck/problem.c @@ -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 */ diff --git a/e2fsck/problem.h b/e2fsck/problem.h index 1b5815bc..aed524dc 100644 --- a/e2fsck/problem.h +++ b/e2fsck/problem.h @@ -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 diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h index 7a14f408..1b35ff78 100644 --- a/lib/ext2fs/ext2fs.h +++ b/lib/ext2fs/ext2fs.h @@ -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, diff --git a/lib/ext2fs/extent.c b/lib/ext2fs/extent.c index 88287648..95a0a864 100644 --- a/lib/ext2fs/extent.c +++ b/lib/ext2fs/extent.c @@ -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;