Skip to content

Commit 9266b4d

Browse files
vireshkrafaeljw
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>
1 parent 6e39ba4 commit 9266b4d

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
@@ -614,7 +614,7 @@ static int policy_set_boost(struct cpufreq_policy *policy, bool enable)
614614
return ret;
615615
}
616616

617-
ret = freq_qos_update_request(policy->boost_freq_req, policy->cpuinfo.max_freq);
617+
ret = freq_qos_update_request(&policy->boost_freq_req, policy->cpuinfo.max_freq);
618618
if (ret < 0) {
619619
policy->boost_enabled = !policy->boost_enabled;
620620
cpufreq_driver->set_boost(policy, policy->boost_enabled);
@@ -769,7 +769,7 @@ static ssize_t store_##file_name \
769769
if (ret) \
770770
return ret; \
771771
\
772-
ret = freq_qos_update_request(policy->object##_freq_req, val);\
772+
ret = freq_qos_update_request(&policy->object##_freq_req, val); \
773773
return ret >= 0 ? count : ret; \
774774
}
775775

@@ -1374,20 +1374,21 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
13741374
/* Cancel any pending policy->update work before freeing the policy. */
13751375
cancel_work_sync(&policy->update);
13761376

1377-
if (policy->max_freq_req) {
1377+
if (freq_qos_request_active(&policy->max_freq_req)) {
13781378
/*
13791379
* Remove max_freq_req after sending CPUFREQ_REMOVE_POLICY
13801380
* notification, since CPUFREQ_CREATE_POLICY notification was
13811381
* sent after adding max_freq_req earlier.
13821382
*/
13831383
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
13841384
CPUFREQ_REMOVE_POLICY, policy);
1385-
freq_qos_remove_request(policy->max_freq_req);
1385+
freq_qos_remove_request(&policy->max_freq_req);
13861386
}
13871387

1388-
freq_qos_remove_request(policy->min_freq_req);
1389-
freq_qos_remove_request(policy->boost_freq_req);
1390-
kfree(policy->min_freq_req);
1388+
if (freq_qos_request_active(&policy->min_freq_req))
1389+
freq_qos_remove_request(&policy->min_freq_req);
1390+
if (freq_qos_request_active(&policy->boost_freq_req))
1391+
freq_qos_remove_request(&policy->boost_freq_req);
13911392

13921393
cpufreq_policy_put_kobj(policy);
13931394
free_cpumask_var(policy->real_cpus);
@@ -1452,57 +1453,31 @@ static int cpufreq_policy_online(struct cpufreq_policy *policy,
14521453
cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
14531454

14541455
if (new_policy) {
1455-
unsigned int count;
1456-
14571456
for_each_cpu(j, policy->related_cpus) {
14581457
per_cpu(cpufreq_cpu_data, j) = policy;
14591458
add_cpu_dev_symlink(policy, j, get_cpu_device(j));
14601459
}
14611460

1462-
count = policy->boost_supported ? 3 : 2;
1463-
policy->min_freq_req = kzalloc(count * sizeof(*policy->min_freq_req),
1464-
GFP_KERNEL);
1465-
if (!policy->min_freq_req) {
1466-
ret = -ENOMEM;
1467-
goto out_destroy_policy;
1468-
}
1469-
14701461
if (policy->boost_supported) {
1471-
policy->boost_freq_req = policy->min_freq_req + 2;
1472-
14731462
ret = freq_qos_add_request(&policy->constraints,
1474-
policy->boost_freq_req,
1463+
&policy->boost_freq_req,
14751464
FREQ_QOS_MAX,
14761465
policy->cpuinfo.max_freq);
1477-
if (ret < 0) {
1478-
policy->boost_freq_req = NULL;
1466+
if (ret < 0)
14791467
goto out_destroy_policy;
1480-
}
14811468
}
14821469

14831470
ret = freq_qos_add_request(&policy->constraints,
1484-
policy->min_freq_req, FREQ_QOS_MIN,
1471+
&policy->min_freq_req, FREQ_QOS_MIN,
14851472
FREQ_QOS_MIN_DEFAULT_VALUE);
1486-
if (ret < 0) {
1487-
kfree(policy->min_freq_req);
1488-
policy->min_freq_req = NULL;
1473+
if (ret < 0)
14891474
goto out_destroy_policy;
1490-
}
1491-
1492-
/*
1493-
* This must be initialized right here to avoid calling
1494-
* freq_qos_remove_request() on uninitialized request in case
1495-
* of errors.
1496-
*/
1497-
policy->max_freq_req = policy->min_freq_req + 1;
14981475

14991476
ret = freq_qos_add_request(&policy->constraints,
1500-
policy->max_freq_req, FREQ_QOS_MAX,
1477+
&policy->max_freq_req, FREQ_QOS_MAX,
15011478
FREQ_QOS_MAX_DEFAULT_VALUE);
1502-
if (ret < 0) {
1503-
policy->max_freq_req = NULL;
1479+
if (ret < 0)
15041480
goto out_destroy_policy;
1505-
}
15061481

15071482
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
15081483
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)