All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH tip/core/rcu 0/4] linked-list updates for 4.5
@ 2015-12-05  0:15 Paul E. McKenney
  2015-12-05  0:15 ` [PATCH tip/core/rcu 1/4] list: Use WRITE_ONCE() when adding to lists and hlists Paul E. McKenney
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Paul E. McKenney @ 2015-12-05  0:15 UTC (permalink / raw)
  To: linux-kernel
  Cc: mingo, jiangshanlai, dipankar, akpm, mathieu.desnoyers, josh,
	tglx, peterz, rostedt, dhowells, edumazet, dvhart, fweisbec,
	oleg, bobby.prani

Hello!

This series contains a few linked-list updates:

1.	Use WRITE_ONCE() when adding to lists and hlists (reported
	by KTSAN).

2.	Use READ_ONCE() when testing for empty lists (reported by
	KTSAN).

3.	Introduce generic list_splice_tail_init_rcu(), courtesy of
	Petko Manolov.

4.	Use WRITE_ONCE() when initializing list_head structures (reported
	by KTSAN).

							Thanx, Paul

------------------------------------------------------------------------

 b/include/linux/list.h       |   14 ++++----
 b/include/linux/list_bl.h    |    2 -
 b/include/linux/list_nulls.h |    2 -
 b/include/linux/rculist.h    |   69 ++++++++++++++++++++++++++++++-------------
 b/lib/list_debug.c           |    2 -
 5 files changed, 59 insertions(+), 30 deletions(-)


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH tip/core/rcu 1/4] list: Use WRITE_ONCE() when adding to lists and hlists
  2015-12-05  0:15 [PATCH tip/core/rcu 0/4] linked-list updates for 4.5 Paul E. McKenney
@ 2015-12-05  0:15 ` Paul E. McKenney
  2015-12-05  0:15 ` [PATCH tip/core/rcu 2/4] list: Use READ_ONCE() when testing for empty lists Paul E. McKenney
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Paul E. McKenney @ 2015-12-05  0:15 UTC (permalink / raw)
  To: linux-kernel
  Cc: mingo, jiangshanlai, dipankar, akpm, mathieu.desnoyers, josh,
	tglx, peterz, rostedt, dhowells, edumazet, dvhart, fweisbec,
	oleg, bobby.prani, Paul E. McKenney

Code that does lockless emptiness testing of non-RCU lists is relying
on the list-addition code to write the list head's ->next pointer
atomically.  This commit therefore adds WRITE_ONCE() to list-addition
pointer stores that could affect the head's ->next pointer.

Reported-by: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
---
 include/linux/list.h | 8 ++++----
 lib/list_debug.c     | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/include/linux/list.h b/include/linux/list.h
index 993395a2e55c..d7e31fe398b3 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -42,7 +42,7 @@ static inline void __list_add(struct list_head *new,
 	next->prev = new;
 	new->next = next;
 	new->prev = prev;
-	prev->next = new;
+	WRITE_ONCE(prev->next, new);
 }
 #else
 extern void __list_add(struct list_head *new,
@@ -642,7 +642,7 @@ static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
 	n->next = first;
 	if (first)
 		first->pprev = &n->next;
-	h->first = n;
+	WRITE_ONCE(h->first, n);
 	n->pprev = &h->first;
 }
 
@@ -653,14 +653,14 @@ static inline void hlist_add_before(struct hlist_node *n,
 	n->pprev = next->pprev;
 	n->next = next;
 	next->pprev = &n->next;
-	*(n->pprev) = n;
+	WRITE_ONCE(*(n->pprev), n);
 }
 
 static inline void hlist_add_behind(struct hlist_node *n,
 				    struct hlist_node *prev)
 {
 	n->next = prev->next;
-	prev->next = n;
+	WRITE_ONCE(prev->next, n);
 	n->pprev = &prev->next;
 
 	if (n->next)
diff --git a/lib/list_debug.c b/lib/list_debug.c
index c24c2f7e296f..3859bf63561c 100644
--- a/lib/list_debug.c
+++ b/lib/list_debug.c
@@ -37,7 +37,7 @@ void __list_add(struct list_head *new,
 	next->prev = new;
 	new->next = next;
 	new->prev = prev;
-	prev->next = new;
+	WRITE_ONCE(prev->next, new);
 }
 EXPORT_SYMBOL(__list_add);
 
-- 
2.5.2


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH tip/core/rcu 2/4] list: Use READ_ONCE() when testing for empty lists
  2015-12-05  0:15 [PATCH tip/core/rcu 0/4] linked-list updates for 4.5 Paul E. McKenney
  2015-12-05  0:15 ` [PATCH tip/core/rcu 1/4] list: Use WRITE_ONCE() when adding to lists and hlists Paul E. McKenney
