mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 09:19:51 +00:00
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