Commit 74a1b1ea authored by Vladimir Davydov's avatar Vladimir Davydov Committed by Jeff Kirsher

e1000: fix possible reset_task running after adapter down

On e1000_down(), we should ensure every asynchronous work is canceled
before proceeding. Since the watchdog_task can schedule other works
apart from itself, it should be stopped first, but currently it is
stopped after the reset_task. This can result in the following race
leading to the reset_task running after the module unload:

e1000_down_and_stop():			e1000_watchdog():
----------------------			-----------------

cancel_work_sync(reset_task)
					schedule_work(reset_task)
cancel_delayed_work_sync(watchdog_task)

The patch moves cancel_delayed_work_sync(watchdog_task) at the beginning
of e1000_down_and_stop() thus ensuring the race is impossible.

Cc: Tushar Dave <tushar.n.dave@intel.com>
Cc: Patrick McHardy <kaber@trash.net>
Signed-off-by: default avatarVladimir Davydov <vdavydov@parallels.com>
Tested-by: default avatarAaron Brown <aaron.f.brown@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent b2f963bf
...@@ -494,13 +494,20 @@ static void e1000_down_and_stop(struct e1000_adapter *adapter) ...@@ -494,13 +494,20 @@ static void e1000_down_and_stop(struct e1000_adapter *adapter)
{ {
set_bit(__E1000_DOWN, &adapter->flags); set_bit(__E1000_DOWN, &adapter->flags);
/* Only kill reset task if adapter is not resetting */
if (!test_bit(__E1000_RESETTING, &adapter->flags))
cancel_work_sync(&adapter->reset_task);
cancel_delayed_work_sync(&adapter->watchdog_task); cancel_delayed_work_sync(&adapter->watchdog_task);
/*
* Since the watchdog task can reschedule other tasks, we should cancel
* it first, otherwise we can run into the situation when a work is
* still running after the adapter has been turned down.
*/
cancel_delayed_work_sync(&adapter->phy_info_task); cancel_delayed_work_sync(&adapter->phy_info_task);
cancel_delayed_work_sync(&adapter->fifo_stall_task); cancel_delayed_work_sync(&adapter->fifo_stall_task);
/* Only kill reset task if adapter is not resetting */
if (!test_bit(__E1000_RESETTING, &adapter->flags))
cancel_work_sync(&adapter->reset_task);
} }
void e1000_down(struct e1000_adapter *adapter) void e1000_down(struct e1000_adapter *adapter)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment