diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index 648c578d..10ffe394 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -1983,6 +1983,22 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx, } } + /* + * Uninitialized blocks in a directory? Clear the flag and + * we'll interpret the blocks later. + */ + if (try_repairs && is_dir && problem == 0 && + (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) && + fix_problem(ctx, PR_1_UNINIT_DBLOCK, pctx)) { + extent.e_flags &= ~EXT2_EXTENT_FLAGS_UNINIT; + pb->inode_modified = 1; + pctx->errcode = ext2fs_extent_replace(ehandle, 0, + &extent); + if (pctx->errcode) + return; + failed_csum = 0; + } + if (try_repairs && problem) { report_problem: pctx->blk = extent.e_pblk; @@ -2619,6 +2635,21 @@ static int process_block(ext2_filsys fs, return 0; } + /* + * For a directory, add logical block zero for processing even if it's + * not mapped or we'll be perennially stuck with broken "." and ".." + * entries. + */ + if (p->is_dir && blockcnt == 0 && blk == 0) { + pctx->errcode = ext2fs_add_dir_block2(fs->dblist, p->ino, 0, 0); + if (pctx->errcode) { + pctx->blk = blk; + pctx->num = blockcnt; + goto failed_add_dir_block; + } + p->last_db_block++; + } + if (blk == 0) return 0; @@ -2710,6 +2741,17 @@ static int process_block(ext2_filsys fs, blk = *block_nr = 0; ret_code = BLOCK_CHANGED; p->inode_modified = 1; + /* + * If the directory block is too big and is beyond the + * end of the FS, don't bother trying to add it for + * processing -- the kernel would never have created a + * directory this large, and we risk an ENOMEM abort. + * In any case, the toobig handler for extent-based + * directories also doesn't feed toobig blocks to + * pass 2. + */ + if (problem == PR_1_TOOBIG_DIR) + return ret_code; goto mark_dir; } else return 0; diff --git a/e2fsck/problem.c b/e2fsck/problem.c index a1986c67..60c02af7 100644 --- a/e2fsck/problem.c +++ b/e2fsck/problem.c @@ -1043,6 +1043,11 @@ static struct e2fsck_problem problem_table[] = { N_("@d @i %i @b %b should be at @b %c. "), PROMPT_FIX, 0 }, + /* Extents/inlinedata flag set on a device or socket inode */ + { PR_1_UNINIT_DBLOCK, + N_("@d @i %i has @x marked uninitialized at @b %c. "), + PROMPT_FIX, PR_PREEN_OK }, + /* Pass 1b errors */ /* Pass 1B: Rescan for duplicate/bad blocks */ diff --git a/e2fsck/problem.h b/e2fsck/problem.h index ab6ced7f..6cd3d50f 100644 --- a/e2fsck/problem.h +++ b/e2fsck/problem.h @@ -603,6 +603,12 @@ struct problem_context { /* file metadata collides with critical metadata */ #define PR_1_CRITICAL_METADATA_COLLISION 0x010071 +/* Directory inode has a missing block (hole) */ +#define PR_1_COLLAPSE_DBLOCK 0x010072 + +/* uninit directory block */ +#define PR_1_UNINIT_DBLOCK 0x010073 + /* * Pass 1b errors */ @@ -665,9 +671,6 @@ 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_emptydir/expect.1 b/tests/f_emptydir/expect.1 new file mode 100644 index 00000000..c6126213 --- /dev/null +++ b/tests/f_emptydir/expect.1 @@ -0,0 +1,19 @@ +Pass 1: Checking inodes, blocks, and sizes +Inode 12, i_size is 1024, should be 0. Fix? yes + +Pass 2: Checking directory structure +Directory inode 12 has an unallocated block #0. Allocate? yes + +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +Free blocks count wrong for group #0 (957, counted=956). +Fix? yes + +Free blocks count wrong (957, counted=956). +Fix? yes + + +test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** +test_filesys: 12/256 files (8.3% non-contiguous), 1092/2048 blocks +Exit status is 1 diff --git a/tests/f_emptydir/expect.2 b/tests/f_emptydir/expect.2 new file mode 100644 index 00000000..75c0515b --- /dev/null +++ b/tests/f_emptydir/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: 12/256 files (16.7% non-contiguous), 1092/2048 blocks +Exit status is 0 diff --git a/tests/f_emptydir/image.gz b/tests/f_emptydir/image.gz new file mode 100644 index 00000000..1b6f8f83 Binary files /dev/null and b/tests/f_emptydir/image.gz differ diff --git a/tests/f_emptydir/name b/tests/f_emptydir/name new file mode 100644 index 00000000..d5bc6609 --- /dev/null +++ b/tests/f_emptydir/name @@ -0,0 +1,2 @@ +always iterate dir block 0 or e2fsck goes into infinite loop + diff --git a/tests/f_hugedir_blocks/expect.1 b/tests/f_hugedir_blocks/expect.1 new file mode 100644 index 00000000..798a7ac8 --- /dev/null +++ b/tests/f_hugedir_blocks/expect.1 @@ -0,0 +1,10 @@ +Pass 1: Checking inodes, blocks, and sizes +Inode 12 is too big. Truncate? yes + +Block #1074791435 (13) causes directory to be too big. CLEARED. +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +test_filesys: 12/128 files (8.3% non-contiguous), 22/512 blocks +Exit status is 0 diff --git a/tests/f_hugedir_blocks/expect.2 b/tests/f_hugedir_blocks/expect.2 new file mode 100644 index 00000000..ac5f4c13 --- /dev/null +++ b/tests/f_hugedir_blocks/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: 12/128 files (8.3% non-contiguous), 22/512 blocks +Exit status is 0 diff --git a/tests/f_hugedir_blocks/image.gz b/tests/f_hugedir_blocks/image.gz new file mode 100644 index 00000000..1d54de80 Binary files /dev/null and b/tests/f_hugedir_blocks/image.gz differ diff --git a/tests/f_hugedir_blocks/name b/tests/f_hugedir_blocks/name new file mode 100644 index 00000000..d74761b4 --- /dev/null +++ b/tests/f_hugedir_blocks/name @@ -0,0 +1 @@ +crash e2fsck with a dir with an impossibly high logical blk offset diff --git a/tests/f_uninit_dir/expect.1 b/tests/f_uninit_dir/expect.1 new file mode 100644 index 00000000..f0065f15 --- /dev/null +++ b/tests/f_uninit_dir/expect.1 @@ -0,0 +1,27 @@ +Pass 1: Checking inodes, blocks, and sizes +Directory inode 12 has extent marked uninitialized at block 0. Fix? yes + +Directory inode 14 has extent marked uninitialized at block 0. Fix? yes + +Pass 2: Checking directory structure +Directory inode 14, block #0, offset 0: directory corrupted +Salvage? yes + +Missing '.' in directory inode 14. +Fix? yes + +Setting filetype for entry '.' in ??? (14) to 2. +Missing '..' in directory inode 14. +Fix? yes + +Setting filetype for entry '..' in ??? (14) to 2. +Pass 3: Checking directory connectivity +'..' in /abc (14) is (0), should be / (2). +Fix? yes + +Pass 4: Checking reference counts +Pass 5: Checking group summary information + +test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** +test_filesys: 14/128 files (0.0% non-contiguous), 20/512 blocks +Exit status is 1 diff --git a/tests/f_uninit_dir/expect.2 b/tests/f_uninit_dir/expect.2 new file mode 100644 index 00000000..7b28f436 --- /dev/null +++ b/tests/f_uninit_dir/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: 14/128 files (0.0% non-contiguous), 20/512 blocks +Exit status is 0 diff --git a/tests/f_uninit_dir/image.gz b/tests/f_uninit_dir/image.gz new file mode 100644 index 00000000..ac9131d2 Binary files /dev/null and b/tests/f_uninit_dir/image.gz differ diff --git a/tests/f_uninit_dir/name b/tests/f_uninit_dir/name new file mode 100644 index 00000000..d7f5bee3 --- /dev/null +++ b/tests/f_uninit_dir/name @@ -0,0 +1 @@ +fix uninit flag on directory extents and check the dir blocks