mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	dm space map: disallow decrementing a reference count below zero
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+
			
			
This commit is contained in:
		
							parent
							
								
									76f5bee5c3
								
							
						
					
					
						commit
						5b564d80f8
					
				
					 1 changed files with 23 additions and 9 deletions
				
			
		| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
| 
						 | 
				
			
			@ -476,9 +483,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 +494,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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue