From acedb85997d7b04b4546154d8acc5d916c020630 Mon Sep 17 00:00:00 2001 From: Zhihao Cheng Date: Mon, 11 Nov 2024 17:07:59 +0800 Subject: fsck.ubifs: Recover isize This is the 5/18 step of fsck. Recover isize. There could be following steps and possible errors: Step 1. Traverse size tree, lookup corresponding inode from TNC 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 2. update isize for inode. Keep in size tree for check mode, update inode node in place for other modes. Signed-off-by: Zhihao Cheng Signed-off-by: David Oberhollenzer --- ubifs-utils/fsck.ubifs/fsck.ubifs.c | 1 + ubifs-utils/fsck.ubifs/load_fs.c | 79 +++++++++++++++++++++---------------- ubifs-utils/libubifs/recovery.c | 34 +++++++++++++--- 3 files changed, 75 insertions(+), 39 deletions(-) (limited to 'ubifs-utils') diff --git a/ubifs-utils/fsck.ubifs/fsck.ubifs.c b/ubifs-utils/fsck.ubifs/fsck.ubifs.c index 83c8a2c..616ed81 100644 --- a/ubifs-utils/fsck.ubifs/fsck.ubifs.c +++ b/ubifs-utils/fsck.ubifs/fsck.ubifs.c @@ -434,6 +434,7 @@ int main(int argc, char *argv[]) * Step 2: Replay journal * Step 3: Handle orphan nodes * Step 4: Consolidate log + * Step 5: Recover isize */ err = ubifs_load_filesystem(c); if (err) { diff --git a/ubifs-utils/fsck.ubifs/load_fs.c b/ubifs-utils/fsck.ubifs/load_fs.c index 42b1afa..5854054 100644 --- a/ubifs-utils/fsck.ubifs/load_fs.c +++ b/ubifs-utils/fsck.ubifs/load_fs.c @@ -17,6 +17,33 @@ #include "misc.h" #include "fsck.ubifs.h" +enum { HAS_DATA_CORRUPTED = 1, HAS_TNC_CORRUPTED = 2 }; + +static void handle_error(const struct ubifs_info *c, int reason_set) +{ + bool handled = false; + unsigned int reason = get_failure_reason_callback(c); + + clear_failure_reason_callback(c); + if ((reason_set & HAS_DATA_CORRUPTED) && (reason & FR_DATA_CORRUPTED)) { + handled = true; + reason &= ~FR_DATA_CORRUPTED; + if (fix_problem(c, LOG_CORRUPTED, NULL)) + FSCK(c)->try_rebuild = true; + } + if ((reason_set & HAS_TNC_CORRUPTED) && (reason & FR_TNC_CORRUPTED)) { + ubifs_assert(c, !handled); + handled = true; + reason &= ~FR_TNC_CORRUPTED; + if (fix_problem(c, TNC_CORRUPTED, NULL)) + FSCK(c)->try_rebuild = true; + } + + ubifs_assert(c, reason == 0); + if (!handled) + exit_code |= FSCK_ERROR; +} + int ubifs_load_filesystem(struct ubifs_info *c) { int err; @@ -164,19 +191,7 @@ int ubifs_load_filesystem(struct ubifs_info *c) log_out(c, "Replay journal"); err = ubifs_replay_journal(c); if (err) { - unsigned int reason = get_failure_reason_callback(c); - - clear_failure_reason_callback(c); - if (reason & FR_DATA_CORRUPTED) { - if (fix_problem(c, LOG_CORRUPTED, NULL)) - FSCK(c)->try_rebuild = true; - } else 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; - } + handle_error(c, HAS_DATA_CORRUPTED | HAS_TNC_CORRUPTED); goto out_journal; } @@ -186,16 +201,7 @@ int ubifs_load_filesystem(struct ubifs_info *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; - } + handle_error(c, HAS_TNC_CORRUPTED); goto out_orphans; } @@ -210,19 +216,26 @@ int ubifs_load_filesystem(struct ubifs_info *c) log_out(c, "Consolidate log"); err = ubifs_consolidate_log(c); if (err) { - unsigned int reason = get_failure_reason_callback(c); - - clear_failure_reason_callback(c); - if (reason & FR_DATA_CORRUPTED) { - if (fix_problem(c, LOG_CORRUPTED, NULL)) - FSCK(c)->try_rebuild = true; - } else { - ubifs_assert(c, reason == 0); - exit_code |= FSCK_ERROR; - } + handle_error(c, HAS_DATA_CORRUPTED); + goto out_orphans; + } + } + + if (c->need_recovery) { + log_out(c, "Recover isize"); + err = ubifs_recover_size(c, true); + if (err) { + handle_error(c, HAS_TNC_CORRUPTED); goto out_orphans; } } + } else if (c->need_recovery) { + log_out(c, "Recover isize"); + err = ubifs_recover_size(c, false); + if (err) { + handle_error(c, HAS_TNC_CORRUPTED); + goto out_orphans; + } } c->mounting = 0; diff --git a/ubifs-utils/libubifs/recovery.c b/ubifs-utils/libubifs/recovery.c index 9115b17..a5133a0 100644 --- a/ubifs-utils/libubifs/recovery.c +++ b/ubifs-utils/libubifs/recovery.c @@ -1272,8 +1272,18 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e) /* Locate the inode node LEB number and offset */ ino_key_init(c, &key, e->inum); err = ubifs_tnc_locate(c, &key, ino, &lnum, &offs); - if (err) + 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_TNC_DATA_CORRUPTED, NULL)) { + /* Leave the inode to be deleted by subsequent steps */ + return 0; + } + } goto out; + } /* * If the size recorded on the inode node is greater than the size that * was calculated from nodes in the journal then don't change the inode. @@ -1320,10 +1330,10 @@ out: */ static int inode_fix_size(struct ubifs_info *c, __unused struct size_entry *e) { - ubifs_assert(c, 0); - - // To be implemented - return -EINVAL; + /* Don't remove entry, keep it in the size tree. */ + /* Remove this assertion after supporting authentication. */ + ubifs_assert(c, c->ro_mount); + return 0; } /** @@ -1353,8 +1363,19 @@ int ubifs_recover_size(struct ubifs_info *c, bool in_place) ino_key_init(c, &key, e->inum); err = ubifs_tnc_lookup(c, &key, c->sbuf); - 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 */ + goto delete_entry; + } + } return err; + } if (err == -ENOENT) { /* Remove data nodes that have no inode */ dbg_rcvry("removing ino %lu", @@ -1390,6 +1411,7 @@ int ubifs_recover_size(struct ubifs_info *c, bool in_place) } } +delete_entry: rb_erase(&e->rb, &c->size_tree); kfree(e); } -- cgit v1.2.3