1ad3d6c72SMatthew Wilcox // SPDX-License-Identifier: GPL-2.0+ 2ad3d6c72SMatthew Wilcox /* 3ad3d6c72SMatthew Wilcox * test_xarray.c: Test the XArray API 4ad3d6c72SMatthew Wilcox * Copyright (c) 2017-2018 Microsoft Corporation 5ad3d6c72SMatthew Wilcox * Author: Matthew Wilcox <[email protected]> 6ad3d6c72SMatthew Wilcox */ 7ad3d6c72SMatthew Wilcox 8ad3d6c72SMatthew Wilcox #include <linux/xarray.h> 9ad3d6c72SMatthew Wilcox #include <linux/module.h> 10ad3d6c72SMatthew Wilcox 11ad3d6c72SMatthew Wilcox static unsigned int tests_run; 12ad3d6c72SMatthew Wilcox static unsigned int tests_passed; 13ad3d6c72SMatthew Wilcox 14ad3d6c72SMatthew Wilcox #ifndef XA_DEBUG 15ad3d6c72SMatthew Wilcox # ifdef __KERNEL__ 16ad3d6c72SMatthew Wilcox void xa_dump(const struct xarray *xa) { } 17ad3d6c72SMatthew Wilcox # endif 18ad3d6c72SMatthew Wilcox #undef XA_BUG_ON 19ad3d6c72SMatthew Wilcox #define XA_BUG_ON(xa, x) do { \ 20ad3d6c72SMatthew Wilcox tests_run++; \ 21ad3d6c72SMatthew Wilcox if (x) { \ 22ad3d6c72SMatthew Wilcox printk("BUG at %s:%d\n", __func__, __LINE__); \ 23ad3d6c72SMatthew Wilcox xa_dump(xa); \ 24ad3d6c72SMatthew Wilcox dump_stack(); \ 25ad3d6c72SMatthew Wilcox } else { \ 26ad3d6c72SMatthew Wilcox tests_passed++; \ 27ad3d6c72SMatthew Wilcox } \ 28ad3d6c72SMatthew Wilcox } while (0) 29ad3d6c72SMatthew Wilcox #endif 30ad3d6c72SMatthew Wilcox 31ad3d6c72SMatthew Wilcox static void *xa_store_index(struct xarray *xa, unsigned long index, gfp_t gfp) 32ad3d6c72SMatthew Wilcox { 3358d6ea30SMatthew Wilcox return xa_store(xa, index, xa_mk_value(index & LONG_MAX), gfp); 34ad3d6c72SMatthew Wilcox } 35ad3d6c72SMatthew Wilcox 36*371c752dSMatthew Wilcox static void xa_alloc_index(struct xarray *xa, unsigned long index, gfp_t gfp) 37*371c752dSMatthew Wilcox { 38*371c752dSMatthew Wilcox u32 id = 0; 39*371c752dSMatthew Wilcox 40*371c752dSMatthew Wilcox XA_BUG_ON(xa, xa_alloc(xa, &id, UINT_MAX, xa_mk_value(index & LONG_MAX), 41*371c752dSMatthew Wilcox gfp) != 0); 42*371c752dSMatthew Wilcox XA_BUG_ON(xa, id != index); 43*371c752dSMatthew Wilcox } 44*371c752dSMatthew Wilcox 45ad3d6c72SMatthew Wilcox static void xa_erase_index(struct xarray *xa, unsigned long index) 46ad3d6c72SMatthew Wilcox { 4758d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_erase(xa, index) != xa_mk_value(index & LONG_MAX)); 4858d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_load(xa, index) != NULL); 4958d6ea30SMatthew Wilcox } 5058d6ea30SMatthew Wilcox 5158d6ea30SMatthew Wilcox /* 5258d6ea30SMatthew Wilcox * If anyone needs this, please move it to xarray.c. We have no current 5358d6ea30SMatthew Wilcox * users outside the test suite because all current multislot users want 5458d6ea30SMatthew Wilcox * to use the advanced API. 5558d6ea30SMatthew Wilcox */ 5658d6ea30SMatthew Wilcox static void *xa_store_order(struct xarray *xa, unsigned long index, 5758d6ea30SMatthew Wilcox unsigned order, void *entry, gfp_t gfp) 5858d6ea30SMatthew Wilcox { 5958d6ea30SMatthew Wilcox XA_STATE_ORDER(xas, xa, index, order); 6058d6ea30SMatthew Wilcox void *curr; 6158d6ea30SMatthew Wilcox 6258d6ea30SMatthew Wilcox do { 6358d6ea30SMatthew Wilcox xas_lock(&xas); 6458d6ea30SMatthew Wilcox curr = xas_store(&xas, entry); 6558d6ea30SMatthew Wilcox xas_unlock(&xas); 6658d6ea30SMatthew Wilcox } while (xas_nomem(&xas, gfp)); 6758d6ea30SMatthew Wilcox 6858d6ea30SMatthew Wilcox return curr; 6958d6ea30SMatthew Wilcox } 7058d6ea30SMatthew Wilcox 7158d6ea30SMatthew Wilcox static noinline void check_xa_err(struct xarray *xa) 7258d6ea30SMatthew Wilcox { 7358d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_err(xa_store_index(xa, 0, GFP_NOWAIT)) != 0); 7458d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_err(xa_erase(xa, 0)) != 0); 7558d6ea30SMatthew Wilcox #ifndef __KERNEL__ 7658d6ea30SMatthew Wilcox /* The kernel does not fail GFP_NOWAIT allocations */ 7758d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_err(xa_store_index(xa, 1, GFP_NOWAIT)) != -ENOMEM); 7858d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_err(xa_store_index(xa, 1, GFP_NOWAIT)) != -ENOMEM); 7958d6ea30SMatthew Wilcox #endif 8058d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_err(xa_store_index(xa, 1, GFP_KERNEL)) != 0); 8158d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_err(xa_store(xa, 1, xa_mk_value(0), GFP_KERNEL)) != 0); 8258d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_err(xa_erase(xa, 1)) != 0); 8358d6ea30SMatthew Wilcox // kills the test-suite :-( 8458d6ea30SMatthew Wilcox // XA_BUG_ON(xa, xa_err(xa_store(xa, 0, xa_mk_internal(0), 0)) != -EINVAL); 85ad3d6c72SMatthew Wilcox } 86ad3d6c72SMatthew Wilcox 87b803b428SMatthew Wilcox static noinline void check_xas_retry(struct xarray *xa) 88b803b428SMatthew Wilcox { 89b803b428SMatthew Wilcox XA_STATE(xas, xa, 0); 90b803b428SMatthew Wilcox void *entry; 91b803b428SMatthew Wilcox 92b803b428SMatthew Wilcox xa_store_index(xa, 0, GFP_KERNEL); 93b803b428SMatthew Wilcox xa_store_index(xa, 1, GFP_KERNEL); 94b803b428SMatthew Wilcox 95b803b428SMatthew Wilcox rcu_read_lock(); 96b803b428SMatthew Wilcox XA_BUG_ON(xa, xas_find(&xas, ULONG_MAX) != xa_mk_value(0)); 97b803b428SMatthew Wilcox xa_erase_index(xa, 1); 98b803b428SMatthew Wilcox XA_BUG_ON(xa, !xa_is_retry(xas_reload(&xas))); 99b803b428SMatthew Wilcox XA_BUG_ON(xa, xas_retry(&xas, NULL)); 100b803b428SMatthew Wilcox XA_BUG_ON(xa, xas_retry(&xas, xa_mk_value(0))); 101b803b428SMatthew Wilcox xas_reset(&xas); 102b803b428SMatthew Wilcox XA_BUG_ON(xa, xas.xa_node != XAS_RESTART); 103b803b428SMatthew Wilcox XA_BUG_ON(xa, xas_next_entry(&xas, ULONG_MAX) != xa_mk_value(0)); 104b803b428SMatthew Wilcox XA_BUG_ON(xa, xas.xa_node != NULL); 105b803b428SMatthew Wilcox 106b803b428SMatthew Wilcox XA_BUG_ON(xa, xa_store_index(xa, 1, GFP_KERNEL) != NULL); 107b803b428SMatthew Wilcox XA_BUG_ON(xa, !xa_is_internal(xas_reload(&xas))); 108b803b428SMatthew Wilcox xas.xa_node = XAS_RESTART; 109b803b428SMatthew Wilcox XA_BUG_ON(xa, xas_next_entry(&xas, ULONG_MAX) != xa_mk_value(0)); 110b803b428SMatthew Wilcox rcu_read_unlock(); 111b803b428SMatthew Wilcox 112b803b428SMatthew Wilcox /* Make sure we can iterate through retry entries */ 113b803b428SMatthew Wilcox xas_lock(&xas); 114b803b428SMatthew Wilcox xas_set(&xas, 0); 115b803b428SMatthew Wilcox xas_store(&xas, XA_RETRY_ENTRY); 116b803b428SMatthew Wilcox xas_set(&xas, 1); 117b803b428SMatthew Wilcox xas_store(&xas, XA_RETRY_ENTRY); 118b803b428SMatthew Wilcox 119b803b428SMatthew Wilcox xas_set(&xas, 0); 120b803b428SMatthew Wilcox xas_for_each(&xas, entry, ULONG_MAX) { 121b803b428SMatthew Wilcox xas_store(&xas, xa_mk_value(xas.xa_index)); 122b803b428SMatthew Wilcox } 123b803b428SMatthew Wilcox xas_unlock(&xas); 124b803b428SMatthew Wilcox 125b803b428SMatthew Wilcox xa_erase_index(xa, 0); 126b803b428SMatthew Wilcox xa_erase_index(xa, 1); 127b803b428SMatthew Wilcox } 128b803b428SMatthew Wilcox 129ad3d6c72SMatthew Wilcox static noinline void check_xa_load(struct xarray *xa) 130ad3d6c72SMatthew Wilcox { 131ad3d6c72SMatthew Wilcox unsigned long i, j; 132ad3d6c72SMatthew Wilcox 133ad3d6c72SMatthew Wilcox for (i = 0; i < 1024; i++) { 134ad3d6c72SMatthew Wilcox for (j = 0; j < 1024; j++) { 135ad3d6c72SMatthew Wilcox void *entry = xa_load(xa, j); 136ad3d6c72SMatthew Wilcox if (j < i) 137ad3d6c72SMatthew Wilcox XA_BUG_ON(xa, xa_to_value(entry) != j); 138ad3d6c72SMatthew Wilcox else 139ad3d6c72SMatthew Wilcox XA_BUG_ON(xa, entry); 140ad3d6c72SMatthew Wilcox } 141ad3d6c72SMatthew Wilcox XA_BUG_ON(xa, xa_store_index(xa, i, GFP_KERNEL) != NULL); 142ad3d6c72SMatthew Wilcox } 143ad3d6c72SMatthew Wilcox 144ad3d6c72SMatthew Wilcox for (i = 0; i < 1024; i++) { 145ad3d6c72SMatthew Wilcox for (j = 0; j < 1024; j++) { 146ad3d6c72SMatthew Wilcox void *entry = xa_load(xa, j); 147ad3d6c72SMatthew Wilcox if (j >= i) 148ad3d6c72SMatthew Wilcox XA_BUG_ON(xa, xa_to_value(entry) != j); 149ad3d6c72SMatthew Wilcox else 150ad3d6c72SMatthew Wilcox XA_BUG_ON(xa, entry); 151ad3d6c72SMatthew Wilcox } 152ad3d6c72SMatthew Wilcox xa_erase_index(xa, i); 153ad3d6c72SMatthew Wilcox } 154ad3d6c72SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 155ad3d6c72SMatthew Wilcox } 156ad3d6c72SMatthew Wilcox 1579b89a035SMatthew Wilcox static noinline void check_xa_mark_1(struct xarray *xa, unsigned long index) 1589b89a035SMatthew Wilcox { 15958d6ea30SMatthew Wilcox unsigned int order; 16058d6ea30SMatthew Wilcox unsigned int max_order = IS_ENABLED(CONFIG_XARRAY_MULTI) ? 8 : 1; 16158d6ea30SMatthew Wilcox 1629b89a035SMatthew Wilcox /* NULL elements have no marks set */ 1639b89a035SMatthew Wilcox XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0)); 1649b89a035SMatthew Wilcox xa_set_mark(xa, index, XA_MARK_0); 1659b89a035SMatthew Wilcox XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0)); 1669b89a035SMatthew Wilcox 1679b89a035SMatthew Wilcox /* Storing a pointer will not make a mark appear */ 1689b89a035SMatthew Wilcox XA_BUG_ON(xa, xa_store_index(xa, index, GFP_KERNEL) != NULL); 1699b89a035SMatthew Wilcox XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0)); 1709b89a035SMatthew Wilcox xa_set_mark(xa, index, XA_MARK_0); 1719b89a035SMatthew Wilcox XA_BUG_ON(xa, !xa_get_mark(xa, index, XA_MARK_0)); 1729b89a035SMatthew Wilcox 1739b89a035SMatthew Wilcox /* Setting one mark will not set another mark */ 1749b89a035SMatthew Wilcox XA_BUG_ON(xa, xa_get_mark(xa, index + 1, XA_MARK_0)); 1759b89a035SMatthew Wilcox XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_1)); 1769b89a035SMatthew Wilcox 1779b89a035SMatthew Wilcox /* Storing NULL clears marks, and they can't be set again */ 1789b89a035SMatthew Wilcox xa_erase_index(xa, index); 1799b89a035SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 1809b89a035SMatthew Wilcox XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0)); 1819b89a035SMatthew Wilcox xa_set_mark(xa, index, XA_MARK_0); 1829b89a035SMatthew Wilcox XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0)); 18358d6ea30SMatthew Wilcox 18458d6ea30SMatthew Wilcox /* 18558d6ea30SMatthew Wilcox * Storing a multi-index entry over entries with marks gives the 18658d6ea30SMatthew Wilcox * entire entry the union of the marks 18758d6ea30SMatthew Wilcox */ 18858d6ea30SMatthew Wilcox BUG_ON((index % 4) != 0); 18958d6ea30SMatthew Wilcox for (order = 2; order < max_order; order++) { 19058d6ea30SMatthew Wilcox unsigned long base = round_down(index, 1UL << order); 19158d6ea30SMatthew Wilcox unsigned long next = base + (1UL << order); 19258d6ea30SMatthew Wilcox unsigned long i; 19358d6ea30SMatthew Wilcox 19458d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_store_index(xa, index + 1, GFP_KERNEL)); 19558d6ea30SMatthew Wilcox xa_set_mark(xa, index + 1, XA_MARK_0); 19658d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_store_index(xa, index + 2, GFP_KERNEL)); 19758d6ea30SMatthew Wilcox xa_set_mark(xa, index + 2, XA_MARK_1); 19858d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_store_index(xa, next, GFP_KERNEL)); 19958d6ea30SMatthew Wilcox xa_store_order(xa, index, order, xa_mk_value(index), 20058d6ea30SMatthew Wilcox GFP_KERNEL); 20158d6ea30SMatthew Wilcox for (i = base; i < next; i++) { 20258d6ea30SMatthew Wilcox XA_BUG_ON(xa, !xa_get_mark(xa, i, XA_MARK_0)); 20358d6ea30SMatthew Wilcox XA_BUG_ON(xa, !xa_get_mark(xa, i, XA_MARK_1)); 20458d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_get_mark(xa, i, XA_MARK_2)); 20558d6ea30SMatthew Wilcox } 20658d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_get_mark(xa, next, XA_MARK_0)); 20758d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_get_mark(xa, next, XA_MARK_1)); 20858d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_get_mark(xa, next, XA_MARK_2)); 20958d6ea30SMatthew Wilcox xa_erase_index(xa, index); 21058d6ea30SMatthew Wilcox xa_erase_index(xa, next); 21158d6ea30SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 21258d6ea30SMatthew Wilcox } 21358d6ea30SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 2149b89a035SMatthew Wilcox } 2159b89a035SMatthew Wilcox 2169b89a035SMatthew Wilcox static noinline void check_xa_mark(struct xarray *xa) 2179b89a035SMatthew Wilcox { 2189b89a035SMatthew Wilcox unsigned long index; 2199b89a035SMatthew Wilcox 2209b89a035SMatthew Wilcox for (index = 0; index < 16384; index += 4) 2219b89a035SMatthew Wilcox check_xa_mark_1(xa, index); 2229b89a035SMatthew Wilcox } 2239b89a035SMatthew Wilcox 22458d6ea30SMatthew Wilcox static noinline void check_xa_shrink(struct xarray *xa) 22558d6ea30SMatthew Wilcox { 22658d6ea30SMatthew Wilcox XA_STATE(xas, xa, 1); 22758d6ea30SMatthew Wilcox struct xa_node *node; 22858d6ea30SMatthew Wilcox 22958d6ea30SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 23058d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_store_index(xa, 0, GFP_KERNEL) != NULL); 23158d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_store_index(xa, 1, GFP_KERNEL) != NULL); 23258d6ea30SMatthew Wilcox 23358d6ea30SMatthew Wilcox /* 23458d6ea30SMatthew Wilcox * Check that erasing the entry at 1 shrinks the tree and properly 23558d6ea30SMatthew Wilcox * marks the node as being deleted. 23658d6ea30SMatthew Wilcox */ 23758d6ea30SMatthew Wilcox xas_lock(&xas); 23858d6ea30SMatthew Wilcox XA_BUG_ON(xa, xas_load(&xas) != xa_mk_value(1)); 23958d6ea30SMatthew Wilcox node = xas.xa_node; 24058d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_entry_locked(xa, node, 0) != xa_mk_value(0)); 24158d6ea30SMatthew Wilcox XA_BUG_ON(xa, xas_store(&xas, NULL) != xa_mk_value(1)); 24258d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_load(xa, 1) != NULL); 24358d6ea30SMatthew Wilcox XA_BUG_ON(xa, xas.xa_node != XAS_BOUNDS); 24458d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_entry_locked(xa, node, 0) != XA_RETRY_ENTRY); 24558d6ea30SMatthew Wilcox XA_BUG_ON(xa, xas_load(&xas) != NULL); 24658d6ea30SMatthew Wilcox xas_unlock(&xas); 24758d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_load(xa, 0) != xa_mk_value(0)); 24858d6ea30SMatthew Wilcox xa_erase_index(xa, 0); 24958d6ea30SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 25058d6ea30SMatthew Wilcox } 25158d6ea30SMatthew Wilcox 25241aec91fSMatthew Wilcox static noinline void check_cmpxchg(struct xarray *xa) 25341aec91fSMatthew Wilcox { 25441aec91fSMatthew Wilcox void *FIVE = xa_mk_value(5); 25541aec91fSMatthew Wilcox void *SIX = xa_mk_value(6); 25641aec91fSMatthew Wilcox void *LOTS = xa_mk_value(12345678); 25741aec91fSMatthew Wilcox 25841aec91fSMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 25941aec91fSMatthew Wilcox XA_BUG_ON(xa, xa_store_index(xa, 12345678, GFP_KERNEL) != NULL); 26041aec91fSMatthew Wilcox XA_BUG_ON(xa, xa_insert(xa, 12345678, xa, GFP_KERNEL) != -EEXIST); 26141aec91fSMatthew Wilcox XA_BUG_ON(xa, xa_cmpxchg(xa, 12345678, SIX, FIVE, GFP_KERNEL) != LOTS); 26241aec91fSMatthew Wilcox XA_BUG_ON(xa, xa_cmpxchg(xa, 12345678, LOTS, FIVE, GFP_KERNEL) != LOTS); 26341aec91fSMatthew Wilcox XA_BUG_ON(xa, xa_cmpxchg(xa, 12345678, FIVE, LOTS, GFP_KERNEL) != FIVE); 26441aec91fSMatthew Wilcox XA_BUG_ON(xa, xa_cmpxchg(xa, 5, FIVE, NULL, GFP_KERNEL) != NULL); 26541aec91fSMatthew Wilcox XA_BUG_ON(xa, xa_cmpxchg(xa, 5, NULL, FIVE, GFP_KERNEL) != NULL); 26641aec91fSMatthew Wilcox xa_erase_index(xa, 12345678); 26741aec91fSMatthew Wilcox xa_erase_index(xa, 5); 26841aec91fSMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 26941aec91fSMatthew Wilcox } 27041aec91fSMatthew Wilcox 2719f14d4f1SMatthew Wilcox static noinline void check_reserve(struct xarray *xa) 2729f14d4f1SMatthew Wilcox { 2739f14d4f1SMatthew Wilcox void *entry; 2749f14d4f1SMatthew Wilcox unsigned long index = 0; 2759f14d4f1SMatthew Wilcox 2769f14d4f1SMatthew Wilcox /* An array with a reserved entry is not empty */ 2779f14d4f1SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 2789f14d4f1SMatthew Wilcox xa_reserve(xa, 12345678, GFP_KERNEL); 2799f14d4f1SMatthew Wilcox XA_BUG_ON(xa, xa_empty(xa)); 2809f14d4f1SMatthew Wilcox XA_BUG_ON(xa, xa_load(xa, 12345678)); 2819f14d4f1SMatthew Wilcox xa_release(xa, 12345678); 2829f14d4f1SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 2839f14d4f1SMatthew Wilcox 2849f14d4f1SMatthew Wilcox /* Releasing a used entry does nothing */ 2859f14d4f1SMatthew Wilcox xa_reserve(xa, 12345678, GFP_KERNEL); 2869f14d4f1SMatthew Wilcox XA_BUG_ON(xa, xa_store_index(xa, 12345678, GFP_NOWAIT) != NULL); 2879f14d4f1SMatthew Wilcox xa_release(xa, 12345678); 2889f14d4f1SMatthew Wilcox xa_erase_index(xa, 12345678); 2899f14d4f1SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 2909f14d4f1SMatthew Wilcox 2919f14d4f1SMatthew Wilcox /* cmpxchg sees a reserved entry as NULL */ 2929f14d4f1SMatthew Wilcox xa_reserve(xa, 12345678, GFP_KERNEL); 2939f14d4f1SMatthew Wilcox XA_BUG_ON(xa, xa_cmpxchg(xa, 12345678, NULL, xa_mk_value(12345678), 2949f14d4f1SMatthew Wilcox GFP_NOWAIT) != NULL); 2959f14d4f1SMatthew Wilcox xa_release(xa, 12345678); 2969f14d4f1SMatthew Wilcox xa_erase_index(xa, 12345678); 2979f14d4f1SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 2989f14d4f1SMatthew Wilcox 2999f14d4f1SMatthew Wilcox /* Can iterate through a reserved entry */ 3009f14d4f1SMatthew Wilcox xa_store_index(xa, 5, GFP_KERNEL); 3019f14d4f1SMatthew Wilcox xa_reserve(xa, 6, GFP_KERNEL); 3029f14d4f1SMatthew Wilcox xa_store_index(xa, 7, GFP_KERNEL); 3039f14d4f1SMatthew Wilcox 3049f14d4f1SMatthew Wilcox xa_for_each(xa, entry, index, ULONG_MAX, XA_PRESENT) { 3059f14d4f1SMatthew Wilcox XA_BUG_ON(xa, index != 5 && index != 7); 3069f14d4f1SMatthew Wilcox } 3079f14d4f1SMatthew Wilcox xa_destroy(xa); 3089f14d4f1SMatthew Wilcox } 3099f14d4f1SMatthew Wilcox 310b803b428SMatthew Wilcox static noinline void check_xas_erase(struct xarray *xa) 311b803b428SMatthew Wilcox { 312b803b428SMatthew Wilcox XA_STATE(xas, xa, 0); 313b803b428SMatthew Wilcox void *entry; 314b803b428SMatthew Wilcox unsigned long i, j; 315b803b428SMatthew Wilcox 316b803b428SMatthew Wilcox for (i = 0; i < 200; i++) { 317b803b428SMatthew Wilcox for (j = i; j < 2 * i + 17; j++) { 318b803b428SMatthew Wilcox xas_set(&xas, j); 319b803b428SMatthew Wilcox do { 320b803b428SMatthew Wilcox xas_lock(&xas); 321b803b428SMatthew Wilcox xas_store(&xas, xa_mk_value(j)); 322b803b428SMatthew Wilcox xas_unlock(&xas); 323b803b428SMatthew Wilcox } while (xas_nomem(&xas, GFP_KERNEL)); 324b803b428SMatthew Wilcox } 325b803b428SMatthew Wilcox 326b803b428SMatthew Wilcox xas_set(&xas, ULONG_MAX); 327b803b428SMatthew Wilcox do { 328b803b428SMatthew Wilcox xas_lock(&xas); 329b803b428SMatthew Wilcox xas_store(&xas, xa_mk_value(0)); 330b803b428SMatthew Wilcox xas_unlock(&xas); 331b803b428SMatthew Wilcox } while (xas_nomem(&xas, GFP_KERNEL)); 332b803b428SMatthew Wilcox 333b803b428SMatthew Wilcox xas_lock(&xas); 334b803b428SMatthew Wilcox xas_store(&xas, NULL); 335b803b428SMatthew Wilcox 336b803b428SMatthew Wilcox xas_set(&xas, 0); 337b803b428SMatthew Wilcox j = i; 338b803b428SMatthew Wilcox xas_for_each(&xas, entry, ULONG_MAX) { 339b803b428SMatthew Wilcox XA_BUG_ON(xa, entry != xa_mk_value(j)); 340b803b428SMatthew Wilcox xas_store(&xas, NULL); 341b803b428SMatthew Wilcox j++; 342b803b428SMatthew Wilcox } 343b803b428SMatthew Wilcox xas_unlock(&xas); 344b803b428SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 345b803b428SMatthew Wilcox } 346b803b428SMatthew Wilcox } 347b803b428SMatthew Wilcox 34858d6ea30SMatthew Wilcox static noinline void check_multi_store(struct xarray *xa) 34958d6ea30SMatthew Wilcox { 35058d6ea30SMatthew Wilcox #ifdef CONFIG_XARRAY_MULTI 35158d6ea30SMatthew Wilcox unsigned long i, j, k; 35258d6ea30SMatthew Wilcox unsigned int max_order = (sizeof(long) == 4) ? 30 : 60; 35358d6ea30SMatthew Wilcox 35458d6ea30SMatthew Wilcox /* Loading from any position returns the same value */ 35558d6ea30SMatthew Wilcox xa_store_order(xa, 0, 1, xa_mk_value(0), GFP_KERNEL); 35658d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_load(xa, 0) != xa_mk_value(0)); 35758d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_load(xa, 1) != xa_mk_value(0)); 35858d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_load(xa, 2) != NULL); 35958d6ea30SMatthew Wilcox rcu_read_lock(); 36058d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_to_node(xa_head(xa))->count != 2); 36158d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_to_node(xa_head(xa))->nr_values != 2); 36258d6ea30SMatthew Wilcox rcu_read_unlock(); 36358d6ea30SMatthew Wilcox 36458d6ea30SMatthew Wilcox /* Storing adjacent to the value does not alter the value */ 36558d6ea30SMatthew Wilcox xa_store(xa, 3, xa, GFP_KERNEL); 36658d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_load(xa, 0) != xa_mk_value(0)); 36758d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_load(xa, 1) != xa_mk_value(0)); 36858d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_load(xa, 2) != NULL); 36958d6ea30SMatthew Wilcox rcu_read_lock(); 37058d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_to_node(xa_head(xa))->count != 3); 37158d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_to_node(xa_head(xa))->nr_values != 2); 37258d6ea30SMatthew Wilcox rcu_read_unlock(); 37358d6ea30SMatthew Wilcox 37458d6ea30SMatthew Wilcox /* Overwriting multiple indexes works */ 37558d6ea30SMatthew Wilcox xa_store_order(xa, 0, 2, xa_mk_value(1), GFP_KERNEL); 37658d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_load(xa, 0) != xa_mk_value(1)); 37758d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_load(xa, 1) != xa_mk_value(1)); 37858d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_load(xa, 2) != xa_mk_value(1)); 37958d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_load(xa, 3) != xa_mk_value(1)); 38058d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_load(xa, 4) != NULL); 38158d6ea30SMatthew Wilcox rcu_read_lock(); 38258d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_to_node(xa_head(xa))->count != 4); 38358d6ea30SMatthew Wilcox XA_BUG_ON(xa, xa_to_node(xa_head(xa))->nr_values != 4); 38458d6ea30SMatthew Wilcox rcu_read_unlock(); 38558d6ea30SMatthew Wilcox 38658d6ea30SMatthew Wilcox /* We can erase multiple values with a single store */ 38758d6ea30SMatthew Wilcox xa_store_order(xa, 0, 63, NULL, GFP_KERNEL); 38858d6ea30SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 38958d6ea30SMatthew Wilcox 39058d6ea30SMatthew Wilcox /* Even when the first slot is empty but the others aren't */ 39158d6ea30SMatthew Wilcox xa_store_index(xa, 1, GFP_KERNEL); 39258d6ea30SMatthew Wilcox xa_store_index(xa, 2, GFP_KERNEL); 39358d6ea30SMatthew Wilcox xa_store_order(xa, 0, 2, NULL, GFP_KERNEL); 39458d6ea30SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 39558d6ea30SMatthew Wilcox 39658d6ea30SMatthew Wilcox for (i = 0; i < max_order; i++) { 39758d6ea30SMatthew Wilcox for (j = 0; j < max_order; j++) { 39858d6ea30SMatthew Wilcox xa_store_order(xa, 0, i, xa_mk_value(i), GFP_KERNEL); 39958d6ea30SMatthew Wilcox xa_store_order(xa, 0, j, xa_mk_value(j), GFP_KERNEL); 40058d6ea30SMatthew Wilcox 40158d6ea30SMatthew Wilcox for (k = 0; k < max_order; k++) { 40258d6ea30SMatthew Wilcox void *entry = xa_load(xa, (1UL << k) - 1); 40358d6ea30SMatthew Wilcox if ((i < k) && (j < k)) 40458d6ea30SMatthew Wilcox XA_BUG_ON(xa, entry != NULL); 40558d6ea30SMatthew Wilcox else 40658d6ea30SMatthew Wilcox XA_BUG_ON(xa, entry != xa_mk_value(j)); 40758d6ea30SMatthew Wilcox } 40858d6ea30SMatthew Wilcox 40958d6ea30SMatthew Wilcox xa_erase(xa, 0); 41058d6ea30SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 41158d6ea30SMatthew Wilcox } 41258d6ea30SMatthew Wilcox } 41358d6ea30SMatthew Wilcox #endif 41458d6ea30SMatthew Wilcox } 41558d6ea30SMatthew Wilcox 416*371c752dSMatthew Wilcox static DEFINE_XARRAY_ALLOC(xa0); 417*371c752dSMatthew Wilcox 418*371c752dSMatthew Wilcox static noinline void check_xa_alloc(void) 419*371c752dSMatthew Wilcox { 420*371c752dSMatthew Wilcox int i; 421*371c752dSMatthew Wilcox u32 id; 422*371c752dSMatthew Wilcox 423*371c752dSMatthew Wilcox /* An empty array should assign 0 to the first alloc */ 424*371c752dSMatthew Wilcox xa_alloc_index(&xa0, 0, GFP_KERNEL); 425*371c752dSMatthew Wilcox 426*371c752dSMatthew Wilcox /* Erasing it should make the array empty again */ 427*371c752dSMatthew Wilcox xa_erase_index(&xa0, 0); 428*371c752dSMatthew Wilcox XA_BUG_ON(&xa0, !xa_empty(&xa0)); 429*371c752dSMatthew Wilcox 430*371c752dSMatthew Wilcox /* And it should assign 0 again */ 431*371c752dSMatthew Wilcox xa_alloc_index(&xa0, 0, GFP_KERNEL); 432*371c752dSMatthew Wilcox 433*371c752dSMatthew Wilcox /* The next assigned ID should be 1 */ 434*371c752dSMatthew Wilcox xa_alloc_index(&xa0, 1, GFP_KERNEL); 435*371c752dSMatthew Wilcox xa_erase_index(&xa0, 1); 436*371c752dSMatthew Wilcox 437*371c752dSMatthew Wilcox /* Storing a value should mark it used */ 438*371c752dSMatthew Wilcox xa_store_index(&xa0, 1, GFP_KERNEL); 439*371c752dSMatthew Wilcox xa_alloc_index(&xa0, 2, GFP_KERNEL); 440*371c752dSMatthew Wilcox 441*371c752dSMatthew Wilcox /* If we then erase 0, it should be free */ 442*371c752dSMatthew Wilcox xa_erase_index(&xa0, 0); 443*371c752dSMatthew Wilcox xa_alloc_index(&xa0, 0, GFP_KERNEL); 444*371c752dSMatthew Wilcox 445*371c752dSMatthew Wilcox xa_erase_index(&xa0, 1); 446*371c752dSMatthew Wilcox xa_erase_index(&xa0, 2); 447*371c752dSMatthew Wilcox 448*371c752dSMatthew Wilcox for (i = 1; i < 5000; i++) { 449*371c752dSMatthew Wilcox xa_alloc_index(&xa0, i, GFP_KERNEL); 450*371c752dSMatthew Wilcox } 451*371c752dSMatthew Wilcox 452*371c752dSMatthew Wilcox xa_destroy(&xa0); 453*371c752dSMatthew Wilcox 454*371c752dSMatthew Wilcox id = 0xfffffffeU; 455*371c752dSMatthew Wilcox XA_BUG_ON(&xa0, xa_alloc(&xa0, &id, UINT_MAX, xa_mk_value(0), 456*371c752dSMatthew Wilcox GFP_KERNEL) != 0); 457*371c752dSMatthew Wilcox XA_BUG_ON(&xa0, id != 0xfffffffeU); 458*371c752dSMatthew Wilcox XA_BUG_ON(&xa0, xa_alloc(&xa0, &id, UINT_MAX, xa_mk_value(0), 459*371c752dSMatthew Wilcox GFP_KERNEL) != 0); 460*371c752dSMatthew Wilcox XA_BUG_ON(&xa0, id != 0xffffffffU); 461*371c752dSMatthew Wilcox XA_BUG_ON(&xa0, xa_alloc(&xa0, &id, UINT_MAX, xa_mk_value(0), 462*371c752dSMatthew Wilcox GFP_KERNEL) != -ENOSPC); 463*371c752dSMatthew Wilcox XA_BUG_ON(&xa0, id != 0xffffffffU); 464*371c752dSMatthew Wilcox xa_destroy(&xa0); 465*371c752dSMatthew Wilcox } 466*371c752dSMatthew Wilcox 4674e99d4e9SMatthew Wilcox static noinline void __check_store_iter(struct xarray *xa, unsigned long start, 4684e99d4e9SMatthew Wilcox unsigned int order, unsigned int present) 4694e99d4e9SMatthew Wilcox { 4704e99d4e9SMatthew Wilcox XA_STATE_ORDER(xas, xa, start, order); 4714e99d4e9SMatthew Wilcox void *entry; 4724e99d4e9SMatthew Wilcox unsigned int count = 0; 4734e99d4e9SMatthew Wilcox 4744e99d4e9SMatthew Wilcox retry: 4754e99d4e9SMatthew Wilcox xas_lock(&xas); 4764e99d4e9SMatthew Wilcox xas_for_each_conflict(&xas, entry) { 4774e99d4e9SMatthew Wilcox XA_BUG_ON(xa, !xa_is_value(entry)); 4784e99d4e9SMatthew Wilcox XA_BUG_ON(xa, entry < xa_mk_value(start)); 4794e99d4e9SMatthew Wilcox XA_BUG_ON(xa, entry > xa_mk_value(start + (1UL << order) - 1)); 4804e99d4e9SMatthew Wilcox count++; 4814e99d4e9SMatthew Wilcox } 4824e99d4e9SMatthew Wilcox xas_store(&xas, xa_mk_value(start)); 4834e99d4e9SMatthew Wilcox xas_unlock(&xas); 4844e99d4e9SMatthew Wilcox if (xas_nomem(&xas, GFP_KERNEL)) { 4854e99d4e9SMatthew Wilcox count = 0; 4864e99d4e9SMatthew Wilcox goto retry; 4874e99d4e9SMatthew Wilcox } 4884e99d4e9SMatthew Wilcox XA_BUG_ON(xa, xas_error(&xas)); 4894e99d4e9SMatthew Wilcox XA_BUG_ON(xa, count != present); 4904e99d4e9SMatthew Wilcox XA_BUG_ON(xa, xa_load(xa, start) != xa_mk_value(start)); 4914e99d4e9SMatthew Wilcox XA_BUG_ON(xa, xa_load(xa, start + (1UL << order) - 1) != 4924e99d4e9SMatthew Wilcox xa_mk_value(start)); 4934e99d4e9SMatthew Wilcox xa_erase_index(xa, start); 4944e99d4e9SMatthew Wilcox } 4954e99d4e9SMatthew Wilcox 4964e99d4e9SMatthew Wilcox static noinline void check_store_iter(struct xarray *xa) 4974e99d4e9SMatthew Wilcox { 4984e99d4e9SMatthew Wilcox unsigned int i, j; 4994e99d4e9SMatthew Wilcox unsigned int max_order = IS_ENABLED(CONFIG_XARRAY_MULTI) ? 20 : 1; 5004e99d4e9SMatthew Wilcox 5014e99d4e9SMatthew Wilcox for (i = 0; i < max_order; i++) { 5024e99d4e9SMatthew Wilcox unsigned int min = 1 << i; 5034e99d4e9SMatthew Wilcox unsigned int max = (2 << i) - 1; 5044e99d4e9SMatthew Wilcox __check_store_iter(xa, 0, i, 0); 5054e99d4e9SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 5064e99d4e9SMatthew Wilcox __check_store_iter(xa, min, i, 0); 5074e99d4e9SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 5084e99d4e9SMatthew Wilcox 5094e99d4e9SMatthew Wilcox xa_store_index(xa, min, GFP_KERNEL); 5104e99d4e9SMatthew Wilcox __check_store_iter(xa, min, i, 1); 5114e99d4e9SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 5124e99d4e9SMatthew Wilcox xa_store_index(xa, max, GFP_KERNEL); 5134e99d4e9SMatthew Wilcox __check_store_iter(xa, min, i, 1); 5144e99d4e9SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 5154e99d4e9SMatthew Wilcox 5164e99d4e9SMatthew Wilcox for (j = 0; j < min; j++) 5174e99d4e9SMatthew Wilcox xa_store_index(xa, j, GFP_KERNEL); 5184e99d4e9SMatthew Wilcox __check_store_iter(xa, 0, i, min); 5194e99d4e9SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 5204e99d4e9SMatthew Wilcox for (j = 0; j < min; j++) 5214e99d4e9SMatthew Wilcox xa_store_index(xa, min + j, GFP_KERNEL); 5224e99d4e9SMatthew Wilcox __check_store_iter(xa, min, i, min); 5234e99d4e9SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 5244e99d4e9SMatthew Wilcox } 5254e99d4e9SMatthew Wilcox #ifdef CONFIG_XARRAY_MULTI 5264e99d4e9SMatthew Wilcox xa_store_index(xa, 63, GFP_KERNEL); 5274e99d4e9SMatthew Wilcox xa_store_index(xa, 65, GFP_KERNEL); 5284e99d4e9SMatthew Wilcox __check_store_iter(xa, 64, 2, 1); 5294e99d4e9SMatthew Wilcox xa_erase_index(xa, 63); 5304e99d4e9SMatthew Wilcox #endif 5314e99d4e9SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 5324e99d4e9SMatthew Wilcox } 5334e99d4e9SMatthew Wilcox 534b803b428SMatthew Wilcox static noinline void check_multi_find(struct xarray *xa) 535b803b428SMatthew Wilcox { 536b803b428SMatthew Wilcox #ifdef CONFIG_XARRAY_MULTI 537b803b428SMatthew Wilcox unsigned long index; 538b803b428SMatthew Wilcox 539b803b428SMatthew Wilcox xa_store_order(xa, 12, 2, xa_mk_value(12), GFP_KERNEL); 540b803b428SMatthew Wilcox XA_BUG_ON(xa, xa_store_index(xa, 16, GFP_KERNEL) != NULL); 541b803b428SMatthew Wilcox 542b803b428SMatthew Wilcox index = 0; 543b803b428SMatthew Wilcox XA_BUG_ON(xa, xa_find(xa, &index, ULONG_MAX, XA_PRESENT) != 544b803b428SMatthew Wilcox xa_mk_value(12)); 545b803b428SMatthew Wilcox XA_BUG_ON(xa, index != 12); 546b803b428SMatthew Wilcox index = 13; 547b803b428SMatthew Wilcox XA_BUG_ON(xa, xa_find(xa, &index, ULONG_MAX, XA_PRESENT) != 548b803b428SMatthew Wilcox xa_mk_value(12)); 549b803b428SMatthew Wilcox XA_BUG_ON(xa, (index < 12) || (index >= 16)); 550b803b428SMatthew Wilcox XA_BUG_ON(xa, xa_find_after(xa, &index, ULONG_MAX, XA_PRESENT) != 551b803b428SMatthew Wilcox xa_mk_value(16)); 552b803b428SMatthew Wilcox XA_BUG_ON(xa, index != 16); 553b803b428SMatthew Wilcox 554b803b428SMatthew Wilcox xa_erase_index(xa, 12); 555b803b428SMatthew Wilcox xa_erase_index(xa, 16); 556b803b428SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 557b803b428SMatthew Wilcox #endif 558b803b428SMatthew Wilcox } 559b803b428SMatthew Wilcox 560b803b428SMatthew Wilcox static noinline void check_multi_find_2(struct xarray *xa) 561b803b428SMatthew Wilcox { 562b803b428SMatthew Wilcox unsigned int max_order = IS_ENABLED(CONFIG_XARRAY_MULTI) ? 10 : 1; 563b803b428SMatthew Wilcox unsigned int i, j; 564b803b428SMatthew Wilcox void *entry; 565b803b428SMatthew Wilcox 566b803b428SMatthew Wilcox for (i = 0; i < max_order; i++) { 567b803b428SMatthew Wilcox unsigned long index = 1UL << i; 568b803b428SMatthew Wilcox for (j = 0; j < index; j++) { 569b803b428SMatthew Wilcox XA_STATE(xas, xa, j + index); 570b803b428SMatthew Wilcox xa_store_index(xa, index - 1, GFP_KERNEL); 571b803b428SMatthew Wilcox xa_store_order(xa, index, i, xa_mk_value(index), 572b803b428SMatthew Wilcox GFP_KERNEL); 573b803b428SMatthew Wilcox rcu_read_lock(); 574b803b428SMatthew Wilcox xas_for_each(&xas, entry, ULONG_MAX) { 575b803b428SMatthew Wilcox xa_erase_index(xa, index); 576b803b428SMatthew Wilcox } 577b803b428SMatthew Wilcox rcu_read_unlock(); 578b803b428SMatthew Wilcox xa_erase_index(xa, index - 1); 579b803b428SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 580b803b428SMatthew Wilcox } 581b803b428SMatthew Wilcox } 582b803b428SMatthew Wilcox } 583b803b428SMatthew Wilcox 584b803b428SMatthew Wilcox static noinline void check_find(struct xarray *xa) 585b803b428SMatthew Wilcox { 586b803b428SMatthew Wilcox unsigned long i, j, k; 587b803b428SMatthew Wilcox 588b803b428SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 589b803b428SMatthew Wilcox 590b803b428SMatthew Wilcox /* 591b803b428SMatthew Wilcox * Check xa_find with all pairs between 0 and 99 inclusive, 592b803b428SMatthew Wilcox * starting at every index between 0 and 99 593b803b428SMatthew Wilcox */ 594b803b428SMatthew Wilcox for (i = 0; i < 100; i++) { 595b803b428SMatthew Wilcox XA_BUG_ON(xa, xa_store_index(xa, i, GFP_KERNEL) != NULL); 596b803b428SMatthew Wilcox xa_set_mark(xa, i, XA_MARK_0); 597b803b428SMatthew Wilcox for (j = 0; j < i; j++) { 598b803b428SMatthew Wilcox XA_BUG_ON(xa, xa_store_index(xa, j, GFP_KERNEL) != 599b803b428SMatthew Wilcox NULL); 600b803b428SMatthew Wilcox xa_set_mark(xa, j, XA_MARK_0); 601b803b428SMatthew Wilcox for (k = 0; k < 100; k++) { 602b803b428SMatthew Wilcox unsigned long index = k; 603b803b428SMatthew Wilcox void *entry = xa_find(xa, &index, ULONG_MAX, 604b803b428SMatthew Wilcox XA_PRESENT); 605b803b428SMatthew Wilcox if (k <= j) 606b803b428SMatthew Wilcox XA_BUG_ON(xa, index != j); 607b803b428SMatthew Wilcox else if (k <= i) 608b803b428SMatthew Wilcox XA_BUG_ON(xa, index != i); 609b803b428SMatthew Wilcox else 610b803b428SMatthew Wilcox XA_BUG_ON(xa, entry != NULL); 611b803b428SMatthew Wilcox 612b803b428SMatthew Wilcox index = k; 613b803b428SMatthew Wilcox entry = xa_find(xa, &index, ULONG_MAX, 614b803b428SMatthew Wilcox XA_MARK_0); 615b803b428SMatthew Wilcox if (k <= j) 616b803b428SMatthew Wilcox XA_BUG_ON(xa, index != j); 617b803b428SMatthew Wilcox else if (k <= i) 618b803b428SMatthew Wilcox XA_BUG_ON(xa, index != i); 619b803b428SMatthew Wilcox else 620b803b428SMatthew Wilcox XA_BUG_ON(xa, entry != NULL); 621b803b428SMatthew Wilcox } 622b803b428SMatthew Wilcox xa_erase_index(xa, j); 623b803b428SMatthew Wilcox XA_BUG_ON(xa, xa_get_mark(xa, j, XA_MARK_0)); 624b803b428SMatthew Wilcox XA_BUG_ON(xa, !xa_get_mark(xa, i, XA_MARK_0)); 625b803b428SMatthew Wilcox } 626b803b428SMatthew Wilcox xa_erase_index(xa, i); 627b803b428SMatthew Wilcox XA_BUG_ON(xa, xa_get_mark(xa, i, XA_MARK_0)); 628b803b428SMatthew Wilcox } 629b803b428SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 630b803b428SMatthew Wilcox check_multi_find(xa); 631b803b428SMatthew Wilcox check_multi_find_2(xa); 632b803b428SMatthew Wilcox } 633b803b428SMatthew Wilcox 63464d3e9a9SMatthew Wilcox static noinline void check_move_small(struct xarray *xa, unsigned long idx) 63564d3e9a9SMatthew Wilcox { 63664d3e9a9SMatthew Wilcox XA_STATE(xas, xa, 0); 63764d3e9a9SMatthew Wilcox unsigned long i; 63864d3e9a9SMatthew Wilcox 63964d3e9a9SMatthew Wilcox xa_store_index(xa, 0, GFP_KERNEL); 64064d3e9a9SMatthew Wilcox xa_store_index(xa, idx, GFP_KERNEL); 64164d3e9a9SMatthew Wilcox 64264d3e9a9SMatthew Wilcox rcu_read_lock(); 64364d3e9a9SMatthew Wilcox for (i = 0; i < idx * 4; i++) { 64464d3e9a9SMatthew Wilcox void *entry = xas_next(&xas); 64564d3e9a9SMatthew Wilcox if (i <= idx) 64664d3e9a9SMatthew Wilcox XA_BUG_ON(xa, xas.xa_node == XAS_RESTART); 64764d3e9a9SMatthew Wilcox XA_BUG_ON(xa, xas.xa_index != i); 64864d3e9a9SMatthew Wilcox if (i == 0 || i == idx) 64964d3e9a9SMatthew Wilcox XA_BUG_ON(xa, entry != xa_mk_value(i)); 65064d3e9a9SMatthew Wilcox else 65164d3e9a9SMatthew Wilcox XA_BUG_ON(xa, entry != NULL); 65264d3e9a9SMatthew Wilcox } 65364d3e9a9SMatthew Wilcox xas_next(&xas); 65464d3e9a9SMatthew Wilcox XA_BUG_ON(xa, xas.xa_index != i); 65564d3e9a9SMatthew Wilcox 65664d3e9a9SMatthew Wilcox do { 65764d3e9a9SMatthew Wilcox void *entry = xas_prev(&xas); 65864d3e9a9SMatthew Wilcox i--; 65964d3e9a9SMatthew Wilcox if (i <= idx) 66064d3e9a9SMatthew Wilcox XA_BUG_ON(xa, xas.xa_node == XAS_RESTART); 66164d3e9a9SMatthew Wilcox XA_BUG_ON(xa, xas.xa_index != i); 66264d3e9a9SMatthew Wilcox if (i == 0 || i == idx) 66364d3e9a9SMatthew Wilcox XA_BUG_ON(xa, entry != xa_mk_value(i)); 66464d3e9a9SMatthew Wilcox else 66564d3e9a9SMatthew Wilcox XA_BUG_ON(xa, entry != NULL); 66664d3e9a9SMatthew Wilcox } while (i > 0); 66764d3e9a9SMatthew Wilcox 66864d3e9a9SMatthew Wilcox xas_set(&xas, ULONG_MAX); 66964d3e9a9SMatthew Wilcox XA_BUG_ON(xa, xas_next(&xas) != NULL); 67064d3e9a9SMatthew Wilcox XA_BUG_ON(xa, xas.xa_index != ULONG_MAX); 67164d3e9a9SMatthew Wilcox XA_BUG_ON(xa, xas_next(&xas) != xa_mk_value(0)); 67264d3e9a9SMatthew Wilcox XA_BUG_ON(xa, xas.xa_index != 0); 67364d3e9a9SMatthew Wilcox XA_BUG_ON(xa, xas_prev(&xas) != NULL); 67464d3e9a9SMatthew Wilcox XA_BUG_ON(xa, xas.xa_index != ULONG_MAX); 67564d3e9a9SMatthew Wilcox rcu_read_unlock(); 67664d3e9a9SMatthew Wilcox 67764d3e9a9SMatthew Wilcox xa_erase_index(xa, 0); 67864d3e9a9SMatthew Wilcox xa_erase_index(xa, idx); 67964d3e9a9SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 68064d3e9a9SMatthew Wilcox } 68164d3e9a9SMatthew Wilcox 68264d3e9a9SMatthew Wilcox static noinline void check_move(struct xarray *xa) 68364d3e9a9SMatthew Wilcox { 68464d3e9a9SMatthew Wilcox XA_STATE(xas, xa, (1 << 16) - 1); 68564d3e9a9SMatthew Wilcox unsigned long i; 68664d3e9a9SMatthew Wilcox 68764d3e9a9SMatthew Wilcox for (i = 0; i < (1 << 16); i++) 68864d3e9a9SMatthew Wilcox XA_BUG_ON(xa, xa_store_index(xa, i, GFP_KERNEL) != NULL); 68964d3e9a9SMatthew Wilcox 69064d3e9a9SMatthew Wilcox rcu_read_lock(); 69164d3e9a9SMatthew Wilcox do { 69264d3e9a9SMatthew Wilcox void *entry = xas_prev(&xas); 69364d3e9a9SMatthew Wilcox i--; 69464d3e9a9SMatthew Wilcox XA_BUG_ON(xa, entry != xa_mk_value(i)); 69564d3e9a9SMatthew Wilcox XA_BUG_ON(xa, i != xas.xa_index); 69664d3e9a9SMatthew Wilcox } while (i != 0); 69764d3e9a9SMatthew Wilcox 69864d3e9a9SMatthew Wilcox XA_BUG_ON(xa, xas_prev(&xas) != NULL); 69964d3e9a9SMatthew Wilcox XA_BUG_ON(xa, xas.xa_index != ULONG_MAX); 70064d3e9a9SMatthew Wilcox 70164d3e9a9SMatthew Wilcox do { 70264d3e9a9SMatthew Wilcox void *entry = xas_next(&xas); 70364d3e9a9SMatthew Wilcox XA_BUG_ON(xa, entry != xa_mk_value(i)); 70464d3e9a9SMatthew Wilcox XA_BUG_ON(xa, i != xas.xa_index); 70564d3e9a9SMatthew Wilcox i++; 70664d3e9a9SMatthew Wilcox } while (i < (1 << 16)); 70764d3e9a9SMatthew Wilcox rcu_read_unlock(); 70864d3e9a9SMatthew Wilcox 70964d3e9a9SMatthew Wilcox for (i = (1 << 8); i < (1 << 15); i++) 71064d3e9a9SMatthew Wilcox xa_erase_index(xa, i); 71164d3e9a9SMatthew Wilcox 71264d3e9a9SMatthew Wilcox i = xas.xa_index; 71364d3e9a9SMatthew Wilcox 71464d3e9a9SMatthew Wilcox rcu_read_lock(); 71564d3e9a9SMatthew Wilcox do { 71664d3e9a9SMatthew Wilcox void *entry = xas_prev(&xas); 71764d3e9a9SMatthew Wilcox i--; 71864d3e9a9SMatthew Wilcox if ((i < (1 << 8)) || (i >= (1 << 15))) 71964d3e9a9SMatthew Wilcox XA_BUG_ON(xa, entry != xa_mk_value(i)); 72064d3e9a9SMatthew Wilcox else 72164d3e9a9SMatthew Wilcox XA_BUG_ON(xa, entry != NULL); 72264d3e9a9SMatthew Wilcox XA_BUG_ON(xa, i != xas.xa_index); 72364d3e9a9SMatthew Wilcox } while (i != 0); 72464d3e9a9SMatthew Wilcox 72564d3e9a9SMatthew Wilcox XA_BUG_ON(xa, xas_prev(&xas) != NULL); 72664d3e9a9SMatthew Wilcox XA_BUG_ON(xa, xas.xa_index != ULONG_MAX); 72764d3e9a9SMatthew Wilcox 72864d3e9a9SMatthew Wilcox do { 72964d3e9a9SMatthew Wilcox void *entry = xas_next(&xas); 73064d3e9a9SMatthew Wilcox if ((i < (1 << 8)) || (i >= (1 << 15))) 73164d3e9a9SMatthew Wilcox XA_BUG_ON(xa, entry != xa_mk_value(i)); 73264d3e9a9SMatthew Wilcox else 73364d3e9a9SMatthew Wilcox XA_BUG_ON(xa, entry != NULL); 73464d3e9a9SMatthew Wilcox XA_BUG_ON(xa, i != xas.xa_index); 73564d3e9a9SMatthew Wilcox i++; 73664d3e9a9SMatthew Wilcox } while (i < (1 << 16)); 73764d3e9a9SMatthew Wilcox rcu_read_unlock(); 73864d3e9a9SMatthew Wilcox 73964d3e9a9SMatthew Wilcox xa_destroy(xa); 74064d3e9a9SMatthew Wilcox 74164d3e9a9SMatthew Wilcox for (i = 0; i < 16; i++) 74264d3e9a9SMatthew Wilcox check_move_small(xa, 1UL << i); 74364d3e9a9SMatthew Wilcox 74464d3e9a9SMatthew Wilcox for (i = 2; i < 16; i++) 74564d3e9a9SMatthew Wilcox check_move_small(xa, (1UL << i) - 1); 74664d3e9a9SMatthew Wilcox } 74764d3e9a9SMatthew Wilcox 7482264f513SMatthew Wilcox static noinline void xa_store_many_order(struct xarray *xa, 7492264f513SMatthew Wilcox unsigned long index, unsigned order) 7502264f513SMatthew Wilcox { 7512264f513SMatthew Wilcox XA_STATE_ORDER(xas, xa, index, order); 7522264f513SMatthew Wilcox unsigned int i = 0; 7532264f513SMatthew Wilcox 7542264f513SMatthew Wilcox do { 7552264f513SMatthew Wilcox xas_lock(&xas); 7562264f513SMatthew Wilcox XA_BUG_ON(xa, xas_find_conflict(&xas)); 7572264f513SMatthew Wilcox xas_create_range(&xas); 7582264f513SMatthew Wilcox if (xas_error(&xas)) 7592264f513SMatthew Wilcox goto unlock; 7602264f513SMatthew Wilcox for (i = 0; i < (1U << order); i++) { 7612264f513SMatthew Wilcox XA_BUG_ON(xa, xas_store(&xas, xa_mk_value(index + i))); 7622264f513SMatthew Wilcox xas_next(&xas); 7632264f513SMatthew Wilcox } 7642264f513SMatthew Wilcox unlock: 7652264f513SMatthew Wilcox xas_unlock(&xas); 7662264f513SMatthew Wilcox } while (xas_nomem(&xas, GFP_KERNEL)); 7672264f513SMatthew Wilcox 7682264f513SMatthew Wilcox XA_BUG_ON(xa, xas_error(&xas)); 7692264f513SMatthew Wilcox } 7702264f513SMatthew Wilcox 7712264f513SMatthew Wilcox static noinline void check_create_range_1(struct xarray *xa, 7722264f513SMatthew Wilcox unsigned long index, unsigned order) 7732264f513SMatthew Wilcox { 7742264f513SMatthew Wilcox unsigned long i; 7752264f513SMatthew Wilcox 7762264f513SMatthew Wilcox xa_store_many_order(xa, index, order); 7772264f513SMatthew Wilcox for (i = index; i < index + (1UL << order); i++) 7782264f513SMatthew Wilcox xa_erase_index(xa, i); 7792264f513SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 7802264f513SMatthew Wilcox } 7812264f513SMatthew Wilcox 7822264f513SMatthew Wilcox static noinline void check_create_range_2(struct xarray *xa, unsigned order) 7832264f513SMatthew Wilcox { 7842264f513SMatthew Wilcox unsigned long i; 7852264f513SMatthew Wilcox unsigned long nr = 1UL << order; 7862264f513SMatthew Wilcox 7872264f513SMatthew Wilcox for (i = 0; i < nr * nr; i += nr) 7882264f513SMatthew Wilcox xa_store_many_order(xa, i, order); 7892264f513SMatthew Wilcox for (i = 0; i < nr * nr; i++) 7902264f513SMatthew Wilcox xa_erase_index(xa, i); 7912264f513SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 7922264f513SMatthew Wilcox } 7932264f513SMatthew Wilcox 7942264f513SMatthew Wilcox static noinline void check_create_range_3(void) 7952264f513SMatthew Wilcox { 7962264f513SMatthew Wilcox XA_STATE(xas, NULL, 0); 7972264f513SMatthew Wilcox xas_set_err(&xas, -EEXIST); 7982264f513SMatthew Wilcox xas_create_range(&xas); 7992264f513SMatthew Wilcox XA_BUG_ON(NULL, xas_error(&xas) != -EEXIST); 8002264f513SMatthew Wilcox } 8012264f513SMatthew Wilcox 8022264f513SMatthew Wilcox static noinline void check_create_range_4(struct xarray *xa, 8032264f513SMatthew Wilcox unsigned long index, unsigned order) 8042264f513SMatthew Wilcox { 8052264f513SMatthew Wilcox XA_STATE_ORDER(xas, xa, index, order); 8062264f513SMatthew Wilcox unsigned long base = xas.xa_index; 8072264f513SMatthew Wilcox unsigned long i = 0; 8082264f513SMatthew Wilcox 8092264f513SMatthew Wilcox xa_store_index(xa, index, GFP_KERNEL); 8102264f513SMatthew Wilcox do { 8112264f513SMatthew Wilcox xas_lock(&xas); 8122264f513SMatthew Wilcox xas_create_range(&xas); 8132264f513SMatthew Wilcox if (xas_error(&xas)) 8142264f513SMatthew Wilcox goto unlock; 8152264f513SMatthew Wilcox for (i = 0; i < (1UL << order); i++) { 8162264f513SMatthew Wilcox void *old = xas_store(&xas, xa_mk_value(base + i)); 8172264f513SMatthew Wilcox if (xas.xa_index == index) 8182264f513SMatthew Wilcox XA_BUG_ON(xa, old != xa_mk_value(base + i)); 8192264f513SMatthew Wilcox else 8202264f513SMatthew Wilcox XA_BUG_ON(xa, old != NULL); 8212264f513SMatthew Wilcox xas_next(&xas); 8222264f513SMatthew Wilcox } 8232264f513SMatthew Wilcox unlock: 8242264f513SMatthew Wilcox xas_unlock(&xas); 8252264f513SMatthew Wilcox } while (xas_nomem(&xas, GFP_KERNEL)); 8262264f513SMatthew Wilcox 8272264f513SMatthew Wilcox XA_BUG_ON(xa, xas_error(&xas)); 8282264f513SMatthew Wilcox 8292264f513SMatthew Wilcox for (i = base; i < base + (1UL << order); i++) 8302264f513SMatthew Wilcox xa_erase_index(xa, i); 8312264f513SMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 8322264f513SMatthew Wilcox } 8332264f513SMatthew Wilcox 8342264f513SMatthew Wilcox static noinline void check_create_range(struct xarray *xa) 8352264f513SMatthew Wilcox { 8362264f513SMatthew Wilcox unsigned int order; 8372264f513SMatthew Wilcox unsigned int max_order = IS_ENABLED(CONFIG_XARRAY_MULTI) ? 12 : 1; 8382264f513SMatthew Wilcox 8392264f513SMatthew Wilcox for (order = 0; order < max_order; order++) { 8402264f513SMatthew Wilcox check_create_range_1(xa, 0, order); 8412264f513SMatthew Wilcox check_create_range_1(xa, 1U << order, order); 8422264f513SMatthew Wilcox check_create_range_1(xa, 2U << order, order); 8432264f513SMatthew Wilcox check_create_range_1(xa, 3U << order, order); 8442264f513SMatthew Wilcox check_create_range_1(xa, 1U << 24, order); 8452264f513SMatthew Wilcox if (order < 10) 8462264f513SMatthew Wilcox check_create_range_2(xa, order); 8472264f513SMatthew Wilcox 8482264f513SMatthew Wilcox check_create_range_4(xa, 0, order); 8492264f513SMatthew Wilcox check_create_range_4(xa, 1U << order, order); 8502264f513SMatthew Wilcox check_create_range_4(xa, 2U << order, order); 8512264f513SMatthew Wilcox check_create_range_4(xa, 3U << order, order); 8522264f513SMatthew Wilcox check_create_range_4(xa, 1U << 24, order); 8532264f513SMatthew Wilcox 8542264f513SMatthew Wilcox check_create_range_4(xa, 1, order); 8552264f513SMatthew Wilcox check_create_range_4(xa, (1U << order) + 1, order); 8562264f513SMatthew Wilcox check_create_range_4(xa, (2U << order) + 1, order); 8572264f513SMatthew Wilcox check_create_range_4(xa, (2U << order) - 1, order); 8582264f513SMatthew Wilcox check_create_range_4(xa, (3U << order) + 1, order); 8592264f513SMatthew Wilcox check_create_range_4(xa, (3U << order) - 1, order); 8602264f513SMatthew Wilcox check_create_range_4(xa, (1U << 24) + 1, order); 8612264f513SMatthew Wilcox } 8622264f513SMatthew Wilcox 8632264f513SMatthew Wilcox check_create_range_3(); 8642264f513SMatthew Wilcox } 8652264f513SMatthew Wilcox 866687149fcSMatthew Wilcox static noinline void check_destroy(struct xarray *xa) 867687149fcSMatthew Wilcox { 868687149fcSMatthew Wilcox unsigned long index; 869687149fcSMatthew Wilcox 870687149fcSMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 871687149fcSMatthew Wilcox 872687149fcSMatthew Wilcox /* Destroying an empty array is a no-op */ 873687149fcSMatthew Wilcox xa_destroy(xa); 874687149fcSMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 875687149fcSMatthew Wilcox 876687149fcSMatthew Wilcox /* Destroying an array with a single entry */ 877687149fcSMatthew Wilcox for (index = 0; index < 1000; index++) { 878687149fcSMatthew Wilcox xa_store_index(xa, index, GFP_KERNEL); 879687149fcSMatthew Wilcox XA_BUG_ON(xa, xa_empty(xa)); 880687149fcSMatthew Wilcox xa_destroy(xa); 881687149fcSMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 882687149fcSMatthew Wilcox } 883687149fcSMatthew Wilcox 884687149fcSMatthew Wilcox /* Destroying an array with a single entry at ULONG_MAX */ 885687149fcSMatthew Wilcox xa_store(xa, ULONG_MAX, xa, GFP_KERNEL); 886687149fcSMatthew Wilcox XA_BUG_ON(xa, xa_empty(xa)); 887687149fcSMatthew Wilcox xa_destroy(xa); 888687149fcSMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 889687149fcSMatthew Wilcox 890687149fcSMatthew Wilcox #ifdef CONFIG_XARRAY_MULTI 891687149fcSMatthew Wilcox /* Destroying an array with a multi-index entry */ 892687149fcSMatthew Wilcox xa_store_order(xa, 1 << 11, 11, xa, GFP_KERNEL); 893687149fcSMatthew Wilcox XA_BUG_ON(xa, xa_empty(xa)); 894687149fcSMatthew Wilcox xa_destroy(xa); 895687149fcSMatthew Wilcox XA_BUG_ON(xa, !xa_empty(xa)); 896687149fcSMatthew Wilcox #endif 897687149fcSMatthew Wilcox } 898687149fcSMatthew Wilcox 89958d6ea30SMatthew Wilcox static DEFINE_XARRAY(array); 900ad3d6c72SMatthew Wilcox 901ad3d6c72SMatthew Wilcox static int xarray_checks(void) 902ad3d6c72SMatthew Wilcox { 90358d6ea30SMatthew Wilcox check_xa_err(&array); 904b803b428SMatthew Wilcox check_xas_retry(&array); 905ad3d6c72SMatthew Wilcox check_xa_load(&array); 9069b89a035SMatthew Wilcox check_xa_mark(&array); 90758d6ea30SMatthew Wilcox check_xa_shrink(&array); 908b803b428SMatthew Wilcox check_xas_erase(&array); 90941aec91fSMatthew Wilcox check_cmpxchg(&array); 9109f14d4f1SMatthew Wilcox check_reserve(&array); 91158d6ea30SMatthew Wilcox check_multi_store(&array); 912*371c752dSMatthew Wilcox check_xa_alloc(); 913b803b428SMatthew Wilcox check_find(&array); 914687149fcSMatthew Wilcox check_destroy(&array); 91564d3e9a9SMatthew Wilcox check_move(&array); 9162264f513SMatthew Wilcox check_create_range(&array); 9174e99d4e9SMatthew Wilcox check_store_iter(&array); 918ad3d6c72SMatthew Wilcox 919ad3d6c72SMatthew Wilcox printk("XArray: %u of %u tests passed\n", tests_passed, tests_run); 920ad3d6c72SMatthew Wilcox return (tests_run == tests_passed) ? 0 : -EINVAL; 921ad3d6c72SMatthew Wilcox } 922ad3d6c72SMatthew Wilcox 923ad3d6c72SMatthew Wilcox static void xarray_exit(void) 924ad3d6c72SMatthew Wilcox { 925ad3d6c72SMatthew Wilcox } 926ad3d6c72SMatthew Wilcox 927ad3d6c72SMatthew Wilcox module_init(xarray_checks); 928ad3d6c72SMatthew Wilcox module_exit(xarray_exit); 929ad3d6c72SMatthew Wilcox MODULE_AUTHOR("Matthew Wilcox <[email protected]>"); 930ad3d6c72SMatthew Wilcox MODULE_LICENSE("GPL"); 931