mirror of
https://github.com/torvalds/linux.git
synced 2024-11-28 15:11:31 +00:00
8139too: RTNL and flush_scheduled_work deadlock
Your usual dont-flush_scheduled_work-with-RTNL-held stuff. It is a bit different here since the thread runs permanently or is only occasionally kicked for recovery depending on the hardware revision. Signed-off-by: Francois Romieu <romieu@fr.zoreil.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
parent
c014f6c8f8
commit
83cbb4d257
@ -1109,6 +1109,8 @@ static void __devexit rtl8139_remove_one (struct pci_dev *pdev)
|
||||
|
||||
assert (dev != NULL);
|
||||
|
||||
flush_scheduled_work();
|
||||
|
||||
unregister_netdev (dev);
|
||||
|
||||
__rtl8139_cleanup_dev (dev);
|
||||
@ -1603,18 +1605,21 @@ static void rtl8139_thread (struct work_struct *work)
|
||||
struct net_device *dev = tp->mii.dev;
|
||||
unsigned long thr_delay = next_tick;
|
||||
|
||||
rtnl_lock();
|
||||
|
||||
if (!netif_running(dev))
|
||||
goto out_unlock;
|
||||
|
||||
if (tp->watchdog_fired) {
|
||||
tp->watchdog_fired = 0;
|
||||
rtl8139_tx_timeout_task(work);
|
||||
} else if (rtnl_trylock()) {
|
||||
rtl8139_thread_iter (dev, tp, tp->mmio_addr);
|
||||
rtnl_unlock ();
|
||||
} else {
|
||||
/* unlikely race. mitigate with fast poll. */
|
||||
thr_delay = HZ / 2;
|
||||
}
|
||||
} else
|
||||
rtl8139_thread_iter(dev, tp, tp->mmio_addr);
|
||||
|
||||
schedule_delayed_work(&tp->thread, thr_delay);
|
||||
if (tp->have_thread)
|
||||
schedule_delayed_work(&tp->thread, thr_delay);
|
||||
out_unlock:
|
||||
rtnl_unlock ();
|
||||
}
|
||||
|
||||
static void rtl8139_start_thread(struct rtl8139_private *tp)
|
||||
@ -1626,19 +1631,11 @@ static void rtl8139_start_thread(struct rtl8139_private *tp)
|
||||
return;
|
||||
|
||||
tp->have_thread = 1;
|
||||
tp->watchdog_fired = 0;
|
||||
|
||||
schedule_delayed_work(&tp->thread, next_tick);
|
||||
}
|
||||
|
||||
static void rtl8139_stop_thread(struct rtl8139_private *tp)
|
||||
{
|
||||
if (tp->have_thread) {
|
||||
cancel_rearming_delayed_work(&tp->thread);
|
||||
tp->have_thread = 0;
|
||||
} else
|
||||
flush_scheduled_work();
|
||||
}
|
||||
|
||||
static inline void rtl8139_tx_clear (struct rtl8139_private *tp)
|
||||
{
|
||||
tp->cur_tx = 0;
|
||||
@ -1696,12 +1693,11 @@ static void rtl8139_tx_timeout (struct net_device *dev)
|
||||
{
|
||||
struct rtl8139_private *tp = netdev_priv(dev);
|
||||
|
||||
tp->watchdog_fired = 1;
|
||||
if (!tp->have_thread) {
|
||||
INIT_DELAYED_WORK(&tp->thread, rtl8139_tx_timeout_task);
|
||||
INIT_DELAYED_WORK(&tp->thread, rtl8139_thread);
|
||||
schedule_delayed_work(&tp->thread, next_tick);
|
||||
} else
|
||||
tp->watchdog_fired = 1;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
|
||||
@ -2233,8 +2229,6 @@ static int rtl8139_close (struct net_device *dev)
|
||||
|
||||
netif_stop_queue (dev);
|
||||
|
||||
rtl8139_stop_thread(tp);
|
||||
|
||||
if (netif_msg_ifdown(tp))
|
||||
printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n",
|
||||
dev->name, RTL_R16 (IntrStatus));
|
||||
|
Loading…
Reference in New Issue
Block a user