From: Andreas Dilger Date: Fri, 28 May 2021 04:57:20 +0000 (-0600) Subject: LU-14710 e2fsck: fix ".." more gracefully if possible X-Git-Tag: v1.46.2.wc2~2 X-Git-Url: https://git.whamcloud.com/?a=commitdiff_plain;h=5aa781e2;p=tools%2Fe2fsprogs.git LU-14710 e2fsck: fix ".." more gracefully if possible If the "." entry is corrupted, it will be reset in check_dot(). It is possible that the ".." entry can be recovered from the directory block instead of also resetting it immediately. If it appears that there is a valid ".." entry in the block, allow that to be used, and let check_dotdot() verify the dirent itself. When resetting the "." and ".." entries, use EXT2_FT_DIR as the file type instead of EXT2_FT_UNKNOWN, to avoid extra problems later can easily be avoided. Fixup affected tests using the new "repair-test" script that updates the expect.[12] files from $test.[12].log for the given tests and re-runs the test to ensure it now passes. Change-Id: Ia5e579bcf31a9d9ee260d5640de6dbdb60514823 Signed-off-by: Andreas dilger Reviewed-on: https://review.whamcloud.com/43858 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Artem Blagodarenko --- diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c index 68e81d1..69a18da 100644 --- a/e2fsck/pass2.c +++ b/e2fsck/pass2.c @@ -481,6 +481,7 @@ static int check_dot(e2fsck_t ctx, int created = 0; problem_t problem = 0; int dir_data_error; + int ftype = EXT2_FT_DIR; if (!dirent->inode) problem = PR_2_MISSING_DOT; @@ -494,12 +495,14 @@ static int check_dot(e2fsck_t ctx, (void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len); if (problem) { + if (!ext2fs_has_feature_filetype(ctx->fs->super)) + ftype = EXT2_FT_UNKNOWN; if (fix_problem(ctx, problem, pctx)) { - if (rec_len < 12 && dir_data_error) + if (rec_len < 12) rec_len = dirent->rec_len = 12; dirent->inode = ino; ext2fs_dirent_set_name_len(dirent, 1); - ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN); + ext2fs_dirent_set_file_type(dirent, ftype); dirent->name[0] = '.'; dirent->name[1] = '\0'; status = 1; @@ -520,12 +523,18 @@ static int check_dot(e2fsck_t ctx, nextdir = (struct ext2_dir_entry *) ((char *) dirent + 12); dirent->rec_len = 12; - (void) ext2fs_set_rec_len(ctx->fs, new_len, - nextdir); - nextdir->inode = 0; - ext2fs_dirent_set_name_len(nextdir, 0); - ext2fs_dirent_set_file_type(nextdir, - EXT2_FT_UNKNOWN); + /* if the next entry looks like "..", leave it + * and let check_dotdot() verify the dirent, + * otherwise zap the following entry. */ + if (strncmp(nextdir->name, "..", 3) != 0) { + (void)ext2fs_set_rec_len(ctx->fs, + new_len, + nextdir); + nextdir->inode = 0; + ext2fs_dirent_set_name_len(nextdir, 0); + ext2fs_dirent_set_file_type(nextdir, + ftype); + } status = 1; } } @@ -545,6 +554,7 @@ static int check_dotdot(e2fsck_t ctx, problem_t problem = 0; unsigned int rec_len; int dir_data_error; + int ftype = EXT2_FT_DIR; if (!dirent->inode) problem = PR_2_MISSING_DOT_DOT; @@ -559,8 +569,10 @@ static int check_dotdot(e2fsck_t ctx, (void) ext2fs_get_rec_len(ctx->fs, dirent, &rec_len); if (problem) { + if (!ext2fs_has_feature_filetype(ctx->fs->super)) + ftype = EXT2_FT_UNKNOWN; if (fix_problem(ctx, problem, pctx)) { - if (rec_len < 12 && dir_data_error) + if (rec_len < 12) dirent->rec_len = 12; /* * Note: we don't have the parent inode just @@ -569,7 +581,7 @@ static int check_dotdot(e2fsck_t ctx, */ dirent->inode = EXT2_ROOT_INO; ext2fs_dirent_set_name_len(dirent, 2); - ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN); + ext2fs_dirent_set_file_type(dirent, ftype); dirent->name[0] = '.'; dirent->name[1] = '.'; dirent->name[2] = '\0'; diff --git a/tests/f_baddotdir/expect.1 b/tests/f_baddotdir/expect.1 index e24aa94..a7ca4e4 100644 --- a/tests/f_baddotdir/expect.1 +++ b/tests/f_baddotdir/expect.1 @@ -29,6 +29,9 @@ Fix? yes Missing '..' in directory inode 16. Fix? yes +Directory entry for '.' in ... (19) is big. +Split? yes + Pass 3: Checking directory connectivity '..' in /a (12) is (0), should be / (2). Fix? yes @@ -47,13 +50,13 @@ Fix? yes Pass 4: Checking reference counts Pass 5: Checking group summary information -Free blocks count wrong for group #0 (70, counted=71). +Free blocks count wrong for group #0 (69, counted=70). Fix? yes -Free blocks count wrong (70, counted=71). +Free blocks count wrong (69, counted=70). Fix? yes test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -test_filesys: 18/32 files (0.0% non-contiguous), 29/100 blocks +test_filesys: 19/32 files (0.0% non-contiguous), 30/100 blocks Exit status is 1 diff --git a/tests/f_baddotdir/expect.2 b/tests/f_baddotdir/expect.2 index 8b3523c..0838aa3 100644 --- a/tests/f_baddotdir/expect.2 +++ b/tests/f_baddotdir/expect.2 @@ -3,5 +3,5 @@ Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information -test_filesys: 18/32 files (0.0% non-contiguous), 29/100 blocks +test_filesys: 19/32 files (0.0% non-contiguous), 30/100 blocks Exit status is 0 diff --git a/tests/f_baddotdir/image.gz b/tests/f_baddotdir/image.gz index 8ed90c5..71df18f 100644 Binary files a/tests/f_baddotdir/image.gz and b/tests/f_baddotdir/image.gz differ diff --git a/tests/f_dir_bad_csum/expect.1 b/tests/f_dir_bad_csum/expect.1 index 2c684fe..ae4b410 100644 --- a/tests/f_dir_bad_csum/expect.1 +++ b/tests/f_dir_bad_csum/expect.1 @@ -24,11 +24,9 @@ Salvage? yes Missing '.' in directory inode 17. Fix? yes -Setting filetype for entry '.' in ??? (17) to 2. Missing '..' in directory inode 17. Fix? yes -Setting filetype for entry '..' in ??? (17) to 2. Entry 'file' in ??? (18) has invalid inode #: 4294967295. Clear? yes diff --git a/tests/f_rebuild_csum_rootdir/expect.1 b/tests/f_rebuild_csum_rootdir/expect.1 index bab07e0..91e6027 100644 --- a/tests/f_rebuild_csum_rootdir/expect.1 +++ b/tests/f_rebuild_csum_rootdir/expect.1 @@ -6,11 +6,9 @@ Salvage? yes Missing '.' in directory inode 2. Fix? yes -Setting filetype for entry '.' in ??? (2) to 2. Missing '..' in directory inode 2. Fix? yes -Setting filetype for entry '..' in ??? (2) to 2. Pass 3: Checking directory connectivity '..' in / (2) is (0), should be / (2). Fix? yes diff --git a/tests/f_resize_inode_meta_bg/expect.1 b/tests/f_resize_inode_meta_bg/expect.1 index c733c18..769f71a 100644 --- a/tests/f_resize_inode_meta_bg/expect.1 +++ b/tests/f_resize_inode_meta_bg/expect.1 @@ -8,11 +8,9 @@ Pass 2: Checking directory structure First entry '' (inode=348) in directory inode 2 (???) should be '.' Fix? yes -Setting filetype for entry '.' in ??? (2) to 2. Missing '..' in directory inode 2. Fix? yes -Setting filetype for entry '..' in ??? (2) to 2. Directory inode 2, block #0, offset 860: directory corrupted Salvage? yes @@ -25,11 +23,9 @@ Salvage? yes Missing '.' in directory inode 11. Fix? yes -Setting filetype for entry '.' in ??? (11) to 2. Missing '..' in directory inode 11. Fix? yes -Setting filetype for entry '..' in ??? (11) to 2. Directory inode 11, block #1, offset 0: directory corrupted Salvage? yes diff --git a/tests/f_uninit_dir/expect.1 b/tests/f_uninit_dir/expect.1 index f0065f1..31870bd 100644 --- a/tests/f_uninit_dir/expect.1 +++ b/tests/f_uninit_dir/expect.1 @@ -10,11 +10,9 @@ 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 diff --git a/tests/scripts/repair-test b/tests/scripts/repair-test new file mode 100755 index 0000000..c164e6e --- /dev/null +++ b/tests/scripts/repair-test @@ -0,0 +1,9 @@ +#!/bin/sh +for T in "$*"; do + [ -f "$T.failed" -a -d "$T" ] || + { echo "usage: $0 "; exit 1; } + + cp $T.1.log $T/expect.1 + cp $T.2.log $T/expect.2 + ./test_one $T +done