[PATCH 10/28] maple_tree: Introduce maple_copy node and use it in mas_spanning_rebalance()

Liam R. Howlett posted 28 patches 3 weeks, 3 days ago
There is a newer version of this series
[PATCH 10/28] maple_tree: Introduce maple_copy node and use it in mas_spanning_rebalance()
Posted by Liam R. Howlett 3 weeks, 3 days ago
Introduce an internal-memory only node type called maple_copy to
facilitate internal copy operations.  Use it in mas_spanning_rebalance()
for just the leaf nodes.  Initially, the maple_copy node is used to
configure the source nodes and copy the data into the big_node.

The maple_copy contains a list of source entries with start and end
offsets.  One of the maple_copy entries can be itself with an offset of
0 to 2, representing the data where the store partially overwrites
entries, or fully overwrites the entry.  The side effect is that the
source nodes no longer have to worry about partially copying the
existing offset if it is not fully overwritten.

This is in preparation of removal of the maple big_node, but for the
time being the data is copied to the big node to limit the change size.

Signed-off-by: Liam R. Howlett <Liam.Howlett@oracle.com>
---
 include/linux/maple_tree.h |  26 ++++++++
 lib/maple_tree.c           | 133 ++++++++++++++++++++++++++++++++++---
 2 files changed, 150 insertions(+), 9 deletions(-)

