Skip to content

Commit 8cc46ae

Browse files
vireshkrafaeljw
authored andcommitted
cpufreq: Fix locking issues with governors
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 <[email protected]> Signed-off-by: Viresh Kumar <[email protected]> Cc: All applicable <[email protected]> [ rjw: Changelog ] Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent f473bf3 commit 8cc46ae

File tree

1 file changed

+35
-23
lines changed

1 file changed

+35
-23
lines changed

drivers/cpufreq/cpufreq.c

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,24 @@ static struct cpufreq_governor *find_governor(const char *str_governor)
621621
return NULL;
622622
}
623623

624+
static struct cpufreq_governor *get_governor(const char *str_governor)
625+
{
626+
struct cpufreq_governor *t;
627+
628+
mutex_lock(&cpufreq_governor_mutex);
629+
t = find_governor(str_governor);
630+
if (!t)
631+
goto unlock;
632+
633+
if (!try_module_get(t->owner))
634+
t = NULL;
635+
636+
unlock:
637+
mutex_unlock(&cpufreq_governor_mutex);
638+
639+
return t;
640+
}
641+
624642
static unsigned int cpufreq_parse_policy(char *str_governor)
625643
{
626644
if (!strncasecmp(str_governor, "performance", CPUFREQ_NAME_LEN))
@@ -640,28 +658,14 @@ static struct cpufreq_governor *cpufreq_parse_governor(char *str_governor)
640658
{
641659
struct cpufreq_governor *t;
642660

643-
mutex_lock(&cpufreq_governor_mutex);
644-
645-
t = find_governor(str_governor);
646-
if (!t) {
647-
int ret;
648-
649-
mutex_unlock(&cpufreq_governor_mutex);
650-
651-
ret = request_module("cpufreq_%s", str_governor);
652-
if (ret)
653-
return NULL;
654-
655-
mutex_lock(&cpufreq_governor_mutex);
661+
t = get_governor(str_governor);
662+
if (t)
663+
return t;
656664

657-
t = find_governor(str_governor);
658-
}
659-
if (t && !try_module_get(t->owner))
660-
t = NULL;
661-
662-
mutex_unlock(&cpufreq_governor_mutex);
665+
if (request_module("cpufreq_%s", str_governor))
666+
return NULL;
663667

664-
return t;
668+
return get_governor(str_governor);
665669
}
666670

667671
/**
@@ -815,12 +819,14 @@ static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy,
815819
goto out;
816820
}
817821

822+
mutex_lock(&cpufreq_governor_mutex);
818823
for_each_governor(t) {
819824
if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char))
820825
- (CPUFREQ_NAME_LEN + 2)))
821-
goto out;
826+
break;
822827
i += scnprintf(&buf[i], CPUFREQ_NAME_PLEN, "%s ", t->name);
823828
}
829+
mutex_unlock(&cpufreq_governor_mutex);
824830
out:
825831
i += sprintf(&buf[i], "\n");
826832
return i;
@@ -1058,15 +1064,17 @@ static int cpufreq_init_policy(struct cpufreq_policy *policy)
10581064
struct cpufreq_governor *def_gov = cpufreq_default_governor();
10591065
struct cpufreq_governor *gov = NULL;
10601066
unsigned int pol = CPUFREQ_POLICY_UNKNOWN;
1067+
int ret;
10611068

10621069
if (has_target()) {
10631070
/* Update policy governor to the one used before hotplug. */
1064-
gov = find_governor(policy->last_governor);
1071+
gov = get_governor(policy->last_governor);
10651072
if (gov) {
10661073
pr_debug("Restoring governor %s for cpu %d\n",
10671074
policy->governor->name, policy->cpu);
10681075
} else if (def_gov) {
10691076
gov = def_gov;
1077+
__module_get(gov->owner);
10701078
} else {
10711079
return -ENODATA;
10721080
}
@@ -1089,7 +1097,11 @@ static int cpufreq_init_policy(struct cpufreq_policy *policy)
10891097
return -ENODATA;
10901098
}
10911099

1092-
return cpufreq_set_policy(policy, gov, pol);
1100+
ret = cpufreq_set_policy(policy, gov, pol);
1101+
if (gov)
1102+
module_put(gov->owner);
1103+
1104+
return ret;
10931105
}
10941106

10951107
static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)

0 commit comments

Comments
 (0)