Skip to content

Commit 2e5b492

Browse files
howlettakpm00
authored andcommitted
maple_tree: fix freeing of nodes in rcu mode
The walk to destroy the nodes was not always setting the node type and would result in a destroy method potentially using the values as nodes. Avoid this by setting the correct node types. This is necessary for the RCU mode of the maple tree. Link: https://lkml.kernel.org/r/20230227173632.3292573-4-surenb@google.com Fixes: 54a611b ("Maple Tree: add new data structure") Signed-off-by: Liam Howlett <Liam.Howlett@oracle.com> Signed-off-by: Suren Baghdasaryan <surenb@google.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent a7b92d5 commit 2e5b492

1 file changed

Lines changed: 62 additions & 11 deletions

File tree

lib/maple_tree.c

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,44 @@ static inline void ma_set_meta(struct maple_node *mn, enum maple_type mt,
902902
meta->end = end;
903903
}
904904

905+
/*
906+
* mas_clear_meta() - clear the metadata information of a node, if it exists
907+
* @mas: The maple state
908+
* @mn: The maple node
909+
* @mt: The maple node type
910+
* @offset: The offset of the highest sub-gap in this node.
911+
* @end: The end of the data in this node.
912+
*/
913+
static inline void mas_clear_meta(struct ma_state *mas, struct maple_node *mn,
914+
enum maple_type mt)
915+
{
916+
struct maple_metadata *meta;
917+
unsigned long *pivots;
918+
void __rcu **slots;
919+
void *next;
920+
921+
switch (mt) {
922+
case maple_range_64:
923+
pivots = mn->mr64.pivot;
924+
if (unlikely(pivots[MAPLE_RANGE64_SLOTS - 2])) {
925+
slots = mn->mr64.slot;
926+
next = mas_slot_locked(mas, slots,
927+
MAPLE_RANGE64_SLOTS - 1);
928+
if (unlikely((mte_to_node(next) && mte_node_type(next))))
929+
return; /* The last slot is a node, no metadata */
930+
}
931+
fallthrough;
932+
case maple_arange_64:
933+
meta = ma_meta(mn, mt);
934+
break;
935+
default:
936+
return;
937+
}
938+
939+
meta->gap = 0;
940+
meta->end = 0;
941+
}
942+
905943
/*
906944
* ma_meta_end() - Get the data end of a node from the metadata
907945
* @mn: The maple node
@@ -5441,20 +5479,22 @@ static inline int mas_rev_alloc(struct ma_state *mas, unsigned long min,
54415479
* mas_dead_leaves() - Mark all leaves of a node as dead.
54425480
* @mas: The maple state
54435481
* @slots: Pointer to the slot array
5482+
* @type: The maple node type
54445483
*
54455484
* Must hold the write lock.
54465485
*
54475486
* Return: The number of leaves marked as dead.
54485487
*/
54495488
static inline
5450-
unsigned char mas_dead_leaves(struct ma_state *mas, void __rcu **slots)
5489+
unsigned char mas_dead_leaves(struct ma_state *mas, void __rcu **slots,
5490+
enum maple_type mt)
54515491
{
54525492
struct maple_node *node;
54535493
enum maple_type type;
54545494
void *entry;
54555495
int offset;
54565496

5457-
for (offset = 0; offset < mt_slot_count(mas->node); offset++) {
5497+
for (offset = 0; offset < mt_slots[mt]; offset++) {
54585498
entry = mas_slot_locked(mas, slots, offset);
54595499
type = mte_node_type(entry);
54605500
node = mte_to_node(entry);
@@ -5473,14 +5513,13 @@ unsigned char mas_dead_leaves(struct ma_state *mas, void __rcu **slots)
54735513

54745514
static void __rcu **mas_dead_walk(struct ma_state *mas, unsigned char offset)
54755515
{
5476-
struct maple_node *node, *next;
5516+
struct maple_node *next;
54775517
void __rcu **slots = NULL;
54785518

54795519
next = mas_mn(mas);
54805520
do {
5481-
mas->node = ma_enode_ptr(next);
5482-
node = mas_mn(mas);
5483-
slots = ma_slots(node, node->type);
5521+
mas->node = mt_mk_node(next, next->type);
5522+
slots = ma_slots(next, next->type);
54845523
next = mas_slot_locked(mas, slots, offset);
54855524
offset = 0;
54865525
} while (!ma_is_leaf(next->type));
@@ -5544,11 +5583,14 @@ static inline void __rcu **mas_destroy_descend(struct ma_state *mas,
55445583
node = mas_mn(mas);
55455584
slots = ma_slots(node, mte_node_type(mas->node));
55465585
next = mas_slot_locked(mas, slots, 0);
5547-
if ((mte_dead_node(next)))
5586+
if ((mte_dead_node(next))) {
5587+
mte_to_node(next)->type = mte_node_type(next);
55485588
next = mas_slot_locked(mas, slots, 1);
5589+
}
55495590

55505591
mte_set_node_dead(mas->node);
55515592
node->type = mte_node_type(mas->node);
5593+
mas_clear_meta(mas, node, node->type);
55525594
node->piv_parent = prev;
55535595
node->parent_slot = offset;
55545596
offset = 0;
@@ -5568,21 +5610,27 @@ static void mt_destroy_walk(struct maple_enode *enode, unsigned char ma_flags,
55685610

55695611
MA_STATE(mas, &mt, 0, 0);
55705612

5571-
if (mte_is_leaf(enode))
5613+
mas.node = enode;
5614+
if (mte_is_leaf(enode)) {
5615+
node->type = mte_node_type(enode);
55725616
goto free_leaf;
5617+
}
55735618

5619+
ma_flags &= ~MT_FLAGS_LOCK_MASK;
55745620
mt_init_flags(&mt, ma_flags);
55755621
mas_lock(&mas);
55765622

5577-
mas.node = start = enode;
5623+
mte_to_node(enode)->ma_flags = ma_flags;
5624+
start = enode;
55785625
slots = mas_destroy_descend(&mas, start, 0);
55795626
node = mas_mn(&mas);
55805627
do {
55815628
enum maple_type type;
55825629
unsigned char offset;
55835630
struct maple_enode *parent, *tmp;
55845631

5585-
node->slot_len = mas_dead_leaves(&mas, slots);
5632+
node->type = mte_node_type(mas.node);
5633+
node->slot_len = mas_dead_leaves(&mas, slots, node->type);
55865634
if (free)
55875635
mt_free_bulk(node->slot_len, slots);
55885636
offset = node->parent_slot + 1;
@@ -5606,7 +5654,8 @@ static void mt_destroy_walk(struct maple_enode *enode, unsigned char ma_flags,
56065654
} while (start != mas.node);
56075655

56085656
node = mas_mn(&mas);
5609-
node->slot_len = mas_dead_leaves(&mas, slots);
5657+
node->type = mte_node_type(mas.node);
5658+
node->slot_len = mas_dead_leaves(&mas, slots, node->type);
56105659
if (free)
56115660
mt_free_bulk(node->slot_len, slots);
56125661

@@ -5616,6 +5665,8 @@ static void mt_destroy_walk(struct maple_enode *enode, unsigned char ma_flags,
56165665
free_leaf:
56175666
if (free)
56185667
mt_free_rcu(&node->rcu);
5668+
else
5669+
mas_clear_meta(&mas, node, node->type);
56195670
}
56205671

56215672
/*

0 commit comments

Comments
 (0)