diff options
-rw-r--r-- | include/linux/cpu.h | 6 | ||||
-rw-r--r-- | kernel/cpu.c | 75 |
2 files changed, 34 insertions, 47 deletions
diff --git a/include/linux/cpu.h b/include/linux/cpu.h index 44a11f1ccaf2..8fb344a9abd8 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h | |||
@@ -48,7 +48,6 @@ static inline void unregister_cpu_notifier(struct notifier_block *nb) | |||
48 | { | 48 | { |
49 | } | 49 | } |
50 | #endif | 50 | #endif |
51 | extern int current_in_cpu_hotplug(void); | ||
52 | 51 | ||
53 | int cpu_up(unsigned int cpu); | 52 | int cpu_up(unsigned int cpu); |
54 | 53 | ||
@@ -61,10 +60,6 @@ static inline int register_cpu_notifier(struct notifier_block *nb) | |||
61 | static inline void unregister_cpu_notifier(struct notifier_block *nb) | 60 | static inline void unregister_cpu_notifier(struct notifier_block *nb) |
62 | { | 61 | { |
63 | } | 62 | } |
64 | static inline int current_in_cpu_hotplug(void) | ||
65 | { | ||
66 | return 0; | ||
67 | } | ||
68 | 63 | ||
69 | #endif /* CONFIG_SMP */ | 64 | #endif /* CONFIG_SMP */ |
70 | extern struct sysdev_class cpu_sysdev_class; | 65 | extern struct sysdev_class cpu_sysdev_class; |
@@ -73,7 +68,6 @@ extern struct sysdev_class cpu_sysdev_class; | |||
73 | /* Stop CPUs going up and down. */ | 68 | /* Stop CPUs going up and down. */ |
74 | extern void lock_cpu_hotplug(void); | 69 | extern void lock_cpu_hotplug(void); |
75 | extern void unlock_cpu_hotplug(void); | 70 | extern void unlock_cpu_hotplug(void); |
76 | extern int lock_cpu_hotplug_interruptible(void); | ||
77 | #define hotcpu_notifier(fn, pri) { \ | 71 | #define hotcpu_notifier(fn, pri) { \ |
78 | static struct notifier_block fn##_nb = \ | 72 | static struct notifier_block fn##_nb = \ |
79 | { .notifier_call = fn, .priority = pri }; \ | 73 | { .notifier_call = fn, .priority = pri }; \ |
diff --git a/kernel/cpu.c b/kernel/cpu.c index 70fbf2e83766..f230f9ae01c2 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c | |||
@@ -16,56 +16,48 @@ | |||
16 | #include <linux/mutex.h> | 16 | #include <linux/mutex.h> |
17 | 17 | ||
18 | /* This protects CPUs going up and down... */ | 18 | /* This protects CPUs going up and down... */ |
19 | static DEFINE_MUTEX(cpucontrol); | 19 | static DEFINE_MUTEX(cpu_add_remove_lock); |
20 | static DEFINE_MUTEX(cpu_bitmask_lock); | ||
20 | 21 | ||
21 | static __cpuinitdata BLOCKING_NOTIFIER_HEAD(cpu_chain); | 22 | static __cpuinitdata BLOCKING_NOTIFIER_HEAD(cpu_chain); |
22 | 23 | ||
23 | #ifdef CONFIG_HOTPLUG_CPU | 24 | #ifdef CONFIG_HOTPLUG_CPU |
24 | static struct task_struct *lock_cpu_hotplug_owner; | ||
25 | static int lock_cpu_hotplug_depth; | ||
26 | 25 | ||
27 | static int __lock_cpu_hotplug(int interruptible) | 26 | /* Crappy recursive lock-takers in cpufreq! Complain loudly about idiots */ |
28 | { | 27 | static struct task_struct *recursive; |
29 | int ret = 0; | 28 | static int recursive_depth; |
30 | |||
31 | if (lock_cpu_hotplug_owner != current) { | ||
32 | if (interruptible) | ||
33 | ret = mutex_lock_interruptible(&cpucontrol); | ||
34 | else | ||
35 | mutex_lock(&cpucontrol); | ||
36 | } | ||
37 | |||
38 | /* | ||
39 | * Set only if we succeed in locking | ||
40 | */ | ||
41 | if (!ret) { | ||
42 | lock_cpu_hotplug_depth++; | ||
43 | lock_cpu_hotplug_owner = current; | ||
44 | } | ||
45 | |||
46 | return ret; | ||
47 | } | ||
48 | 29 | ||
49 | void lock_cpu_hotplug(void) | 30 | void lock_cpu_hotplug(void) |
50 | { | 31 | { |
51 | __lock_cpu_hotplug(0); | 32 | struct task_struct *tsk = current; |
33 | |||
34 | if (tsk == recursive) { | ||
35 | static int warnings = 10; | ||
36 | if (warnings) { | ||
37 | printk(KERN_ERR "Lukewarm IQ detected in hotplug locking\n"); | ||
38 | WARN_ON(1); | ||
39 | warnings--; | ||
40 | } | ||
41 | recursive_depth++; | ||
42 | return; | ||
43 | } | ||
44 | mutex_lock(&cpu_bitmask_lock); | ||
45 | recursive = tsk; | ||
52 | } | 46 | } |
53 | EXPORT_SYMBOL_GPL(lock_cpu_hotplug); | 47 | EXPORT_SYMBOL_GPL(lock_cpu_hotplug); |
54 | 48 | ||
55 | void unlock_cpu_hotplug(void) | 49 | void unlock_cpu_hotplug(void) |
56 | { | 50 | { |
57 | if (--lock_cpu_hotplug_depth == 0) { | 51 | WARN_ON(recursive != current); |
58 | lock_cpu_hotplug_owner = NULL; | 52 | if (recursive_depth) { |
59 | mutex_unlock(&cpucontrol); | 53 | recursive_depth--; |
54 | return; | ||
60 | } | 55 | } |
56 | mutex_unlock(&cpu_bitmask_lock); | ||
57 | recursive = NULL; | ||
61 | } | 58 | } |
62 | EXPORT_SYMBOL_GPL(unlock_cpu_hotplug); | 59 | EXPORT_SYMBOL_GPL(unlock_cpu_hotplug); |
63 | 60 | ||
64 | int lock_cpu_hotplug_interruptible(void) | ||
65 | { | ||
66 | return __lock_cpu_hotplug(1); | ||
67 | } | ||
68 | EXPORT_SYMBOL_GPL(lock_cpu_hotplug_interruptible); | ||
69 | #endif /* CONFIG_HOTPLUG_CPU */ | 61 | #endif /* CONFIG_HOTPLUG_CPU */ |
70 | 62 | ||
71 | /* Need to know about CPUs going up/down? */ | 63 | /* Need to know about CPUs going up/down? */ |
@@ -122,9 +114,7 @@ int cpu_down(unsigned int cpu) | |||
122 | struct task_struct *p; | 114 | struct task_struct *p; |
123 | cpumask_t old_allowed, tmp; | 115 | cpumask_t old_allowed, tmp; |
124 | 116 | ||
125 | if ((err = lock_cpu_hotplug_interruptible()) != 0) | 117 | mutex_lock(&cpu_add_remove_lock); |
126 | return err; | ||
127 | |||
128 | if (num_online_cpus() == 1) { | 118 | if (num_online_cpus() == 1) { |
129 | err = -EBUSY; | 119 | err = -EBUSY; |
130 | goto out; | 120 | goto out; |
@@ -150,7 +140,10 @@ int cpu_down(unsigned int cpu) | |||
150 | cpu_clear(cpu, tmp); | 140 | cpu_clear(cpu, tmp); |
151 | set_cpus_allowed(current, tmp); | 141 | set_cpus_allowed(current, tmp); |
152 | 142 | ||
143 | mutex_lock(&cpu_bitmask_lock); | ||
153 | p = __stop_machine_run(take_cpu_down, NULL, cpu); | 144 | p = __stop_machine_run(take_cpu_down, NULL, cpu); |
145 | mutex_unlock(&cpu_bitmask_lock); | ||
146 | |||
154 | if (IS_ERR(p)) { | 147 | if (IS_ERR(p)) { |
155 | /* CPU didn't die: tell everyone. Can't complain. */ | 148 | /* CPU didn't die: tell everyone. Can't complain. */ |
156 | if (blocking_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED, | 149 | if (blocking_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED, |
@@ -187,7 +180,7 @@ out_thread: | |||
187 | out_allowed: | 180 | out_allowed: |
188 | set_cpus_allowed(current, old_allowed); | 181 | set_cpus_allowed(current, old_allowed); |
189 | out: | 182 | out: |
190 | unlock_cpu_hotplug(); | 183 | mutex_unlock(&cpu_add_remove_lock); |
191 | return err; | 184 | return err; |
192 | } | 185 | } |
193 | #endif /*CONFIG_HOTPLUG_CPU*/ | 186 | #endif /*CONFIG_HOTPLUG_CPU*/ |
@@ -197,9 +190,7 @@ int __devinit cpu_up(unsigned int cpu) | |||
197 | int ret; | 190 | int ret; |
198 | void *hcpu = (void *)(long)cpu; | 191 | void *hcpu = (void *)(long)cpu; |
199 | 192 | ||
200 | if ((ret = lock_cpu_hotplug_interruptible()) != 0) | 193 | mutex_lock(&cpu_add_remove_lock); |
201 | return ret; | ||
202 | |||
203 | if (cpu_online(cpu) || !cpu_present(cpu)) { | 194 | if (cpu_online(cpu) || !cpu_present(cpu)) { |
204 | ret = -EINVAL; | 195 | ret = -EINVAL; |
205 | goto out; | 196 | goto out; |
@@ -214,7 +205,9 @@ int __devinit cpu_up(unsigned int cpu) | |||
214 | } | 205 | } |
215 | 206 | ||
216 | /* Arch-specific enabling code. */ | 207 | /* Arch-specific enabling code. */ |
208 | mutex_lock(&cpu_bitmask_lock); | ||
217 | ret = __cpu_up(cpu); | 209 | ret = __cpu_up(cpu); |
210 | mutex_unlock(&cpu_bitmask_lock); | ||
218 | if (ret != 0) | 211 | if (ret != 0) |
219 | goto out_notify; | 212 | goto out_notify; |
220 | BUG_ON(!cpu_online(cpu)); | 213 | BUG_ON(!cpu_online(cpu)); |
@@ -227,6 +220,6 @@ out_notify: | |||
227 | blocking_notifier_call_chain(&cpu_chain, | 220 | blocking_notifier_call_chain(&cpu_chain, |
228 | CPU_UP_CANCELED, hcpu); | 221 | CPU_UP_CANCELED, hcpu); |
229 | out: | 222 | out: |
230 | unlock_cpu_hotplug(); | 223 | mutex_unlock(&cpu_add_remove_lock); |
231 | return ret; | 224 | return ret; |
232 | } | 225 | } |