]> www.infradead.org Git - mtd-utils.git/commitdiff
fsck.ubifs: Handle orphan nodes
authorZhihao Cheng <chengzhihao1@huawei.com>
Mon, 11 Nov 2024 09:01:23 +0000 (17:01 +0800)
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>
Mon, 11 Nov 2024 09:32:46 +0000 (10:32 +0100)
This is the 3/18 step of fsck. Handle orphan nodes, update TNC & LPT.
There could be following steps and possible errors:
 Step 1. scan orphan LEB, get all orphan nodes
  a. corrupted scanning data in orphan area: danger mode and normal mode
     with 'yes' answer will drop orphan LEB, other modes will exit.
 Step 2. parse orphan node, find the original inode for each inum
  a. corrupted node searched from TNC: skip node for danger mode and
     normal mode with 'yes' answer, other modes will exit.
  b. corrupted index node read from TNC: danger mode with rebuild_fs and
     normal mode with 'yes' answer will turn to rebuild filesystem, other
     modes will exit.
 Step 4. remove inode for each inum, update TNC & LPT
  a. corrupted index node read from TNC: danger mode with rebuild_fs and
     normal mode with 'yes' answer will turn to rebuild filesystem, other
     modes will exit.
  b. corrupted lpt: Set %FR_LPT_CORRUPTED for lpt status. Ignore the
     error.
  c. incorrect lpt: Set %FR_LPT_INCORRECT for lpt status. Ignore the
     error.
  d. If lpt status is not empty, skip updating lpt.

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

