aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@linux.foundation.org>2007-06-27 03:39:42 -0400
committerDavid S. Miller <davem@davemloft.net>2007-06-27 03:39:42 -0400
commit0db3dc73f7a3a73b0dc725b6a991253f5652c905 (patch)
tree55d78b37c8fd13ba0f56e3419d4dc3f57856e781
parent48d8d7ee5dd17c64833e0343ab4ae8ef01cc2648 (diff)
[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)
250 unsigned long flags; 250 unsigned long flags;
251 251
252 local_irq_save(flags); 252 local_irq_save(flags);
253 if (netif_tx_trylock(dev)) { 253 /* try until next clock tick */
254 /* try until next clock tick */ 254 for (tries = jiffies_to_usecs(1)/USEC_PER_POLL;
255 for (tries = jiffies_to_usecs(1)/USEC_PER_POLL; 255 tries > 0; --tries) {
256 tries > 0; --tries) { 256 if (netif_tx_trylock(dev)) {
257 if (!netif_queue_stopped(dev)) 257 if (!netif_queue_stopped(dev))
258 status = dev->hard_start_xmit(skb, dev); 258 status = dev->hard_start_xmit(skb, dev);
259 netif_tx_unlock(dev);
259 260
260 if (status == NETDEV_TX_OK) 261 if (status == NETDEV_TX_OK)
261 break; 262 break;
262 263
263 /* tickle device maybe there is some cleanup */
264 netpoll_poll(np);
265
266 udelay(USEC_PER_POLL);
267 } 264 }
268 netif_tx_unlock(dev); 265
266 /* tickle device maybe there is some cleanup */
267 netpoll_poll(np);
268
269 udelay(USEC_PER_POLL);
269 } 270 }
270 local_irq_restore(flags); 271 local_irq_restore(flags);
271 } 272 }