diff options
Diffstat (limited to 'ubifs-utils/libubifs')
| -rw-r--r-- | ubifs-utils/libubifs/lprops.c | 21 | ||||
| -rw-r--r-- | ubifs-utils/libubifs/replay.c | 54 | ||||
| -rw-r--r-- | ubifs-utils/libubifs/tnc.c | 13 | ||||
| -rw-r--r-- | ubifs-utils/libubifs/ubifs.h | 11 | 
4 files changed, 89 insertions, 10 deletions
diff --git a/ubifs-utils/libubifs/lprops.c b/ubifs-utils/libubifs/lprops.c index 84cdb35..a7a2305 100644 --- a/ubifs-utils/libubifs/lprops.c +++ b/ubifs-utils/libubifs/lprops.c @@ -656,14 +656,24 @@ int ubifs_change_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,  	int err = 0, flags;  	const struct ubifs_lprops *lp; +	if (!test_lpt_valid_callback(c, lnum, LPROPS_NC, LPROPS_NC, LPROPS_NC, +				     LPROPS_NC)) +		return 0; +  	ubifs_get_lprops(c);  	lp = ubifs_lpt_lookup_dirty(c, lnum);  	if (IS_ERR(lp)) {  		err = PTR_ERR(lp); +		if (test_and_clear_failure_reason_callback(c, FR_LPT_CORRUPTED) && +		    can_ignore_failure_callback(c, FR_LPT_CORRUPTED)) +			err = 0;  		goto out;  	} +	if (!test_lpt_valid_callback(c, lnum, lp->free, lp->dirty, free, dirty)) +		goto out; +  	flags = (lp->flags | flags_set) & ~flags_clean;  	lp = ubifs_change_lp(c, lp, free, dirty, flags, idx_gc_cnt);  	if (IS_ERR(lp)) @@ -695,14 +705,25 @@ int ubifs_update_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,  	int err = 0, flags;  	const struct ubifs_lprops *lp; +	if (!test_lpt_valid_callback(c, lnum, LPROPS_NC, LPROPS_NC, LPROPS_NC, +				     LPROPS_NC)) +		return 0; +  	ubifs_get_lprops(c);  	lp = ubifs_lpt_lookup_dirty(c, lnum);  	if (IS_ERR(lp)) {  		err = PTR_ERR(lp); +		if (test_and_clear_failure_reason_callback(c, FR_LPT_CORRUPTED) && +		    can_ignore_failure_callback(c, FR_LPT_CORRUPTED)) +			err = 0;  		goto out;  	} +	if (!test_lpt_valid_callback(c, lnum, lp->free, lp->dirty, free, +				     lp->dirty + dirty)) +		goto out; +  	flags = (lp->flags | flags_set) & ~flags_clean;  	lp = ubifs_change_lp(c, lp, free, lp->dirty + dirty, flags, 0);  	if (IS_ERR(lp)) diff --git a/ubifs-utils/libubifs/replay.c b/ubifs-utils/libubifs/replay.c index 30ed282..2741742 100644 --- a/ubifs-utils/libubifs/replay.c +++ b/ubifs-utils/libubifs/replay.c @@ -94,11 +94,18 @@ static int set_bud_lprops(struct ubifs_info *c, struct bud_entry *b)  	const struct ubifs_lprops *lp;  	int err = 0, dirty; +	if (!test_lpt_valid_callback(c, b->bud->lnum, LPROPS_NC, LPROPS_NC, +				     LPROPS_NC, LPROPS_NC)) +		return 0; +  	ubifs_get_lprops(c);  	lp = ubifs_lpt_lookup_dirty(c, b->bud->lnum);  	if (IS_ERR(lp)) {  		err = PTR_ERR(lp); +		if (test_and_clear_failure_reason_callback(c, FR_LPT_CORRUPTED) && +		    can_ignore_failure_callback(c, FR_LPT_CORRUPTED)) +			err = 0;  		goto out;  	} @@ -140,6 +147,10 @@ static int set_bud_lprops(struct ubifs_info *c, struct bud_entry *b)  				b->bud->lnum, lp->free, lp->dirty, b->free,  				b->dirty);  	} +	if (!test_lpt_valid_callback(c, b->bud->lnum, lp->free, lp->dirty, +				     b->free, dirty + b->dirty)) +		goto out; +  	lp = ubifs_change_lp(c, lp, b->free, dirty + b->dirty,  			     lp->flags | LPROPS_TAKEN, 0);  	if (IS_ERR(lp)) { @@ -766,6 +777,7 @@ out:  	return err;  out_dump: +	set_failure_reason_callback(c, FR_DATA_CORRUPTED);  	ubifs_err(c, "bad node is at LEB %d:%d", lnum, snod->offs);  	ubifs_dump_node(c, snod->node, c->leb_size - snod->offs);  	ubifs_scan_destroy(sleb); @@ -781,14 +793,24 @@ out_dump:   */  static int replay_buds(struct ubifs_info *c)  { -	struct bud_entry *b; +	struct bud_entry *b, *tmp_b;  	int err;  	unsigned long long prev_sqnum = 0; -	list_for_each_entry(b, &c->replay_buds, list) { +	list_for_each_entry_safe(b, tmp_b, &c->replay_buds, list) {  		err = replay_bud(c, b); -		if (err) +		if (err) { +			if (test_and_clear_failure_reason_callback(c, FR_DATA_CORRUPTED) && +			    handle_failure_callback(c, FR_H_BUD_CORRUPTED, b->bud)) { +				/* Set %FR_LPT_INCORRECT for lpt status. */ +				set_lpt_invalid_callback(c, FR_LPT_INCORRECT); +				/* Skip replaying the bud LEB. */ +				list_del(&b->list); +				kfree(b); +				continue; +			}  			return err; +		}  		ubifs_assert(c, b->sqnum > prev_sqnum);  		prev_sqnum = b->sqnum; @@ -1062,6 +1084,7 @@ out:  	return err;  out_dump: +	set_failure_reason_callback(c, FR_DATA_CORRUPTED);  	ubifs_err(c, "log error detected while replaying the log at LEB %d:%d",  		  lnum, offs + snod->offs);  	ubifs_dump_node(c, snod->node, c->leb_size - snod->offs); @@ -1086,11 +1109,20 @@ static int take_ihead(struct ubifs_info *c)  	lp = ubifs_lpt_lookup_dirty(c, c->ihead_lnum);  	if (IS_ERR(lp)) {  		err = PTR_ERR(lp); +		if (test_and_clear_failure_reason_callback(c, FR_LPT_CORRUPTED) && +		    can_ignore_failure_callback(c, FR_LPT_CORRUPTED)) +			err = 0;  		goto out;  	}  	free = lp->free; +	if (!test_lpt_valid_callback(c, c->ihead_lnum, LPROPS_NC, LPROPS_NC, +				     LPROPS_NC, LPROPS_NC)) { +		err = free; +		goto out; +	} +  	lp = ubifs_change_lp(c, lp, LPROPS_NC, LPROPS_NC,  			     lp->flags | LPROPS_TAKEN, 0);  	if (IS_ERR(lp)) { @@ -1123,10 +1155,17 @@ int ubifs_replay_journal(struct ubifs_info *c)  	if (free < 0)  		return free; /* Error code */ -	if (c->ihead_offs != c->leb_size - free) { -		ubifs_err(c, "bad index head LEB %d:%d", c->ihead_lnum, -			  c->ihead_offs); -		return -EINVAL; +	if (c->program_type != FSCK_PROGRAM_TYPE) { +		/* +		 * Skip index head checking for fsck, it is hard to check it +		 * caused by possible corrupted/incorrect lpt, tnc updating +		 * will report error code if index tree is really corrupted. +		 */ +		if (c->ihead_offs != c->leb_size - free) { +			ubifs_err(c, "bad index head LEB %d:%d", c->ihead_lnum, +				  c->ihead_offs); +			return -EINVAL; +		}  	}  	dbg_mnt("start replaying the journal"); @@ -1147,6 +1186,7 @@ int ubifs_replay_journal(struct ubifs_info *c)  			 * something went wrong and we cannot proceed mounting  			 * the file-system.  			 */ +			set_failure_reason_callback(c, FR_DATA_CORRUPTED);  			ubifs_err(c, "no UBIFS nodes found at the log head LEB %d:%d, possibly corrupted",  				  lnum, 0);  			err = -EINVAL; diff --git a/ubifs-utils/libubifs/tnc.c b/ubifs-utils/libubifs/tnc.c index 12c56e0..cd1013d 100644 --- a/ubifs-utils/libubifs/tnc.c +++ b/ubifs-utils/libubifs/tnc.c @@ -2402,9 +2402,22 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)  		xent = ubifs_tnc_next_ent(c, &key1, &nm);  		if (IS_ERR(xent)) { +			unsigned int reason; +  			err = PTR_ERR(xent);  			if (err == -ENOENT)  				break; + +			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)) { +					/* Set %FR_LPT_INCORRECT for lpt status. */ +					set_lpt_invalid_callback(c, FR_LPT_INCORRECT); +					/* Leave xattrs to be deleted by subsequent steps */ +					break; +				} +			}  			kfree(pxent);  			return err;  		} diff --git a/ubifs-utils/libubifs/ubifs.h b/ubifs-utils/libubifs/ubifs.h index 6f96555..ae812ff 100644 --- a/ubifs-utils/libubifs/ubifs.h +++ b/ubifs-utils/libubifs/ubifs.h @@ -1286,7 +1286,7 @@ struct ubifs_info {  	bool (*can_ignore_failure_cb)(const struct ubifs_info *c,  				      unsigned int reason);  	bool (*handle_failure_cb)(const struct ubifs_info *c, -				  unsigned int reason); +				  unsigned int reason, void *priv);  };  extern atomic_long_t ubifs_clean_zn_cnt; @@ -1542,6 +1542,11 @@ enum {  	FR_LPT_CORRUPTED = 4,	/* LPT is corrupted */  	FR_LPT_INCORRECT = 8	/* Space statistics are wrong */  }; +/* Partial failure reasons in common libs, which are handled by fsck. */ +enum { +	FR_H_BUD_CORRUPTED = 0,		/* Bud LEB is corrupted */ +	FR_H_TNC_DATA_CORRUPTED,	/* Data searched from TNC 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,  					       unsigned int reason) @@ -1596,10 +1601,10 @@ static inline bool can_ignore_failure_callback(const struct ubifs_info *c,  	return false;  }  static inline bool handle_failure_callback(const struct ubifs_info *c, -					   unsigned int reason) +					   unsigned int reason, void *priv)  {  	if (c->handle_failure_cb) -		return c->handle_failure_cb(c, reason); +		return c->handle_failure_cb(c, reason, priv);  	return false;  }  | 
