diff options
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/ieee80211_i.h | 30 | ||||
-rw-r--r-- | net/mac80211/iface.c | 7 | ||||
-rw-r--r-- | net/mac80211/util.c | 15 |
3 files changed, 40 insertions, 12 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, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 4371c123a95e..81a27516813e 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1170,12 +1170,7 @@ static void ieee80211_iface_work(struct work_struct *work) if (local->scanning) return; - /* - * ieee80211_queue_work() should have picked up most cases, - * here we'll pick the rest. - */ - if (WARN(local->suspended, - "interface work scheduled while going to suspend\n")) + if (!ieee80211_can_run_worker(local)) return; /* first process frames */ 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; } |