XArray: Fix xas_pause at ULONG_MAX
If we were unlucky enough to call xas_pause() when the index was at ULONG_MAX (or a multi-slot entry which ends at ULONG_MAX), we would wrap the index back around to 0 and restart the iteration from the beginning. Use the XAS_BOUNDS state to indicate that we should just stop the iteration. Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
This commit is contained in:
parent
0058b0a506
commit
82a22311b7
@ -1132,6 +1132,27 @@ static noinline void check_move_tiny(struct xarray *xa)
|
|||||||
XA_BUG_ON(xa, !xa_empty(xa));
|
XA_BUG_ON(xa, !xa_empty(xa));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static noinline void check_move_max(struct xarray *xa)
|
||||||
|
{
|
||||||
|
XA_STATE(xas, xa, 0);
|
||||||
|
|
||||||
|
xa_store_index(xa, ULONG_MAX, GFP_KERNEL);
|
||||||
|
rcu_read_lock();
|
||||||
|
XA_BUG_ON(xa, xas_find(&xas, ULONG_MAX) != xa_mk_index(ULONG_MAX));
|
||||||
|
XA_BUG_ON(xa, xas_find(&xas, ULONG_MAX) != NULL);
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
xas_set(&xas, 0);
|
||||||
|
rcu_read_lock();
|
||||||
|
XA_BUG_ON(xa, xas_find(&xas, ULONG_MAX) != xa_mk_index(ULONG_MAX));
|
||||||
|
xas_pause(&xas);
|
||||||
|
XA_BUG_ON(xa, xas_find(&xas, ULONG_MAX) != NULL);
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
xa_erase_index(xa, ULONG_MAX);
|
||||||
|
XA_BUG_ON(xa, !xa_empty(xa));
|
||||||
|
}
|
||||||
|
|
||||||
static noinline void check_move_small(struct xarray *xa, unsigned long idx)
|
static noinline void check_move_small(struct xarray *xa, unsigned long idx)
|
||||||
{
|
{
|
||||||
XA_STATE(xas, xa, 0);
|
XA_STATE(xas, xa, 0);
|
||||||
@ -1240,6 +1261,7 @@ static noinline void check_move(struct xarray *xa)
|
|||||||
xa_destroy(xa);
|
xa_destroy(xa);
|
||||||
|
|
||||||
check_move_tiny(xa);
|
check_move_tiny(xa);
|
||||||
|
check_move_max(xa);
|
||||||
|
|
||||||
for (i = 0; i < 16; i++)
|
for (i = 0; i < 16; i++)
|
||||||
check_move_small(xa, 1UL << i);
|
check_move_small(xa, 1UL << i);
|
||||||
|
@ -967,6 +967,7 @@ void xas_pause(struct xa_state *xas)
|
|||||||
if (xas_invalid(xas))
|
if (xas_invalid(xas))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
xas->xa_node = XAS_RESTART;
|
||||||
if (node) {
|
if (node) {
|
||||||
unsigned int offset = xas->xa_offset;
|
unsigned int offset = xas->xa_offset;
|
||||||
while (++offset < XA_CHUNK_SIZE) {
|
while (++offset < XA_CHUNK_SIZE) {
|
||||||
@ -974,10 +975,11 @@ void xas_pause(struct xa_state *xas)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
xas->xa_index += (offset - xas->xa_offset) << node->shift;
|
xas->xa_index += (offset - xas->xa_offset) << node->shift;
|
||||||
|
if (xas->xa_index == 0)
|
||||||
|
xas->xa_node = XAS_BOUNDS;
|
||||||
} else {
|
} else {
|
||||||
xas->xa_index++;
|
xas->xa_index++;
|
||||||
}
|
}
|
||||||
xas->xa_node = XAS_RESTART;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(xas_pause);
|
EXPORT_SYMBOL_GPL(xas_pause);
|
||||||
|
|
||||||
@ -1079,13 +1081,13 @@ void *xas_find(struct xa_state *xas, unsigned long max)
|
|||||||
{
|
{
|
||||||
void *entry;
|
void *entry;
|
||||||
|
|
||||||
if (xas_error(xas))
|
if (xas_error(xas) || xas->xa_node == XAS_BOUNDS)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (!xas->xa_node) {
|
if (!xas->xa_node) {
|
||||||
xas->xa_index = 1;
|
xas->xa_index = 1;
|
||||||
return set_bounds(xas);
|
return set_bounds(xas);
|
||||||
} else if (xas_top(xas->xa_node)) {
|
} else if (xas->xa_node == XAS_RESTART) {
|
||||||
entry = xas_load(xas);
|
entry = xas_load(xas);
|
||||||
if (entry || xas_not_node(xas->xa_node))
|
if (entry || xas_not_node(xas->xa_node))
|
||||||
return entry;
|
return entry;
|
||||||
|
Loading…
Reference in New Issue
Block a user