diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h index cee74a35..f904026f 100644 --- a/e2fsck/e2fsck.h +++ b/e2fsck/e2fsck.h @@ -369,6 +369,9 @@ struct e2fsck_struct { profile_t profile; int blocks_per_page; + /* Reserve blocks for root and l+f re-creation */ + blk64_t root_repair_block, lnf_repair_block; + /* * For the use of callers of the e2fsck functions; not used by * e2fsck functions themselves. diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index 0f2b9be9..647d91b4 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -540,6 +540,42 @@ void e2fsck_setup_tdb_icount(e2fsck_t ctx, int flags, *ret = 0; } +static void reserve_block_for_root_repair(e2fsck_t ctx) +{ + blk64_t blk = 0; + errcode_t err; + ext2_filsys fs = ctx->fs; + + ctx->root_repair_block = 0; + if (ext2fs_test_inode_bitmap2(ctx->inode_used_map, EXT2_ROOT_INO)) + return; + + err = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); + if (err) + return; + ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); + ctx->root_repair_block = blk; +} + +static void reserve_block_for_lnf_repair(e2fsck_t ctx) +{ + blk64_t blk = 0; + errcode_t err; + ext2_filsys fs = ctx->fs; + static const char name[] = "lost+found"; + ext2_ino_t ino; + + ctx->lnf_repair_block = 0; + if (!ext2fs_lookup(fs, EXT2_ROOT_INO, name, sizeof(name)-1, 0, &ino)) + return; + + err = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); + if (err) + return; + ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); + ctx->lnf_repair_block = blk; +} + void e2fsck_pass1(e2fsck_t ctx) { int i; @@ -1158,6 +1194,9 @@ void e2fsck_pass1(e2fsck_t ctx) ext2fs_close_inode_scan(scan); scan = NULL; + reserve_block_for_root_repair(ctx); + reserve_block_for_lnf_repair(ctx); + /* * If any extended attribute blocks' reference counts need to * be adjusted, either up (ctx->refcount_extra), or down diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c index fb217273..0274213d 100644 --- a/e2fsck/pass3.c +++ b/e2fsck/pass3.c @@ -134,6 +134,17 @@ abort_exit: inode_done_map = 0; } + if (ctx->lnf_repair_block) { + ext2fs_unmark_block_bitmap2(ctx->block_found_map, + ctx->lnf_repair_block); + ctx->lnf_repair_block = 0; + } + if (ctx->root_repair_block) { + ext2fs_unmark_block_bitmap2(ctx->block_found_map, + ctx->root_repair_block); + ctx->root_repair_block = 0; + } + print_resource_track(ctx, _("Pass 3"), &rtrack, ctx->fs->io); } @@ -176,6 +187,11 @@ static void check_root(e2fsck_t ctx) /* * First, find a free block */ + if (ctx->root_repair_block) { + blk = ctx->root_repair_block; + ctx->root_repair_block = 0; + goto skip_new_block; + } pctx.errcode = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); if (pctx.errcode) { pctx.str = "ext2fs_new_block"; @@ -184,6 +200,7 @@ static void check_root(e2fsck_t ctx) return; } ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); +skip_new_block: ext2fs_mark_block_bitmap2(fs->block_map, blk); ext2fs_mark_bb_dirty(fs); @@ -412,6 +429,11 @@ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix) /* * First, find a free block */ + if (ctx->lnf_repair_block) { + blk = ctx->lnf_repair_block; + ctx->lnf_repair_block = 0; + goto skip_new_block; + } retval = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); if (retval) { pctx.errcode = retval; @@ -419,6 +441,7 @@ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix) return 0; } ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); +skip_new_block: ext2fs_block_alloc_stats2(fs, blk, +1); /* diff --git a/tests/f_illitable/expect.1 b/tests/f_illitable/expect.1 index 552a2e79..0aa56872 100644 --- a/tests/f_illitable/expect.1 +++ b/tests/f_illitable/expect.1 @@ -12,7 +12,7 @@ Relocate? yes ../e2fsck/e2fsck: A block group is missing an inode table while reading bad blocks inode This doesn't bode well, but we'll try to go on... Pass 1: Checking inodes, blocks, and sizes -Relocating group 0's inode table to 5... +Relocating group 0's inode table to 7... Restarting e2fsck from the beginning... Pass 1: Checking inodes, blocks, and sizes Root inode is not a directory. Clear? yes