aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2016-07-01 02:53:51 -0400
committerDavid Howells <dhowells@redhat.com>2016-07-06 05:51:14 -0400
commitc1adf20052d80f776849fa2c1acb472cdeb7786c (patch)
treee73407fdc52ab77e9666ae7798c8b38b6da1ed09 /lib
parent1291e9d1084506c5cba6313ce809d7516bb5868a (diff)
Introduce rb_replace_node_rcu()
Implement an RCU-safe variant of rb_replace_node() and rearrange rb_replace_node() to do things in the same order. Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/rbtree.c26
1 files changed, 24 insertions, 2 deletions
diff --git a/lib/rbtree.c b/lib/rbtree.c
index 1356454e36de..eb8a19fee110 100644
--- a/lib/rbtree.c
+++ b/lib/rbtree.c
@@ -539,17 +539,39 @@ void rb_replace_node(struct rb_node *victim, struct rb_node *new,
539{ 539{
540 struct rb_node *parent = rb_parent(victim); 540 struct rb_node *parent = rb_parent(victim);
541 541
542 /* Copy the pointers/colour from the victim to the replacement */
543 *new = *victim;
544
542 /* Set the surrounding nodes to point to the replacement */ 545 /* Set the surrounding nodes to point to the replacement */
543 __rb_change_child(victim, new, parent, root);
544 if (victim->rb_left) 546 if (victim->rb_left)
545 rb_set_parent(victim->rb_left, new); 547 rb_set_parent(victim->rb_left, new);
546 if (victim->rb_right) 548 if (victim->rb_right)
547 rb_set_parent(victim->rb_right, new); 549 rb_set_parent(victim->rb_right, new);
550 __rb_change_child(victim, new, parent, root);
551}
552EXPORT_SYMBOL(rb_replace_node);
553
554void rb_replace_node_rcu(struct rb_node *victim, struct rb_node *new,
555 struct rb_root *root)
556{
557 struct rb_node *parent = rb_parent(victim);
548 558
549 /* Copy the pointers/colour from the victim to the replacement */ 559 /* Copy the pointers/colour from the victim to the replacement */
550 *new = *victim; 560 *new = *victim;
561
562 /* Set the surrounding nodes to point to the replacement */
563 if (victim->rb_left)
564 rb_set_parent(victim->rb_left, new);
565 if (victim->rb_right)
566 rb_set_parent(victim->rb_right, new);
567
568 /* Set the parent's pointer to the new node last after an RCU barrier
569 * so that the pointers onwards are seen to be set correctly when doing
570 * an RCU walk over the tree.
571 */
572 __rb_change_child_rcu(victim, new, parent, root);
551} 573}
552EXPORT_SYMBOL(rb_replace_node); 574EXPORT_SYMBOL(rb_replace_node_rcu);
553 575
554static struct rb_node *rb_left_deepest_node(const struct rb_node *node) 576static struct rb_node *rb_left_deepest_node(const struct rb_node *node)
555{ 577{