diff options
Diffstat (limited to 'ubifs-utils/libubifs')
| -rw-r--r-- | ubifs-utils/libubifs/orphan.c | 42 | ||||
| -rw-r--r-- | ubifs-utils/libubifs/ubifs.h | 1 | 
2 files changed, 40 insertions, 3 deletions
| 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, | 
