]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
maple_tree: Fix potential metadata off by one in mas_mab_cp() on final node
authorLiam R. Howlett <Liam.Howlett@oracle.com>
Tue, 8 Mar 2022 14:45:49 +0000 (09:45 -0500)
committerLiam R. Howlett <Liam.Howlett@oracle.com>
Tue, 8 Mar 2022 18:19:16 +0000 (13:19 -0500)
Signed-off-by: Liam R. Howlett <Liam.Howlett@oracle.com>
lib/maple_tree.c

index 8449d21118bd6836936ab0b7151b0172c4cba986..556cdbd0db81198858b06725cbc69c693afb08d8 100644 (file)
@@ -1915,6 +1915,33 @@ complete:
        }
 }
 
+/*
+ * mas_leaf_set_meta() - Set the metadata of a leaf if possible.
+ * @mas: The maple state
+ * @node: The maple node
+ * @pivots: pointer to the maple node pivots
+ * @mt: The maple type
+ * @end: The assumed end
+ *
+ * Note, end may be incremented within this function but not modified at the
+ * source.  This is fine since the metadata is the last thing to be stored in a
+ * node during a write.
+ */
+static inline void mas_leaf_set_meta(struct ma_state *mas,
+               struct maple_node *node, unsigned long *pivots,
+               enum maple_type mt, unsigned char end)
+{
+       /* There is no room for metadata already */
+       if (mt_pivots[mt] <= end)
+               return;
+
+       if (pivots[end] && pivots[end] < mas->max)
+               end++;
+
+       if (end < mt_slots[mt] - 1)
+               ma_set_meta(node, mt, 0, end);
+}
+
 /*
  * mab_mas_cp() - Copy data from maple_big_node to a maple encoded node.
  * @b_node: the maple_big_node that has the data
@@ -1967,12 +1994,8 @@ static inline void mab_mas_cp(struct maple_big_node *b_node,
                } while (j);
 
                ma_set_meta(node, mt, offset, end);
-       } else if (end <= mt_pivots[mt] - 1) {
-               if (pivots[end] != mas->max)
-                       end++;
-
-               if (end < mt_slots[mt] - 1)
-                       ma_set_meta(node, mt, 0, end);
+       } else {
+               mas_leaf_set_meta(mas, node, pivots, mt, end);
        }
 }
 
@@ -3925,7 +3948,6 @@ static inline bool mas_wr_node_store(struct ma_wr_state *wr_mas)
        unsigned char new_end = wr_mas->node_end;
        unsigned char offset;
        unsigned char node_slots = mt_slots[wr_mas->type];
-       unsigned char node_pivots = mt_pivots[wr_mas->type];
        struct maple_node reuse, *newnode;
        unsigned char copy_size, max_piv = mt_pivots[wr_mas->type];
        bool in_rcu = mt_in_rcu(mas->tree);
@@ -4016,12 +4038,7 @@ done:
        if ((wr_mas->node_end == node_slots - 1) && (new_end < node_slots - 1))
                dst_pivots[new_end] = mas->max;
 
-       if (!dst_pivots[node_pivots - 1] || dst_pivots[node_pivots - 1] == mas->max) {
-               if (dst_pivots[new_end] && dst_pivots[new_end] < mas->max)
-                       new_end++;
-               ma_set_meta(newnode, maple_leaf_64, 0, new_end);
-       }
-
+       mas_leaf_set_meta(mas, newnode, dst_pivots, maple_leaf_64, new_end);
        if (in_rcu) {
                mas->node = mt_mk_node(newnode, wr_mas->type);
                mas_replace(mas, false);