[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAJuCfpFKjKAAyXgW_SFBXEp9N55txYdayw2h+=cSLO7wLvO2Pw@mail.gmail.com>
Date: Fri, 22 Aug 2025 13:18:08 -0700
From: Suren Baghdasaryan <surenb@...gle.com>
To: Vlastimil Babka <vbabka@...e.cz>
Cc: "Liam R. Howlett" <Liam.Howlett@...cle.com>, Christoph Lameter <cl@...two.org>,
David Rientjes <rientjes@...gle.com>, Roman Gushchin <roman.gushchin@...ux.dev>,
Harry Yoo <harry.yoo@...cle.com>, Uladzislau Rezki <urezki@...il.com>, linux-mm@...ck.org,
linux-kernel@...r.kernel.org, rcu@...r.kernel.org,
maple-tree@...ts.infradead.org
Subject: Re: [PATCH v5 12/14] maple_tree: Sheaf conversion
On Wed, Jul 23, 2025 at 6:35 AM Vlastimil Babka <vbabka@...e.cz> wrote:
>
> From: "Liam R. Howlett" <Liam.Howlett@...cle.com>
>
> Use sheaves instead of bulk allocations. This should speed up the
> allocations and the return path of unused allocations.
Nice cleanup!
>
> Remove push/pop of nodes from maple state.
> Remove unnecessary testing
> ifdef out other testing that probably will be deleted
Should we simply remove them if they are unused?
> Fix testcase for testing race
> Move some testing around in the same commit.
Would it be possible to separate test changes from kernel changes into
another patch? Kernel part looks good to me but I don't know enough
about these tests to vote on that.
>
> Signed-off-by: Liam R. Howlett <Liam.Howlett@...cle.com>
> Signed-off-by: Vlastimil Babka <vbabka@...e.cz>
> ---
> include/linux/maple_tree.h | 6 +-
> lib/maple_tree.c | 331 ++++----------------
> lib/test_maple_tree.c | 8 +
> tools/testing/radix-tree/maple.c | 632 +++++++--------------------------------
> tools/testing/shared/linux.c | 8 +-
> 5 files changed, 185 insertions(+), 800 deletions(-)
>
> diff --git a/include/linux/maple_tree.h b/include/linux/maple_tree.h
> index 9ef1290382249462d73ae72435dada7ce4b0622c..3cf1ae9dde7ce43fa20ae400c01fefad048c302e 100644
> --- a/include/linux/maple_tree.h
> +++ b/include/linux/maple_tree.h
> @@ -442,7 +442,8 @@ struct ma_state {
> struct maple_enode *node; /* The node containing this entry */
> unsigned long min; /* The minimum index of this node - implied pivot min */
> unsigned long max; /* The maximum index of this node - implied pivot max */
> - struct maple_alloc *alloc; /* Allocated nodes for this operation */
> + struct slab_sheaf *sheaf; /* Allocated nodes for this operation */
> + unsigned long node_request;
> enum maple_status status; /* The status of the state (active, start, none, etc) */
> unsigned char depth; /* depth of tree descent during write */
> unsigned char offset;
> @@ -490,7 +491,8 @@ struct ma_wr_state {
> .status = ma_start, \
> .min = 0, \
> .max = ULONG_MAX, \
> - .alloc = NULL, \
> + .node_request= 0, \
> + .sheaf = NULL, \
> .mas_flags = 0, \
> .store_type = wr_invalid, \
> }
> diff --git a/lib/maple_tree.c b/lib/maple_tree.c
> index 82f39fe29a462aa3c779789a28efdd6cdef64c79..3c3c14a76d98ded3b619c178d64099b464a2ca23 100644
> --- a/lib/maple_tree.c
> +++ b/lib/maple_tree.c
> @@ -198,6 +198,22 @@ static void mt_free_rcu(struct rcu_head *head)
> kmem_cache_free(maple_node_cache, node);
> }
>
> +static void mt_return_sheaf(struct slab_sheaf *sheaf)
> +{
> + kmem_cache_return_sheaf(maple_node_cache, GFP_KERNEL, sheaf);
> +}
> +
> +static struct slab_sheaf *mt_get_sheaf(gfp_t gfp, int count)
> +{
> + return kmem_cache_prefill_sheaf(maple_node_cache, gfp, count);
> +}
> +
> +static int mt_refill_sheaf(gfp_t gfp, struct slab_sheaf **sheaf,
> + unsigned int size)
> +{
> + return kmem_cache_refill_sheaf(maple_node_cache, gfp, sheaf, size);
> +}
> +
> /*
> * ma_free_rcu() - Use rcu callback to free a maple node
> * @node: The node to free
> @@ -590,67 +606,6 @@ static __always_inline bool mte_dead_node(const struct maple_enode *enode)
> return ma_dead_node(node);
> }
>
> -/*
> - * mas_allocated() - Get the number of nodes allocated in a maple state.
> - * @mas: The maple state
> - *
> - * The ma_state alloc member is overloaded to hold a pointer to the first
> - * allocated node or to the number of requested nodes to allocate. If bit 0 is
> - * set, then the alloc contains the number of requested nodes. If there is an
> - * allocated node, then the total allocated nodes is in that node.
> - *
> - * Return: The total number of nodes allocated
> - */
> -static inline unsigned long mas_allocated(const struct ma_state *mas)
> -{
> - if (!mas->alloc || ((unsigned long)mas->alloc & 0x1))
> - return 0;
> -
> - return mas->alloc->total;
> -}
> -
> -/*
> - * mas_set_alloc_req() - Set the requested number of allocations.
> - * @mas: the maple state
> - * @count: the number of allocations.
> - *
> - * The requested number of allocations is either in the first allocated node,
> - * located in @mas->alloc->request_count, or directly in @mas->alloc if there is
> - * no allocated node. Set the request either in the node or do the necessary
> - * encoding to store in @mas->alloc directly.
> - */
> -static inline void mas_set_alloc_req(struct ma_state *mas, unsigned long count)
> -{
> - if (!mas->alloc || ((unsigned long)mas->alloc & 0x1)) {
> - if (!count)
> - mas->alloc = NULL;
> - else
> - mas->alloc = (struct maple_alloc *)(((count) << 1U) | 1U);
> - return;
> - }
> -
> - mas->alloc->request_count = count;
> -}
> -
> -/*
> - * mas_alloc_req() - get the requested number of allocations.
> - * @mas: The maple state
> - *
> - * The alloc count is either stored directly in @mas, or in
> - * @mas->alloc->request_count if there is at least one node allocated. Decode
> - * the request count if it's stored directly in @mas->alloc.
> - *
> - * Return: The allocation request count.
> - */
> -static inline unsigned int mas_alloc_req(const struct ma_state *mas)
> -{
> - if ((unsigned long)mas->alloc & 0x1)
> - return (unsigned long)(mas->alloc) >> 1;
> - else if (mas->alloc)
> - return mas->alloc->request_count;
> - return 0;
> -}
> -
> /*
> * ma_pivots() - Get a pointer to the maple node pivots.
> * @node: the maple node
> @@ -1148,77 +1103,15 @@ static int mas_ascend(struct ma_state *mas)
> */
> static inline struct maple_node *mas_pop_node(struct ma_state *mas)
> {
> - struct maple_alloc *ret, *node = mas->alloc;
> - unsigned long total = mas_allocated(mas);
> - unsigned int req = mas_alloc_req(mas);
> + struct maple_node *ret;
>
> - /* nothing or a request pending. */
> - if (WARN_ON(!total))
> + if (WARN_ON_ONCE(!mas->sheaf))
> return NULL;
>
> - if (total == 1) {
> - /* single allocation in this ma_state */
> - mas->alloc = NULL;
> - ret = node;
> - goto single_node;
> - }
> -
> - if (node->node_count == 1) {
> - /* Single allocation in this node. */
> - mas->alloc = node->slot[0];
> - mas->alloc->total = node->total - 1;
> - ret = node;
> - goto new_head;
> - }
> - node->total--;
> - ret = node->slot[--node->node_count];
> - node->slot[node->node_count] = NULL;
> -
> -single_node:
> -new_head:
> - if (req) {
> - req++;
> - mas_set_alloc_req(mas, req);
> - }
> -
> + ret = kmem_cache_alloc_from_sheaf(maple_node_cache, GFP_NOWAIT, mas->sheaf);
> memset(ret, 0, sizeof(*ret));
> - return (struct maple_node *)ret;
> -}
> -
> -/*
> - * mas_push_node() - Push a node back on the maple state allocation.
> - * @mas: The maple state
> - * @used: The used maple node
> - *
> - * Stores the maple node back into @mas->alloc for reuse. Updates allocated and
> - * requested node count as necessary.
> - */
> -static inline void mas_push_node(struct ma_state *mas, struct maple_node *used)
> -{
> - struct maple_alloc *reuse = (struct maple_alloc *)used;
> - struct maple_alloc *head = mas->alloc;
> - unsigned long count;
> - unsigned int requested = mas_alloc_req(mas);
> -
> - count = mas_allocated(mas);
>
> - reuse->request_count = 0;
> - reuse->node_count = 0;
> - if (count) {
> - if (head->node_count < MAPLE_ALLOC_SLOTS) {
> - head->slot[head->node_count++] = reuse;
> - head->total++;
> - goto done;
> - }
> - reuse->slot[0] = head;
> - reuse->node_count = 1;
> - }
> -
> - reuse->total = count + 1;
> - mas->alloc = reuse;
> -done:
> - if (requested > 1)
> - mas_set_alloc_req(mas, requested - 1);
> + return ret;
> }
>
> /*
> @@ -1228,75 +1121,32 @@ static inline void mas_push_node(struct ma_state *mas, struct maple_node *used)
> */
> static inline void mas_alloc_nodes(struct ma_state *mas, gfp_t gfp)
> {
> - struct maple_alloc *node;
> - unsigned long allocated = mas_allocated(mas);
> - unsigned int requested = mas_alloc_req(mas);
> - unsigned int count;
> - void **slots = NULL;
> - unsigned int max_req = 0;
> -
> - if (!requested)
> - return;
> + if (unlikely(mas->sheaf)) {
> + unsigned long refill = mas->node_request;
>
> - mas_set_alloc_req(mas, 0);
> - if (mas->mas_flags & MA_STATE_PREALLOC) {
> - if (allocated)
> + if(kmem_cache_sheaf_size(mas->sheaf) >= refill) {
> + mas->node_request = 0;
> return;
> - WARN_ON(!allocated);
> - }
> -
> - if (!allocated || mas->alloc->node_count == MAPLE_ALLOC_SLOTS) {
> - node = (struct maple_alloc *)mt_alloc_one(gfp);
> - if (!node)
> - goto nomem_one;
> -
> - if (allocated) {
> - node->slot[0] = mas->alloc;
> - node->node_count = 1;
> - } else {
> - node->node_count = 0;
> }
>
> - mas->alloc = node;
> - node->total = ++allocated;
> - node->request_count = 0;
> - requested--;
> - }
> + if (mt_refill_sheaf(gfp, &mas->sheaf, refill))
> + goto error;
>
> - node = mas->alloc;
> - while (requested) {
> - max_req = MAPLE_ALLOC_SLOTS - node->node_count;
> - slots = (void **)&node->slot[node->node_count];
> - max_req = min(requested, max_req);
> - count = mt_alloc_bulk(gfp, max_req, slots);
> - if (!count)
> - goto nomem_bulk;
> -
> - if (node->node_count == 0) {
> - node->slot[0]->node_count = 0;
> - node->slot[0]->request_count = 0;
> - }
> + mas->node_request = 0;
> + return;
> + }
>
> - node->node_count += count;
> - allocated += count;
> - /* find a non-full node*/
> - do {
> - node = node->slot[0];
> - } while (unlikely(node->node_count == MAPLE_ALLOC_SLOTS));
> - requested -= count;
> + mas->sheaf = mt_get_sheaf(gfp, mas->node_request);
> + if (likely(mas->sheaf)) {
> + mas->node_request = 0;
> + return;
> }
> - mas->alloc->total = allocated;
> - return;
>
> -nomem_bulk:
> - /* Clean up potential freed allocations on bulk failure */
> - memset(slots, 0, max_req * sizeof(unsigned long));
> - mas->alloc->total = allocated;
> -nomem_one:
> - mas_set_alloc_req(mas, requested);
> +error:
> mas_set_err(mas, -ENOMEM);
> }
>
> +
> /*
> * mas_free() - Free an encoded maple node
> * @mas: The maple state
> @@ -1307,42 +1157,7 @@ static inline void mas_alloc_nodes(struct ma_state *mas, gfp_t gfp)
> */
> static inline void mas_free(struct ma_state *mas, struct maple_enode *used)
> {
> - struct maple_node *tmp = mte_to_node(used);
> -
> - if (mt_in_rcu(mas->tree))
> - ma_free_rcu(tmp);
> - else
> - mas_push_node(mas, tmp);
> -}
> -
> -/*
> - * mas_node_count_gfp() - Check if enough nodes are allocated and request more
> - * if there is not enough nodes.
> - * @mas: The maple state
> - * @count: The number of nodes needed
> - * @gfp: the gfp flags
> - */
> -static void mas_node_count_gfp(struct ma_state *mas, int count, gfp_t gfp)
> -{
> - unsigned long allocated = mas_allocated(mas);
> -
> - if (allocated < count) {
> - mas_set_alloc_req(mas, count - allocated);
> - mas_alloc_nodes(mas, gfp);
> - }
> -}
> -
> -/*
> - * mas_node_count() - Check if enough nodes are allocated and request more if
> - * there is not enough nodes.
> - * @mas: The maple state
> - * @count: The number of nodes needed
> - *
> - * Note: Uses GFP_NOWAIT | __GFP_NOWARN for gfp flags.
> - */
> -static void mas_node_count(struct ma_state *mas, int count)
> -{
> - return mas_node_count_gfp(mas, count, GFP_NOWAIT | __GFP_NOWARN);
> + ma_free_rcu(mte_to_node(used));
> }
>
> /*
> @@ -2517,10 +2332,7 @@ static inline void mas_topiary_node(struct ma_state *mas,
> enode = tmp_mas->node;
> tmp = mte_to_node(enode);
> mte_set_node_dead(enode);
> - if (in_rcu)
> - ma_free_rcu(tmp);
> - else
> - mas_push_node(mas, tmp);
> + ma_free_rcu(tmp);
> }
>
> /*
> @@ -4168,7 +3980,7 @@ static inline void mas_wr_prealloc_setup(struct ma_wr_state *wr_mas)
> *
> * Return: Number of nodes required for preallocation.
> */
> -static inline int mas_prealloc_calc(struct ma_wr_state *wr_mas, void *entry)
> +static inline void mas_prealloc_calc(struct ma_wr_state *wr_mas, void *entry)
> {
> struct ma_state *mas = wr_mas->mas;
> unsigned char height = mas_mt_height(mas);
> @@ -4214,7 +4026,7 @@ static inline int mas_prealloc_calc(struct ma_wr_state *wr_mas, void *entry)
> WARN_ON_ONCE(1);
> }
>
> - return ret;
> + mas->node_request = ret;
> }
>
> /*
> @@ -4275,15 +4087,15 @@ static inline enum store_type mas_wr_store_type(struct ma_wr_state *wr_mas)
> */
> static inline void mas_wr_preallocate(struct ma_wr_state *wr_mas, void *entry)
> {
> - int request;
> + struct ma_state *mas = wr_mas->mas;
>
> mas_wr_prealloc_setup(wr_mas);
> - wr_mas->mas->store_type = mas_wr_store_type(wr_mas);
> - request = mas_prealloc_calc(wr_mas, entry);
> - if (!request)
> + mas->store_type = mas_wr_store_type(wr_mas);
> + mas_prealloc_calc(wr_mas, entry);
> + if (!mas->node_request)
> return;
>
> - mas_node_count(wr_mas->mas, request);
> + mas_alloc_nodes(mas, GFP_NOWAIT | __GFP_NOWARN);
> }
>
> /**
> @@ -5398,7 +5210,6 @@ static inline void mte_destroy_walk(struct maple_enode *enode,
> */
> void *mas_store(struct ma_state *mas, void *entry)
> {
> - int request;
> MA_WR_STATE(wr_mas, mas, entry);
>
> trace_ma_write(__func__, mas, 0, entry);
> @@ -5428,11 +5239,11 @@ void *mas_store(struct ma_state *mas, void *entry)
> return wr_mas.content;
> }
>
> - request = mas_prealloc_calc(&wr_mas, entry);
> - if (!request)
> + mas_prealloc_calc(&wr_mas, entry);
> + if (!mas->node_request)
> goto store;
>
> - mas_node_count(mas, request);
> + mas_alloc_nodes(mas, GFP_NOWAIT | __GFP_NOWARN);
> if (mas_is_err(mas))
> return NULL;
>
> @@ -5520,26 +5331,25 @@ EXPORT_SYMBOL_GPL(mas_store_prealloc);
> int mas_preallocate(struct ma_state *mas, void *entry, gfp_t gfp)
> {
> MA_WR_STATE(wr_mas, mas, entry);
> - int ret = 0;
> - int request;
>
> mas_wr_prealloc_setup(&wr_mas);
> mas->store_type = mas_wr_store_type(&wr_mas);
> - request = mas_prealloc_calc(&wr_mas, entry);
> - if (!request)
> - return ret;
> + mas_prealloc_calc(&wr_mas, entry);
> + if (!mas->node_request)
> + return 0;
>
> - mas_node_count_gfp(mas, request, gfp);
> + mas_alloc_nodes(mas, gfp);
> if (mas_is_err(mas)) {
> - mas_set_alloc_req(mas, 0);
> - ret = xa_err(mas->node);
> + int ret = xa_err(mas->node);
> +
> + mas->node_request = 0;
> mas_destroy(mas);
> mas_reset(mas);
> return ret;
> }
>
> mas->mas_flags |= MA_STATE_PREALLOC;
> - return ret;
> + return 0;
> }
> EXPORT_SYMBOL_GPL(mas_preallocate);
>
> @@ -5553,9 +5363,6 @@ EXPORT_SYMBOL_GPL(mas_preallocate);
> */
> void mas_destroy(struct ma_state *mas)
> {
> - struct maple_alloc *node;
> - unsigned long total;
> -
> /*
> * When using mas_for_each() to insert an expected number of elements,
> * it is possible that the number inserted is less than the expected
> @@ -5576,21 +5383,11 @@ void mas_destroy(struct ma_state *mas)
> }
> mas->mas_flags &= ~(MA_STATE_BULK|MA_STATE_PREALLOC);
>
> - total = mas_allocated(mas);
> - while (total) {
> - node = mas->alloc;
> - mas->alloc = node->slot[0];
> - if (node->node_count > 1) {
> - size_t count = node->node_count - 1;
> -
> - mt_free_bulk(count, (void __rcu **)&node->slot[1]);
> - total -= count;
> - }
> - mt_free_one(ma_mnode_ptr(node));
> - total--;
> - }
> + mas->node_request = 0;
> + if (mas->sheaf)
> + mt_return_sheaf(mas->sheaf);
>
> - mas->alloc = NULL;
> + mas->sheaf = NULL;
> }
> EXPORT_SYMBOL_GPL(mas_destroy);
>
> @@ -5640,7 +5437,8 @@ int mas_expected_entries(struct ma_state *mas, unsigned long nr_entries)
> /* Internal nodes */
> nr_nodes += DIV_ROUND_UP(nr_nodes, nonleaf_cap);
> /* Add working room for split (2 nodes) + new parents */
> - mas_node_count_gfp(mas, nr_nodes + 3, GFP_KERNEL);
> + mas->node_request = nr_nodes + 3;
> + mas_alloc_nodes(mas, GFP_KERNEL);
>
> /* Detect if allocations run out */
> mas->mas_flags |= MA_STATE_PREALLOC;
> @@ -6276,7 +6074,7 @@ bool mas_nomem(struct ma_state *mas, gfp_t gfp)
> mas_alloc_nodes(mas, gfp);
> }
>
> - if (!mas_allocated(mas))
> + if (!mas->sheaf)
> return false;
>
> mas->status = ma_start;
> @@ -7671,8 +7469,9 @@ void mas_dump(const struct ma_state *mas)
>
> pr_err("[%u/%u] index=%lx last=%lx\n", mas->offset, mas->end,
> mas->index, mas->last);
> - pr_err(" min=%lx max=%lx alloc=" PTR_FMT ", depth=%u, flags=%x\n",
> - mas->min, mas->max, mas->alloc, mas->depth, mas->mas_flags);
> + pr_err(" min=%lx max=%lx sheaf=" PTR_FMT ", request %lu depth=%u, flags=%x\n",
> + mas->min, mas->max, mas->sheaf, mas->node_request, mas->depth,
> + mas->mas_flags);
> if (mas->index > mas->last)
> pr_err("Check index & last\n");
> }
> diff --git a/lib/test_maple_tree.c b/lib/test_maple_tree.c
> index 13e2a10d7554d6b1de5ffbda59f3a5bc4039a8c8..5549eb4200c7974e3bb457e0fd054c434e4b85da 100644
> --- a/lib/test_maple_tree.c
> +++ b/lib/test_maple_tree.c
> @@ -2746,6 +2746,7 @@ static noinline void __init check_fuzzer(struct maple_tree *mt)
> mtree_test_erase(mt, ULONG_MAX - 10);
> }
>
> +#if 0
> /* duplicate the tree with a specific gap */
> static noinline void __init check_dup_gaps(struct maple_tree *mt,
> unsigned long nr_entries, bool zero_start,
> @@ -2770,6 +2771,7 @@ static noinline void __init check_dup_gaps(struct maple_tree *mt,
> mtree_store_range(mt, i*10, (i+1)*10 - gap,
> xa_mk_value(i), GFP_KERNEL);
>
> + mt_dump(mt, mt_dump_dec);
> mt_init_flags(&newmt, MT_FLAGS_ALLOC_RANGE | MT_FLAGS_LOCK_EXTERN);
> mt_set_non_kernel(99999);
> down_write(&newmt_lock);
> @@ -2779,9 +2781,12 @@ static noinline void __init check_dup_gaps(struct maple_tree *mt,
>
> rcu_read_lock();
> mas_for_each(&mas, tmp, ULONG_MAX) {
> + printk("%lu nodes %lu\n", mas.index,
> + kmem_cache_sheaf_count(newmas.sheaf));
> newmas.index = mas.index;
> newmas.last = mas.last;
> mas_store(&newmas, tmp);
> + mt_dump(&newmt, mt_dump_dec);
> }
> rcu_read_unlock();
> mas_destroy(&newmas);
> @@ -2878,6 +2883,7 @@ static noinline void __init check_dup(struct maple_tree *mt)
> cond_resched();
> }
> }
> +#endif
>
> static noinline void __init check_bnode_min_spanning(struct maple_tree *mt)
> {
> @@ -4045,9 +4051,11 @@ static int __init maple_tree_seed(void)
> check_fuzzer(&tree);
> mtree_destroy(&tree);
>
> +#if 0
> mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
> check_dup(&tree);
> mtree_destroy(&tree);
> +#endif
>
> mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
> check_bnode_min_spanning(&tree);
> diff --git a/tools/testing/radix-tree/maple.c b/tools/testing/radix-tree/maple.c
> index f6f923c9dc1039997953a94ec184c560b225c2d4..1bd789191f232385d69f2dd3e900bac99d8919ff 100644
> --- a/tools/testing/radix-tree/maple.c
> +++ b/tools/testing/radix-tree/maple.c
> @@ -63,430 +63,6 @@ struct rcu_reader_struct {
> struct rcu_test_struct2 *test;
> };
>
> -static int get_alloc_node_count(struct ma_state *mas)
> -{
> - int count = 1;
> - struct maple_alloc *node = mas->alloc;
> -
> - if (!node || ((unsigned long)node & 0x1))
> - return 0;
> - while (node->node_count) {
> - count += node->node_count;
> - node = node->slot[0];
> - }
> - return count;
> -}
> -
> -static void check_mas_alloc_node_count(struct ma_state *mas)
> -{
> - mas_node_count_gfp(mas, MAPLE_ALLOC_SLOTS + 1, GFP_KERNEL);
> - mas_node_count_gfp(mas, MAPLE_ALLOC_SLOTS + 3, GFP_KERNEL);
> - MT_BUG_ON(mas->tree, get_alloc_node_count(mas) != mas->alloc->total);
> - mas_destroy(mas);
> -}
> -
> -/*
> - * check_new_node() - Check the creation of new nodes and error path
> - * verification.
> - */
> -static noinline void __init check_new_node(struct maple_tree *mt)
> -{
> -
> - struct maple_node *mn, *mn2, *mn3;
> - struct maple_alloc *smn;
> - struct maple_node *nodes[100];
> - int i, j, total;
> -
> - MA_STATE(mas, mt, 0, 0);
> -
> - check_mas_alloc_node_count(&mas);
> -
> - /* Try allocating 3 nodes */
> - mtree_lock(mt);
> - mt_set_non_kernel(0);
> - /* request 3 nodes to be allocated. */
> - mas_node_count(&mas, 3);
> - /* Allocation request of 3. */
> - MT_BUG_ON(mt, mas_alloc_req(&mas) != 3);
> - /* Allocate failed. */
> - MT_BUG_ON(mt, mas.node != MA_ERROR(-ENOMEM));
> - MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
> -
> - MT_BUG_ON(mt, mas_allocated(&mas) != 3);
> - mn = mas_pop_node(&mas);
> - MT_BUG_ON(mt, not_empty(mn));
> - MT_BUG_ON(mt, mn == NULL);
> - MT_BUG_ON(mt, mas.alloc == NULL);
> - MT_BUG_ON(mt, mas.alloc->slot[0] == NULL);
> - mas_push_node(&mas, mn);
> - mas_reset(&mas);
> - mas_destroy(&mas);
> - mtree_unlock(mt);
> -
> -
> - /* Try allocating 1 node, then 2 more */
> - mtree_lock(mt);
> - /* Set allocation request to 1. */
> - mas_set_alloc_req(&mas, 1);
> - /* Check Allocation request of 1. */
> - MT_BUG_ON(mt, mas_alloc_req(&mas) != 1);
> - mas_set_err(&mas, -ENOMEM);
> - /* Validate allocation request. */
> - MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
> - /* Eat the requested node. */
> - mn = mas_pop_node(&mas);
> - MT_BUG_ON(mt, not_empty(mn));
> - MT_BUG_ON(mt, mn == NULL);
> - MT_BUG_ON(mt, mn->slot[0] != NULL);
> - MT_BUG_ON(mt, mn->slot[1] != NULL);
> - MT_BUG_ON(mt, mas_allocated(&mas) != 0);
> -
> - mn->parent = ma_parent_ptr(mn);
> - ma_free_rcu(mn);
> - mas.status = ma_start;
> - mas_destroy(&mas);
> - /* Allocate 3 nodes, will fail. */
> - mas_node_count(&mas, 3);
> - /* Drop the lock and allocate 3 nodes. */
> - mas_nomem(&mas, GFP_KERNEL);
> - /* Ensure 3 are allocated. */
> - MT_BUG_ON(mt, mas_allocated(&mas) != 3);
> - /* Allocation request of 0. */
> - MT_BUG_ON(mt, mas_alloc_req(&mas) != 0);
> -
> - MT_BUG_ON(mt, mas.alloc == NULL);
> - MT_BUG_ON(mt, mas.alloc->slot[0] == NULL);
> - MT_BUG_ON(mt, mas.alloc->slot[1] == NULL);
> - /* Ensure we counted 3. */
> - MT_BUG_ON(mt, mas_allocated(&mas) != 3);
> - /* Free. */
> - mas_reset(&mas);
> - mas_destroy(&mas);
> -
> - /* Set allocation request to 1. */
> - mas_set_alloc_req(&mas, 1);
> - MT_BUG_ON(mt, mas_alloc_req(&mas) != 1);
> - mas_set_err(&mas, -ENOMEM);
> - /* Validate allocation request. */
> - MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
> - MT_BUG_ON(mt, mas_allocated(&mas) != 1);
> - /* Check the node is only one node. */
> - mn = mas_pop_node(&mas);
> - MT_BUG_ON(mt, not_empty(mn));
> - MT_BUG_ON(mt, mas_allocated(&mas) != 0);
> - MT_BUG_ON(mt, mn == NULL);
> - MT_BUG_ON(mt, mn->slot[0] != NULL);
> - MT_BUG_ON(mt, mn->slot[1] != NULL);
> - MT_BUG_ON(mt, mas_allocated(&mas) != 0);
> - mas_push_node(&mas, mn);
> - MT_BUG_ON(mt, mas_allocated(&mas) != 1);
> - MT_BUG_ON(mt, mas.alloc->node_count);
> -
> - mas_set_alloc_req(&mas, 2); /* request 2 more. */
> - MT_BUG_ON(mt, mas_alloc_req(&mas) != 2);
> - mas_set_err(&mas, -ENOMEM);
> - MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
> - MT_BUG_ON(mt, mas_allocated(&mas) != 3);
> - MT_BUG_ON(mt, mas.alloc == NULL);
> - MT_BUG_ON(mt, mas.alloc->slot[0] == NULL);
> - MT_BUG_ON(mt, mas.alloc->slot[1] == NULL);
> - for (i = 2; i >= 0; i--) {
> - mn = mas_pop_node(&mas);
> - MT_BUG_ON(mt, mas_allocated(&mas) != i);
> - MT_BUG_ON(mt, !mn);
> - MT_BUG_ON(mt, not_empty(mn));
> - mn->parent = ma_parent_ptr(mn);
> - ma_free_rcu(mn);
> - }
> -
> - total = 64;
> - mas_set_alloc_req(&mas, total); /* request 2 more. */
> - MT_BUG_ON(mt, mas_alloc_req(&mas) != total);
> - mas_set_err(&mas, -ENOMEM);
> - MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
> - for (i = total; i > 0; i--) {
> - unsigned int e = 0; /* expected node_count */
> -
> - if (!MAPLE_32BIT) {
> - if (i >= 35)
> - e = i - 34;
> - else if (i >= 5)
> - e = i - 4;
> - else if (i >= 2)
> - e = i - 1;
> - } else {
> - if (i >= 4)
> - e = i - 3;
> - else if (i >= 1)
> - e = i - 1;
> - else
> - e = 0;
> - }
> -
> - MT_BUG_ON(mt, mas.alloc->node_count != e);
> - mn = mas_pop_node(&mas);
> - MT_BUG_ON(mt, not_empty(mn));
> - MT_BUG_ON(mt, mas_allocated(&mas) != i - 1);
> - MT_BUG_ON(mt, !mn);
> - mn->parent = ma_parent_ptr(mn);
> - ma_free_rcu(mn);
> - }
> -
> - total = 100;
> - for (i = 1; i < total; i++) {
> - mas_set_alloc_req(&mas, i);
> - mas_set_err(&mas, -ENOMEM);
> - MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
> - for (j = i; j > 0; j--) {
> - mn = mas_pop_node(&mas);
> - MT_BUG_ON(mt, mas_allocated(&mas) != j - 1);
> - MT_BUG_ON(mt, !mn);
> - MT_BUG_ON(mt, not_empty(mn));
> - mas_push_node(&mas, mn);
> - MT_BUG_ON(mt, mas_allocated(&mas) != j);
> - mn = mas_pop_node(&mas);
> - MT_BUG_ON(mt, not_empty(mn));
> - MT_BUG_ON(mt, mas_allocated(&mas) != j - 1);
> - mn->parent = ma_parent_ptr(mn);
> - ma_free_rcu(mn);
> - }
> - MT_BUG_ON(mt, mas_allocated(&mas) != 0);
> -
> - mas_set_alloc_req(&mas, i);
> - mas_set_err(&mas, -ENOMEM);
> - MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
> - for (j = 0; j <= i/2; j++) {
> - MT_BUG_ON(mt, mas_allocated(&mas) != i - j);
> - nodes[j] = mas_pop_node(&mas);
> - MT_BUG_ON(mt, mas_allocated(&mas) != i - j - 1);
> - }
> -
> - while (j) {
> - j--;
> - mas_push_node(&mas, nodes[j]);
> - MT_BUG_ON(mt, mas_allocated(&mas) != i - j);
> - }
> - MT_BUG_ON(mt, mas_allocated(&mas) != i);
> - for (j = 0; j <= i/2; j++) {
> - MT_BUG_ON(mt, mas_allocated(&mas) != i - j);
> - mn = mas_pop_node(&mas);
> - MT_BUG_ON(mt, not_empty(mn));
> - mn->parent = ma_parent_ptr(mn);
> - ma_free_rcu(mn);
> - MT_BUG_ON(mt, mas_allocated(&mas) != i - j - 1);
> - }
> - mas_reset(&mas);
> - MT_BUG_ON(mt, mas_nomem(&mas, GFP_KERNEL));
> - mas_destroy(&mas);
> -
> - }
> -
> - /* Set allocation request. */
> - total = 500;
> - mas_node_count(&mas, total);
> - /* Drop the lock and allocate the nodes. */
> - mas_nomem(&mas, GFP_KERNEL);
> - MT_BUG_ON(mt, !mas.alloc);
> - i = 1;
> - smn = mas.alloc;
> - while (i < total) {
> - for (j = 0; j < MAPLE_ALLOC_SLOTS; j++) {
> - i++;
> - MT_BUG_ON(mt, !smn->slot[j]);
> - if (i == total)
> - break;
> - }
> - smn = smn->slot[0]; /* next. */
> - }
> - MT_BUG_ON(mt, mas_allocated(&mas) != total);
> - mas_reset(&mas);
> - mas_destroy(&mas); /* Free. */
> -
> - MT_BUG_ON(mt, mas_allocated(&mas) != 0);
> - for (i = 1; i < 128; i++) {
> - mas_node_count(&mas, i); /* Request */
> - mas_nomem(&mas, GFP_KERNEL); /* Fill request */
> - MT_BUG_ON(mt, mas_allocated(&mas) != i); /* check request filled */
> - for (j = i; j > 0; j--) { /*Free the requests */
> - mn = mas_pop_node(&mas); /* get the next node. */
> - MT_BUG_ON(mt, mn == NULL);
> - MT_BUG_ON(mt, not_empty(mn));
> - mn->parent = ma_parent_ptr(mn);
> - ma_free_rcu(mn);
> - }
> - MT_BUG_ON(mt, mas_allocated(&mas) != 0);
> - }
> -
> - for (i = 1; i < MAPLE_NODE_MASK + 1; i++) {
> - MA_STATE(mas2, mt, 0, 0);
> - mas_node_count(&mas, i); /* Request */
> - mas_nomem(&mas, GFP_KERNEL); /* Fill request */
> - MT_BUG_ON(mt, mas_allocated(&mas) != i); /* check request filled */
> - for (j = 1; j <= i; j++) { /* Move the allocations to mas2 */
> - mn = mas_pop_node(&mas); /* get the next node. */
> - MT_BUG_ON(mt, mn == NULL);
> - MT_BUG_ON(mt, not_empty(mn));
> - mas_push_node(&mas2, mn);
> - MT_BUG_ON(mt, mas_allocated(&mas2) != j);
> - }
> - MT_BUG_ON(mt, mas_allocated(&mas) != 0);
> - MT_BUG_ON(mt, mas_allocated(&mas2) != i);
> -
> - for (j = i; j > 0; j--) { /*Free the requests */
> - MT_BUG_ON(mt, mas_allocated(&mas2) != j);
> - mn = mas_pop_node(&mas2); /* get the next node. */
> - MT_BUG_ON(mt, mn == NULL);
> - MT_BUG_ON(mt, not_empty(mn));
> - mn->parent = ma_parent_ptr(mn);
> - ma_free_rcu(mn);
> - }
> - MT_BUG_ON(mt, mas_allocated(&mas2) != 0);
> - }
> -
> -
> - MT_BUG_ON(mt, mas_allocated(&mas) != 0);
> - mas_node_count(&mas, MAPLE_ALLOC_SLOTS + 1); /* Request */
> - MT_BUG_ON(mt, mas.node != MA_ERROR(-ENOMEM));
> - MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
> - MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS + 1);
> - MT_BUG_ON(mt, mas.alloc->node_count != MAPLE_ALLOC_SLOTS);
> -
> - mn = mas_pop_node(&mas); /* get the next node. */
> - MT_BUG_ON(mt, mn == NULL);
> - MT_BUG_ON(mt, not_empty(mn));
> - MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS);
> - MT_BUG_ON(mt, mas.alloc->node_count != MAPLE_ALLOC_SLOTS - 1);
> -
> - mas_push_node(&mas, mn);
> - MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS + 1);
> - MT_BUG_ON(mt, mas.alloc->node_count != MAPLE_ALLOC_SLOTS);
> -
> - /* Check the limit of pop/push/pop */
> - mas_node_count(&mas, MAPLE_ALLOC_SLOTS + 2); /* Request */
> - MT_BUG_ON(mt, mas_alloc_req(&mas) != 1);
> - MT_BUG_ON(mt, mas.node != MA_ERROR(-ENOMEM));
> - MT_BUG_ON(mt, !mas_nomem(&mas, GFP_KERNEL));
> - MT_BUG_ON(mt, mas_alloc_req(&mas));
> - MT_BUG_ON(mt, mas.alloc->node_count != 1);
> - MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS + 2);
> - mn = mas_pop_node(&mas);
> - MT_BUG_ON(mt, not_empty(mn));
> - MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS + 1);
> - MT_BUG_ON(mt, mas.alloc->node_count != MAPLE_ALLOC_SLOTS);
> - mas_push_node(&mas, mn);
> - MT_BUG_ON(mt, mas.alloc->node_count != 1);
> - MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS + 2);
> - mn = mas_pop_node(&mas);
> - MT_BUG_ON(mt, not_empty(mn));
> - mn->parent = ma_parent_ptr(mn);
> - ma_free_rcu(mn);
> - for (i = 1; i <= MAPLE_ALLOC_SLOTS + 1; i++) {
> - mn = mas_pop_node(&mas);
> - MT_BUG_ON(mt, not_empty(mn));
> - mn->parent = ma_parent_ptr(mn);
> - ma_free_rcu(mn);
> - }
> - MT_BUG_ON(mt, mas_allocated(&mas) != 0);
> -
> -
> - for (i = 3; i < MAPLE_NODE_MASK * 3; i++) {
> - mas.node = MA_ERROR(-ENOMEM);
> - mas_node_count(&mas, i); /* Request */
> - mas_nomem(&mas, GFP_KERNEL); /* Fill request */
> - mn = mas_pop_node(&mas); /* get the next node. */
> - mas_push_node(&mas, mn); /* put it back */
> - mas_destroy(&mas);
> -
> - mas.node = MA_ERROR(-ENOMEM);
> - mas_node_count(&mas, i); /* Request */
> - mas_nomem(&mas, GFP_KERNEL); /* Fill request */
> - mn = mas_pop_node(&mas); /* get the next node. */
> - mn2 = mas_pop_node(&mas); /* get the next node. */
> - mas_push_node(&mas, mn); /* put them back */
> - mas_push_node(&mas, mn2);
> - mas_destroy(&mas);
> -
> - mas.node = MA_ERROR(-ENOMEM);
> - mas_node_count(&mas, i); /* Request */
> - mas_nomem(&mas, GFP_KERNEL); /* Fill request */
> - mn = mas_pop_node(&mas); /* get the next node. */
> - mn2 = mas_pop_node(&mas); /* get the next node. */
> - mn3 = mas_pop_node(&mas); /* get the next node. */
> - mas_push_node(&mas, mn); /* put them back */
> - mas_push_node(&mas, mn2);
> - mas_push_node(&mas, mn3);
> - mas_destroy(&mas);
> -
> - mas.node = MA_ERROR(-ENOMEM);
> - mas_node_count(&mas, i); /* Request */
> - mas_nomem(&mas, GFP_KERNEL); /* Fill request */
> - mn = mas_pop_node(&mas); /* get the next node. */
> - mn->parent = ma_parent_ptr(mn);
> - ma_free_rcu(mn);
> - mas_destroy(&mas);
> -
> - mas.node = MA_ERROR(-ENOMEM);
> - mas_node_count(&mas, i); /* Request */
> - mas_nomem(&mas, GFP_KERNEL); /* Fill request */
> - mn = mas_pop_node(&mas); /* get the next node. */
> - mn->parent = ma_parent_ptr(mn);
> - ma_free_rcu(mn);
> - mn = mas_pop_node(&mas); /* get the next node. */
> - mn->parent = ma_parent_ptr(mn);
> - ma_free_rcu(mn);
> - mn = mas_pop_node(&mas); /* get the next node. */
> - mn->parent = ma_parent_ptr(mn);
> - ma_free_rcu(mn);
> - mas_destroy(&mas);
> - }
> -
> - mas.node = MA_ERROR(-ENOMEM);
> - mas_node_count(&mas, 5); /* Request */
> - mas_nomem(&mas, GFP_KERNEL); /* Fill request */
> - MT_BUG_ON(mt, mas_allocated(&mas) != 5);
> - mas.node = MA_ERROR(-ENOMEM);
> - mas_node_count(&mas, 10); /* Request */
> - mas_nomem(&mas, GFP_KERNEL); /* Fill request */
> - mas.status = ma_start;
> - MT_BUG_ON(mt, mas_allocated(&mas) != 10);
> - mas_destroy(&mas);
> -
> - mas.node = MA_ERROR(-ENOMEM);
> - mas_node_count(&mas, MAPLE_ALLOC_SLOTS - 1); /* Request */
> - mas_nomem(&mas, GFP_KERNEL); /* Fill request */
> - MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS - 1);
> - mas.node = MA_ERROR(-ENOMEM);
> - mas_node_count(&mas, 10 + MAPLE_ALLOC_SLOTS - 1); /* Request */
> - mas_nomem(&mas, GFP_KERNEL); /* Fill request */
> - mas.status = ma_start;
> - MT_BUG_ON(mt, mas_allocated(&mas) != 10 + MAPLE_ALLOC_SLOTS - 1);
> - mas_destroy(&mas);
> -
> - mas.node = MA_ERROR(-ENOMEM);
> - mas_node_count(&mas, MAPLE_ALLOC_SLOTS + 1); /* Request */
> - mas_nomem(&mas, GFP_KERNEL); /* Fill request */
> - MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS + 1);
> - mas.node = MA_ERROR(-ENOMEM);
> - mas_node_count(&mas, MAPLE_ALLOC_SLOTS * 2 + 2); /* Request */
> - mas_nomem(&mas, GFP_KERNEL); /* Fill request */
> - mas.status = ma_start;
> - MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS * 2 + 2);
> - mas_destroy(&mas);
> -
> - mas.node = MA_ERROR(-ENOMEM);
> - mas_node_count(&mas, MAPLE_ALLOC_SLOTS * 2 + 1); /* Request */
> - mas_nomem(&mas, GFP_KERNEL); /* Fill request */
> - MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS * 2 + 1);
> - mas.node = MA_ERROR(-ENOMEM);
> - mas_node_count(&mas, MAPLE_ALLOC_SLOTS * 3 + 2); /* Request */
> - mas_nomem(&mas, GFP_KERNEL); /* Fill request */
> - mas.status = ma_start;
> - MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS * 3 + 2);
> - mas_destroy(&mas);
> -
> - mtree_unlock(mt);
> -}
> -
> /*
> * Check erasing including RCU.
> */
> @@ -35458,8 +35034,7 @@ static void check_dfs_preorder(struct maple_tree *mt)
> mt_init_flags(mt, MT_FLAGS_ALLOC_RANGE);
> mas_reset(&mas);
> mt_zero_nr_tallocated();
> - mt_set_non_kernel(200);
> - mas_expected_entries(&mas, max);
> + mt_set_non_kernel(1000);
> for (count = 0; count <= max; count++) {
> mas.index = mas.last = count;
> mas_store(&mas, xa_mk_value(count));
> @@ -35524,6 +35099,13 @@ static unsigned char get_vacant_height(struct ma_wr_state *wr_mas, void *entry)
> return vacant_height;
> }
>
> +static int mas_allocated(struct ma_state *mas)
> +{
> + if (mas->sheaf)
> + return kmem_cache_sheaf_size(mas->sheaf);
> +
> + return 0;
> +}
> /* Preallocation testing */
> static noinline void __init check_prealloc(struct maple_tree *mt)
> {
> @@ -35533,8 +35115,8 @@ static noinline void __init check_prealloc(struct maple_tree *mt)
> unsigned char vacant_height;
> struct maple_node *mn;
> void *ptr = check_prealloc;
> + struct ma_wr_state wr_mas;
> MA_STATE(mas, mt, 10, 20);
> - MA_WR_STATE(wr_mas, &mas, ptr);
>
> mt_set_non_kernel(1000);
> for (i = 0; i <= max; i++)
> @@ -35542,7 +35124,11 @@ static noinline void __init check_prealloc(struct maple_tree *mt)
>
> /* Spanning store */
> mas_set_range(&mas, 470, 500);
> - MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
> + wr_mas.mas = &mas;
> +
> + mas_wr_preallocate(&wr_mas, ptr);
> + MT_BUG_ON(mt, mas.store_type != wr_spanning_store);
> + MT_BUG_ON(mt, mas_is_err(&mas));
> allocated = mas_allocated(&mas);
> height = mas_mt_height(&mas);
> vacant_height = get_vacant_height(&wr_mas, ptr);
> @@ -35552,6 +35138,7 @@ static noinline void __init check_prealloc(struct maple_tree *mt)
> allocated = mas_allocated(&mas);
> MT_BUG_ON(mt, allocated != 0);
>
> + mas_wr_preallocate(&wr_mas, ptr);
> MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
> allocated = mas_allocated(&mas);
> height = mas_mt_height(&mas);
> @@ -35592,20 +35179,6 @@ static noinline void __init check_prealloc(struct maple_tree *mt)
> mn->parent = ma_parent_ptr(mn);
> ma_free_rcu(mn);
>
> - MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
> - allocated = mas_allocated(&mas);
> - height = mas_mt_height(&mas);
> - vacant_height = get_vacant_height(&wr_mas, ptr);
> - MT_BUG_ON(mt, allocated != 1 + (height - vacant_height) * 3);
> - mn = mas_pop_node(&mas);
> - MT_BUG_ON(mt, mas_allocated(&mas) != allocated - 1);
> - mas_push_node(&mas, mn);
> - MT_BUG_ON(mt, mas_allocated(&mas) != allocated);
> - MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
> - mas_destroy(&mas);
> - allocated = mas_allocated(&mas);
> - MT_BUG_ON(mt, allocated != 0);
> -
> MT_BUG_ON(mt, mas_preallocate(&mas, ptr, GFP_KERNEL) != 0);
> allocated = mas_allocated(&mas);
> height = mas_mt_height(&mas);
> @@ -36394,11 +35967,17 @@ static void check_nomem_writer_race(struct maple_tree *mt)
> check_load(mt, 6, xa_mk_value(0xC));
> mtree_unlock(mt);
>
> + mt_set_non_kernel(0);
> /* test for the same race but with mas_store_gfp() */
> mtree_store_range(mt, 0, 5, xa_mk_value(0xA), GFP_KERNEL);
> mtree_store_range(mt, 6, 10, NULL, GFP_KERNEL);
>
> mas_set_range(&mas, 0, 5);
> +
> + /* setup writer 2 that will trigger the race condition */
> + mt_set_private(mt);
> + mt_set_callback(writer2);
> +
> mtree_lock(mt);
> mas_store_gfp(&mas, NULL, GFP_KERNEL);
>
> @@ -36435,7 +36014,6 @@ static inline int check_vma_modification(struct maple_tree *mt)
> __mas_set_range(&mas, 0x7ffde4ca2000, 0x7ffffffff000 - 1);
> mas_preallocate(&mas, NULL, GFP_KERNEL);
> mas_store_prealloc(&mas, NULL);
> - mt_dump(mt, mt_dump_hex);
>
> mas_destroy(&mas);
> mtree_unlock(mt);
> @@ -36453,6 +36031,8 @@ static inline void check_bulk_rebalance(struct maple_tree *mt)
>
> build_full_tree(mt, 0, 2);
>
> +
> + mtree_lock(mt);
> /* erase every entry in the tree */
> do {
> /* set up bulk store mode */
> @@ -36462,6 +36042,85 @@ static inline void check_bulk_rebalance(struct maple_tree *mt)
> } while (mas_prev(&mas, 0) != NULL);
>
> mas_destroy(&mas);
> + mtree_unlock(mt);
> +}
> +
> +static unsigned long get_last_index(struct ma_state *mas)
> +{
> + struct maple_node *node = mas_mn(mas);
> + enum maple_type mt = mte_node_type(mas->node);
> + unsigned long *pivots = ma_pivots(node, mt);
> + unsigned long last_index = mas_data_end(mas);
> +
> + BUG_ON(last_index == 0);
> +
> + return pivots[last_index - 1] + 1;
> +}
> +
> +/*
> + * Assert that we handle spanning stores that consume the entirety of the right
> + * leaf node correctly.
> + */
> +static void test_spanning_store_regression(void)
> +{
> + unsigned long from = 0, to = 0;
> + DEFINE_MTREE(tree);
> + MA_STATE(mas, &tree, 0, 0);
> +
> + /*
> + * Build a 3-level tree. We require a parent node below the root node
> + * and 2 leaf nodes under it, so we can span the entirety of the right
> + * hand node.
> + */
> + build_full_tree(&tree, 0, 3);
> +
> + /* Descend into position at depth 2. */
> + mas_reset(&mas);
> + mas_start(&mas);
> + mas_descend(&mas);
> + mas_descend(&mas);
> +
> + /*
> + * We need to establish a tree like the below.
> + *
> + * Then we can try a store in [from, to] which results in a spanned
> + * store across nodes B and C, with the maple state at the time of the
> + * write being such that only the subtree at A and below is considered.
> + *
> + * Height
> + * 0 Root Node
> + * / \
> + * pivot = to / \ pivot = ULONG_MAX
> + * / \
> + * 1 A [-----] ...
> + * / \
> + * pivot = from / \ pivot = to
> + * / \
> + * 2 (LEAVES) B [-----] [-----] C
> + * ^--- Last pivot to.
> + */
> + while (true) {
> + unsigned long tmp = get_last_index(&mas);
> +
> + if (mas_next_sibling(&mas)) {
> + from = tmp;
> + to = mas.max;
> + } else {
> + break;
> + }
> + }
> +
> + BUG_ON(from == 0 && to == 0);
> +
> + /* Perform the store. */
> + mas_set_range(&mas, from, to);
> + mas_store_gfp(&mas, xa_mk_value(0xdead), GFP_KERNEL);
> +
> + /* If the regression occurs, the validation will fail. */
> + mt_validate(&tree);
> +
> + /* Cleanup. */
> + __mt_destroy(&tree);
> }
>
> void farmer_tests(void)
> @@ -36525,6 +36184,7 @@ void farmer_tests(void)
> check_collapsing_rebalance(&tree);
> mtree_destroy(&tree);
>
> +
> mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
> check_null_expand(&tree);
> mtree_destroy(&tree);
> @@ -36538,10 +36198,6 @@ void farmer_tests(void)
> check_erase_testset(&tree);
> mtree_destroy(&tree);
>
> - mt_init_flags(&tree, 0);
> - check_new_node(&tree);
> - mtree_destroy(&tree);
> -
> if (!MAPLE_32BIT) {
> mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
> check_rcu_simulated(&tree);
> @@ -36563,95 +36219,13 @@ void farmer_tests(void)
>
> /* No memory handling */
> check_nomem(&tree);
> -}
> -
> -static unsigned long get_last_index(struct ma_state *mas)
> -{
> - struct maple_node *node = mas_mn(mas);
> - enum maple_type mt = mte_node_type(mas->node);
> - unsigned long *pivots = ma_pivots(node, mt);
> - unsigned long last_index = mas_data_end(mas);
> -
> - BUG_ON(last_index == 0);
>
> - return pivots[last_index - 1] + 1;
> -}
> -
> -/*
> - * Assert that we handle spanning stores that consume the entirety of the right
> - * leaf node correctly.
> - */
> -static void test_spanning_store_regression(void)
> -{
> - unsigned long from = 0, to = 0;
> - DEFINE_MTREE(tree);
> - MA_STATE(mas, &tree, 0, 0);
> -
> - /*
> - * Build a 3-level tree. We require a parent node below the root node
> - * and 2 leaf nodes under it, so we can span the entirety of the right
> - * hand node.
> - */
> - build_full_tree(&tree, 0, 3);
> -
> - /* Descend into position at depth 2. */
> - mas_reset(&mas);
> - mas_start(&mas);
> - mas_descend(&mas);
> - mas_descend(&mas);
> -
> - /*
> - * We need to establish a tree like the below.
> - *
> - * Then we can try a store in [from, to] which results in a spanned
> - * store across nodes B and C, with the maple state at the time of the
> - * write being such that only the subtree at A and below is considered.
> - *
> - * Height
> - * 0 Root Node
> - * / \
> - * pivot = to / \ pivot = ULONG_MAX
> - * / \
> - * 1 A [-----] ...
> - * / \
> - * pivot = from / \ pivot = to
> - * / \
> - * 2 (LEAVES) B [-----] [-----] C
> - * ^--- Last pivot to.
> - */
> - while (true) {
> - unsigned long tmp = get_last_index(&mas);
> -
> - if (mas_next_sibling(&mas)) {
> - from = tmp;
> - to = mas.max;
> - } else {
> - break;
> - }
> - }
> -
> - BUG_ON(from == 0 && to == 0);
> -
> - /* Perform the store. */
> - mas_set_range(&mas, from, to);
> - mas_store_gfp(&mas, xa_mk_value(0xdead), GFP_KERNEL);
> -
> - /* If the regression occurs, the validation will fail. */
> - mt_validate(&tree);
> -
> - /* Cleanup. */
> - __mt_destroy(&tree);
> -}
> -
> -static void regression_tests(void)
> -{
> test_spanning_store_regression();
> }
>
> void maple_tree_tests(void)
> {
> #if !defined(BENCH)
> - regression_tests();
> farmer_tests();
> #endif
> maple_tree_seed();
> diff --git a/tools/testing/shared/linux.c b/tools/testing/shared/linux.c
> index e0255f53159bd3a1325d49192283dd6790a5e3b8..6a15665fc8315168c718e6810c7deaeed13a3a6a 100644
> --- a/tools/testing/shared/linux.c
> +++ b/tools/testing/shared/linux.c
> @@ -82,7 +82,8 @@ void *kmem_cache_alloc_lru(struct kmem_cache *cachep, struct list_lru *lru,
>
> if (!(gfp & __GFP_DIRECT_RECLAIM)) {
> if (!cachep->non_kernel) {
> - cachep->exec_callback = true;
> + if (cachep->callback)
> + cachep->exec_callback = true;
> return NULL;
> }
>
> @@ -236,6 +237,8 @@ int kmem_cache_alloc_bulk(struct kmem_cache *cachep, gfp_t gfp, size_t size,
> for (i = 0; i < size; i++)
> __kmem_cache_free_locked(cachep, p[i]);
> pthread_mutex_unlock(&cachep->lock);
> + if (cachep->callback)
> + cachep->exec_callback = true;
> return 0;
> }
>
> @@ -288,9 +291,8 @@ kmem_cache_prefill_sheaf(struct kmem_cache *s, gfp_t gfp, unsigned int size)
> capacity = s->sheaf_capacity;
>
> sheaf = malloc(sizeof(*sheaf) + sizeof(void *) * s->sheaf_capacity * capacity);
> - if (!sheaf) {
> + if (!sheaf)
> return NULL;
> - }
>
> memset(sheaf, 0, size);
> sheaf->cache = s;
>
> --
> 2.50.1
>
Powered by blists - more mailing lists