]> www.infradead.org Git - mtd-utils.git/commitdiff
fsck.ubifs: Check and handle unreachable files
authorZhihao Cheng <chengzhihao1@huawei.com>
Mon, 11 Nov 2024 09:08:05 +0000 (17:08 +0800)
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>
Mon, 11 Nov 2024 09:32:46 +0000 (10:32 +0100)
This is the 9/18 step of fsck. Check and handle unreachable files, the
checking rule is same as rebuild mode which has been implemented in
file_is_reachable, but the methods of handling are different:
1. Move unreachable regular file into disconnected list, let subsequent
   steps to handle them with lost+found.
2. Delete unreachable non-regular file.
3. Delete unreachable directory entries.

Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
ubifs-utils/fsck.ubifs/check_files.c
ubifs-utils/fsck.ubifs/extract_files.c
ubifs-utils/fsck.ubifs/fsck.ubifs.c
ubifs-utils/fsck.ubifs/fsck.ubifs.h
ubifs-utils/fsck.ubifs/problem.c

index c5c606e11f9ca14d5beab42f784ee7f20977e403..2be96193a9b88fc71776102c401b2fa37ea02c20 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/stat.h>
 
 #include "linux_err.h"
 #include "bitops.h"
@@ -442,3 +443,59 @@ int handle_invalid_files(struct ubifs_info *c)
 
        return 0;
 }
+
+/**
+ * handle_dentry_tree - Handle unreachable dentries and files.
+ * @c: UBIFS file-system description object
+ *
+ * This function iterates all directory entries and remove those unreachable
+ * ones. If file has no directory entries, it becomes unreachable:
+ * 1. If the unreachable file has non-regular type, delete it;
+ * 2. If the unreachable file has regular type, move it into the
+ *    @FSCK(c)->disconnected_files.
+ * 'Unreachable' means that a directory entry can not be searched from '/'.
+ *
+ * Returns zero in case of success, a negative error code in case of failure.
+ */
+int handle_dentry_tree(struct ubifs_info *c)
+{
+       struct rb_node *node;
+       struct scanned_file *file;
+       struct rb_root *tree = &FSCK(c)->scanned_files;
+       LIST_HEAD(unreachable);
+
+       for (node = rb_first(tree); node; node = rb_next(node)) {
+               file = rb_entry(node, struct scanned_file, rb);
+
+               /*
+                * Since all xattr files are already attached to corresponding
+                * host file, there are only non-xattr files in the file tree.
+                */
+               ubifs_assert(c, !file->ino.is_xattr);
+               if (!file_is_reachable(c, file, tree))
+                       list_add(&file->list, &unreachable);
+       }
+
+       while (!list_empty(&unreachable)) {
+               file = list_entry(unreachable.next, struct scanned_file, list);
+
+               list_del(&file->list);
+               if (S_ISREG(file->ino.mode)) {
+                       /*
+                        * Move regular type unreachable file into the
+                        * @FSCK(c)->disconnected_files.
+                        */
+                       list_add(&file->list, &FSCK(c)->disconnected_files);
+                       rb_erase(&file->rb, tree);
+               } else {
+                       /* Delete non-regular type unreachable file. */
+                       int err = delete_file(c, file);
+                       if (err)
+                               return err;
+                       rb_erase(&file->rb, tree);
+                       kfree(file);
+               }
+       }
+
+       return 0;
+}
index 51b83b82ae25a4bc77be001d72d588fdf3b200ed..b24445bebb92606bfbf64401beb733e3a0a89b3e 100644 (file)
@@ -1247,6 +1247,15 @@ retry:
                        dent_node = list_entry(path_list.next,
                                               struct scanned_dent_node, list);
 
+                       handle_invalid_file(c, DENTRY_IS_UNREACHABLE,
+                                           dent_node->file, dent_node);
+                       if (FSCK(c)->mode != REBUILD_MODE) {
+                               int err = delete_node(c, &dent_node->key,
+                                                     dent_node->header.lnum,
+                                                     dent_node->header.offs);
+                               if (err)
+                                       return err;
+                       }
                        dbg_fsck("remove unreachable dentry %s, in %s",
                                 c->encrypted && !file->ino.is_xattr ?
                                 "<encrypted>" : dent_node->name, c->dev_name);
@@ -1260,6 +1269,10 @@ retry:
        }
 
        if (!rb_first(&file->dent_nodes)) {
+               if (S_ISREG(file->ino.mode))
+                       handle_invalid_file(c, FILE_IS_DISCONNECTED, file, NULL);
+               else
+                       handle_invalid_file(c, FILE_HAS_NO_DENT, file, NULL);
                dbg_fsck("file %lu is unreachable, in %s", file->inum, c->dev_name);
                return false;
        }
