Skip to content

Commit dc82c18

Browse files
vireshksforshee
authored andcommitted
cpufreq: Allocate QoS freq_req objects with policy
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: 6e39ba4 ("cpufreq: Add boost_freq_req QoS request") Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Reviewed-by: Lifeng Zheng <zhenglifeng1@huawei.com> Tested-by: Pierre Gondois <pierre.gondois@arm.com> Reviewed-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com> Link: https://patch.msgid.link/a293f29d841b86c51f34699c6e717e01858d8ada.1774933424.git.viresh.kumar@linaro.org Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> (cherry picked from commit 9266b4d) Signed-off-by: Seth Forshee <sforshee@nvidia.com>
1 parent a172876 commit dc82c18

2 files changed

Lines changed: 17 additions & 42 deletions

File tree

drivers/cpufreq/cpufreq.c

Lines changed: 14 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ static int policy_set_boost(struct cpufreq_policy *policy, bool enable)
608608
return ret;
609609
}
610610

611-
ret = freq_qos_update_request(policy->boost_freq_req, policy->cpuinfo.max_freq);
611+
ret = freq_qos_update_request(&policy->boost_freq_req, policy->cpuinfo.max_freq);
612612
if (ret < 0) {
613613
policy->boost_enabled = !policy->boost_enabled;
614614
cpufreq_driver->set_boost(policy, policy->boost_enabled);
@@ -763,7 +763,7 @@ static ssize_t store_##file_name \
763763
if (ret) \
764764
return ret; \
765765
\
766-
ret = freq_qos_update_request(policy->object##_freq_req, val);\
766+
ret = freq_qos_update_request(&policy->object##_freq_req, val); \
767767
return ret >= 0 ? count : ret; \
768768
}
769769

@@ -1368,20 +1368,21 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
13681368
/* Cancel any pending policy->update work before freeing the policy. */
13691369
cancel_work_sync(&policy->update);
13701370

1371-
if (policy->max_freq_req) {
1371+
if (freq_qos_request_active(&policy->max_freq_req)) {
13721372
/*
13731373
* Remove max_freq_req after sending CPUFREQ_REMOVE_POLICY
13741374
* notification, since CPUFREQ_CREATE_POLICY notification was
13751375
* sent after adding max_freq_req earlier.
13761376
*/
13771377
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
13781378
CPUFREQ_REMOVE_POLICY, policy);
1379-
freq_qos_remove_request(policy->max_freq_req);
1379+
freq_qos_remove_request(&policy->max_freq_req);
13801380
}
13811381

1382-
freq_qos_remove_request(policy->min_freq_req);
1383-
freq_qos_remove_request(policy->boost_freq_req);
1384-
kfree(policy->min_freq_req);
1382+
if (freq_qos_request_active(&policy->min_freq_req))
1383+
freq_qos_remove_request(&policy->min_freq_req);
1384+
if (freq_qos_request_active(&policy->boost_freq_req))
1385+
freq_qos_remove_request(&policy->boost_freq_req);
13851386

13861387
cpufreq_policy_put_kobj(policy);
13871388
free_cpumask_var(policy->real_cpus);
@@ -1446,57 +1447,31 @@ static int cpufreq_policy_online(struct cpufreq_policy *policy,
14461447
cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
14471448

14481449
if (new_policy) {
1449-
unsigned int count;
1450-
14511450
for_each_cpu(j, policy->related_cpus) {
14521451
per_cpu(cpufreq_cpu_data, j) = policy;
14531452
add_cpu_dev_symlink(policy, j, get_cpu_device(j));
14541453
}
14551454

1456-
count = policy->boost_supported ? 3 : 2;
1457-
policy->min_freq_req = kzalloc(count * sizeof(*policy->min_freq_req),
1458-
GFP_KERNEL);
1459-
if (!policy->min_freq_req) {
1460-
ret = -ENOMEM;
1461-
goto out_destroy_policy;
1462-
}
1463-
14641455
if (policy->boost_supported) {
1465-
policy->boost_freq_req = policy->min_freq_req + 2;
1466-
14671456
ret = freq_qos_add_request(&policy->constraints,
1468-
policy->boost_freq_req,
1457+
&policy->boost_freq_req,
14691458
FREQ_QOS_MAX,
14701459
policy->cpuinfo.max_freq);
1471-
if (ret < 0) {
1472-
policy->boost_freq_req = NULL;
1460+
if (ret < 0)
14731461
goto out_destroy_policy;
1474-
}
14751462
}
14761463

14771464
ret = freq_qos_add_request(&policy->constraints,
1478-
policy->min_freq_req, FREQ_QOS_MIN,
1465+
&policy->min_freq_req, FREQ_QOS_MIN,
14791466
FREQ_QOS_MIN_DEFAULT_VALUE);
1480-
if (ret < 0) {
1481-
kfree(policy->min_freq_req);
1482-
policy->min_freq_req = NULL;
1467+
if (ret < 0)
14831468
goto out_destroy_policy;
1484-
}
1485-
1486-
/*
1487-
* This must be initialized right here to avoid calling
1488-
* freq_qos_remove_request() on uninitialized request in case
1489-
* of errors.
1490-
*/
1491-
policy->max_freq_req = policy->min_freq_req + 1;
14921469

14931470
ret = freq_qos_add_request(&policy->constraints,
1494-
policy->max_freq_req, FREQ_QOS_MAX,
1471+
&policy->max_freq_req, FREQ_QOS_MAX,
14951472
FREQ_QOS_MAX_DEFAULT_VALUE);
1496-
if (ret < 0) {
1497-
policy->max_freq_req = NULL;
1473+
if (ret < 0)
14981474
goto out_destroy_policy;
1499-
}
15001475

15011476
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
15021477
CPUFREQ_CREATE_POLICY, policy);

include/linux/cpufreq.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,9 @@ struct cpufreq_policy {
7979
* called, but you're in IRQ context */
8080

8181
struct freq_constraints constraints;
82-
struct freq_qos_request *min_freq_req;
83-
struct freq_qos_request *max_freq_req;
84-
struct freq_qos_request *boost_freq_req;
82+
struct freq_qos_request min_freq_req;
83+
struct freq_qos_request max_freq_req;
84+
struct freq_qos_request boost_freq_req;
8585

8686
struct cpufreq_frequency_table *freq_table;
8787
enum cpufreq_table_sorting freq_table_sorted;

0 commit comments

Comments
 (0)