]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
maple_tree: Fix mte_destroy_walk() overwriting slots when spinlock debug is enabled.
authorLiam R. Howlett <Liam.Howlett@Oracle.com>
Thu, 1 Oct 2020 14:03:22 +0000 (10:03 -0400)
committerLiam R. Howlett <Liam.Howlett@Oracle.com>
Tue, 5 Jan 2021 17:30:32 +0000 (12:30 -0500)
When spinlock debug is enabled, the size fo the spinlock expands and causes the anon union
in maple_node to overwrite slots.  Fix this by only passing through the maple flags.

Signed-off-by: Liam R. Howlett <Liam.Howlett@Oracle.com>
include/linux/maple_tree.h
lib/maple_tree.c

index fc16e6f1a219de93ff7c7aa1fbc2cb50e4c6539f..25348e7c17bb52b544a3fc28a6217a958e25586c 100644 (file)
@@ -146,8 +146,8 @@ struct maple_node {
                struct {
                        void *pad;
                        struct rcu_head rcu;
+                       unsigned int ma_flags;
                        enum maple_type type;
-                       struct maple_tree mt;
                };
                struct maple_range_64 mr64;
                struct maple_arange_64 ma64;
index 6969e971356f561c83435f7a2ef338412df3750c..edb548f9d4fa3576be10f9b8f1774dd30d5f5074 100644 (file)
@@ -4358,18 +4358,21 @@ done:
 static inline unsigned char mas_dead_leaves(struct ma_state *mas, void **slots)
 {
        struct maple_node *node;
-       int slot = 0;
-       for (; slot < mt_slot_count(mas->node); slot++) {
-               if (!slots[slot])
+       int offset;
+
+       for (offset = 0; offset < mt_slot_count(mas->node); offset++) {
+               if (!slots[offset])
                        break;
-               node = mte_to_node(ma_enode_ptr(slots[slot]));
+
+               node = mte_to_node(slots[offset]);
                node->parent = ma_parent_ptr(node);
-               slots[slot] = (void *)node;
+               slots[offset] = (void *)node;
        }
-       return slot;
+
+       return offset;
 }
 
-void **mas_destroy_descend(struct ma_state *mas)
+static inline void **mas_destroy_descend(struct ma_state *mas)
 {
        void **slots = ma_slots(mte_to_node(mas->node),
                                    mte_node_type(mas->node));
@@ -4378,6 +4381,7 @@ void **mas_destroy_descend(struct ma_state *mas)
                slots = ma_slots(mte_to_node(mas->node),
                                     mte_node_type(mas->node));
        }
+
        return slots;
 }
 
@@ -4388,12 +4392,12 @@ void **mas_destroy_descend(struct ma_state *mas)
  */
 void mt_destroy_walk(struct rcu_head *head)
 {
-       unsigned char end, slot = 0;
+       unsigned char end, offset = 0;
        void **slots;
        struct maple_node *node = container_of(head, struct maple_node, rcu);
        struct maple_enode *start;
-       MA_STATE(mas, &node->mt, 0, 0);
-
+       struct maple_tree mt = MTREE_INIT(mt, node->ma_flags);
+       MA_STATE(mas, &mt, 0, 0);
 
        if (ma_is_leaf(node->type))
                goto free_leaf;
@@ -4411,28 +4415,28 @@ void mt_destroy_walk(struct rcu_head *head)
                        break;
 
                type = mas_parent_enum(&mas, mas.node);
-               slot = mte_parent_slot(mas.node);
+               offset = mte_parent_slot(mas.node);
                mas.node = mt_mk_node(mte_parent(mas.node), type);
                slots = ma_slots(mte_to_node(mas.node), type);
 
-               if ((slot == mt_slots[type] - 1) || !slots[slot + 1])
+               if ((offset == mt_slots[type] - 1) || !slots[offset + 1])
                        continue;
 
-               mas.node = slots[++slot];
+               mas.node = slots[++offset];
                slots = mas_destroy_descend(&mas);
-
        }
 
 free_leaf:
        kmem_cache_free(maple_node_cache, node);
 }
 
+void mt_dump(const struct maple_tree *mt);
 void mte_destroy_walk(struct maple_enode *enode, struct maple_tree *mt)
 {
        struct maple_node *node = mte_to_node(enode);
 
        node->type = mte_node_type(enode);
-       node->mt.ma_flags = mt->ma_flags;
+       node->ma_flags = mt->ma_flags;
        mte_set_node_dead(enode);
        if (mt_in_rcu(mt))
                call_rcu(&node->rcu, mt_destroy_walk);