sunvnet: Schedule maybe_tx_wakeup() as a tasklet from ldc_rx path
Subsystems (2)
PATCH v2 3/3 sunvnet: Schedule maybe_tx_wakeup() as a tasklet from ldc_rx path
At the tail of vnet_event(), if we hit the maybe_tx_wakeup() condition, we try to take the netif_tx_lock() in the recv-interrupt-context and can deadlock with dev_watchdog(). vnet_event() should schedule maybe_tx_wakeup() as a tasklet to avoid this deadlock
Signed-off-by Sowmini Varadhan <[email protected]>
---
v2: incorporated comments from David Miller
drivers/net/ethernet/sun/sunvnet.c | 12 ++++++++++-- drivers/net/ethernet/sun/sunvnet.h | 4 ++++ 2 files changed, 14 insertions(+), 2 deletions(-)
drivers/net/ethernet/sun/sunvnet.c +10 -2
@@ -475,8 +475,9 @@ static int handle_mcast(struct vnet_port *port, void *msgbuf)return 0 ; } -static void maybe_tx_wakeup (struct vnet *vp) +static void maybe_tx_wakeup (unsigned long param) { +struct vnet *vp = (struct vnet *)param;struct net_device *dev = vp->dev;netif_tx_lock (dev);
@@ -573,8 +574,13 @@ static void vnet_event(void *arg, int event)break ; }spin_unlock (&vio->lock); +/* Kick off a tasklet to wake the queue. We cannot call +* maybe_tx_wakeup directly here because we could deadlock on +* netif_tx_lock() with dev_watchdog() +*/ if (unlikely (tx_wakeup && err != -ECONNRESET )) -maybe_tx_wakeup (port->vp); +tasklet_schedule (&port->vp->vnet_tx_wakeup); +local_irq_restore (flags); }
@@ -1046,6 +1052,7 @@ static struct vnet *vnet_new(const u64 *local_mac) vp =netdev_priv (dev);spin_lock_init (&vp->lock); +tasklet_init (&vp->vnet_tx_wakeup, maybe_tx_wakeup, (unsigned long )vp); vp->dev = dev;INIT_LIST_HEAD (&vp->port_list);
@@ -1105,6 +1112,7 @@ static void vnet_cleanup(void) vp = list_first_entry(&vnet_list, struct vnet, list);list_del (&vp->list); dev = vp->dev; +tasklet_kill (&vp->vnet_tx_wakeup);/* vio_unregister_driver() should have cleaned up port_list */ BUG_ON (!list_empty (&vp->port_list));unregister_netdev (dev);
drivers/net/ethernet/sun/sunvnet.h +4 -0
@@ -1,6 +1,8 @@#ifndef _SUNVNET_H#define _SUNVNET_H +#include <linux/interrupt.h> +#define DESC_NCOOKIES (entry_size) \ ((entry_size) - sizeof(struct vio_net_desc))
@@ -78,6 +80,8 @@ struct vnet {struct list_head list;u64 local_mac; + + struct tasklet_struct vnet_tx_wakeup; };#endif /* _SUNVNET_H */
Signature · 1 line
1.8.4.2
From: Sowmini Varadhan <[email protected]>
Date: Wed, 13 Aug 2014 10:29:41 -0400
Quoted 7 lines
At the tail of
vnet_event(), if we hit themaybe_tx_wakeup()condition, we try to take thenetif_tx_lock()in the recv-interrupt-context and can deadlock withdev_watchdog().vnet_event()should schedulemaybe_tx_wakeup()as a tasklet to avoid this deadlockSigned-off-by Sowmini Varadhan <[email protected]>
Applied, thanks.