From: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
To: Viresh Kumar <viresh.kumar@linaro.org>,
"Rafael J. Wysocki" <rafael@kernel.org>,
Pierre Gondois <pierre.gondois@arm.com>,
Lifeng Zheng <zhenglifeng1@huawei.com>
Cc: linux-pm@vger.kernel.org,
Vincent Guittot <vincent.guittot@linaro.org>,
Sumit Semwal <sumit.semwal@linaro.org>,
"Rafael J. Wysocki" <rafael.j.wysocki@intel.com>,
linux-kernel@vger.kernel.org, zhongqiu.han@oss.qualcomm.com
Subject: Re: [PATCH] cpufreq: Allocate QoS freq_req objects with policy
Date: Tue, 31 Mar 2026 15:10:54 +0800 [thread overview]
Message-ID: <cc388a7c-7c2b-4fc0-9869-853c5316697b@oss.qualcomm.com> (raw)
In-Reply-To: <a293f29d841b86c51f34699c6e717e01858d8ada.1774933424.git.viresh.kumar@linaro.org>
On 3/31/2026 1:03 PM, Viresh Kumar wrote:
> A recent change exposed a bug in the error path: if
> freq_qos_add_request(boost_freq_req) fails, min_freq_req may remain a
> valid pointer even though it was never successfully added. During policy
> teardown, this leads to an unconditional call to
> freq_qos_remove_request(), triggering a WARN.
>
> The current design allocates all three freq_req objects together, making
> the lifetime rules unclear and error handling fragile.
>
> Simplify this by allocating the QoS freq_req objects at policy
> allocation time. The policy itself is dynamically allocated, and two of
> the three requests are always needed anyway. This ensures consistent
> lifetime management and eliminates the inconsistent state in failure
> paths.
>
> Reported-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
> Fixes: 6e39ba4e5a82 ("cpufreq: Add boost_freq_req QoS request")
> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Thanks for the elegant solution. It looks good to me.
Reviewed-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
> ---
> drivers/cpufreq/cpufreq.c | 53 +++++++++++----------------------------
> include/linux/cpufreq.h | 6 ++---
> 2 files changed, 17 insertions(+), 42 deletions(-)
>
> diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
> index c0aa970c7a67..f4a949f1e48f 100644
> --- a/drivers/cpufreq/cpufreq.c
> +++ b/drivers/cpufreq/cpufreq.c
> @@ -614,7 +614,7 @@ static int policy_set_boost(struct cpufreq_policy *policy, bool enable)
> return ret;
> }
>
> - ret = freq_qos_update_request(policy->boost_freq_req, policy->cpuinfo.max_freq);
> + ret = freq_qos_update_request(&policy->boost_freq_req, policy->cpuinfo.max_freq);
> if (ret < 0) {
> policy->boost_enabled = !policy->boost_enabled;
> cpufreq_driver->set_boost(policy, policy->boost_enabled);
> @@ -769,7 +769,7 @@ static ssize_t store_##file_name \
> if (ret) \
> return ret; \
> \
> - ret = freq_qos_update_request(policy->object##_freq_req, val);\
> + ret = freq_qos_update_request(&policy->object##_freq_req, val); \
> return ret >= 0 ? count : ret; \
> }
>
> @@ -1374,7 +1374,7 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
> /* Cancel any pending policy->update work before freeing the policy. */
> cancel_work_sync(&policy->update);
>
> - if (policy->max_freq_req) {
> + if (freq_qos_request_active(&policy->max_freq_req)) {
> /*
> * Remove max_freq_req after sending CPUFREQ_REMOVE_POLICY
> * notification, since CPUFREQ_CREATE_POLICY notification was
> @@ -1382,12 +1382,13 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
> */
> blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
> CPUFREQ_REMOVE_POLICY, policy);
> - freq_qos_remove_request(policy->max_freq_req);
> + freq_qos_remove_request(&policy->max_freq_req);
> }
>
> - freq_qos_remove_request(policy->min_freq_req);
> - freq_qos_remove_request(policy->boost_freq_req);
> - kfree(policy->min_freq_req);
> + if (freq_qos_request_active(&policy->min_freq_req))
> + freq_qos_remove_request(&policy->min_freq_req);
> + if (freq_qos_request_active(&policy->boost_freq_req))
> + freq_qos_remove_request(&policy->boost_freq_req);
>
> cpufreq_policy_put_kobj(policy);
> free_cpumask_var(policy->real_cpus);
> @@ -1452,57 +1453,31 @@ static int cpufreq_policy_online(struct cpufreq_policy *policy,
> cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
>
> if (new_policy) {
> - unsigned int count;
> -
> for_each_cpu(j, policy->related_cpus) {
> per_cpu(cpufreq_cpu_data, j) = policy;
> add_cpu_dev_symlink(policy, j, get_cpu_device(j));
> }
>
> - count = policy->boost_supported ? 3 : 2;
> - policy->min_freq_req = kzalloc(count * sizeof(*policy->min_freq_req),
> - GFP_KERNEL);
> - if (!policy->min_freq_req) {
> - ret = -ENOMEM;
> - goto out_destroy_policy;
> - }
> -
> if (policy->boost_supported) {
> - policy->boost_freq_req = policy->min_freq_req + 2;
> -
> ret = freq_qos_add_request(&policy->constraints,
> - policy->boost_freq_req,
> + &policy->boost_freq_req,
> FREQ_QOS_MAX,
> policy->cpuinfo.max_freq);
> - if (ret < 0) {
> - policy->boost_freq_req = NULL;
> + if (ret < 0)
> goto out_destroy_policy;
> - }
> }
>
> ret = freq_qos_add_request(&policy->constraints,
> - policy->min_freq_req, FREQ_QOS_MIN,
> + &policy->min_freq_req, FREQ_QOS_MIN,
> FREQ_QOS_MIN_DEFAULT_VALUE);
> - if (ret < 0) {
> - kfree(policy->min_freq_req);
> - policy->min_freq_req = NULL;
> + if (ret < 0)
> goto out_destroy_policy;
> - }
> -
> - /*
> - * This must be initialized right here to avoid calling
> - * freq_qos_remove_request() on uninitialized request in case
> - * of errors.
> - */
> - policy->max_freq_req = policy->min_freq_req + 1;
>
> ret = freq_qos_add_request(&policy->constraints,
> - policy->max_freq_req, FREQ_QOS_MAX,
> + &policy->max_freq_req, FREQ_QOS_MAX,
> FREQ_QOS_MAX_DEFAULT_VALUE);
> - if (ret < 0) {
> - policy->max_freq_req = NULL;
> + if (ret < 0)
> goto out_destroy_policy;
> - }
>
> blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
> CPUFREQ_CREATE_POLICY, policy);
> diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
> index b6f6c7d06912..9b10eb486ece 100644
> --- a/include/linux/cpufreq.h
> +++ b/include/linux/cpufreq.h
> @@ -79,9 +79,9 @@ struct cpufreq_policy {
> * called, but you're in IRQ context */
>
> struct freq_constraints constraints;
> - struct freq_qos_request *min_freq_req;
> - struct freq_qos_request *max_freq_req;
> - struct freq_qos_request *boost_freq_req;
> + struct freq_qos_request min_freq_req;
> + struct freq_qos_request max_freq_req;
> + struct freq_qos_request boost_freq_req;
>
> struct cpufreq_frequency_table *freq_table;
> enum cpufreq_table_sorting freq_table_sorted;
--
Thx and BRs,
Zhongqiu Han
next prev parent reply other threads:[~2026-03-31 7:11 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-31 5:03 [PATCH] cpufreq: Allocate QoS freq_req objects with policy Viresh Kumar
2026-03-31 6:44 ` zhenglifeng (A)
2026-03-31 7:03 ` Pierre Gondois
2026-03-31 7:10 ` Zhongqiu Han [this message]
2026-04-01 13:55 ` Rafael J. Wysocki
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=cc388a7c-7c2b-4fc0-9869-853c5316697b@oss.qualcomm.com \
--to=zhongqiu.han@oss.qualcomm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=pierre.gondois@arm.com \
--cc=rafael.j.wysocki@intel.com \
--cc=rafael@kernel.org \
--cc=sumit.semwal@linaro.org \
--cc=vincent.guittot@linaro.org \
--cc=viresh.kumar@linaro.org \
--cc=zhenglifeng1@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox