From f67dcbea7f75a70601ac408416e572eac3f7d272 Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Thu, 22 Dec 2016 19:21:42 +0530 Subject: sched: Fix deadlock between cpu hotplug and upmigrate change There is a circular dependency between cpu_hotplug.lock and HMP scheduler policy mutex. Prevent this by enforcing the same lock order. Here CPU0 and CPU4 are governed by different cpufreq policies. ---------------- -------------------- CPU 0 CPU 4 --------------- -------------------- proc_sys_call_handler() cpu_up() --> acquired cpu_hotplug.lock sched_hmp_proc_update_handler() cpufreq_cpu_callback() --> acquired policy_mutex cpufreq_governor_interactive() get_online_cpus() sched_set_window() --> waiting for cpu_hotplug.lock --> waiting for policy_mutex Change-Id: I39efc394f4f00815b72adc975021fdb16fe6e30a Signed-off-by: Pavankumar Kondeti --- kernel/sched/hmp.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'kernel') diff --git a/kernel/sched/hmp.c b/kernel/sched/hmp.c index a8bf39c6d7d7..ab5587309760 100644 --- a/kernel/sched/hmp.c +++ b/kernel/sched/hmp.c @@ -1470,7 +1470,20 @@ int sched_hmp_proc_update_handler(struct ctl_table *table, int write, int ret; unsigned int old_val; unsigned int *data = (unsigned int *)table->data; - int update_min_nice = 0; + int update_task_count = 0; + + if (!sched_enable_hmp) + return 0; + + /* + * The policy mutex is acquired with cpu_hotplug.lock + * held from cpu_up()->cpufreq_governor_interactive()-> + * sched_set_window(). So enforce the same order here. + */ + if (write && (data == &sysctl_sched_upmigrate_pct)) { + update_task_count = 1; + get_online_cpus(); + } mutex_lock(&policy_mutex); @@ -1478,7 +1491,7 @@ int sched_hmp_proc_update_handler(struct ctl_table *table, int write, ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); - if (ret || !write || !sched_enable_hmp) + if (ret || !write) goto done; if (write && (old_val == *data)) @@ -1500,20 +1513,18 @@ int sched_hmp_proc_update_handler(struct ctl_table *table, int write, * includes taking runqueue lock of all online cpus and re-initiatizing * their big counter values based on changed criteria. */ - if ((data == &sysctl_sched_upmigrate_pct || update_min_nice)) { - get_online_cpus(); + if (update_task_count) pre_big_task_count_change(cpu_online_mask); - } set_hmp_defaults(); - if ((data == &sysctl_sched_upmigrate_pct || update_min_nice)) { + if (update_task_count) post_big_task_count_change(cpu_online_mask); - put_online_cpus(); - } done: mutex_unlock(&policy_mutex); + if (update_task_count) + put_online_cpus(); return ret; } -- cgit v1.2.3