From a9d365333b7f62be348ba8737dfb6e73755974cf Mon Sep 17 00:00:00 2001 From: "Liam R. Howlett" Date: Thu, 1 Oct 2020 10:03:22 -0400 Subject: [PATCH] maple_tree: Fix mte_destroy_walk() overwriting slots when spinlock debug is enabled. 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 --- include/linux/maple_tree.h | 2 +- lib/maple_tree.c | 34 +++++++++++++++++++--------------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/include/linux/maple_tree.h b/include/linux/maple_tree.h index fc16e6f1a219..25348e7c17bb 100644 --- a/include/linux/maple_tree.h +++ b/include/linux/maple_tree.h @@ -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; diff --git a/lib/maple_tree.c b/lib/maple_tree.c index 6969e971356f..edb548f9d4fa 100644 --- a/lib/maple_tree.c +++ b/lib/maple_tree.c @@ -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); -- 2.50.1