]> www.infradead.org Git - mtd-utils.git/commitdiff
fsck.ubifs: Check and correct files' information
authorXiang Yang <xiangyang3@huawei.com>
Mon, 11 Nov 2024 09:08:06 +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 10/18 step of fsck. Check and handle inconsistent files, the
checking rule is same as rebuild mode which has been implemented in
check_and_correct_files, but the methods of handling are different:
 1. Correct the file information for safe mode, danger mode and normal
    mode with 'yes' answer, other modes will exit.

Signed-off-by: Xiang Yang <xiangyang3@huawei.com>
Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
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 b24445bebb92606bfbf64401beb733e3a0a89b3e..c83d37749bc041d2c3fe01a979d15e6ed6c7bcf9 100644 (file)
@@ -1292,8 +1292,8 @@ reachable:
  * data nodes and truncation node. The calculated informaion will be used
  * to correct inode node.
  */
-static void calculate_file_info(struct ubifs_info *c, struct scanned_file *file,
-                               struct rb_root *file_tree)
+static int calculate_file_info(struct ubifs_info *c, struct scanned_file *file,
+                              struct rb_root *file_tree)
 {
        int nlink = 0;
        bool corrupted_truncation = false;
@@ -1306,15 +1306,24 @@ static void calculate_file_info(struct ubifs_info *c, struct scanned_file *file,
 
        for (node = rb_first(&file->xattr_files); node; node = rb_next(node)) {
                xattr_file = rb_entry(node, struct scanned_file, rb);
+               dent_node = rb_entry(rb_first(&xattr_file->dent_nodes),
+                                    struct scanned_dent_node, rb);
 
+               ubifs_assert(c, xattr_file->ino.is_xattr);
                ubifs_assert(c, !rb_first(&xattr_file->xattr_files));
-               calculate_file_info(c, xattr_file, file_tree);
+               xattr_file->calc_nlink = 1;
+               xattr_file->calc_size = xattr_file->ino.size;
+
+               file->calc_xcnt += 1;
+               file->calc_xsz += CALC_DENT_SIZE(dent_node->nlen);
+               file->calc_xsz += CALC_XATTR_BYTES(xattr_file->ino.size);
+               file->calc_xnms += dent_node->nlen;
        }
 
        if (file->inum == UBIFS_ROOT_INO) {
                file->calc_nlink += 2;
                file->calc_size += UBIFS_INO_NODE_SZ;
-               return;
+               return 0;
        }
 
        if (S_ISDIR(file->ino.mode)) {
@@ -1326,29 +1335,11 @@ static void calculate_file_info(struct ubifs_info *c, struct scanned_file *file,
                parent_file = lookup_file(file_tree, key_inum(c, &dent_node->key));
                if (!parent_file) {
                        ubifs_assert(c, 0);
-                       return;
+                       return 0;
                }
                parent_file->calc_nlink += 1;
                parent_file->calc_size += CALC_DENT_SIZE(dent_node->nlen);
-               return;
-       }
-
-       if (file->ino.is_xattr) {
-               file->calc_nlink = 1;
-               file->calc_size = file->ino.size;
-
-               dent_node = rb_entry(rb_first(&file->dent_nodes),
-                                    struct scanned_dent_node, rb);
-               parent_file = lookup_file(file_tree, key_inum(c, &dent_node->key));
-               if (!parent_file) {
-                       ubifs_assert(c, 0);
-                       return;
-               }
-               parent_file->calc_xcnt += 1;
-               parent_file->calc_xsz += CALC_DENT_SIZE(dent_node->nlen);
-               parent_file->calc_xsz += CALC_XATTR_BYTES(file->ino.size);
-               parent_file->calc_xnms += dent_node->nlen;
-               return;
+               return 0;
        }
 
        for (node = rb_first(&file->dent_nodes); node; node = rb_next(node)) {
@@ -1359,7 +1350,7 @@ static void calculate_file_info(struct ubifs_info *c, struct scanned_file *file,
                parent_file = lookup_file(file_tree, key_inum(c, &dent_node->key));
                if (!parent_file) {
                        ubifs_assert(c, 0);
-                       return;
+                       return 0;
                }
                parent_file->calc_size += CALC_DENT_SIZE(dent_node->nlen);
        }
@@ -1368,7 +1359,7 @@ static void calculate_file_info(struct ubifs_info *c, struct scanned_file *file,
        if (!S_ISREG(file->ino.mode)) {
                /* No need to verify i_size for symlink/sock/block/char/fifo. */
                file->calc_size = file->ino.size;
-               return;
+               return 0;
        }
 
        /*
@@ -1452,10 +1443,22 @@ drop_data:
                data_node = list_entry(drop_list.next, struct scanned_data_node,
                                       list);
 
+               if (FSCK(c)->mode != REBUILD_MODE) {
+                       /*
+                        * Don't ask, inconsistent file correcting will be
+                        * asked in function correct_file_info().
+                        */
+                       int err = delete_node(c, &data_node->key,
+                               data_node->header.lnum, data_node->header.offs);
+                       if (err)
+                               return err;
+               }
                list_del(&data_node->list);
                rb_erase(&data_node->rb, &file->data_nodes);
                kfree(data_node);
        }
+
+       return 0;
 }
 
 /**
@@ -1490,6 +1493,7 @@ static int correct_file_info(struct ubifs_info *c, struct scanned_file *file)
            file->calc_size == file->ino.size)
                return 0;
 
+       handle_invalid_file(c, FILE_IS_INCONSISTENT, file, NULL);
        lnum = file->ino.header.lnum;
        dbg_fsck("correct file(inum:%lu type:%s), nlink %u->%u, xattr cnt %u->%u, xattr size %u->%u, xattr names %u->%u, size %llu->%llu, at %d:%d, in %s",
                 file->inum, file->ino.is_xattr ? "xattr" :
@@ -1537,7 +1541,9 @@ int check_and_correct_files(struct ubifs_info *c)
        for (node = rb_first(tree); node; node = rb_next(node)) {
                file = rb_entry(node, struct scanned_file, rb);
 
-               calculate_file_info(c, file, tree);
+               err = calculate_file_info(c, file, tree);
+               if (err)
+                       return err;
        }
 
        for (node = rb_first(tree); node; node = rb_next(node)) {
@@ -1548,5 +1554,21 @@ int check_and_correct_files(struct ubifs_info *c)
                        return err;
        }
 
+       if (list_empty(&FSCK(c)->disconnected_files))
+               return 0;
+
+       ubifs_assert(c, FSCK(c)->mode != REBUILD_MODE);
+       list_for_each_entry(file, &FSCK(c)->disconnected_files, list) {
+               err = calculate_file_info(c, file, tree);
+               if (err)
+                       return err;
+
+               /* Reset disconnected file's nlink as one. */
+               file->calc_nlink = 1;
+               err = correct_file_info(c, file);
+               if (err)
+                       return err;
+       }
+
        return 0;
 }
