summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRohit Gupta <rohgup@codeaurora.org>2015-01-07 09:56:22 -0800
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 21:22:24 -0700
commit11ff15ea438cd77dafc54dde22a84f50a38ed4c2 (patch)
tree54a9d93d17e0b5780db024f65fcc415b1bf5ce7a
parenta47233f55bf1097ef1685f0f08a0a95147e2f642 (diff)
soc: qcom: msm_perf: Fix a race condition in hotplug callback
msm_performance relies on userspace to initialize cluster related variables such as num_clusters, managed_cpus etc. Once num_clusters is set the cluster related data structures are initialized and userspace is allowed to set them. However there could be a race where between num_clusters being set and the cluster data structures being allocated, there is a hotplug activity which would invoke the hotplug callback which in turn tries to access managed_cpus. managed_cpus might not have been allocated by that time resulting in a NULL pointer access in the callback causing kernel panic. Change-Id: Ia40af624322a89e0c0f9598bf7eea059e6969ebe Signed-off-by: Rohit Gupta <rohgup@codeaurora.org>
-rw-r--r--drivers/soc/qcom/msm_performance.c20
1 files changed, 14 insertions, 6 deletions
diff --git a/drivers/soc/qcom/msm_performance.c b/drivers/soc/qcom/msm_performance.c
index 38302c52202c..cc8faf63515c 100644
--- a/drivers/soc/qcom/msm_performance.c
+++ b/drivers/soc/qcom/msm_performance.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -33,6 +33,7 @@ struct cpu_hp {
cpumask_var_t offlined_cpus;
};
static struct cpu_hp **managed_clusters;
+static bool clusters_inited;
/* Work to evaluate the onlining/offlining CPUs */
struct delayed_work evaluate_hotplug_work;
@@ -86,7 +87,7 @@ static int set_max_cpus(const char *buf, const struct kernel_param *kp)
const char *cp = buf;
int val;
- if (!num_clusters)
+ if (!clusters_inited)
return -EINVAL;
while ((cp = strpbrk(cp + 1, ":")))
@@ -120,7 +121,7 @@ static int get_max_cpus(char *buf, const struct kernel_param *kp)
{
int i, cnt = 0;
- if (!num_clusters)
+ if (!clusters_inited)
return cnt;
for (i = 0; i < num_clusters; i++)
@@ -143,7 +144,7 @@ static int set_managed_cpus(const char *buf, const struct kernel_param *kp)
int i, ret;
struct cpumask tmp_mask;
- if (!num_clusters)
+ if (!clusters_inited)
return -EINVAL;
ret = cpulist_parse(buf, &tmp_mask);
@@ -168,7 +169,7 @@ static int get_managed_cpus(char *buf, const struct kernel_param *kp)
{
int i, cnt = 0;
- if (!num_clusters)
+ if (!clusters_inited)
return cnt;
for (i = 0; i < num_clusters; i++) {
@@ -195,7 +196,7 @@ static int get_managed_online_cpus(char *buf, const struct kernel_param *kp)
struct cpumask tmp_mask;
struct cpu_hp *i_cpu_hp;
- if (!num_clusters)
+ if (!clusters_inited)
return cnt;
for (i = 0; i < num_clusters; i++) {
@@ -498,6 +499,9 @@ static void __ref try_hotplug(struct cpu_hp *data)
{
unsigned int i;
+ if (!clusters_inited)
+ return;
+
pr_debug("msm_perf: Trying hotplug...%d:%d\n",
num_online_managed(data->cpus), num_online_cpus());
@@ -590,6 +594,9 @@ static int __ref msm_performance_cpu_callback(struct notifier_block *nfb,
unsigned int i;
struct cpu_hp *i_hp = NULL;
+ if (!clusters_inited)
+ return NOTIFY_OK;
+
for (i = 0; i < num_clusters; i++) {
if (cpumask_test_cpu(cpu, managed_clusters[i]->cpus)) {
i_hp = managed_clusters[i];
@@ -656,6 +663,7 @@ static int init_cluster_control(void)
INIT_DELAYED_WORK(&evaluate_hotplug_work, check_cluster_status);
mutex_init(&managed_cpus_lock);
+ clusters_inited = true;
return 0;
}