Whamcloud - gitweb
e2fsck: reserve blocks for root/lost+found directory repair
authorDarrick J. Wong <darrick.wong@oracle.com>
Sat, 26 Jul 2014 00:33:45 +0000 (17:33 -0700)
committerTheodore Ts'o <tytso@mit.edu>
Sat, 26 Jul 2014 19:45:42 +0000 (15:45 -0400)
If we think we're going to need to repair either the root directory or
the lost+found directory, reserve a block at the end of pass 1 to
reduce the likelihood of an e2fsck abort while reconstructing
root/lost+found during pass 3.

If / and/or /lost+found are corrupt and duplicate processing in pass
1b allocates all the free blocks in the FS, fsck aborts with an
unusable FS since pass 3 can't recreate / or /lost+found.  If either
of those directories are missing, an admin can't easily mount the FS
and access the directory tree to move files off the injured FS and
free up space; this in turn prevents subsequent runs of e2fsck from
being able to continue repairs of the FS.

(One could migrate files manually with debugfs without the help of
path names, but it seems easier if users can simply mount the FS and
use regular FS management tools.)

[ Fixed up an obvious C trap: const char * and const char [] are not
  the same thing when you are taking the size of the parameter.
  People, run your regression tests!  Like spinach, it's good for you.  :-)
  -- tytso ]

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
e2fsck/e2fsck.h
e2fsck/pass1.c
e2fsck/pass3.c
tests/f_illitable/expect.1

index cee74a3..f904026 100644 (file)
@@ -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.
index 0f2b9be..647d91b 100644 (file)
@@ -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
index fb21727..0274213 100644 (file)
@@ -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);
 
        /*
index 552a2e7..0aa5687 100644 (file)
@@ -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