From: Johannes Berg johannes.berg@intel.com
stable inclusion from stable-v6.6.2 commit 5d9eefa23bd9b0bddc74132753352b9d63f5ac01 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8IW7G
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
[ Upstream commit 56cfb8ce1f7f6c4e5ca571a2ec0880e131cd0311 ]
There may be sometimes reasons to actually run the work if it's pending, add flush functions for both regular and delayed wiphy work that will do this.
Signed-off-by: Johannes Berg johannes.berg@intel.com Stable-dep-of: eadfb54756ae ("wifi: mac80211: move sched-scan stop work to wiphy work") Signed-off-by: Sasha Levin sashal@kernel.org Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- include/net/cfg80211.h | 21 +++++++++++++++++++++ net/wireless/core.c | 34 ++++++++++++++++++++++++++++++++-- net/wireless/core.h | 3 ++- net/wireless/sysfs.c | 4 ++-- 4 files changed, 57 insertions(+), 5 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 7192346e4a22..308a004c1d1d 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -5826,6 +5826,16 @@ void wiphy_work_queue(struct wiphy *wiphy, struct wiphy_work *work); */ void wiphy_work_cancel(struct wiphy *wiphy, struct wiphy_work *work);
+/** + * wiphy_work_flush - flush previously queued work + * @wiphy: the wiphy, for debug purposes + * @work: the work to flush, this can be %NULL to flush all work + * + * Flush the work (i.e. run it if pending). This must be called + * under the wiphy mutex acquired by wiphy_lock(). + */ +void wiphy_work_flush(struct wiphy *wiphy, struct wiphy_work *work); + struct wiphy_delayed_work { struct wiphy_work work; struct wiphy *wiphy; @@ -5869,6 +5879,17 @@ void wiphy_delayed_work_queue(struct wiphy *wiphy, void wiphy_delayed_work_cancel(struct wiphy *wiphy, struct wiphy_delayed_work *dwork);
+/** + * wiphy_delayed work_flush - flush previously queued delayed work + * @wiphy: the wiphy, for debug purposes + * @work: the work to flush + * + * Flush the work (i.e. run it if pending). This must be called + * under the wiphy mutex acquired by wiphy_lock(). + */ +void wiphy_delayed_work_flush(struct wiphy *wiphy, + struct wiphy_delayed_work *dwork); + /** * struct wireless_dev - wireless device state * diff --git a/net/wireless/core.c b/net/wireless/core.c index acec41c1809a..563cfbe3237c 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -1049,7 +1049,8 @@ void wiphy_rfkill_start_polling(struct wiphy *wiphy) } EXPORT_SYMBOL(wiphy_rfkill_start_polling);
-void cfg80211_process_wiphy_works(struct cfg80211_registered_device *rdev) +void cfg80211_process_wiphy_works(struct cfg80211_registered_device *rdev, + struct wiphy_work *end) { unsigned int runaway_limit = 100; unsigned long flags; @@ -1068,6 +1069,10 @@ void cfg80211_process_wiphy_works(struct cfg80211_registered_device *rdev) wk->func(&rdev->wiphy, wk);
spin_lock_irqsave(&rdev->wiphy_work_lock, flags); + + if (wk == end) + break; + if (WARN_ON(--runaway_limit == 0)) INIT_LIST_HEAD(&rdev->wiphy_work_list); } @@ -1118,7 +1123,7 @@ void wiphy_unregister(struct wiphy *wiphy) #endif
/* surely nothing is reachable now, clean up work */ - cfg80211_process_wiphy_works(rdev); + cfg80211_process_wiphy_works(rdev, NULL); wiphy_unlock(&rdev->wiphy); rtnl_unlock();
@@ -1640,6 +1645,21 @@ void wiphy_work_cancel(struct wiphy *wiphy, struct wiphy_work *work) } EXPORT_SYMBOL_GPL(wiphy_work_cancel);
+void wiphy_work_flush(struct wiphy *wiphy, struct wiphy_work *work) +{ + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + unsigned long flags; + bool run; + + spin_lock_irqsave(&rdev->wiphy_work_lock, flags); + run = !work || !list_empty(&work->entry); + spin_unlock_irqrestore(&rdev->wiphy_work_lock, flags); + + if (run) + cfg80211_process_wiphy_works(rdev, work); +} +EXPORT_SYMBOL_GPL(wiphy_work_flush); + void wiphy_delayed_work_timer(struct timer_list *t) { struct wiphy_delayed_work *dwork = from_timer(dwork, t, timer); @@ -1672,6 +1692,16 @@ void wiphy_delayed_work_cancel(struct wiphy *wiphy, } EXPORT_SYMBOL_GPL(wiphy_delayed_work_cancel);
+void wiphy_delayed_work_flush(struct wiphy *wiphy, + struct wiphy_delayed_work *dwork) +{ + lockdep_assert_held(&wiphy->mtx); + + del_timer_sync(&dwork->timer); + wiphy_work_flush(wiphy, &dwork->work); +} +EXPORT_SYMBOL_GPL(wiphy_delayed_work_flush); + static int __init cfg80211_init(void) { int err; diff --git a/net/wireless/core.h b/net/wireless/core.h index ba9c7170afa4..e536c0b615a0 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -464,7 +464,8 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, struct net_device *dev, enum nl80211_iftype ntype, struct vif_params *params); void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); -void cfg80211_process_wiphy_works(struct cfg80211_registered_device *rdev); +void cfg80211_process_wiphy_works(struct cfg80211_registered_device *rdev, + struct wiphy_work *end); void cfg80211_process_wdev_events(struct wireless_dev *wdev);
bool cfg80211_does_bw_fit_range(const struct ieee80211_freq_range *freq_range, diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index c629bac3f298..565511a3f461 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c @@ -105,14 +105,14 @@ static int wiphy_suspend(struct device *dev) cfg80211_leave_all(rdev); cfg80211_process_rdev_events(rdev); } - cfg80211_process_wiphy_works(rdev); + cfg80211_process_wiphy_works(rdev, NULL); if (rdev->ops->suspend) ret = rdev_suspend(rdev, rdev->wiphy.wowlan_config); if (ret == 1) { /* Driver refuse to configure wowlan */ cfg80211_leave_all(rdev); cfg80211_process_rdev_events(rdev); - cfg80211_process_wiphy_works(rdev); + cfg80211_process_wiphy_works(rdev, NULL); ret = rdev_suspend(rdev, NULL); } if (ret == 0)