Commit 01305db8 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents 0839c537 12fd2aee
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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);
+1 −0
Original line number Diff line number Diff line
@@ -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)))

+12 −2
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
@@ -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);
+10 −2
Original line number Diff line number Diff line
@@ -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;
Loading