forked from mirrors/linux
		
	XArray: Fix xa_find_after with multi-index entries
If the entry is of an order which is a multiple of XA_CHUNK_SIZE, the current detection of sibling entries does not work. Factor out an xas_sibling() function to make xa_find_after() a little more understandable, and write a new implementation that doesn't suffer from the same bug. Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> Cc: stable@vger.kernel.org
This commit is contained in:
		
							parent
							
								
									430f24f94c
								
							
						
					
					
						commit
						19c30f4dd0
					
				
					 2 changed files with 32 additions and 20 deletions
				
			
		|  | @ -902,28 +902,30 @@ static noinline void check_store_iter(struct xarray *xa) | |||
| 	XA_BUG_ON(xa, !xa_empty(xa)); | ||||
| } | ||||
| 
 | ||||
| static noinline void check_multi_find(struct xarray *xa) | ||||
| static noinline void check_multi_find_1(struct xarray *xa, unsigned order) | ||||
| { | ||||
| #ifdef CONFIG_XARRAY_MULTI | ||||
| 	unsigned long multi = 3 << order; | ||||
| 	unsigned long next = 4 << order; | ||||
| 	unsigned long index; | ||||
| 
 | ||||
| 	xa_store_order(xa, 12, 2, xa_mk_value(12), GFP_KERNEL); | ||||
| 	XA_BUG_ON(xa, xa_store_index(xa, 16, GFP_KERNEL) != NULL); | ||||
| 	xa_store_order(xa, multi, order, xa_mk_value(multi), GFP_KERNEL); | ||||
| 	XA_BUG_ON(xa, xa_store_index(xa, next, GFP_KERNEL) != NULL); | ||||
| 
 | ||||
| 	index = 0; | ||||
| 	XA_BUG_ON(xa, xa_find(xa, &index, ULONG_MAX, XA_PRESENT) != | ||||
| 			xa_mk_value(12)); | ||||
| 	XA_BUG_ON(xa, index != 12); | ||||
| 	index = 13; | ||||
| 			xa_mk_value(multi)); | ||||
| 	XA_BUG_ON(xa, index != multi); | ||||
| 	index = multi + 1; | ||||
| 	XA_BUG_ON(xa, xa_find(xa, &index, ULONG_MAX, XA_PRESENT) != | ||||
| 			xa_mk_value(12)); | ||||
| 	XA_BUG_ON(xa, (index < 12) || (index >= 16)); | ||||
| 			xa_mk_value(multi)); | ||||
| 	XA_BUG_ON(xa, (index < multi) || (index >= next)); | ||||
| 	XA_BUG_ON(xa, xa_find_after(xa, &index, ULONG_MAX, XA_PRESENT) != | ||||
| 			xa_mk_value(16)); | ||||
| 	XA_BUG_ON(xa, index != 16); | ||||
| 			xa_mk_value(next)); | ||||
| 	XA_BUG_ON(xa, index != next); | ||||
| 
 | ||||
| 	xa_erase_index(xa, 12); | ||||
| 	xa_erase_index(xa, 16); | ||||
| 	xa_erase_index(xa, multi); | ||||
| 	xa_erase_index(xa, next); | ||||
| 	XA_BUG_ON(xa, !xa_empty(xa)); | ||||
| #endif | ||||
| } | ||||
|  | @ -1064,11 +1066,15 @@ static noinline void check_find_4(struct xarray *xa) | |||
| 
 | ||||
| static noinline void check_find(struct xarray *xa) | ||||
| { | ||||
| 	unsigned i; | ||||
| 
 | ||||
| 	check_find_1(xa); | ||||
| 	check_find_2(xa); | ||||
| 	check_find_3(xa); | ||||
| 	check_find_4(xa); | ||||
| 	check_multi_find(xa); | ||||
| 
 | ||||
| 	for (i = 2; i < 10; i++) | ||||
| 		check_multi_find_1(xa, i); | ||||
| 	check_multi_find_2(xa); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										20
									
								
								lib/xarray.c
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								lib/xarray.c
									
									
									
									
									
								
							|  | @ -1826,6 +1826,17 @@ void *xa_find(struct xarray *xa, unsigned long *indexp, | |||
| } | ||||
| EXPORT_SYMBOL(xa_find); | ||||
| 
 | ||||
| static bool xas_sibling(struct xa_state *xas) | ||||
| { | ||||
| 	struct xa_node *node = xas->xa_node; | ||||
| 	unsigned long mask; | ||||
| 
 | ||||
| 	if (!node) | ||||
| 		return false; | ||||
| 	mask = (XA_CHUNK_SIZE << node->shift) - 1; | ||||
| 	return (xas->xa_index & mask) > (xas->xa_offset << node->shift); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * xa_find_after() - Search the XArray for a present entry. | ||||
|  * @xa: XArray. | ||||
|  | @ -1860,13 +1871,8 @@ void *xa_find_after(struct xarray *xa, unsigned long *indexp, | |||
| 			entry = xas_find(&xas, max); | ||||
| 		if (xas.xa_node == XAS_BOUNDS) | ||||
| 			break; | ||||
| 		if (xas.xa_shift) { | ||||
| 			if (xas.xa_index & ((1UL << xas.xa_shift) - 1)) | ||||
| 				continue; | ||||
| 		} else { | ||||
| 			if (xas.xa_offset < (xas.xa_index & XA_CHUNK_MASK)) | ||||
| 				continue; | ||||
| 		} | ||||
| 		if (xas_sibling(&xas)) | ||||
| 			continue; | ||||
| 		if (!xas_retry(&xas, entry)) | ||||
| 			break; | ||||
| 	} | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Matthew Wilcox (Oracle)
						Matthew Wilcox (Oracle)