sctp: do not clear chunk->ecn_ce_done flag
[cascardo/linux.git] / lib / rbtree.c
index 1356454..eb8a19f 100644 (file)
@@ -539,17 +539,39 @@ void rb_replace_node(struct rb_node *victim, struct rb_node *new,
 {
        struct rb_node *parent = rb_parent(victim);
 
+       /* Copy the pointers/colour from the victim to the replacement */
+       *new = *victim;
+
        /* Set the surrounding nodes to point to the replacement */
-       __rb_change_child(victim, new, parent, root);
        if (victim->rb_left)
                rb_set_parent(victim->rb_left, new);
        if (victim->rb_right)
                rb_set_parent(victim->rb_right, new);
+       __rb_change_child(victim, new, parent, root);
+}
+EXPORT_SYMBOL(rb_replace_node);
+
+void rb_replace_node_rcu(struct rb_node *victim, struct rb_node *new,
+                        struct rb_root *root)
+{
+       struct rb_node *parent = rb_parent(victim);
 
        /* Copy the pointers/colour from the victim to the replacement */
        *new = *victim;
+
+       /* Set the surrounding nodes to point to the replacement */
+       if (victim->rb_left)
+               rb_set_parent(victim->rb_left, new);
+       if (victim->rb_right)
+               rb_set_parent(victim->rb_right, new);
+
+       /* Set the parent's pointer to the new node last after an RCU barrier
+        * so that the pointers onwards are seen to be set correctly when doing
+        * an RCU walk over the tree.
+        */
+       __rb_change_child_rcu(victim, new, parent, root);
 }
-EXPORT_SYMBOL(rb_replace_node);
+EXPORT_SYMBOL(rb_replace_node_rcu);
 
 static struct rb_node *rb_left_deepest_node(const struct rb_node *node)
 {