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: Matthew Wilcox <willy@infradead.org>
This commit is contained in:
Matthew Wilcox 2017-11-22 08:36:00 -05:00
parent a12831bf42
commit e21a29552f
5 changed files with 66 additions and 101 deletions

View File

@ -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);

View File

@ -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;
}
/*

View File

@ -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",

View File

@ -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)
{

View File

@ -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);