]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
maple_tree: Sheaf conversion
authorLiam R. Howlett <Liam.Howlett@Oracle.com>
Wed, 4 Dec 2024 20:26:33 +0000 (15:26 -0500)
committerLiam R. Howlett <Liam.Howlett@oracle.com>
Tue, 4 Mar 2025 16:35:37 +0000 (11:35 -0500)
Use sheaves instead of bulk allocations.  This should speed up the
allocations and the return path of unused allocations.

Remove push/pop of nodes from maple state.
Remove unnecessary testing
ifdef out other testing that probably will be deleted
Fix testcase for testing race
Move some testing around in the same commit.

Signed-off-by: Liam R. Howlett <Liam.Howlett@Oracle.com>
include/linux/maple_tree.h
lib/maple_tree.c
lib/test_maple_tree.c
tools/testing/radix-tree/maple.c
tools/testing/shared/linux.c

index 37dc9525dff67b7c11e161cd8071871273caaa85..9a53e527297ebf40456febfb59908b9146283c9f 100644 (file)
@@ -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,                               \
        }
index 1c97599100d24ece341f49f5040354cec08e3a3e..26b986ee4b9a827544f2bed8a93f2ebf871b6394 100644 (file)
@@ -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,72 +1121,29 @@ done:
  */
 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;
+               mas->node_request = 0;
+               return;
+       }
 
-               if (node->node_count == 0) {
-                       node->slot[0]->node_count = 0;
-                       node->slot[0]->request_count = 0;
-               }
+       mas->sheaf = mt_get_sheaf(gfp, mas->node_request);
 
-               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;
+       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);
 }
 
@@ -1307,42 +1157,7 @@ nomem_one:
  */
 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);
 }
 
 /*
@@ -4174,7 +3986,7 @@ set_content:
  *
  * 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);
@@ -4220,7 +4032,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;
 }
 
 /*
@@ -4281,15 +4093,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);
 }
 
 /**
@@ -5404,7 +5216,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);
@@ -5434,11 +5245,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;
 
@@ -5526,26 +5337,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);
 
@@ -5559,9 +5369,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
@@ -5582,21 +5389,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);
 
@@ -5646,7 +5443,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;
@@ -6282,7 +6080,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;
@@ -7677,8 +7475,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");
 }
index 13e2a10d7554d6b1de5ffbda59f3a5bc4039a8c8..5549eb4200c7974e3bb457e0fd054c434e4b85da 100644 (file)
@@ -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);
index 3717d76f8f0ac1a50aff163e95188698b53acfcf..ed9627df933c0f3056dcd6b2df8e1d116f140695 100644 (file)
@@ -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);
@@ -36379,11 +35952,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);
 
@@ -36420,7 +35999,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);
@@ -36438,6 +36016,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 */
@@ -36447,6 +36027,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)
@@ -36506,6 +36165,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);
@@ -36519,10 +36179,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);
@@ -36544,95 +36200,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();
index a61c755c3c87e80036a5173115e955bfe7d5a80c..e42189406e8cff08fefb9414c1c543bde9a45cc5 100644 (file)
@@ -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;