Skip to content

Commit c87a124

Browse files
Eric Dumazetdavem330
authored andcommitted
net: force a reload of first item in hlist_nulls_for_each_entry_rcu
Roman Gushchin discovered that udp4_lib_lookup2() was not reloading first item in the rcu protected list, in case the loop was restarted. This produced soft lockups as in https://lkml.org/lkml/2013/4/16/37 rcu_dereference(X)/ACCESS_ONCE(X) seem to not work as intended if X is ptr->field : In some cases, gcc caches the value or ptr->field in a register. Use a barrier() to disallow such caching, as documented in Documentation/atomic_ops.txt line 114 Thanks a lot to Roman for providing analysis and numerous patches. Diagnosed-by: Roman Gushchin <[email protected]> Signed-off-by: Eric Dumazet <[email protected]> Reported-by: Boris Zhmurov <[email protected]> Signed-off-by: Roman Gushchin <[email protected]> Acked-by: Paul E. McKenney <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c802db1 commit c87a124

File tree

1 file changed

+6
-1
lines changed

1 file changed

+6
-1
lines changed

include/linux/rculist_nulls.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,14 @@ static inline void hlist_nulls_add_head_rcu(struct hlist_nulls_node *n,
105105
* @head: the head for your list.
106106
* @member: the name of the hlist_nulls_node within the struct.
107107
*
108+
* The barrier() is needed to make sure compiler doesn't cache first element [1],
109+
* as this loop can be restarted [2]
110+
* [1] Documentation/atomic_ops.txt around line 114
111+
* [2] Documentation/RCU/rculist_nulls.txt around line 146
108112
*/
109113
#define hlist_nulls_for_each_entry_rcu(tpos, pos, head, member) \
110-
for (pos = rcu_dereference_raw(hlist_nulls_first_rcu(head)); \
114+
for (({barrier();}), \
115+
pos = rcu_dereference_raw(hlist_nulls_first_rcu(head)); \
111116
(!is_a_nulls(pos)) && \
112117
({ tpos = hlist_nulls_entry(pos, typeof(*tpos), member); 1; }); \
113118
pos = rcu_dereference_raw(hlist_nulls_next_rcu(pos)))

0 commit comments

Comments
 (0)