diff options
Diffstat (limited to 'ubifs-utils')
| -rw-r--r-- | ubifs-utils/fsck.ubifs/fsck.ubifs.c | 1 | ||||
| -rw-r--r-- | ubifs-utils/fsck.ubifs/load_fs.c | 79 | ||||
| -rw-r--r-- | ubifs-utils/libubifs/recovery.c | 34 | 
3 files changed, 75 insertions, 39 deletions
| 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);  	} | 
