Skip to content

Commit c13af03

Browse files
howlettakpm00
authored andcommitted
maple_tree: fix write memory barrier of nodes once dead for RCU mode
During the development of the maple tree, the strategy of freeing multiple nodes changed and, in the process, the pivots were reused to store pointers to dead nodes. To ensure the readers see accurate pivots, the writers need to mark the nodes as dead and call smp_wmb() to ensure any readers can identify the node as dead before using the pivot values. There were two places where the old method of marking the node as dead without smp_wmb() were being used, which resulted in RCU readers seeing the wrong pivot value before seeing the node was dead. Fix this race condition by using mte_set_node_dead() which has the smp_wmb() call to ensure the race is closed. Add a WARN_ON() to the ma_free_rcu() call to ensure all nodes being freed are marked as dead to ensure there are no other call paths besides the two updated paths. This is necessary for the RCU mode of the maple tree. Link: https://lkml.kernel.org/r/[email protected] Fixes: 54a611b ("Maple Tree: add new data structure") Signed-off-by: Liam R. Howlett <[email protected]> Signed-off-by: Suren Baghdasaryan <[email protected]> Cc: <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 8372f4d commit c13af03

File tree

2 files changed

+21
-2
lines changed

2 files changed

+21
-2
lines changed

lib/maple_tree.c

+5-2
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ static void mt_free_rcu(struct rcu_head *head)
185185
*/
186186
static void ma_free_rcu(struct maple_node *node)
187187
{
188-
node->parent = ma_parent_ptr(node);
188+
WARN_ON(node->parent != ma_parent_ptr(node));
189189
call_rcu(&node->rcu, mt_free_rcu);
190190
}
191191

@@ -1778,8 +1778,10 @@ static inline void mas_replace(struct ma_state *mas, bool advanced)
17781778
rcu_assign_pointer(slots[offset], mas->node);
17791779
}
17801780

1781-
if (!advanced)
1781+
if (!advanced) {
1782+
mte_set_node_dead(old_enode);
17821783
mas_free(mas, old_enode);
1784+
}
17831785
}
17841786

17851787
/*
@@ -4218,6 +4220,7 @@ static inline bool mas_wr_node_store(struct ma_wr_state *wr_mas)
42184220
done:
42194221
mas_leaf_set_meta(mas, newnode, dst_pivots, maple_leaf_64, new_end);
42204222
if (in_rcu) {
4223+
mte_set_node_dead(mas->node);
42214224
mas->node = mt_mk_node(newnode, wr_mas->type);
42224225
mas_replace(mas, false);
42234226
} else {

tools/testing/radix-tree/maple.c

+16
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ static noinline void check_new_node(struct maple_tree *mt)
108108
MT_BUG_ON(mt, mn->slot[1] != NULL);
109109
MT_BUG_ON(mt, mas_allocated(&mas) != 0);
110110

111+
mn->parent = ma_parent_ptr(mn);
111112
ma_free_rcu(mn);
112113
mas.node = MAS_START;
113114
mas_nomem(&mas, GFP_KERNEL);
@@ -160,6 +161,7 @@ static noinline void check_new_node(struct maple_tree *mt)
160161
MT_BUG_ON(mt, mas_allocated(&mas) != i);
161162
MT_BUG_ON(mt, !mn);
162163
MT_BUG_ON(mt, not_empty(mn));
164+
mn->parent = ma_parent_ptr(mn);
163165
ma_free_rcu(mn);
164166
}
165167

@@ -192,6 +194,7 @@ static noinline void check_new_node(struct maple_tree *mt)
192194
MT_BUG_ON(mt, not_empty(mn));
193195
MT_BUG_ON(mt, mas_allocated(&mas) != i - 1);
194196
MT_BUG_ON(mt, !mn);
197+
mn->parent = ma_parent_ptr(mn);
195198
ma_free_rcu(mn);
196199
}
197200

@@ -210,6 +213,7 @@ static noinline void check_new_node(struct maple_tree *mt)
210213
mn = mas_pop_node(&mas);
211214
MT_BUG_ON(mt, not_empty(mn));
212215
MT_BUG_ON(mt, mas_allocated(&mas) != j - 1);
216+
mn->parent = ma_parent_ptr(mn);
213217
ma_free_rcu(mn);
214218
}
215219
MT_BUG_ON(mt, mas_allocated(&mas) != 0);
@@ -233,6 +237,7 @@ static noinline void check_new_node(struct maple_tree *mt)
233237
MT_BUG_ON(mt, mas_allocated(&mas) != i - j);
234238
mn = mas_pop_node(&mas);
235239
MT_BUG_ON(mt, not_empty(mn));
240+
mn->parent = ma_parent_ptr(mn);
236241
ma_free_rcu(mn);
237242
MT_BUG_ON(mt, mas_allocated(&mas) != i - j - 1);
238243
}
@@ -269,6 +274,7 @@ static noinline void check_new_node(struct maple_tree *mt)
269274
mn = mas_pop_node(&mas); /* get the next node. */
270275
MT_BUG_ON(mt, mn == NULL);
271276
MT_BUG_ON(mt, not_empty(mn));
277+
mn->parent = ma_parent_ptr(mn);
272278
ma_free_rcu(mn);
273279
}
274280
MT_BUG_ON(mt, mas_allocated(&mas) != 0);
@@ -294,6 +300,7 @@ static noinline void check_new_node(struct maple_tree *mt)
294300
mn = mas_pop_node(&mas2); /* get the next node. */
295301
MT_BUG_ON(mt, mn == NULL);
296302
MT_BUG_ON(mt, not_empty(mn));
303+
mn->parent = ma_parent_ptr(mn);
297304
ma_free_rcu(mn);
298305
}
299306
MT_BUG_ON(mt, mas_allocated(&mas2) != 0);
@@ -334,10 +341,12 @@ static noinline void check_new_node(struct maple_tree *mt)
334341
MT_BUG_ON(mt, mas_allocated(&mas) != MAPLE_ALLOC_SLOTS + 2);
335342
mn = mas_pop_node(&mas);
336343
MT_BUG_ON(mt, not_empty(mn));
344+
mn->parent = ma_parent_ptr(mn);
337345
ma_free_rcu(mn);
338346
for (i = 1; i <= MAPLE_ALLOC_SLOTS + 1; i++) {
339347
mn = mas_pop_node(&mas);
340348
MT_BUG_ON(mt, not_empty(mn));
349+
mn->parent = ma_parent_ptr(mn);
341350
ma_free_rcu(mn);
342351
}
343352
MT_BUG_ON(mt, mas_allocated(&mas) != 0);
@@ -375,17 +384,21 @@ static noinline void check_new_node(struct maple_tree *mt)
375384
mas_node_count(&mas, i); /* Request */
376385
mas_nomem(&mas, GFP_KERNEL); /* Fill request */
377386
mn = mas_pop_node(&mas); /* get the next node. */
387+
mn->parent = ma_parent_ptr(mn);
378388
ma_free_rcu(mn);
379389
mas_destroy(&mas);
380390

