]> www.infradead.org Git - mtd-utils.git/commitdiff
fsck.ubifs: Read master node & init lpt
authorZhihao Cheng <chengzhihao1@huawei.com>
Mon, 11 Nov 2024 09:01:21 +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 1/18 step of fsck. Read and check master node, init lpt.
There could be following errors:
 1. corrupted scanning data in master area or invalid master node:
    danger mode with rebuild_fs and normal mode with 'yes' answer will
    turn to rebuild filesystem, other modes will exit.
 2. incorrect space statistics in master node: Set %FR_LPT_INCORRECT for
    for lpt status. Ignore the error.
 3. corrupted lpt: Set %FR_LPT_CORRUPTED for lpt status. Ignore the error.

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/lpt.c
ubifs-utils/libubifs/master.c

index e674451609c29fae91420ca20a23dafc7f35e870..2fd68df56d409fab3cf6c7857f6c394ee7256e00 100644 (file)
@@ -423,7 +423,10 @@ int main(int argc, char *argv[])
                goto out_destroy_fsck;
        }
 
-       /* Init: Read superblock */
+       /*
+        * Init: Read superblock
+        * Step 1: Read master & init lpt
+        */
        err = ubifs_load_filesystem(c);
        if (err) {
                if (FSCK(c)->try_rebuild)
index d25ecc2d2efe46af1d085c1fcbea247e52af1815..7f8261567bd4b315da3c0e4d90d39e7525e43806 100644 (file)
@@ -37,7 +37,7 @@ enum { NORMAL_MODE = 0, SAFE_MODE, DANGER_MODE0,
        DANGER_MODE1, REBUILD_MODE, CHECK_MODE };
 
 /* Types of inconsistent problems */
-enum { SB_CORRUPTED = 0 };
+enum { SB_CORRUPTED = 0, MST_CORRUPTED };
 
 struct scanned_file;
 
index 4a06b4c242922c5f566a959d57c46e4638afce53..036e307cb8f3256aac16230145afef4ca0276ba7 100644 (file)
@@ -99,10 +99,81 @@ int ubifs_load_filesystem(struct ubifs_info *c)
                goto out_mounting;
        }
 
+       log_out(c, "Read master & init lpt");
+       err = ubifs_read_master(c);
+       if (err) {
+               if (test_and_clear_failure_reason_callback(c, FR_DATA_CORRUPTED)) {
+                       if (fix_problem(c, MST_CORRUPTED))
+                               FSCK(c)->try_rebuild = true;
+               } else
+                       exit_code |= FSCK_ERROR;
+               goto out_master;
+       }
+
+       init_constants_master(c);
+
+       if ((c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY)) != 0) {
+               ubifs_msg(c, "recovery needed");
+               c->need_recovery = 1;
+       }
+
+       if (c->need_recovery && !c->ro_mount) {
+               err = ubifs_recover_inl_heads(c, c->sbuf);
+               if (err) {
+                       exit_code |= FSCK_ERROR;
+                       goto out_master;
+               }
+       }
+
+       err = ubifs_lpt_init(c, 1, !c->ro_mount);
+       if (err) {
+               exit_code |= FSCK_ERROR;
+               goto out_master;
+       }
+
+       if (!c->ro_mount && c->space_fixup) {
+               err = ubifs_fixup_free_space(c);
+               if (err) {
+                       exit_code |= FSCK_ERROR;
+                       goto out_lpt;
+               }
+       }
+
+       if (!c->ro_mount && !c->need_recovery) {
+               /*
+                * Set the "dirty" flag so that if we reboot uncleanly we
+                * will notice this immediately on the next mount.
+                */
+               c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
+               err = ubifs_write_master(c);
+               if (err) {
+                       exit_code |= FSCK_ERROR;
+                       goto out_lpt;
+               }
+       }
+
+       if (!c->ro_mount && c->superblock_need_write) {
+               err = ubifs_write_sb_node(c, c->sup_node);
+               if (err) {
+                       exit_code |= FSCK_ERROR;
+                       goto out_lpt;
+               }
+               c->superblock_need_write = 0;
+       }
+
        c->mounting = 0;
 
        return 0;
 
+out_lpt:
+       ubifs_lpt_free(c, 0);
+out_master:
+       c->max_sqnum = 0;
+       c->highest_inum = 0;
+       c->calc_idx_sz = 0;
+       kfree(c->mst_node);
+       kfree(c->rcvrd_mst_node);
+       free_wbufs(c);
 out_mounting:
        c->mounting = 0;
 out_free:
@@ -118,8 +189,15 @@ out_free:
 void ubifs_destroy_filesystem(struct ubifs_info *c)
 {
        free_wbufs(c);
+       ubifs_lpt_free(c, 0);
+
+       c->max_sqnum = 0;
+       c->highest_inum = 0;
+       c->calc_idx_sz = 0;
 
        kfree(c->cbuf);
+       kfree(c->rcvrd_mst_node);
+       kfree(c->mst_node);
        kfree(c->ileb_buf);
        kfree(c->sbuf);
        kfree(c->bottom_up_buf);
index acb9e45ecd118bb4f41fa1b7cc71a735409dea9c..1af66632732e489dd44b1bb366b1e440ca9219d3 100644 (file)
@@ -36,6 +36,7 @@ struct fsck_problem {
 
 static const struct fsck_problem problem_table[] = {
        {0, "Corrupted superblock"},    // SB_CORRUPTED
+       {PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA | PROBLEM_NEED_REBUILD, "Corrupted master node"},       // MST_CORRUPTED
 };
 
 static void print_problem(const struct ubifs_info *c,
index c0df7c7d7721ba8180f21c130768281d46d28898..b07f1f7775d11de158e4dc352a6165254d41a2a0 100644 (file)
@@ -1883,8 +1883,13 @@ static int lpt_init_rd(struct ubifs_info *c)
        c->dirty_idx.max_cnt = LPT_HEAP_SZ;
 
        err = read_ltab(c);
-       if (err)
-               return err;
+       if (err) {
+               if (test_and_clear_failure_reason_callback(c, FR_LPT_CORRUPTED) &&
+                   can_ignore_failure_callback(c, FR_LPT_CORRUPTED))
+                       err = 0;
+               else
+                       return err;
+       }
 
        err = lpt_check_hash(c);
        if (err)
@@ -1938,8 +1943,13 @@ static int lpt_init_wr(struct ubifs_info *c)
                if (!c->lsave)
                        return -ENOMEM;
                err = read_lsave(c);
-               if (err)
-                       return err;
+               if (err) {
+                       if (test_and_clear_failure_reason_callback(c, FR_LPT_CORRUPTED) &&
+                           can_ignore_failure_callback(c, FR_LPT_CORRUPTED))
+                               err = 0;
+                       else
+                               return err;
+               }
        }
 
        for (i = 0; i < c->lpt_lebs; i++)
index 61ff4cec6f5e8202704a6162408661c725ee5178..54d2a7897a0fc37fca6fdbb616c5406cf5176c63 100644 (file)
@@ -323,7 +323,12 @@ out:
        set_failure_reason_callback(c, reason);
        ubifs_err(c, "bad master node at offset %d error %d", c->mst_offs, err);
        ubifs_dump_node(c, c->mst_node, c->mst_node_alsz);
-       return -EINVAL;
+       err = -EINVAL;
+       if (can_ignore_failure_callback(c, reason)) {
+               clear_failure_reason_callback(c);
+               err = 0;
+       }
+       return err;
 }
 
 /**