diff options
Diffstat (limited to 'ubifs-utils')
| -rw-r--r-- | ubifs-utils/fsck.ubifs/rebuild_fs.c | 120 | 
1 files changed, 119 insertions, 1 deletions
| diff --git a/ubifs-utils/fsck.ubifs/rebuild_fs.c b/ubifs-utils/fsck.ubifs/rebuild_fs.c index 3ca9486..dbb0f3b 100644 --- a/ubifs-utils/fsck.ubifs/rebuild_fs.c +++ b/ubifs-utils/fsck.ubifs/rebuild_fs.c @@ -364,6 +364,117 @@ out:  	return err;  } +static struct scanned_ino_node * +lookup_valid_ino_node(struct ubifs_info *c, struct scanned_info *si, +		      struct scanned_ino_node *target) +{ +	int cmp; +	struct scanned_ino_node *ino_node; +	struct rb_node *p; + +	p = si->valid_inos.rb_node; +	while (p) { +		ino_node = rb_entry(p, struct scanned_ino_node, rb); +		cmp = keys_cmp(c, &target->key, &ino_node->key); +		if (cmp < 0) { +			p = p->rb_left; +		} else if (cmp > 0) { +			p = p->rb_right; +		} else { +			if (target->header.sqnum > ino_node->header.sqnum) +				return ino_node; +			else +				return NULL; +		} +	} + +	return NULL; +} + +static struct scanned_dent_node * +lookup_valid_dent_node(struct ubifs_info *c, struct scanned_info *si, +		       struct scanned_dent_node *target) +{ +	int cmp, nlen; +	struct scanned_dent_node *dent_node; +	struct rb_node *p; + +	p = si->valid_dents.rb_node; +	while (p) { +		dent_node = rb_entry(p, struct scanned_dent_node, rb); +		cmp = keys_cmp(c, &target->key, &dent_node->key); +		if (cmp < 0) { +			p = p->rb_left; +		} else if (cmp > 0) { +			p = p->rb_right; +		} else { +			nlen = min(target->nlen, dent_node->nlen); +			cmp = strncmp(target->name, dent_node->name, nlen) ? : +				      target->nlen - dent_node->nlen; +			if (cmp < 0) { +				p = p->rb_left; +			} else if (cmp > 0) { +				p = p->rb_right; +			} else { +				if (target->header.sqnum > +				    dent_node->header.sqnum) +					return dent_node; +				else +					return NULL; +			} +		} +	} + +	return NULL; +} + +/** + * remove_del_nodes - remove deleted nodes from valid node tree. + * @c: UBIFS file-system description object + * @si: records nodes and files information during scanning + * + * This function compares sqnum between deleted node and corresponding valid + * node, removes valid node from tree if the sqnum of deleted node is bigger. + * Deleted ino/dent nodes will be removed from @si->del_inos/@si->del_dents + * after this function finished. + */ +static void remove_del_nodes(struct ubifs_info *c, struct scanned_info *si) +{ +	struct scanned_ino_node *del_ino_node, *valid_ino_node; +	struct scanned_dent_node *del_dent_node, *valid_dent_node; +	struct rb_node *this; + +	this = rb_first(&si->del_inos); +	while (this) { +		del_ino_node = rb_entry(this, struct scanned_ino_node, rb); +		this = rb_next(this); + +		valid_ino_node = lookup_valid_ino_node(c, si, del_ino_node); +		if (valid_ino_node) { +			rb_erase(&valid_ino_node->rb, &si->valid_inos); +			kfree(valid_ino_node); +		} + +		rb_erase(&del_ino_node->rb, &si->del_inos); +		kfree(del_ino_node); +	} + +	this = rb_first(&si->del_dents); +	while (this) { +		del_dent_node = rb_entry(this, struct scanned_dent_node, rb); +		this = rb_next(this); + +		valid_dent_node = lookup_valid_dent_node(c, si, del_dent_node); +		if (valid_dent_node) { +			rb_erase(&valid_dent_node->rb, &si->valid_dents); +			kfree(valid_dent_node); +		} + +		rb_erase(&del_dent_node->rb, &si->del_dents); +		kfree(del_dent_node); +	} +} +  /**   * ubifs_rebuild_filesystem - Rebuild filesystem.   * @c: UBIFS file-system description object @@ -389,9 +500,16 @@ int ubifs_rebuild_filesystem(struct ubifs_info *c)  	/* Step 1: Scan valid/deleted nodes from volume. */  	log_out(c, "Scan nodes");  	err = scan_nodes(c, &si); -	if (err) +	if (err) {  		exit_code |= FSCK_ERROR; +		goto out; +	} + +	/* Step 2: Remove deleted nodes from valid node tree. */ +	log_out(c, "Remove deleted nodes"); +	remove_del_nodes(c, &si); +out:  	destroy_scanned_info(c, &si);  	destroy_rebuild_info(c); | 
