list: Use READ_ONCE() when testing for empty lists
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Mon, 21 Sep 2015 00:03:16 +0000 (17:03 -0700)
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Mon, 23 Nov 2015 18:37:35 +0000 (10:37 -0800)
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
include/linux/list_bl.h
include/linux/list_nulls.h

index d7e31fe398b3b7d980ec7d6b09dccd68f747a566..06c2d887a918867a64757e65e913e9a862385b61 100644 (file)
@@ -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)
index 8132214e8efd2930ff752fcc4c37da7d23b9643f..ee7229a6c06ae5e0f130056c8fadc80d0b733601 100644 (file)
@@ -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,
index 444d2b1313bda37647b1660e4582202a7e3b66e4..b01fe100908430708df0df5162594b497ffdad62 100644 (file)
@@ -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,