Commit e21a2955 authored by Matthew Wilcox's avatar Matthew Wilcox
Browse files

shmem: Convert find_swap_entry to XArray



This is a 1:1 conversion.  The major part of this patch is converting
the test framework from userspace to kernel space and mirroring the
algorithm now used in find_swap_entry().

Signed-off-by: default avatarMatthew Wilcox <willy@infradead.org>
parent a12831bf
Loading
Loading
Loading
Loading
+56 −0
Original line number Diff line number Diff line
@@ -631,6 +631,61 @@ static noinline void check_find(struct xarray *xa)
	check_multi_find_2(xa);
}

/* See find_swap_entry() in mm/shmem.c */
static noinline unsigned long xa_find_entry(struct xarray *xa, void *item)
{
	XA_STATE(xas, xa, 0);
	unsigned int checked = 0;
	void *entry;

	rcu_read_lock();
	xas_for_each(&xas, entry, ULONG_MAX) {
		if (xas_retry(&xas, entry))
			continue;
		if (entry == item)
			break;
		checked++;
		if ((checked % 4) != 0)
			continue;
		xas_pause(&xas);
	}
	rcu_read_unlock();

	return entry ? xas.xa_index : -1;
}

static noinline void check_find_entry(struct xarray *xa)
{
#ifdef CONFIG_XARRAY_MULTI
	unsigned int order;
	unsigned long offset, index;

	for (order = 0; order < 20; order++) {
		for (offset = 0; offset < (1UL << (order + 3));
		     offset += (1UL << order)) {
			for (index = 0; index < (1UL << (order + 5));
			     index += (1UL << order)) {
				xa_store_order(xa, index, order,
						xa_mk_value(index), GFP_KERNEL);
				XA_BUG_ON(xa, xa_load(xa, index) !=
						xa_mk_value(index));
				XA_BUG_ON(xa, xa_find_entry(xa,
						xa_mk_value(index)) != index);
			}
			XA_BUG_ON(xa, xa_find_entry(xa, xa) != -1);
			xa_destroy(xa);
		}
	}
#endif

	XA_BUG_ON(xa, xa_find_entry(xa, xa) != -1);
	xa_store_index(xa, ULONG_MAX, GFP_KERNEL);
	XA_BUG_ON(xa, xa_find_entry(xa, xa) != -1);
	XA_BUG_ON(xa, xa_find_entry(xa, xa_mk_value(LONG_MAX)) != -1);
	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);
@@ -972,6 +1027,7 @@ static int xarray_checks(void)
	check_multi_store(&array);
	check_xa_alloc();
	check_find(&array);
	check_find_entry(&array);
	check_destroy(&array);
	check_move(&array);
	check_create_range(&array);
+10 −17
Original line number Diff line number Diff line
@@ -1100,34 +1100,27 @@ static void shmem_evict_inode(struct inode *inode)
	clear_inode(inode);
}

static unsigned long find_swap_entry(struct radix_tree_root *root, void *item)
static unsigned long find_swap_entry(struct xarray *xa, void *item)
{
	struct radix_tree_iter iter;
	void __rcu **slot;
	unsigned long found = -1;
	XA_STATE(xas, xa, 0);
	unsigned int checked = 0;
	void *entry;

	rcu_read_lock();
	radix_tree_for_each_slot(slot, root, &iter, 0) {
		void *entry = radix_tree_deref_slot(slot);

		if (radix_tree_deref_retry(entry)) {
			slot = radix_tree_iter_retry(&iter);
	xas_for_each(&xas, entry, ULONG_MAX) {
		if (xas_retry(&xas, entry))
			continue;
		}
		if (entry == item) {
			found = iter.index;
		if (entry == item)
			break;
		}
		checked++;
		if ((checked % 4096) != 0)
		if ((checked % XA_CHECK_SCHED) != 0)
			continue;
		slot = radix_tree_iter_resume(slot, &iter);
		xas_pause(&xas);
		cond_resched_rcu();
	}

	rcu_read_unlock();
	return found;

	return entry ? xas.xa_index : -1;
}

/*
+0 −61
Original line number Diff line number Diff line
@@ -236,63 +236,6 @@ void copy_tag_check(void)
	item_kill_tree(&tree);
}

static void __locate_check(struct radix_tree_root *tree, unsigned long index,
			unsigned order)
{
	struct item *item;
	unsigned long index2;

	item_insert_order(tree, index, order);
	item = item_lookup(tree, index);
	index2 = find_item(tree, item);
	if (index != index2) {
		printv(2, "index %ld order %d inserted; found %ld\n",
			index, order, index2);
		abort();
	}
}

static void __order_0_locate_check(void)
{
	RADIX_TREE(tree, GFP_KERNEL);
	int i;

	for (i = 0; i < 50; i++)
		__locate_check(&tree, rand() % INT_MAX, 0);

	item_kill_tree(&tree);
}

static void locate_check(void)
{
	RADIX_TREE(tree, GFP_KERNEL);
	unsigned order;
	unsigned long offset, index;

	__order_0_locate_check();

	for (order = 0; order < 20; order++) {
		for (offset = 0; offset < (1 << (order + 3));
		     offset += (1UL << order)) {
			for (index = 0; index < (1UL << (order + 5));
			     index += (1UL << order)) {
				__locate_check(&tree, index + offset, order);
			}
			if (find_item(&tree, &tree) != -1)
				abort();

			item_kill_tree(&tree);
		}
	}

	if (find_item(&tree, &tree) != -1)
		abort();
	__locate_check(&tree, -1, 0);
	if (find_item(&tree, &tree) != -1)
		abort();
	item_kill_tree(&tree);
}

static void single_thread_tests(bool long_run)
{
	int i;
@@ -303,10 +246,6 @@ static void single_thread_tests(bool long_run)
	rcu_barrier();
	printv(2, "after multiorder_check: %d allocated, preempt %d\n",
		nr_allocated, preempt_count);
	locate_check();
	rcu_barrier();
	printv(2, "after locate_check: %d allocated, preempt %d\n",
		nr_allocated, preempt_count);
	tag_check();
	rcu_barrier();
	printv(2, "after tag_check: %d allocated, preempt %d\n",
+0 −22
Original line number Diff line number Diff line
@@ -209,28 +209,6 @@ int tag_tagged_items(struct radix_tree_root *root, pthread_mutex_t *lock,
	return tagged;
}

/* Use the same pattern as find_swap_entry() in mm/shmem.c */
unsigned long find_item(struct radix_tree_root *root, void *item)
{
	struct radix_tree_iter iter;
	void **slot;
	unsigned long found = -1;
	unsigned long checked = 0;

	radix_tree_for_each_slot(slot, root, &iter, 0) {
		if (*slot == item) {
			found = iter.index;
			break;
		}
		checked++;
		if ((checked % 4) != 0)
			continue;
		slot = radix_tree_iter_resume(slot, &iter);
	}

	return found;
}

static int verify_node(struct radix_tree_node *slot, unsigned int tag,
			int tagged)
{
+0 −1
Original line number Diff line number Diff line
@@ -32,7 +32,6 @@ void item_kill_tree(struct radix_tree_root *root);
int tag_tagged_items(struct radix_tree_root *, pthread_mutex_t *,
			unsigned long start, unsigned long end, unsigned batch,
			unsigned iftag, unsigned thentag);
unsigned long find_item(struct radix_tree_root *, void *item);

void xarray_tests(void);
void tag_check(void);