aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ubifs-utils/fsck.ubifs/check_files.c122
-rw-r--r--ubifs-utils/fsck.ubifs/fsck.ubifs.c1
-rw-r--r--ubifs-utils/fsck.ubifs/fsck.ubifs.h2
-rw-r--r--ubifs-utils/fsck.ubifs/problem.c10
4 files changed, 128 insertions, 7 deletions
diff --git a/ubifs-utils/fsck.ubifs/check_files.c b/ubifs-utils/fsck.ubifs/check_files.c
index 982c05b..29848c4 100644
--- a/ubifs-utils/fsck.ubifs/check_files.c
+++ b/ubifs-utils/fsck.ubifs/check_files.c
@@ -8,6 +8,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include "linux_err.h"
#include "bitops.h"
#include "kmem.h"
#include "ubifs.h"
@@ -25,6 +26,7 @@ struct invalid_node {
struct iteration_info {
struct list_head invalid_nodes;
+ unsigned long *corrupted_lebs;
};
static int add_invalid_node(struct ubifs_info *c, union ubifs_key *key,
@@ -103,6 +105,49 @@ static int construct_file(struct ubifs_info *c, union ubifs_key *key,
return insert_or_update_file(c, tree, sn, key_type(c, key), inum);
}
+static int scan_check_leb(struct ubifs_info *c, int lnum, bool is_idx)
+{
+ int err = 0;
+ struct ubifs_scan_leb *sleb;
+ struct ubifs_scan_node *snod;
+
+ if (FSCK(c)->mode == CHECK_MODE)
+ /* Skip check mode. */
+ return 0;
+
+ ubifs_assert(c, lnum >= c->main_first);
+ if (test_bit(lnum - c->main_first, FSCK(c)->used_lebs))
+ return 0;
+
+ sleb = ubifs_scan(c, lnum, 0, c->sbuf, 0);
+ if (IS_ERR(sleb)) {
+ err = PTR_ERR(sleb);
+ if (test_and_clear_failure_reason_callback(c, FR_DATA_CORRUPTED))
+ err = 1;
+ return err;
+ }
+
+ list_for_each_entry(snod, &sleb->nodes, list) {
+ if (is_idx) {
+ if (snod->type != UBIFS_IDX_NODE) {
+ err = 1;
+ goto out;
+ }
+ } else {
+ if (snod->type == UBIFS_IDX_NODE) {
+ err = 1;
+ goto out;
+ }
+ }
+ }
+
+ set_bit(lnum - c->main_first, FSCK(c)->used_lebs);
+
+out:
+ ubifs_scan_destroy(sleb);
+ return err;
+}
+
static int check_leaf(struct ubifs_info *c, struct ubifs_zbranch *zbr,
void *priv)
{
@@ -127,6 +172,23 @@ static int check_leaf(struct ubifs_info *c, struct ubifs_zbranch *zbr,
return -EINVAL;
}
+ if (test_bit(lnum - c->main_first, iter->corrupted_lebs)) {
+ if (fix_problem(c, SCAN_CORRUPTED, zbr))
+ /* All nodes in corrupted LEB should be removed. */
+ return add_invalid_node(c, key, lnum, offs, iter);
+ return 0;
+ }
+
+ err = scan_check_leb(c, lnum, false);
+ if (err < 0) {
+ return err;
+ } else if (err) {
+ set_bit(lnum - c->main_first, iter->corrupted_lebs);
+ if (fix_problem(c, SCAN_CORRUPTED, zbr))
+ return add_invalid_node(c, key, lnum, offs, iter);
+ return 0;
+ }
+
node = kmalloc(len, GFP_NOFS);
if (!node)
return -ENOMEM;
@@ -147,6 +209,34 @@ out:
return err;
}
+static int check_znode(struct ubifs_info *c, struct ubifs_znode *znode,
+ __unused void *priv)
+{
+ int err;
+ const struct ubifs_zbranch *zbr;
+
+ if (znode->parent)
+ zbr = &znode->parent->zbranch[znode->iip];
+ else
+ zbr = &c->zroot;
+
+ if (zbr->lnum == 0) {
+ /* The znode has been split up. */
+ ubifs_assert(c, zbr->offs == 0 && zbr->len == 0);
+ return 0;
+ }
+
+ err = scan_check_leb(c, zbr->lnum, true);
+ if (err < 0) {
+ return err;
+ } else if (err) {
+ set_failure_reason_callback(c, FR_TNC_CORRUPTED);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int remove_invalid_nodes(struct ubifs_info *c,
struct list_head *invalid_nodes, int error)
{
@@ -176,10 +266,12 @@ static int remove_invalid_nodes(struct ubifs_info *c,
* traverse_tnc_and_construct_files - traverse TNC and construct all files.
* @c: UBIFS file-system description object
*
- * This function checks all index nodes and non-index nodes by traversing TNC,
- * then construct file according to scanned non-index nodes and insert file
- * into file tree. Returns zero in case of success, a negative error code in
- * case of failure.
+ * This function does two things by traversing TNC:
+ * 1. Check all index nodes and non-index nodes, then construct file according
+ * to scanned non-index nodes and insert file into file tree.
+ * 2. Make sure that LEB(contains any nodes from TNC) can be scanned by
+ * ubifs_scan, and the LEB only contains index nodes or non-index nodes.
+ * Returns zero in case of success, a negative error code in case of failure.
*/
int traverse_tnc_and_construct_files(struct ubifs_info *c)
{
@@ -187,15 +279,33 @@ int traverse_tnc_and_construct_files(struct ubifs_info *c)
struct iteration_info iter;
FSCK(c)->scanned_files = RB_ROOT;
+ FSCK(c)->used_lebs = kcalloc(BITS_TO_LONGS(c->main_lebs),
+ sizeof(unsigned long), GFP_KERNEL);
+ if (!FSCK(c)->used_lebs) {
+ err = -ENOMEM;
+ log_err(c, errno, "can not allocate bitmap of used lebs");
+ return err;
+ }
INIT_LIST_HEAD(&iter.invalid_nodes);
+ iter.corrupted_lebs = kcalloc(BITS_TO_LONGS(c->main_lebs),
+ sizeof(unsigned long), GFP_KERNEL);
+ if (!iter.corrupted_lebs) {
+ err = -ENOMEM;
+ log_err(c, errno, "can not allocate bitmap of corrupted lebs");
+ goto out;
+ }
- err = dbg_walk_index(c, check_leaf, NULL, &iter);
+ err = dbg_walk_index(c, check_leaf, check_znode, &iter);
ret = remove_invalid_nodes(c, &iter.invalid_nodes, err);
if (!err)
err = ret;
- if (err)
+ kfree(iter.corrupted_lebs);
+out:
+ if (err) {
+ kfree(FSCK(c)->used_lebs);
destroy_file_tree(c, &FSCK(c)->scanned_files);
+ }
return err;
}
diff --git a/ubifs-utils/fsck.ubifs/fsck.ubifs.c b/ubifs-utils/fsck.ubifs/fsck.ubifs.c
index 96091b4..c0b1bf6 100644
--- a/ubifs-utils/fsck.ubifs/fsck.ubifs.c
+++ b/ubifs-utils/fsck.ubifs/fsck.ubifs.c
@@ -443,6 +443,7 @@ static int do_fsck(void)
return err;
}
+ kfree(FSCK(c)->used_lebs);
destroy_file_tree(c, &FSCK(c)->scanned_files);
return err;
}
diff --git a/ubifs-utils/fsck.ubifs/fsck.ubifs.h b/ubifs-utils/fsck.ubifs/fsck.ubifs.h
index 4fa4088..c917a0e 100644
--- a/ubifs-utils/fsck.ubifs/fsck.ubifs.h
+++ b/ubifs-utils/fsck.ubifs/fsck.ubifs.h
@@ -39,7 +39,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, ORPHAN_CORRUPTED, INVALID_INO_NODE,
- INVALID_DENT_NODE, INVALID_DATA_NODE };
+ INVALID_DENT_NODE, INVALID_DATA_NODE, SCAN_CORRUPTED };
enum { HAS_DATA_CORRUPTED = 1, HAS_TNC_CORRUPTED = 2 };
diff --git a/ubifs-utils/fsck.ubifs/problem.c b/ubifs-utils/fsck.ubifs/problem.c
index f99fd90..c5ecd10 100644
--- a/ubifs-utils/fsck.ubifs/problem.c
+++ b/ubifs-utils/fsck.ubifs/problem.c
@@ -45,6 +45,7 @@ static const struct fsck_problem problem_table[] = {
{PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA, "Invalid inode node"}, // INVALID_INO_NODE
{PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA, "Invalid dentry node"}, // INVALID_DENT_NODE
{PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA, "Invalid data node"}, // INVALID_DATA_NODE
+ {PROBLEM_FIXABLE | PROBLEM_MUST_FIX | PROBLEM_DROP_DATA, "Corrupted data is scanned"}, // SCAN_CORRUPTED
};
static const char *get_question(const struct fsck_problem *problem,
@@ -60,6 +61,7 @@ static const char *get_question(const struct fsck_problem *problem,
case INVALID_INO_NODE:
case INVALID_DENT_NODE:
case INVALID_DATA_NODE:
+ case SCAN_CORRUPTED:
return "Drop it?";
case ORPHAN_CORRUPTED:
return "Drop orphans on the LEB?";
@@ -88,6 +90,14 @@ static void print_problem(const struct ubifs_info *c,
log_out(c, "problem: %s %d", problem->desc, *lnum);
break;
}
+ case SCAN_CORRUPTED:
+ {
+ const struct ubifs_zbranch *zbr = (const struct ubifs_zbranch *)priv;
+
+ log_out(c, "problem: %s in LEB %d, node in %d:%d becomes invalid",
+ problem->desc, zbr->lnum, zbr->lnum, zbr->offs);
+ break;
+ }
default:
log_out(c, "problem: %s", problem->desc);
break;