Skip to content

Commit

Permalink
dm space map: disallow decrementing a reference count below zero
Browse files Browse the repository at this point in the history
The old behaviour, returning -EINVAL if a ref_count of 0 would be
decremented, was removed in commit f722063 ("dm space map: optimise
sm_ll_dec and sm_ll_inc").  To fix this regression we return an error
code from the mutator function pointer passed to sm_ll_mutate() and have
dec_ref_count() return -EINVAL if the old ref_count is 0.

Add a DMERR to reflect the potential seriousness of this error.

Also, add missing dm_tm_unlock() to sm_ll_mutate()'s error path.

With this fix the following dmts regression test now passes:
 dmtest run --suite cache -n /metadata_use_kernel/

The next patch fixes the higher-level dm-array code that exposed this
regression.

Signed-off-by: Joe Thornber <ejt@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Cc: stable@vger.kernel.org # 3.12+
  • Loading branch information
Joe Thornber authored and Mike Snitzer committed Dec 13, 2013
1 parent 76f5bee commit 5b564d8
Showing 1 changed file with 23 additions and 9 deletions.
32 changes: 23 additions & 9 deletions drivers/md/persistent-data/dm-space-map-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ int sm_ll_find_free_block(struct ll_disk *ll, dm_block_t begin,
}

static int sm_ll_mutate(struct ll_disk *ll, dm_block_t b,
uint32_t (*mutator)(void *context, uint32_t old),
int (*mutator)(void *context, uint32_t old, uint32_t *new),
void *context, enum allocation_event *ev)
{
int r;
Expand Down Expand Up @@ -410,11 +410,17 @@ static int sm_ll_mutate(struct ll_disk *ll, dm_block_t b,

if (old > 2) {
r = sm_ll_lookup_big_ref_count(ll, b, &old);
if (r < 0)
if (r < 0) {
dm_tm_unlock(ll->tm, nb);
return r;
}
}

ref_count = mutator(context, old);
r = mutator(context, old, &ref_count);
if (r) {
dm_tm_unlock(ll->tm, nb);
return r;
}

if (ref_count <= 2) {
sm_set_bitmap(bm_le, bit, ref_count);
Expand Down Expand Up @@ -465,9 +471,10 @@ static int sm_ll_mutate(struct ll_disk *ll, dm_block_t b,
return ll->save_ie(ll, index, &ie_disk);
}

static uint32_t set_ref_count(void *context, uint32_t old)
static int set_ref_count(void *context, uint32_t old, uint32_t *new)
{
return *((uint32_t *) context);
*new = *((uint32_t *) context);
return 0;
}

int sm_ll_insert(struct ll_disk *ll, dm_block_t b,
Expand All @@ -476,19 +483,26 @@ int sm_ll_insert(struct ll_disk *ll, dm_block_t b,
return sm_ll_mutate(ll, b, set_ref_count, &ref_count, ev);
}

static uint32_t inc_ref_count(void *context, uint32_t old)
static int inc_ref_count(void *context, uint32_t old, uint32_t *new)
{
return old + 1;
*new = old + 1;
return 0;
}

int sm_ll_inc(struct ll_disk *ll, dm_block_t b, enum allocation_event *ev)
{
return sm_ll_mutate(ll, b, inc_ref_count, NULL, ev);
}

static uint32_t dec_ref_count(void *context, uint32_t old)
static int dec_ref_count(void *context, uint32_t old, uint32_t *new)
{
return old - 1;
if (!old) {
DMERR_LIMIT("unable to decrement a reference count below 0");
return -EINVAL;
}

*new = old - 1;
return 0;
}

int sm_ll_dec(struct ll_disk *ll, dm_block_t b, enum allocation_event *ev)
Expand Down

0 comments on commit 5b564d8

Please sign in to comment.