diff options
| author | Neil Brown <neilb@suse.de> | 2006-10-17 03:10:35 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-17 11:18:48 -0400 |
| commit | bd5349cfd2b9bbb10a3dbcd3fe5cbaabe0b2ab9e (patch) | |
| tree | 20a55c6592f0934d6dccebb7972d28d120b4badd /kernel | |
| parent | bea493a031fe3337f4fe5479e8e865513828ea76 (diff) | |
[PATCH] Convert cpu hotplug notifiers to use raw_notifier instead of blocking_notifier
The use of blocking notifier by _cpu_up and _cpu_down in cpu.c has two
problem.
1/ An interaction with the workqueue notifier causes lockdep to spit a
warning.
2/ A notifier could conceivable be added or removed while _cpu_up or
_cpu_down are in process. As each notifier is called twice (prepare
then commit/abort) this could be unhealthy.
To fix to we simply take cpu_add_remove_lock while adding or removing
notifiers to/from the list.
This makes the 'blocking' usage unnecessary as all accesses to cpu_chain
are now protected by cpu_add_remove_lock. So change "blocking" to "raw" in
all relevant places. This fixes 1.
Credit: Andrew Morton
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Michal Piotrowski <michal.k.k.piotrowski@gmail.com> (reporter)
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/cpu.c | 24 |
1 files changed, 15 insertions, 9 deletions
diff --git a/kernel/cpu.c b/kernel/cpu.c index 32c96628463e..27dd3ee47099 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c | |||
| @@ -19,7 +19,7 @@ | |||
| 19 | static DEFINE_MUTEX(cpu_add_remove_lock); | 19 | static DEFINE_MUTEX(cpu_add_remove_lock); |
| 20 | static DEFINE_MUTEX(cpu_bitmask_lock); | 20 | static DEFINE_MUTEX(cpu_bitmask_lock); |
| 21 | 21 | ||
| 22 | static __cpuinitdata BLOCKING_NOTIFIER_HEAD(cpu_chain); | 22 | static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain); |
| 23 | 23 | ||
| 24 | /* If set, cpu_up and cpu_down will return -EBUSY and do nothing. | 24 | /* If set, cpu_up and cpu_down will return -EBUSY and do nothing. |
| 25 | * Should always be manipulated under cpu_add_remove_lock | 25 | * Should always be manipulated under cpu_add_remove_lock |
| @@ -68,7 +68,11 @@ EXPORT_SYMBOL_GPL(unlock_cpu_hotplug); | |||
| 68 | /* Need to know about CPUs going up/down? */ | 68 | /* Need to know about CPUs going up/down? */ |
| 69 | int __cpuinit register_cpu_notifier(struct notifier_block *nb) | 69 | int __cpuinit register_cpu_notifier(struct notifier_block *nb) |
| 70 | { | 70 | { |
| 71 | return blocking_notifier_chain_register(&cpu_chain, nb); | 71 | int ret; |
| 72 | mutex_lock(&cpu_add_remove_lock); | ||
| 73 | ret = raw_notifier_chain_register(&cpu_chain, nb); | ||
| 74 | mutex_unlock(&cpu_add_remove_lock); | ||
| 75 | return ret; | ||
| 72 | } | 76 | } |
| 73 | 77 | ||
| 74 | #ifdef CONFIG_HOTPLUG_CPU | 78 | #ifdef CONFIG_HOTPLUG_CPU |
| @@ -77,7 +81,9 @@ EXPORT_SYMBOL(register_cpu_notifier); | |||
| 77 | 81 | ||
| 78 | void unregister_cpu_notifier(struct notifier_block *nb) | 82 | void unregister_cpu_notifier(struct notifier_block *nb) |
| 79 | { | 83 | { |
| 80 | blocking_notifier_chain_unregister(&cpu_chain, nb); | 84 | mutex_lock(&cpu_add_remove_lock); |
| 85 | raw_notifier_chain_unregister(&cpu_chain, nb); | ||
| 86 | mutex_unlock(&cpu_add_remove_lock); | ||
| 81 | } | 87 | } |
| 82 | EXPORT_SYMBOL(unregister_cpu_notifier); | 88 | EXPORT_SYMBOL(unregister_cpu_notifier); |
| 83 | 89 | ||
| @@ -126,7 +132,7 @@ static int _cpu_down(unsigned int cpu) | |||
| 126 | if (!cpu_online(cpu)) | 132 | if (!cpu_online(cpu)) |
| 127 | return -EINVAL; | 133 | return -EINVAL; |
| 128 | 134 | ||
| 129 | err = blocking_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE, | 135 | err = raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE, |
| 130 | (void *)(long)cpu); | 136 | (void *)(long)cpu); |
| 131 | if (err == NOTIFY_BAD) { | 137 | if (err == NOTIFY_BAD) { |
| 132 | printk("%s: attempt to take down CPU %u failed\n", | 138 | printk("%s: attempt to take down CPU %u failed\n", |
| @@ -146,7 +152,7 @@ static int _cpu_down(unsigned int cpu) | |||
| 146 | 152 | ||
| 147 | if (IS_ERR(p)) { | 153 | if (IS_ERR(p)) { |
| 148 | /* CPU didn't die: tell everyone. Can't complain. */ | 154 | /* CPU didn't die: tell everyone. Can't complain. */ |
| 149 | if (blocking_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED, | 155 | if (raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED, |
| 150 | (void *)(long)cpu) == NOTIFY_BAD) | 156 | (void *)(long)cpu) == NOTIFY_BAD) |
| 151 | BUG(); | 157 | BUG(); |
| 152 | 158 | ||
| @@ -169,7 +175,7 @@ static int _cpu_down(unsigned int cpu) | |||
| 169 | put_cpu(); | 175 | put_cpu(); |
| 170 | 176 | ||
| 171 | /* CPU is completely dead: tell everyone. Too late to complain. */ | 177 | /* CPU is completely dead: tell everyone. Too late to complain. */ |
| 172 | if (blocking_notifier_call_chain(&cpu_chain, CPU_DEAD, | 178 | if (raw_notifier_call_chain(&cpu_chain, CPU_DEAD, |
| 173 | (void *)(long)cpu) == NOTIFY_BAD) | 179 | (void *)(long)cpu) == NOTIFY_BAD) |
| 174 | BUG(); | 180 | BUG(); |
| 175 | 181 | ||
| @@ -206,7 +212,7 @@ static int __devinit _cpu_up(unsigned int cpu) | |||
| 206 | if (cpu_online(cpu) || !cpu_present(cpu)) | 212 | if (cpu_online(cpu) || !cpu_present(cpu)) |
| 207 | return -EINVAL; | 213 | return -EINVAL; |
| 208 | 214 | ||
| 209 | ret = blocking_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu); | 215 | ret = raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu); |
| 210 | if (ret == NOTIFY_BAD) { | 216 | if (ret == NOTIFY_BAD) { |
| 211 | printk("%s: attempt to bring up CPU %u failed\n", | 217 | printk("%s: attempt to bring up CPU %u failed\n", |
| 212 | __FUNCTION__, cpu); | 218 | __FUNCTION__, cpu); |
| @@ -223,11 +229,11 @@ static int __devinit _cpu_up(unsigned int cpu) | |||
| 223 | BUG_ON(!cpu_online(cpu)); | 229 | BUG_ON(!cpu_online(cpu)); |
| 224 | 230 | ||
| 225 | /* Now call notifier in preparation. */ | 231 | /* Now call notifier in preparation. */ |
| 226 | blocking_notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu); | 232 | raw_notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu); |
| 227 | 233 | ||
| 228 | out_notify: | 234 | out_notify: |
| 229 | if (ret != 0) | 235 | if (ret != 0) |
| 230 | blocking_notifier_call_chain(&cpu_chain, | 236 | raw_notifier_call_chain(&cpu_chain, |
| 231 | CPU_UP_CANCELED, hcpu); | 237 | CPU_UP_CANCELED, hcpu); |
| 232 | 238 | ||
| 233 | return ret; | 239 | return ret; |
