aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Wilcox <mawilcox@microsoft.com>2017-03-10 13:33:28 -0500
committerZhang Rui <rui.zhang@intel.com>2017-03-12 22:06:04 -0400
commit088db931e065bd3b159fa2e588eab859ef0d9d23 (patch)
tree7211f7bc220cfc430e37dc4fa37dec978efbe0f7
parent4495c08e84729385774601b5146d51d9e5849f81 (diff)
thermal: Fix potential deadlock in cpu_cooling
cooling_list_lock is covering not just cpufreq_dev_count, but also the calls to cpufreq_register_notifier() and cpufreq_unregister_notifier(). Since cooling_list_lock is also used within cpufreq_thermal_notifier(), lockdep reports a potential deadlock. Fix it by testing the condition under cooling_list_lock and dropping the lock before calling cpufreq_register_notifier(). And variable cpufreq_dev_count is removed at the same time, because it's no longer needed after the fix. Fixes: ae606089621e ("thermal: convert cpu_cooling to use an IDA") Reported-and-Tested-by: Russell King <linux@armlinux.org.uk> Signed-off-by: Matthew Wilcox <mawilcox@microsoft.com> Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com Signed-off-by: Zhang Rui <rui.zhang@intel.com>
-rw-r--r--drivers/thermal/cpu_cooling.c20
1 files changed, 11 insertions, 9 deletions
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index 91048eeca28b..11b5ea685518 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -107,8 +107,6 @@ struct cpufreq_cooling_device {
107}; 107};
108static DEFINE_IDA(cpufreq_ida); 108static DEFINE_IDA(cpufreq_ida);
109 109
110static unsigned int cpufreq_dev_count;
111
112static DEFINE_MUTEX(cooling_list_lock); 110static DEFINE_MUTEX(cooling_list_lock);
113static LIST_HEAD(cpufreq_dev_list); 111static LIST_HEAD(cpufreq_dev_list);
114 112
@@ -771,6 +769,7 @@ __cpufreq_cooling_register(struct device_node *np,
771 unsigned int freq, i, num_cpus; 769 unsigned int freq, i, num_cpus;
772 int ret; 770 int ret;
773 struct thermal_cooling_device_ops *cooling_ops; 771 struct thermal_cooling_device_ops *cooling_ops;
772 bool first;
774 773
775 if (!alloc_cpumask_var(&temp_mask, GFP_KERNEL)) 774 if (!alloc_cpumask_var(&temp_mask, GFP_KERNEL))
776 return ERR_PTR(-ENOMEM); 775 return ERR_PTR(-ENOMEM);
@@ -874,13 +873,14 @@ __cpufreq_cooling_register(struct device_node *np,
874 cpufreq_dev->cool_dev = cool_dev; 873 cpufreq_dev->cool_dev = cool_dev;
875 874
876 mutex_lock(&cooling_list_lock); 875 mutex_lock(&cooling_list_lock);
876 /* Register the notifier for first cpufreq cooling device */
877 first = list_empty(&cpufreq_dev_list);
877 list_add(&cpufreq_dev->node, &cpufreq_dev_list); 878 list_add(&cpufreq_dev->node, &cpufreq_dev_list);
879 mutex_unlock(&cooling_list_lock);
878 880
879 /* Register the notifier for first cpufreq cooling device */ 881 if (first)
880 if (!cpufreq_dev_count++)
881 cpufreq_register_notifier(&thermal_cpufreq_notifier_block, 882 cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
882 CPUFREQ_POLICY_NOTIFIER); 883 CPUFREQ_POLICY_NOTIFIER);
883 mutex_unlock(&cooling_list_lock);
884 884
885 goto put_policy; 885 goto put_policy;
886 886
@@ -1021,6 +1021,7 @@ EXPORT_SYMBOL(of_cpufreq_power_cooling_register);
1021void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) 1021void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
1022{ 1022{
1023 struct cpufreq_cooling_device *cpufreq_dev; 1023 struct cpufreq_cooling_device *cpufreq_dev;
1024 bool last;
1024 1025
1025 if (!cdev) 1026 if (!cdev)
1026 return; 1027 return;
@@ -1028,14 +1029,15 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
1028 cpufreq_dev = cdev->devdata; 1029 cpufreq_dev = cdev->devdata;
1029 1030
1030 mutex_lock(&cooling_list_lock); 1031 mutex_lock(&cooling_list_lock);
1032 list_del(&cpufreq_dev->node);
1031 /* Unregister the notifier for the last cpufreq cooling device */ 1033 /* Unregister the notifier for the last cpufreq cooling device */
1032 if (!--cpufreq_dev_count) 1034 last = list_empty(&cpufreq_dev_list);
1035 mutex_unlock(&cooling_list_lock);
1036
1037 if (last)
1033 cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block, 1038 cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
1034 CPUFREQ_POLICY_NOTIFIER); 1039 CPUFREQ_POLICY_NOTIFIER);
1035 1040
1036 list_del(&cpufreq_dev->node);
1037 mutex_unlock(&cooling_list_lock);
1038
1039 thermal_cooling_device_unregister(cpufreq_dev->cool_dev); 1041 thermal_cooling_device_unregister(cpufreq_dev->cool_dev);
1040 ida_simple_remove(&cpufreq_ida, cpufreq_dev->id); 1042 ida_simple_remove(&cpufreq_ida, cpufreq_dev->id);
1041 kfree(cpufreq_dev->dyn_power_table); 1043 kfree(cpufreq_dev->dyn_power_table);