2278 lines · 59.2 KB · C
RawDownload
	XA_BUG_ON(xa, xa_reserve(xa, 12345678, GFP_KERNEL) != 0);	XA_BUG_ON(xa, xa_cmpxchg(xa, 12345678, XA_ZERO_ENTRY,				xa_mk_value(12345678), GFP_NOWAIT) != NULL);	xa_release(xa, 12345678);	xa_erase_index(xa, 12345678);	XA_BUG_ON(xa, !xa_empty(xa)); 	/* xa_insert treats it as busy */	XA_BUG_ON(xa, xa_reserve(xa, 12345678, GFP_KERNEL) != 0);	XA_BUG_ON(xa, xa_insert(xa, 12345678, xa_mk_value(12345678), 0) !=			-EBUSY);	XA_BUG_ON(xa, xa_empty(xa));	XA_BUG_ON(xa, xa_erase(xa, 12345678) != NULL);	XA_BUG_ON(xa, !xa_empty(xa)); 	/* Can iterate through a reserved entry */	xa_store_index(xa, 5, GFP_KERNEL);	XA_BUG_ON(xa, xa_reserve(xa, 6, GFP_KERNEL) != 0);	xa_store_index(xa, 7, GFP_KERNEL); 	count = 0;	xa_for_each(xa, index, entry) {		XA_BUG_ON(xa, index != 5 && index != 7);		count++;	}	XA_BUG_ON(xa, count != 2); 	/* If we free a reserved entry, we should be able to allocate it */	if (xa->xa_flags & XA_FLAGS_ALLOC) {		u32 id; 		XA_BUG_ON(xa, xa_alloc(xa, &id, xa_mk_value(8),					XA_LIMIT(5, 10), GFP_KERNEL) != 0);		XA_BUG_ON(xa, id != 8); 		xa_release(xa, 6);		XA_BUG_ON(xa, xa_alloc(xa, &id, xa_mk_value(6),					XA_LIMIT(5, 10), GFP_KERNEL) != 0);		XA_BUG_ON(xa, id != 6);	} 	xa_destroy(xa);} static noinline void check_xas_erase(struct xarray *xa){	XA_STATE(xas, xa, 0);	void *entry;	unsigned long i, j; 	for (i = 0; i < 200; i++) {		for (j = i; j < 2 * i + 17; j++) {			xas_set(&xas, j);			do {				xas_lock(&xas);				xas_store(&xas, xa_mk_index(j));				xas_unlock(&xas);			} while (xas_nomem(&xas, GFP_KERNEL));		} 		xas_set(&xas, ULONG_MAX);		do {			xas_lock(&xas);			xas_store(&xas, xa_mk_value(0));			xas_unlock(&xas);		} while (xas_nomem(&xas, GFP_KERNEL)); 		xas_lock(&xas);		xas_store(&xas, NULL); 		xas_set(&xas, 0);		j = i;		xas_for_each(&xas, entry, ULONG_MAX) {			XA_BUG_ON(xa, entry != xa_mk_index(j));			xas_store(&xas, NULL);			j++;		}		xas_unlock(&xas);		XA_BUG_ON(xa, !xa_empty(xa));	}} #ifdef CONFIG_XARRAY_MULTIstatic noinline void check_multi_store_1(struct xarray *xa, unsigned long index,		unsigned int order){	XA_STATE(xas, xa, index);	unsigned long min = index & ~((1UL << order) - 1);	unsigned long max = min + (1UL << order); 	xa_store_order(xa, index, order, xa_mk_index(index), GFP_KERNEL);	XA_BUG_ON(xa, xa_load(xa, min) != xa_mk_index(index));	XA_BUG_ON(xa, xa_load(xa, max - 1) != xa_mk_index(index));	XA_BUG_ON(xa, xa_load(xa, max) != NULL);	XA_BUG_ON(xa, xa_load(xa, min - 1) != NULL); 	xas_lock(&xas);	XA_BUG_ON(xa, xas_store(&xas, xa_mk_index(min)) != xa_mk_index(index));	xas_unlock(&xas);	XA_BUG_ON(xa, xa_load(xa, min) != xa_mk_index(min));	XA_BUG_ON(xa, xa_load(xa, max - 1) != xa_mk_index(min));	XA_BUG_ON(xa, xa_load(xa, max) != NULL);	XA_BUG_ON(xa, xa_load(xa, min - 1) != NULL); 	xa_erase_index(xa, min);	XA_BUG_ON(xa, !xa_empty(xa));} static noinline void check_multi_store_2(struct xarray *xa, unsigned long index,		unsigned int order){	XA_STATE(xas, xa, index);	xa_store_order(xa, index, order, xa_mk_value(0), GFP_KERNEL); 	xas_lock(&xas);	XA_BUG_ON(xa, xas_store(&xas, xa_mk_value(1)) != xa_mk_value(0));	XA_BUG_ON(xa, xas.xa_index != index);	XA_BUG_ON(xa, xas_store(&xas, NULL) != xa_mk_value(1));	xas_unlock(&xas);	XA_BUG_ON(xa, !xa_empty(xa));} static noinline void check_multi_store_3(struct xarray *xa, unsigned long index,		unsigned int order){	XA_STATE(xas, xa, 0);	void *entry;	int n = 0; 	xa_store_order(xa, index, order, xa_mk_index(index), GFP_KERNEL); 	xas_lock(&xas);	xas_for_each(&xas, entry, ULONG_MAX) {		XA_BUG_ON(xa, entry != xa_mk_index(index));		n++;	}	XA_BUG_ON(xa, n != 1);	xas_set(&xas, index + 1);	xas_for_each(&xas, entry, ULONG_MAX) {		XA_BUG_ON(xa, entry != xa_mk_index(index));		n++;	}	XA_BUG_ON(xa, n != 2);	xas_unlock(&xas); 	xa_destroy(xa);}#endif static noinline void check_multi_store(struct xarray *xa){#ifdef CONFIG_XARRAY_MULTI	unsigned long i, j, k;	unsigned int max_order = (sizeof(long) == 4) ? 30 : 60; 	/* Loading from any position returns the same value */	xa_store_order(xa, 0, 1, xa_mk_value(0), GFP_KERNEL);	XA_BUG_ON(xa, xa_load(xa, 0) != xa_mk_value(0));	XA_BUG_ON(xa, xa_load(xa, 1) != xa_mk_value(0));	XA_BUG_ON(xa, xa_load(xa, 2) != NULL);	rcu_read_lock();	XA_BUG_ON(xa, xa_to_node(xa_head(xa))->count != 2);	XA_BUG_ON(xa, xa_to_node(xa_head(xa))->nr_values != 2);	rcu_read_unlock(); 	/* Storing adjacent to the value does not alter the value */	xa_store(xa, 3, xa, GFP_KERNEL);	XA_BUG_ON(xa, xa_load(xa, 0) != xa_mk_value(0));	XA_BUG_ON(xa, xa_load(xa, 1) != xa_mk_value(0));	XA_BUG_ON(xa, xa_load(xa, 2) != NULL);	rcu_read_lock();	XA_BUG_ON(xa, xa_to_node(xa_head(xa))->count != 3);	XA_BUG_ON(xa, xa_to_node(xa_head(xa))->nr_values != 2);	rcu_read_unlock(); 	/* Overwriting multiple indexes works */	xa_store_order(xa, 0, 2, xa_mk_value(1), GFP_KERNEL);	XA_BUG_ON(xa, xa_load(xa, 0) != xa_mk_value(1));	XA_BUG_ON(xa, xa_load(xa, 1) != xa_mk_value(1));	XA_BUG_ON(xa, xa_load(xa, 2) != xa_mk_value(1));	XA_BUG_ON(xa, xa_load(xa, 3) != xa_mk_value(1));	XA_BUG_ON(xa, xa_load(xa, 4) != NULL);	rcu_read_lock();	XA_BUG_ON(xa, xa_to_node(xa_head(xa))->count != 4);	XA_BUG_ON(xa, xa_to_node(xa_head(xa))->nr_values != 4);	rcu_read_unlock(); 	/* We can erase multiple values with a single store */	xa_store_order(xa, 0, BITS_PER_LONG - 1, NULL, GFP_KERNEL);	XA_BUG_ON(xa, !xa_empty(xa)); 	/* Even when the first slot is empty but the others aren't */	xa_store_index(xa, 1, GFP_KERNEL);	xa_store_index(xa, 2, GFP_KERNEL);	xa_store_order(xa, 0, 2, NULL, GFP_KERNEL);	XA_BUG_ON(xa, !xa_empty(xa)); 	for (i = 0; i < max_order; i++) {		for (j = 0; j < max_order; j++) {			xa_store_order(xa, 0, i, xa_mk_index(i), GFP_KERNEL);			xa_store_order(xa, 0, j, xa_mk_index(j), GFP_KERNEL); 			for (k = 0; k < max_order; k++) {				void *entry = xa_load(xa, (1UL << k) - 1);				if ((i < k) && (j < k))					XA_BUG_ON(xa, entry != NULL);				else					XA_BUG_ON(xa, entry != xa_mk_index(j));			} 			xa_erase(xa, 0);			XA_BUG_ON(xa, !xa_empty(xa));		}	} 	for (i = 0; i < 20; i++) {		check_multi_store_1(xa, 200, i);		check_multi_store_1(xa, 0, i);		check_multi_store_1(xa, (1UL << i) + 1, i);	}	check_multi_store_2(xa, 4095, 9); 	for (i = 1; i < 20; i++) {		check_multi_store_3(xa, 0, i);		check_multi_store_3(xa, 1UL << i, i);	}#endif} #ifdef CONFIG_XARRAY_MULTI/* mimics page cache __filemap_add_folio() */static noinline void check_xa_multi_store_adv_add(struct xarray *xa,						  unsigned long index,						  unsigned int order,						  void *p){	XA_STATE(xas, xa, index);	unsigned int nrpages = 1UL << order; 	/* users are responsible for index alignemnt to the order when adding */	XA_BUG_ON(xa, index & (nrpages - 1)); 	xas_set_order(&xas, index, order); 	do {		xas_lock_irq(&xas);		xas_store(&xas, p);		xas_unlock_irq(&xas);		/*		 * In our selftest case the only failure we can expect is for		 * there not to be enough memory as we're not mimicking the		 * entire page cache, so verify that's the only error we can run		 * into here. The xas_nomem() which follows will ensure to fix		 * that condition for us so to chug on on the loop.		 */		XA_BUG_ON(xa, xas_error(&xas) && xas_error(&xas) != -ENOMEM);	} while (xas_nomem(&xas, GFP_KERNEL)); 	XA_BUG_ON(xa, xas_error(&xas));	XA_BUG_ON(xa, xa_load(xa, index) != p);} /* mimics page_cache_delete() */static noinline void check_xa_multi_store_adv_del_entry(struct xarray *xa,							unsigned long index,							unsigned int order){	XA_STATE(xas, xa, index); 	xas_set_order(&xas, index, order);	xas_store(&xas, NULL);	xas_init_marks(&xas);} static noinline void check_xa_multi_store_adv_delete(struct xarray *xa,						     unsigned long index,						     unsigned int order){	xa_lock_irq(xa);	check_xa_multi_store_adv_del_entry(xa, index, order);	xa_unlock_irq(xa);} /* mimics page cache filemap_get_entry() */static noinline void *test_get_entry(struct xarray *xa, unsigned long index){	XA_STATE(xas, xa, index);	void *p;	static unsigned int loops = 0; 	rcu_read_lock();repeat:	xas_reset(&xas);	p = xas_load(&xas);	if (xas_retry(&xas, p))		goto repeat;	rcu_read_unlock(); 	/*	 * This is not part of the page cache, this selftest is pretty	 * aggressive and does not want to trust the xarray API but rather	 * test it, and for order 20 (4 GiB block size) we can loop over	 * over a million entries which can cause a soft lockup. Page cache	 * APIs won't be stupid, proper page cache APIs loop over the proper	 * order so when using a larger order we skip shared entries.	 */	if (++loops % XA_CHECK_SCHED == 0)		schedule(); 	return p;} static unsigned long some_val = 0xdeadbeef;static unsigned long some_val_2 = 0xdeaddead; /* mimics the page cache usage */static noinline void check_xa_multi_store_adv(struct xarray *xa,					      unsigned long pos,					      unsigned int order){	unsigned int nrpages = 1UL << order;	unsigned long index, base, next_index, next_next_index;	unsigned int i; 	index = pos >> PAGE_SHIFT;	base = round_down(index, nrpages);	next_index = round_down(base + nrpages, nrpages);	next_next_index = round_down(next_index + nrpages, nrpages); 	check_xa_multi_store_adv_add(xa, base, order, &some_val); 	for (i = 0; i < nrpages; i++)		XA_BUG_ON(xa, test_get_entry(xa, base + i) != &some_val); 	XA_BUG_ON(xa, test_get_entry(xa, next_index) != NULL); 	/* Use order 0 for the next item */	check_xa_multi_store_adv_add(xa, next_index, 0, &some_val_2);	XA_BUG_ON(xa, test_get_entry(xa, next_index) != &some_val_2); 	/* Remove the next item */	check_xa_multi_store_adv_delete(xa, next_index, 0); 	/* Now use order for a new pointer */	check_xa_multi_store_adv_add(xa, next_index, order, &some_val_2); 	for (i = 0; i < nrpages; i++)		XA_BUG_ON(xa, test_get_entry(xa, next_index + i) != &some_val_2); 	check_xa_multi_store_adv_delete(xa, next_index, order);	check_xa_multi_store_adv_delete(xa, base, order);	XA_BUG_ON(xa, !xa_empty(xa)); 	/* starting fresh again */ 	/* let's test some holes now */ 	/* hole at base and next_next */	check_xa_multi_store_adv_add(xa, next_index, order, &some_val_2); 	for (i = 0; i < nrpages; i++)		XA_BUG_ON(xa, test_get_entry(xa, base + i) != NULL); 	for (i = 0; i < nrpages; i++)		XA_BUG_ON(xa, test_get_entry(xa, next_index + i) != &some_val_2); 	for (i = 0; i < nrpages; i++)		XA_BUG_ON(xa, test_get_entry(xa, next_next_index + i) != NULL); 	check_xa_multi_store_adv_delete(xa, next_index, order);	XA_BUG_ON(xa, !xa_empty(xa)); 	/* hole at base and next */ 	check_xa_multi_store_adv_add(xa, next_next_index, order, &some_val_2); 	for (i = 0; i < nrpages; i++)		XA_BUG_ON(xa, test_get_entry(xa, base + i) != NULL); 	for (i = 0; i < nrpages; i++)		XA_BUG_ON(xa, test_get_entry(xa, next_index + i) != NULL); 	for (i = 0; i < nrpages; i++)		XA_BUG_ON(xa, test_get_entry(xa, next_next_index + i) != &some_val_2); 	check_xa_multi_store_adv_delete(xa, next_next_index, order);	XA_BUG_ON(xa, !xa_empty(xa));}#endif static noinline void check_multi_store_advanced(struct xarray *xa){#ifdef CONFIG_XARRAY_MULTI	unsigned int max_order = IS_ENABLED(CONFIG_XARRAY_MULTI) ? 20 : 1;	unsigned long end = ULONG_MAX/2;	unsigned long pos, i; 	/*	 * About 117 million tests below.	 */	for (pos = 7; pos < end; pos = (pos * pos) + 564) {		for (i = 0; i < max_order; i++) {			check_xa_multi_store_adv(xa, pos, i);			check_xa_multi_store_adv(xa, pos + 157, i);		}	}#endif} static noinline void check_xa_alloc_1(struct xarray *xa, unsigned int base){	int i;	u32 id; 	XA_BUG_ON(xa, !xa_empty(xa));	/* An empty array should assign %base to the first alloc */	xa_alloc_index(xa, base, GFP_KERNEL); 	/* Erasing it should make the array empty again */	xa_erase_index(xa, base);	XA_BUG_ON(xa, !xa_empty(xa)); 	/* And it should assign %base again */	xa_alloc_index(xa, base, GFP_KERNEL); 	/* Allocating and then erasing a lot should not lose base */	for (i = base + 1; i < 2 * XA_CHUNK_SIZE; i++)		xa_alloc_index(xa, i, GFP_KERNEL);	for (i = base; i < 2 * XA_CHUNK_SIZE; i++)		xa_erase_index(xa, i);	xa_alloc_index(xa, base, GFP_KERNEL); 	/* Destroying the array should do the same as erasing */	xa_destroy(xa); 	/* And it should assign %base again */	xa_alloc_index(xa, base, GFP_KERNEL); 	/* The next assigned ID should be base+1 */	xa_alloc_index(xa, base + 1, GFP_KERNEL);	xa_erase_index(xa, base + 1); 	/* Storing a value should mark it used */	xa_store_index(xa, base + 1, GFP_KERNEL);	xa_alloc_index(xa, base + 2, GFP_KERNEL); 	/* If we then erase base, it should be free */	xa_erase_index(xa, base);	xa_alloc_index(xa, base, GFP_KERNEL); 	xa_erase_index(xa, base + 1);	xa_erase_index(xa, base + 2); 	for (i = 1; i < 5000; i++) {		xa_alloc_index(xa, base + i, GFP_KERNEL);	} 	xa_destroy(xa); 	/* Check that we fail properly at the limit of allocation */	XA_BUG_ON(xa, xa_alloc(xa, &id, xa_mk_index(UINT_MAX - 1),				XA_LIMIT(UINT_MAX - 1, UINT_MAX),				GFP_KERNEL) != 0);	XA_BUG_ON(xa, id != 0xfffffffeU);	XA_BUG_ON(xa, xa_alloc(xa, &id, xa_mk_index(UINT_MAX),				XA_LIMIT(UINT_MAX - 1, UINT_MAX),				GFP_KERNEL) != 0);	XA_BUG_ON(xa, id != 0xffffffffU);	id = 3;	XA_BUG_ON(xa, xa_alloc(xa, &id, xa_mk_index(0),				XA_LIMIT(UINT_MAX - 1, UINT_MAX),				GFP_KERNEL) != -EBUSY);	XA_BUG_ON(xa, id != 3);	xa_destroy(xa); 	XA_BUG_ON(xa, xa_alloc(xa, &id, xa_mk_index(10), XA_LIMIT(10, 5),				GFP_KERNEL) != -EBUSY);	XA_BUG_ON(xa, xa_store_index(xa, 3, GFP_KERNEL) != 0);	XA_BUG_ON(xa, xa_alloc(xa, &id, xa_mk_index(10), XA_LIMIT(10, 5),				GFP_KERNEL) != -EBUSY);	xa_erase_index(xa, 3);	XA_BUG_ON(xa, !xa_empty(xa));} static noinline void check_xa_alloc_2(struct xarray *xa, unsigned int base){	unsigned int i, id;	unsigned long index;	void *entry; 	/* Allocate and free a NULL and check xa_empty() behaves */	XA_BUG_ON(xa, !xa_empty(xa));	XA_BUG_ON(xa, xa_alloc(xa, &id, NULL, xa_limit_32b, GFP_KERNEL) != 0);	XA_BUG_ON(xa, id != base);	XA_BUG_ON(xa, xa_empty(xa));	XA_BUG_ON(xa, xa_erase(xa, id) != NULL);	XA_BUG_ON(xa, !xa_empty(xa)); 	/* Ditto, but check destroy instead of erase */	XA_BUG_ON(xa, !xa_empty(xa));

Lines 501–1000 of 2278. Previous lines