aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-09-10 18:01:50 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-09-15 16:48:20 -0400
commitb7413430d4d2a6168e68231d9f93763047b6d60c (patch)
tree18e85326ddb298500820252f2e510b58319b52d2
parent472dbc45dc1966284de72d7de15690c17ed2cf33 (diff)
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: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--net/mac80211/main.c8
-rw-r--r--net/mac80211/mesh.c9
2 files changed, 17 insertions, 0 deletions
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 522fe6176485..ebdec7106d63 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -548,6 +548,14 @@ static int ieee80211_stop(struct net_device *dev)
548 memset(sdata->u.sta.bssid, 0, ETH_ALEN); 548 memset(sdata->u.sta.bssid, 0, ETH_ALEN);
549 del_timer_sync(&sdata->u.sta.timer); 549 del_timer_sync(&sdata->u.sta.timer);
550 /* 550 /*
551 * If the timer fired while we waited for it, it will have
552 * requeued the work. Now the work will be running again
553 * but will not rearm the timer again because it checks
554 * whether the interface is running, which, at this point,
555 * it no longer is.
556 */
557 cancel_work_sync(&sdata->u.sta.work);
558 /*
551 * When we get here, the interface is marked down. 559 * When we get here, the interface is marked down.
552 * Call synchronize_rcu() to wait for the RX path 560 * Call synchronize_rcu() to wait for the RX path
553 * should it be using the interface and enqueuing 561 * should it be using the interface and enqueuing
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 9e47725cc592..a0141f5ff184 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -449,6 +449,15 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
449{ 449{
450 del_timer_sync(&sdata->u.mesh.housekeeping_timer); 450 del_timer_sync(&sdata->u.mesh.housekeeping_timer);
451 /* 451 /*
452 * If the timer fired while we waited for it, it will have
453 * requeued the work. Now the work will be running again
454 * but will not rearm the timer again because it checks
455 * whether the interface is running, which, at this point,
456 * it no longer is.
457 */
458 cancel_work_sync(&sdata->u.mesh.work);
459
460 /*
452 * When we get here, the interface is marked down. 461 * When we get here, the interface is marked down.
453 * Call synchronize_rcu() to wait for the RX path 462 * Call synchronize_rcu() to wait for the RX path
454 * should it be using the interface and enqueuing 463 * should it be using the interface and enqueuing