diff options
author | Francois Romieu <romieu@fr.zoreil.com> | 2007-02-15 23:37:21 +0100 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-02-20 11:18:12 -0500 |
commit | eb2a021c4710b98081daa797d5a729ac23c240cd (patch) | |
tree | 93f0d67ed4fef48fa324f33890bec242e35fbfe0 | |
parent | 1ca949299260aa49eeba34ff912e2321c8b1f647 (diff) | |
download | linux-eb2a021c4710b98081daa797d5a729ac23c240cd.tar.gz linux-eb2a021c4710b98081daa797d5a729ac23c240cd.tar.bz2 linux-eb2a021c4710b98081daa797d5a729ac23c240cd.zip |
r8169: RTNL and flush_scheduled_work deadlock
flush_scheduled_work() in net_device->close has a slight tendency
to deadlock with tasks on the workqueue that hold RTNL.
rtl8169_close/down simply need the recovery tasks to not meddle
with the hardware while the device is going down.
Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r-- | drivers/net/r8169.c | 25 |
1 files changed, 18 insertions, 7 deletions
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 5598d86380b4..13cf06ee97f7 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -1733,6 +1733,8 @@ rtl8169_remove_one(struct pci_dev *pdev) assert(dev != NULL); assert(tp != NULL); + flush_scheduled_work(); + unregister_netdev(dev); rtl8169_release_board(pdev, dev, tp->mmio_addr); pci_set_drvdata(pdev, NULL); @@ -2161,10 +2163,13 @@ static void rtl8169_reinit_task(struct work_struct *work) struct net_device *dev = tp->dev; int ret; - if (netif_running(dev)) { - rtl8169_wait_for_quiescence(dev); - rtl8169_close(dev); - } + rtnl_lock(); + + if (!netif_running(dev)) + goto out_unlock; + + rtl8169_wait_for_quiescence(dev); + rtl8169_close(dev); ret = rtl8169_open(dev); if (unlikely(ret < 0)) { @@ -2179,6 +2184,9 @@ static void rtl8169_reinit_task(struct work_struct *work) } rtl8169_schedule_work(dev, rtl8169_reinit_task); } + +out_unlock: + rtnl_unlock(); } static void rtl8169_reset_task(struct work_struct *work) @@ -2187,8 +2195,10 @@ static void rtl8169_reset_task(struct work_struct *work) container_of(work, struct rtl8169_private, task.work); struct net_device *dev = tp->dev; + rtnl_lock(); + if (!netif_running(dev)) - return; + goto out_unlock; rtl8169_wait_for_quiescence(dev); @@ -2210,6 +2220,9 @@ static void rtl8169_reset_task(struct work_struct *work) } rtl8169_schedule_work(dev, rtl8169_reset_task); } + +out_unlock: + rtnl_unlock(); } static void rtl8169_tx_timeout(struct net_device *dev) @@ -2722,8 +2735,6 @@ static void rtl8169_down(struct net_device *dev) netif_stop_queue(dev); - flush_scheduled_work(); - core_down: spin_lock_irq(&tp->lock); |