index 6a718fd89d5468a5cce59645706c76c5e8443669..3f61668e9f964499f3a9ace8231d0dae24008832 100644 (file)
@@ -460,6 +460,13 @@ static int do_fsck(void)
                goto free_disconnected_files;
        }
 
+       log_out(c, "Check and correct files");
+       err = check_and_correct_files(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:
@@ -504,6 +511,7 @@ int main(int argc, char *argv[])
         * Step 7: Update files' size
         * Step 8: Check and handle invalid files
         * Step 9: Check and handle unreachable files
+        * Step 10: Check and correct files
         */
        err = do_fsck();
        if (err && FSCK(c)->try_rebuild) {
index 521723d757951bc28c4ccafacbfe4f774f9a185f..32a991dd412f4bd6ff251641fc27f7131d309a62 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, DENTRY_IS_UNREACHABLE };
+       FILE_ROOT_HAS_DENT, DENTRY_IS_UNREACHABLE, FILE_IS_INCONSISTENT };
 
 enum { HAS_DATA_CORRUPTED = 1, HAS_TNC_CORRUPTED = 2 };
 
index 0395a34fdacc9ae0874c73a90e49738eec9045d7..e8f08606c51f020fc250ec8b2a8ab76a1d55cbb4 100644 (file)
@@ -59,6 +59,7 @@ static const struct fsck_problem problem_table[] = {
        {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
+       {PROBLEM_FIXABLE | PROBLEM_MUST_FIX, "File is inconsistent"},   // FILE_IS_INCONSISTENT
 };
 
 static const char *get_question(const struct fsck_problem *problem,
@@ -212,6 +213,21 @@ static void print_problem(const struct ubifs_info *c,
                        key_type(c, &dent_node->key) == UBIFS_XENT_KEY ? "(xattr)" : "");
                break;
        }
+       case FILE_IS_INCONSISTENT:
+       {
+               const struct invalid_file_problem *ifp = (const struct invalid_file_problem *)priv;
+               const struct scanned_file *file = ifp->file;
+
+               log_out(c, "problem: %s, ino %lu type %s, nlink %u xcnt %u xsz %u xnms %u size %llu, "
+                       "should be nlink %u xcnt %u xsz %u xnms %u size %llu",
+                       problem->desc, file->inum,
+                       file->ino.is_xattr ? "xattr" : ubifs_get_type_name(ubifs_get_dent_type(file->ino.mode)),
+                       file->ino.nlink, file->ino.xcnt, file->ino.xsz,
+                       file->ino.xnms, file->ino.size,
+                       file->calc_nlink, file->calc_xcnt, file->calc_xsz,
+                       file->calc_xnms, file->calc_size);
+               break;
+       }
        default:
                log_out(c, "problem: %s", problem->desc);
                break;