* [PATCH v8 0/2] cpufreq: Introduce boost frequency QoS
@ 2026-03-26 20:43 Pierre Gondois
2026-03-26 20:44 ` [PATCH v8 1/2] cpufreq: Remove max_freq_req update for pre-existing policy Pierre Gondois
` (2 more replies)
0 siblings, 3 replies; 15+ messages in thread
From: Pierre Gondois @ 2026-03-26 20:43 UTC (permalink / raw)
To: linux-kernel
Cc: Lifeng Zheng, Pierre Gondois, Huang Rui, Gautham R. Shenoy,
Mario Limonciello, Perry Yuan, Rafael J. Wysocki, Viresh Kumar,
linux-pm
The Power Management Quality of Service (PM QoS) allows to
aggregate constraints from multiple entities. It is currently
used to manage the min/max frequency of a given policy.
Frequency constraints can come from:
- Thermal framework: acpi_thermal_cpufreq_init()
- Firmware: _PPC objects: acpi_processor_ppc_init()
- User: by setting policyX/scaling_[min|max]_freq
The minimum of the max frequency constraints is used to compute
the resulting maximum allowed frequency.
When enabling boost frequencies, the same frequency request object
(policy->max_freq_req) as to handle requests from users is used.
As a result, when setting:
- scaling_max_freq
- boost
The last sysfs file used overwrites the request from the other
sysfs file.
To avoid this:
1. Create a per-policy boost_freq_req to save the boost
constraints instead of overwriting the last scaling_max_freq
constraint.
2. policy_set_boost() calls the cpufreq set_boost callback.
Update the newly added boost_freq_req request from there:
- whenever boost is toggled
- to cover all possible paths
3. In the existing set_boost() callbacks:
- Don't update policy->max as this is done through the qos notifier
cpufreq_notifier_max() which calls cpufreq_set_policy().
- Remove freq_qos_update_request() calls as the qos request is now
done in policy_set_boost() and updates the new boost_freq_req
---
E.g.:
On a Juno with available frequencies: 600.000, 1.000.000
Boost frequencies: 1.200.000
Using the cppc-cpufreq driver.
---
Without the patches:
# ## Init state
scaling_max_freq:1000000
cpuinfo_max_freq:1000000
# echo 700000 > scaling_max_freq
scaling_max_freq:700000
cpuinfo_max_freq:1000000
# echo 1 > ../boost
scaling_max_freq:1200000
cpuinfo_max_freq:1200000
# echo 800000 > scaling_max_freq
scaling_max_freq:800000
cpuinfo_max_freq:1200000
# echo 0 > ../boost
scaling_max_freq:1000000
cpuinfo_max_freq:1000000
---
With the patches:
# ## Init
scaling_max_freq:1000000
cpuinfo_max_freq:1000000
# echo 700000 > scaling_max_freq
scaling_max_freq:700000
cpuinfo_max_freq:1000000
# echo 1 > ../boost
scaling_max_freq:700000
cpuinfo_max_freq:1200000
# echo 800000 > scaling_max_freq
scaling_max_freq:800000
cpuinfo_max_freq:1200000
# echo 0 > ../boost
scaling_max_freq:800000
cpuinfo_max_freq:1000000
With the patches, the maximum scaling frequency requested is
conserved even though boosting is enabled/disabled.
---
Note:
It seems that there is a confusion in the cpufreq framework between:
- the min/max frequency requested by the user
- the min/max frequency constraint applied when selecting a frequency.
E.g:
A.
$ echo XXX > scaling_max_freq
updates the max_freq_req QoS request.
B.
$ cat scaling_max_freq
shows the content of policy->max, which is the not representing
the value of the max_freq_req QoS request.
C.
Whenever policy->max is accessed in the cpufreq framework,
the aggregation of all the requests on the maximum frequency should
be used instead.
cpufreq_set_policy() aggregates min/max constraints and
writes the resulting value in policy->min/max. These values
are then used in the cpufreq drivers.
Creating a clear distinction would be doable but quite invasive.
This patchset focuses on handling the boost frequency QoS request
first and should not change the current behaviour of policy->min
and max.
---
v1: https://lore.kernel.org/all/20251204101344.192678-1-pierre.gondois@arm.com/#t
v2: https://lore.kernel.org/all/20251208105933.1369125-1-pierre.gondois@arm.com/#t
Changes:
- Fixed error path
- Integrated [PATCH 1/4] Revert "cpufreq: Fix re-boost issue after hotplugging a CPU"
to another patch
v3:
Changes:
- Fixed error path
- Extracted the revert of:
"cpufreq: Fix re-boost issue after hotplugging a CPU"
for clarity purpose
- Set cpuinfo.max_freq as a max_freq_req QoS constraint by default
New patches:
- "cpufreq: Allow decreasing cpuinfo.max_freq"
- "cpufreq: Set policy->min and max as QoS constraints"
v4:
- Correct reported issues
v5:
- Corrections
v6:
- Folded patches:
- cpufreq: Centralize boost freq QoS requests
- cpufreq: Update .set_boost() callbacks to rely on boost_freq_req
inside:
- cpufreq: Add boost_freq_req QoS request
- Simplified allocation handling of boost_freq_req
- Removed unnecessary bits
v7:
- Removed the following patches to submit them separately
- cpufreq: Set policy->min and max as real QoS constraints
- cpufreq/freq_table: Allow decreasing cpuinfo.max_freq
- Fixed blocking_notifier_call_chain() call order when removing
a policy.
- Updated the commit message of:
- cpufreq: Remove per-CPU QoS constraint
v8:
- Renamed first patch
- Small corrections to second patch.
Pierre Gondois (2):
cpufreq: Remove max_freq_req update for pre-existing policy
cpufreq: Add boost_freq_req QoS request
drivers/cpufreq/amd-pstate.c | 2 --
drivers/cpufreq/cppc_cpufreq.c | 10 ++-----
drivers/cpufreq/cpufreq.c | 50 +++++++++++++++++++++-------------
include/linux/cpufreq.h | 1 +
4 files changed, 34 insertions(+), 29 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH v8 1/2] cpufreq: Remove max_freq_req update for pre-existing policy 2026-03-26 20:43 [PATCH v8 0/2] cpufreq: Introduce boost frequency QoS Pierre Gondois @ 2026-03-26 20:44 ` Pierre Gondois 2026-03-26 20:44 ` [PATCH v8 2/2] cpufreq: Add boost_freq_req QoS request Pierre Gondois 2026-03-27 3:43 ` [PATCH v8 0/2] cpufreq: Introduce boost frequency QoS Viresh Kumar 2 siblings, 0 replies; 15+ messages in thread From: Pierre Gondois @ 2026-03-26 20:44 UTC (permalink / raw) To: linux-kernel Cc: Lifeng Zheng, Pierre Gondois, Huang Rui, Gautham R. Shenoy, Mario Limonciello, Perry Yuan, Rafael J. Wysocki, Viresh Kumar, linux-pm policy->max_freq_req QoS constraint represents the maximal allowed frequency than can be requested. It is set by: - writing to policyX/scaling_max sysfs file - toggling the cpufreq/boost sysfs file Upon calling freq_qos_update_request(), a successful update of the max_freq_req value triggers cpufreq_notifier_max(), followed by cpufreq_set_policy() which update the requested frequency for the policy. If the new max_freq_req value is not different from the original value, no frequency update is triggered. In a specific sequence of toggling: - cpufreq/boost sysfs file - CPU hot-plugging a CPU could end up with boost enabled but running at the maximal non-boost frequency, cpufreq_notifier_max() not being triggered. The following fixed that: commit 1608f0230510 ("cpufreq: Fix re-boost issue after hotplugging a CPU") The following: commit dd016f379ebc ("cpufreq: Introduce a more generic way to set default per-policy boost flag") also fixed the issue by correctly setting the max_freq_req constraint of a policy that is re-activated. This makes the first fix unnecessary. As the original issue is fixed by another method, this patch reverts: commit 1608f0230510 ("cpufreq: Fix re-boost issue after hotplugging a CPU") Reviewed-by: Lifeng Zheng <zhenglifeng1@huawei.com> Signed-off-by: Pierre Gondois <pierre.gondois@arm.com> --- drivers/cpufreq/cpufreq.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 277884d91913c..5757f12633d16 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1487,10 +1487,6 @@ static int cpufreq_policy_online(struct cpufreq_policy *policy, blocking_notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_CREATE_POLICY, policy); - } else { - ret = freq_qos_update_request(policy->max_freq_req, policy->max); - if (ret < 0) - goto out_destroy_policy; } if (cpufreq_driver->get && has_target()) { -- 2.43.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v8 2/2] cpufreq: Add boost_freq_req QoS request 2026-03-26 20:43 [PATCH v8 0/2] cpufreq: Introduce boost frequency QoS Pierre Gondois 2026-03-26 20:44 ` [PATCH v8 1/2] cpufreq: Remove max_freq_req update for pre-existing policy Pierre Gondois @ 2026-03-26 20:44 ` Pierre Gondois 2026-03-29 9:00 ` Zhongqiu Han 2026-03-27 3:43 ` [PATCH v8 0/2] cpufreq: Introduce boost frequency QoS Viresh Kumar 2 siblings, 1 reply; 15+ messages in thread From: Pierre Gondois @ 2026-03-26 20:44 UTC (permalink / raw) To: linux-kernel Cc: Lifeng Zheng, Pierre Gondois, Huang Rui, Gautham R. Shenoy, Mario Limonciello, Perry Yuan, Rafael J. Wysocki, Viresh Kumar, linux-pm The Power Management Quality of Service (PM QoS) allows to aggregate constraints from multiple entities. It is currently used to manage the min/max frequency of a given policy. Frequency constraints can come for instance from: - Thermal framework: acpi_thermal_cpufreq_init() - Firmware: _PPC objects: acpi_processor_ppc_init() - User: by setting policyX/scaling_[min|max]_freq The minimum of the max frequency constraints is used to compute the resulting maximum allowed frequency. When enabling boost frequencies, the same frequency request object (policy->max_freq_req) as to handle requests from users is used. As a result, when setting: - scaling_max_freq - boost The last sysfs file used overwrites the request from the other sysfs file. To avoid this, create a per-policy boost_freq_req to save the boost constraints instead of overwriting the last scaling_max_freq constraint. policy_set_boost() calls the cpufreq set_boost callback. Update the newly added boost_freq_req request from there: - whenever boost is toggled - to cover all possible paths In the existing .set_boost() callbacks: - Don't update policy->max as this is done through the qos notifier cpufreq_notifier_max() which calls cpufreq_set_policy(). - Remove freq_qos_update_request() calls as the qos request is now done in policy_set_boost() and updates the new boost_freq_req $ ## Init state scaling_max_freq:1000000 cpuinfo_max_freq:1000000 $ echo 700000 > scaling_max_freq scaling_max_freq:700000 cpuinfo_max_freq:1000000 $ echo 1 > ../boost scaling_max_freq:1200000 cpuinfo_max_freq:1200000 $ echo 800000 > scaling_max_freq scaling_max_freq:800000 cpuinfo_max_freq:1200000 $ ## Final step: $ ## Without the patches: $ echo 0 > ../boost scaling_max_freq:1000000 cpuinfo_max_freq:1000000 $ ## With the patches: $ echo 0 > ../boost scaling_max_freq:800000 cpuinfo_max_freq:1000000 Note: cpufreq_frequency_table_cpuinfo() updates policy->min and max from: A. cpufreq_boost_set_sw() \-cpufreq_frequency_table_cpuinfo() B. cpufreq_policy_online() \-cpufreq_table_validate_and_sort() \-cpufreq_frequency_table_cpuinfo() Keep these updates as some drivers expect policy->min and max to be set through B. Reviewed-by: Lifeng Zheng <zhenglifeng1@huawei.com> Signed-off-by: Pierre Gondois <pierre.gondois@arm.com> --- drivers/cpufreq/amd-pstate.c | 2 -- drivers/cpufreq/cppc_cpufreq.c | 10 ++------ drivers/cpufreq/cpufreq.c | 46 +++++++++++++++++++++++----------- include/linux/cpufreq.h | 1 + 4 files changed, 34 insertions(+), 25 deletions(-) diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c index 5aa9fcd80cf51..d0675d6a19fe1 100644 --- a/drivers/cpufreq/amd-pstate.c +++ b/drivers/cpufreq/amd-pstate.c @@ -769,8 +769,6 @@ static int amd_pstate_cpu_boost_update(struct cpufreq_policy *policy, bool on) else if (policy->cpuinfo.max_freq > nominal_freq) policy->cpuinfo.max_freq = nominal_freq; - policy->max = policy->cpuinfo.max_freq; - if (cppc_state == AMD_PSTATE_PASSIVE) { ret = freq_qos_update_request(&cpudata->req[1], policy->cpuinfo.max_freq); if (ret < 0) diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index 011f35cb47b94..f4f574fbe547b 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -807,17 +807,11 @@ static int cppc_cpufreq_set_boost(struct cpufreq_policy *policy, int state) { struct cppc_cpudata *cpu_data = policy->driver_data; struct cppc_perf_caps *caps = &cpu_data->perf_caps; - int ret; if (state) - policy->max = cppc_perf_to_khz(caps, caps->highest_perf); + policy->cpuinfo.max_freq = cppc_perf_to_khz(caps, caps->highest_perf); else - policy->max = cppc_perf_to_khz(caps, caps->nominal_perf); - policy->cpuinfo.max_freq = policy->max; - - ret = freq_qos_update_request(policy->max_freq_req, policy->max); - if (ret < 0) - return ret; + policy->cpuinfo.max_freq = cppc_perf_to_khz(caps, caps->nominal_perf); return 0; } diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 5757f12633d16..d2f393d738a39 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -609,10 +609,19 @@ static int policy_set_boost(struct cpufreq_policy *policy, bool enable) policy->boost_enabled = enable; ret = cpufreq_driver->set_boost(policy, enable); - if (ret) + if (ret) { policy->boost_enabled = !policy->boost_enabled; + return ret; + } - return ret; + 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); + return ret; + } + + return 0; } static ssize_t store_local_boost(struct cpufreq_policy *policy, @@ -1377,6 +1386,7 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy) } freq_qos_remove_request(policy->min_freq_req); + freq_qos_remove_request(policy->boost_freq_req); kfree(policy->min_freq_req); cpufreq_policy_put_kobj(policy); @@ -1445,26 +1455,38 @@ 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)); } - policy->min_freq_req = kzalloc(2 * sizeof(*policy->min_freq_req), + 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, + FREQ_QOS_MAX, + policy->cpuinfo.max_freq); + if (ret < 0) { + policy->boost_freq_req = NULL; + goto out_destroy_policy; + } + } + ret = freq_qos_add_request(&policy->constraints, policy->min_freq_req, FREQ_QOS_MIN, FREQ_QOS_MIN_DEFAULT_VALUE); if (ret < 0) { - /* - * So we don't call freq_qos_remove_request() for an - * uninitialized request. - */ kfree(policy->min_freq_req); policy->min_freq_req = NULL; goto out_destroy_policy; @@ -2788,16 +2810,10 @@ int cpufreq_boost_set_sw(struct cpufreq_policy *policy, int state) return -ENXIO; ret = cpufreq_frequency_table_cpuinfo(policy); - if (ret) { + if (ret) pr_err("%s: Policy frequency update failed\n", __func__); - return ret; - } - - ret = freq_qos_update_request(policy->max_freq_req, policy->max); - if (ret < 0) - return ret; - return 0; + return ret; } EXPORT_SYMBOL_GPL(cpufreq_boost_set_sw); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index cc894fc389710..89157e367eefa 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -81,6 +81,7 @@ struct cpufreq_policy { 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 cpufreq_frequency_table *freq_table; enum cpufreq_table_sorting freq_table_sorted; -- 2.43.0 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v8 2/2] cpufreq: Add boost_freq_req QoS request 2026-03-26 20:44 ` [PATCH v8 2/2] cpufreq: Add boost_freq_req QoS request Pierre Gondois @ 2026-03-29 9:00 ` Zhongqiu Han 2026-03-30 2:10 ` zhenglifeng (A) 2026-03-30 5:20 ` Viresh Kumar 0 siblings, 2 replies; 15+ messages in thread From: Zhongqiu Han @ 2026-03-29 9:00 UTC (permalink / raw) To: Pierre Gondois, linux-kernel Cc: Lifeng Zheng, Huang Rui, Gautham R. Shenoy, Mario Limonciello, Perry Yuan, Rafael J. Wysocki, Viresh Kumar, linux-pm, zhongqiu.han On 3/27/2026 4:44 AM, Pierre Gondois wrote: > The Power Management Quality of Service (PM QoS) allows to > aggregate constraints from multiple entities. It is currently > used to manage the min/max frequency of a given policy. > > Frequency constraints can come for instance from: > - Thermal framework: acpi_thermal_cpufreq_init() > - Firmware: _PPC objects: acpi_processor_ppc_init() > - User: by setting policyX/scaling_[min|max]_freq > The minimum of the max frequency constraints is used to compute > the resulting maximum allowed frequency. > > When enabling boost frequencies, the same frequency request object > (policy->max_freq_req) as to handle requests from users is used. > As a result, when setting: > - scaling_max_freq > - boost > The last sysfs file used overwrites the request from the other > sysfs file. > > To avoid this, create a per-policy boost_freq_req to save the boost > constraints instead of overwriting the last scaling_max_freq > constraint. > > policy_set_boost() calls the cpufreq set_boost callback. > Update the newly added boost_freq_req request from there: > - whenever boost is toggled > - to cover all possible paths > > In the existing .set_boost() callbacks: > - Don't update policy->max as this is done through the qos notifier > cpufreq_notifier_max() which calls cpufreq_set_policy(). > - Remove freq_qos_update_request() calls as the qos request is now > done in policy_set_boost() and updates the new boost_freq_req > > $ ## Init state > scaling_max_freq:1000000 > cpuinfo_max_freq:1000000 > > $ echo 700000 > scaling_max_freq > scaling_max_freq:700000 > cpuinfo_max_freq:1000000 > > $ echo 1 > ../boost > scaling_max_freq:1200000 > cpuinfo_max_freq:1200000 > > $ echo 800000 > scaling_max_freq > scaling_max_freq:800000 > cpuinfo_max_freq:1200000 > > $ ## Final step: > $ ## Without the patches: > $ echo 0 > ../boost > scaling_max_freq:1000000 > cpuinfo_max_freq:1000000 > > $ ## With the patches: > $ echo 0 > ../boost > scaling_max_freq:800000 > cpuinfo_max_freq:1000000 > > Note: > cpufreq_frequency_table_cpuinfo() updates policy->min > and max from: > A. > cpufreq_boost_set_sw() > \-cpufreq_frequency_table_cpuinfo() > B. > cpufreq_policy_online() > \-cpufreq_table_validate_and_sort() > \-cpufreq_frequency_table_cpuinfo() > Keep these updates as some drivers expect policy->min and > max to be set through B. > > Reviewed-by: Lifeng Zheng <zhenglifeng1@huawei.com> > Signed-off-by: Pierre Gondois <pierre.gondois@arm.com> > --- > drivers/cpufreq/amd-pstate.c | 2 -- > drivers/cpufreq/cppc_cpufreq.c | 10 ++------ > drivers/cpufreq/cpufreq.c | 46 +++++++++++++++++++++++----------- > include/linux/cpufreq.h | 1 + > 4 files changed, 34 insertions(+), 25 deletions(-) > > diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c > index 5aa9fcd80cf51..d0675d6a19fe1 100644 > --- a/drivers/cpufreq/amd-pstate.c > +++ b/drivers/cpufreq/amd-pstate.c > @@ -769,8 +769,6 @@ static int amd_pstate_cpu_boost_update(struct cpufreq_policy *policy, bool on) > else if (policy->cpuinfo.max_freq > nominal_freq) > policy->cpuinfo.max_freq = nominal_freq; > > - policy->max = policy->cpuinfo.max_freq; > - > if (cppc_state == AMD_PSTATE_PASSIVE) { > ret = freq_qos_update_request(&cpudata->req[1], policy->cpuinfo.max_freq); > if (ret < 0) > diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c > index 011f35cb47b94..f4f574fbe547b 100644 > --- a/drivers/cpufreq/cppc_cpufreq.c > +++ b/drivers/cpufreq/cppc_cpufreq.c > @@ -807,17 +807,11 @@ static int cppc_cpufreq_set_boost(struct cpufreq_policy *policy, int state) > { > struct cppc_cpudata *cpu_data = policy->driver_data; > struct cppc_perf_caps *caps = &cpu_data->perf_caps; > - int ret; > > if (state) > - policy->max = cppc_perf_to_khz(caps, caps->highest_perf); > + policy->cpuinfo.max_freq = cppc_perf_to_khz(caps, caps->highest_perf); > else > - policy->max = cppc_perf_to_khz(caps, caps->nominal_perf); > - policy->cpuinfo.max_freq = policy->max; > - > - ret = freq_qos_update_request(policy->max_freq_req, policy->max); > - if (ret < 0) > - return ret; > + policy->cpuinfo.max_freq = cppc_perf_to_khz(caps, caps->nominal_perf); > > return 0; > } > diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c > index 5757f12633d16..d2f393d738a39 100644 > --- a/drivers/cpufreq/cpufreq.c > +++ b/drivers/cpufreq/cpufreq.c > @@ -609,10 +609,19 @@ static int policy_set_boost(struct cpufreq_policy *policy, bool enable) > policy->boost_enabled = enable; > > ret = cpufreq_driver->set_boost(policy, enable); > - if (ret) > + if (ret) { > policy->boost_enabled = !policy->boost_enabled; > + return ret; > + } > > - return ret; > + 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); > + return ret; > + } > + > + return 0; > } > > static ssize_t store_local_boost(struct cpufreq_policy *policy, > @@ -1377,6 +1386,7 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy) > } > > freq_qos_remove_request(policy->min_freq_req); > + freq_qos_remove_request(policy->boost_freq_req); > kfree(policy->min_freq_req); > > cpufreq_policy_put_kobj(policy); > @@ -1445,26 +1455,38 @@ 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)); > } > > - policy->min_freq_req = kzalloc(2 * sizeof(*policy->min_freq_req), > + 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, > + FREQ_QOS_MAX, > + policy->cpuinfo.max_freq); > + if (ret < 0) { > + policy->boost_freq_req = NULL; > + goto out_destroy_policy; > + } > + } > + > ret = freq_qos_add_request(&policy->constraints, > policy->min_freq_req, FREQ_QOS_MIN, > FREQ_QOS_MIN_DEFAULT_VALUE); > if (ret < 0) { > - /* > - * So we don't call freq_qos_remove_request() for an > - * uninitialized request. > - */ > kfree(policy->min_freq_req); > policy->min_freq_req = NULL; > goto out_destroy_policy; Hi Pierre, Viresh, Sorry for the late follow-up on v8. While re-reading the patch, I noticed a potential UAF issue on an error path — I might be missing something, so I'd appreciate a double-check. min_freq_req, max_freq_req and boost_freq_req all point into the same contiguous kzalloc'd block: slot0 (min_freq_req + 0) -> min_freq_req slot1 (min_freq_req + 1) -> max_freq_req slot2 (min_freq_req + 2) -> boost_freq_req If boost_freq_req is successfully added to the QoS constraints list, but the subsequent freq_qos_add_request() for min_freq_req fails, the error path does: kfree(policy->min_freq_req); /* frees the entire block, including slot2 */ policy->min_freq_req = NULL; goto out_destroy_policy; policy->boost_freq_req is not set to NULL here, so it becomes a dangling pointer into freed memory. cpufreq_policy_free() is then called from cpufreq_online() and does: freq_qos_remove_request(policy->boost_freq_req); /* UAF */ or this boost qos req will leak. If freq_qos_add_request() for min_freq_req fails, maybe we can remove boost qos first, such as: if (ret < 0) { if (policy->boost_freq_req) { freq_qos_remove_request(policy->boost_freq_req); policy->boost_freq_req = NULL; } kfree(policy->min_freq_req); policy->min_freq_req = NULL; goto out_destroy_policy; } Besides, if freq_qos_add_request() for boost_freq_req fails first on cpufreq_policy_online(), policy->min_freq_req is valid pointer but qos req is inactive, will trigger one warn on freq_qos_remove_request(policy->min_freq_req) { if (WARN(!freq_qos_request_active(req), "%s() called for unknown object\n", __func__)) return -EINVAL; } > @@ -2788,16 +2810,10 @@ int cpufreq_boost_set_sw(struct cpufreq_policy *policy, int state) > return -ENXIO; > > ret = cpufreq_frequency_table_cpuinfo(policy); > - if (ret) { > + if (ret) > pr_err("%s: Policy frequency update failed\n", __func__); > - return ret; > - } > - > - ret = freq_qos_update_request(policy->max_freq_req, policy->max); > - if (ret < 0) > - return ret; > > - return 0; > + return ret; > } > EXPORT_SYMBOL_GPL(cpufreq_boost_set_sw); > > diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h > index cc894fc389710..89157e367eefa 100644 > --- a/include/linux/cpufreq.h > +++ b/include/linux/cpufreq.h > @@ -81,6 +81,7 @@ struct cpufreq_policy { > 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 cpufreq_frequency_table *freq_table; > enum cpufreq_table_sorting freq_table_sorted; -- Thx and BRs, Zhongqiu Han ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 2/2] cpufreq: Add boost_freq_req QoS request 2026-03-29 9:00 ` Zhongqiu Han @ 2026-03-30 2:10 ` zhenglifeng (A) 2026-03-30 4:00 ` Zhongqiu Han 2026-03-30 5:20 ` Viresh Kumar 1 sibling, 1 reply; 15+ messages in thread From: zhenglifeng (A) @ 2026-03-30 2:10 UTC (permalink / raw) To: Zhongqiu Han, Pierre Gondois, linux-kernel Cc: Huang Rui, Gautham R. Shenoy, Mario Limonciello, Perry Yuan, Rafael J. Wysocki, Viresh Kumar, linux-pm On 3/29/2026 5:00 PM, Zhongqiu Han wrote: >> @@ -1377,6 +1386,7 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy) >> } >> freq_qos_remove_request(policy->min_freq_req); >> + freq_qos_remove_request(policy->boost_freq_req); >> kfree(policy->min_freq_req); >> cpufreq_policy_put_kobj(policy); >> @@ -1445,26 +1455,38 @@ 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)); >> } >> - policy->min_freq_req = kzalloc(2 * sizeof(*policy->min_freq_req), >> + 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, >> + FREQ_QOS_MAX, >> + policy->cpuinfo.max_freq); >> + if (ret < 0) { >> + policy->boost_freq_req = NULL; >> + goto out_destroy_policy; >> + } >> + } >> + >> ret = freq_qos_add_request(&policy->constraints, >> policy->min_freq_req, FREQ_QOS_MIN, >> FREQ_QOS_MIN_DEFAULT_VALUE); >> if (ret < 0) { >> - /* >> - * So we don't call freq_qos_remove_request() for an >> - * uninitialized request. >> - */ >> kfree(policy->min_freq_req); >> policy->min_freq_req = NULL; >> goto out_destroy_policy; > > Hi Pierre, Viresh, > > Sorry for the late follow-up on v8. While re-reading the patch, I > noticed a potential UAF issue on an error path — I might be missing > something, so I'd appreciate a double-check. > > min_freq_req, max_freq_req and boost_freq_req all point into the same > contiguous kzalloc'd block: > > slot0 (min_freq_req + 0) -> min_freq_req > slot1 (min_freq_req + 1) -> max_freq_req > slot2 (min_freq_req + 2) -> boost_freq_req > > If boost_freq_req is successfully added to the QoS constraints list, but > the subsequent freq_qos_add_request() for min_freq_req fails, the error > path does: > > kfree(policy->min_freq_req); /* frees the entire block, including slot2 > */ > policy->min_freq_req = NULL; > goto out_destroy_policy; > > policy->boost_freq_req is not set to NULL here, so it becomes a dangling > pointer into freed memory. > cpufreq_policy_free() is then called from cpufreq_online() and does: > > freq_qos_remove_request(policy->boost_freq_req); /* UAF */ > or this boost qos req will leak. > Good catch! How about remove the kfree() here and just leave it to cpufreq_policy_free()? ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 2/2] cpufreq: Add boost_freq_req QoS request 2026-03-30 2:10 ` zhenglifeng (A) @ 2026-03-30 4:00 ` Zhongqiu Han 2026-03-30 7:16 ` zhenglifeng (A) 0 siblings, 1 reply; 15+ messages in thread From: Zhongqiu Han @ 2026-03-30 4:00 UTC (permalink / raw) To: zhenglifeng (A), Pierre Gondois, linux-kernel Cc: Huang Rui, Gautham R. Shenoy, Mario Limonciello, Perry Yuan, Rafael J. Wysocki, Viresh Kumar, linux-pm, zhongqiu.han On 3/30/2026 10:10 AM, zhenglifeng (A) wrote: > On 3/29/2026 5:00 PM, Zhongqiu Han wrote: >>> @@ -1377,6 +1386,7 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy) >>> } >>> freq_qos_remove_request(policy->min_freq_req); >>> + freq_qos_remove_request(policy->boost_freq_req); >>> kfree(policy->min_freq_req); >>> cpufreq_policy_put_kobj(policy); >>> @@ -1445,26 +1455,38 @@ 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)); >>> } >>> - policy->min_freq_req = kzalloc(2 * sizeof(*policy->min_freq_req), >>> + 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, >>> + FREQ_QOS_MAX, >>> + policy->cpuinfo.max_freq); >>> + if (ret < 0) { >>> + policy->boost_freq_req = NULL; >>> + goto out_destroy_policy; >>> + } >>> + } >>> + >>> ret = freq_qos_add_request(&policy->constraints, >>> policy->min_freq_req, FREQ_QOS_MIN, >>> FREQ_QOS_MIN_DEFAULT_VALUE); >>> if (ret < 0) { >>> - /* >>> - * So we don't call freq_qos_remove_request() for an >>> - * uninitialized request. >>> - */ >>> kfree(policy->min_freq_req); >>> policy->min_freq_req = NULL; >>> goto out_destroy_policy; >> >> Hi Pierre, Viresh, >> >> Sorry for the late follow-up on v8. While re-reading the patch, I >> noticed a potential UAF issue on an error path — I might be missing >> something, so I'd appreciate a double-check. >> >> min_freq_req, max_freq_req and boost_freq_req all point into the same >> contiguous kzalloc'd block: >> >> slot0 (min_freq_req + 0) -> min_freq_req >> slot1 (min_freq_req + 1) -> max_freq_req >> slot2 (min_freq_req + 2) -> boost_freq_req >> >> If boost_freq_req is successfully added to the QoS constraints list, but >> the subsequent freq_qos_add_request() for min_freq_req fails, the error >> path does: >> >> kfree(policy->min_freq_req); /* frees the entire block, including slot2 >> */ >> policy->min_freq_req = NULL; >> goto out_destroy_policy; >> >> policy->boost_freq_req is not set to NULL here, so it becomes a dangling >> pointer into freed memory. >> cpufreq_policy_free() is then called from cpufreq_online() and does: >> >> freq_qos_remove_request(policy->boost_freq_req); /* UAF */ >> or this boost qos req will leak. >> > > Good catch! > > How about remove the kfree() here and just leave it to > cpufreq_policy_free()? > Thanks for the suggestion — this is another fix approach we can explore, but there seems to be a small caveat. Some additional changes would still be needed; otherwise, removing the kfree() here and deferring it to cpufreq_policy_free() can lead to a warning. The reason is that we neither free policy->min_freq_req nor set policy ->min_freq_req = NULL. As a result, when cpufreq_policy_free() later calls freq_qos_remove_request(policy->min_freq_req), it hits the following warning: if (WARN(!freq_qos_request_active(req), "%s() called for unknown object\n", __func__)) return -EINVAL; -- Thx and BRs, Zhongqiu Han ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 2/2] cpufreq: Add boost_freq_req QoS request 2026-03-30 4:00 ` Zhongqiu Han @ 2026-03-30 7:16 ` zhenglifeng (A) 2026-03-30 13:01 ` Zhongqiu Han 0 siblings, 1 reply; 15+ messages in thread From: zhenglifeng (A) @ 2026-03-30 7:16 UTC (permalink / raw) To: Zhongqiu Han, Pierre Gondois, linux-kernel Cc: Huang Rui, Gautham R. Shenoy, Mario Limonciello, Perry Yuan, Rafael J. Wysocki, Viresh Kumar, linux-pm On 3/30/2026 12:00 PM, Zhongqiu Han wrote: > On 3/30/2026 10:10 AM, zhenglifeng (A) wrote: >> On 3/29/2026 5:00 PM, Zhongqiu Han wrote: >>>> @@ -1377,6 +1386,7 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy) >>>> } >>>> freq_qos_remove_request(policy->min_freq_req); >>>> + freq_qos_remove_request(policy->boost_freq_req); >>>> kfree(policy->min_freq_req); >>>> cpufreq_policy_put_kobj(policy); >>>> @@ -1445,26 +1455,38 @@ 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)); >>>> } >>>> - policy->min_freq_req = kzalloc(2 * sizeof(*policy->min_freq_req), >>>> + 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, >>>> + FREQ_QOS_MAX, >>>> + policy->cpuinfo.max_freq); >>>> + if (ret < 0) { >>>> + policy->boost_freq_req = NULL; >>>> + goto out_destroy_policy; >>>> + } >>>> + } >>>> + >>>> ret = freq_qos_add_request(&policy->constraints, >>>> policy->min_freq_req, FREQ_QOS_MIN, >>>> FREQ_QOS_MIN_DEFAULT_VALUE); >>>> if (ret < 0) { >>>> - /* >>>> - * So we don't call freq_qos_remove_request() for an >>>> - * uninitialized request. >>>> - */ >>>> kfree(policy->min_freq_req); >>>> policy->min_freq_req = NULL; >>>> goto out_destroy_policy; >>> >>> Hi Pierre, Viresh, >>> >>> Sorry for the late follow-up on v8. While re-reading the patch, I >>> noticed a potential UAF issue on an error path — I might be missing >>> something, so I'd appreciate a double-check. >>> >>> min_freq_req, max_freq_req and boost_freq_req all point into the same >>> contiguous kzalloc'd block: >>> >>> slot0 (min_freq_req + 0) -> min_freq_req >>> slot1 (min_freq_req + 1) -> max_freq_req >>> slot2 (min_freq_req + 2) -> boost_freq_req >>> >>> If boost_freq_req is successfully added to the QoS constraints list, but >>> the subsequent freq_qos_add_request() for min_freq_req fails, the error >>> path does: >>> >>> kfree(policy->min_freq_req); /* frees the entire block, including slot2 >>> */ >>> policy->min_freq_req = NULL; >>> goto out_destroy_policy; >>> >>> policy->boost_freq_req is not set to NULL here, so it becomes a dangling >>> pointer into freed memory. >>> cpufreq_policy_free() is then called from cpufreq_online() and does: >>> >>> freq_qos_remove_request(policy->boost_freq_req); /* UAF */ >>> or this boost qos req will leak. >>> >> >> Good catch! >> >> How about remove the kfree() here and just leave it to >> cpufreq_policy_free()? >> > > Thanks for the suggestion — this is another fix approach we can > explore, but there seems to be a small caveat. > > Some additional changes would still be needed; otherwise, removing the > kfree() here and deferring it to cpufreq_policy_free() can lead to a > warning. > > The reason is that we neither free policy->min_freq_req nor set policy > ->min_freq_req = NULL. As a result, when cpufreq_policy_free() later > calls freq_qos_remove_request(policy->min_freq_req), it hits the > following warning: > > if (WARN(!freq_qos_request_active(req), > "%s() called for unknown object\n", __func__)) > return -EINVAL; > Therefore, it seems the only option is to allocate memory separately for boost_freq_req. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 2/2] cpufreq: Add boost_freq_req QoS request 2026-03-30 7:16 ` zhenglifeng (A) @ 2026-03-30 13:01 ` Zhongqiu Han 0 siblings, 0 replies; 15+ messages in thread From: Zhongqiu Han @ 2026-03-30 13:01 UTC (permalink / raw) To: zhenglifeng (A), Pierre Gondois, linux-kernel Cc: Huang Rui, Gautham R. Shenoy, Mario Limonciello, Perry Yuan, Rafael J. Wysocki, Viresh Kumar, linux-pm, zhongqiu.han On 3/30/2026 3:16 PM, zhenglifeng (A) wrote: > On 3/30/2026 12:00 PM, Zhongqiu Han wrote: >> On 3/30/2026 10:10 AM, zhenglifeng (A) wrote: >>> On 3/29/2026 5:00 PM, Zhongqiu Han wrote: >>>>> @@ -1377,6 +1386,7 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy) >>>>> } >>>>> freq_qos_remove_request(policy->min_freq_req); >>>>> + freq_qos_remove_request(policy->boost_freq_req); >>>>> kfree(policy->min_freq_req); >>>>> cpufreq_policy_put_kobj(policy); >>>>> @@ -1445,26 +1455,38 @@ 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)); >>>>> } >>>>> - policy->min_freq_req = kzalloc(2 * sizeof(*policy->min_freq_req), >>>>> + 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, >>>>> + FREQ_QOS_MAX, >>>>> + policy->cpuinfo.max_freq); >>>>> + if (ret < 0) { >>>>> + policy->boost_freq_req = NULL; >>>>> + goto out_destroy_policy; >>>>> + } >>>>> + } >>>>> + >>>>> ret = freq_qos_add_request(&policy->constraints, >>>>> policy->min_freq_req, FREQ_QOS_MIN, >>>>> FREQ_QOS_MIN_DEFAULT_VALUE); >>>>> if (ret < 0) { >>>>> - /* >>>>> - * So we don't call freq_qos_remove_request() for an >>>>> - * uninitialized request. >>>>> - */ >>>>> kfree(policy->min_freq_req); >>>>> policy->min_freq_req = NULL; >>>>> goto out_destroy_policy; >>>> >>>> Hi Pierre, Viresh, >>>> >>>> Sorry for the late follow-up on v8. While re-reading the patch, I >>>> noticed a potential UAF issue on an error path — I might be missing >>>> something, so I'd appreciate a double-check. >>>> >>>> min_freq_req, max_freq_req and boost_freq_req all point into the same >>>> contiguous kzalloc'd block: >>>> >>>> slot0 (min_freq_req + 0) -> min_freq_req >>>> slot1 (min_freq_req + 1) -> max_freq_req >>>> slot2 (min_freq_req + 2) -> boost_freq_req >>>> >>>> If boost_freq_req is successfully added to the QoS constraints list, but >>>> the subsequent freq_qos_add_request() for min_freq_req fails, the error >>>> path does: >>>> >>>> kfree(policy->min_freq_req); /* frees the entire block, including slot2 >>>> */ >>>> policy->min_freq_req = NULL; >>>> goto out_destroy_policy; >>>> >>>> policy->boost_freq_req is not set to NULL here, so it becomes a dangling >>>> pointer into freed memory. >>>> cpufreq_policy_free() is then called from cpufreq_online() and does: >>>> >>>> freq_qos_remove_request(policy->boost_freq_req); /* UAF */ >>>> or this boost qos req will leak. >>>> >>> >>> Good catch! >>> >>> How about remove the kfree() here and just leave it to >>> cpufreq_policy_free()? >>> >> >> Thanks for the suggestion — this is another fix approach we can >> explore, but there seems to be a small caveat. >> >> Some additional changes would still be needed; otherwise, removing the >> kfree() here and deferring it to cpufreq_policy_free() can lead to a >> warning. >> >> The reason is that we neither free policy->min_freq_req nor set policy >> ->min_freq_req = NULL. As a result, when cpufreq_policy_free() later >> calls freq_qos_remove_request(policy->min_freq_req), it hits the >> following warning: >> >> if (WARN(!freq_qos_request_active(req), >> "%s() called for unknown object\n", __func__)) >> return -EINVAL; >> > > Therefore, it seems the only option is to allocate memory separately for > boost_freq_req. > Thanks Lifeng. Allocating memory separately could also be a direction we can explore. I also sketched another small example in a separate mail thread for discussion. -- Thx and BRs, Zhongqiu Han ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 2/2] cpufreq: Add boost_freq_req QoS request 2026-03-29 9:00 ` Zhongqiu Han 2026-03-30 2:10 ` zhenglifeng (A) @ 2026-03-30 5:20 ` Viresh Kumar 2026-03-30 12:55 ` Zhongqiu Han 1 sibling, 1 reply; 15+ messages in thread From: Viresh Kumar @ 2026-03-30 5:20 UTC (permalink / raw) To: Zhongqiu Han Cc: Pierre Gondois, linux-kernel, Lifeng Zheng, Huang Rui, Gautham R. Shenoy, Mario Limonciello, Perry Yuan, Rafael J. Wysocki, linux-pm On 29-03-26, 17:00, Zhongqiu Han wrote: > Sorry for the late follow-up on v8. While re-reading the patch, I > noticed a potential UAF issue on an error path — I might be missing > something, so I'd appreciate a double-check. > > min_freq_req, max_freq_req and boost_freq_req all point into the same > contiguous kzalloc'd block: > > slot0 (min_freq_req + 0) -> min_freq_req > slot1 (min_freq_req + 1) -> max_freq_req > slot2 (min_freq_req + 2) -> boost_freq_req > > If boost_freq_req is successfully added to the QoS constraints list, but > the subsequent freq_qos_add_request() for min_freq_req fails, the error > path does: > > kfree(policy->min_freq_req); /* frees the entire block, including slot2 > */ > policy->min_freq_req = NULL; > goto out_destroy_policy; > > policy->boost_freq_req is not set to NULL here, so it becomes a dangling > pointer into freed memory. Nice catch. The right solution to this I guess is to do kfree and setting min_freq_req to NULL if boost_freq_req fails (just like what happens in min_freq_req failure now) and then for later failures, don't do kfree at all but just set the failed qos feature to NULL (like what is done for max_freq_req now). -- viresh ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 2/2] cpufreq: Add boost_freq_req QoS request 2026-03-30 5:20 ` Viresh Kumar @ 2026-03-30 12:55 ` Zhongqiu Han 2026-03-31 3:14 ` Zhongqiu Han 2026-03-31 3:58 ` Viresh Kumar 0 siblings, 2 replies; 15+ messages in thread From: Zhongqiu Han @ 2026-03-30 12:55 UTC (permalink / raw) To: Viresh Kumar Cc: Pierre Gondois, linux-kernel, Lifeng Zheng, Huang Rui, Gautham R. Shenoy, Mario Limonciello, Perry Yuan, Rafael J. Wysocki, linux-pm, zhongqiu.han On 3/30/2026 1:20 PM, Viresh Kumar wrote: > On 29-03-26, 17:00, Zhongqiu Han wrote: >> Sorry for the late follow-up on v8. While re-reading the patch, I >> noticed a potential UAF issue on an error path — I might be missing >> something, so I'd appreciate a double-check. >> >> min_freq_req, max_freq_req and boost_freq_req all point into the same >> contiguous kzalloc'd block: >> >> slot0 (min_freq_req + 0) -> min_freq_req >> slot1 (min_freq_req + 1) -> max_freq_req >> slot2 (min_freq_req + 2) -> boost_freq_req >> >> If boost_freq_req is successfully added to the QoS constraints list, but >> the subsequent freq_qos_add_request() for min_freq_req fails, the error >> path does: >> >> kfree(policy->min_freq_req); /* frees the entire block, including slot2 >> */ >> policy->min_freq_req = NULL; >> goto out_destroy_policy; >> >> policy->boost_freq_req is not set to NULL here, so it becomes a dangling >> pointer into freed memory. > > Nice catch. > > The right solution to this I guess is to do kfree and setting min_freq_req to > NULL if boost_freq_req fails (just like what happens in min_freq_req failure > now) and then for later failures, don't do kfree at all but just set the failed > qos feature to NULL (like what is done for max_freq_req now). > Thanks Viresh — agreed, that approach makes sense. I sketched a small example along those lines for discussion only if needed: add boost_freq_req early when boost_supported, free the shared allocation if that add fails, and on later failures just unwind without freeing the block. + 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, + FREQ_QOS_MAX, + policy->cpuinfo.max_freq); + if (ret < 0) { + policy->boost_freq_req = NULL; + kfree(policy->min_freq_req); + policy->min_freq_req = NULL; + goto out_destroy_policy; + } + } + ret = freq_qos_add_request(&policy->constraints, policy->min_freq_req, FREQ_QOS_MIN, FREQ_QOS_MIN_DEFAULT_VALUE); if (ret < 0) { - /* - * So we don't call freq_qos_remove_request() for an - * uninitialized request. - */ + if (policy->boost_freq_req) { + freq_qos_remove_request(policy->boost_freq_req); + policy->boost_freq_req = NULL; + } kfree(policy->min_freq_req); policy->min_freq_req = NULL; goto out_destroy_policy; -- Thx and BRs, Zhongqiu Han ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 2/2] cpufreq: Add boost_freq_req QoS request 2026-03-30 12:55 ` Zhongqiu Han @ 2026-03-31 3:14 ` Zhongqiu Han 2026-03-31 3:58 ` Viresh Kumar 1 sibling, 0 replies; 15+ messages in thread From: Zhongqiu Han @ 2026-03-31 3:14 UTC (permalink / raw) To: Viresh Kumar Cc: Pierre Gondois, linux-kernel, Lifeng Zheng, Huang Rui, Gautham R. Shenoy, Mario Limonciello, Perry Yuan, Rafael J. Wysocki, linux-pm, zhongqiu.han On 3/30/2026 8:55 PM, Zhongqiu Han wrote: > On 3/30/2026 1:20 PM, Viresh Kumar wrote: >> On 29-03-26, 17:00, Zhongqiu Han wrote: >>> Sorry for the late follow-up on v8. While re-reading the patch, I >>> noticed a potential UAF issue on an error path — I might be missing >>> something, so I'd appreciate a double-check. >>> >>> min_freq_req, max_freq_req and boost_freq_req all point into the same >>> contiguous kzalloc'd block: >>> >>> slot0 (min_freq_req + 0) -> min_freq_req >>> slot1 (min_freq_req + 1) -> max_freq_req >>> slot2 (min_freq_req + 2) -> boost_freq_req >>> >>> If boost_freq_req is successfully added to the QoS constraints list, but >>> the subsequent freq_qos_add_request() for min_freq_req fails, the error >>> path does: >>> >>> kfree(policy->min_freq_req); /* frees the entire block, including slot2 >>> */ >>> policy->min_freq_req = NULL; >>> goto out_destroy_policy; >>> >>> policy->boost_freq_req is not set to NULL here, so it becomes a dangling >>> pointer into freed memory. >> >> Nice catch. >> >> The right solution to this I guess is to do kfree and setting >> min_freq_req to >> NULL if boost_freq_req fails (just like what happens in min_freq_req >> failure >> now) and then for later failures, don't do kfree at all but just set >> the failed >> qos feature to NULL (like what is done for max_freq_req now). >> > > > Thanks Viresh — agreed, that approach makes sense. > I sketched a small example along those lines for discussion only if > needed: add boost_freq_req early when boost_supported, free the shared > allocation if that add fails, and on later failures just unwind without > freeing the block. > > > + 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, > + FREQ_QOS_MAX, > + policy->cpuinfo.max_freq); > + if (ret < 0) { > + policy->boost_freq_req = NULL; > + kfree(policy->min_freq_req); > + policy->min_freq_req = NULL; > + goto out_destroy_policy; > + } > + } > + > ret = freq_qos_add_request(&policy->constraints, > policy->min_freq_req, FREQ_QOS_MIN, > FREQ_QOS_MIN_DEFAULT_VALUE); > if (ret < 0) { > - /* > - * So we don't call freq_qos_remove_request() for an > - * uninitialized request. > - */ > + if (policy->boost_freq_req) { > + freq_qos_remove_request(policy->boost_freq_req); > + policy->boost_freq_req = NULL; > + } > kfree(policy->min_freq_req); > policy->min_freq_req = NULL; > goto out_destroy_policy; > > > Now that the patch has been picked on queue, if the approach in the current draft looks reasonable, I'm happy to send it out as a proper fixup. -- Thx and BRs, Zhongqiu Han ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 2/2] cpufreq: Add boost_freq_req QoS request 2026-03-30 12:55 ` Zhongqiu Han 2026-03-31 3:14 ` Zhongqiu Han @ 2026-03-31 3:58 ` Viresh Kumar 1 sibling, 0 replies; 15+ messages in thread From: Viresh Kumar @ 2026-03-31 3:58 UTC (permalink / raw) To: Zhongqiu Han Cc: Pierre Gondois, linux-kernel, Lifeng Zheng, Huang Rui, Gautham R. Shenoy, Mario Limonciello, Perry Yuan, Rafael J. Wysocki, linux-pm On 30-03-26, 20:55, Zhongqiu Han wrote: > Thanks Viresh — agreed, that approach makes sense. > I sketched a small example along those lines for discussion only if > needed: add boost_freq_req early when boost_supported, free the shared > allocation if that add fails, and on later failures just unwind without > freeing the block. I have taken a different approach to fix this. (Build tested). 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; -- viresh ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v8 0/2] cpufreq: Introduce boost frequency QoS 2026-03-26 20:43 [PATCH v8 0/2] cpufreq: Introduce boost frequency QoS Pierre Gondois 2026-03-26 20:44 ` [PATCH v8 1/2] cpufreq: Remove max_freq_req update for pre-existing policy Pierre Gondois 2026-03-26 20:44 ` [PATCH v8 2/2] cpufreq: Add boost_freq_req QoS request Pierre Gondois @ 2026-03-27 3:43 ` Viresh Kumar 2026-03-27 16:07 ` Pierre Gondois 2 siblings, 1 reply; 15+ messages in thread From: Viresh Kumar @ 2026-03-27 3:43 UTC (permalink / raw) To: Pierre Gondois Cc: linux-kernel, Lifeng Zheng, Huang Rui, Gautham R. Shenoy, Mario Limonciello, Perry Yuan, Rafael J. Wysocki, linux-pm On 26-03-26, 21:43, Pierre Gondois wrote: > Pierre Gondois (2): > cpufreq: Remove max_freq_req update for pre-existing policy > cpufreq: Add boost_freq_req QoS request > > drivers/cpufreq/amd-pstate.c | 2 -- > drivers/cpufreq/cppc_cpufreq.c | 10 ++----- > drivers/cpufreq/cpufreq.c | 50 +++++++++++++++++++++------------- > include/linux/cpufreq.h | 1 + > 4 files changed, 34 insertions(+), 29 deletions(-) Thanks Pierre for your patience. Acked-by: Viresh Kumar <viresh.kumar@linaro.org> -- viresh ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 0/2] cpufreq: Introduce boost frequency QoS 2026-03-27 3:43 ` [PATCH v8 0/2] cpufreq: Introduce boost frequency QoS Viresh Kumar @ 2026-03-27 16:07 ` Pierre Gondois 2026-03-30 19:58 ` Rafael J. Wysocki 0 siblings, 1 reply; 15+ messages in thread From: Pierre Gondois @ 2026-03-27 16:07 UTC (permalink / raw) To: Viresh Kumar Cc: linux-kernel, Lifeng Zheng, Huang Rui, Gautham R. Shenoy, Mario Limonciello, Perry Yuan, Rafael J. Wysocki, linux-pm On 3/27/26 04:43, Viresh Kumar wrote: > On 26-03-26, 21:43, Pierre Gondois wrote: >> Pierre Gondois (2): >> cpufreq: Remove max_freq_req update for pre-existing policy >> cpufreq: Add boost_freq_req QoS request >> >> drivers/cpufreq/amd-pstate.c | 2 -- >> drivers/cpufreq/cppc_cpufreq.c | 10 ++----- >> drivers/cpufreq/cpufreq.c | 50 +++++++++++++++++++++------------- >> include/linux/cpufreq.h | 1 + >> 4 files changed, 34 insertions(+), 29 deletions(-) > Thanks Pierre for your patience. Thanks for the review (to Lifeng aswell) > > Acked-by: Viresh Kumar <viresh.kumar@linaro.org> > ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v8 0/2] cpufreq: Introduce boost frequency QoS 2026-03-27 16:07 ` Pierre Gondois @ 2026-03-30 19:58 ` Rafael J. Wysocki 0 siblings, 0 replies; 15+ messages in thread From: Rafael J. Wysocki @ 2026-03-30 19:58 UTC (permalink / raw) To: Pierre Gondois Cc: Viresh Kumar, linux-kernel, Lifeng Zheng, Huang Rui, Gautham R. Shenoy, Mario Limonciello, Perry Yuan, Rafael J. Wysocki, linux-pm On Fri, Mar 27, 2026 at 5:09 PM Pierre Gondois <pierre.gondois@arm.com> wrote: > > > On 3/27/26 04:43, Viresh Kumar wrote: > > On 26-03-26, 21:43, Pierre Gondois wrote: > >> Pierre Gondois (2): > >> cpufreq: Remove max_freq_req update for pre-existing policy > >> cpufreq: Add boost_freq_req QoS request > >> > >> drivers/cpufreq/amd-pstate.c | 2 -- > >> drivers/cpufreq/cppc_cpufreq.c | 10 ++----- > >> drivers/cpufreq/cpufreq.c | 50 +++++++++++++++++++++------------- > >> include/linux/cpufreq.h | 1 + > >> 4 files changed, 34 insertions(+), 29 deletions(-) > > Thanks Pierre for your patience. > Thanks for the review (to Lifeng aswell) > > > > Acked-by: Viresh Kumar <viresh.kumar@linaro.org> Applied as 7.1 material, thanks! ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-03-31 3:58 UTC | newest] Thread overview: 15+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-03-26 20:43 [PATCH v8 0/2] cpufreq: Introduce boost frequency QoS Pierre Gondois 2026-03-26 20:44 ` [PATCH v8 1/2] cpufreq: Remove max_freq_req update for pre-existing policy Pierre Gondois 2026-03-26 20:44 ` [PATCH v8 2/2] cpufreq: Add boost_freq_req QoS request Pierre Gondois 2026-03-29 9:00 ` Zhongqiu Han 2026-03-30 2:10 ` zhenglifeng (A) 2026-03-30 4:00 ` Zhongqiu Han 2026-03-30 7:16 ` zhenglifeng (A) 2026-03-30 13:01 ` Zhongqiu Han 2026-03-30 5:20 ` Viresh Kumar 2026-03-30 12:55 ` Zhongqiu Han 2026-03-31 3:14 ` Zhongqiu Han 2026-03-31 3:58 ` Viresh Kumar 2026-03-27 3:43 ` [PATCH v8 0/2] cpufreq: Introduce boost frequency QoS Viresh Kumar 2026-03-27 16:07 ` Pierre Gondois 2026-03-30 19:58 ` Rafael J. Wysocki
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.