diff --git a/ubifs-utils/fsck.ubifs/fsck.ubifs.c b/ubifs-utils/fsck.ubifs/fsck.ubifs.c
index b1286150..36a8e061 100644
--- a/ubifs-utils/fsck.ubifs/fsck.ubifs.c
+++ b/ubifs-utils/fsck.ubifs/fsck.ubifs.c
@@ -168,6 +168,172 @@ static void fsck_assert_failed(__unused const struct ubifs_info *c)
 	exit(exit_code);
 }
 
+static void fsck_set_failure_reason(const struct ubifs_info *c,
+				    unsigned int reason)
+{
+	if (FSCK(c)->mode == REBUILD_MODE)
+		return;
+
+	FSCK(c)->failure_reason = reason;
+	if (reason & FR_LPT_CORRUPTED) {
+		log_out(c, "Found corrupted pnode/nnode, set lpt corrupted");
+		FSCK(c)->lpt_status |= FR_LPT_CORRUPTED;
+	}
+	if (reason & FR_LPT_INCORRECT) {
+		log_out(c, "Bad space statistics, set lpt incorrect");
+		FSCK(c)->lpt_status |= FR_LPT_INCORRECT;
+	}
+}
+
+static unsigned int fsck_get_failure_reason(const struct ubifs_info *c)
+{
+	ubifs_assert(c, FSCK(c)->mode != REBUILD_MODE);
+
+	return FSCK(c)->failure_reason;
+}
+
+static void fsck_clear_failure_reason(const struct ubifs_info *c)
+{
+	ubifs_assert(c, FSCK(c)->mode != REBUILD_MODE);
+
+	FSCK(c)->failure_reason = 0;
+}
+
+static bool fsck_test_and_clear_failure_reason(const struct ubifs_info *c,
+					       unsigned int reason)
+{
+	bool res = (FSCK(c)->failure_reason & reason) != 0;
+
+	ubifs_assert(c, FSCK(c)->mode != REBUILD_MODE);
+	ubifs_assert(c, !(FSCK(c)->failure_reason & (~reason)));
+
+	FSCK(c)->failure_reason = 0;
+
+	return res;
+}
+
+static void fsck_set_lpt_invalid(const struct ubifs_info *c,
+				 unsigned int reason)
+{
+	ubifs_assert(c, FSCK(c)->mode != REBUILD_MODE);
+
+	if (reason & FR_LPT_CORRUPTED) {
+		log_out(c, "Found corrupted pnode/nnode, set lpt corrupted");
+		FSCK(c)->lpt_status |= FR_LPT_CORRUPTED;
+	}
+	if (reason & FR_LPT_INCORRECT) {
+		log_out(c, "Bad space statistics, set lpt incorrect");
+		FSCK(c)->lpt_status |= FR_LPT_INCORRECT;
+	}
+}
+
+static bool fsck_test_lpt_valid(const struct ubifs_info *c, int lnum,
+				int old_free, int old_dirty,
+				int free, int dirty)
+{
+	ubifs_assert(c, FSCK(c)->mode != REBUILD_MODE);
+
+	if (c->cmt_state != COMMIT_RESTING)
+		/* Don't skip updating lpt when do commit. */
+		goto out;
+
+	if (FSCK(c)->lpt_status)
+		return false;
+
+	if (c->lst.empty_lebs < 0 || c->lst.empty_lebs > c->main_lebs) {
+		log_out(c, "Bad empty_lebs %d(main_lebs %d), set lpt incorrect",
+			c->lst.empty_lebs, c->main_lebs);
+		goto out_invalid;
+	}
+	if (c->freeable_cnt < 0 || c->freeable_cnt > c->main_lebs) {
+		log_out(c, "Bad freeable_cnt %d(main_lebs %d), set lpt incorrect",
+			c->freeable_cnt, c->main_lebs);
+		goto out_invalid;
+	}
+	if (c->lst.taken_empty_lebs < 0 ||
+	    c->lst.taken_empty_lebs > c->lst.empty_lebs) {
+		log_out(c, "Bad taken_empty_lebs %d(empty_lebs %d), set lpt incorrect",
+			c->lst.taken_empty_lebs, c->lst.empty_lebs);
+		goto out_invalid;
+	}
+	if (c->lst.total_free & 7) {
+		log_out(c, "total_free(%lld) is not 8 bytes aligned, set lpt incorrect",
+			c->lst.total_free);
+		goto out_invalid;
+	}
+	if (c->lst.total_dirty & 7) {
+		log_out(c, "total_dirty(%lld) is not 8 bytes aligned, set lpt incorrect",
+			c->lst.total_dirty);
+		goto out_invalid;
+	}
+	if (c->lst.total_dead & 7) {
+		log_out(c, "total_dead(%lld) is not 8 bytes aligned, set lpt incorrect",
+			c->lst.total_dead);
+		goto out_invalid;
+	}
+	if (c->lst.total_dark & 7) {
+		log_out(c, "total_dark(%lld) is not 8 bytes aligned, set lpt incorrect",
+			c->lst.total_dark);
+		goto out_invalid;
+	}
+	if (c->lst.total_used & 7) {
+		log_out(c, "total_used(%lld) is not 8 bytes aligned, set lpt incorrect",
+			c->lst.total_used);
+		goto out_invalid;
+	}
+	if (old_free != LPROPS_NC && (old_free & 7)) {
+		log_out(c, "LEB %d old_free(%d) is not 8 bytes aligned, set lpt incorrect",
+			lnum, old_free);
+		goto out_invalid;
+	}
+	if (old_dirty != LPROPS_NC && (old_dirty & 7)) {
+		log_out(c, "LEB %d old_dirty(%d) is not 8 bytes aligned, set lpt incorrect",
+			lnum, old_dirty);
+		goto out_invalid;
+	}
+	if (free != LPROPS_NC && (free < 0 || free > c->leb_size)) {
+		log_out(c, "LEB %d bad free %d(leb_size %d), set lpt incorrect",
+			lnum, free, c->leb_size);
+		goto out_invalid;
+	}
+	if (dirty != LPROPS_NC && dirty < 0) {
+		/* Dirty may be more than c->leb_size before set_bud_lprops. */
+		log_out(c, "LEB %d bad dirty %d(leb_size %d), set lpt incorrect",
+			lnum, dirty, c->leb_size);
+		goto out_invalid;
+	}
+
+out:
+	return true;
+
+out_invalid:
+	FSCK(c)->lpt_status |= FR_LPT_INCORRECT;
+	return false;
+}
+
+static bool fsck_can_ignore_failure(const struct ubifs_info *c,
+				    unsigned int reason)
+{
+	ubifs_assert(c, FSCK(c)->mode != REBUILD_MODE);
+
+	if (c->cmt_state != COMMIT_RESTING)
+		/* Don't ignore failure when do commit. */
+		return false;
+	if (reason & (FR_LPT_CORRUPTED | FR_LPT_INCORRECT))
+		return true;
+
+	return false;
+}
+
+static const unsigned int reason_mapping_table[] = {};
+
+static bool fsck_handle_failure(const struct ubifs_info *c, unsigned int reason)
+{
+	ubifs_assert(c, FSCK(c)->mode != REBUILD_MODE);
+
+	return fix_problem(c, reason_mapping_table[reason]);
+}
+
 static void signal_cancel(int sig)
 {
 	ubifs_warn(c, "killed by signo %d", sig);
@@ -199,6 +365,14 @@ static int init_fsck_info(struct ubifs_info *c, int argc, char *argv[])
 	c->private = fsck;
 	FSCK(c)->mode = mode;
 	c->assert_failed_cb = fsck_assert_failed;
+	c->set_failure_reason_cb = fsck_set_failure_reason;
+	c->get_failure_reason_cb = fsck_get_failure_reason;
+	c->clear_failure_reason_cb = fsck_clear_failure_reason;
+	c->test_and_clear_failure_reason_cb = fsck_test_and_clear_failure_reason;
+	c->set_lpt_invalid_cb = fsck_set_lpt_invalid;
+	c->test_lpt_valid_cb = fsck_test_lpt_valid;
+	c->can_ignore_failure_cb = fsck_can_ignore_failure;
+	c->handle_failure_cb = fsck_handle_failure;
 
 	memset(&sa, 0, sizeof(struct sigaction));
 	sa.sa_handler = signal_cancel;
diff --git a/ubifs-utils/fsck.ubifs/fsck.ubifs.h b/ubifs-utils/fsck.ubifs/fsck.ubifs.h
index b9783c15..53dc5ff0 100644
--- a/ubifs-utils/fsck.ubifs/fsck.ubifs.h
+++ b/ubifs-utils/fsck.ubifs/fsck.ubifs.h
@@ -39,9 +39,14 @@ enum { NORMAL_MODE = 0, SAFE_MODE, DANGER_MODE0,
 /**
  * struct ubifs_fsck_info - UBIFS fsck information.
  * @mode: working mode
+ * @failure_reason: reasons for failed operations
+ * @lpt_status: the status of lpt, could be: %0(OK), %FR_LPT_CORRUPTED or
+ *		%FR_LPT_INCORRECT
  */
 struct ubifs_fsck_info {
 	int mode;
+	unsigned int failure_reason;
+	unsigned int lpt_status;
 };
 
 #define FSCK(c) ((struct ubifs_fsck_info*)c->private)
diff --git a/ubifs-utils/libubifs/io.c b/ubifs-utils/libubifs/io.c
index 6f170172..b6fb331b 100644
--- a/ubifs-utils/libubifs/io.c
+++ b/ubifs-utils/libubifs/io.c
@@ -964,6 +964,7 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
 
 	err = ubifs_check_node(c, buf, len, lnum, offs, 0, 0);
 	if (err) {
+		set_failure_reason_callback(c, FR_DATA_CORRUPTED);
 		ubifs_err(c, "expected node type %d", type);
 		return err;
 	}
@@ -977,6 +978,7 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
 	return 0;
 
 out:
+	set_failure_reason_callback(c, FR_DATA_CORRUPTED);
 	ubifs_err(c, "bad node at LEB %d:%d", lnum, offs);
 	ubifs_dump_node(c, buf, len);
 	dump_stack();
@@ -1020,6 +1022,7 @@ int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
 
 	err = ubifs_check_node(c, buf, len, lnum, offs, 0, 0);
 	if (err) {
+		set_failure_reason_callback(c, FR_DATA_CORRUPTED);
 		ubifs_err(c, "expected node type %d", type);
 		return err;
 	}
@@ -1033,6 +1036,7 @@ int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
 	return 0;
 
 out:
+	set_failure_reason_callback(c, FR_DATA_CORRUPTED);
 	ubifs_err(c, "bad node at LEB %d:%d, LEB mapping status %d", lnum,
 		  offs, ubi_is_mapped(c->dev_fd, lnum));
 	ubifs_dump_node(c, buf, len);
diff --git a/ubifs-utils/libubifs/lpt.c b/ubifs-utils/libubifs/lpt.c
index 92b3fec8..c0df7c7d 100644
--- a/ubifs-utils/libubifs/lpt.c
+++ b/ubifs-utils/libubifs/lpt.c
@@ -983,6 +983,7 @@ static int check_lpt_crc(const struct ubifs_info *c, void *buf, int len)
 	calc_crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
 			 len - UBIFS_LPT_CRC_BYTES);
 	if (crc != calc_crc) {
+		set_failure_reason_callback(c, FR_LPT_CORRUPTED);
 		ubifs_err(c, "invalid crc in LPT node: crc %hx calc %hx",
 			  crc, calc_crc);
 		dump_stack();
@@ -1007,6 +1008,7 @@ static int check_lpt_type(const struct ubifs_info *c, uint8_t **addr,
 
 	node_type = ubifs_unpack_bits(c, addr, pos, UBIFS_LPT_TYPE_BITS);
 	if (node_type != type) {
+		set_failure_reason_callback(c, FR_LPT_CORRUPTED);
 		ubifs_err(c, "invalid type (%d) in LPT node type %d",
 			  node_type, type);
 		dump_stack();
@@ -1106,8 +1108,10 @@ static int unpack_ltab(const struct ubifs_info *c, void *buf)
 		int dirty = ubifs_unpack_bits(c, &addr, &pos, c->lpt_spc_bits);
 
 		if (free < 0 || free > c->leb_size || dirty < 0 ||
-		    dirty > c->leb_size || free + dirty > c->leb_size)
+		    dirty > c->leb_size || free + dirty > c->leb_size) {
+			set_failure_reason_callback(c, FR_LPT_CORRUPTED);
 			return -EINVAL;
+		}
 
 		c->ltab[i].free = free;
 		c->ltab[i].dirty = dirty;
@@ -1136,8 +1140,10 @@ static int unpack_lsave(const struct ubifs_info *c, void *buf)
 	for (i = 0; i < c->lsave_cnt; i++) {
 		int lnum = ubifs_unpack_bits(c, &addr, &pos, c->lnum_bits);
 
-		if (lnum < c->main_first || lnum >= c->leb_cnt)
+		if (lnum < c->main_first || lnum >= c->leb_cnt) {
+			set_failure_reason_callback(c, FR_LPT_CORRUPTED);
 			return -EINVAL;
+		}
 		c->lsave[i] = lnum;
 	}
 	err = check_lpt_crc(c, buf, c->lsave_sz);
@@ -1162,11 +1168,11 @@ static int validate_nnode(const struct ubifs_info *c, struct ubifs_nnode *nnode,
 		int num = calc_nnode_num_from_parent(c, parent, iip);
 
 		if (nnode->num != num)
-			return -EINVAL;
+			goto out_invalid;
 	}
 	lvl = parent ? parent->level - 1 : c->lpt_hght;
 	if (lvl < 1)
-		return -EINVAL;
+		goto out_invalid;
 	if (lvl == 1)
 		max_offs = c->leb_size - c->pnode_sz;
 	else
@@ -1177,15 +1183,19 @@ static int validate_nnode(const struct ubifs_info *c, struct ubifs_nnode *nnode,
 
 		if (lnum == 0) {
 			if (offs != 0)
-				return -EINVAL;
+				goto out_invalid;
 			continue;
 		}
 		if (lnum < c->lpt_first || lnum > c->lpt_last)
-			return -EINVAL;
+			goto out_invalid;
 		if (offs < 0 || offs > max_offs)
-			return -EINVAL;
+			goto out_invalid;
 	}
 	return 0;
+
+out_invalid:
+	set_failure_reason_callback(c, FR_LPT_CORRUPTED);
+	return -EINVAL;
 }
 
 /**
@@ -1206,7 +1216,7 @@ static int validate_pnode(const struct ubifs_info *c, struct ubifs_pnode *pnode,
 		int num = calc_pnode_num_from_parent(c, parent, iip);
 
 		if (pnode->num != num)
-			return -EINVAL;
+			goto out_invalid;
 	}
 	for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
 		int free = pnode->lprops[i].free;
@@ -1214,13 +1224,17 @@ static int validate_pnode(const struct ubifs_info *c, struct ubifs_pnode *pnode,
 
 		if (free < 0 || free > c->leb_size || free % c->min_io_size ||
 		    (free & 7))
-			return -EINVAL;
+			goto out_invalid;
 		if (dirty < 0 || dirty > c->leb_size || (dirty & 7))
-			return -EINVAL;
+			goto out_invalid;
 		if (dirty + free > c->leb_size)
-			return -EINVAL;
+			goto out_invalid;
 	}
 	return 0;
+
+out_invalid:
+	set_failure_reason_callback(c, FR_LPT_CORRUPTED);
+	return -EINVAL;
 }
 
 /**
@@ -1283,8 +1297,11 @@ int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
 			nnode->num = calc_nnode_num_from_parent(c, parent, iip);
 	} else {
 		err = ubifs_leb_read(c, lnum, buf, offs, c->nnode_sz, 1);
-		if (err)
+		if (err) {
+			if (err == -EBADMSG)
+				set_failure_reason_callback(c, FR_LPT_CORRUPTED);
 			goto out;
+		}
 		err = ubifs_unpack_nnode(c, buf, nnode);
 		if (err)
 			goto out;
@@ -1352,8 +1369,11 @@ static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
 		}
 	} else {
 		err = ubifs_leb_read(c, lnum, buf, offs, c->pnode_sz, 1);
-		if (err)
+		if (err) {
+			if (err == -EBADMSG)
+				set_failure_reason_callback(c, FR_LPT_CORRUPTED);
 			goto out;
+		}
 		err = unpack_pnode(c, buf, pnode);
 		if (err)
 			goto out;
@@ -1394,8 +1414,11 @@ static int read_ltab(struct ubifs_info *c)
 	if (!buf)
 		return -ENOMEM;
 	err = ubifs_leb_read(c, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz, 1);
-	if (err)
+	if (err) {
+		if (err == -EBADMSG)
+			set_failure_reason_callback(c, FR_LPT_CORRUPTED);
 		goto out;
+	}
 	err = unpack_ltab(c, buf);
 out:
 	vfree(buf);
@@ -1418,8 +1441,11 @@ static int read_lsave(struct ubifs_info *c)
 		return -ENOMEM;
 	err = ubifs_leb_read(c, c->lsave_lnum, buf, c->lsave_offs,
 			     c->lsave_sz, 1);
-	if (err)
+	if (err) {
+		if (err == -EBADMSG)
+			set_failure_reason_callback(c, FR_LPT_CORRUPTED);
 		goto out;
+	}
 	err = unpack_lsave(c, buf);
 	if (err)
 		goto out;
@@ -2031,8 +2057,11 @@ static struct ubifs_nnode *scan_get_nnode(struct ubifs_info *c,
 	} else {
 		err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
 				     c->nnode_sz, 1);
-		if (err)
+		if (err) {
+			if (err == -EBADMSG)
+				set_failure_reason_callback(c, FR_LPT_CORRUPTED);
 			return ERR_PTR(err);
+		}
 		err = ubifs_unpack_nnode(c, buf, nnode);
 		if (err)
 			return ERR_PTR(err);
@@ -2100,8 +2129,11 @@ static struct ubifs_pnode *scan_get_pnode(struct ubifs_info *c,
 		ubifs_assert(c, branch->offs >= 0 && branch->offs < c->leb_size);
 		err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
 				     c->pnode_sz, 1);
-		if (err)
+		if (err) {
+			if (err == -EBADMSG)
+				set_failure_reason_callback(c, FR_LPT_CORRUPTED);
 			return ERR_PTR(err);
+		}
 		err = unpack_pnode(c, buf, pnode);
 		if (err)
 			return ERR_PTR(err);
diff --git a/ubifs-utils/libubifs/lpt_commit.c b/ubifs-utils/libubifs/lpt_commit.c
index b00f75f0..43eb7a6a 100644
--- a/ubifs-utils/libubifs/lpt_commit.c
+++ b/ubifs-utils/libubifs/lpt_commit.c
@@ -1607,8 +1607,11 @@ static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
 	dbg_lp("LEB %d", lnum);
 
 	err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
-	if (err)
+	if (err) {
+		if (err == -EBADMSG)
+			set_failure_reason_callback(c, FR_LPT_CORRUPTED);
 		goto out;
+	}
 
 	while (1) {
 		if (!is_a_node(c, p, len)) {
diff --git a/ubifs-utils/libubifs/master.c b/ubifs-utils/libubifs/master.c
index cce1a415..61ff4cec 100644
--- a/ubifs-utils/libubifs/master.c
+++ b/ubifs-utils/libubifs/master.c
@@ -146,10 +146,12 @@ static int scan_for_master(struct ubifs_info *c)
 	return 0;
 
 out:
+	set_failure_reason_callback(c, FR_DATA_CORRUPTED);
 	ubifs_scan_destroy(sleb);
 	return -EUCLEAN;
 
 out_dump:
+	set_failure_reason_callback(c, FR_DATA_CORRUPTED);
 	ubifs_err(c, "unexpected node type %d master LEB %d:%d",
 		  snod->type, lnum, snod->offs);
 	ubifs_scan_destroy(sleb);
@@ -165,6 +167,7 @@ out_dump:
  */
 static int validate_master(const struct ubifs_info *c)
 {
+	unsigned int reason = FR_DATA_CORRUPTED;
 	long long main_sz;
 	int err;
 
@@ -254,39 +257,46 @@ static int validate_master(const struct ubifs_info *c)
 	}
 
 	if (c->lst.empty_lebs < 0 || c->lst.empty_lebs > c->main_lebs - 2) {
+		reason = FR_LPT_INCORRECT;
 		err = 15;
 		goto out;
 	}
 
 	if (c->lst.idx_lebs < 0 || c->lst.idx_lebs > c->main_lebs - 1) {
+		reason = FR_LPT_INCORRECT;
 		err = 16;
 		goto out;
 	}
 
 	if (c->lst.total_free < 0 || c->lst.total_free > main_sz ||
 	    c->lst.total_free & 7) {
+		reason = FR_LPT_INCORRECT;
 		err = 17;
 		goto out;
 	}
 
 	if (c->lst.total_dirty < 0 || (c->lst.total_dirty & 7)) {
+		reason = FR_LPT_INCORRECT;
 		err = 18;
 		goto out;
 	}
 
 	if (c->lst.total_used < 0 || (c->lst.total_used & 7)) {
+		reason = FR_LPT_INCORRECT;
 		err = 19;
 		goto out;
 	}
 
 	if (c->lst.total_free + c->lst.total_dirty +
 	    c->lst.total_used > main_sz) {
+		reason = FR_LPT_INCORRECT;
 		err = 20;
 		goto out;
 	}
 
 	if (c->lst.total_dead + c->lst.total_dark +
 	    c->lst.total_used + c->bi.old_idx_sz > main_sz) {
+		reason = FR_LPT_INCORRECT;
 		err = 21;
 		goto out;
 	}
@@ -294,6 +304,7 @@ static int validate_master(const struct ubifs_info *c)
 	if (c->lst.total_dead < 0 ||
 	    c->lst.total_dead > c->lst.total_free + c->lst.total_dirty ||
 	    c->lst.total_dead & 7) {
+		reason = FR_LPT_INCORRECT;
 		err = 22;
 		goto out;
 	}
@@ -301,6 +312,7 @@ static int validate_master(const struct ubifs_info *c)
 	if (c->lst.total_dark < 0 ||
 	    c->lst.total_dark > c->lst.total_free + c->lst.total_dirty ||
 	    c->lst.total_dark & 7) {
+		reason = FR_LPT_INCORRECT;
 		err = 23;
 		goto out;
 	}
@@ -308,6 +320,7 @@ static int validate_master(const struct ubifs_info *c)
 	return 0;
 
 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;
@@ -331,8 +344,10 @@ int ubifs_read_master(struct ubifs_info *c)
 
 	err = scan_for_master(c);
 	if (err) {
-		if (err == -EUCLEAN)
+		if (err == -EUCLEAN) {
+			clear_failure_reason_callback(c);
 			err = ubifs_recover_master_node(c);
+		}
 		if (err)
 			/*
 			 * Note, we do not free 'c->mst_node' here because the
@@ -386,6 +401,7 @@ int ubifs_read_master(struct ubifs_info *c)
 
 		if (c->leb_cnt < old_leb_cnt ||
 		    c->leb_cnt < UBIFS_MIN_LEB_CNT) {
+			set_failure_reason_callback(c, FR_DATA_CORRUPTED);
 			ubifs_err(c, "bad leb_cnt on master node");
 			ubifs_dump_node(c, c->mst_node, c->mst_node_alsz);
 			return -EINVAL;
diff --git a/ubifs-utils/libubifs/orphan.c b/ubifs-utils/libubifs/orphan.c
index 2f318748..26668cbd 100644
--- a/ubifs-utils/libubifs/orphan.c
+++ b/ubifs-utils/libubifs/orphan.c
@@ -547,9 +547,11 @@ static int kill_orphans(struct ubifs_info *c)
 		dbg_rcvry("LEB %d", lnum);
 		sleb = ubifs_scan(c, lnum, 0, c->sbuf, 1);
 		if (IS_ERR(sleb)) {
-			if (PTR_ERR(sleb) == -EUCLEAN)
+			if (PTR_ERR(sleb) == -EUCLEAN) {
+				clear_failure_reason_callback(c);
 				sleb = ubifs_recover_leb(c, lnum, 0,
 							 c->sbuf, -1);
+			}
 			if (IS_ERR(sleb)) {
 				err = PTR_ERR(sleb);
 				break;
diff --git a/ubifs-utils/libubifs/recovery.c b/ubifs-utils/libubifs/recovery.c
index 910414cb..9115b17a 100644
--- a/ubifs-utils/libubifs/recovery.c
+++ b/ubifs-utils/libubifs/recovery.c
@@ -182,6 +182,7 @@ static int get_master_node(const struct ubifs_info *c, int lnum, void **pbuf,
 	return 0;
 
 out_err:
+	set_failure_reason_callback(c, FR_DATA_CORRUPTED);
 	err = -EINVAL;
 out_free:
 	vfree(sbuf);
@@ -355,6 +356,7 @@ int ubifs_recover_master_node(struct ubifs_info *c)
 	return 0;
 
 out_err:
+	set_failure_reason_callback(c, FR_DATA_CORRUPTED);
 	err = -EINVAL;
 out_free:
 	ubifs_err(c, "failed to recover master node");
@@ -762,6 +764,7 @@ corrupted_rescan:
 	ubifs_err(c, "corruption %d", ret);
 	ubifs_scan_a_node(c, buf, len, lnum, offs, 0);
 corrupted:
+	set_failure_reason_callback(c, FR_DATA_CORRUPTED);
 	ubifs_scanned_corruption(c, lnum, offs, buf);
 	err = -EUCLEAN;
 error:
@@ -817,6 +820,7 @@ static int get_cs_sqnum(struct ubifs_info *c, int lnum, int offs,
 
 out_err:
 	err = -EINVAL;
+	set_failure_reason_callback(c, FR_DATA_CORRUPTED);
 out_free:
 	ubifs_err(c, "failed to get CS sqnum");
 	kfree(cs_node);
diff --git a/ubifs-utils/libubifs/replay.c b/ubifs-utils/libubifs/replay.c
index ff9efaac..0ed12e3a 100644
--- a/ubifs-utils/libubifs/replay.c
+++ b/ubifs-utils/libubifs/replay.c
@@ -928,6 +928,7 @@ static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf)
 	if (IS_ERR(sleb)) {
 		if (PTR_ERR(sleb) != -EUCLEAN || !c->need_recovery)
 			return PTR_ERR(sleb);
+		clear_failure_reason_callback(c);
 		/*
 		 * Note, the below function will recover this log LEB only if
 		 * it is the last, because unclean reboots can possibly corrupt
diff --git a/ubifs-utils/libubifs/sb.c b/ubifs-utils/libubifs/sb.c
index 312661d6..2147280e 100644
--- a/ubifs-utils/libubifs/sb.c
+++ b/ubifs-utils/libubifs/sb.c
@@ -360,6 +360,8 @@ int ubifs_read_superblock(struct ubifs_info *c)
 
 	err = validate_sb(c, sup);
 out:
+	if (err)
+		set_failure_reason_callback(c, FR_DATA_CORRUPTED);
 	return err;
 }
 
diff --git a/ubifs-utils/libubifs/scan.c b/ubifs-utils/libubifs/scan.c
index 74509fd0..e9581a62 100644
--- a/ubifs-utils/libubifs/scan.c
+++ b/ubifs-utils/libubifs/scan.c
@@ -344,6 +344,7 @@ corrupted:
 	}
 	err = -EUCLEAN;
 	ubifs_scan_destroy(sleb);
+	set_failure_reason_callback(c, FR_DATA_CORRUPTED);
 	return ERR_PTR(err);
 
 error:
diff --git a/ubifs-utils/libubifs/tnc_misc.c b/ubifs-utils/libubifs/tnc_misc.c
index 8c38f153..0ffb4342 100644
--- a/ubifs-utils/libubifs/tnc_misc.c
+++ b/ubifs-utils/libubifs/tnc_misc.c
@@ -222,6 +222,8 @@ static int read_znode(struct ubifs_info *c, struct ubifs_zbranch *zzbr,
 
 	err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs);
 	if (err < 0) {
+		if (test_and_clear_failure_reason_callback(c, FR_DATA_CORRUPTED))
+			set_failure_reason_callback(c, FR_TNC_CORRUPTED);
 		kfree(idx);
 		return err;
 	}
@@ -335,6 +337,7 @@ static int read_znode(struct ubifs_info *c, struct ubifs_zbranch *zzbr,
 	return 0;
 
 out_dump:
+	set_failure_reason_callback(c, FR_TNC_CORRUPTED);
 	ubifs_err(c, "bad indexing node at LEB %d:%d, error %d", lnum, offs, err);
 	ubifs_dump_node(c, idx, c->max_idx_node_sz);
 	kfree(idx);
@@ -430,6 +433,7 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
 	/* Make sure the key of the read node is correct */
 	key_read(c, node + UBIFS_KEY_OFFSET, &key1);
 	if (!keys_eq(c, key, &key1)) {
+		set_failure_reason_callback(c, FR_DATA_CORRUPTED);
 		ubifs_err(c, "bad key in node at LEB %d:%d",
 			  zbr->lnum, zbr->offs);
 		dbg_tnck(key, "looked for key ");
diff --git a/ubifs-utils/libubifs/ubifs.h b/ubifs-utils/libubifs/ubifs.h
index babaae8f..21b0ce0a 100644
--- a/ubifs-utils/libubifs/ubifs.h
+++ b/ubifs-utils/libubifs/ubifs.h
@@ -1029,6 +1029,20 @@ struct ubifs_budg_info {
  *
  * @private: private information related to specific situation, eg. fsck.
  * @assert_failed_cb: callback function to handle assertion failure
+ * @set_failure_reason_cb: record reasons while certain failure happens
+ * @get_failure_reason_cb: get failure reasons
+ * @clear_failure_reason_cb: callback function to clear the error which is
+ *			     caused by reading corrupted data or invalid lpt
+ * @test_and_clear_failure_reason_cb: callback function to check and clear the
+ *				      error which is caused by reading corrupted
+ *				      data or invalid lpt
+ * @set_lpt_invalid_cb: callback function to set the invalid lpt status
+ * @test_lpt_valid_cb: callback function to check whether lpt is corrupted or
+ *		       incorrect, should be called before updating lpt
+ * @can_ignore_failure_cb: callback function to decide whether the failure
+ *			   can be ignored
+ * @handle_failure_cb: callback function to decide whether the failure can be
+ *		       handled
  */
 struct ubifs_info {
 	struct ubifs_sb_node *sup_node;
@@ -1254,6 +1268,21 @@ struct ubifs_info {
 
 	void *private;
 	void (*assert_failed_cb)(const struct ubifs_info *c);
+	void (*set_failure_reason_cb)(const struct ubifs_info *c,
+				      unsigned int reason);
+	unsigned int (*get_failure_reason_cb)(const struct ubifs_info *c);
+	void (*clear_failure_reason_cb)(const struct ubifs_info *c);
+	bool (*test_and_clear_failure_reason_cb)(const struct ubifs_info *c,
+						 unsigned int reason);
+	void (*set_lpt_invalid_cb)(const struct ubifs_info *c,
+				   unsigned int reason);
+	bool (*test_lpt_valid_cb)(const struct ubifs_info *c, int lnum,
+				  int old_free, int old_dirty,
+				  int free, int dirty);
+	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);
 };
 
 extern atomic_long_t ubifs_clean_zn_cnt;
@@ -1502,6 +1531,75 @@ int ubifs_add_snod(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
 void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs,
 			      void *buf);
 
+/* Failure reasons which are checked by fsck. */
+enum {
+	FR_DATA_CORRUPTED = 1,	/* Data is corrupted(master/log/orphan/main) */
+	FR_TNC_CORRUPTED = 2,	/* TNC is corrupted */
+	FR_LPT_CORRUPTED = 4,	/* LPT is corrupted */
+	FR_LPT_INCORRECT = 8	/* Space statistics are wrong */
+};
+/* 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)
+{
+	if (c->set_failure_reason_cb)
+		c->set_failure_reason_cb(c, reason);
+}
+static inline unsigned int get_failure_reason_callback(
+						const struct ubifs_info *c)
+{
+	if (c->get_failure_reason_cb)
+		return c->get_failure_reason_cb(c);
+
+	return 0;
+}
+static inline void clear_failure_reason_callback(const struct ubifs_info *c)
+{
+	if (c->clear_failure_reason_cb)
+		c->clear_failure_reason_cb(c);
+}
+static inline bool test_and_clear_failure_reason_callback(
+						const struct ubifs_info *c,
+						unsigned int reason)
+{
+	if (c->test_and_clear_failure_reason_cb)
+		return c->test_and_clear_failure_reason_cb(c, reason);
+
+	return false;
+}
+static inline void set_lpt_invalid_callback(const struct ubifs_info *c,
+					    unsigned int reason)
+{
+	if (c->set_lpt_invalid_cb)
+		c->set_lpt_invalid_cb(c, reason);
+}
+static inline bool test_lpt_valid_callback(const struct ubifs_info *c, int lnum,
+					   int old_free, int old_dirty,
+					   int free, int dirty)
+{
+	if (c->test_lpt_valid_cb)
+		return c->test_lpt_valid_cb(c, lnum,
+					    old_free, old_dirty, free, dirty);
+
+	return false;
+}
+static inline bool can_ignore_failure_callback(const struct ubifs_info *c,
+					       unsigned int reason)
+{
+	if (c->can_ignore_failure_cb)
+		return c->can_ignore_failure_cb(c, reason);
+
+	return false;
+}
+static inline bool handle_failure_callback(const struct ubifs_info *c,
+					   unsigned int reason)
+{
+	if (c->handle_failure_cb)
+		return c->handle_failure_cb(c, reason);
+
+	return false;
+}
+
 /* log.c */
 void ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud);
 void ubifs_create_buds_lists(struct ubifs_info *c);
