Commit 9e521295 authored by Kairui Song's avatar Kairui Song Committed by Peng Zhang
Browse files

lib/xarray: introduce a new helper xas_get_order

maillist inclusion
category: performance
bugzilla: https://gitee.com/openeuler/kernel/issues/I9JAY9
CVE: NA

Reference: https://lore.kernel.org/linux-mm/20240416071722.45997-1-ryncsn@gmail.com/#t

--------------------------------

It can be used after xas_load to check the order of loaded entries.
Compared to xa_get_order, it saves an XA_STATE and avoid a rewalk.

Added new test for xas_get_order, to make the test work, we have to export
xas_get_order with EXPORT_SYMBOL_GPL.

Also fix a sparse warning by checking the slot value with xa_entry instead
of accessing it directly, as suggested by Matthew Wilcox.

Link: https://lkml.kernel.org/r/20240415171857.19244-4-ryncsn@gmail.com


Signed-off-by: default avatarKairui Song <kasong@tencent.com>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>

Conflicts:
	lib/test_xarray.c

Signed-off-by: default avatarZhangPeng <zhangpeng362@huawei.com>
parent 160a6705
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -1551,6 +1551,7 @@ void xas_create_range(struct xa_state *);

#ifdef CONFIG_XARRAY_MULTI
int xa_get_order(struct xarray *, unsigned long index);
int xas_get_order(struct xa_state *xas);
void xas_split(struct xa_state *, void *entry, unsigned int order);
void xas_split_alloc(struct xa_state *, void *entry, unsigned int order, gfp_t);
#else
@@ -1559,6 +1560,11 @@ static inline int xa_get_order(struct xarray *xa, unsigned long index)
	return 0;
}

static inline int xas_get_order(struct xa_state *xas)
{
	return 0;
}

static inline void xas_split(struct xa_state *xas, void *entry,
		unsigned int order)
{
+34 −0
Original line number Diff line number Diff line
@@ -1756,6 +1756,39 @@ static noinline void check_get_order(struct xarray *xa)
	}
}

static noinline void check_xas_get_order(struct xarray *xa)
{
	XA_STATE(xas, xa, 0);

	unsigned int max_order = IS_ENABLED(CONFIG_XARRAY_MULTI) ? 20 : 1;
	unsigned int order;
	unsigned long i, j;

	for (order = 0; order < max_order; order++) {
		for (i = 0; i < 10; i++) {
			xas_set_order(&xas, i << order, order);
			do {
				xas_lock(&xas);
				xas_store(&xas, xa_mk_value(i));
				xas_unlock(&xas);
			} while (xas_nomem(&xas, GFP_KERNEL));

			for (j = i << order; j < (i + 1) << order; j++) {
				xas_set_order(&xas, j, 0);
				rcu_read_lock();
				xas_load(&xas);
				XA_BUG_ON(xa, xas_get_order(&xas) != order);
				rcu_read_unlock();
			}

			xas_lock(&xas);
			xas_set_order(&xas, i << order, order);
			xas_store(&xas, NULL);
			xas_unlock(&xas);
		}
	}
}

static noinline void check_destroy(struct xarray *xa)
{
	unsigned long index;
@@ -1805,6 +1838,7 @@ static int xarray_checks(void)
	check_reserve(&xa0);
	check_multi_store(&array);
	check_get_order(&array);
	check_xas_get_order(&array);
	check_xa_alloc();
	check_find(&array);
	check_find_entry(&array);
+31 −18
Original line number Diff line number Diff line
@@ -1751,39 +1751,52 @@ void *xa_store_range(struct xarray *xa, unsigned long first,
EXPORT_SYMBOL(xa_store_range);

/**
 * xa_get_order() - Get the order of an entry.
 * @xa: XArray.
 * @index: Index of the entry.
 * xas_get_order() - Get the order of an loaded entry after xas_load.
 * @xas: XArray operation state.
 *
 * Called after xas_load, the xas should not be in an error state.
 *
 * Return: A number between 0 and 63 indicating the order of the entry.
 */
int xa_get_order(struct xarray *xa, unsigned long index)
int xas_get_order(struct xa_state *xas)
{
	XA_STATE(xas, xa, index);
	void *entry;
	int order = 0;

	rcu_read_lock();
	entry = xas_load(&xas);

	if (!entry)
		goto unlock;

	if (!xas.xa_node)
		goto unlock;
	if (!xas->xa_node)
		return 0;

	for (;;) {
		unsigned int slot = xas.xa_offset + (1 << order);
		unsigned int slot = xas->xa_offset + (1 << order);

		if (slot >= XA_CHUNK_SIZE)
			break;
		if (!xa_is_sibling(xas.xa_node->slots[slot]))
		if (!xa_is_sibling(xas->xa_node->slots[slot]))
			break;
		order++;
	}

	order += xas.xa_node->shift;
unlock:
	order += xas->xa_node->shift;
	return order;
}
EXPORT_SYMBOL_GPL(xas_get_order);

/**
 * xa_get_order() - Get the order of an entry.
 * @xa: XArray.
 * @index: Index of the entry.
 *
 * Return: A number between 0 and 63 indicating the order of the entry.
 */
int xa_get_order(struct xarray *xa, unsigned long index)
{
	XA_STATE(xas, xa, index);
	int order = 0;
	void *entry;

	rcu_read_lock();
	entry = xas_load(&xas);
	if (entry)
		order = xas_get_order(&xas);
	rcu_read_unlock();

	return order;