]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
e2fsck: fix ".." more gracefully if possible
authorAndreas Dilger <adilger@whamcloud.com>
Mon, 31 May 2021 23:31:23 +0000 (17:31 -0600)
committerTheodore Ts'o <tytso@mit.edu>
Tue, 6 Jul 2021 19:43:21 +0000 (15:43 -0400)
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 for the very common case of
filesystems with the "filetype" feature, to avoid later problems
that can be easily avoided.  This can't always be done, even if
filesystems without "filetype" are totally obsolete, because many
old test images do not have this feature enabled.

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.

Signed-off-by: Andreas dilger <adilger@whamcloud.com>
Reviewed-by: Artem Blagodarenko <artem.blagodarenko@hpe.com>
Lustre-bug-Id: https://jira.whamcloud.com/browse/LU-14710
Change-Id: Ia5e579bcf31a9d9ee260d5640de6dbdb60514823
Reviewed-on: https://review.whamcloud.com/43858
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
e2fsck/pass2.c
tests/f_baddotdir/expect.1
tests/f_baddotdir/expect.2
tests/f_baddotdir/image.gz
tests/f_dir_bad_csum/expect.1
tests/f_rebuild_csum_rootdir/expect.1
tests/f_resize_inode_meta_bg/expect.1
tests/f_uninit_dir/expect.1
tests/scripts/repair-test [new file with mode: 0755]

index e504b30ad5f3e0914af87d74f89db8dbc4e78d3d..94f92c8bdd65404732e7b4c16f8cc6ed740046f8 100644 (file)
@@ -405,6 +405,7 @@ static int check_dot(e2fsck_t ctx,
        int             status = 0;
        int             created = 0;
        problem_t       problem = 0;
+       int             ftype = EXT2_FT_DIR;
 
        if (!dirent->inode)
                problem = PR_2_MISSING_DOT;
@@ -416,12 +417,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)
                                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;
@@ -442,12 +445,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;
                        }
                }
@@ -466,6 +475,7 @@ static int check_dotdot(e2fsck_t ctx,
 {
        problem_t       problem = 0;
        unsigned int    rec_len;
+       int             ftype = EXT2_FT_DIR;
 
        if (!dirent->inode)
                problem = PR_2_MISSING_DOT_DOT;
@@ -478,6 +488,8 @@ 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)
                                dirent->rec_len = 12;
@@ -488,7 +500,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';
index e24aa94ff9f442a718d2cce0091cb49fb3e43966..a7ca4e4952cfafeeb03d38f1758fcad5194c4397 100644 (file)
@@ -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 <The NULL inode> (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
index 8b3523cb42010bd7ca7a2560dd3fa4e58b14f2c3..0838aa33d118fac619666390958b0052bfa1fc63 100644 (file)
@@ -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
index 8ed90c5d6aaf0da309d34b91e615eac7682f585c..71df18f2198afd056e79e6b35b27400e334a80ba 100644 (file)
Binary files a/tests/f_baddotdir/image.gz and b/tests/f_baddotdir/image.gz differ
index 2c684fe6249d9644ee92700a8ac0c8099b0c7679..ae4b410ebbae774da18c476d8d9052aed2ba266a 100644 (file)
@@ -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
 
index bab07e0528a163143fbce5664d9e1da8df29bc51..91e6027df50c7fa308a876e28066a5fc5afd553d 100644 (file)
@@ -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 <The NULL inode> (0), should be / (2).
 Fix? yes
index c733c18d96a78a5f518deaac944a349ebc7c16e4..769f71aea22b0a5a0eeff6c06cdef62099a8e71f 100644 (file)
@@ -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
 
index f0065f1557a714e1c755d0c2062f551a8c77624c..31870bda5b5d0780c76d24112f49b86c9d1194b4 100644 (file)
@@ -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 <The NULL inode> (0), should be / (2).
 Fix? yes
diff --git a/tests/scripts/repair-test b/tests/scripts/repair-test
new file mode 100755 (executable)
index 0000000..c164e6e
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/sh
+for T in "$*"; do
+       [ -f "$T.failed" -a -d "$T" ] ||
+               { echo "usage: $0 <test_to_repair>"; exit 1; }
+
+       cp $T.1.log $T/expect.1
+       cp $T.2.log $T/expect.2
+       ./test_one $T
+done