XArray updates for 5.2-rc6
Account XArray nodes for the page cache to the appropriate cgroup (Johannes Weiner) Fix idr_get_next() when called under the RCU lock (Matthew Wilcox) Add a test for xa_insert() (Matthew Wilcox) -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEejHryeLBw/spnjHrDpNsjXcpgj4FAl0WuKsACgkQDpNsjXcp gj73zgf9Eb477PuwYZpFBA9ZxI5v/6WyqbaWXKdqEhotARgIUuv1CfVnkt1IJE6P Z3QCRABZ3pIKHgIErJN53B7AdvdONUO4Xf9VFBqmxeWE7F9L3sROOpXc8IrR26kV hITQn8mwgacNQ8mLtQmcSFaCVC2E7yVNBhVd5zmcA6jNIAFsOJcP06KLJTe94OXe AB9TJvswxpzAEX8emHQ/a1SFBNZWJ7b53hBcu8CJn8CuGDxmo1/+qqoRyNY+WrDO OohFk2u1j6Esfc6j0k+Akt8mEFyfU2oxFfv5MjL0KYEyrHoU84eZljFGgf7rQqGj fqH9RO8J8eoj4D/3XaLL5QYRLIxRaw== =AXZy -----END PGP SIGNATURE----- Merge tag 'xarray-5.2-rc6' of git://git.infradead.org/users/willy/linux-dax Pull XArray fixes from Matthew Wilcox: - Account XArray nodes for the page cache to the appropriate cgroup (Johannes Weiner) - Fix idr_get_next() when called under the RCU lock (Matthew Wilcox) - Add a test for xa_insert() (Matthew Wilcox) * tag 'xarray-5.2-rc6' of git://git.infradead.org/users/willy/linux-dax: XArray tests: Add check_insert idr: Fix idr_get_next race with idr_remove mm: fix page cache convergence regression
This commit is contained in:
commit
01305db842
|
@ -362,7 +362,7 @@ EXPORT_SYMBOL(inc_nlink);
|
|||
|
||||
static void __address_space_init_once(struct address_space *mapping)
|
||||
{
|
||||
xa_init_flags(&mapping->i_pages, XA_FLAGS_LOCK_IRQ);
|
||||
xa_init_flags(&mapping->i_pages, XA_FLAGS_LOCK_IRQ | XA_FLAGS_ACCOUNT);
|
||||
init_rwsem(&mapping->i_mmap_rwsem);
|
||||
INIT_LIST_HEAD(&mapping->private_list);
|
||||
spin_lock_init(&mapping->private_lock);
|
||||
|
|
|
@ -265,6 +265,7 @@ enum xa_lock_type {
|
|||
#define XA_FLAGS_TRACK_FREE ((__force gfp_t)4U)
|
||||
#define XA_FLAGS_ZERO_BUSY ((__force gfp_t)8U)
|
||||
#define XA_FLAGS_ALLOC_WRAPPED ((__force gfp_t)16U)
|
||||
#define XA_FLAGS_ACCOUNT ((__force gfp_t)32U)
|
||||
#define XA_FLAGS_MARK(mark) ((__force gfp_t)((1U << __GFP_BITS_SHIFT) << \
|
||||
(__force unsigned)(mark)))
|
||||
|
||||
|
|
14
lib/idr.c
14
lib/idr.c
|
@ -228,11 +228,21 @@ void *idr_get_next(struct idr *idr, int *nextid)
|
|||
{
|
||||
struct radix_tree_iter iter;
|
||||
void __rcu **slot;
|
||||
void *entry = NULL;
|
||||
unsigned long base = idr->idr_base;
|
||||
unsigned long id = *nextid;
|
||||
|
||||
id = (id < base) ? 0 : id - base;
|
||||
slot = radix_tree_iter_find(&idr->idr_rt, &iter, id);
|
||||
radix_tree_for_each_slot(slot, &idr->idr_rt, &iter, id) {
|
||||
entry = rcu_dereference_raw(*slot);
|
||||
if (!entry)
|
||||
continue;
|
||||
if (!xa_is_internal(entry))
|
||||
break;
|
||||
if (slot != &idr->idr_rt.xa_head && !xa_is_retry(entry))
|
||||
break;
|
||||
slot = radix_tree_iter_retry(&iter);
|
||||
}
|
||||
if (!slot)
|
||||
return NULL;
|
||||
id = iter.index + base;
|
||||
|
@ -241,7 +251,7 @@ void *idr_get_next(struct idr *idr, int *nextid)
|
|||
return NULL;
|
||||
|
||||
*nextid = id;
|
||||
return rcu_dereference_raw(*slot);
|
||||
return entry;
|
||||
}
|
||||
EXPORT_SYMBOL(idr_get_next);
|
||||
|
||||
|
|
|
@ -38,6 +38,12 @@ static void *xa_store_index(struct xarray *xa, unsigned long index, gfp_t gfp)
|
|||
return xa_store(xa, index, xa_mk_index(index), gfp);
|
||||
}
|
||||
|
||||
static void xa_insert_index(struct xarray *xa, unsigned long index)
|
||||
{
|
||||
XA_BUG_ON(xa, xa_insert(xa, index, xa_mk_index(index),
|
||||
GFP_KERNEL) != 0);
|
||||
}
|
||||
|
||||
static void xa_alloc_index(struct xarray *xa, unsigned long index, gfp_t gfp)
|
||||
{
|
||||
u32 id;
|
||||
|
@ -338,6 +344,37 @@ static noinline void check_xa_shrink(struct xarray *xa)
|
|||
}
|
||||
}
|
||||
|
||||
static noinline void check_insert(struct xarray *xa)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
for (i = 0; i < 1024; i++) {
|
||||
xa_insert_index(xa, i);
|
||||
XA_BUG_ON(xa, xa_load(xa, i - 1) != NULL);
|
||||
XA_BUG_ON(xa, xa_load(xa, i + 1) != NULL);
|
||||
xa_erase_index(xa, i);
|
||||
}
|
||||
|
||||
for (i = 10; i < BITS_PER_LONG; i++) {
|
||||
xa_insert_index(xa, 1UL << i);
|
||||
XA_BUG_ON(xa, xa_load(xa, (1UL << i) - 1) != NULL);
|
||||
XA_BUG_ON(xa, xa_load(xa, (1UL << i) + 1) != NULL);
|
||||
xa_erase_index(xa, 1UL << i);
|
||||
|
||||
xa_insert_index(xa, (1UL << i) - 1);
|
||||
XA_BUG_ON(xa, xa_load(xa, (1UL << i) - 2) != NULL);
|
||||
XA_BUG_ON(xa, xa_load(xa, 1UL << i) != NULL);
|
||||
xa_erase_index(xa, (1UL << i) - 1);
|
||||
}
|
||||
|
||||
xa_insert_index(xa, ~0UL);
|
||||
XA_BUG_ON(xa, xa_load(xa, 0UL) != NULL);
|
||||
XA_BUG_ON(xa, xa_load(xa, ~1UL) != NULL);
|
||||
xa_erase_index(xa, ~0UL);
|
||||
|
||||
XA_BUG_ON(xa, !xa_empty(xa));
|
||||
}
|
||||
|
||||
static noinline void check_cmpxchg(struct xarray *xa)
|
||||
{
|
||||
void *FIVE = xa_mk_value(5);
|
||||
|
@ -1527,6 +1564,7 @@ static int xarray_checks(void)
|
|||
check_xa_mark(&array);
|
||||
check_xa_shrink(&array);
|
||||
check_xas_erase(&array);
|
||||
check_insert(&array);
|
||||
check_cmpxchg(&array);
|
||||
check_reserve(&array);
|
||||
check_reserve(&xa0);
|
||||
|
|
12
lib/xarray.c
12
lib/xarray.c
|
@ -298,6 +298,8 @@ bool xas_nomem(struct xa_state *xas, gfp_t gfp)
|
|||
xas_destroy(xas);
|
||||
return false;
|
||||
}
|
||||
if (xas->xa->xa_flags & XA_FLAGS_ACCOUNT)
|
||||
gfp |= __GFP_ACCOUNT;
|
||||
xas->xa_alloc = kmem_cache_alloc(radix_tree_node_cachep, gfp);
|
||||
if (!xas->xa_alloc)
|
||||
return false;
|
||||
|
@ -325,6 +327,8 @@ static bool __xas_nomem(struct xa_state *xas, gfp_t gfp)
|
|||
xas_destroy(xas);
|
||||
return false;
|
||||
}
|
||||
if (xas->xa->xa_flags & XA_FLAGS_ACCOUNT)
|
||||
gfp |= __GFP_ACCOUNT;
|
||||
if (gfpflags_allow_blocking(gfp)) {
|
||||
xas_unlock_type(xas, lock_type);
|
||||
xas->xa_alloc = kmem_cache_alloc(radix_tree_node_cachep, gfp);
|
||||
|
@ -358,8 +362,12 @@ static void *xas_alloc(struct xa_state *xas, unsigned int shift)
|
|||
if (node) {
|
||||
xas->xa_alloc = NULL;
|
||||
} else {
|
||||
node = kmem_cache_alloc(radix_tree_node_cachep,
|
||||
GFP_NOWAIT | __GFP_NOWARN);
|
||||
gfp_t gfp = GFP_NOWAIT | __GFP_NOWARN;
|
||||
|
||||
if (xas->xa->xa_flags & XA_FLAGS_ACCOUNT)
|
||||
gfp |= __GFP_ACCOUNT;
|
||||
|
||||
node = kmem_cache_alloc(radix_tree_node_cachep, gfp);
|
||||
if (!node) {
|
||||
xas_set_err(xas, -ENOMEM);
|
||||
return NULL;
|
||||
|
|
|
@ -279,6 +279,51 @@ static void idr_align_test(struct idr *idr)
|
|||
}
|
||||
}
|
||||
|
||||
DEFINE_IDR(find_idr);
|
||||
|
||||
static void *idr_throbber(void *arg)
|
||||
{
|
||||
time_t start = time(NULL);
|
||||
int id = *(int *)arg;
|
||||
|
||||
rcu_register_thread();
|
||||
do {
|
||||
idr_alloc(&find_idr, xa_mk_value(id), id, id + 1, GFP_KERNEL);
|
||||
idr_remove(&find_idr, id);
|
||||
} while (time(NULL) < start + 10);
|
||||
rcu_unregister_thread();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void idr_find_test_1(int anchor_id, int throbber_id)
|
||||
{
|
||||
pthread_t throbber;
|
||||
time_t start = time(NULL);
|
||||
|
||||
pthread_create(&throbber, NULL, idr_throbber, &throbber_id);
|
||||
|
||||
BUG_ON(idr_alloc(&find_idr, xa_mk_value(anchor_id), anchor_id,
|
||||
anchor_id + 1, GFP_KERNEL) != anchor_id);
|
||||
|
||||
do {
|
||||
int id = 0;
|
||||
void *entry = idr_get_next(&find_idr, &id);
|
||||
BUG_ON(entry != xa_mk_value(id));
|
||||
} while (time(NULL) < start + 11);
|
||||
|
||||
pthread_join(throbber, NULL);
|
||||
|
||||
idr_remove(&find_idr, anchor_id);
|
||||
BUG_ON(!idr_is_empty(&find_idr));
|
||||
}
|
||||
|
||||
void idr_find_test(void)
|
||||
{
|
||||
idr_find_test_1(100000, 0);
|
||||
idr_find_test_1(0, 100000);
|
||||
}
|
||||
|
||||
void idr_checks(void)
|
||||
{
|
||||
unsigned long i;
|
||||
|
@ -360,6 +405,7 @@ void idr_checks(void)
|
|||
idr_u32_test(1);
|
||||
idr_u32_test(0);
|
||||
idr_align_test(&idr);
|
||||
idr_find_test();
|
||||
}
|
||||
|
||||
#define module_init(x)
|
||||
|
|
Loading…
Reference in New Issue