summaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg2008-09-11 00:01:50 +0200
committerJohn W. Linville2008-09-15 22:48:20 +0200
commitb7413430d4d2a6168e68231d9f93763047b6d60c (patch)
tree18e85326ddb298500820252f2e510b58319b52d2 /net/mac80211
parentmac80211: split off mesh handling entirely (diff)
downloadkernel-qcow2-linux-b7413430d4d2a6168e68231d9f93763047b6d60c.tar.gz
kernel-qcow2-linux-b7413430d4d2a6168e68231d9f93763047b6d60c.tar.xz
kernel-qcow2-linux-b7413430d4d2a6168e68231d9f93763047b6d60c.zip
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>
Diffstat (limited to 'net/mac80211')
-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)
memset(sdata->u.sta.bssid, 0, ETH_ALEN);
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.
* Call synchronize_rcu() to wait for the RX path
* 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)
{
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.
* Call synchronize_rcu() to wait for the RX path
* should it be using the interface and enqueuing