cpufreq: Register for hotplug notifier before locking hotplug
If a CPU hotplug operation occurs in parallel while a driver is registering with the cpufreq framework it can lead to the following deadlock scenario: Thread A (cpufreq_register_driver()) Thread B (cpu_down()) get_online_cpus() | atomic_inc(&cpu_hotplug.refcount) cpu_down() | mutex_lock(&cpu_add_remove_lock) | cpu_hotplug_begin() waits on cpu_hotplug.refcount to reset register_cpu_notifier() | mutex_lock(&cpu_add_remove_lock) This happens because the registration for hotplug notifiers happens inside the hotplug locked section. This change moves hotplug registration call before get_online_cpus() to avoid the deadlock. Change-Id: Ia59a3e2710133d3b3608e49938e746e58af5a6d4 Signed-off-by: Rohit Gupta <rohgup@codeaurora.org>
This commit is contained in:
parent
a80e267a8c
commit
d36dd7737c
1 changed files with 6 additions and 1 deletions
|
@ -2269,6 +2269,9 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
|
||||||
{
|
{
|
||||||
unsigned int cpu = (unsigned long)hcpu;
|
unsigned int cpu = (unsigned long)hcpu;
|
||||||
|
|
||||||
|
if (!cpufreq_driver)
|
||||||
|
return NOTIFY_OK;
|
||||||
|
|
||||||
switch (action & ~CPU_TASKS_FROZEN) {
|
switch (action & ~CPU_TASKS_FROZEN) {
|
||||||
case CPU_ONLINE:
|
case CPU_ONLINE:
|
||||||
cpufreq_online(cpu);
|
cpufreq_online(cpu);
|
||||||
|
@ -2435,6 +2438,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
|
||||||
|
|
||||||
pr_debug("trying to register driver %s\n", driver_data->name);
|
pr_debug("trying to register driver %s\n", driver_data->name);
|
||||||
|
|
||||||
|
/* Register for hotplug notifers before blocking hotplug. */
|
||||||
|
register_hotcpu_notifier(&cpufreq_cpu_notifier);
|
||||||
|
|
||||||
/* Protect against concurrent CPU online/offline. */
|
/* Protect against concurrent CPU online/offline. */
|
||||||
get_online_cpus();
|
get_online_cpus();
|
||||||
|
|
||||||
|
@ -2466,7 +2472,6 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
|
||||||
goto err_if_unreg;
|
goto err_if_unreg;
|
||||||
}
|
}
|
||||||
|
|
||||||
register_hotcpu_notifier(&cpufreq_cpu_notifier);
|
|
||||||
pr_info("driver %s up and running\n", driver_data->name);
|
pr_info("driver %s up and running\n", driver_data->name);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
Loading…
Add table
Reference in a new issue