aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeil Horman <nhorman@tuxdriver.com>2010-08-11 01:12:57 -0400
committerDavid S. Miller <davem@davemloft.net>2010-08-24 04:47:40 -0400
commitaa25ab7d943a5e1e6bcc2a65ff6669144f5b5d60 (patch)
tree86b4d306cea36eb547a88f59c2568a16b9bac700
parentbf82791ed667758a0f18a4b76be2d931d2c1b39d (diff)
3c59x: Fix deadlock between boomerang_interrupt and boomerang_start_tx
If netconsole is in use, there is a possibility for deadlock in 3c59x between boomerang_interrupt and boomerang_start_xmit. Both routines take the vp->lock, and if netconsole is in use, a pr_* call from the boomerang_interrupt routine will result in the netconsole code attempting to trnasmit an skb, which can try to take the same spin lock, resulting in deadlock. The fix is pretty straightforward. This patch allocats a bit in the 3c59x private structure to indicate that its handling an interrupt. If we get into the transmit routine and that bit is set, we can be sure that we have recursed and will deadlock if we continue, so instead we just return NETDEV_TX_BUSY, so the stack requeues the skb to try again later. Signed-off-by: Neil Horman <nhorman@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/3c59x.c15
1 files changed, 14 insertions, 1 deletions
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index c754d88e5ec9..c685a55fc2f4 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -633,7 +633,8 @@ struct vortex_private {
633 open:1, 633 open:1,
634 medialock:1, 634 medialock:1,
635 must_free_region:1, /* Flag: if zero, Cardbus owns the I/O region */ 635 must_free_region:1, /* Flag: if zero, Cardbus owns the I/O region */
636 large_frames:1; /* accept large frames */ 636 large_frames:1, /* accept large frames */
637 handling_irq:1; /* private in_irq indicator */
637 int drv_flags; 638 int drv_flags;
638 u16 status_enable; 639 u16 status_enable;
639 u16 intr_enable; 640 u16 intr_enable;
@@ -2133,6 +2134,15 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev)
2133 dev->name, vp->cur_tx); 2134 dev->name, vp->cur_tx);
2134 } 2135 }
2135 2136
2137 /*
2138 * We can't allow a recursion from our interrupt handler back into the
2139 * tx routine, as they take the same spin lock, and that causes
2140 * deadlock. Just return NETDEV_TX_BUSY and let the stack try again in
2141 * a bit
2142 */
2143 if (vp->handling_irq)
2144 return NETDEV_TX_BUSY;
2145
2136 if (vp->cur_tx - vp->dirty_tx >= TX_RING_SIZE) { 2146 if (vp->cur_tx - vp->dirty_tx >= TX_RING_SIZE) {
2137 if (vortex_debug > 0) 2147 if (vortex_debug > 0)
2138 pr_warning("%s: BUG! Tx Ring full, refusing to send buffer.\n", 2148 pr_warning("%s: BUG! Tx Ring full, refusing to send buffer.\n",
@@ -2335,11 +2345,13 @@ boomerang_interrupt(int irq, void *dev_id)
2335 2345
2336 ioaddr = vp->ioaddr; 2346 ioaddr = vp->ioaddr;
2337 2347
2348
2338 /* 2349 /*
2339 * It seems dopey to put the spinlock this early, but we could race against vortex_tx_timeout 2350 * It seems dopey to put the spinlock this early, but we could race against vortex_tx_timeout
2340 * and boomerang_start_xmit 2351 * and boomerang_start_xmit
2341 */ 2352 */
2342 spin_lock(&vp->lock); 2353 spin_lock(&vp->lock);
2354 vp->handling_irq = 1;
2343 2355
2344 status = ioread16(ioaddr + EL3_STATUS); 2356 status = ioread16(ioaddr + EL3_STATUS);
2345 2357
@@ -2447,6 +2459,7 @@ boomerang_interrupt(int irq, void *dev_id)
2447 pr_debug("%s: exiting interrupt, status %4.4x.\n", 2459 pr_debug("%s: exiting interrupt, status %4.4x.\n",
2448 dev->name, status); 2460 dev->name, status);
2449handler_exit: 2461handler_exit:
2462 vp->handling_irq = 0;
2450 spin_unlock(&vp->lock); 2463 spin_unlock(&vp->lock);
2451 return IRQ_HANDLED; 2464 return IRQ_HANDLED;
2452} 2465}