diff options
author | Silas Boyd-Wickizer <sbw@mit.edu> | 2012-09-23 14:27:32 -0400 |
---|---|---|
committer | Jean Delvare <khali@endymion.delvare> | 2012-09-23 14:27:32 -0400 |
commit | 641f14560035bbb86500ea4b3a27ad27f034725b (patch) | |
tree | acf190876e015304f959294c37b302e904380baa | |
parent | 1ec3ddfd27a77db55b8c0e80bcd27c656473fb96 (diff) |
hwmon: (coretemp) Use get_online_cpus to avoid races involving CPU hotplug
coretemp_init loops with for_each_online_cpu, adding platform_devices
and sysfs interfaces, then calls register_hotcpu_notifier. There is a
race if a CPU is offlined or onlined after the loop, but before
register_hotcpu_notifier. The race might result in the absence of a
platform_device+sysfs interface for an online CPU, or the presence of
a platform_device+sysfs interface for an offline CPU. A similar race
occurs during coretemp_exit, after the module calls
unregister_hotcpu_notifier, but before it unregisters all devices, a
CPU might offline and a device for an offline CPU will exist for a
short while.
This fix surrounds for_each_online_cpu and register_hotcpu_notifier
with get_online_cpus+put_online_cpus; and surrounds
unregister_hotcpu_notifier and device unregistering with
get_online_cpus+put_online_cpus.
Build tested.
Signed-off-by: Silas Boyd-Wickizer <sbw@mit.edu>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
-rw-r--r-- | drivers/hwmon/coretemp.c | 5 |
1 files changed, 5 insertions, 0 deletions
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 0fa356fe82cc..984a3f13923b 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c | |||
@@ -815,17 +815,20 @@ static int __init coretemp_init(void) | |||
815 | if (err) | 815 | if (err) |
816 | goto exit; | 816 | goto exit; |
817 | 817 | ||
818 | get_online_cpus(); | ||
818 | for_each_online_cpu(i) | 819 | for_each_online_cpu(i) |
819 | get_core_online(i); | 820 | get_core_online(i); |
820 | 821 | ||
821 | #ifndef CONFIG_HOTPLUG_CPU | 822 | #ifndef CONFIG_HOTPLUG_CPU |
822 | if (list_empty(&pdev_list)) { | 823 | if (list_empty(&pdev_list)) { |
824 | put_online_cpus(); | ||
823 | err = -ENODEV; | 825 | err = -ENODEV; |
824 | goto exit_driver_unreg; | 826 | goto exit_driver_unreg; |
825 | } | 827 | } |
826 | #endif | 828 | #endif |
827 | 829 | ||
828 | register_hotcpu_notifier(&coretemp_cpu_notifier); | 830 | register_hotcpu_notifier(&coretemp_cpu_notifier); |
831 | put_online_cpus(); | ||
829 | return 0; | 832 | return 0; |
830 | 833 | ||
831 | #ifndef CONFIG_HOTPLUG_CPU | 834 | #ifndef CONFIG_HOTPLUG_CPU |
@@ -840,6 +843,7 @@ static void __exit coretemp_exit(void) | |||
840 | { | 843 | { |
841 | struct pdev_entry *p, *n; | 844 | struct pdev_entry *p, *n; |
842 | 845 | ||
846 | get_online_cpus(); | ||
843 | unregister_hotcpu_notifier(&coretemp_cpu_notifier); | 847 | unregister_hotcpu_notifier(&coretemp_cpu_notifier); |
844 | mutex_lock(&pdev_list_mutex); | 848 | mutex_lock(&pdev_list_mutex); |
845 | list_for_each_entry_safe(p, n, &pdev_list, list) { | 849 | list_for_each_entry_safe(p, n, &pdev_list, list) { |
@@ -848,6 +852,7 @@ static void __exit coretemp_exit(void) | |||
848 | kfree(p); | 852 | kfree(p); |
849 | } | 853 | } |
850 | mutex_unlock(&pdev_list_mutex); | 854 | mutex_unlock(&pdev_list_mutex); |
855 | put_online_cpus(); | ||
851 | platform_driver_unregister(&coretemp_driver); | 856 | platform_driver_unregister(&coretemp_driver); |
852 | } | 857 | } |
853 | 858 | ||