summaryrefslogtreecommitdiff
path: root/ubifs-utils/libubifs/lpt.c
diff options
context:
space:
mode:
authorZhihao Cheng <chengzhihao1@huawei.com>2024-11-11 17:01:04 +0800
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2024-11-11 10:32:45 +0100
commit518e5374471233125a595c5aeff2d0c3f5d27c0b (patch)
treef9f541d1ddcfcd456382ac1cdbb2b458b8f93181 /ubifs-utils/libubifs/lpt.c
parente17ad291a8da970a4cf64a57796c30437d8c5fbd (diff)
fsck.ubifs: Distinguish reasons when certain failures happen
Read failure caused by scanning corrupted data or invalid data members should be identified, because fsck can handle it. Updating lp failure caused by bad space statistics should be identified too, because fsck can handle it. Add eight callback functions to implement it for fsck: 1. set_failure_reason_callback: Record failure reasons when reading or parsing node failed, there are four reasons: a. FR_DATA_CORRUPTED: scanning corrupted data or invalid nodes found b. FR_TNC_CORRUPTED: invalid index nodes c. FR_LPT_CORRUPTED: invalid pnode/nnode d. FR_LPT_INCORRECT: invalid space statistics or invalid LEB properties 2. get_failure_reason_callback: get failure reasons 3. clear_failure_reason_callback: Clear the error which is caused by above reasons. 4. test_and_clear_failure_reason_callback: Check and clear the error which is caused by above reasons, if so, fsck will handle it according to specific situation. For example, fsck will drop data node rather than fails to return when reading failure is caused by DATA_CORRUPTED. For another example, journal replaying will continue rather than fails to return if updating lpt failure is caused by LPT_CORRUPTED. 5. set_lpt_invalid_callback: Set the invalid lpt status 6. test_lpt_valid_callback: Check whether the lpt is corrupted/incorrect, it should be invoked before updating lp, if lpt status is invalid, returns false (which means that caller should skip updating lp, because updating lp could trigger assertion failed in ubifs_change_lp). 7. can_ignore_failure_callback: Check whether the failure can be ignored, some inconsistent errors won't affect the fsck process, for example wrong space statistics can be fixed after traversing TNC, so failures caused by incorrect space statistics can be ignored. 8. handle_failure_callback: Check whether the failure can be handled, some inconsistent errors could be fixed by fsck, we have fix_problem to do that, but UBIFS needs a callback function to invoke it in common libs. Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com> Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'ubifs-utils/libubifs/lpt.c')
-rw-r--r--ubifs-utils/libubifs/lpt.c66
1 files changed, 49 insertions, 17 deletions
diff --git a/ubifs-utils/libubifs/lpt.c b/ubifs-utils/libubifs/lpt.c
index 92b3fec..c0df7c7 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);