diff --git a/include/linux/maple_tree.h b/include/linux/maple_tree.h
index 7b8aad47121e7..9bc7fa89bc2ee 100644
--- a/include/linux/maple_tree.h
+++ b/include/linux/maple_tree.h
@@ -139,6 +139,7 @@ enum maple_type {
 	maple_leaf_64,
 	maple_range_64,
 	maple_arange_64,
+	maple_copy,
 };
 
 enum store_type {
@@ -154,6 +155,30 @@ enum store_type {
 	wr_slot_store,
 };
 
+struct maple_copy {
+	struct {
+		struct maple_node *node;
+		unsigned long max;
+		unsigned char start;
+		unsigned char end;
+		enum maple_type mt;
+	} src[4];
+	/* Simulated node */
+	void __rcu *slot[3];
+	unsigned long min;
+	union {
+		unsigned long pivot[3];
+		struct {
+			void *_pad[2];
+			unsigned long max;
+		};
+	};
+	unsigned char end;
+
+	/*Avoid passing these around */
+	unsigned char s_count;
+};
+
 /**
  * DOC: Maple tree flags
  *
@@ -299,6 +324,7 @@ struct maple_node {
 		};
 		struct maple_range_64 mr64;
 		struct maple_arange_64 ma64;
+		struct maple_copy cp;
 	};
 };
 
diff --git a/lib/maple_tree.c b/lib/maple_tree.c
index 8cefaebf414d3..8927e8e1b8012 100644
--- a/lib/maple_tree.c
+++ b/lib/maple_tree.c
@@ -605,6 +605,8 @@ static inline unsigned long *ma_pivots(struct maple_node *node,
 	case maple_range_64:
 	case maple_leaf_64:
 		return node->mr64.pivot;
+	case maple_copy:
+		return node->cp.pivot;
 	case maple_dense:
 		return NULL;
 	}
@@ -624,6 +626,7 @@ static inline unsigned long *ma_gaps(struct maple_node *node,
 	switch (type) {
 	case maple_arange_64:
 		return node->ma64.gap;
+	case maple_copy:
 	case maple_range_64:
 	case maple_leaf_64:
 	case maple_dense:
@@ -690,6 +693,7 @@ static inline void mte_set_pivot(struct maple_enode *mn, unsigned char piv,
 	case maple_arange_64:
 		node->ma64.pivot[piv] = val;
 		break;
+	case maple_copy:
 	case maple_dense:
 		break;
 	}
@@ -711,6 +715,8 @@ static inline void __rcu **ma_slots(struct maple_node *mn, enum maple_type mt)
 	case maple_range_64:
 	case maple_leaf_64:
 		return mn->mr64.slot;
+	case maple_copy:
+		return mn->cp.slot;
 	case maple_dense:
 		return mn->slot;
 	}
@@ -2595,6 +2601,103 @@ static inline void *mtree_range_walk(struct ma_state *mas)
 	return NULL;
 }
 
+/*
+ * cp_leaf_init() - Initialize a maple_copy node for the leaf level of a
+ * spanning store
+ * @cp: The maple copy node
+ * @mas: The maple state
+ * @l_wr_mas: The left write state of the spanning store
+ * @r_wr_mas: The right write state of the spanning store
+ */
+static inline void cp_leaf_init(struct maple_copy *cp,
+		struct ma_state *mas, struct ma_wr_state *l_wr_mas,
+		struct ma_wr_state *r_wr_mas)
+{
+	unsigned char end = 0;
+
+	/* Create entries to insert including split entries to left and right */
+	if (l_wr_mas->r_min < mas->index) {
+		end++;
+		cp->slot[0] = l_wr_mas->content;
+		cp->pivot[0] = mas->index - 1;
+	}
+	cp->slot[end] = l_wr_mas->entry;
+	cp->pivot[end] = mas->last;
+
+	if (r_wr_mas->end_piv > mas->last) {
+		end++;
+		cp->slot[end] = r_wr_mas->slots[r_wr_mas->offset_end];
+		cp->pivot[end] = r_wr_mas->end_piv;
+	}
+
+	cp->min = l_wr_mas->r_min;
+	cp->max = cp->pivot[end];
+	cp->end = end;
+}
+
+static inline void append_wr_mas_cp(struct maple_copy *cp,
+	struct ma_wr_state *wr_mas, unsigned char start, unsigned char end)
+{
+	unsigned char count;
+
+	count = cp->s_count;
+	cp->src[count].node = wr_mas->node;
+	cp->src[count].mt = wr_mas->type;
+	if (wr_mas->mas->end <= end)
+		cp->src[count].max = wr_mas->mas->max;
+	else
+		cp->src[count].max = wr_mas->pivots[end];
+
+	cp->src[count].start = start;
+	cp->src[count].end = end;
+	cp->s_count++;
+}
+
+static inline void init_cp_src(struct maple_copy *cp)
+{
+	cp->src[cp->s_count].node = ma_mnode_ptr(cp);
+	cp->src[cp->s_count].mt = maple_copy;
+	cp->src[cp->s_count].max = cp->max;
+	cp->src[cp->s_count].start = 0;
+	cp->src[cp->s_count].end = cp->end;
+	cp->s_count++;
+}
+
+static inline
+void cp_data_write(struct maple_copy *cp, struct maple_big_node *b_node)
+{
+	struct maple_node *src;
+	unsigned char s;
+	unsigned char src_end, s_offset;
+	unsigned long *b_pivots, *cp_pivots;
+	void __rcu **b_slots, **cp_slots;
+	enum maple_type s_mt;
+
+	b_node->b_end = 0;
+
+	s = 0;
+	b_pivots = b_node->pivot;
+	b_slots = (void __rcu *)b_node->slot;
+	do {
+		unsigned char size;
+
+		src = cp->src[s].node;
+		s_mt = cp->src[s].mt;
+		s_offset = cp->src[s].start;
+		src_end = cp->src[s].end;
+		size = src_end - s_offset + 1;
+		cp_pivots = ma_pivots(src, s_mt) + s_offset;
+		cp_slots = ma_slots(src, s_mt) + s_offset;
+		memcpy(b_slots, cp_slots, size * sizeof(void __rcu *));
+		if (size > 1)
+			memcpy(b_pivots, cp_pivots, (size - 1) * sizeof(unsigned long));
+		b_pivots[size - 1] = cp->src[s].max;
+		b_pivots += size;
+		b_slots += size;
+		b_node->b_end += size;
+	} while (++s < cp->s_count);
+}
+
 static void mas_spanning_rebalance_loop(struct ma_state *mas,
 		struct maple_subtree_state *mast, unsigned char count)
 {
@@ -2750,10 +2853,11 @@ static void mas_spanning_rebalance(struct ma_state *mas,
 
 
 static noinline void mas_wr_spanning_rebalance(struct ma_state *mas,
-		struct ma_wr_state *wr_mas, struct ma_wr_state *r_wr_mas)
+		struct ma_wr_state *l_wr_mas, struct ma_wr_state *r_wr_mas)
 {
 	struct maple_subtree_state mast;
 	struct maple_big_node b_node;
+	struct maple_copy cp;
 	unsigned char height;
 	MA_STATE(l_mas, mas->tree, mas->index, mas->index);
 	MA_STATE(r_mas, mas->tree, mas->index, mas->last);
@@ -2765,15 +2869,26 @@ static noinline void mas_wr_spanning_rebalance(struct ma_state *mas,
 	mast.orig_l = &mast_l_mas;
 	mast.orig_r = r_wr_mas->mas;
 	memset(&b_node, 0, sizeof(struct maple_big_node));
-	/* Copy l_mas and store the value in b_node. */
-	mas_store_b_node(wr_mas, &b_node, mast.orig_l->end);
-	/* Copy r_mas into b_node if there is anything to copy. */
-	if (mast.orig_r->max > mast.orig_r->last)
-		mas_mab_cp(mast.orig_r, mast.orig_r->offset,
-			   mast.orig_r->end, &b_node, b_node.b_end + 1);
-	else
-		b_node.b_end++;
+	cp.s_count = 0;
+	cp_leaf_init(&cp, mas, l_wr_mas, r_wr_mas);
+	/* Copy left 0 - offset */
+	if (l_wr_mas->mas->offset) {
+		unsigned char off = l_wr_mas->mas->offset - 1;
+
+		append_wr_mas_cp(&cp, l_wr_mas, 0, off);
+		cp.src[cp.s_count - 1].max = cp.min - 1;
+	}
+
+	init_cp_src(&cp);
+
+	/* Copy right from offset_end + 1 to end */
+	if (r_wr_mas->mas->end != r_wr_mas->offset_end)
+		append_wr_mas_cp(&cp, r_wr_mas, r_wr_mas->offset_end + 1,
+			       r_wr_mas->mas->end);
+
 
+	b_node.type = l_wr_mas->type;
+	cp_data_write(&cp, &b_node);
 	/* Stop spanning searches by searching for just index. */
 	mast.orig_l->last = mas->index;
 
-- 
2.47.3
Re: [PATCH 10/28] maple_tree: Introduce maple_copy node and use it in mas_spanning_rebalance()
Posted by kernel test robot 3 weeks, 2 days ago
Hi Liam,

kernel test robot noticed the following build warnings:

[auto build test WARNING on akpm-mm/mm-everything]
[also build test WARNING on next-20260115]
[cannot apply to akpm-mm/mm-nonmm-unstable soc/for-next linus/master v6.19-rc5]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Liam-R-Howlett/maple_tree-Move-mas_spanning_rebalance-loop-to-function/20260116-034135
base:   https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything
patch link:    https://lore.kernel.org/r/20260115193647.1695937-11-Liam.Howlett%40oracle.com
patch subject: [PATCH 10/28] maple_tree: Introduce maple_copy node and use it in mas_spanning_rebalance()
config: x86_64-randconfig-121-20260116 (https://download.01.org/0day-ci/archive/20260116/202601161501.NZ3GNDCG-lkp@intel.com/config)
compiler: gcc-13 (Debian 13.3.0-16) 13.3.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260116/202601161501.NZ3GNDCG-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202601161501.NZ3GNDCG-lkp@intel.com/

sparse warnings: (new ones prefixed by >>)
>> lib/maple_tree.c:2621:29: sparse: sparse: incorrect type in assignment (different address spaces) @@     expected void [noderef] __rcu * @@     got void *content @@
   lib/maple_tree.c:2621:29: sparse:     expected void [noderef] __rcu *
   lib/maple_tree.c:2621:29: sparse:     got void *content
>> lib/maple_tree.c:2624:23: sparse: sparse: incorrect type in assignment (different address spaces) @@     expected void [noderef] __rcu * @@     got void *entry @@
   lib/maple_tree.c:2624:23: sparse:     expected void [noderef] __rcu *
   lib/maple_tree.c:2624:23: sparse:     got void *entry
   lib/maple_tree.c:2680:17: sparse: sparse: incorrect type in assignment (different address spaces) @@     expected void [noderef] __rcu **b_slots @@     got void [noderef] __rcu * @@
   lib/maple_tree.c:2680:17: sparse:     expected void [noderef] __rcu **b_slots
   lib/maple_tree.c:2680:17: sparse:     got void [noderef] __rcu *
   lib/maple_tree.c:6412:30: sparse: sparse: incorrect type in assignment (different address spaces) @@     expected void [noderef] __rcu * @@     got struct maple_node * @@
   lib/maple_tree.c:6412:30: sparse:     expected void [noderef] __rcu *
   lib/maple_tree.c:6412:30: sparse:     got struct maple_node *
   lib/maple_tree.c:6412:30: sparse: sparse: incorrect type in assignment (different address spaces) @@     expected void [noderef] __rcu * @@     got struct maple_node * @@
   lib/maple_tree.c:6412:30: sparse:     expected void [noderef] __rcu *
   lib/maple_tree.c:6412:30: sparse:     got struct maple_node *

vim +2621 lib/maple_tree.c

  2603	
  2604	/*
  2605	 * cp_leaf_init() - Initialize a maple_copy node for the leaf level of a
  2606	 * spanning store
  2607	 * @cp: The maple copy node
  2608	 * @mas: The maple state
  2609	 * @l_wr_mas: The left write state of the spanning store
  2610	 * @r_wr_mas: The right write state of the spanning store
  2611	 */
  2612	static inline void cp_leaf_init(struct maple_copy *cp,
  2613			struct ma_state *mas, struct ma_wr_state *l_wr_mas,
  2614			struct ma_wr_state *r_wr_mas)
  2615	{
  2616		unsigned char end = 0;
  2617	
  2618		/* Create entries to insert including split entries to left and right */
  2619		if (l_wr_mas->r_min < mas->index) {
  2620			end++;
> 2621			cp->slot[0] = l_wr_mas->content;
  2622			cp->pivot[0] = mas->index - 1;
  2623		}
> 2624		cp->slot[end] = l_wr_mas->entry;
  2625		cp->pivot[end] = mas->last;
  2626	
  2627		if (r_wr_mas->end_piv > mas->last) {
  2628			end++;
  2629			cp->slot[end] = r_wr_mas->slots[r_wr_mas->offset_end];
  2630			cp->pivot[end] = r_wr_mas->end_piv;
  2631		}
  2632	
  2633		cp->min = l_wr_mas->r_min;
  2634		cp->max = cp->pivot[end];
  2635		cp->end = end;
  2636	}
  2637	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Re: [PATCH 10/28] maple_tree: Introduce maple_copy node and use it in mas_spanning_rebalance()
Posted by Liam R. Howlett 3 weeks, 2 days ago
* kernel test robot <lkp@intel.com> [260116 02:45]:
> Hi Liam,
> 
> kernel test robot noticed the following build warnings:
> 
> [auto build test WARNING on akpm-mm/mm-everything]
> [also build test WARNING on next-20260115]
> [cannot apply to akpm-mm/mm-nonmm-unstable soc/for-next linus/master v6.19-rc5]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
> 
> url:    https://github.com/intel-lab-lkp/linux/commits/Liam-R-Howlett/maple_tree-Move-mas_spanning_rebalance-loop-to-function/20260116-034135
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything
> patch link:    https://lore.kernel.org/r/20260115193647.1695937-11-Liam.Howlett%40oracle.com
> patch subject: [PATCH 10/28] maple_tree: Introduce maple_copy node and use it in mas_spanning_rebalance()
> config: x86_64-randconfig-121-20260116 (https://download.01.org/0day-ci/archive/20260116/202601161501.NZ3GNDCG-lkp@intel.com/config)
> compiler: gcc-13 (Debian 13.3.0-16) 13.3.0
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260116/202601161501.NZ3GNDCG-lkp@intel.com/reproduce)
> 
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202601161501.NZ3GNDCG-lkp@intel.com/
> 
> sparse warnings: (new ones prefixed by >>)
> >> lib/maple_tree.c:2621:29: sparse: sparse: incorrect type in assignment (different address spaces) @@     expected void [noderef] __rcu * @@     got void *content @@
>    lib/maple_tree.c:2621:29: sparse:     expected void [noderef] __rcu *
>    lib/maple_tree.c:2621:29: sparse:     got void *content
> >> lib/maple_tree.c:2624:23: sparse: sparse: incorrect type in assignment (different address spaces) @@     expected void [noderef] __rcu * @@     got void *entry @@
>    lib/maple_tree.c:2624:23: sparse:     expected void [noderef] __rcu *
>    lib/maple_tree.c:2624:23: sparse:     got void *entry
>    lib/maple_tree.c:2680:17: sparse: sparse: incorrect type in assignment (different address spaces) @@     expected void [noderef] __rcu **b_slots @@     got void [noderef] __rcu * @@
>    lib/maple_tree.c:2680:17: sparse:     expected void [noderef] __rcu **b_slots
>    lib/maple_tree.c:2680:17: sparse:     got void [noderef] __rcu *
>    lib/maple_tree.c:6412:30: sparse: sparse: incorrect type in assignment (different address spaces) @@     expected void [noderef] __rcu * @@     got struct maple_node * @@
>    lib/maple_tree.c:6412:30: sparse:     expected void [noderef] __rcu *
>    lib/maple_tree.c:6412:30: sparse:     got struct maple_node *
>    lib/maple_tree.c:6412:30: sparse: sparse: incorrect type in assignment (different address spaces) @@     expected void [noderef] __rcu * @@     got struct maple_node * @@
>    lib/maple_tree.c:6412:30: sparse:     expected void [noderef] __rcu *
>    lib/maple_tree.c:6412:30: sparse:     got struct maple_node *
> 
> vim +2621 lib/maple_tree.c
> 
>   2603	
>   2604	/*
>   2605	 * cp_leaf_init() - Initialize a maple_copy node for the leaf level of a
>   2606	 * spanning store
>   2607	 * @cp: The maple copy node
>   2608	 * @mas: The maple state
>   2609	 * @l_wr_mas: The left write state of the spanning store
>   2610	 * @r_wr_mas: The right write state of the spanning store
>   2611	 */
>   2612	static inline void cp_leaf_init(struct maple_copy *cp,
>   2613			struct ma_state *mas, struct ma_wr_state *l_wr_mas,
>   2614			struct ma_wr_state *r_wr_mas)
>   2615	{
>   2616		unsigned char end = 0;
>   2617	
>   2618		/* Create entries to insert including split entries to left and right */
>   2619		if (l_wr_mas->r_min < mas->index) {
>   2620			end++;
> > 2621			cp->slot[0] = l_wr_mas->content;
>   2622			cp->pivot[0] = mas->index - 1;
>   2623		}
> > 2624		cp->slot[end] = l_wr_mas->entry;
>   2625		cp->pivot[end] = mas->last;
>   2626	
>   2627		if (r_wr_mas->end_piv > mas->last) {
>   2628			end++;
>   2629			cp->slot[end] = r_wr_mas->slots[r_wr_mas->offset_end];
>   2630			cp->pivot[end] = r_wr_mas->end_piv;
>   2631		}
>   2632	
>   2633		cp->min = l_wr_mas->r_min;
>   2634		cp->max = cp->pivot[end];
>   2635		cp->end = end;
>   2636	}
>   2637	
> 

#syz test:   https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything

--- a/lib/maple_tree.c
+++ b/lib/maple_tree.c
@@ -2092,19 +2092,28 @@ static inline void cp_leaf_init(struct maple_copy *cp,
 {
        unsigned char end = 0;
 
+       /*
+        * It is very important that the maple_copy node is never seen before a
+        * write side barrier happens.  Otherwise, there could be a reordering
+        * in the RCU code below that will be extremely difficult to debug.
+        *
+        * In this case, it is fine because the maple_copy is never exposed to
+        * readers until it is put into a final node and a wmb() occurs.
+        */
        cp->height = 1;
        /* Create entries to insert including split entries to left and right */
        if (l_wr_mas->r_min < mas->index) {
                end++;
-               cp->slot[0] = l_wr_mas->content;
+               RCU_INIT_POINTER(cp->slot[0], l_wr_mas->content);
                cp->pivot[0] = mas->index - 1;
        }
-       cp->slot[end] = l_wr_mas->entry;
+       RCU_INIT_POINTER(cp->slot[end], l_wr_mas->entry);
        cp->pivot[end] = mas->last;
 
        if (r_wr_mas->end_piv > mas->last) {
                end++;
-               cp->slot[end] = r_wr_mas->slots[r_wr_mas->offset_end];
+               RCU_INIT_POINTER(cp->slot[end],
+                                r_wr_mas->slots[r_wr_mas->offset_end]);
                cp->pivot[end] = r_wr_mas->end_piv;
        }