Merge tag 'xarray-5.5' of git://git.infradead.org/users/willy/linux-dax
Pull XArray fixes from Matthew Wilcox: "Primarily bugfixes, mostly around handling index wrap-around correctly. A couple of doc fixes and adding missing APIs. I had an oops live on stage at linux.conf.au this year, and it turned out to be a bug in xas_find() which I can't prove isn't triggerable in the current codebase. Then in looking for the bug, I spotted two more bugs. The bots have had a few days to chew on this with no problems reported, and it passes the test-suite (which now has more tests to make sure these problems don't come back)" * tag 'xarray-5.5' of git://git.infradead.org/users/willy/linux-dax: XArray: Add xa_for_each_range XArray: Fix xas_find returning too many entries XArray: Fix xa_find_after with multi-index entries XArray: Fix infinite loop with entry at ULONG_MAX XArray: Add wrappers for nested spinlocks XArray: Improve documentation of search marks XArray: Fix xas_pause at ULONG_MAX
Esse commit está contido em:
@@ -2,6 +2,7 @@
|
||||
/*
|
||||
* test_xarray.c: Test the XArray API
|
||||
* Copyright (c) 2017-2018 Microsoft Corporation
|
||||
* Copyright (c) 2019-2020 Oracle
|
||||
* Author: Matthew Wilcox <willy@infradead.org>
|
||||
*/
|
||||
|
||||
@@ -902,28 +903,34 @@ 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);
|
||||
XA_BUG_ON(xa, xa_store_index(xa, next + 1, 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_BUG_ON(xa, xa_find_after(xa, &index, next, XA_PRESENT) != NULL);
|
||||
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_erase_index(xa, next + 1);
|
||||
XA_BUG_ON(xa, !xa_empty(xa));
|
||||
#endif
|
||||
}
|
||||
@@ -1046,12 +1053,33 @@ static noinline void check_find_3(struct xarray *xa)
|
||||
xa_destroy(xa);
|
||||
}
|
||||
|
||||
static noinline void check_find_4(struct xarray *xa)
|
||||
{
|
||||
unsigned long index = 0;
|
||||
void *entry;
|
||||
|
||||
xa_store_index(xa, ULONG_MAX, GFP_KERNEL);
|
||||
|
||||
entry = xa_find_after(xa, &index, ULONG_MAX, XA_PRESENT);
|
||||
XA_BUG_ON(xa, entry != xa_mk_index(ULONG_MAX));
|
||||
|
||||
entry = xa_find_after(xa, &index, ULONG_MAX, XA_PRESENT);
|
||||
XA_BUG_ON(xa, entry);
|
||||
|
||||
xa_erase_index(xa, ULONG_MAX);
|
||||
}
|
||||
|
||||
static noinline void check_find(struct xarray *xa)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
check_find_1(xa);
|
||||
check_find_2(xa);
|
||||
check_find_3(xa);
|
||||
check_multi_find(xa);
|
||||
check_find_4(xa);
|
||||
|
||||
for (i = 2; i < 10; i++)
|
||||
check_multi_find_1(xa, i);
|
||||
check_multi_find_2(xa);
|
||||
}
|
||||
|
||||
@@ -1132,6 +1160,27 @@ static noinline void check_move_tiny(struct xarray *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)
|
||||
{
|
||||
XA_STATE(xas, xa, 0);
|
||||
@@ -1240,6 +1289,7 @@ static noinline void check_move(struct xarray *xa)
|
||||
xa_destroy(xa);
|
||||
|
||||
check_move_tiny(xa);
|
||||
check_move_max(xa);
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
check_move_small(xa, 1UL << i);
|
||||
|
41
lib/xarray.c
41
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;
|
||||
}
|
||||
|
Referência em uma nova issue
Block a user