summaryrefslogtreecommitdiff
path: root/e2fsck/pass3.c
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2014-07-26 17:14:40 -0400
committerTheodore Ts'o <tytso@mit.edu>2014-07-26 17:14:40 -0400
commiteb89a6287d27d90f10cf7b80da4a5dbd9d1bcd3e (patch)
tree5e9a944925178fd3d2466c0bdcafb6fb5727019b /e2fsck/pass3.c
parent17641bf208afc98a59a0a245ecaa06ecb8e081dd (diff)
downloade2fsprogs-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.c85
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
*/