diff options
Diffstat (limited to 'drivers/md/persistent-data/dm-btree.c')
-rw-r--r-- | drivers/md/persistent-data/dm-btree.c | 101 |
1 files changed, 99 insertions, 2 deletions
diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c index c573402033b2..b1ced58eb5e1 100644 --- a/drivers/md/persistent-data/dm-btree.c +++ b/drivers/md/persistent-data/dm-btree.c | |||
@@ -63,6 +63,11 @@ int lower_bound(struct btree_node *n, uint64_t key) | |||
63 | return bsearch(n, key, 0); | 63 | return bsearch(n, key, 0); |
64 | } | 64 | } |
65 | 65 | ||
66 | static int upper_bound(struct btree_node *n, uint64_t key) | ||
67 | { | ||
68 | return bsearch(n, key, 1); | ||
69 | } | ||
70 | |||
66 | void inc_children(struct dm_transaction_manager *tm, struct btree_node *n, | 71 | void inc_children(struct dm_transaction_manager *tm, struct btree_node *n, |
67 | struct dm_btree_value_type *vt) | 72 | struct dm_btree_value_type *vt) |
68 | { | 73 | { |
@@ -252,6 +257,16 @@ static void pop_frame(struct del_stack *s) | |||
252 | dm_tm_unlock(s->tm, f->b); | 257 | dm_tm_unlock(s->tm, f->b); |
253 | } | 258 | } |
254 | 259 | ||
260 | static void unlock_all_frames(struct del_stack *s) | ||
261 | { | ||
262 | struct frame *f; | ||
263 | |||
264 | while (unprocessed_frames(s)) { | ||
265 | f = s->spine + s->top--; | ||
266 | dm_tm_unlock(s->tm, f->b); | ||
267 | } | ||
268 | } | ||
269 | |||
255 | int dm_btree_del(struct dm_btree_info *info, dm_block_t root) | 270 | int dm_btree_del(struct dm_btree_info *info, dm_block_t root) |
256 | { | 271 | { |
257 | int r; | 272 | int r; |
@@ -308,9 +323,13 @@ int dm_btree_del(struct dm_btree_info *info, dm_block_t root) | |||
308 | pop_frame(s); | 323 | pop_frame(s); |
309 | } | 324 | } |
310 | } | 325 | } |
311 | |||
312 | out: | 326 | out: |
327 | if (r) { | ||
328 | /* cleanup all frames of del_stack */ | ||
329 | unlock_all_frames(s); | ||
330 | } | ||
313 | kfree(s); | 331 | kfree(s); |
332 | |||
314 | return r; | 333 | return r; |
315 | } | 334 | } |
316 | EXPORT_SYMBOL_GPL(dm_btree_del); | 335 | EXPORT_SYMBOL_GPL(dm_btree_del); |
@@ -392,6 +411,82 @@ int dm_btree_lookup(struct dm_btree_info *info, dm_block_t root, | |||
392 | } | 411 | } |
393 | EXPORT_SYMBOL_GPL(dm_btree_lookup); | 412 | EXPORT_SYMBOL_GPL(dm_btree_lookup); |
394 | 413 | ||
414 | static int dm_btree_lookup_next_single(struct dm_btree_info *info, dm_block_t root, | ||
415 | uint64_t key, uint64_t *rkey, void *value_le) | ||
416 | { | ||
417 | int r, i; | ||
418 | uint32_t flags, nr_entries; | ||
419 | struct dm_block *node; | ||
420 | struct btree_node *n; | ||
421 | |||
422 | r = bn_read_lock(info, root, &node); | ||
423 | if (r) | ||
424 | return r; | ||
425 | |||
426 | n = dm_block_data(node); | ||
427 | flags = le32_to_cpu(n->header.flags); | ||
428 | nr_entries = le32_to_cpu(n->header.nr_entries); | ||
429 | |||
430 | if (flags & INTERNAL_NODE) { | ||
431 | i = lower_bound(n, key); | ||
432 | if (i < 0 || i >= nr_entries) { | ||
433 | r = -ENODATA; | ||
434 | goto out; | ||
435 | } | ||
436 | |||
437 | r = dm_btree_lookup_next_single(info, value64(n, i), key, rkey, value_le); | ||
438 | if (r == -ENODATA && i < (nr_entries - 1)) { | ||
439 | i++; | ||
440 | r = dm_btree_lookup_next_single(info, value64(n, i), key, rkey, value_le); | ||
441 | } | ||
442 | |||
443 | } else { | ||
444 | i = upper_bound(n, key); | ||
445 | if (i < 0 || i >= nr_entries) { | ||
446 | r = -ENODATA; | ||
447 | goto out; | ||
448 | } | ||
449 | |||
450 | *rkey = le64_to_cpu(n->keys[i]); | ||
451 | memcpy(value_le, value_ptr(n, i), info->value_type.size); | ||
452 | } | ||
453 | out: | ||
454 | dm_tm_unlock(info->tm, node); | ||
455 | return r; | ||
456 | } | ||
457 | |||
458 | int dm_btree_lookup_next(struct dm_btree_info *info, dm_block_t root, | ||
459 | uint64_t *keys, uint64_t *rkey, void *value_le) | ||
460 | { | ||
461 | unsigned level; | ||
462 | int r = -ENODATA; | ||
463 | __le64 internal_value_le; | ||
464 | struct ro_spine spine; | ||
465 | |||
466 | init_ro_spine(&spine, info); | ||
467 | for (level = 0; level < info->levels - 1u; level++) { | ||
468 | r = btree_lookup_raw(&spine, root, keys[level], | ||
469 | lower_bound, rkey, | ||
470 | &internal_value_le, sizeof(uint64_t)); | ||
471 | if (r) | ||
472 | goto out; | ||
473 | |||
474 | if (*rkey != keys[level]) { | ||
475 | r = -ENODATA; | ||
476 | goto out; | ||
477 | } | ||
478 | |||
479 | root = le64_to_cpu(internal_value_le); | ||
480 | } | ||
481 | |||
482 | r = dm_btree_lookup_next_single(info, root, keys[level], rkey, value_le); | ||
483 | out: | ||
484 | exit_ro_spine(&spine); | ||
485 | return r; | ||
486 | } | ||
487 | |||
488 | EXPORT_SYMBOL_GPL(dm_btree_lookup_next); | ||
489 | |||
395 | /* | 490 | /* |
396 | * Splits a node by creating a sibling node and shifting half the nodes | 491 | * Splits a node by creating a sibling node and shifting half the nodes |
397 | * contents across. Assumes there is a parent node, and it has room for | 492 | * contents across. Assumes there is a parent node, and it has room for |
@@ -473,8 +568,10 @@ static int btree_split_sibling(struct shadow_spine *s, unsigned parent_index, | |||
473 | 568 | ||
474 | r = insert_at(sizeof(__le64), pn, parent_index + 1, | 569 | r = insert_at(sizeof(__le64), pn, parent_index + 1, |
475 | le64_to_cpu(rn->keys[0]), &location); | 570 | le64_to_cpu(rn->keys[0]), &location); |
476 | if (r) | 571 | if (r) { |
572 | unlock_block(s->info, right); | ||
477 | return r; | 573 | return r; |
574 | } | ||
478 | 575 | ||
479 | if (key < le64_to_cpu(rn->keys[0])) { | 576 | if (key < le64_to_cpu(rn->keys[0])) { |
480 | unlock_block(s->info, right); | 577 | unlock_block(s->info, right); |