summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@linux.foundation.org>2007-06-27 09:39:42 +0200
committerDavid S. Miller <davem@davemloft.net>2007-06-27 09:39:42 +0200
commit0db3dc73f7a3a73b0dc725b6a991253f5652c905 (patch)
tree55d78b37c8fd13ba0f56e3419d4dc3f57856e781
parentx86_64 irq: use mask/unmask and proper locking in fixup_irqs() (diff)
downloadlinux-0db3dc73f7a3a73b0dc725b6a991253f5652c905.tar.xz
linux-0db3dc73f7a3a73b0dc725b6a991253f5652c905.zip
[NETPOLL]: tx lock deadlock fix
If sky2 device poll routine is called from netpoll_send_skb, it would deadlock. The netpoll_send_skb held the netif_tx_lock, and the poll routine could acquire it to clean up skb's. Other drivers might use same locking model. The driver is correct, netpoll should not introduce more locking problems than it causes already. So change the code to drop lock before calling poll handler. Signed-off-by: Stephen Hemminger <shemminger@linux.foundation.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/core/netpoll.c19
1 files changed, 10 insertions, 9 deletions
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 758dafe284c0..f8e74e511ce6 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -250,22 +250,23 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
unsigned long flags;
local_irq_save(flags);
- if (netif_tx_trylock(dev)) {
- /* try until next clock tick */
- for (tries = jiffies_to_usecs(1)/USEC_PER_POLL;
- tries > 0; --tries) {
+ /* try until next clock tick */
+ for (tries = jiffies_to_usecs(1)/USEC_PER_POLL;
+ tries > 0; --tries) {
+ if (netif_tx_trylock(dev)) {
if (!netif_queue_stopped(dev))
status = dev->hard_start_xmit(skb, dev);
+ netif_tx_unlock(dev);
if (status == NETDEV_TX_OK)
break;
- /* tickle device maybe there is some cleanup */
- netpoll_poll(np);
-
- udelay(USEC_PER_POLL);
}
- netif_tx_unlock(dev);
+
+ /* tickle device maybe there is some cleanup */
+ netpoll_poll(np);
+
+ udelay(USEC_PER_POLL);
}
local_irq_restore(flags);
}