diff options
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; } |