From: Remi Pommarel <repk@xxxxxxxxxxxx> [ Upstream commit 68d0021fe7231eec0fb84cd110cf62a6e782b72d ] Add wiphy_delayed_work_pending() to check if any delayed work timer is pending, that can be used to be sure that wiphy_delayed_work_queue() won't postpone an already pending delayed work. Signed-off-by: Remi Pommarel <repk@xxxxxxxxxxxx> Link: https://patch.msgid.link/20240924192805.13859-2-repk@xxxxxxxxxxxx [fix return value kernel-doc] Signed-off-by: Johannes Berg <johannes.berg@xxxxxxxxx> Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx> --- include/net/cfg80211.h | 44 ++++++++++++++++++++++++++++++++++++++++++ net/wireless/core.c | 7 +++++++ 2 files changed, 51 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 192d72c8b4654..702653448d2fc 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -6129,6 +6129,50 @@ void wiphy_delayed_work_cancel(struct wiphy *wiphy, void wiphy_delayed_work_flush(struct wiphy *wiphy, struct wiphy_delayed_work *dwork); +/** + * wiphy_delayed_work_pending - Find out whether a wiphy delayable + * work item is currently pending. + * + * @wiphy: the wiphy, for debug purposes + * @dwork: the delayed work in question + * + * Return: true if timer is pending, false otherwise + * + * How wiphy_delayed_work_queue() works is by setting a timer which + * when it expires calls wiphy_work_queue() to queue the wiphy work. + * Because wiphy_delayed_work_queue() uses mod_timer(), if it is + * called twice and the second call happens before the first call + * deadline, the work will rescheduled for the second deadline and + * won't run before that. + * + * wiphy_delayed_work_pending() can be used to detect if calling + * wiphy_work_delayed_work_queue() would start a new work schedule + * or delayed a previous one. As seen below it cannot be used to + * detect precisely if the work has finished to execute nor if it + * is currently executing. + * + * CPU0 CPU1 + * wiphy_delayed_work_queue(wk) + * mod_timer(wk->timer) + * wiphy_delayed_work_pending(wk) -> true + * + * [...] + * expire_timers(wk->timer) + * detach_timer(wk->timer) + * wiphy_delayed_work_pending(wk) -> false + * wk->timer->function() | + * wiphy_work_queue(wk) | delayed work pending + * list_add_tail() | returns false but + * queue_work(cfg80211_wiphy_work) | wk->func() has not + * | been run yet + * [...] | + * cfg80211_wiphy_work() | + * wk->func() V + * + */ +bool wiphy_delayed_work_pending(struct wiphy *wiphy, + struct wiphy_delayed_work *dwork); + /** * enum ieee80211_ap_reg_power - regulatory power for an Access Point * diff --git a/net/wireless/core.c b/net/wireless/core.c index 4d5d351bd0b51..c9a1158dbdd11 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -1704,6 +1704,13 @@ void wiphy_delayed_work_flush(struct wiphy *wiphy, } EXPORT_SYMBOL_GPL(wiphy_delayed_work_flush); +bool wiphy_delayed_work_pending(struct wiphy *wiphy, + struct wiphy_delayed_work *dwork) +{ + return timer_pending(&dwork->timer); +} +EXPORT_SYMBOL_GPL(wiphy_delayed_work_pending); + static int __init cfg80211_init(void) { int err; -- 2.43.0