diff options
author | Darrick J. Wong <darrick.wong@oracle.com> | 2014-07-26 17:14:40 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2014-07-26 17:14:40 -0400 |
commit | eb89a6287d27d90f10cf7b80da4a5dbd9d1bcd3e (patch) | |
tree | 5e9a944925178fd3d2466c0bdcafb6fb5727019b /e2fsck/pass3.c | |
parent | 17641bf208afc98a59a0a245ecaa06ecb8e081dd (diff) | |
download | e2fsprogs-eb89a6287d27d90f10cf7b80da4a5dbd9d1bcd3e.tar.gz |
e2fsck: write dir blocks after new inode when reconstructing root/lost+found
If we trash the root directory block, e2fsck will find inode 11 (the
old lost+found) and try to attach it to l+f. The lost+found checker
also fails to find l+f and tries to add one to the root dir. The root
dir is not found but is recreated with incorrect checksums, so linking
in the l+f dir fails and the l+f '..' entry isn't set. Since both
dirs now fail checksum verification, they're both referred to rehash
to have that fixed, but because l+f doesn't have a '..' entry, rehash
crashes because l+f has < 2 entries.
On a checksumming filesystem, the routines in e2fsck that recreate
/lost+found and / must write the new directory block *after* the inode
has been written to disk because the checksum depends on i_generation.
Add a regression test while we're at it.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'e2fsck/pass3.c')
-rw-r--r-- | e2fsck/pass3.c | 85 |
1 files changed, 45 insertions, 40 deletions
diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c index 3fd1253d..31131ab5 100644 --- a/e2fsck/pass3.c +++ b/e2fsck/pass3.c @@ -205,28 +205,6 @@ skip_new_block: ext2fs_mark_bb_dirty(fs); /* - * Now let's create the actual data block for the inode - */ - pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, - &block); - if (pctx.errcode) { - pctx.str = "ext2fs_new_dir_block"; - fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); - ctx->flags |= E2F_FLAG_ABORT; - return; - } - - pctx.errcode = ext2fs_write_dir_block4(fs, blk, block, 0, - EXT2_ROOT_INO); - if (pctx.errcode) { - pctx.str = "ext2fs_write_dir_block4"; - fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); - ctx->flags |= E2F_FLAG_ABORT; - return; - } - ext2fs_free_mem(&block); - - /* * Set up the inode structure */ memset(&inode, 0, sizeof(inode)); @@ -249,6 +227,30 @@ skip_new_block: } /* + * Now let's create the actual data block for the inode. + * Due to metadata_csum, we must write the dir blocks AFTER + * the inode has been written to disk! + */ + pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, + &block); + if (pctx.errcode) { + pctx.str = "ext2fs_new_dir_block"; + fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); + ctx->flags |= E2F_FLAG_ABORT; + return; + } + + pctx.errcode = ext2fs_write_dir_block4(fs, blk, block, 0, + EXT2_ROOT_INO); + ext2fs_free_mem(&block); + if (pctx.errcode) { + pctx.str = "ext2fs_write_dir_block4"; + fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); + ctx->flags |= E2F_FLAG_ABORT; + return; + } + + /* * Miscellaneous bookkeeping... */ e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO); @@ -472,24 +474,6 @@ skip_new_block: ext2fs_inode_alloc_stats2(fs, ino, +1, 1); /* - * Now let's create the actual data block for the inode - */ - retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block); - if (retval) { - pctx.errcode = retval; - fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx); - return 0; - } - - retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino); - ext2fs_free_mem(&block); - if (retval) { - pctx.errcode = retval; - fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx); - return 0; - } - - /* * Set up the inode structure */ memset(&inode, 0, sizeof(inode)); @@ -509,6 +493,27 @@ skip_new_block: fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } + + /* + * Now let's create the actual data block for the inode. + * Due to metadata_csum, the directory block MUST be written + * after the inode is written to disk! + */ + retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block); + if (retval) { + pctx.errcode = retval; + fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx); + return 0; + } + + retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino); + ext2fs_free_mem(&block); + if (retval) { + pctx.errcode = retval; + fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx); + return 0; + } + /* * Finally, create the directory link */ |