From 82372e32de94f0ad142123b123e6af8e597e4526 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 15 Aug 2012 13:00:14 -0400 Subject: [PATCH] ext4: fix rehashing of the lost+found directory Commit 07307114dea didn't correctly handle the lost+found directory when it added support for metadata checksums. First of all, e2fsck_get_lost_and_found() assumed that the inode_dir_map bitmap was initialized, and it wasn't when it was called earlier by a change in that commit. Secondly, it's important that lost+found dirctory is processed in case its directory checksums are incorrect, but should preserve any empty dirctory blocks so there space available for e2fsck to reconnect any orphan inodes. Fix these problems, to fix test failures: f_holedir2 and f_rehash_dir Signed-off-by: "Theodore Ts'o" --- e2fsck/pass1.c | 8 +++++++- e2fsck/pass3.c | 2 +- e2fsck/rehash.c | 24 +++++++++++++++++++----- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index 8907e75..a4bd956 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -1299,6 +1299,12 @@ endit: ext2fs_free_mem(&block_buf); ext2fs_free_mem(&inode); + /* + * The l+f inode may have been cleared, so zap it now and + * later passes will recalculate it if necessary + */ + ctx->lost_and_found = 0; + print_resource_track(ctx, _("Pass 1"), &rtrack, ctx->fs->io); } @@ -2248,7 +2254,7 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, } if (ctx->dirs_to_hash && pb.is_dir && - (ctx->lost_and_found == ino) && + !(ctx->lost_and_found && ctx->lost_and_found == ino) && !(inode->i_flags & EXT2_INDEX_FL) && ((inode->i_size / fs->blocksize) >= 3)) e2fsck_rehash_dir_later(ctx, ino); diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c index ad733c2..a379e9b 100644 --- a/e2fsck/pass3.c +++ b/e2fsck/pass3.c @@ -375,7 +375,7 @@ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix) if (retval && !fix) return 0; if (!retval) { - if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, ino)) { + if (ext2fs_check_directory(fs, ino) == 0) { ctx->lost_and_found = ino; return ino; } diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c index b159bb7..347f1b0 100644 --- a/e2fsck/rehash.c +++ b/e2fsck/rehash.c @@ -694,11 +694,23 @@ static int write_dir_block(ext2_filsys fs, { struct write_dir_struct *wd = (struct write_dir_struct *) priv_data; blk64_t blk; - char *dir; + char *dir, *buf = 0; if (*block_nr == 0) return 0; - if (blockcnt >= wd->outdir->num) { + if (blockcnt < 0) + return 0; + if (blockcnt < wd->outdir->num) + dir = wd->outdir->buf + (blockcnt * fs->blocksize); + else if (wd->ctx->lost_and_found == wd->dir) { + /* Don't release any extra directory blocks for lost+found */ + wd->err = ext2fs_new_dir_block(fs, 0, 0, &buf); + if (wd->err) + return BLOCK_ABORT; + dir = buf; + wd->outdir->num++; + } else { + /* We don't need this block, so release it */ e2fsck_read_bitmaps(wd->ctx); blk = *block_nr; ext2fs_unmark_block_bitmap2(wd->ctx->block_found_map, blk); @@ -707,11 +719,11 @@ static int write_dir_block(ext2_filsys fs, wd->cleared++; return BLOCK_CHANGED; } - if (blockcnt < 0) - return 0; - dir = wd->outdir->buf + (blockcnt * fs->blocksize); wd->err = ext2fs_write_dir_block4(fs, *block_nr, dir, 0, wd->dir); + if (buf) + ext2fs_free_mem(&buf); + if (wd->err) return BLOCK_ABORT; return 0; @@ -890,6 +902,8 @@ void e2fsck_rehash_directories(e2fsck_t ctx) if (!ctx->dirs_to_hash && !all_dirs) return; + (void) e2fsck_get_lost_and_found(ctx, 0); + clear_problem_context(&pctx); dir_index = ctx->fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX; -- 1.8.3.1