Commit b7413430 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

mac80211: fix work race

When we stop an interface, the work on it may still be pending
or running. We do cancel the timer, but we do not currently
protect against the work struct. The race is very unlikely to
hit -- it'll happen only when the driver is using mac80211's
workqueue to run long-running tasks and the sta/mesh works are
delayed for quite a bit.

This patch fixes it by cancelling the work explicitly.
Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 472dbc45
...@@ -547,6 +547,14 @@ static int ieee80211_stop(struct net_device *dev) ...@@ -547,6 +547,14 @@ static int ieee80211_stop(struct net_device *dev)
sdata->u.sta.state = IEEE80211_STA_MLME_DISABLED; sdata->u.sta.state = IEEE80211_STA_MLME_DISABLED;
memset(sdata->u.sta.bssid, 0, ETH_ALEN); memset(sdata->u.sta.bssid, 0, ETH_ALEN);
del_timer_sync(&sdata->u.sta.timer); del_timer_sync(&sdata->u.sta.timer);
/*
* If the timer fired while we waited for it, it will have
* requeued the work. Now the work will be running again
* but will not rearm the timer again because it checks
* whether the interface is running, which, at this point,
* it no longer is.
*/
cancel_work_sync(&sdata->u.sta.work);
/* /*
* When we get here, the interface is marked down. * When we get here, the interface is marked down.
* Call synchronize_rcu() to wait for the RX path * Call synchronize_rcu() to wait for the RX path
......
...@@ -448,6 +448,15 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) ...@@ -448,6 +448,15 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
{ {
del_timer_sync(&sdata->u.mesh.housekeeping_timer); del_timer_sync(&sdata->u.mesh.housekeeping_timer);
/*
* If the timer fired while we waited for it, it will have
* requeued the work. Now the work will be running again
* but will not rearm the timer again because it checks
* whether the interface is running, which, at this point,
* it no longer is.
*/
cancel_work_sync(&sdata->u.mesh.work);
/* /*
* When we get here, the interface is marked down. * When we get here, the interface is marked down.
* Call synchronize_rcu() to wait for the RX path * Call synchronize_rcu() to wait for the RX path
......
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