diff options
-rw-r--r-- | ubifs-utils/fsck.ubifs/fsck.ubifs.c | 2 | ||||
-rw-r--r-- | ubifs-utils/fsck.ubifs/fsck.ubifs.h | 2 | ||||
-rw-r--r-- | ubifs-utils/fsck.ubifs/load_fs.c | 19 | ||||
-rw-r--r-- | ubifs-utils/fsck.ubifs/problem.c | 20 | ||||
-rw-r--r-- | ubifs-utils/libubifs/orphan.c | 42 | ||||
-rw-r--r-- | ubifs-utils/libubifs/ubifs.h | 1 |
6 files changed, 80 insertions, 6 deletions
diff --git a/ubifs-utils/fsck.ubifs/fsck.ubifs.c b/ubifs-utils/fsck.ubifs/fsck.ubifs.c index 85175cf..31c2aa6 100644 --- a/ubifs-utils/fsck.ubifs/fsck.ubifs.c +++ b/ubifs-utils/fsck.ubifs/fsck.ubifs.c @@ -328,6 +328,7 @@ static bool fsck_can_ignore_failure(const struct ubifs_info *c, static const unsigned int reason_mapping_table[] = { BUD_CORRUPTED, /* FR_H_BUD_CORRUPTED */ TNC_DATA_CORRUPTED, /* FR_H_TNC_DATA_CORRUPTED */ + ORPHAN_CORRUPTED, /* FR_H_ORPHAN_CORRUPTED */ }; static bool fsck_handle_failure(const struct ubifs_info *c, unsigned int reason, @@ -431,6 +432,7 @@ int main(int argc, char *argv[]) * Init: Read superblock * Step 1: Read master & init lpt * Step 2: Replay journal + * Step 3: Handle orphan nodes */ err = ubifs_load_filesystem(c); if (err) { diff --git a/ubifs-utils/fsck.ubifs/fsck.ubifs.h b/ubifs-utils/fsck.ubifs/fsck.ubifs.h index f1da974..a1c64e3 100644 --- a/ubifs-utils/fsck.ubifs/fsck.ubifs.h +++ b/ubifs-utils/fsck.ubifs/fsck.ubifs.h @@ -38,7 +38,7 @@ enum { NORMAL_MODE = 0, SAFE_MODE, DANGER_MODE0, /* Types of inconsistent problems */ enum { SB_CORRUPTED = 0, MST_CORRUPTED, LOG_CORRUPTED, BUD_CORRUPTED, - TNC_CORRUPTED, TNC_DATA_CORRUPTED }; + TNC_CORRUPTED, TNC_DATA_CORRUPTED, ORPHAN_CORRUPTED }; struct scanned_file; diff --git a/ubifs-utils/fsck.ubifs/load_fs.c b/ubifs-utils/fsck.ubifs/load_fs.c index f45c411..f376383 100644 --- a/ubifs-utils/fsck.ubifs/load_fs.c +++ b/ubifs-utils/fsck.ubifs/load_fs.c @@ -183,10 +183,28 @@ int ubifs_load_filesystem(struct ubifs_info *c) /* Calculate 'min_idx_lebs' after journal replay */ c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c); + log_out(c, "Handle orphan nodes"); + err = ubifs_mount_orphans(c, c->need_recovery, c->ro_mount); + if (err) { + unsigned int reason = get_failure_reason_callback(c); + + clear_failure_reason_callback(c); + if (reason & FR_TNC_CORRUPTED) { + if (fix_problem(c, TNC_CORRUPTED, NULL)) + FSCK(c)->try_rebuild = true; + } else { + ubifs_assert(c, reason == 0); + exit_code |= FSCK_ERROR; + } + goto out_orphans; + } + c->mounting = 0; return 0; +out_orphans: + free_orphans(c); out_journal: destroy_journal(c); out_lpt: @@ -214,6 +232,7 @@ void ubifs_destroy_filesystem(struct ubifs_info *c) { destroy_journal(c); free_wbufs(c); + free_orphans(c); ubifs_lpt_free(c, 0); c->max_sqnum = 0; diff --git a/ubifs-utils/fsck.ubifs/problem.c b/ubifs-utils/fsck.ubifs/problem.c index 9df2c2a..9c8730a 100644 --- a/ubifs-utils/fsck.ubifs/problem.c +++ b/ubifs-utils/fsck.ubifs/problem.c @@ -41,6 +41,7 @@ static const struct fsck_problem problem_table[] = { {PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA, "Corrupted bud LEB"}, // BUD_CORRUPTED {PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA | PROBLEM_NEED_REBUILD, "Corrupted index node"}, // TNC_CORRUPTED {PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA, "Corrupted data searched from TNC"}, // TNC_DATA_CORRUPTED + {PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA, "Corrupted orphan LEB"}, // ORPHAN_CORRUPTED }; static const char *get_question(const struct fsck_problem *problem, @@ -54,6 +55,8 @@ static const char *get_question(const struct fsck_problem *problem, return "Drop bud?"; case TNC_DATA_CORRUPTED: return "Drop it?"; + case ORPHAN_CORRUPTED: + return "Drop orphans on the LEB?"; } return "Fix it?"; @@ -63,13 +66,26 @@ static void print_problem(const struct ubifs_info *c, const struct fsck_problem *problem, int problem_type, const void *priv) { - if (problem_type == BUD_CORRUPTED) { + switch (problem_type) { + case BUD_CORRUPTED: + { const struct ubifs_bud *bud = (const struct ubifs_bud *)priv; log_out(c, "problem: %s %d:%d %s", problem->desc, bud->lnum, bud->start, dbg_jhead(bud->jhead)); - } else + break; + } + case ORPHAN_CORRUPTED: + { + const int *lnum = (const int *)priv; + + log_out(c, "problem: %s %d", problem->desc, *lnum); + break; + } + default: log_out(c, "problem: %s", problem->desc); + break; + } } static void fatal_error(const struct ubifs_info *c, 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, |