Commit a664a4f7 authored by Shlomo Pongratz's avatar Shlomo Pongratz Committed by David S. Miller

net/ipv4: Use proper RCU APIs for writer-side in udp_offload.c

RCU writer side should use rcu_dereference_protected() and not
rcu_dereference(), fix that. This also removes the "suspicious RCU usage"
warning seen when running with CONFIG_PROVE_RCU.

Also, don't use rcu_assign_pointer/rcu_dereference for pointers
which are invisible beyond the udp offload code.

Fixes: b582ef09 ('net: Add GRO support for UDP encapsulating protocols')
Reported-by: default avatarEric Dumazet <edumazet@google.com>
Cc: Eric Dumazet <edumazet@google.com>
Signed-off-by: default avatarOr Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: default avatarShlomo Pongratz <shlomop@mellanox.com>
Acked-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9330ed16
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
static DEFINE_SPINLOCK(udp_offload_lock); static DEFINE_SPINLOCK(udp_offload_lock);
static struct udp_offload_priv __rcu *udp_offload_base __read_mostly; static struct udp_offload_priv __rcu *udp_offload_base __read_mostly;
#define udp_deref_protected(X) rcu_dereference_protected(X, lockdep_is_held(&udp_offload_lock))
struct udp_offload_priv { struct udp_offload_priv {
struct udp_offload *offload; struct udp_offload *offload;
struct rcu_head rcu; struct rcu_head rcu;
...@@ -100,7 +102,6 @@ static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, ...@@ -100,7 +102,6 @@ static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
int udp_add_offload(struct udp_offload *uo) int udp_add_offload(struct udp_offload *uo)
{ {
struct udp_offload_priv __rcu **head = &udp_offload_base;
struct udp_offload_priv *new_offload = kzalloc(sizeof(*new_offload), GFP_ATOMIC); struct udp_offload_priv *new_offload = kzalloc(sizeof(*new_offload), GFP_ATOMIC);
if (!new_offload) if (!new_offload)
...@@ -109,8 +110,8 @@ int udp_add_offload(struct udp_offload *uo) ...@@ -109,8 +110,8 @@ int udp_add_offload(struct udp_offload *uo)
new_offload->offload = uo; new_offload->offload = uo;
spin_lock(&udp_offload_lock); spin_lock(&udp_offload_lock);
rcu_assign_pointer(new_offload->next, rcu_dereference(*head)); new_offload->next = udp_offload_base;
rcu_assign_pointer(*head, new_offload); rcu_assign_pointer(udp_offload_base, new_offload);
spin_unlock(&udp_offload_lock); spin_unlock(&udp_offload_lock);
return 0; return 0;
...@@ -130,12 +131,12 @@ void udp_del_offload(struct udp_offload *uo) ...@@ -130,12 +131,12 @@ void udp_del_offload(struct udp_offload *uo)
spin_lock(&udp_offload_lock); spin_lock(&udp_offload_lock);
uo_priv = rcu_dereference(*head); uo_priv = udp_deref_protected(*head);
for (; uo_priv != NULL; for (; uo_priv != NULL;
uo_priv = rcu_dereference(*head)) { uo_priv = udp_deref_protected(*head)) {
if (uo_priv->offload == uo) { if (uo_priv->offload == uo) {
rcu_assign_pointer(*head, rcu_dereference(uo_priv->next)); rcu_assign_pointer(*head,
udp_deref_protected(uo_priv->next));
goto unlock; goto unlock;
} }
head = &uo_priv->next; head = &uo_priv->next;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment