summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg2011-11-09 12:14:16 +0100
committerJohn W. Linville2011-11-09 20:35:56 +0100
commit0ecfe806f146e0cb10c2c5abbb3bb4e91959e41a (patch)
treee70bd8430b61545e91aacc298718634ac217491f
parentwireless: libertas: fix unaligned le64 accesses (diff)
downloadkernel-qcow2-linux-0ecfe806f146e0cb10c2c5abbb3bb4e91959e41a.tar.gz
kernel-qcow2-linux-0ecfe806f146e0cb10c2c5abbb3bb4e91959e41a.tar.xz
kernel-qcow2-linux-0ecfe806f146e0cb10c2c5abbb3bb4e91959e41a.zip
mac80211: fix race between connection monitor & suspend
When the connection monitor timer fires right before suspend, the following will happen: timer fires -> monitor_work gets queued suspend calls ieee80211_sta_quiesce ieee80211_sta_quiesce: - deletes timer - cancels monitor_work synchronously, running it [note wrong order of these steps] monitor_work runs, re-arming the timer later, timer fires while system should be quiesced This causes a warning: WARNING: at net/mac80211/util.c:540 ieee80211_can_queue_work+0x35/0x40 [mac80211]() but is otherwise harmless. I'm not completely sure this is the scenario Thomas stumbled across, but it is the only way I can right now see the warning in a scenario like the one he reported. Reported-by: Thomas Meyer <thomas@m3y3r.de> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--net/mac80211/mlme.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index d3b408cda08d..40db011da580 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2286,6 +2286,7 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)
cancel_work_sync(&ifmgd->request_smps_work);
+ cancel_work_sync(&ifmgd->monitor_work);
cancel_work_sync(&ifmgd->beacon_connection_loss_work);
if (del_timer_sync(&ifmgd->timer))
set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
@@ -2294,7 +2295,6 @@ void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)
if (del_timer_sync(&ifmgd->chswitch_timer))
set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running);
- cancel_work_sync(&ifmgd->monitor_work);
/* these will just be re-established on connection */
del_timer_sync(&ifmgd->conn_mon_timer);
del_timer_sync(&ifmgd->bcn_mon_timer);