diff options
author | Zhihao Cheng <chengzhihao1@huawei.com> | 2024-11-11 17:01:23 +0800 |
---|---|---|
committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2024-11-11 10:32:46 +0100 |
commit | 585047e6c4136a474f3ff22a0e9e839cc6ede75d (patch) | |
tree | 3875a251c5ed9d6cec70f855a3752d6cdac637c3 /ubifs-utils/libubifs | |
parent | cf844f788d34e1facf142910b955554c69eb8f9b (diff) |
fsck.ubifs: Handle orphan nodes
This is the 3/18 step of fsck. Handle orphan nodes, update TNC & LPT.
There could be following steps and possible errors:
Step 1. scan orphan LEB, get all orphan nodes
a. corrupted scanning data in orphan area: danger mode and normal mode
with 'yes' answer will drop orphan LEB, other modes will exit.
Step 2. parse orphan node, find the original inode for each inum
a. corrupted node searched from TNC: skip node 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.
Step 4. remove inode for each inum, update TNC & LPT
a. 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.
b. corrupted lpt: Set %FR_LPT_CORRUPTED for lpt status. Ignore the
error.
c. incorrect lpt: Set %FR_LPT_INCORRECT for lpt status. Ignore the
error.
d. 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/orphan.c | 42 | ||||
-rw-r--r-- | ubifs-utils/libubifs/ubifs.h | 1 |
2 files changed, 40 insertions, 3 deletions
diff --git a/ubifs-utils/libubifs/orphan.c b/ubifs-utils/libubifs/orphan.c index 26668cb..baa4db7 100644 --- a/ubifs-utils/libubifs/orphan.c +++ b/ubifs-utils/libubifs/orphan.c @@ -423,6 +423,7 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb, ubifs_dump_node(c, snod->node, c->leb_size - snod->offs); err = -EINVAL; + set_failure_reason_callback(c, FR_DATA_CORRUPTED); goto out_free; } @@ -452,6 +453,7 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb, ubifs_dump_node(c, snod->node, c->leb_size - snod->offs); err = -EINVAL; + set_failure_reason_callback(c, FR_DATA_CORRUPTED); goto out_free; } dbg_rcvry("out of date LEB %d", sleb->lnum); @@ -471,8 +473,19 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb, ino_key_init(c, &key, inum); err = ubifs_tnc_lookup(c, &key, ino); - if (err && err != -ENOENT) + if (err && err != -ENOENT) { + unsigned int reason; + + 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)) { + /* Leave the inode to be deleted by subsequent steps */ + continue; + } + } goto out_free; + } /* * Check whether an inode can really get deleted. @@ -483,8 +496,11 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb, (unsigned long)inum); err = ubifs_tnc_remove_ino(c, inum); - if (err) + if (err) { + if (c->program_type == FSCK_PROGRAM_TYPE) + goto out_free; goto out_ro; + } } } @@ -553,13 +569,33 @@ static int kill_orphans(struct ubifs_info *c) c->sbuf, -1); } if (IS_ERR(sleb)) { + if (test_and_clear_failure_reason_callback(c, FR_DATA_CORRUPTED) && + handle_failure_callback(c, FR_H_ORPHAN_CORRUPTED, &lnum)) { + /* Skip the orphan LEB. */ + continue; + } err = PTR_ERR(sleb); break; } } err = do_kill_orphans(c, sleb, &last_cmt_no, &outofdate, &last_flagged); - if (err || outofdate) { + if (err) { + unsigned int 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_ORPHAN_CORRUPTED, &lnum)) { + err = 0; + /* Skip the orphan LEB. */ + ubifs_scan_destroy(sleb); + continue; + } + } + ubifs_scan_destroy(sleb); + break; + } + if (outofdate) { ubifs_scan_destroy(sleb); break; } diff --git a/ubifs-utils/libubifs/ubifs.h b/ubifs-utils/libubifs/ubifs.h index ae812ff..8a506a8 100644 --- a/ubifs-utils/libubifs/ubifs.h +++ b/ubifs-utils/libubifs/ubifs.h @@ -1546,6 +1546,7 @@ enum { enum { FR_H_BUD_CORRUPTED = 0, /* Bud LEB is corrupted */ FR_H_TNC_DATA_CORRUPTED, /* Data searched from TNC is corrupted */ + FR_H_ORPHAN_CORRUPTED, /* Orphan LEB 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, |