aboutsummaryrefslogtreecommitdiff
path: root/ubifs-utils/libubifs
diff options
context:
space:
mode:
Diffstat (limited to 'ubifs-utils/libubifs')
-rw-r--r--ubifs-utils/libubifs/lprops.c21
-rw-r--r--ubifs-utils/libubifs/replay.c54
-rw-r--r--ubifs-utils/libubifs/tnc.c13
-rw-r--r--ubifs-utils/libubifs/ubifs.h11
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;
}