2278 lines · 59.2 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0+/* * test_xarray.c: Test the XArray API * Copyright (c) 2017-2018 Microsoft Corporation * Copyright (c) 2019-2020 Oracle * Author: Matthew Wilcox <willy@infradead.org> */ #include <linux/xarray.h>#include <linux/module.h> static unsigned int tests_run;static unsigned int tests_passed; static const unsigned int order_limit =		IS_ENABLED(CONFIG_XARRAY_MULTI) ? BITS_PER_LONG : 1; #ifndef XA_DEBUG# ifdef __KERNEL__void xa_dump(const struct xarray *xa) { }# endif#undef XA_BUG_ON#define XA_BUG_ON(xa, x) do {					\	tests_run++;						\	if (x) {						\		printk("BUG at %s:%d\n", __func__, __LINE__);	\		xa_dump(xa);					\		dump_stack();					\	} else {						\		tests_passed++;					\	}							\} while (0)#endif static void *xa_mk_index(unsigned long index){	return xa_mk_value(index & LONG_MAX);} 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; 	XA_BUG_ON(xa, xa_alloc(xa, &id, xa_mk_index(index), xa_limit_32b,				gfp) != 0);	XA_BUG_ON(xa, id != index);} static void xa_erase_index(struct xarray *xa, unsigned long index){	XA_BUG_ON(xa, xa_erase(xa, index) != xa_mk_index(index));	XA_BUG_ON(xa, xa_load(xa, index) != NULL);} /* * If anyone needs this, please move it to xarray.c.  We have no current * users outside the test suite because all current multislot users want * to use the advanced API. */static void *xa_store_order(struct xarray *xa, unsigned long index,		unsigned order, void *entry, gfp_t gfp){	XA_STATE_ORDER(xas, xa, index, order);	void *curr; 	do {		xas_lock(&xas);		curr = xas_store(&xas, entry);		xas_unlock(&xas);	} while (xas_nomem(&xas, gfp)); 	return curr;} static noinline void check_xa_err(struct xarray *xa){	XA_BUG_ON(xa, xa_err(xa_store_index(xa, 0, GFP_NOWAIT)) != 0);	XA_BUG_ON(xa, xa_err(xa_erase(xa, 0)) != 0);#ifndef __KERNEL__	/* The kernel does not fail GFP_NOWAIT allocations */	XA_BUG_ON(xa, xa_err(xa_store_index(xa, 1, GFP_NOWAIT)) != -ENOMEM);	XA_BUG_ON(xa, xa_err(xa_store_index(xa, 1, GFP_NOWAIT)) != -ENOMEM);#endif	XA_BUG_ON(xa, xa_err(xa_store_index(xa, 1, GFP_KERNEL)) != 0);	XA_BUG_ON(xa, xa_err(xa_store(xa, 1, xa_mk_value(0), GFP_KERNEL)) != 0);	XA_BUG_ON(xa, xa_err(xa_erase(xa, 1)) != 0);// kills the test-suite :-(//	XA_BUG_ON(xa, xa_err(xa_store(xa, 0, xa_mk_internal(0), 0)) != -EINVAL);} static noinline void check_xas_retry(struct xarray *xa){	XA_STATE(xas, xa, 0);	void *entry; 	xa_store_index(xa, 0, GFP_KERNEL);	xa_store_index(xa, 1, GFP_KERNEL); 	rcu_read_lock();	XA_BUG_ON(xa, xas_find(&xas, ULONG_MAX) != xa_mk_value(0));	xa_erase_index(xa, 1);	XA_BUG_ON(xa, !xa_is_retry(xas_reload(&xas)));	XA_BUG_ON(xa, xas_retry(&xas, NULL));	XA_BUG_ON(xa, xas_retry(&xas, xa_mk_value(0)));	xas_reset(&xas);	XA_BUG_ON(xa, xas.xa_node != XAS_RESTART);	XA_BUG_ON(xa, xas_next_entry(&xas, ULONG_MAX) != xa_mk_value(0));	XA_BUG_ON(xa, xas.xa_node != NULL);	rcu_read_unlock(); 	XA_BUG_ON(xa, xa_store_index(xa, 1, GFP_KERNEL) != NULL); 	rcu_read_lock();	XA_BUG_ON(xa, !xa_is_internal(xas_reload(&xas)));	xas.xa_node = XAS_RESTART;	XA_BUG_ON(xa, xas_next_entry(&xas, ULONG_MAX) != xa_mk_value(0));	rcu_read_unlock(); 	/* Make sure we can iterate through retry entries */	xas_lock(&xas);	xas_set(&xas, 0);	xas_store(&xas, XA_RETRY_ENTRY);	xas_set(&xas, 1);	xas_store(&xas, XA_RETRY_ENTRY); 	xas_set(&xas, 0);	xas_for_each(&xas, entry, ULONG_MAX) {		xas_store(&xas, xa_mk_index(xas.xa_index));	}	xas_unlock(&xas); 	xa_erase_index(xa, 0);	xa_erase_index(xa, 1);} static noinline void check_xa_load(struct xarray *xa){	unsigned long i, j; 	for (i = 0; i < 1024; i++) {		for (j = 0; j < 1024; j++) {			void *entry = xa_load(xa, j);			if (j < i)				XA_BUG_ON(xa, xa_to_value(entry) != j);			else				XA_BUG_ON(xa, entry);		}		XA_BUG_ON(xa, xa_store_index(xa, i, GFP_KERNEL) != NULL);	} 	for (i = 0; i < 1024; i++) {		for (j = 0; j < 1024; j++) {			void *entry = xa_load(xa, j);			if (j >= i)				XA_BUG_ON(xa, xa_to_value(entry) != j);			else				XA_BUG_ON(xa, entry);		}		xa_erase_index(xa, i);	}	XA_BUG_ON(xa, !xa_empty(xa));} static noinline void check_xa_mark_1(struct xarray *xa, unsigned long index){	unsigned int order;	unsigned int max_order = IS_ENABLED(CONFIG_XARRAY_MULTI) ? 8 : 1; 	/* NULL elements have no marks set */	XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0));	xa_set_mark(xa, index, XA_MARK_0);	XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0)); 	/* Storing a pointer will not make a mark appear */	XA_BUG_ON(xa, xa_store_index(xa, index, GFP_KERNEL) != NULL);	XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0));	xa_set_mark(xa, index, XA_MARK_0);	XA_BUG_ON(xa, !xa_get_mark(xa, index, XA_MARK_0)); 	/* Setting one mark will not set another mark */	XA_BUG_ON(xa, xa_get_mark(xa, index + 1, XA_MARK_0));	XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_1)); 	/* Storing NULL clears marks, and they can't be set again */	xa_erase_index(xa, index);	XA_BUG_ON(xa, !xa_empty(xa));	XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0));	xa_set_mark(xa, index, XA_MARK_0);	XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0)); 	/*	 * Storing a multi-index entry over entries with marks gives the	 * entire entry the union of the marks	 */	BUG_ON((index % 4) != 0);	for (order = 2; order < max_order; order++) {		unsigned long base = round_down(index, 1UL << order);		unsigned long next = base + (1UL << order);		unsigned long i; 		XA_BUG_ON(xa, xa_store_index(xa, index + 1, GFP_KERNEL));		xa_set_mark(xa, index + 1, XA_MARK_0);		XA_BUG_ON(xa, xa_store_index(xa, index + 2, GFP_KERNEL));		xa_set_mark(xa, index + 2, XA_MARK_2);		XA_BUG_ON(xa, xa_store_index(xa, next, GFP_KERNEL));		xa_store_order(xa, index, order, xa_mk_index(index),				GFP_KERNEL);		for (i = base; i < next; i++) {			XA_STATE(xas, xa, i);			unsigned int seen = 0;			void *entry; 			XA_BUG_ON(xa, !xa_get_mark(xa, i, XA_MARK_0));			XA_BUG_ON(xa, xa_get_mark(xa, i, XA_MARK_1));			XA_BUG_ON(xa, !xa_get_mark(xa, i, XA_MARK_2)); 			/* We should see two elements in the array */			rcu_read_lock();			xas_for_each(&xas, entry, ULONG_MAX)				seen++;			rcu_read_unlock();			XA_BUG_ON(xa, seen != 2); 			/* One of which is marked */			xas_set(&xas, 0);			seen = 0;			rcu_read_lock();			xas_for_each_marked(&xas, entry, ULONG_MAX, XA_MARK_0)				seen++;			rcu_read_unlock();			XA_BUG_ON(xa, seen != 1);		}		XA_BUG_ON(xa, xa_get_mark(xa, next, XA_MARK_0));		XA_BUG_ON(xa, xa_get_mark(xa, next, XA_MARK_1));		XA_BUG_ON(xa, xa_get_mark(xa, next, XA_MARK_2));		xa_erase_index(xa, index);		xa_erase_index(xa, next);		XA_BUG_ON(xa, !xa_empty(xa));	}	XA_BUG_ON(xa, !xa_empty(xa));} static noinline void check_xa_mark_2(struct xarray *xa){	XA_STATE(xas, xa, 0);	unsigned long index;	unsigned int count = 0;	void *entry; 	xa_store_index(xa, 0, GFP_KERNEL);	xa_set_mark(xa, 0, XA_MARK_0);	xas_lock(&xas);	xas_load(&xas);	xas_init_marks(&xas);	xas_unlock(&xas);	XA_BUG_ON(xa, !xa_get_mark(xa, 0, XA_MARK_0) == 0); 	for (index = 3500; index < 4500; index++) {		xa_store_index(xa, index, GFP_KERNEL);		xa_set_mark(xa, index, XA_MARK_0);	} 	xas_reset(&xas);	rcu_read_lock();	xas_for_each_marked(&xas, entry, ULONG_MAX, XA_MARK_0)		count++;	rcu_read_unlock();	XA_BUG_ON(xa, count != 1000); 	xas_lock(&xas);	xas_for_each(&xas, entry, ULONG_MAX) {		xas_init_marks(&xas);		XA_BUG_ON(xa, !xa_get_mark(xa, xas.xa_index, XA_MARK_0));		XA_BUG_ON(xa, !xas_get_mark(&xas, XA_MARK_0));	}	xas_unlock(&xas); 	xa_destroy(xa);} static noinline void check_xa_mark_3(struct xarray *xa){#ifdef CONFIG_XARRAY_MULTI	XA_STATE(xas, xa, 0x41);	void *entry;	int count = 0; 	xa_store_order(xa, 0x40, 2, xa_mk_index(0x40), GFP_KERNEL);	xa_set_mark(xa, 0x41, XA_MARK_0); 	rcu_read_lock();	xas_for_each_marked(&xas, entry, ULONG_MAX, XA_MARK_0) {		count++;		XA_BUG_ON(xa, entry != xa_mk_index(0x40));	}	XA_BUG_ON(xa, count != 1);	rcu_read_unlock();	xa_destroy(xa);#endif} static noinline void check_xa_mark(struct xarray *xa){	unsigned long index; 	for (index = 0; index < 16384; index += 4)		check_xa_mark_1(xa, index); 	check_xa_mark_2(xa);	check_xa_mark_3(xa);} static noinline void check_xa_shrink(struct xarray *xa){	XA_STATE(xas, xa, 1);	struct xa_node *node;	unsigned int order;	unsigned int max_order = IS_ENABLED(CONFIG_XARRAY_MULTI) ? 15 : 1; 	XA_BUG_ON(xa, !xa_empty(xa));	XA_BUG_ON(xa, xa_store_index(xa, 0, GFP_KERNEL) != NULL);	XA_BUG_ON(xa, xa_store_index(xa, 1, GFP_KERNEL) != NULL); 	/*	 * Check that erasing the entry at 1 shrinks the tree and properly	 * marks the node as being deleted.	 */	xas_lock(&xas);	XA_BUG_ON(xa, xas_load(&xas) != xa_mk_value(1));	node = xas.xa_node;	XA_BUG_ON(xa, xa_entry_locked(xa, node, 0) != xa_mk_value(0));	XA_BUG_ON(xa, xas_store(&xas, NULL) != xa_mk_value(1));	XA_BUG_ON(xa, xa_load(xa, 1) != NULL);	XA_BUG_ON(xa, xas.xa_node != XAS_BOUNDS);	XA_BUG_ON(xa, xa_entry_locked(xa, node, 0) != XA_RETRY_ENTRY);	XA_BUG_ON(xa, xas_load(&xas) != NULL);	xas_unlock(&xas);	XA_BUG_ON(xa, xa_load(xa, 0) != xa_mk_value(0));	xa_erase_index(xa, 0);	XA_BUG_ON(xa, !xa_empty(xa)); 	for (order = 0; order < max_order; order++) {		unsigned long max = (1UL << order) - 1;		xa_store_order(xa, 0, order, xa_mk_value(0), GFP_KERNEL);		XA_BUG_ON(xa, xa_load(xa, max) != xa_mk_value(0));		XA_BUG_ON(xa, xa_load(xa, max + 1) != NULL);		rcu_read_lock();		node = xa_head(xa);		rcu_read_unlock();		XA_BUG_ON(xa, xa_store_index(xa, ULONG_MAX, GFP_KERNEL) !=				NULL);		rcu_read_lock();		XA_BUG_ON(xa, xa_head(xa) == node);		rcu_read_unlock();		XA_BUG_ON(xa, xa_load(xa, max + 1) != NULL);		xa_erase_index(xa, ULONG_MAX);		XA_BUG_ON(xa, xa->xa_head != node);		xa_erase_index(xa, 0);	}} 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);	void *SIX = xa_mk_value(6);	void *LOTS = xa_mk_value(12345678); 	XA_BUG_ON(xa, !xa_empty(xa));	XA_BUG_ON(xa, xa_store_index(xa, 12345678, GFP_KERNEL) != NULL);	XA_BUG_ON(xa, xa_insert(xa, 12345678, xa, GFP_KERNEL) != -EBUSY);	XA_BUG_ON(xa, xa_cmpxchg(xa, 12345678, SIX, FIVE, GFP_KERNEL) != LOTS);	XA_BUG_ON(xa, xa_cmpxchg(xa, 12345678, LOTS, FIVE, GFP_KERNEL) != LOTS);	XA_BUG_ON(xa, xa_cmpxchg(xa, 12345678, FIVE, LOTS, GFP_KERNEL) != FIVE);	XA_BUG_ON(xa, xa_cmpxchg(xa, 5, FIVE, NULL, GFP_KERNEL) != NULL);	XA_BUG_ON(xa, xa_cmpxchg(xa, 5, NULL, FIVE, GFP_KERNEL) != NULL);	XA_BUG_ON(xa, xa_insert(xa, 5, FIVE, GFP_KERNEL) != -EBUSY);	XA_BUG_ON(xa, xa_cmpxchg(xa, 5, FIVE, NULL, GFP_KERNEL) != FIVE);	XA_BUG_ON(xa, xa_insert(xa, 5, FIVE, GFP_KERNEL) == -EBUSY);	xa_erase_index(xa, 12345678);	xa_erase_index(xa, 5);	XA_BUG_ON(xa, !xa_empty(xa));} static noinline void check_cmpxchg_order(struct xarray *xa){#ifdef CONFIG_XARRAY_MULTI	void *FIVE = xa_mk_value(5);	unsigned int i, order = 3; 	XA_BUG_ON(xa, xa_store_order(xa, 0, order, FIVE, GFP_KERNEL)); 	/* Check entry FIVE has the order saved */	XA_BUG_ON(xa, xa_get_order(xa, xa_to_value(FIVE)) != order); 	/* Check all the tied indexes have the same entry and order */	for (i = 0; i < (1 << order); i++) {		XA_BUG_ON(xa, xa_load(xa, i) != FIVE);		XA_BUG_ON(xa, xa_get_order(xa, i) != order);	} 	/* Ensure that nothing is stored at index '1 << order' */	XA_BUG_ON(xa, xa_load(xa, 1 << order) != NULL); 	/*	 * Additionally, keep the node information and the order at	 * '1 << order'	 */	XA_BUG_ON(xa, xa_store_order(xa, 1 << order, order, FIVE, GFP_KERNEL));	for (i = (1 << order); i < (1 << order) + (1 << order) - 1; i++) {		XA_BUG_ON(xa, xa_load(xa, i) != FIVE);		XA_BUG_ON(xa, xa_get_order(xa, i) != order);	} 	/* Conditionally replace FIVE entry at index '0' with NULL */	XA_BUG_ON(xa, xa_cmpxchg(xa, 0, FIVE, NULL, GFP_KERNEL) != FIVE); 	/* Verify the order is lost at FIVE (and old) entries */	XA_BUG_ON(xa, xa_get_order(xa, xa_to_value(FIVE)) != 0); 	/* Verify the order and entries are lost in all the tied indexes */	for (i = 0; i < (1 << order); i++) {		XA_BUG_ON(xa, xa_load(xa, i) != NULL);		XA_BUG_ON(xa, xa_get_order(xa, i) != 0);	} 	/* Verify node and order are kept at '1 << order' */	for (i = (1 << order); i < (1 << order) + (1 << order) - 1; i++) {		XA_BUG_ON(xa, xa_load(xa, i) != FIVE);		XA_BUG_ON(xa, xa_get_order(xa, i) != order);	} 	xa_store_order(xa, 0, BITS_PER_LONG - 1, NULL, GFP_KERNEL);	XA_BUG_ON(xa, !xa_empty(xa));#endif} static noinline void check_reserve(struct xarray *xa){	void *entry;	unsigned long index;	int count; 	/* An array with a reserved entry is not empty */	XA_BUG_ON(xa, !xa_empty(xa));	XA_BUG_ON(xa, xa_reserve(xa, 12345678, GFP_KERNEL) != 0);	XA_BUG_ON(xa, xa_empty(xa));	XA_BUG_ON(xa, xa_load(xa, 12345678));	xa_release(xa, 12345678);	XA_BUG_ON(xa, !xa_empty(xa)); 	/* Releasing a used entry does nothing */	XA_BUG_ON(xa, xa_reserve(xa, 12345678, GFP_KERNEL) != 0);	XA_BUG_ON(xa, xa_store_index(xa, 12345678, GFP_NOWAIT) != NULL);	xa_release(xa, 12345678);	xa_erase_index(xa, 12345678);	XA_BUG_ON(xa, !xa_empty(xa)); 	/* cmpxchg sees a reserved entry as ZERO */

Lines 1–500 of 2278.