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 | 38 | 
1 files changed, 28 insertions, 10 deletions
diff --git a/drivers/md/persistent-data/dm-space-map-common.c b/drivers/md/persistent-data/dm-space-map-common.c index 6058569fe86..aacbe70c2c2 100644 --- a/drivers/md/persistent-data/dm-space-map-common.c +++ b/drivers/md/persistent-data/dm-space-map-common.c @@ -245,6 +245,10 @@ int sm_ll_extend(struct ll_disk *ll, dm_block_t extra_blocks)  		return -EINVAL;  	} +	/* +	 * We need to set this before the dm_tm_new_block() call below. +	 */ +	ll->nr_blocks = nr_blocks;  	for (i = old_blocks; i < blocks; i++) {  		struct dm_block *b;  		struct disk_index_entry idx; @@ -252,6 +256,7 @@ int sm_ll_extend(struct ll_disk *ll, dm_block_t extra_blocks)  		r = dm_tm_new_block(ll->tm, &dm_sm_bitmap_validator, &b);  		if (r < 0)  			return r; +  		idx.blocknr = cpu_to_le64(dm_block_location(b));  		r = dm_tm_unlock(ll->tm, b); @@ -266,7 +271,6 @@ int sm_ll_extend(struct ll_disk *ll, dm_block_t extra_blocks)  			return r;  	} -	ll->nr_blocks = nr_blocks;  	return 0;  } @@ -381,7 +385,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; @@ -410,11 +414,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); @@ -465,9 +475,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, @@ -476,9 +487,10 @@ 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) @@ -486,9 +498,15 @@ 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)  | 
