cpufreq: Fix locking issues with governors
commit 8cc46ae565
upstream.
The locking around governors handling isn't adequate currently.
The list of governors should never be traversed without the locking
in place. Also governor modules must not be removed while the code
in them is still in use.
Reported-by: Quentin Perret <qperret@google.com>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Cc: All applicable <stable@vger.kernel.org>
[ rjw: Changelog ]
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
5.4-rM2-2.2.x-imx-squashed
parent
6d1e56826e
commit
613a374f3f
|
@ -616,6 +616,24 @@ static struct cpufreq_governor *find_governor(const char *str_governor)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct cpufreq_governor *get_governor(const char *str_governor)
|
||||||
|
{
|
||||||
|
struct cpufreq_governor *t;
|
||||||
|
|
||||||
|
mutex_lock(&cpufreq_governor_mutex);
|
||||||
|
t = find_governor(str_governor);
|
||||||
|
if (!t)
|
||||||
|
goto unlock;
|
||||||
|
|
||||||
|
if (!try_module_get(t->owner))
|
||||||
|
t = NULL;
|
||||||
|
|
||||||
|
unlock:
|
||||||
|
mutex_unlock(&cpufreq_governor_mutex);
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
static unsigned int cpufreq_parse_policy(char *str_governor)
|
static unsigned int cpufreq_parse_policy(char *str_governor)
|
||||||
{
|
{
|
||||||
if (!strncasecmp(str_governor, "performance", CPUFREQ_NAME_LEN))
|
if (!strncasecmp(str_governor, "performance", CPUFREQ_NAME_LEN))
|
||||||
|
@ -635,28 +653,14 @@ static struct cpufreq_governor *cpufreq_parse_governor(char *str_governor)
|
||||||
{
|
{
|
||||||
struct cpufreq_governor *t;
|
struct cpufreq_governor *t;
|
||||||
|
|
||||||
mutex_lock(&cpufreq_governor_mutex);
|
t = get_governor(str_governor);
|
||||||
|
if (t)
|
||||||
|
return t;
|
||||||
|
|
||||||
t = find_governor(str_governor);
|
if (request_module("cpufreq_%s", str_governor))
|
||||||
if (!t) {
|
return NULL;
|
||||||
int ret;
|
|
||||||
|
|
||||||
mutex_unlock(&cpufreq_governor_mutex);
|
return get_governor(str_governor);
|
||||||
|
|
||||||
ret = request_module("cpufreq_%s", str_governor);
|
|
||||||
if (ret)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
mutex_lock(&cpufreq_governor_mutex);
|
|
||||||
|
|
||||||
t = find_governor(str_governor);
|
|
||||||
}
|
|
||||||
if (t && !try_module_get(t->owner))
|
|
||||||
t = NULL;
|
|
||||||
|
|
||||||
mutex_unlock(&cpufreq_governor_mutex);
|
|
||||||
|
|
||||||
return t;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -810,12 +814,14 @@ static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_lock(&cpufreq_governor_mutex);
|
||||||
for_each_governor(t) {
|
for_each_governor(t) {
|
||||||
if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char))
|
if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char))
|
||||||
- (CPUFREQ_NAME_LEN + 2)))
|
- (CPUFREQ_NAME_LEN + 2)))
|
||||||
goto out;
|
break;
|
||||||
i += scnprintf(&buf[i], CPUFREQ_NAME_PLEN, "%s ", t->name);
|
i += scnprintf(&buf[i], CPUFREQ_NAME_PLEN, "%s ", t->name);
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&cpufreq_governor_mutex);
|
||||||
out:
|
out:
|
||||||
i += sprintf(&buf[i], "\n");
|
i += sprintf(&buf[i], "\n");
|
||||||
return i;
|
return i;
|
||||||
|
@ -1053,15 +1059,17 @@ static int cpufreq_init_policy(struct cpufreq_policy *policy)
|
||||||
struct cpufreq_governor *def_gov = cpufreq_default_governor();
|
struct cpufreq_governor *def_gov = cpufreq_default_governor();
|
||||||
struct cpufreq_governor *gov = NULL;
|
struct cpufreq_governor *gov = NULL;
|
||||||
unsigned int pol = CPUFREQ_POLICY_UNKNOWN;
|
unsigned int pol = CPUFREQ_POLICY_UNKNOWN;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (has_target()) {
|
if (has_target()) {
|
||||||
/* Update policy governor to the one used before hotplug. */
|
/* Update policy governor to the one used before hotplug. */
|
||||||
gov = find_governor(policy->last_governor);
|
gov = get_governor(policy->last_governor);
|
||||||
if (gov) {
|
if (gov) {
|
||||||
pr_debug("Restoring governor %s for cpu %d\n",
|
pr_debug("Restoring governor %s for cpu %d\n",
|
||||||
policy->governor->name, policy->cpu);
|
policy->governor->name, policy->cpu);
|
||||||
} else if (def_gov) {
|
} else if (def_gov) {
|
||||||
gov = def_gov;
|
gov = def_gov;
|
||||||
|
__module_get(gov->owner);
|
||||||
} else {
|
} else {
|
||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
}
|
}
|
||||||
|
@ -1084,7 +1092,11 @@ static int cpufreq_init_policy(struct cpufreq_policy *policy)
|
||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
return cpufreq_set_policy(policy, gov, pol);
|
ret = cpufreq_set_policy(policy, gov, pol);
|
||||||
|
if (gov)
|
||||||
|
module_put(gov->owner);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
|
static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
|
||||||
|
|
Loading…
Reference in New Issue