summaryrefslogtreecommitdiffstats
path: root/net/mac80211/util.c
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2015-01-22 23:32:46 +0200
committerJohannes Berg <johannes.berg@intel.com>2015-01-23 10:54:22 +0100
commit4afaff176a968457df18eeebc1aad910b6154761 (patch)
treeb72d595e376af86d6e3217a5d608fb690864cec2 /net/mac80211/util.c
parent14f2ae83d07a0a0d499d4760dd4a1bffd310b6ae (diff)
downloadlinux-4afaff176a968457df18eeebc1aad910b6154761.tar.bz2
mac80211: avoid races related to suspend flow
When we go to suspend, there is complex set of states that avoids races. The quiescing variable is set whlie __ieee80211_suspend is running. Then suspended is set. The code makes sure there is no window without any of these flags. The problem is that workers can still be enqueued while we are quiescing. This leads to situations where the driver is already suspending and other flows like disassociation are handled by a worker. To fix this, we need to check quiescing and suspended flags in the worker itself and not only before enqueueing it. I also add here extensive documentation to ease the understanding of these complex issues. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r--net/mac80211/util.c15
1 files changed, 9 insertions, 6 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index fbd37d43dfce..c65d03f3c167 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -744,16 +744,19 @@ EXPORT_SYMBOL_GPL(wdev_to_ieee80211_vif);
/*
* Nothing should have been stuffed into the workqueue during
- * the suspend->resume cycle. If this WARN is seen then there
- * is a bug with either the driver suspend or something in
- * mac80211 stuffing into the workqueue which we haven't yet
- * cleared during mac80211's suspend cycle.
+ * the suspend->resume cycle. Since we can't check each caller
+ * of this function if we are already quiescing / suspended,
+ * check here and don't WARN since this can actually happen when
+ * the rx path (for example) is racing against __ieee80211_suspend
+ * and suspending / quiescing was set after the rx path checked
+ * them.
*/
static bool ieee80211_can_queue_work(struct ieee80211_local *local)
{
- if (WARN(local->suspended && !local->resuming,
- "queueing ieee80211 work while going to suspend\n"))
+ if (local->quiescing || (local->suspended && !local->resuming)) {
+ pr_warn("queueing ieee80211 work while going to suspend\n");
return false;
+ }
return true;
}