@ 2015-12-05  0:15 ` Paul E. McKenney
  2015-12-05  0:15 ` [PATCH tip/core/rcu 3/4] list: Introduces generic list_splice_tail_init_rcu() Paul E. McKenney
  2015-12-05  0:15 ` [PATCH tip/core/rcu 4/4] list: Use WRITE_ONCE() when initializing list_head structures Paul E. McKenney
  3 siblings, 0 replies; 5+ messages in thread
From: Paul E. McKenney @ 2015-12-05  0:15 UTC (permalink / raw)
  To: linux-kernel
  Cc: mingo, jiangshanlai, dipankar, akpm, mathieu.desnoyers, josh,
	tglx, peterz, rostedt, dhowells, edumazet, dvhart, fweisbec,
	oleg, bobby.prani, Paul E. McKenney

Most of the list-empty-check macros (list_empty(), hlist_empty(),
hlist_bl_empty(), hlist_nulls_empty(), and hlist_nulls_empty()) use
an unadorned load to check the list header.  Given that these macros
are sometimes invoked without the protection of a lock, this is
not sufficient.  This commit therefore adds READ_ONCE() calls to
them.  This commit does not touch llist_empty() because it already
has the needed ACCESS_ONCE().

Reported-by: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
---
 include/linux/list.h       | 4 ++--
 include/linux/list_bl.h    | 2 +-
 include/linux/list_nulls.h | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/include/linux/list.h b/include/linux/list.h
index d7e31fe398b3..06c2d887a918 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -186,7 +186,7 @@ static inline int list_is_last(const struct list_head *list,
  */
 static inline int list_empty(const struct list_head *head)
 {
-	return head->next == head;
+	return READ_ONCE(head->next) == head;
 }
 
 /**
@@ -608,7 +608,7 @@ static inline int hlist_unhashed(const struct hlist_node *h)
 
 static inline int hlist_empty(const struct hlist_head *h)
 {
-	return !h->first;
+	return !READ_ONCE(h->first);
 }
 
 static inline void __hlist_del(struct hlist_node *n)
diff --git a/include/linux/list_bl.h b/include/linux/list_bl.h
index 8132214e8efd..ee7229a6c06a 100644
--- a/include/linux/list_bl.h
+++ b/include/linux/list_bl.h
@@ -70,7 +70,7 @@ static inline void hlist_bl_set_first(struct hlist_bl_head *h,
 
 static inline int hlist_bl_empty(const struct hlist_bl_head *h)
 {
-	return !((unsigned long)h->first & ~LIST_BL_LOCKMASK);
+	return !((unsigned long)READ_ONCE(h->first) & ~LIST_BL_LOCKMASK);
 }
 
 static inline void hlist_bl_add_head(struct hlist_bl_node *n,
diff --git a/include/linux/list_nulls.h b/include/linux/list_nulls.h
index 444d2b1313bd..b01fe1009084 100644
--- a/include/linux/list_nulls.h
+++ b/include/linux/list_nulls.h
@@ -57,7 +57,7 @@ static inline int hlist_nulls_unhashed(const struct hlist_nulls_node *h)
 
 static inline int hlist_nulls_empty(const struct hlist_nulls_head *h)
 {
-	return is_a_nulls(h->first);
+	return is_a_nulls(READ_ONCE(h->first));
 }
 
 static inline void hlist_nulls_add_head(struct hlist_nulls_node *n,
-- 
2.5.2


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH tip/core/rcu 3/4] list: Introduces generic list_splice_tail_init_rcu()
  2015-12-05  0:15 [PATCH tip/core/rcu 0/4] linked-list updates for 4.5 Paul E. McKenney
  2015-12-05  0:15 ` [PATCH tip/core/rcu 1/4] list: Use WRITE_ONCE() when adding to lists and hlists Paul E. McKenney
  2015-12-05  0:15 ` [PATCH tip/core/rcu 2/4] list: Use READ_ONCE() when testing for empty lists Paul E. McKenney
@ 2015-12-05  0:15 ` Paul E. McKenney
  2015-12-05  0:15 ` [PATCH tip/core/rcu 4/4] list: Use WRITE_ONCE() when initializing list_head structures Paul E. McKenney
  3 siblings, 0 replies; 5+ messages in thread
From: Paul E. McKenney @ 2015-12-05  0:15 UTC (permalink / raw)
  To: linux-kernel
  Cc: mingo, jiangshanlai, dipankar, akpm, mathieu.desnoyers, josh,
	tglx, peterz, rostedt, dhowells, edumazet, dvhart, fweisbec,
	oleg, bobby.prani, Petko Manolov, Mimi Zohar, Paul E. McKenney

From: Petko Manolov <petkan@mip-labs.com>

The list_splice_init_rcu() can be used as a stack onto which full lists
are pushed, but queue-like behavior is now needed by some security
policies.  This requires a list_splice_tail_init_rcu().

This commit therefore supplies a list_splice_tail_init_rcu() by
pulling code common it and to list_splice_init_rcu() into a new
__list_splice_init_rcu() function.  This new function is based on the
existing list_splice_init_rcu() implementation.

Signed-off-by: Petko Manolov <petkan@mip-labs.com>
Cc: Mimi Zohar <zohar@linux.vnet.ibm.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
---
 include/linux/rculist.h | 69 +++++++++++++++++++++++++++++++++++--------------
 1 file changed, 49 insertions(+), 20 deletions(-)

diff --git a/include/linux/rculist.h b/include/linux/rculist.h
index 5ed540986019..e99d834545b6 100644
--- a/include/linux/rculist.h
+++ b/include/linux/rculist.h
@@ -179,32 +179,31 @@ static inline void list_replace_rcu(struct list_head *old,
 }
 
 /**
- * list_splice_init_rcu - splice an RCU-protected list into an existing list.
+ * __list_splice_init_rcu - join an RCU-protected list into an existing list.
  * @list:	the RCU-protected list to splice
- * @head:	the place in the list to splice the first list into
+ * @prev:	points to the last element of the existing list
+ * @next:	points to the first element of the existing list
  * @sync:	function to sync: synchronize_rcu(), synchronize_sched(), ...
  *
- * @head can be RCU-read traversed concurrently with this function.
+ * The list pointed to by @prev and @next can be RCU-read traversed
+ * concurrently with this function.
  *
  * Note that this function blocks.
  *
- * Important note: the caller must take whatever action is necessary to
- *	prevent any other updates to @head.  In principle, it is possible
- *	to modify the list as soon as sync() begins execution.
- *	If this sort of thing becomes necessary, an alternative version
- *	based on call_rcu() could be created.  But only if -really-
- *	needed -- there is no shortage of RCU API members.
+ * Important note: the caller must take whatever action is necessary to prevent
+ * any other updates to the existing list.  In principle, it is possible to
+ * modify the list as soon as sync() begins execution. If this sort of thing
+ * becomes necessary, an alternative version based on call_rcu() could be
+ * created.  But only if -really- needed -- there is no shortage of RCU API
+ * members.
  */
-static inline void list_splice_init_rcu(struct list_head *list,
-					struct list_head *head,
-					void (*sync)(void))
+static inline void __list_splice_init_rcu(struct list_head *list,
+					  struct list_head *prev,
+					  struct list_head *next,
+					  void (*sync)(void))
 {
 	struct list_head *first = list->next;
 	struct list_head *last = list->prev;
-	struct list_head *at = head->next;
-
-	if (list_empty(list))
-		return;
 
 	/*
 	 * "first" and "last" tracking list, so initialize it.  RCU readers
@@ -231,10 +230,40 @@ static inline void list_splice_init_rcu(struct list_head *list,
 	 * this function.
 	 */
 
-	last->next = at;
-	rcu_assign_pointer(list_next_rcu(head), first);
-	first->prev = head;
-	at->prev = last;
+	last->next = next;
+	rcu_assign_pointer(list_next_rcu(prev), first);
+	first->prev = prev;
+	next->prev = last;
+}
+
+/**
+ * list_splice_init_rcu - splice an RCU-protected list into an existing list,
+ *                        designed for stacks.
+ * @list:	the RCU-protected list to splice
+ * @head:	the place in the existing list to splice the first list into
+ * @sync:	function to sync: synchronize_rcu(), synchronize_sched(), ...
+ */
+static inline void list_splice_init_rcu(struct list_head *list,
+					struct list_head *head,
+					void (*sync)(void))
+{
+	if (!list_empty(list))
+		__list_splice_init_rcu(list, head, head->next, sync);
+}
+
+/**
+ * list_splice_tail_init_rcu - splice an RCU-protected list into an existing
+ *                             list, designed for queues.
+ * @list:	the RCU-protected list to splice
+ * @head:	the place in the existing list to splice the first list into
+ * @sync:	function to sync: synchronize_rcu(), synchronize_sched(), ...
+ */
+static inline void list_splice_tail_init_rcu(struct list_head *list,
+					     struct list_head *head,
+					     void (*sync)(void))
+{
+	if (!list_empty(list))
+		__list_splice_init_rcu(list, head->prev, head, sync);
 }
 
 /**
-- 
2.5.2


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH tip/core/rcu 4/4] list: Use WRITE_ONCE() when initializing list_head structures
  2015-12-05  0:15 [PATCH tip/core/rcu 0/4] linked-list updates for 4.5 Paul E. McKenney
                   ` (2 preceding siblings ...)
  2015-12-05  0:15 ` [PATCH tip/core/rcu 3/4] list: Introduces generic list_splice_tail_init_rcu() Paul E. McKenney
@ 2015-12-05  0:15 ` Paul E. McKenney
  3 siblings, 0 replies; 5+ messages in thread
