summaryrefslogtreecommitdiffstats
path: root/net/mac80211/ieee80211_i.h
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/ieee80211_i.h
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/ieee80211_i.h')
-rw-r--r--net/mac80211/ieee80211_i.h30
1 files changed, 30 insertions, 0 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 6e1b184183fb..bdb3e3bc7503 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1886,6 +1886,36 @@ void __ieee80211_flush_queues(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
unsigned int queues, bool drop);
+static inline bool ieee80211_can_run_worker(struct ieee80211_local *local)
+{
+ /*
+ * If quiescing is set, we are racing with __ieee80211_suspend.
+ * __ieee80211_suspend flushes the workers after setting quiescing,
+ * and we check quiescing / suspended before enqueing new workers.
+ * We should abort the worker to avoid the races below.
+ */
+ if (local->quiescing)
+ return false;
+
+ /*
+ * We might already be suspended if the following scenario occurs:
+ * __ieee80211_suspend Control path
+ *
+ * if (local->quiescing)
+ * return;
+ * local->quiescing = true;
+ * flush_workqueue();
+ * queue_work(...);
+ * local->suspended = true;
+ * local->quiescing = false;
+ * worker starts running...
+ */
+ if (local->suspended)
+ return false;
+
+ return true;
+}
+
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg, u16 status,
const u8 *extra, size_t extra_len, const u8 *bssid,