aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/cpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/cpu.c')
-rw-r--r--kernel/cpu.c170
1 files changed, 98 insertions, 72 deletions
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 1c8ddd6ee940..8b92539b4754 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -14,11 +14,26 @@
14#include <linux/kthread.h> 14#include <linux/kthread.h>
15#include <linux/stop_machine.h> 15#include <linux/stop_machine.h>
16#include <linux/mutex.h> 16#include <linux/mutex.h>
17#include <linux/gfp.h>
17 18
18#ifdef CONFIG_SMP 19#ifdef CONFIG_SMP
19/* Serializes the updates to cpu_online_mask, cpu_present_mask */ 20/* Serializes the updates to cpu_online_mask, cpu_present_mask */
20static DEFINE_MUTEX(cpu_add_remove_lock); 21static DEFINE_MUTEX(cpu_add_remove_lock);
21 22
23/*
24 * The following two API's must be used when attempting
25 * to serialize the updates to cpu_online_mask, cpu_present_mask.
26 */
27void cpu_maps_update_begin(void)
28{
29 mutex_lock(&cpu_add_remove_lock);
30}
31
32void cpu_maps_update_done(void)
33{
34 mutex_unlock(&cpu_add_remove_lock);
35}
36
22static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain); 37static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain);
23 38
24/* If set, cpu_up and cpu_down will return -EBUSY and do nothing. 39/* If set, cpu_up and cpu_down will return -EBUSY and do nothing.
@@ -26,6 +41,8 @@ static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain);
26 */ 41 */
27static int cpu_hotplug_disabled; 42static int cpu_hotplug_disabled;
28 43
44#ifdef CONFIG_HOTPLUG_CPU
45
29static struct { 46static struct {
30 struct task_struct *active_writer; 47 struct task_struct *active_writer;
31 struct mutex lock; /* Synchronizes accesses to refcount, */ 48 struct mutex lock; /* Synchronizes accesses to refcount, */
@@ -40,8 +57,6 @@ static struct {
40 .refcount = 0, 57 .refcount = 0,
41}; 58};
42 59
43#ifdef CONFIG_HOTPLUG_CPU
44
45void get_online_cpus(void) 60void get_online_cpus(void)
46{ 61{
47 might_sleep(); 62 might_sleep();
@@ -66,22 +81,6 @@ void put_online_cpus(void)
66} 81}
67EXPORT_SYMBOL_GPL(put_online_cpus); 82EXPORT_SYMBOL_GPL(put_online_cpus);
68 83
69#endif /* CONFIG_HOTPLUG_CPU */
70
71/*
72 * The following two API's must be used when attempting
73 * to serialize the updates to cpu_online_mask, cpu_present_mask.
74 */
75void cpu_maps_update_begin(void)
76{
77 mutex_lock(&cpu_add_remove_lock);
78}
79
80void cpu_maps_update_done(void)
81{
82 mutex_unlock(&cpu_add_remove_lock);
83}
84
85/* 84/*
86 * This ensures that the hotplug operation can begin only when the 85 * This ensures that the hotplug operation can begin only when the
87 * refcount goes to zero. 86 * refcount goes to zero.
@@ -123,6 +122,12 @@ static void cpu_hotplug_done(void)
123 cpu_hotplug.active_writer = NULL; 122 cpu_hotplug.active_writer = NULL;
124 mutex_unlock(&cpu_hotplug.lock); 123 mutex_unlock(&cpu_hotplug.lock);
125} 124}
125
126#else /* #if CONFIG_HOTPLUG_CPU */
127static void cpu_hotplug_begin(void) {}
128static void cpu_hotplug_done(void) {}
129#endif /* #esle #if CONFIG_HOTPLUG_CPU */
130
126/* Need to know about CPUs going up/down? */ 131/* Need to know about CPUs going up/down? */
127int __ref register_cpu_notifier(struct notifier_block *nb) 132int __ref register_cpu_notifier(struct notifier_block *nb)
128{ 133{
@@ -133,8 +138,29 @@ int __ref register_cpu_notifier(struct notifier_block *nb)
133 return ret; 138 return ret;
134} 139}
135 140
141static int __cpu_notify(unsigned long val, void *v, int nr_to_call,
142 int *nr_calls)
143{
144 int ret;
145
146 ret = __raw_notifier_call_chain(&cpu_chain, val, v, nr_to_call,
147 nr_calls);
148
149 return notifier_to_errno(ret);
150}
151
152static int cpu_notify(unsigned long val, void *v)
153{
154 return __cpu_notify(val, v, -1, NULL);
155}
156
136#ifdef CONFIG_HOTPLUG_CPU 157#ifdef CONFIG_HOTPLUG_CPU
137 158
159static void cpu_notify_nofail(unsigned long val, void *v)
160{
161 BUG_ON(cpu_notify(val, v));
162}
163
138EXPORT_SYMBOL(register_cpu_notifier); 164EXPORT_SYMBOL(register_cpu_notifier);
139 165
140void __ref unregister_cpu_notifier(struct notifier_block *nb) 166void __ref unregister_cpu_notifier(struct notifier_block *nb)
@@ -151,18 +177,19 @@ static inline void check_for_tasks(int cpu)
151 177
152 write_lock_irq(&tasklist_lock); 178 write_lock_irq(&tasklist_lock);
153 for_each_process(p) { 179 for_each_process(p) {
154 if (task_cpu(p) == cpu && 180 if (task_cpu(p) == cpu && p->state == TASK_RUNNING &&
155 (!cputime_eq(p->utime, cputime_zero) || 181 (!cputime_eq(p->utime, cputime_zero) ||
156 !cputime_eq(p->stime, cputime_zero))) 182 !cputime_eq(p->stime, cputime_zero)))
157 printk(KERN_WARNING "Task %s (pid = %d) is on cpu %d\ 183 printk(KERN_WARNING "Task %s (pid = %d) is on cpu %d "
158 (state = %ld, flags = %x) \n", 184 "(state = %ld, flags = %x)\n",
159 p->comm, task_pid_nr(p), cpu, 185 p->comm, task_pid_nr(p), cpu,
160 p->state, p->flags); 186 p->state, p->flags);
161 } 187 }
162 write_unlock_irq(&tasklist_lock); 188 write_unlock_irq(&tasklist_lock);
163} 189}
164 190
165struct take_cpu_down_param { 191struct take_cpu_down_param {
192 struct task_struct *caller;
166 unsigned long mod; 193 unsigned long mod;
167 void *hcpu; 194 void *hcpu;
168}; 195};
@@ -171,6 +198,7 @@ struct take_cpu_down_param {
171static int __ref take_cpu_down(void *_param) 198static int __ref take_cpu_down(void *_param)
172{ 199{
173 struct take_cpu_down_param *param = _param; 200 struct take_cpu_down_param *param = _param;
201 unsigned int cpu = (unsigned long)param->hcpu;
174 int err; 202 int err;
175 203
176 /* Ensure this CPU doesn't handle any more interrupts. */ 204 /* Ensure this CPU doesn't handle any more interrupts. */
@@ -178,9 +206,10 @@ static int __ref take_cpu_down(void *_param)
178 if (err < 0) 206 if (err < 0)
179 return err; 207 return err;
180 208
181 raw_notifier_call_chain(&cpu_chain, CPU_DYING | param->mod, 209 cpu_notify(CPU_DYING | param->mod, param->hcpu);
182 param->hcpu);
183 210
211 if (task_cpu(param->caller) == cpu)
212 move_task_off_dead_cpu(cpu, param->caller);
184 /* Force idle task to run as soon as we yield: it should 213 /* Force idle task to run as soon as we yield: it should
185 immediately notice cpu is offline and die quickly. */ 214 immediately notice cpu is offline and die quickly. */
186 sched_idle_next(); 215 sched_idle_next();
@@ -191,10 +220,10 @@ static int __ref take_cpu_down(void *_param)
191static int __ref _cpu_down(unsigned int cpu, int tasks_frozen) 220static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
192{ 221{
193 int err, nr_calls = 0; 222 int err, nr_calls = 0;
194 cpumask_var_t old_allowed;
195 void *hcpu = (void *)(long)cpu; 223 void *hcpu = (void *)(long)cpu;
196 unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0; 224 unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
197 struct take_cpu_down_param tcd_param = { 225 struct take_cpu_down_param tcd_param = {
226 .caller = current,
198 .mod = mod, 227 .mod = mod,
199 .hcpu = hcpu, 228 .hcpu = hcpu,
200 }; 229 };
@@ -205,38 +234,26 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
205 if (!cpu_online(cpu)) 234 if (!cpu_online(cpu))
206 return -EINVAL; 235 return -EINVAL;
207 236
208 if (!alloc_cpumask_var(&old_allowed, GFP_KERNEL))
209 return -ENOMEM;
210
211 cpu_hotplug_begin(); 237 cpu_hotplug_begin();
212 set_cpu_active(cpu, false); 238 set_cpu_active(cpu, false);
213 err = __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE | mod, 239 err = __cpu_notify(CPU_DOWN_PREPARE | mod, hcpu, -1, &nr_calls);
214 hcpu, -1, &nr_calls); 240 if (err) {
215 if (err == NOTIFY_BAD) {
216 set_cpu_active(cpu, true); 241 set_cpu_active(cpu, true);
217 242
218 nr_calls--; 243 nr_calls--;
219 __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod, 244 __cpu_notify(CPU_DOWN_FAILED | mod, hcpu, nr_calls, NULL);
220 hcpu, nr_calls, NULL);
221 printk("%s: attempt to take down CPU %u failed\n", 245 printk("%s: attempt to take down CPU %u failed\n",
222 __func__, cpu); 246 __func__, cpu);
223 err = -EINVAL;
224 goto out_release; 247 goto out_release;
225 } 248 }
226 249
227 /* Ensure that we are not runnable on dying cpu */
228 cpumask_copy(old_allowed, &current->cpus_allowed);
229 set_cpus_allowed_ptr(current, cpu_active_mask);
230
231 err = __stop_machine(take_cpu_down, &tcd_param, cpumask_of(cpu)); 250 err = __stop_machine(take_cpu_down, &tcd_param, cpumask_of(cpu));
232 if (err) { 251 if (err) {
233 set_cpu_active(cpu, true); 252 set_cpu_active(cpu, true);
234 /* CPU didn't die: tell everyone. Can't complain. */ 253 /* CPU didn't die: tell everyone. Can't complain. */
235 if (raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod, 254 cpu_notify_nofail(CPU_DOWN_FAILED | mod, hcpu);
236 hcpu) == NOTIFY_BAD)
237 BUG();
238 255
239 goto out_allowed; 256 goto out_release;
240 } 257 }
241 BUG_ON(cpu_online(cpu)); 258 BUG_ON(cpu_online(cpu));
242 259
@@ -248,22 +265,14 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
248 __cpu_die(cpu); 265 __cpu_die(cpu);
249 266
250 /* CPU is completely dead: tell everyone. Too late to complain. */ 267 /* CPU is completely dead: tell everyone. Too late to complain. */
251 if (raw_notifier_call_chain(&cpu_chain, CPU_DEAD | mod, 268 cpu_notify_nofail(CPU_DEAD | mod, hcpu);
252 hcpu) == NOTIFY_BAD)
253 BUG();
254 269
255 check_for_tasks(cpu); 270 check_for_tasks(cpu);
256 271
257out_allowed:
258 set_cpus_allowed_ptr(current, old_allowed);
259out_release: 272out_release:
260 cpu_hotplug_done(); 273 cpu_hotplug_done();
261 if (!err) { 274 if (!err)
262 if (raw_notifier_call_chain(&cpu_chain, CPU_POST_DEAD | mod, 275 cpu_notify_nofail(CPU_POST_DEAD | mod, hcpu);
263 hcpu) == NOTIFY_BAD)
264 BUG();
265 }
266 free_cpumask_var(old_allowed);
267 return err; 276 return err;
268} 277}
269 278
@@ -271,9 +280,6 @@ int __ref cpu_down(unsigned int cpu)
271{ 280{
272 int err; 281 int err;
273 282
274 err = stop_machine_create();
275 if (err)
276 return err;
277 cpu_maps_update_begin(); 283 cpu_maps_update_begin();
278 284
279 if (cpu_hotplug_disabled) { 285 if (cpu_hotplug_disabled) {
@@ -285,7 +291,6 @@ int __ref cpu_down(unsigned int cpu)
285 291
286out: 292out:
287 cpu_maps_update_done(); 293 cpu_maps_update_done();
288 stop_machine_destroy();
289 return err; 294 return err;
290} 295}
291EXPORT_SYMBOL(cpu_down); 296EXPORT_SYMBOL(cpu_down);
@@ -302,13 +307,11 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
302 return -EINVAL; 307 return -EINVAL;
303 308
304 cpu_hotplug_begin(); 309 cpu_hotplug_begin();
305 ret = __raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE | mod, hcpu, 310 ret = __cpu_notify(CPU_UP_PREPARE | mod, hcpu, -1, &nr_calls);
306 -1, &nr_calls); 311 if (ret) {
307 if (ret == NOTIFY_BAD) {
308 nr_calls--; 312 nr_calls--;
309 printk("%s: attempt to bring up CPU %u failed\n", 313 printk("%s: attempt to bring up CPU %u failed\n",
310 __func__, cpu); 314 __func__, cpu);
311 ret = -EINVAL;
312 goto out_notify; 315 goto out_notify;
313 } 316 }
314 317
@@ -321,12 +324,11 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
321 set_cpu_active(cpu, true); 324 set_cpu_active(cpu, true);
322 325
323 /* Now call notifier in preparation. */ 326 /* Now call notifier in preparation. */
324 raw_notifier_call_chain(&cpu_chain, CPU_ONLINE | mod, hcpu); 327 cpu_notify(CPU_ONLINE | mod, hcpu);
325 328
326out_notify: 329out_notify:
327 if (ret != 0) 330 if (ret != 0)
328 __raw_notifier_call_chain(&cpu_chain, 331 __cpu_notify(CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL);
329 CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL);
330 cpu_hotplug_done(); 332 cpu_hotplug_done();
331 333
332 return ret; 334 return ret;
@@ -335,16 +337,44 @@ out_notify:
335int __cpuinit cpu_up(unsigned int cpu) 337int __cpuinit cpu_up(unsigned int cpu)
336{ 338{
337 int err = 0; 339 int err = 0;
340
341#ifdef CONFIG_MEMORY_HOTPLUG
342 int nid;
343 pg_data_t *pgdat;
344#endif
345
338 if (!cpu_possible(cpu)) { 346 if (!cpu_possible(cpu)) {
339 printk(KERN_ERR "can't online cpu %d because it is not " 347 printk(KERN_ERR "can't online cpu %d because it is not "
340 "configured as may-hotadd at boot time\n", cpu); 348 "configured as may-hotadd at boot time\n", cpu);
341#if defined(CONFIG_IA64) || defined(CONFIG_X86_64) 349#if defined(CONFIG_IA64)
342 printk(KERN_ERR "please check additional_cpus= boot " 350 printk(KERN_ERR "please check additional_cpus= boot "
343 "parameter\n"); 351 "parameter\n");
344#endif 352#endif
345 return -EINVAL; 353 return -EINVAL;
346 } 354 }
347 355
356#ifdef CONFIG_MEMORY_HOTPLUG
357 nid = cpu_to_node(cpu);
358 if (!node_online(nid)) {
359 err = mem_online_node(nid);
360 if (err)
361 return err;
362 }
363
364 pgdat = NODE_DATA(nid);
365 if (!pgdat) {
366 printk(KERN_ERR
367 "Can't online cpu %d due to NULL pgdat\n", cpu);
368 return -ENOMEM;
369 }
370
371 if (pgdat->node_zonelists->_zonerefs->zone == NULL) {
372 mutex_lock(&zonelists_mutex);
373 build_all_zonelists(NULL);
374 mutex_unlock(&zonelists_mutex);
375 }
376#endif
377
348 cpu_maps_update_begin(); 378 cpu_maps_update_begin();
349 379
350 if (cpu_hotplug_disabled) { 380 if (cpu_hotplug_disabled) {
@@ -364,11 +394,8 @@ static cpumask_var_t frozen_cpus;
364 394
365int disable_nonboot_cpus(void) 395int disable_nonboot_cpus(void)
366{ 396{
367 int cpu, first_cpu, error; 397 int cpu, first_cpu, error = 0;
368 398
369 error = stop_machine_create();
370 if (error)
371 return error;
372 cpu_maps_update_begin(); 399 cpu_maps_update_begin();
373 first_cpu = cpumask_first(cpu_online_mask); 400 first_cpu = cpumask_first(cpu_online_mask);
374 /* 401 /*
@@ -399,7 +426,6 @@ int disable_nonboot_cpus(void)
399 printk(KERN_ERR "Non-boot CPUs are not disabled\n"); 426 printk(KERN_ERR "Non-boot CPUs are not disabled\n");
400 } 427 }
401 cpu_maps_update_done(); 428 cpu_maps_update_done();
402 stop_machine_destroy();
403 return error; 429 return error;
404} 430}
405 431
@@ -466,7 +492,7 @@ void __cpuinit notify_cpu_starting(unsigned int cpu)
466 if (frozen_cpus != NULL && cpumask_test_cpu(cpu, frozen_cpus)) 492 if (frozen_cpus != NULL && cpumask_test_cpu(cpu, frozen_cpus))
467 val = CPU_STARTING_FROZEN; 493 val = CPU_STARTING_FROZEN;
468#endif /* CONFIG_PM_SLEEP_SMP */ 494#endif /* CONFIG_PM_SLEEP_SMP */
469 raw_notifier_call_chain(&cpu_chain, val, (void *)(long)cpu); 495 cpu_notify(val, (void *)(long)cpu);
470} 496}
471 497
472#endif /* CONFIG_SMP */ 498#endif /* CONFIG_SMP */