aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2010-09-17 19:55:03 -0400
committerDavid S. Miller <davem@davemloft.net>2010-09-17 19:55:03 -0400
commitf0f9deae9e7c421fa0c1c627beb8e174325e1ba7 (patch)
tree7883b0c64cc16f1c3f3f4360a4dbcc214e6a6a22 /include/linux
parent4bdab43323b459900578b200a4b8cf9713ac8fab (diff)
netpoll: Disable IRQ around RCU dereference in netpoll_rx
We cannot use rcu_dereference_bh safely in netpoll_rx as we may be called with IRQs disabled. We could however simply disable IRQs as that too causes BH to be disabled and is safe in either case. Thanks to John Linville for discovering this bug and providing a patch. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/netpoll.h8
1 files changed, 4 insertions, 4 deletions
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index 791d5109f34c..50d8009be86c 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -63,20 +63,20 @@ static inline bool netpoll_rx(struct sk_buff *skb)
63 unsigned long flags; 63 unsigned long flags;
64 bool ret = false; 64 bool ret = false;
65 65
66 rcu_read_lock_bh(); 66 local_irq_save(flags);
67 npinfo = rcu_dereference_bh(skb->dev->npinfo); 67 npinfo = rcu_dereference_bh(skb->dev->npinfo);
68 68
69 if (!npinfo || (list_empty(&npinfo->rx_np) && !npinfo->rx_flags)) 69 if (!npinfo || (list_empty(&npinfo->rx_np) && !npinfo->rx_flags))
70 goto out; 70 goto out;
71 71
72 spin_lock_irqsave(&npinfo->rx_lock, flags); 72 spin_lock(&npinfo->rx_lock);
73 /* check rx_flags again with the lock held */ 73 /* check rx_flags again with the lock held */
74 if (npinfo->rx_flags && __netpoll_rx(skb)) 74 if (npinfo->rx_flags && __netpoll_rx(skb))
75 ret = true; 75 ret = true;
76 spin_unlock_irqrestore(&npinfo->rx_lock, flags); 76 spin_unlock(&npinfo->rx_lock);
77 77
78out: 78out:
79 rcu_read_unlock_bh(); 79 local_irq_restore(flags);
80 return ret; 80 return ret;
81} 81}
82 82