diff options
Diffstat (limited to 'kernel/cpu.c')
| -rw-r--r-- | kernel/cpu.c | 38 |
1 files changed, 36 insertions, 2 deletions
diff --git a/kernel/cpu.c b/kernel/cpu.c index deff2e693766..a9e710eef0e2 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/mutex.h> | 19 | #include <linux/mutex.h> |
| 20 | #include <linux/gfp.h> | 20 | #include <linux/gfp.h> |
| 21 | #include <linux/suspend.h> | 21 | #include <linux/suspend.h> |
| 22 | #include <linux/lockdep.h> | ||
| 22 | 23 | ||
| 23 | #include "smpboot.h" | 24 | #include "smpboot.h" |
| 24 | 25 | ||
| @@ -27,18 +28,23 @@ | |||
| 27 | static DEFINE_MUTEX(cpu_add_remove_lock); | 28 | static DEFINE_MUTEX(cpu_add_remove_lock); |
| 28 | 29 | ||
| 29 | /* | 30 | /* |
| 30 | * The following two API's must be used when attempting | 31 | * The following two APIs (cpu_maps_update_begin/done) must be used when |
| 31 | * to serialize the updates to cpu_online_mask, cpu_present_mask. | 32 | * attempting to serialize the updates to cpu_online_mask & cpu_present_mask. |
| 33 | * The APIs cpu_notifier_register_begin/done() must be used to protect CPU | ||
| 34 | * hotplug callback (un)registration performed using __register_cpu_notifier() | ||
| 35 | * or __unregister_cpu_notifier(). | ||
| 32 | */ | 36 | */ |
| 33 | void cpu_maps_update_begin(void) | 37 | void cpu_maps_update_begin(void) |
| 34 | { | 38 | { |
| 35 | mutex_lock(&cpu_add_remove_lock); | 39 | mutex_lock(&cpu_add_remove_lock); |
| 36 | } | 40 | } |
| 41 | EXPORT_SYMBOL(cpu_notifier_register_begin); | ||
| 37 | 42 | ||
| 38 | void cpu_maps_update_done(void) | 43 | void cpu_maps_update_done(void) |
| 39 | { | 44 | { |
| 40 | mutex_unlock(&cpu_add_remove_lock); | 45 | mutex_unlock(&cpu_add_remove_lock); |
| 41 | } | 46 | } |
| 47 | EXPORT_SYMBOL(cpu_notifier_register_done); | ||
| 42 | 48 | ||
| 43 | static RAW_NOTIFIER_HEAD(cpu_chain); | 49 | static RAW_NOTIFIER_HEAD(cpu_chain); |
| 44 | 50 | ||
| @@ -57,17 +63,30 @@ static struct { | |||
| 57 | * an ongoing cpu hotplug operation. | 63 | * an ongoing cpu hotplug operation. |
| 58 | */ | 64 | */ |
| 59 | int refcount; | 65 | int refcount; |
| 66 | |||
| 67 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
| 68 | struct lockdep_map dep_map; | ||
| 69 | #endif | ||
| 60 | } cpu_hotplug = { | 70 | } cpu_hotplug = { |
| 61 | .active_writer = NULL, | 71 | .active_writer = NULL, |
| 62 | .lock = __MUTEX_INITIALIZER(cpu_hotplug.lock), | 72 | .lock = __MUTEX_INITIALIZER(cpu_hotplug.lock), |
| 63 | .refcount = 0, | 73 | .refcount = 0, |
| 74 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
| 75 | .dep_map = {.name = "cpu_hotplug.lock" }, | ||
| 76 | #endif | ||
| 64 | }; | 77 | }; |
| 65 | 78 | ||
| 79 | /* Lockdep annotations for get/put_online_cpus() and cpu_hotplug_begin/end() */ | ||
| 80 | #define cpuhp_lock_acquire_read() lock_map_acquire_read(&cpu_hotplug.dep_map) | ||
| 81 | #define cpuhp_lock_acquire() lock_map_acquire(&cpu_hotplug.dep_map) | ||
| 82 | #define cpuhp_lock_release() lock_map_release(&cpu_hotplug.dep_map) | ||
| 83 | |||
| 66 | void get_online_cpus(void) | 84 | void get_online_cpus(void) |
| 67 | { | 85 | { |
| 68 | might_sleep(); | 86 | might_sleep(); |
| 69 | if (cpu_hotplug.active_writer == current) | 87 | if (cpu_hotplug.active_writer == current) |
| 70 | return; | 88 | return; |
| 89 | cpuhp_lock_acquire_read(); | ||
| 71 | mutex_lock(&cpu_hotplug.lock); | 90 | mutex_lock(&cpu_hotplug.lock); |
| 72 | cpu_hotplug.refcount++; | 91 | cpu_hotplug.refcount++; |
| 73 | mutex_unlock(&cpu_hotplug.lock); | 92 | mutex_unlock(&cpu_hotplug.lock); |
| @@ -87,6 +106,7 @@ void put_online_cpus(void) | |||
| 87 | if (!--cpu_hotplug.refcount && unlikely(cpu_hotplug.active_writer)) | 106 | if (!--cpu_hotplug.refcount && unlikely(cpu_hotplug.active_writer)) |
| 88 | wake_up_process(cpu_hotplug.active_writer); | 107 | wake_up_process(cpu_hotplug.active_writer); |
| 89 | mutex_unlock(&cpu_hotplug.lock); | 108 | mutex_unlock(&cpu_hotplug.lock); |
| 109 | cpuhp_lock_release(); | ||
| 90 | 110 | ||
| 91 | } | 111 | } |
| 92 | EXPORT_SYMBOL_GPL(put_online_cpus); | 112 | EXPORT_SYMBOL_GPL(put_online_cpus); |
| @@ -117,6 +137,7 @@ void cpu_hotplug_begin(void) | |||
| 117 | { | 137 | { |
| 118 | cpu_hotplug.active_writer = current; | 138 | cpu_hotplug.active_writer = current; |
| 119 | 139 | ||
| 140 | cpuhp_lock_acquire(); | ||
| 120 | for (;;) { | 141 | for (;;) { |
| 121 | mutex_lock(&cpu_hotplug.lock); | 142 | mutex_lock(&cpu_hotplug.lock); |
| 122 | if (likely(!cpu_hotplug.refcount)) | 143 | if (likely(!cpu_hotplug.refcount)) |
| @@ -131,6 +152,7 @@ void cpu_hotplug_done(void) | |||
| 131 | { | 152 | { |
| 132 | cpu_hotplug.active_writer = NULL; | 153 | cpu_hotplug.active_writer = NULL; |
| 133 | mutex_unlock(&cpu_hotplug.lock); | 154 | mutex_unlock(&cpu_hotplug.lock); |
| 155 | cpuhp_lock_release(); | ||
| 134 | } | 156 | } |
| 135 | 157 | ||
| 136 | /* | 158 | /* |
| @@ -166,6 +188,11 @@ int __ref register_cpu_notifier(struct notifier_block *nb) | |||
| 166 | return ret; | 188 | return ret; |
| 167 | } | 189 | } |
| 168 | 190 | ||
| 191 | int __ref __register_cpu_notifier(struct notifier_block *nb) | ||
| 192 | { | ||
| 193 | return raw_notifier_chain_register(&cpu_chain, nb); | ||
| 194 | } | ||
| 195 | |||
| 169 | static int __cpu_notify(unsigned long val, void *v, int nr_to_call, | 196 | static int __cpu_notify(unsigned long val, void *v, int nr_to_call, |
| 170 | int *nr_calls) | 197 | int *nr_calls) |
| 171 | { | 198 | { |
| @@ -189,6 +216,7 @@ static void cpu_notify_nofail(unsigned long val, void *v) | |||
| 189 | BUG_ON(cpu_notify(val, v)); | 216 | BUG_ON(cpu_notify(val, v)); |
| 190 | } | 217 | } |
| 191 | EXPORT_SYMBOL(register_cpu_notifier); | 218 | EXPORT_SYMBOL(register_cpu_notifier); |
| 219 | EXPORT_SYMBOL(__register_cpu_notifier); | ||
| 192 | 220 | ||
| 193 | void __ref unregister_cpu_notifier(struct notifier_block *nb) | 221 | void __ref unregister_cpu_notifier(struct notifier_block *nb) |
| 194 | { | 222 | { |
| @@ -198,6 +226,12 @@ void __ref unregister_cpu_notifier(struct notifier_block *nb) | |||
| 198 | } | 226 | } |
| 199 | EXPORT_SYMBOL(unregister_cpu_notifier); | 227 | EXPORT_SYMBOL(unregister_cpu_notifier); |
| 200 | 228 | ||
| 229 | void __ref __unregister_cpu_notifier(struct notifier_block *nb) | ||
| 230 | { | ||
| 231 | raw_notifier_chain_unregister(&cpu_chain, nb); | ||
| 232 | } | ||
| 233 | EXPORT_SYMBOL(__unregister_cpu_notifier); | ||
| 234 | |||
| 201 | /** | 235 | /** |
| 202 | * clear_tasks_mm_cpumask - Safely clear tasks' mm_cpumask for a CPU | 236 | * clear_tasks_mm_cpumask - Safely clear tasks' mm_cpumask for a CPU |
| 203 | * @cpu: a CPU id | 237 | * @cpu: a CPU id |