381391
mas.node = MA_ERROR(-ENOMEM);
382392
mas_node_count(&mas, i); /* Request */
383393
mas_nomem(&mas, GFP_KERNEL); /* Fill request */
384394
mn = mas_pop_node(&mas); /* get the next node. */
395+
mn->parent = ma_parent_ptr(mn);
385396
ma_free_rcu(mn);
386397
mn = mas_pop_node(&mas); /* get the next node. */
398+
mn->parent = ma_parent_ptr(mn);
387399
ma_free_rcu(mn);
388400
mn = mas_pop_node(&mas); /* get the next node. */
401+
mn->parent = ma_parent_ptr(mn);
389402
ma_free_rcu(mn);
390403
mas_destroy(&mas);
391404
}
@@ -35369,6 +35382,7 @@ static noinline void check_prealloc(struct maple_tree *mt)
3536935382
MT_BUG_ON(mt, allocated != 1 + height * 3);
3537035383
mn = mas_pop_node(&mas);
3537135384
MT_BUG_ON(mt, mas_allocated(&mas) != allocated - 1);
35385+
mn->parent = ma_parent_ptr(mn);
3537235386
ma_free_rcu(mn);
3537335387
MT_BUG_ON(mt, mas_preallocate(&mas, GFP_KERNEL) != 0);
3537435388
mas_destroy(&mas);
@@ -35386,6 +35400,7 @@ static noinline void check_prealloc(struct maple_tree *mt)
3538635400
mas_destroy(&mas);
3538735401
allocated = mas_allocated(&mas);
3538835402
MT_BUG_ON(mt, allocated != 0);
35403+
mn->parent = ma_parent_ptr(mn);
3538935404
ma_free_rcu(mn);
3539035405

3539135406
MT_BUG_ON(mt, mas_preallocate(&mas, GFP_KERNEL) != 0);
@@ -35756,6 +35771,7 @@ void farmer_tests(void)
3575635771
tree.ma_root = mt_mk_node(node, maple_leaf_64);
3575735772
mt_dump(&tree);
3575835773

35774+
node->parent = ma_parent_ptr(node);
3575935775
ma_free_rcu(node);
3576035776

3576135777
/* Check things that will make lockdep angry */

0 commit comments

Comments
 (0)