index 85175cf839f5836da3fe22b682026dc2f9e3d892..31c2aa6a08409b9810b57d1ee14cffc90f288dc5 100644 (file)
@@ -328,6 +328,7 @@ static bool fsck_can_ignore_failure(const struct ubifs_info *c,
 static const unsigned int reason_mapping_table[] = {
        BUD_CORRUPTED,          /* FR_H_BUD_CORRUPTED */
        TNC_DATA_CORRUPTED,     /* FR_H_TNC_DATA_CORRUPTED */
+       ORPHAN_CORRUPTED,       /* FR_H_ORPHAN_CORRUPTED */
 };
 
 static bool fsck_handle_failure(const struct ubifs_info *c, unsigned int reason,
@@ -431,6 +432,7 @@ int main(int argc, char *argv[])
         * Init: Read superblock
         * Step 1: Read master & init lpt
         * Step 2: Replay journal
+        * Step 3: Handle orphan nodes
         */
        err = ubifs_load_filesystem(c);
        if (err) {
index f1da974ba23dfc3230c3fa7992e9f7b39fb2a9c8..a1c64e3a6035e4dc32f98ef83b79cff0d9a7d20b 100644 (file)
@@ -38,7 +38,7 @@ enum { NORMAL_MODE = 0, SAFE_MODE, DANGER_MODE0,
 
 /* Types of inconsistent problems */
 enum { SB_CORRUPTED = 0, MST_CORRUPTED, LOG_CORRUPTED, BUD_CORRUPTED,
-       TNC_CORRUPTED, TNC_DATA_CORRUPTED };
+       TNC_CORRUPTED, TNC_DATA_CORRUPTED, ORPHAN_CORRUPTED };
 
 struct scanned_file;
 
index f45c4117ea33bf206d58272cce9249a4dccd4cec..f376383cc2f0c709cf3b779c2eb01ae8889808ed 100644 (file)
@@ -183,10 +183,28 @@ int ubifs_load_filesystem(struct ubifs_info *c)
        /* Calculate 'min_idx_lebs' after journal replay */
        c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
 
+       log_out(c, "Handle orphan nodes");
+       err = ubifs_mount_orphans(c, c->need_recovery, c->ro_mount);
+       if (err) {
+               unsigned int reason = get_failure_reason_callback(c);
+
+               clear_failure_reason_callback(c);
+               if (reason & FR_TNC_CORRUPTED) {
+                       if (fix_problem(c, TNC_CORRUPTED, NULL))
+                               FSCK(c)->try_rebuild = true;
+               } else {
+                       ubifs_assert(c, reason == 0);
+                       exit_code |= FSCK_ERROR;
+               }
+               goto out_orphans;
+       }
+
        c->mounting = 0;
 
        return 0;
 
+out_orphans:
+       free_orphans(c);
 out_journal:
        destroy_journal(c);
 out_lpt:
@@ -214,6 +232,7 @@ void ubifs_destroy_filesystem(struct ubifs_info *c)
 {
        destroy_journal(c);
        free_wbufs(c);
+       free_orphans(c);
        ubifs_lpt_free(c, 0);
 
        c->max_sqnum = 0;
index 9df2c2aeff09e24dbb06981dd8fb71999b158557..9c8730a5604c0179f0dc468efd9de3a8b019dba3 100644 (file)
@@ -41,6 +41,7 @@ static const struct fsck_problem problem_table[] = {
        {PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA, "Corrupted bud LEB"},  // BUD_CORRUPTED
        {PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA | PROBLEM_NEED_REBUILD, "Corrupted index node"},        // TNC_CORRUPTED
        {PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA, "Corrupted data searched from TNC"},   // TNC_DATA_CORRUPTED
+       {PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA, "Corrupted orphan LEB"},       // ORPHAN_CORRUPTED
 };
 
 static const char *get_question(const struct fsck_problem *problem,
@@ -54,6 +55,8 @@ static const char *get_question(const struct fsck_problem *problem,
                return "Drop bud?";
        case TNC_DATA_CORRUPTED:
                return "Drop it?";
+       case ORPHAN_CORRUPTED:
+               return "Drop orphans on the LEB?";
        }
 
        return "Fix it?";
@@ -63,13 +66,26 @@ static void print_problem(const struct ubifs_info *c,
                          const struct fsck_problem *problem, int problem_type,
                          const void *priv)
 {
-       if (problem_type == BUD_CORRUPTED) {
+       switch (problem_type) {
+       case BUD_CORRUPTED:
+       {
                const struct ubifs_bud *bud = (const struct ubifs_bud *)priv;
 
                log_out(c, "problem: %s %d:%d %s", problem->desc, bud->lnum,
                        bud->start, dbg_jhead(bud->jhead));
-       } else
+               break;
+       }
+       case ORPHAN_CORRUPTED:
+       {
+               const int *lnum = (const int *)priv;
+
+               log_out(c, "problem: %s %d", problem->desc, *lnum);
+               break;
+       }
+       default:
                log_out(c, "problem: %s", problem->desc);
+               break;
+       }
 }
 
 static void fatal_error(const struct ubifs_info *c,
index 26668cbd3ace0cdb422e29ab9f6c0e8bced9b716..baa4db7827e43bc3d6e2c290d84184850c67dc3b 100644 (file)
@@ -423,6 +423,7 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
                        ubifs_dump_node(c, snod->node,
                                        c->leb_size - snod->offs);
                        err = -EINVAL;
+                       set_failure_reason_callback(c, FR_DATA_CORRUPTED);
                        goto out_free;
                }
 
@@ -452,6 +453,7 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
                                ubifs_dump_node(c, snod->node,
                                                c->leb_size - snod->offs);
                                err = -EINVAL;
+                               set_failure_reason_callback(c, FR_DATA_CORRUPTED);
                                goto out_free;
                        }
                        dbg_rcvry("out of date LEB %d", sleb->lnum);
@@ -471,8 +473,19 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
 
                        ino_key_init(c, &key, inum);
                        err = ubifs_tnc_lookup(c, &key, ino);
-                       if (err && err != -ENOENT)
+                       if (err && err != -ENOENT) {
+                               unsigned int reason;
+
+                               reason = get_failure_reason_callback(c);
+                               if (reason & FR_DATA_CORRUPTED) {
+                                       test_and_clear_failure_reason_callback(c, FR_DATA_CORRUPTED);
+                                       if (handle_failure_callback(c, FR_H_TNC_DATA_CORRUPTED, NULL)) {
+                                               /* Leave the inode to be deleted by subsequent steps */
+                                               continue;
+                                       }
+                               }
                                goto out_free;
+                       }
 
                        /*
                         * Check whether an inode can really get deleted.
@@ -483,8 +496,11 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
                                          (unsigned long)inum);
 
                                err = ubifs_tnc_remove_ino(c, inum);
-                               if (err)
+                               if (err) {
+                                       if (c->program_type == FSCK_PROGRAM_TYPE)
+                                               goto out_free;
                                        goto out_ro;
+                               }
                        }
                }
 
@@ -553,13 +569,33 @@ static int kill_orphans(struct ubifs_info *c)
                                                         c->sbuf, -1);
                        }
                        if (IS_ERR(sleb)) {
+                               if (test_and_clear_failure_reason_callback(c, FR_DATA_CORRUPTED) &&
+                                   handle_failure_callback(c, FR_H_ORPHAN_CORRUPTED, &lnum)) {
+                                       /* Skip the orphan LEB. */
+                                       continue;
+                               }
                                err = PTR_ERR(sleb);
                                break;
                        }
                }
                err = do_kill_orphans(c, sleb, &last_cmt_no, &outofdate,
                                      &last_flagged);
-               if (err || outofdate) {
+               if (err) {
+                       unsigned int reason = get_failure_reason_callback(c);
+
+                       if (reason & FR_DATA_CORRUPTED) {
+                               test_and_clear_failure_reason_callback(c, FR_DATA_CORRUPTED);
+                               if (handle_failure_callback(c, FR_H_ORPHAN_CORRUPTED, &lnum)) {
+                                       err = 0;
+                                       /* Skip the orphan LEB. */
+                                       ubifs_scan_destroy(sleb);
+                                       continue;
+                               }
+                       }
+                       ubifs_scan_destroy(sleb);
+                       break;
+               }
+               if (outofdate) {
                        ubifs_scan_destroy(sleb);
                        break;
                }
index ae812ff8642d59ec17b39dafca7cbf5bc77522d1..8a506a8b1c08791501a3f2392edead7f2ae8e1de 100644 (file)
@@ -1546,6 +1546,7 @@ enum {
 enum {
        FR_H_BUD_CORRUPTED = 0,         /* Bud LEB is corrupted */
        FR_H_TNC_DATA_CORRUPTED,        /* Data searched from TNC is corrupted */
+       FR_H_ORPHAN_CORRUPTED,          /* Orphan LEB is corrupted */
 };
 /* Callback functions for failure(which can be handled by fsck) happens. */
 static inline void set_failure_reason_callback(const struct ubifs_info *c,