diff options
Diffstat (limited to 'ubifs-utils')
| -rw-r--r-- | ubifs-utils/fsck.ubifs/fsck.ubifs.c | 2 | ||||
| -rw-r--r-- | ubifs-utils/fsck.ubifs/fsck.ubifs.h | 2 | ||||
| -rw-r--r-- | ubifs-utils/fsck.ubifs/load_fs.c | 19 | ||||
| -rw-r--r-- | ubifs-utils/fsck.ubifs/problem.c | 20 | ||||
| -rw-r--r-- | ubifs-utils/libubifs/orphan.c | 42 | ||||
| -rw-r--r-- | ubifs-utils/libubifs/ubifs.h | 1 | 
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, | 
