diff options
author | Zhihao Cheng <chengzhihao1@huawei.com> | 2024-11-11 17:01:22 +0800 |
---|---|---|
committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2024-11-11 10:32:46 +0100 |
commit | cf844f788d34e1facf142910b955554c69eb8f9b (patch) | |
tree | 1da22bb52854b759515661b41ea1fb4b53524a91 /ubifs-utils/libubifs | |
parent | 3f8ee068870a046b0dcf2921ed7ee375f405e49f (diff) |
fsck.ubifs: Replay journal
This is the 2/18 step of fsck. Replay journal, update TNC & LPT.
There could be following steps and possible errors:
Step 1. scan log LEB, get all bud LEBs
a. corrupted scanning data in log area: danger mode with rebuild_fs and
normal mode with 'yes' answer will turn to rebuild filesystem, other
modes will exit.
Step 2. scan bud LEBs, get all nodes
a. corrupted scanning data in bud LEB: danger mode and normal mode with
'yes' answer will drop bud LEB and set %FR_LPT_INCORRECT for lpt
status, other modes will exit.
Step 3. apply nodes, record latest isize into size_tree
Step 4. apply nodes, update TNC & LPT
a. corrupted data searched from TNC: skip node and set %FR_LPT_INCORRECT
lpt status 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.
c. corrupted lpt: Set %FR_LPT_CORRUPTED for lpt status. Ignore the
error.
d. incorrect lpt: Set %FR_LPT_INCORRECT for lpt status. Ignore the
error.
e. 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>
Diffstat (limited to 'ubifs-utils/libubifs')
-rw-r--r-- | ubifs-utils/libubifs/lprops.c | 21 | ||||
-rw-r--r-- | ubifs-utils/libubifs/replay.c | 54 | ||||
-rw-r--r-- | ubifs-utils/libubifs/tnc.c | 13 | ||||
-rw-r--r-- | ubifs-utils/libubifs/ubifs.h | 11 |
4 files changed, 89 insertions, 10 deletions
diff --git a/ubifs-utils/libubifs/lprops.c b/ubifs-utils/libubifs/lprops.c index 84cdb35..a7a2305 100644 --- a/ubifs-utils/libubifs/lprops.c +++ b/ubifs-utils/libubifs/lprops.c @@ -656,14 +656,24 @@ int ubifs_change_one_lp(struct ubifs_info *c, int lnum, int free, int dirty, int err = 0, flags; const struct ubifs_lprops *lp; + if (!test_lpt_valid_callback(c, lnum, LPROPS_NC, LPROPS_NC, LPROPS_NC, + LPROPS_NC)) + return 0; + ubifs_get_lprops(c); lp = ubifs_lpt_lookup_dirty(c, lnum); if (IS_ERR(lp)) { err = PTR_ERR(lp); + if (test_and_clear_failure_reason_callback(c, FR_LPT_CORRUPTED) && + can_ignore_failure_callback(c, FR_LPT_CORRUPTED)) + err = 0; goto out; } + if (!test_lpt_valid_callback(c, lnum, lp->free, lp->dirty, free, dirty)) + goto out; + flags = (lp->flags | flags_set) & ~flags_clean; lp = ubifs_change_lp(c, lp, free, dirty, flags, idx_gc_cnt); if (IS_ERR(lp)) @@ -695,14 +705,25 @@ int ubifs_update_one_lp(struct ubifs_info *c, int lnum, int free, int dirty, int err = 0, flags; const struct ubifs_lprops *lp; + if (!test_lpt_valid_callback(c, lnum, LPROPS_NC, LPROPS_NC, LPROPS_NC, + LPROPS_NC)) + return 0; + ubifs_get_lprops(c); lp = ubifs_lpt_lookup_dirty(c, lnum); if (IS_ERR(lp)) { err = PTR_ERR(lp); + if (test_and_clear_failure_reason_callback(c, FR_LPT_CORRUPTED) && + can_ignore_failure_callback(c, FR_LPT_CORRUPTED)) + err = 0; goto out; } + if (!test_lpt_valid_callback(c, lnum, lp->free, lp->dirty, free, + lp->dirty + dirty)) + goto out; + flags = (lp->flags | flags_set) & ~flags_clean; lp = ubifs_change_lp(c, lp, free, lp->dirty + dirty, flags, 0); if (IS_ERR(lp)) diff --git a/ubifs-utils/libubifs/replay.c b/ubifs-utils/libubifs/replay.c index 30ed282..2741742 100644 --- a/ubifs-utils/libubifs/replay.c +++ b/ubifs-utils/libubifs/replay.c @@ -94,11 +94,18 @@ static int set_bud_lprops(struct ubifs_info *c, struct bud_entry *b) const struct ubifs_lprops *lp; int err = 0, dirty; + if (!test_lpt_valid_callback(c, b->bud->lnum, LPROPS_NC, LPROPS_NC, + LPROPS_NC, LPROPS_NC)) + return 0; + ubifs_get_lprops(c); lp = ubifs_lpt_lookup_dirty(c, b->bud->lnum); if (IS_ERR(lp)) { err = PTR_ERR(lp); + if (test_and_clear_failure_reason_callback(c, FR_LPT_CORRUPTED) && + can_ignore_failure_callback(c, FR_LPT_CORRUPTED)) + err = 0; goto out; } @@ -140,6 +147,10 @@ static int set_bud_lprops(struct ubifs_info *c, struct bud_entry *b) b->bud->lnum, lp->free, lp->dirty, b->free, b->dirty); } + if (!test_lpt_valid_callback(c, b->bud->lnum, lp->free, lp->dirty, + b->free, dirty + b->dirty)) + goto out; + lp = ubifs_change_lp(c, lp, b->free, dirty + b->dirty, lp->flags | LPROPS_TAKEN, 0); if (IS_ERR(lp)) { @@ -766,6 +777,7 @@ out: return err; out_dump: + set_failure_reason_callback(c, FR_DATA_CORRUPTED); ubifs_err(c, "bad node is at LEB %d:%d", lnum, snod->offs); ubifs_dump_node(c, snod->node, c->leb_size - snod->offs); ubifs_scan_destroy(sleb); @@ -781,14 +793,24 @@ out_dump: */ static int replay_buds(struct ubifs_info *c) { - struct bud_entry *b; + struct bud_entry *b, *tmp_b; int err; unsigned long long prev_sqnum = 0; - list_for_each_entry(b, &c->replay_buds, list) { + list_for_each_entry_safe(b, tmp_b, &c->replay_buds, list) { err = replay_bud(c, b); - if (err) + if (err) { + if (test_and_clear_failure_reason_callback(c, FR_DATA_CORRUPTED) && + handle_failure_callback(c, FR_H_BUD_CORRUPTED, b->bud)) { + /* Set %FR_LPT_INCORRECT for lpt status. */ + set_lpt_invalid_callback(c, FR_LPT_INCORRECT); + /* Skip replaying the bud LEB. */ + list_del(&b->list); + kfree(b); + continue; + } return err; + } ubifs_assert(c, b->sqnum > prev_sqnum); prev_sqnum = b->sqnum; @@ -1062,6 +1084,7 @@ out: return err; out_dump: + set_failure_reason_callback(c, FR_DATA_CORRUPTED); ubifs_err(c, "log error detected while replaying the log at LEB %d:%d", lnum, offs + snod->offs); ubifs_dump_node(c, snod->node, c->leb_size - snod->offs); @@ -1086,11 +1109,20 @@ static int take_ihead(struct ubifs_info *c) lp = ubifs_lpt_lookup_dirty(c, c->ihead_lnum); if (IS_ERR(lp)) { err = PTR_ERR(lp); + if (test_and_clear_failure_reason_callback(c, FR_LPT_CORRUPTED) && + can_ignore_failure_callback(c, FR_LPT_CORRUPTED)) + err = 0; goto out; } free = lp->free; + if (!test_lpt_valid_callback(c, c->ihead_lnum, LPROPS_NC, LPROPS_NC, + LPROPS_NC, LPROPS_NC)) { + err = free; + goto out; + } + lp = ubifs_change_lp(c, lp, LPROPS_NC, LPROPS_NC, lp->flags | LPROPS_TAKEN, 0); if (IS_ERR(lp)) { @@ -1123,10 +1155,17 @@ int ubifs_replay_journal(struct ubifs_info *c) if (free < 0) return free; /* Error code */ - if (c->ihead_offs != c->leb_size - free) { - ubifs_err(c, "bad index head LEB %d:%d", c->ihead_lnum, - c->ihead_offs); - return -EINVAL; + if (c->program_type != FSCK_PROGRAM_TYPE) { + /* + * Skip index head checking for fsck, it is hard to check it + * caused by possible corrupted/incorrect lpt, tnc updating + * will report error code if index tree is really corrupted. + */ + if (c->ihead_offs != c->leb_size - free) { + ubifs_err(c, "bad index head LEB %d:%d", c->ihead_lnum, + c->ihead_offs); + return -EINVAL; + } } dbg_mnt("start replaying the journal"); @@ -1147,6 +1186,7 @@ int ubifs_replay_journal(struct ubifs_info *c) * something went wrong and we cannot proceed mounting * the file-system. */ + set_failure_reason_callback(c, FR_DATA_CORRUPTED); ubifs_err(c, "no UBIFS nodes found at the log head LEB %d:%d, possibly corrupted", lnum, 0); err = -EINVAL; diff --git a/ubifs-utils/libubifs/tnc.c b/ubifs-utils/libubifs/tnc.c index 12c56e0..cd1013d 100644 --- a/ubifs-utils/libubifs/tnc.c +++ b/ubifs-utils/libubifs/tnc.c @@ -2402,9 +2402,22 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum) xent = ubifs_tnc_next_ent(c, &key1, &nm); if (IS_ERR(xent)) { + unsigned int reason; + err = PTR_ERR(xent); if (err == -ENOENT) break; + + 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)) { + /* Set %FR_LPT_INCORRECT for lpt status. */ + set_lpt_invalid_callback(c, FR_LPT_INCORRECT); + /* Leave xattrs to be deleted by subsequent steps */ + break; + } + } kfree(pxent); return err; } diff --git a/ubifs-utils/libubifs/ubifs.h b/ubifs-utils/libubifs/ubifs.h index 6f96555..ae812ff 100644 --- a/ubifs-utils/libubifs/ubifs.h +++ b/ubifs-utils/libubifs/ubifs.h @@ -1286,7 +1286,7 @@ struct ubifs_info { bool (*can_ignore_failure_cb)(const struct ubifs_info *c, unsigned int reason); bool (*handle_failure_cb)(const struct ubifs_info *c, - unsigned int reason); + unsigned int reason, void *priv); }; extern atomic_long_t ubifs_clean_zn_cnt; @@ -1542,6 +1542,11 @@ enum { FR_LPT_CORRUPTED = 4, /* LPT is corrupted */ FR_LPT_INCORRECT = 8 /* Space statistics are wrong */ }; +/* Partial failure reasons in common libs, which are handled by fsck. */ +enum { + FR_H_BUD_CORRUPTED = 0, /* Bud LEB is corrupted */ + FR_H_TNC_DATA_CORRUPTED, /* Data searched from TNC 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, unsigned int reason) @@ -1596,10 +1601,10 @@ static inline bool can_ignore_failure_callback(const struct ubifs_info *c, return false; } static inline bool handle_failure_callback(const struct ubifs_info *c, - unsigned int reason) + unsigned int reason, void *priv) { if (c->handle_failure_cb) - return c->handle_failure_cb(c, reason); + return c->handle_failure_cb(c, reason, priv); return false; } |