summaryrefslogtreecommitdiffstats
path: root/include/linux/rculist.h
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2020-04-24 11:19:10 -0500
committerEric W. Biederman <ebiederm@xmission.com>2020-04-28 16:08:54 -0500
commit35fc0e3b0bd5be3b059e53ae90c4536ee4922330 (patch)
treea461194992f27f31aad43d2c15ee8e0c53d81b91 /include/linux/rculist.h
parent3147d8aaa03eac0e68742621e8f05323459aa37d (diff)
downloadlinux-35fc0e3b0bd5be3b059e53ae90c4536ee4922330.tar.gz
linux-35fc0e3b0bd5be3b059e53ae90c4536ee4922330.tar.bz2
linux-35fc0e3b0bd5be3b059e53ae90c4536ee4922330.zip
rculist: Add hlists_swap_heads_rcu
Using the struct pid to refer to two tasks in de_thread was a clever idea and ultimately too clever, as it has lead to proc_flush_task being called inconsistently. To support rectifying this add hlists_swap_heads_rcu. An hlist primitive that just swaps the hlist heads of two lists. This is exactly what is needed for exchanging the pids of two tasks. Only consideration of correctness of the code has been given, as the caller is expected to be a slowpath. Link: https://lore.kernel.org/lkml/87mu6vajnq.fsf_-_@x220.int.ebiederm.org/ Acked-by: Linus Torvalds <torvalds@linux-foundation.org> Acked-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Diffstat (limited to 'include/linux/rculist.h')
-rw-r--r--include/linux/rculist.h21
1 files changed, 21 insertions, 0 deletions
diff --git a/include/linux/rculist.h b/include/linux/rculist.h
index 8214cdc715f2..67867e0d4cec 100644
--- a/include/linux/rculist.h
+++ b/include/linux/rculist.h
@@ -506,6 +506,27 @@ static inline void hlist_replace_rcu(struct hlist_node *old,
WRITE_ONCE(old->pprev, LIST_POISON2);
}
+/**
+ * hlists_swap_heads_rcu - swap the lists the hlist heads point to
+ * @left: The hlist head on the left
+ * @right: The hlist head on the right
+ *
+ * The lists start out as [@left ][node1 ... ] and
+ [@right ][node2 ... ]
+ * The lists end up as [@left ][node2 ... ]
+ * [@right ][node1 ... ]
+ */
+static inline void hlists_swap_heads_rcu(struct hlist_head *left, struct hlist_head *right)
+{
+ struct hlist_node *node1 = left->first;
+ struct hlist_node *node2 = right->first;
+
+ rcu_assign_pointer(left->first, node2);
+ rcu_assign_pointer(right->first, node1);
+ WRITE_ONCE(node2->pprev, &left->first);
+ WRITE_ONCE(node1->pprev, &right->first);
+}
+
/*
* return the first or the next element in an RCU protected hlist
*/