diff options
Diffstat (limited to 'ubifs-utils')
| -rw-r--r-- | ubifs-utils/fsck.ubifs/check_files.c | 122 | ||||
| -rw-r--r-- | ubifs-utils/fsck.ubifs/fsck.ubifs.c | 1 | ||||
| -rw-r--r-- | ubifs-utils/fsck.ubifs/fsck.ubifs.h | 2 | ||||
| -rw-r--r-- | ubifs-utils/fsck.ubifs/problem.c | 10 | 
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; | 
