diff options
Diffstat (limited to 'lib/xarray.c')
| -rw-r--r-- | lib/xarray.c | 41 | 
1 files changed, 29 insertions, 12 deletions
diff --git a/lib/xarray.c b/lib/xarray.c index 1237c213f52b..1d9fab7db8da 100644 --- a/lib/xarray.c +++ b/lib/xarray.c @@ -1,7 +1,8 @@  // SPDX-License-Identifier: GPL-2.0+  /*   * XArray implementation - * Copyright (c) 2017 Microsoft Corporation + * Copyright (c) 2017-2018 Microsoft Corporation + * Copyright (c) 2018-2020 Oracle   * Author: Matthew Wilcox <willy@infradead.org>   */ @@ -967,6 +968,7 @@ void xas_pause(struct xa_state *xas)  	if (xas_invalid(xas))  		return; +	xas->xa_node = XAS_RESTART;  	if (node) {  		unsigned int offset = xas->xa_offset;  		while (++offset < XA_CHUNK_SIZE) { @@ -974,10 +976,11 @@ void xas_pause(struct xa_state *xas)  				break;  		}  		xas->xa_index += (offset - xas->xa_offset) << node->shift; +		if (xas->xa_index == 0) +			xas->xa_node = XAS_BOUNDS;  	} else {  		xas->xa_index++;  	} -	xas->xa_node = XAS_RESTART;  }  EXPORT_SYMBOL_GPL(xas_pause); @@ -1079,13 +1082,15 @@ void *xas_find(struct xa_state *xas, unsigned long max)  {  	void *entry; -	if (xas_error(xas)) +	if (xas_error(xas) || xas->xa_node == XAS_BOUNDS)  		return NULL; +	if (xas->xa_index > max) +		return set_bounds(xas);  	if (!xas->xa_node) {  		xas->xa_index = 1;  		return set_bounds(xas); -	} else if (xas_top(xas->xa_node)) { +	} else if (xas->xa_node == XAS_RESTART) {  		entry = xas_load(xas);  		if (entry || xas_not_node(xas->xa_node))  			return entry; @@ -1150,6 +1155,8 @@ void *xas_find_marked(struct xa_state *xas, unsigned long max, xa_mark_t mark)  	if (xas_error(xas))  		return NULL; +	if (xas->xa_index > max) +		goto max;  	if (!xas->xa_node) {  		xas->xa_index = 1; @@ -1824,6 +1831,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. @@ -1847,21 +1865,20 @@ void *xa_find_after(struct xarray *xa, unsigned long *indexp,  	XA_STATE(xas, xa, *indexp + 1);  	void *entry; +	if (xas.xa_index == 0) +		return NULL; +  	rcu_read_lock();  	for (;;) {  		if ((__force unsigned int)filter < XA_MAX_MARKS)  			entry = xas_find_marked(&xas, max, filter);  		else  			entry = xas_find(&xas, max); -		if (xas.xa_node == XAS_BOUNDS) + +		if (xas_invalid(&xas))  			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;  	}  | 
