Skip to content

Commit

Permalink
e1000: fix possible reset_task running after adapter down
Browse files Browse the repository at this point in the history
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 <[email protected]>
Cc: Patrick McHardy <[email protected]>
Signed-off-by: Vladimir Davydov <[email protected]>
Tested-by: Aaron Brown <[email protected]>
Signed-off-by: Jeff Kirsher <[email protected]>
  • Loading branch information
Vladimir Davydov authored and Jeff Kirsher committed Nov 30, 2013
1 parent b2f963b commit 74a1b1e
Showing 1 changed file with 11 additions and 4 deletions.
15 changes: 11 additions & 4 deletions drivers/net/ethernet/intel/e1000/e1000_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -494,13 +494,20 @@ static void e1000_down_and_stop(struct e1000_adapter *adapter)
{
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);

/*
* 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->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)
Expand Down

0 comments on commit 74a1b1e

Please sign in to comment.