index ac94ba4f94bee6e55a88e756cf854b94ff383b91..6a718fd89d5468a5cce59645706c76c5e8443669 100644 (file)
@@ -453,6 +453,14 @@ static int do_fsck(void)
                goto free_used_lebs;
        }
 
+       log_out(c, "Check and handle unreachable files");
+       err = handle_dentry_tree(c);
+       if (err) {
+               exit_code |= FSCK_ERROR;
+               goto free_disconnected_files;
+       }
+
+free_disconnected_files:
        destroy_file_list(c, &FSCK(c)->disconnected_files);
 free_used_lebs:
        kfree(FSCK(c)->used_lebs);
@@ -495,6 +503,7 @@ int main(int argc, char *argv[])
         * Step 6: Traverse tnc and construct files
         * Step 7: Update files' size
         * Step 8: Check and handle invalid files
+        * Step 9: Check and handle unreachable files
         */
        err = do_fsck();
        if (err && FSCK(c)->try_rebuild) {
index 7ac512c10c55feb797c69c3121c3cbde1c2e5bcc..521723d757951bc28c4ccafacbfe4f774f9a185f 100644 (file)
@@ -43,7 +43,7 @@ enum { SB_CORRUPTED = 0, MST_CORRUPTED, LOG_CORRUPTED, BUD_CORRUPTED,
        FILE_HAS_0_NLINK_INODE, FILE_HAS_INCONSIST_TYPE, FILE_HAS_TOO_MANY_DENT,
        FILE_SHOULDNT_HAVE_DATA, FILE_HAS_NO_DENT, XATTR_HAS_NO_HOST,
        XATTR_HAS_WRONG_HOST, FILE_HAS_NO_ENCRYPT, FILE_IS_DISCONNECTED,
-       FILE_ROOT_HAS_DENT };
+       FILE_ROOT_HAS_DENT, DENTRY_IS_UNREACHABLE };
 
 enum { HAS_DATA_CORRUPTED = 1, HAS_TNC_CORRUPTED = 2 };
 
@@ -317,5 +317,6 @@ int ubifs_rebuild_filesystem(struct ubifs_info *c);
 int traverse_tnc_and_construct_files(struct ubifs_info *c);
 void update_files_size(struct ubifs_info *c);
 int handle_invalid_files(struct ubifs_info *c);
+int handle_dentry_tree(struct ubifs_info *c);
 
 #endif
index 9222cba47b6d81450283d2e637cf0a94fb234477..0395a34fdacc9ae0874c73a90e49738eec9045d7 100644 (file)
@@ -58,6 +58,7 @@ static const struct fsck_problem problem_table[] = {
        {PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA, "Encrypted file has no encryption information"},       // FILE_HAS_NO_ENCRYPT
        {PROBLEM_FIXABLE | PROBLEM_MUST_FIX, "File is disconnected(regular file without dentries)"},    // FILE_IS_DISCONNECTED
        {PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA, "Root dir should not have a dentry"},  // FILE_ROOT_HAS_DENT
+       {PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA, "Dentry is unreachable"},      // DENTRY_IS_UNREACHABLE
 };
 
 static const char *get_question(const struct fsck_problem *problem,
@@ -84,6 +85,7 @@ static const char *get_question(const struct fsck_problem *problem,
        case XATTR_HAS_WRONG_HOST:
        case FILE_HAS_NO_ENCRYPT:
        case FILE_ROOT_HAS_DENT:
+       case DENTRY_IS_UNREACHABLE:
                return "Delete it?";
        case FILE_HAS_INCONSIST_TYPE:
        case FILE_HAS_TOO_MANY_DENT:
@@ -198,6 +200,18 @@ static void print_problem(const struct ubifs_info *c,
                        host->ino.is_xattr ? "(xattr)" : "");
                break;
        }
+       case DENTRY_IS_UNREACHABLE:
+       {
+               const struct invalid_file_problem *ifp = (const struct invalid_file_problem *)priv;
+               const struct scanned_dent_node *dent_node = (const struct scanned_dent_node *)ifp->priv;
+
+               log_out(c, "problem: %s, ino %lu, unreachable dentry %s, type %s%s",
+                       problem->desc, ifp->file->inum,
+                       c->encrypted && !ifp->file->ino.is_xattr ? "<encrypted>" : dent_node->name,
+                       ubifs_get_type_name(dent_node->type),
+                       key_type(c, &dent_node->key) == UBIFS_XENT_KEY ? "(xattr)" : "");
+               break;
+       }
        default:
                log_out(c, "problem: %s", problem->desc);
                break;