diff options
Diffstat (limited to 'drivers/md/persistent-data/dm-space-map-common.c')
-rw-r--r-- | drivers/md/persistent-data/dm-space-map-common.c | 32 |
1 files changed, 23 insertions, 9 deletions
diff --git a/drivers/md/persistent-data/dm-space-map-common.c b/drivers/md/persistent-data/dm-space-map-common.c index 6058569fe86c..466a60bbd716 100644 --- a/drivers/md/persistent-data/dm-space-map-common.c +++ b/drivers/md/persistent-data/dm-space-map-common.c | |||
@@ -381,7 +381,7 @@ int sm_ll_find_free_block(struct ll_disk *ll, dm_block_t begin, | |||
381 | } | 381 | } |
382 | 382 | ||
383 | static int sm_ll_mutate(struct ll_disk *ll, dm_block_t b, | 383 | static int sm_ll_mutate(struct ll_disk *ll, dm_block_t b, |
384 | uint32_t (*mutator)(void *context, uint32_t old), | 384 | int (*mutator)(void *context, uint32_t old, uint32_t *new), |
385 | void *context, enum allocation_event *ev) | 385 | void *context, enum allocation_event *ev) |
386 | { | 386 | { |
387 | int r; | 387 | int r; |
@@ -410,11 +410,17 @@ static int sm_ll_mutate(struct ll_disk *ll, dm_block_t b, | |||
410 | 410 | ||
411 | if (old > 2) { | 411 | if (old > 2) { |
412 | r = sm_ll_lookup_big_ref_count(ll, b, &old); | 412 | r = sm_ll_lookup_big_ref_count(ll, b, &old); |
413 | if (r < 0) | 413 | if (r < 0) { |
414 | dm_tm_unlock(ll->tm, nb); | ||
414 | return r; | 415 | return r; |
416 | } | ||
415 | } | 417 | } |
416 | 418 | ||
417 | ref_count = mutator(context, old); | 419 | r = mutator(context, old, &ref_count); |
420 | if (r) { | ||
421 | dm_tm_unlock(ll->tm, nb); | ||
422 | return r; | ||
423 | } | ||
418 | 424 | ||
419 | if (ref_count <= 2) { | 425 | if (ref_count <= 2) { |
420 | sm_set_bitmap(bm_le, bit, ref_count); | 426 | sm_set_bitmap(bm_le, bit, ref_count); |
@@ -465,9 +471,10 @@ static int sm_ll_mutate(struct ll_disk *ll, dm_block_t b, | |||
465 | return ll->save_ie(ll, index, &ie_disk); | 471 | return ll->save_ie(ll, index, &ie_disk); |
466 | } | 472 | } |
467 | 473 | ||
468 | static uint32_t set_ref_count(void *context, uint32_t old) | 474 | static int set_ref_count(void *context, uint32_t old, uint32_t *new) |
469 | { | 475 | { |
470 | return *((uint32_t *) context); | 476 | *new = *((uint32_t *) context); |
477 | return 0; | ||
471 | } | 478 | } |
472 | 479 | ||
473 | int sm_ll_insert(struct ll_disk *ll, dm_block_t b, | 480 | int sm_ll_insert(struct ll_disk *ll, dm_block_t b, |
@@ -476,9 +483,10 @@ int sm_ll_insert(struct ll_disk *ll, dm_block_t b, | |||
476 | return sm_ll_mutate(ll, b, set_ref_count, &ref_count, ev); | 483 | return sm_ll_mutate(ll, b, set_ref_count, &ref_count, ev); |
477 | } | 484 | } |
478 | 485 | ||
479 | static uint32_t inc_ref_count(void *context, uint32_t old) | 486 | static int inc_ref_count(void *context, uint32_t old, uint32_t *new) |
480 | { | 487 | { |
481 | return old + 1; | 488 | *new = old + 1; |
489 | return 0; | ||
482 | } | 490 | } |
483 | 491 | ||
484 | int sm_ll_inc(struct ll_disk *ll, dm_block_t b, enum allocation_event *ev) | 492 | int sm_ll_inc(struct ll_disk *ll, dm_block_t b, enum allocation_event *ev) |
@@ -486,9 +494,15 @@ int sm_ll_inc(struct ll_disk *ll, dm_block_t b, enum allocation_event *ev) | |||
486 | return sm_ll_mutate(ll, b, inc_ref_count, NULL, ev); | 494 | return sm_ll_mutate(ll, b, inc_ref_count, NULL, ev); |
487 | } | 495 | } |
488 | 496 | ||
489 | static uint32_t dec_ref_count(void *context, uint32_t old) | 497 | static int dec_ref_count(void *context, uint32_t old, uint32_t *new) |
490 | { | 498 | { |
491 | return old - 1; | 499 | if (!old) { |
500 | DMERR_LIMIT("unable to decrement a reference count below 0"); | ||
501 | return -EINVAL; | ||
502 | } | ||
503 | |||
504 | *new = old - 1; | ||
505 | return 0; | ||
492 | } | 506 | } |
493 | 507 | ||
494 | int sm_ll_dec(struct ll_disk *ll, dm_block_t b, enum allocation_event *ev) | 508 | int sm_ll_dec(struct ll_disk *ll, dm_block_t b, enum allocation_event *ev) |