From 83b7477eae174e974237685f83f0fec4fb794892 Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Mon, 11 Nov 2024 17:08:09 +0800 Subject: fsck.ubifs: check and correct the space statistics This is the 12/18 step of fsck. Check and correct the space statistics. There could be following steps and possible errors: Step 1. Exit for check mode, if %FR_LPT_CORRUPTED or %FR_LPT_INCORRECT is set in lpt status, the exit code should have %FSCK_UNCORRECTED. Step 2. Check lpt status, if %FR_LPT_CORRUPTED is set in lpt status, normal mode with 'no' answer will exit, other modes will rebuild lpt. Step 3. Traverse LPT nodes, check the correctness of nnode and pnode, compare LEB scanning result with LEB properties. a. LPT node is corrupted, normal mode with 'no' answer will exit, rebuild lpt for other modes. b. Incorrect nnode/pnode, normal mode with 'no' answer will exit, other other modes will correct the nnode/pnode. c. Inconsistent comparing result, normal mode with 'no' answer will exit, other modes will correct the space statistics. Step 4. Check and correct the lprops table information. Step 5. Set gc lnum(ubifs_rcvry_gc_commit / take_gc_lnum). Signed-off-by: Zhihao Cheng Signed-off-by: David Oberhollenzer --- ubifs-utils/libubifs/lpt.c | 9 ++++++--- ubifs-utils/libubifs/lpt_commit.c | 18 ++++++++++++++---- ubifs-utils/libubifs/replay.c | 2 +- ubifs-utils/libubifs/ubifs.h | 5 ++++- 4 files changed, 25 insertions(+), 9 deletions(-) (limited to 'ubifs-utils/libubifs') diff --git a/ubifs-utils/libubifs/lpt.c b/ubifs-utils/libubifs/lpt.c index fc70cad..8e20a17 100644 --- a/ubifs-utils/libubifs/lpt.c +++ b/ubifs-utils/libubifs/lpt.c @@ -605,6 +605,7 @@ static int calc_pnode_num_from_parent(const struct ubifs_info *c, * @lps: array of logical eraseblock properties * @lp_cnt: the length of @lps * @hash: hash of the LPT is returned here + * @free_ltab: %true means to release c->ltab after creating lpt * * This function creates lpt, the pnode will be initialized based on * corresponding elements in @lps. If there are no corresponding lprops @@ -612,7 +613,7 @@ static int calc_pnode_num_from_parent(const struct ubifs_info *c, * as free state. */ int ubifs_create_lpt(struct ubifs_info *c, struct ubifs_lprops *lps, int lp_cnt, - u8 *hash) + u8 *hash, bool free_ltab) { int lnum, err = 0, i, j, cnt, len, alen, row; int blnum, boffs, bsz, bcnt; @@ -910,10 +911,12 @@ int ubifs_create_lpt(struct ubifs_info *c, struct ubifs_lprops *lps, int lp_cnt, if (c->big_lpt) dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs); out: - c->ltab = NULL; + if (free_ltab || err) { + c->ltab = NULL; + vfree(ltab); + } kfree(desc); kfree(lsave); - vfree(ltab); vfree(buf); kfree(nnode); kfree(pnode); diff --git a/ubifs-utils/libubifs/lpt_commit.c b/ubifs-utils/libubifs/lpt_commit.c index 8a44546..ee84f80 100644 --- a/ubifs-utils/libubifs/lpt_commit.c +++ b/ubifs-utils/libubifs/lpt_commit.c @@ -1599,7 +1599,7 @@ static int dbg_is_node_dirty(struct ubifs_info *c, int node_type, int lnum, * * This function returns %0 on success and a negative error code on failure. */ -static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum) +int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum) { int err, len = c->leb_size, dirty = 0, node_type, node_num, node_len; int ret; @@ -1608,7 +1608,7 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum) buf = p = __vmalloc(c->leb_size, GFP_NOFS); if (!buf) { ubifs_err(c, "cannot allocate memory for ltab checking"); - return 0; + return -ENOMEM; } dbg_lp("LEB %d", lnum); @@ -1632,20 +1632,30 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum) continue; } if (!dbg_is_all_ff(p, len)) { + set_failure_reason_callback(c, FR_LPT_CORRUPTED); ubifs_err(c, "invalid empty space in LEB %d at %d", lnum, c->leb_size - len); err = -EINVAL; + goto out; } i = lnum - c->lpt_first; if (len != c->ltab[i].free) { ubifs_err(c, "invalid free space in LEB %d (free %d, expected %d)", - lnum, len, c->ltab[i].free); + lnum, c->ltab[i].free, len); err = -EINVAL; + if (handle_failure_callback(c, FR_H_LTAB_INCORRECT, NULL)) { + c->ltab[i].free = len; + err = 0; + } } if (dirty != c->ltab[i].dirty) { ubifs_err(c, "invalid dirty space in LEB %d (dirty %d, expected %d)", - lnum, dirty, c->ltab[i].dirty); + lnum, c->ltab[i].dirty, dirty); err = -EINVAL; + if (handle_failure_callback(c, FR_H_LTAB_INCORRECT, NULL)) { + c->ltab[i].dirty = dirty; + err = 0; + } } goto out; } diff --git a/ubifs-utils/libubifs/replay.c b/ubifs-utils/libubifs/replay.c index 2741742..3943b32 100644 --- a/ubifs-utils/libubifs/replay.c +++ b/ubifs-utils/libubifs/replay.c @@ -1099,7 +1099,7 @@ out_dump: * This function returns the amount of free space in the index head LEB or a * negative error code. */ -static int take_ihead(struct ubifs_info *c) +int take_ihead(struct ubifs_info *c) { const struct ubifs_lprops *lp; int err, free; diff --git a/ubifs-utils/libubifs/ubifs.h b/ubifs-utils/libubifs/ubifs.h index 45c4105..a4b05a6 100644 --- a/ubifs-utils/libubifs/ubifs.h +++ b/ubifs-utils/libubifs/ubifs.h @@ -1563,6 +1563,7 @@ 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 */ + FR_H_LTAB_INCORRECT, /* Lprops table is incorrect */ }; /* Callback functions for failure(which can be handled by fsck) happens. */ static inline void set_failure_reason_callback(const struct ubifs_info *c, @@ -1734,6 +1735,7 @@ int ubifs_fixup_free_space(struct ubifs_info *c); /* replay.c */ int ubifs_validate_entry(struct ubifs_info *c, const struct ubifs_dent_node *dent); +int take_ihead(struct ubifs_info *c); int ubifs_replay_journal(struct ubifs_info *c); /* gc.c */ @@ -1754,7 +1756,7 @@ int ubifs_clear_orphans(struct ubifs_info *c); int ubifs_calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs, int *big_lpt); int ubifs_calc_lpt_geom(struct ubifs_info *c); int ubifs_create_lpt(struct ubifs_info *c, struct ubifs_lprops *lps, int lp_cnt, - u8 *hash); + u8 *hash, bool free_ltab); int ubifs_lpt_init(struct ubifs_info *c, int rd, int wr); struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum); struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum); @@ -1795,6 +1797,7 @@ int ubifs_lpt_end_commit(struct ubifs_info *c); int ubifs_lpt_post_commit(struct ubifs_info *c); void ubifs_free_lpt_nodes(struct ubifs_info *c); void ubifs_lpt_free(struct ubifs_info *c, int wr_only); +int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum); /* lprops.c */ const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c, -- cgit v1.2.3