aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ubifs-utils/fsck.ubifs/fsck.ubifs.c2
-rw-r--r--ubifs-utils/fsck.ubifs/fsck.ubifs.h2
-rw-r--r--ubifs-utils/fsck.ubifs/load_fs.c19
-rw-r--r--ubifs-utils/fsck.ubifs/problem.c20
-rw-r--r--ubifs-utils/libubifs/orphan.c42
-rw-r--r--ubifs-utils/libubifs/ubifs.h1
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,