forked from mirrors/linux
		
	dm btree: add dm_btree_remove_leaves()
Removes a range of leaf values from the tree. Signed-off-by: Joe Thornber <ejt@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
This commit is contained in:
		
							parent
							
								
									0f24b79b52
								
							
						
					
					
						commit
						4ec331c3ea
					
				
					 2 changed files with 136 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -590,3 +590,130 @@ int dm_btree_remove(struct dm_btree_info *info, dm_block_t root,
 | 
			
		|||
	return r;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(dm_btree_remove);
 | 
			
		||||
 | 
			
		||||
/*----------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
static int remove_nearest(struct shadow_spine *s, struct dm_btree_info *info,
 | 
			
		||||
			  struct dm_btree_value_type *vt, dm_block_t root,
 | 
			
		||||
			  uint64_t key, int *index)
 | 
			
		||||
{
 | 
			
		||||
	int i = *index, r;
 | 
			
		||||
	struct btree_node *n;
 | 
			
		||||
 | 
			
		||||
	for (;;) {
 | 
			
		||||
		r = shadow_step(s, root, vt);
 | 
			
		||||
		if (r < 0)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * We have to patch up the parent node, ugly, but I don't
 | 
			
		||||
		 * see a way to do this automatically as part of the spine
 | 
			
		||||
		 * op.
 | 
			
		||||
		 */
 | 
			
		||||
		if (shadow_has_parent(s)) {
 | 
			
		||||
			__le64 location = cpu_to_le64(dm_block_location(shadow_current(s)));
 | 
			
		||||
			memcpy(value_ptr(dm_block_data(shadow_parent(s)), i),
 | 
			
		||||
			       &location, sizeof(__le64));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		n = dm_block_data(shadow_current(s));
 | 
			
		||||
 | 
			
		||||
		if (le32_to_cpu(n->header.flags) & LEAF_NODE) {
 | 
			
		||||
			*index = lower_bound(n, key);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		r = rebalance_children(s, info, vt, key);
 | 
			
		||||
		if (r)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		n = dm_block_data(shadow_current(s));
 | 
			
		||||
		if (le32_to_cpu(n->header.flags) & LEAF_NODE) {
 | 
			
		||||
			*index = lower_bound(n, key);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		i = lower_bound(n, key);
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * We know the key is present, or else
 | 
			
		||||
		 * rebalance_children would have returned
 | 
			
		||||
		 * -ENODATA
 | 
			
		||||
		 */
 | 
			
		||||
		root = value64(n, i);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int remove_one(struct dm_btree_info *info, dm_block_t root,
 | 
			
		||||
		      uint64_t *keys, uint64_t end_key,
 | 
			
		||||
		      dm_block_t *new_root, unsigned *nr_removed)
 | 
			
		||||
{
 | 
			
		||||
	unsigned level, last_level = info->levels - 1;
 | 
			
		||||
	int index = 0, r = 0;
 | 
			
		||||
	struct shadow_spine spine;
 | 
			
		||||
	struct btree_node *n;
 | 
			
		||||
	uint64_t k;
 | 
			
		||||
 | 
			
		||||
	init_shadow_spine(&spine, info);
 | 
			
		||||
	for (level = 0; level < last_level; level++) {
 | 
			
		||||
		r = remove_raw(&spine, info, &le64_type,
 | 
			
		||||
			       root, keys[level], (unsigned *) &index);
 | 
			
		||||
		if (r < 0)
 | 
			
		||||
			goto out;
 | 
			
		||||
 | 
			
		||||
		n = dm_block_data(shadow_current(&spine));
 | 
			
		||||
		root = value64(n, index);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r = remove_nearest(&spine, info, &info->value_type,
 | 
			
		||||
			   root, keys[last_level], &index);
 | 
			
		||||
	if (r < 0)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	n = dm_block_data(shadow_current(&spine));
 | 
			
		||||
 | 
			
		||||
	if (index < 0)
 | 
			
		||||
		index = 0;
 | 
			
		||||
 | 
			
		||||
	if (index >= le32_to_cpu(n->header.nr_entries)) {
 | 
			
		||||
		r = -ENODATA;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	k = le64_to_cpu(n->keys[index]);
 | 
			
		||||
	if (k >= keys[last_level] && k < end_key) {
 | 
			
		||||
		if (info->value_type.dec)
 | 
			
		||||
			info->value_type.dec(info->value_type.context,
 | 
			
		||||
					     value_ptr(n, index));
 | 
			
		||||
 | 
			
		||||
		delete_at(n, index);
 | 
			
		||||
 | 
			
		||||
	} else
 | 
			
		||||
		r = -ENODATA;
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	*new_root = shadow_root(&spine);
 | 
			
		||||
	exit_shadow_spine(&spine);
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dm_btree_remove_leaves(struct dm_btree_info *info, dm_block_t root,
 | 
			
		||||
			   uint64_t *first_key, uint64_t end_key,
 | 
			
		||||
			   dm_block_t *new_root, unsigned *nr_removed)
 | 
			
		||||
{
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
	*nr_removed = 0;
 | 
			
		||||
	do {
 | 
			
		||||
		r = remove_one(info, root, first_key, end_key, &root, nr_removed);
 | 
			
		||||
		if (!r)
 | 
			
		||||
			(*nr_removed)++;
 | 
			
		||||
	} while (!r);
 | 
			
		||||
 | 
			
		||||
	*new_root = root;
 | 
			
		||||
	return r == -ENODATA ? 0 : r;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(dm_btree_remove_leaves);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -134,6 +134,15 @@ int dm_btree_insert_notify(struct dm_btree_info *info, dm_block_t root,
 | 
			
		|||
int dm_btree_remove(struct dm_btree_info *info, dm_block_t root,
 | 
			
		||||
		    uint64_t *keys, dm_block_t *new_root);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Removes values between 'keys' and keys2, where keys2 is keys with the
 | 
			
		||||
 * final key replaced with 'end_key'.  'end_key' is the one-past-the-end
 | 
			
		||||
 * value.  'keys' may be altered.
 | 
			
		||||
 */
 | 
			
		||||
int dm_btree_remove_leaves(struct dm_btree_info *info, dm_block_t root,
 | 
			
		||||
			   uint64_t *keys, uint64_t end_key,
 | 
			
		||||
			   dm_block_t *new_root, unsigned *nr_removed);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Returns < 0 on failure.  Otherwise the number of key entries that have
 | 
			
		||||
 * been filled out.  Remember trees can have zero entries, and as such have
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue