Whamcloud - gitweb
LU-14710 e2fsck: fix ".." more gracefully if possible 58/43858/3
authorAndreas Dilger <adilger@whamcloud.com>
Fri, 28 May 2021 04:57:20 +0000 (22:57 -0600)
committerAndreas Dilger <adilger@whamcloud.com>
Mon, 31 May 2021 23:25:02 +0000 (23:25 +0000)
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 <adilger@whamcloud.com>
Reviewed-on: https://review.whamcloud.com/43858
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Artem Blagodarenko <artem.blagodarenko@hpe.com>
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 68e81d1..69a18da 100644 (file)
@@ -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';
index e24aa94..a7ca4e4 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 8b3523c..0838aa3 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 8ed90c5..71df18f 100644 (file)
Binary files a/tests/f_baddotdir/image.gz and b/tests/f_baddotdir/image.gz differ
index 2c684fe..ae4b410 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 bab07e0..91e6027 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 c733c18..769f71a 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 f0065f1..31870bd 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