From: Darrick J. Wong Date: Fri, 18 Jul 2014 22:54:30 +0000 (-0700) Subject: e2fsck: collapse holes in extent-based directories X-Git-Tag: v1.42.12~70 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9f005a90f86fccdfb9b016e39a9e9eca3e8911b2;p=thirdparty%2Fe2fsprogs.git e2fsck: collapse holes in extent-based directories If we notice a hole in the block map of an extent-based directory, offer to collapse the hole by decreasing the logical block # of the extent. This saves us from pass 3's inefficient strategy, which fills the holes by mapping in a lot of empty directory blocks. Signed-off-by: Darrick J. Wong Signed-off-by: Theodore Ts'o --- diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index cf36a086a..87e6d341d 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -1927,6 +1927,45 @@ report_problem: } pb->fragmented = 1; } + /* + * If we notice a gap in the logical block mappings of an + * extent-mapped directory, offer to close the hole by + * moving the logical block down, otherwise we'll go mad in + * pass 3 allocating empty directory blocks to fill the hole. + */ + if (is_dir && + pb->last_block + 1 < (e2_blkcnt_t)extent.e_lblk) { + blk64_t new_lblk; + + new_lblk = pb->last_block + 1; + if (EXT2FS_CLUSTER_RATIO(ctx->fs) > 1) + new_lblk = ((new_lblk + + EXT2FS_CLUSTER_RATIO(ctx->fs)) & + EXT2FS_CLUSTER_MASK(ctx->fs)) | + (extent.e_lblk & + EXT2FS_CLUSTER_MASK(ctx->fs)); + pctx->blk = extent.e_lblk; + pctx->blk2 = new_lblk; + if (fix_problem(ctx, PR_1_COLLAPSE_DBLOCK, pctx)) { + extent.e_lblk = new_lblk; + pb->inode_modified = 1; + pctx->errcode = ext2fs_extent_replace(ehandle, + 0, &extent); + if (pctx->errcode) { + pctx->errcode = 0; + goto alloc_later; + } + pctx->errcode = ext2fs_extent_fix_parents(ehandle); + if (pctx->errcode) + goto failed_add_dir_block; + pctx->errcode = ext2fs_extent_goto(ehandle, + extent.e_lblk); + if (pctx->errcode) + goto failed_add_dir_block; + last_lblk = extent.e_lblk + extent.e_len - 1; + } + } +alloc_later: while (is_dir && (++pb->last_db_block < (e2_blkcnt_t) extent.e_lblk)) { pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist, diff --git a/e2fsck/problem.c b/e2fsck/problem.c index 4c105bb29..837d11109 100644 --- a/e2fsck/problem.c +++ b/e2fsck/problem.c @@ -967,6 +967,11 @@ static struct e2fsck_problem problem_table[] = { PROMPT_CLEAR, 0 }, + /* Directory inode block should be at block */ + { PR_1_COLLAPSE_DBLOCK, + N_("@d @i %i @b %b should be at @b %c. "), + PROMPT_FIX, 0 }, + /* Pass 1b errors */ /* Pass 1B: Rescan for duplicate/bad blocks */ diff --git a/e2fsck/problem.h b/e2fsck/problem.h index 6cb09cfbc..d3e66ad60 100644 --- a/e2fsck/problem.h +++ b/e2fsck/problem.h @@ -624,6 +624,9 @@ struct problem_context { /* Couldn't clone file (error) */ #define PR_1D_CLONE_ERROR 0x013008 +/* Directory inode has a missing block (hole) */ +#define PR_1_COLLAPSE_DBLOCK 0x010072 + /* * Pass 2 errors */ diff --git a/tests/f_holedir2/expect.1 b/tests/f_holedir2/expect.1 index 5124f6178..455f4b065 100644 --- a/tests/f_holedir2/expect.1 +++ b/tests/f_holedir2/expect.1 @@ -1,21 +1,19 @@ Pass 1: Checking inodes, blocks, and sizes Inode 12, i_size is 0, should be 5120. Fix? yes -Inode 13, i_size is 4096, should be 5120. Fix? yes +Directory inode 13 block 2 should be at block 1. Fix? yes Pass 2: Checking directory structure Directory inode 12 has an unallocated block #3. Allocate? yes -Directory inode 13 has an unallocated block #1. Allocate? yes - Pass 3: Checking directory connectivity Pass 3A: Optimizing directories Pass 4: Checking reference counts Pass 5: Checking group summary information -Free blocks count wrong for group #0 (79, counted=77). +Free blocks count wrong for group #0 (78, counted=77). Fix? yes -Free blocks count wrong (79, counted=77). +Free blocks count wrong (78, counted=77). Fix? yes diff --git a/tests/f_holedir3/expect.1 b/tests/f_holedir3/expect.1 new file mode 100644 index 000000000..074ca6c8c --- /dev/null +++ b/tests/f_holedir3/expect.1 @@ -0,0 +1,13 @@ +Pass 1: Checking inodes, blocks, and sizes +Directory inode 12 block 5 should be at block 2. Fix? yes + +Inode 12, i_size is 6144, should be 3072. Fix? yes + +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information + +test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** +test_filesys: 17/128 files (5.9% non-contiguous), 1093/2048 blocks +Exit status is 1 diff --git a/tests/f_holedir3/expect.2 b/tests/f_holedir3/expect.2 new file mode 100644 index 000000000..b675e6df9 --- /dev/null +++ b/tests/f_holedir3/expect.2 @@ -0,0 +1,7 @@ +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +test_filesys: 17/128 files (5.9% non-contiguous), 1093/2048 blocks +Exit status is 0 diff --git a/tests/f_holedir3/image.gz b/tests/f_holedir3/image.gz new file mode 100644 index 000000000..c5eeb37d2 Binary files /dev/null and b/tests/f_holedir3/image.gz differ diff --git a/tests/f_holedir3/name b/tests/f_holedir3/name new file mode 100644 index 000000000..a526787c5 --- /dev/null +++ b/tests/f_holedir3/name @@ -0,0 +1,2 @@ +real directories with holes and zero i_size +