From: Paul E. McKenney @ 2015-12-05  0:15 UTC (permalink / raw)
  To: linux-kernel
  Cc: mingo, jiangshanlai, dipankar, akpm, mathieu.desnoyers, josh,
	tglx, peterz, rostedt, dhowells, edumazet, dvhart, fweisbec,
	oleg, bobby.prani, Paul E. McKenney

Code that does lockless emptiness testing of non-RCU lists is relying
on INIT_LIST_HEAD() to write the list head's ->next pointer atomically,
particularly when INIT_LIST_HEAD() is invoked from list_del_init().
This commit therefore adds WRITE_ONCE() to this function's pointer stores
that could affect the head's ->next pointer.

Reported-by: Andrey Konovalov <andreyknvl@google.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
---
 include/linux/list.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/list.h b/include/linux/list.h
index 06c2d887a918..5356f4d661a7 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -24,7 +24,7 @@
 
 static inline void INIT_LIST_HEAD(struct list_head *list)
 {
-	list->next = list;
+	WRITE_ONCE(list->next, list);
 	list->prev = list;
 }
 
-- 
2.5.2


^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2015-12-05  0:16 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-12-05  0:15 [PATCH tip/core/rcu 0/4] linked-list updates for 4.5 Paul E. McKenney
2015-12-05  0:15 ` [PATCH tip/core/rcu 1/4] list: Use WRITE_ONCE() when adding to lists and hlists Paul E. McKenney
2015-12-05  0:15 ` [PATCH tip/core/rcu 2/4] list: Use READ_ONCE() when testing for empty lists Paul E. McKenney
2015-12-05  0:15 ` [PATCH tip/core/rcu 3/4] list: Introduces generic list_splice_tail_init_rcu() Paul E. McKenney
2015-12-05  0:15 ` [PATCH tip/core/rcu 4/4] list: Use WRITE_ONCE() when initializing list_head structures Paul E. McKenney

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.