diff options
-rw-r--r-- | include/linux/cpuhotplug.h | 21 | ||||
-rw-r--r-- | kernel/cpu.c | 506 |
2 files changed, 384 insertions, 143 deletions
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index f24bfb2b9a2d..6d508767e144 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h | |||
@@ -3,8 +3,27 @@ | |||
3 | 3 | ||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | 5 | ||
6 | /* | ||
7 | * CPU-up CPU-down | ||
8 | * | ||
9 | * BP AP BP AP | ||
10 | * | ||
11 | * OFFLINE OFFLINE | ||
12 | * | ^ | ||
13 | * v | | ||
14 | * BRINGUP_CPU->AP_OFFLINE BRINGUP_CPU <- AP_IDLE_DEAD (idle thread/play_dead) | ||
15 | * | AP_OFFLINE | ||
16 | * v (IRQ-off) ,---------------^ | ||
17 | * AP_ONLNE | (stop_machine) | ||
18 | * | TEARDOWN_CPU <- AP_ONLINE_IDLE | ||
19 | * | ^ | ||
20 | * v | | ||
21 | * AP_ACTIVE AP_ACTIVE | ||
22 | */ | ||
23 | |||
6 | enum cpuhp_state { | 24 | enum cpuhp_state { |
7 | CPUHP_OFFLINE, | 25 | CPUHP_INVALID = -1, |
26 | CPUHP_OFFLINE = 0, | ||
8 | CPUHP_CREATE_THREADS, | 27 | CPUHP_CREATE_THREADS, |
9 | CPUHP_PERF_PREPARE, | 28 | CPUHP_PERF_PREPARE, |
10 | CPUHP_PERF_X86_PREPARE, | 29 | CPUHP_PERF_X86_PREPARE, |
diff --git a/kernel/cpu.c b/kernel/cpu.c index acf5308fad51..8de11a29e495 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c | |||
@@ -46,11 +46,13 @@ | |||
46 | * @bringup: Single callback bringup or teardown selector | 46 | * @bringup: Single callback bringup or teardown selector |
47 | * @cb_state: The state for a single callback (install/uninstall) | 47 | * @cb_state: The state for a single callback (install/uninstall) |
48 | * @result: Result of the operation | 48 | * @result: Result of the operation |
49 | * @done: Signal completion to the issuer of the task | 49 | * @done_up: Signal completion to the issuer of the task for cpu-up |
50 | * @done_down: Signal completion to the issuer of the task for cpu-down | ||
50 | */ | 51 | */ |
51 | struct cpuhp_cpu_state { | 52 | struct cpuhp_cpu_state { |
52 | enum cpuhp_state state; | 53 | enum cpuhp_state state; |
53 | enum cpuhp_state target; | 54 | enum cpuhp_state target; |
55 | enum cpuhp_state fail; | ||
54 | #ifdef CONFIG_SMP | 56 | #ifdef CONFIG_SMP |
55 | struct task_struct *thread; | 57 | struct task_struct *thread; |
56 | bool should_run; | 58 | bool should_run; |
@@ -58,18 +60,39 @@ struct cpuhp_cpu_state { | |||
58 | bool single; | 60 | bool single; |
59 | bool bringup; | 61 | bool bringup; |
60 | struct hlist_node *node; | 62 | struct hlist_node *node; |
63 | struct hlist_node *last; | ||
61 | enum cpuhp_state cb_state; | 64 | enum cpuhp_state cb_state; |
62 | int result; | 65 | int result; |
63 | struct completion done; | 66 | struct completion done_up; |
67 | struct completion done_down; | ||
64 | #endif | 68 | #endif |
65 | }; | 69 | }; |
66 | 70 | ||
67 | static DEFINE_PER_CPU(struct cpuhp_cpu_state, cpuhp_state); | 71 | static DEFINE_PER_CPU(struct cpuhp_cpu_state, cpuhp_state) = { |
72 | .fail = CPUHP_INVALID, | ||
73 | }; | ||
68 | 74 | ||
69 | #if defined(CONFIG_LOCKDEP) && defined(CONFIG_SMP) | 75 | #if defined(CONFIG_LOCKDEP) && defined(CONFIG_SMP) |
70 | static struct lock_class_key cpuhp_state_key; | 76 | static struct lockdep_map cpuhp_state_up_map = |
71 | static struct lockdep_map cpuhp_state_lock_map = | 77 | STATIC_LOCKDEP_MAP_INIT("cpuhp_state-up", &cpuhp_state_up_map); |
72 | STATIC_LOCKDEP_MAP_INIT("cpuhp_state", &cpuhp_state_key); | 78 | static struct lockdep_map cpuhp_state_down_map = |
79 | STATIC_LOCKDEP_MAP_INIT("cpuhp_state-down", &cpuhp_state_down_map); | ||
80 | |||
81 | |||
82 | static void inline cpuhp_lock_acquire(bool bringup) | ||
83 | { | ||
84 | lock_map_acquire(bringup ? &cpuhp_state_up_map : &cpuhp_state_down_map); | ||
85 | } | ||
86 | |||
87 | static void inline cpuhp_lock_release(bool bringup) | ||
88 | { | ||
89 | lock_map_release(bringup ? &cpuhp_state_up_map : &cpuhp_state_down_map); | ||
90 | } | ||
91 | #else | ||
92 | |||
93 | static void inline cpuhp_lock_acquire(bool bringup) { } | ||
94 | static void inline cpuhp_lock_release(bool bringup) { } | ||
95 | |||
73 | #endif | 96 | #endif |
74 | 97 | ||
75 | /** | 98 | /** |
@@ -123,13 +146,16 @@ static struct cpuhp_step *cpuhp_get_step(enum cpuhp_state state) | |||
123 | /** | 146 | /** |
124 | * cpuhp_invoke_callback _ Invoke the callbacks for a given state | 147 | * cpuhp_invoke_callback _ Invoke the callbacks for a given state |
125 | * @cpu: The cpu for which the callback should be invoked | 148 | * @cpu: The cpu for which the callback should be invoked |
126 | * @step: The step in the state machine | 149 | * @state: The state to do callbacks for |
127 | * @bringup: True if the bringup callback should be invoked | 150 | * @bringup: True if the bringup callback should be invoked |
151 | * @node: For multi-instance, do a single entry callback for install/remove | ||
152 | * @lastp: For multi-instance rollback, remember how far we got | ||
128 | * | 153 | * |
129 | * Called from cpu hotplug and from the state register machinery. | 154 | * Called from cpu hotplug and from the state register machinery. |
130 | */ | 155 | */ |
131 | static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state, | 156 | static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state, |
132 | bool bringup, struct hlist_node *node) | 157 | bool bringup, struct hlist_node *node, |
158 | struct hlist_node **lastp) | ||
133 | { | 159 | { |
134 | struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); | 160 | struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); |
135 | struct cpuhp_step *step = cpuhp_get_step(state); | 161 | struct cpuhp_step *step = cpuhp_get_step(state); |
@@ -137,7 +163,17 @@ static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state, | |||
137 | int (*cb)(unsigned int cpu); | 163 | int (*cb)(unsigned int cpu); |
138 | int ret, cnt; | 164 | int ret, cnt; |
139 | 165 | ||
166 | if (st->fail == state) { | ||
167 | st->fail = CPUHP_INVALID; | ||
168 | |||
169 | if (!(bringup ? step->startup.single : step->teardown.single)) | ||
170 | return 0; | ||
171 | |||
172 | return -EAGAIN; | ||
173 | } | ||
174 | |||
140 | if (!step->multi_instance) { | 175 | if (!step->multi_instance) { |
176 | WARN_ON_ONCE(lastp && *lastp); | ||
141 | cb = bringup ? step->startup.single : step->teardown.single; | 177 | cb = bringup ? step->startup.single : step->teardown.single; |
142 | if (!cb) | 178 | if (!cb) |
143 | return 0; | 179 | return 0; |
@@ -152,6 +188,7 @@ static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state, | |||
152 | 188 | ||
153 | /* Single invocation for instance add/remove */ | 189 | /* Single invocation for instance add/remove */ |
154 | if (node) { | 190 | if (node) { |
191 | WARN_ON_ONCE(lastp && *lastp); | ||
155 | trace_cpuhp_multi_enter(cpu, st->target, state, cbm, node); | 192 | trace_cpuhp_multi_enter(cpu, st->target, state, cbm, node); |
156 | ret = cbm(cpu, node); | 193 | ret = cbm(cpu, node); |
157 | trace_cpuhp_exit(cpu, st->state, state, ret); | 194 | trace_cpuhp_exit(cpu, st->state, state, ret); |
@@ -161,13 +198,23 @@ static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state, | |||
161 | /* State transition. Invoke on all instances */ | 198 | /* State transition. Invoke on all instances */ |
162 | cnt = 0; | 199 | cnt = 0; |
163 | hlist_for_each(node, &step->list) { | 200 | hlist_for_each(node, &step->list) { |
201 | if (lastp && node == *lastp) | ||
202 | break; | ||
203 | |||
164 | trace_cpuhp_multi_enter(cpu, st->target, state, cbm, node); | 204 | trace_cpuhp_multi_enter(cpu, st->target, state, cbm, node); |
165 | ret = cbm(cpu, node); | 205 | ret = cbm(cpu, node); |
166 | trace_cpuhp_exit(cpu, st->state, state, ret); | 206 | trace_cpuhp_exit(cpu, st->state, state, ret); |
167 | if (ret) | 207 | if (ret) { |
168 | goto err; | 208 | if (!lastp) |
209 | goto err; | ||
210 | |||
211 | *lastp = node; | ||
212 | return ret; | ||
213 | } | ||
169 | cnt++; | 214 | cnt++; |
170 | } | 215 | } |
216 | if (lastp) | ||
217 | *lastp = NULL; | ||
171 | return 0; | 218 | return 0; |
172 | err: | 219 | err: |
173 | /* Rollback the instances if one failed */ | 220 | /* Rollback the instances if one failed */ |
@@ -178,12 +225,39 @@ err: | |||
178 | hlist_for_each(node, &step->list) { | 225 | hlist_for_each(node, &step->list) { |
179 | if (!cnt--) | 226 | if (!cnt--) |
180 | break; | 227 | break; |
181 | cbm(cpu, node); | 228 | |
229 | trace_cpuhp_multi_enter(cpu, st->target, state, cbm, node); | ||
230 | ret = cbm(cpu, node); | ||
231 | trace_cpuhp_exit(cpu, st->state, state, ret); | ||
232 | /* | ||
233 | * Rollback must not fail, | ||
234 | */ | ||
235 | WARN_ON_ONCE(ret); | ||
182 | } | 236 | } |
183 | return ret; | 237 | return ret; |
184 | } | 238 | } |
185 | 239 | ||
186 | #ifdef CONFIG_SMP | 240 | #ifdef CONFIG_SMP |
241 | static inline void wait_for_ap_thread(struct cpuhp_cpu_state *st, bool bringup) | ||
242 | { | ||
243 | struct completion *done = bringup ? &st->done_up : &st->done_down; | ||
244 | wait_for_completion(done); | ||
245 | } | ||
246 | |||
247 | static inline void complete_ap_thread(struct cpuhp_cpu_state *st, bool bringup) | ||
248 | { | ||
249 | struct completion *done = bringup ? &st->done_up : &st->done_down; | ||
250 | complete(done); | ||
251 | } | ||
252 | |||
253 | /* | ||
254 | * The former STARTING/DYING states, ran with IRQs disabled and must not fail. | ||
255 | */ | ||
256 | static bool cpuhp_is_atomic_state(enum cpuhp_state state) | ||
257 | { | ||
258 | return CPUHP_AP_IDLE_DEAD <= state && state < CPUHP_AP_ONLINE; | ||
259 | } | ||
260 | |||
187 | /* Serializes the updates to cpu_online_mask, cpu_present_mask */ | 261 | /* Serializes the updates to cpu_online_mask, cpu_present_mask */ |
188 | static DEFINE_MUTEX(cpu_add_remove_lock); | 262 | static DEFINE_MUTEX(cpu_add_remove_lock); |
189 | bool cpuhp_tasks_frozen; | 263 | bool cpuhp_tasks_frozen; |
@@ -271,14 +345,79 @@ void cpu_hotplug_enable(void) | |||
271 | EXPORT_SYMBOL_GPL(cpu_hotplug_enable); | 345 | EXPORT_SYMBOL_GPL(cpu_hotplug_enable); |
272 | #endif /* CONFIG_HOTPLUG_CPU */ | 346 | #endif /* CONFIG_HOTPLUG_CPU */ |
273 | 347 | ||
274 | static void __cpuhp_kick_ap_work(struct cpuhp_cpu_state *st); | 348 | static inline enum cpuhp_state |
349 | cpuhp_set_state(struct cpuhp_cpu_state *st, enum cpuhp_state target) | ||
350 | { | ||
351 | enum cpuhp_state prev_state = st->state; | ||
352 | |||
353 | st->rollback = false; | ||
354 | st->last = NULL; | ||
355 | |||
356 | st->target = target; | ||
357 | st->single = false; | ||
358 | st->bringup = st->state < target; | ||
359 | |||
360 | return prev_state; | ||
361 | } | ||
362 | |||
363 | static inline void | ||
364 | cpuhp_reset_state(struct cpuhp_cpu_state *st, enum cpuhp_state prev_state) | ||
365 | { | ||
366 | st->rollback = true; | ||
367 | |||
368 | /* | ||
369 | * If we have st->last we need to undo partial multi_instance of this | ||
370 | * state first. Otherwise start undo at the previous state. | ||
371 | */ | ||
372 | if (!st->last) { | ||
373 | if (st->bringup) | ||
374 | st->state--; | ||
375 | else | ||
376 | st->state++; | ||
377 | } | ||
378 | |||
379 | st->target = prev_state; | ||
380 | st->bringup = !st->bringup; | ||
381 | } | ||
382 | |||
383 | /* Regular hotplug invocation of the AP hotplug thread */ | ||
384 | static void __cpuhp_kick_ap(struct cpuhp_cpu_state *st) | ||
385 | { | ||
386 | if (!st->single && st->state == st->target) | ||
387 | return; | ||
388 | |||
389 | st->result = 0; | ||
390 | /* | ||
391 | * Make sure the above stores are visible before should_run becomes | ||
392 | * true. Paired with the mb() above in cpuhp_thread_fun() | ||
393 | */ | ||
394 | smp_mb(); | ||
395 | st->should_run = true; | ||
396 | wake_up_process(st->thread); | ||
397 | wait_for_ap_thread(st, st->bringup); | ||
398 | } | ||
399 | |||
400 | static int cpuhp_kick_ap(struct cpuhp_cpu_state *st, enum cpuhp_state target) | ||
401 | { | ||
402 | enum cpuhp_state prev_state; | ||
403 | int ret; | ||
404 | |||
405 | prev_state = cpuhp_set_state(st, target); | ||
406 | __cpuhp_kick_ap(st); | ||
407 | if ((ret = st->result)) { | ||
408 | cpuhp_reset_state(st, prev_state); | ||
409 | __cpuhp_kick_ap(st); | ||
410 | } | ||
411 | |||
412 | return ret; | ||
413 | } | ||
275 | 414 | ||
276 | static int bringup_wait_for_ap(unsigned int cpu) | 415 | static int bringup_wait_for_ap(unsigned int cpu) |
277 | { | 416 | { |
278 | struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); | 417 | struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); |
279 | 418 | ||
280 | /* Wait for the CPU to reach CPUHP_AP_ONLINE_IDLE */ | 419 | /* Wait for the CPU to reach CPUHP_AP_ONLINE_IDLE */ |
281 | wait_for_completion(&st->done); | 420 | wait_for_ap_thread(st, true); |
282 | if (WARN_ON_ONCE((!cpu_online(cpu)))) | 421 | if (WARN_ON_ONCE((!cpu_online(cpu)))) |
283 | return -ECANCELED; | 422 | return -ECANCELED; |
284 | 423 | ||
@@ -286,12 +425,10 @@ static int bringup_wait_for_ap(unsigned int cpu) | |||
286 | stop_machine_unpark(cpu); | 425 | stop_machine_unpark(cpu); |
287 | kthread_unpark(st->thread); | 426 | kthread_unpark(st->thread); |
288 | 427 | ||
289 | /* Should we go further up ? */ | 428 | if (st->target <= CPUHP_AP_ONLINE_IDLE) |
290 | if (st->target > CPUHP_AP_ONLINE_IDLE) { | 429 | return 0; |
291 | __cpuhp_kick_ap_work(st); | 430 | |
292 | wait_for_completion(&st->done); | 431 | return cpuhp_kick_ap(st, st->target); |
293 | } | ||
294 | return st->result; | ||
295 | } | 432 | } |
296 | 433 | ||
297 | static int bringup_cpu(unsigned int cpu) | 434 | static int bringup_cpu(unsigned int cpu) |
@@ -317,32 +454,6 @@ static int bringup_cpu(unsigned int cpu) | |||
317 | /* | 454 | /* |
318 | * Hotplug state machine related functions | 455 | * Hotplug state machine related functions |
319 | */ | 456 | */ |
320 | static void undo_cpu_down(unsigned int cpu, struct cpuhp_cpu_state *st) | ||
321 | { | ||
322 | for (st->state++; st->state < st->target; st->state++) { | ||
323 | struct cpuhp_step *step = cpuhp_get_step(st->state); | ||
324 | |||
325 | if (!step->skip_onerr) | ||
326 | cpuhp_invoke_callback(cpu, st->state, true, NULL); | ||
327 | } | ||
328 | } | ||
329 | |||
330 | static int cpuhp_down_callbacks(unsigned int cpu, struct cpuhp_cpu_state *st, | ||
331 | enum cpuhp_state target) | ||
332 | { | ||
333 | enum cpuhp_state prev_state = st->state; | ||
334 | int ret = 0; | ||
335 | |||
336 | for (; st->state > target; st->state--) { | ||
337 | ret = cpuhp_invoke_callback(cpu, st->state, false, NULL); | ||
338 | if (ret) { | ||
339 | st->target = prev_state; | ||
340 | undo_cpu_down(cpu, st); | ||
341 | break; | ||
342 | } | ||
343 | } | ||
344 | return ret; | ||
345 | } | ||
346 | 457 | ||
347 | static void undo_cpu_up(unsigned int cpu, struct cpuhp_cpu_state *st) | 458 | static void undo_cpu_up(unsigned int cpu, struct cpuhp_cpu_state *st) |
348 | { | 459 | { |
@@ -350,7 +461,7 @@ static void undo_cpu_up(unsigned int cpu, struct cpuhp_cpu_state *st) | |||
350 | struct cpuhp_step *step = cpuhp_get_step(st->state); | 461 | struct cpuhp_step *step = cpuhp_get_step(st->state); |
351 | 462 | ||
352 | if (!step->skip_onerr) | 463 | if (!step->skip_onerr) |
353 | cpuhp_invoke_callback(cpu, st->state, false, NULL); | 464 | cpuhp_invoke_callback(cpu, st->state, false, NULL, NULL); |
354 | } | 465 | } |
355 | } | 466 | } |
356 | 467 | ||
@@ -362,7 +473,7 @@ static int cpuhp_up_callbacks(unsigned int cpu, struct cpuhp_cpu_state *st, | |||
362 | 473 | ||
363 | while (st->state < target) { | 474 | while (st->state < target) { |
364 | st->state++; | 475 | st->state++; |
365 | ret = cpuhp_invoke_callback(cpu, st->state, true, NULL); | 476 | ret = cpuhp_invoke_callback(cpu, st->state, true, NULL, NULL); |
366 | if (ret) { | 477 | if (ret) { |
367 | st->target = prev_state; | 478 | st->target = prev_state; |
368 | undo_cpu_up(cpu, st); | 479 | undo_cpu_up(cpu, st); |
@@ -379,7 +490,8 @@ static void cpuhp_create(unsigned int cpu) | |||
379 | { | 490 | { |
380 | struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); | 491 | struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); |
381 | 492 | ||
382 | init_completion(&st->done); | 493 | init_completion(&st->done_up); |
494 | init_completion(&st->done_down); | ||
383 | } | 495 | } |
384 | 496 | ||
385 | static int cpuhp_should_run(unsigned int cpu) | 497 | static int cpuhp_should_run(unsigned int cpu) |
@@ -389,69 +501,90 @@ static int cpuhp_should_run(unsigned int cpu) | |||
389 | return st->should_run; | 501 | return st->should_run; |
390 | } | 502 | } |
391 | 503 | ||
392 | /* Execute the teardown callbacks. Used to be CPU_DOWN_PREPARE */ | ||
393 | static int cpuhp_ap_offline(unsigned int cpu, struct cpuhp_cpu_state *st) | ||
394 | { | ||
395 | enum cpuhp_state target = max((int)st->target, CPUHP_TEARDOWN_CPU); | ||
396 | |||
397 | return cpuhp_down_callbacks(cpu, st, target); | ||
398 | } | ||
399 | |||
400 | /* Execute the online startup callbacks. Used to be CPU_ONLINE */ | ||
401 | static int cpuhp_ap_online(unsigned int cpu, struct cpuhp_cpu_state *st) | ||
402 | { | ||
403 | return cpuhp_up_callbacks(cpu, st, st->target); | ||
404 | } | ||
405 | |||
406 | /* | 504 | /* |
407 | * Execute teardown/startup callbacks on the plugged cpu. Also used to invoke | 505 | * Execute teardown/startup callbacks on the plugged cpu. Also used to invoke |
408 | * callbacks when a state gets [un]installed at runtime. | 506 | * callbacks when a state gets [un]installed at runtime. |
507 | * | ||
508 | * Each invocation of this function by the smpboot thread does a single AP | ||
509 | * state callback. | ||
510 | * | ||
511 | * It has 3 modes of operation: | ||
512 | * - single: runs st->cb_state | ||
513 | * - up: runs ++st->state, while st->state < st->target | ||
514 | * - down: runs st->state--, while st->state > st->target | ||
515 | * | ||
516 | * When complete or on error, should_run is cleared and the completion is fired. | ||
409 | */ | 517 | */ |
410 | static void cpuhp_thread_fun(unsigned int cpu) | 518 | static void cpuhp_thread_fun(unsigned int cpu) |
411 | { | 519 | { |
412 | struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state); | 520 | struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state); |
413 | int ret = 0; | 521 | bool bringup = st->bringup; |
522 | enum cpuhp_state state; | ||
414 | 523 | ||
415 | /* | 524 | /* |
416 | * Paired with the mb() in cpuhp_kick_ap_work and | 525 | * ACQUIRE for the cpuhp_should_run() load of ->should_run. Ensures |
417 | * cpuhp_invoke_ap_callback, so the work set is consistent visible. | 526 | * that if we see ->should_run we also see the rest of the state. |
418 | */ | 527 | */ |
419 | smp_mb(); | 528 | smp_mb(); |
420 | if (!st->should_run) | 529 | |
530 | if (WARN_ON_ONCE(!st->should_run)) | ||
421 | return; | 531 | return; |
422 | 532 | ||
423 | st->should_run = false; | 533 | cpuhp_lock_acquire(bringup); |
424 | 534 | ||
425 | lock_map_acquire(&cpuhp_state_lock_map); | ||
426 | /* Single callback invocation for [un]install ? */ | ||
427 | if (st->single) { | 535 | if (st->single) { |
428 | if (st->cb_state < CPUHP_AP_ONLINE) { | 536 | state = st->cb_state; |
429 | local_irq_disable(); | 537 | st->should_run = false; |
430 | ret = cpuhp_invoke_callback(cpu, st->cb_state, | 538 | } else { |
431 | st->bringup, st->node); | 539 | if (bringup) { |
432 | local_irq_enable(); | 540 | st->state++; |
541 | state = st->state; | ||
542 | st->should_run = (st->state < st->target); | ||
543 | WARN_ON_ONCE(st->state > st->target); | ||
433 | } else { | 544 | } else { |
434 | ret = cpuhp_invoke_callback(cpu, st->cb_state, | 545 | state = st->state; |
435 | st->bringup, st->node); | 546 | st->state--; |
547 | st->should_run = (st->state > st->target); | ||
548 | WARN_ON_ONCE(st->state < st->target); | ||
436 | } | 549 | } |
437 | } else if (st->rollback) { | 550 | } |
438 | BUG_ON(st->state < CPUHP_AP_ONLINE_IDLE); | 551 | |
552 | WARN_ON_ONCE(!cpuhp_is_ap_state(state)); | ||
439 | 553 | ||
440 | undo_cpu_down(cpu, st); | 554 | if (st->rollback) { |
441 | st->rollback = false; | 555 | struct cpuhp_step *step = cpuhp_get_step(state); |
556 | if (step->skip_onerr) | ||
557 | goto next; | ||
558 | } | ||
559 | |||
560 | if (cpuhp_is_atomic_state(state)) { | ||
561 | local_irq_disable(); | ||
562 | st->result = cpuhp_invoke_callback(cpu, state, bringup, st->node, &st->last); | ||
563 | local_irq_enable(); | ||
564 | |||
565 | /* | ||
566 | * STARTING/DYING must not fail! | ||
567 | */ | ||
568 | WARN_ON_ONCE(st->result); | ||
442 | } else { | 569 | } else { |
443 | /* Cannot happen .... */ | 570 | st->result = cpuhp_invoke_callback(cpu, state, bringup, st->node, &st->last); |
444 | BUG_ON(st->state < CPUHP_AP_ONLINE_IDLE); | 571 | } |
445 | 572 | ||
446 | /* Regular hotplug work */ | 573 | if (st->result) { |
447 | if (st->state < st->target) | 574 | /* |
448 | ret = cpuhp_ap_online(cpu, st); | 575 | * If we fail on a rollback, we're up a creek without no |
449 | else if (st->state > st->target) | 576 | * paddle, no way forward, no way back. We loose, thanks for |
450 | ret = cpuhp_ap_offline(cpu, st); | 577 | * playing. |
578 | */ | ||
579 | WARN_ON_ONCE(st->rollback); | ||
580 | st->should_run = false; | ||
451 | } | 581 | } |
452 | lock_map_release(&cpuhp_state_lock_map); | 582 | |
453 | st->result = ret; | 583 | next: |
454 | complete(&st->done); | 584 | cpuhp_lock_release(bringup); |
585 | |||
586 | if (!st->should_run) | ||
587 | complete_ap_thread(st, bringup); | ||
455 | } | 588 | } |
456 | 589 | ||
457 | /* Invoke a single callback on a remote cpu */ | 590 | /* Invoke a single callback on a remote cpu */ |
@@ -460,62 +593,64 @@ cpuhp_invoke_ap_callback(int cpu, enum cpuhp_state state, bool bringup, | |||
460 | struct hlist_node *node) | 593 | struct hlist_node *node) |
461 | { | 594 | { |
462 | struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); | 595 | struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); |
596 | int ret; | ||
463 | 597 | ||
464 | if (!cpu_online(cpu)) | 598 | if (!cpu_online(cpu)) |
465 | return 0; | 599 | return 0; |
466 | 600 | ||
467 | lock_map_acquire(&cpuhp_state_lock_map); | 601 | cpuhp_lock_acquire(false); |
468 | lock_map_release(&cpuhp_state_lock_map); | 602 | cpuhp_lock_release(false); |
603 | |||
604 | cpuhp_lock_acquire(true); | ||
605 | cpuhp_lock_release(true); | ||
469 | 606 | ||
470 | /* | 607 | /* |
471 | * If we are up and running, use the hotplug thread. For early calls | 608 | * If we are up and running, use the hotplug thread. For early calls |
472 | * we invoke the thread function directly. | 609 | * we invoke the thread function directly. |
473 | */ | 610 | */ |
474 | if (!st->thread) | 611 | if (!st->thread) |
475 | return cpuhp_invoke_callback(cpu, state, bringup, node); | 612 | return cpuhp_invoke_callback(cpu, state, bringup, node, NULL); |
476 | 613 | ||
614 | st->rollback = false; | ||
615 | st->last = NULL; | ||
616 | |||
617 | st->node = node; | ||
618 | st->bringup = bringup; | ||
477 | st->cb_state = state; | 619 | st->cb_state = state; |
478 | st->single = true; | 620 | st->single = true; |
479 | st->bringup = bringup; | ||
480 | st->node = node; | ||
481 | 621 | ||
482 | /* | 622 | __cpuhp_kick_ap(st); |
483 | * Make sure the above stores are visible before should_run becomes | ||
484 | * true. Paired with the mb() above in cpuhp_thread_fun() | ||
485 | */ | ||
486 | smp_mb(); | ||
487 | st->should_run = true; | ||
488 | wake_up_process(st->thread); | ||
489 | wait_for_completion(&st->done); | ||
490 | return st->result; | ||
491 | } | ||
492 | 623 | ||
493 | /* Regular hotplug invocation of the AP hotplug thread */ | ||
494 | static void __cpuhp_kick_ap_work(struct cpuhp_cpu_state *st) | ||
495 | { | ||
496 | st->result = 0; | ||
497 | st->single = false; | ||
498 | /* | 624 | /* |
499 | * Make sure the above stores are visible before should_run becomes | 625 | * If we failed and did a partial, do a rollback. |
500 | * true. Paired with the mb() above in cpuhp_thread_fun() | ||
501 | */ | 626 | */ |
502 | smp_mb(); | 627 | if ((ret = st->result) && st->last) { |
503 | st->should_run = true; | 628 | st->rollback = true; |
504 | wake_up_process(st->thread); | 629 | st->bringup = !bringup; |
630 | |||
631 | __cpuhp_kick_ap(st); | ||
632 | } | ||
633 | |||
634 | return ret; | ||
505 | } | 635 | } |
506 | 636 | ||
507 | static int cpuhp_kick_ap_work(unsigned int cpu) | 637 | static int cpuhp_kick_ap_work(unsigned int cpu) |
508 | { | 638 | { |
509 | struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); | 639 | struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); |
510 | enum cpuhp_state state = st->state; | 640 | enum cpuhp_state prev_state = st->state; |
641 | int ret; | ||
642 | |||
643 | cpuhp_lock_acquire(false); | ||
644 | cpuhp_lock_release(false); | ||
645 | |||
646 | cpuhp_lock_acquire(true); | ||
647 | cpuhp_lock_release(true); | ||
648 | |||
649 | trace_cpuhp_enter(cpu, st->target, prev_state, cpuhp_kick_ap_work); | ||
650 | ret = cpuhp_kick_ap(st, st->target); | ||
651 | trace_cpuhp_exit(cpu, st->state, prev_state, ret); | ||
511 | 652 | ||
512 | trace_cpuhp_enter(cpu, st->target, state, cpuhp_kick_ap_work); | 653 | return ret; |
513 | lock_map_acquire(&cpuhp_state_lock_map); | ||
514 | lock_map_release(&cpuhp_state_lock_map); | ||
515 | __cpuhp_kick_ap_work(st); | ||
516 | wait_for_completion(&st->done); | ||
517 | trace_cpuhp_exit(cpu, st->state, state, st->result); | ||
518 | return st->result; | ||
519 | } | 654 | } |
520 | 655 | ||
521 | static struct smp_hotplug_thread cpuhp_threads = { | 656 | static struct smp_hotplug_thread cpuhp_threads = { |
@@ -581,6 +716,7 @@ static int take_cpu_down(void *_param) | |||
581 | struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state); | 716 | struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state); |
582 | enum cpuhp_state target = max((int)st->target, CPUHP_AP_OFFLINE); | 717 | enum cpuhp_state target = max((int)st->target, CPUHP_AP_OFFLINE); |
583 | int err, cpu = smp_processor_id(); | 718 | int err, cpu = smp_processor_id(); |
719 | int ret; | ||
584 | 720 | ||
585 | /* Ensure this CPU doesn't handle any more interrupts. */ | 721 | /* Ensure this CPU doesn't handle any more interrupts. */ |
586 | err = __cpu_disable(); | 722 | err = __cpu_disable(); |
@@ -594,8 +730,13 @@ static int take_cpu_down(void *_param) | |||
594 | WARN_ON(st->state != CPUHP_TEARDOWN_CPU); | 730 | WARN_ON(st->state != CPUHP_TEARDOWN_CPU); |
595 | st->state--; | 731 | st->state--; |
596 | /* Invoke the former CPU_DYING callbacks */ | 732 | /* Invoke the former CPU_DYING callbacks */ |
597 | for (; st->state > target; st->state--) | 733 | for (; st->state > target; st->state--) { |
598 | cpuhp_invoke_callback(cpu, st->state, false, NULL); | 734 | ret = cpuhp_invoke_callback(cpu, st->state, false, NULL, NULL); |
735 | /* | ||
736 | * DYING must not fail! | ||
737 | */ | ||
738 | WARN_ON_ONCE(ret); | ||
739 | } | ||
599 | 740 | ||
600 | /* Give up timekeeping duties */ | 741 | /* Give up timekeeping duties */ |
601 | tick_handover_do_timer(); | 742 | tick_handover_do_timer(); |
@@ -639,7 +780,7 @@ static int takedown_cpu(unsigned int cpu) | |||
639 | * | 780 | * |
640 | * Wait for the stop thread to go away. | 781 | * Wait for the stop thread to go away. |
641 | */ | 782 | */ |
642 | wait_for_completion(&st->done); | 783 | wait_for_ap_thread(st, false); |
643 | BUG_ON(st->state != CPUHP_AP_IDLE_DEAD); | 784 | BUG_ON(st->state != CPUHP_AP_IDLE_DEAD); |
644 | 785 | ||
645 | /* Interrupts are moved away from the dying cpu, reenable alloc/free */ | 786 | /* Interrupts are moved away from the dying cpu, reenable alloc/free */ |
@@ -658,7 +799,7 @@ static void cpuhp_complete_idle_dead(void *arg) | |||
658 | { | 799 | { |
659 | struct cpuhp_cpu_state *st = arg; | 800 | struct cpuhp_cpu_state *st = arg; |
660 | 801 | ||
661 | complete(&st->done); | 802 | complete_ap_thread(st, false); |
662 | } | 803 | } |
663 | 804 | ||
664 | void cpuhp_report_idle_dead(void) | 805 | void cpuhp_report_idle_dead(void) |
@@ -676,11 +817,32 @@ void cpuhp_report_idle_dead(void) | |||
676 | cpuhp_complete_idle_dead, st, 0); | 817 | cpuhp_complete_idle_dead, st, 0); |
677 | } | 818 | } |
678 | 819 | ||
679 | #else | 820 | static void undo_cpu_down(unsigned int cpu, struct cpuhp_cpu_state *st) |
680 | #define takedown_cpu NULL | 821 | { |
681 | #endif | 822 | for (st->state++; st->state < st->target; st->state++) { |
823 | struct cpuhp_step *step = cpuhp_get_step(st->state); | ||
682 | 824 | ||
683 | #ifdef CONFIG_HOTPLUG_CPU | 825 | if (!step->skip_onerr) |
826 | cpuhp_invoke_callback(cpu, st->state, true, NULL, NULL); | ||
827 | } | ||
828 | } | ||
829 | |||
830 | static int cpuhp_down_callbacks(unsigned int cpu, struct cpuhp_cpu_state *st, | ||
831 | enum cpuhp_state target) | ||
832 | { | ||
833 | enum cpuhp_state prev_state = st->state; | ||
834 | int ret = 0; | ||
835 | |||
836 | for (; st->state > target; st->state--) { | ||
837 | ret = cpuhp_invoke_callback(cpu, st->state, false, NULL, NULL); | ||
838 | if (ret) { | ||
839 | st->target = prev_state; | ||
840 | undo_cpu_down(cpu, st); | ||
841 | break; | ||
842 | } | ||
843 | } | ||
844 | return ret; | ||
845 | } | ||
684 | 846 | ||
685 | /* Requires cpu_add_remove_lock to be held */ | 847 | /* Requires cpu_add_remove_lock to be held */ |
686 | static int __ref _cpu_down(unsigned int cpu, int tasks_frozen, | 848 | static int __ref _cpu_down(unsigned int cpu, int tasks_frozen, |
@@ -699,13 +861,13 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen, | |||
699 | 861 | ||
700 | cpuhp_tasks_frozen = tasks_frozen; | 862 | cpuhp_tasks_frozen = tasks_frozen; |
701 | 863 | ||
702 | prev_state = st->state; | 864 | prev_state = cpuhp_set_state(st, target); |
703 | st->target = target; | ||
704 | /* | 865 | /* |
705 | * If the current CPU state is in the range of the AP hotplug thread, | 866 | * If the current CPU state is in the range of the AP hotplug thread, |
706 | * then we need to kick the thread. | 867 | * then we need to kick the thread. |
707 | */ | 868 | */ |
708 | if (st->state > CPUHP_TEARDOWN_CPU) { | 869 | if (st->state > CPUHP_TEARDOWN_CPU) { |
870 | st->target = max((int)target, CPUHP_TEARDOWN_CPU); | ||
709 | ret = cpuhp_kick_ap_work(cpu); | 871 | ret = cpuhp_kick_ap_work(cpu); |
710 | /* | 872 | /* |
711 | * The AP side has done the error rollback already. Just | 873 | * The AP side has done the error rollback already. Just |
@@ -720,6 +882,8 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen, | |||
720 | */ | 882 | */ |
721 | if (st->state > CPUHP_TEARDOWN_CPU) | 883 | if (st->state > CPUHP_TEARDOWN_CPU) |
722 | goto out; | 884 | goto out; |
885 | |||
886 | st->target = target; | ||
723 | } | 887 | } |
724 | /* | 888 | /* |
725 | * The AP brought itself down to CPUHP_TEARDOWN_CPU. So we need | 889 | * The AP brought itself down to CPUHP_TEARDOWN_CPU. So we need |
@@ -727,9 +891,8 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen, | |||
727 | */ | 891 | */ |
728 | ret = cpuhp_down_callbacks(cpu, st, target); | 892 | ret = cpuhp_down_callbacks(cpu, st, target); |
729 | if (ret && st->state > CPUHP_TEARDOWN_CPU && st->state < prev_state) { | 893 | if (ret && st->state > CPUHP_TEARDOWN_CPU && st->state < prev_state) { |
730 | st->target = prev_state; | 894 | cpuhp_reset_state(st, prev_state); |
731 | st->rollback = true; | 895 | __cpuhp_kick_ap(st); |
732 | cpuhp_kick_ap_work(cpu); | ||
733 | } | 896 | } |
734 | 897 | ||
735 | out: | 898 | out: |
@@ -754,11 +917,15 @@ out: | |||
754 | cpu_maps_update_done(); | 917 | cpu_maps_update_done(); |
755 | return err; | 918 | return err; |
756 | } | 919 | } |
920 | |||
757 | int cpu_down(unsigned int cpu) | 921 | int cpu_down(unsigned int cpu) |
758 | { | 922 | { |
759 | return do_cpu_down(cpu, CPUHP_OFFLINE); | 923 | return do_cpu_down(cpu, CPUHP_OFFLINE); |
760 | } | 924 | } |
761 | EXPORT_SYMBOL(cpu_down); | 925 | EXPORT_SYMBOL(cpu_down); |
926 | |||
927 | #else | ||
928 | #define takedown_cpu NULL | ||
762 | #endif /*CONFIG_HOTPLUG_CPU*/ | 929 | #endif /*CONFIG_HOTPLUG_CPU*/ |
763 | 930 | ||
764 | /** | 931 | /** |
@@ -772,11 +939,16 @@ void notify_cpu_starting(unsigned int cpu) | |||
772 | { | 939 | { |
773 | struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); | 940 | struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); |
774 | enum cpuhp_state target = min((int)st->target, CPUHP_AP_ONLINE); | 941 | enum cpuhp_state target = min((int)st->target, CPUHP_AP_ONLINE); |
942 | int ret; | ||
775 | 943 | ||
776 | rcu_cpu_starting(cpu); /* Enables RCU usage on this CPU. */ | 944 | rcu_cpu_starting(cpu); /* Enables RCU usage on this CPU. */ |
777 | while (st->state < target) { | 945 | while (st->state < target) { |
778 | st->state++; | 946 | st->state++; |
779 | cpuhp_invoke_callback(cpu, st->state, true, NULL); | 947 | ret = cpuhp_invoke_callback(cpu, st->state, true, NULL, NULL); |
948 | /* | ||
949 | * STARTING must not fail! | ||
950 | */ | ||
951 | WARN_ON_ONCE(ret); | ||
780 | } | 952 | } |
781 | } | 953 | } |
782 | 954 | ||
@@ -794,7 +966,7 @@ void cpuhp_online_idle(enum cpuhp_state state) | |||
794 | return; | 966 | return; |
795 | 967 | ||
796 | st->state = CPUHP_AP_ONLINE_IDLE; | 968 | st->state = CPUHP_AP_ONLINE_IDLE; |
797 | complete(&st->done); | 969 | complete_ap_thread(st, true); |
798 | } | 970 | } |
799 | 971 | ||
800 | /* Requires cpu_add_remove_lock to be held */ | 972 | /* Requires cpu_add_remove_lock to be held */ |
@@ -829,7 +1001,7 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen, enum cpuhp_state target) | |||
829 | 1001 | ||
830 | cpuhp_tasks_frozen = tasks_frozen; | 1002 | cpuhp_tasks_frozen = tasks_frozen; |
831 | 1003 | ||
832 | st->target = target; | 1004 | cpuhp_set_state(st, target); |
833 | /* | 1005 | /* |
834 | * If the current CPU state is in the range of the AP hotplug thread, | 1006 | * If the current CPU state is in the range of the AP hotplug thread, |
835 | * then we need to kick the thread once more. | 1007 | * then we need to kick the thread once more. |
@@ -1296,6 +1468,10 @@ static int cpuhp_issue_call(int cpu, enum cpuhp_state state, bool bringup, | |||
1296 | struct cpuhp_step *sp = cpuhp_get_step(state); | 1468 | struct cpuhp_step *sp = cpuhp_get_step(state); |
1297 | int ret; | 1469 | int ret; |
1298 | 1470 | ||
1471 | /* | ||
1472 | * If there's nothing to do, we done. | ||
1473 | * Relies on the union for multi_instance. | ||
1474 | */ | ||
1299 | if ((bringup && !sp->startup.single) || | 1475 | if ((bringup && !sp->startup.single) || |
1300 | (!bringup && !sp->teardown.single)) | 1476 | (!bringup && !sp->teardown.single)) |
1301 | return 0; | 1477 | return 0; |
@@ -1307,9 +1483,9 @@ static int cpuhp_issue_call(int cpu, enum cpuhp_state state, bool bringup, | |||
1307 | if (cpuhp_is_ap_state(state)) | 1483 | if (cpuhp_is_ap_state(state)) |
1308 | ret = cpuhp_invoke_ap_callback(cpu, state, bringup, node); | 1484 | ret = cpuhp_invoke_ap_callback(cpu, state, bringup, node); |
1309 | else | 1485 | else |
1310 | ret = cpuhp_invoke_callback(cpu, state, bringup, node); | 1486 | ret = cpuhp_invoke_callback(cpu, state, bringup, node, NULL); |
1311 | #else | 1487 | #else |
1312 | ret = cpuhp_invoke_callback(cpu, state, bringup, node); | 1488 | ret = cpuhp_invoke_callback(cpu, state, bringup, node, NULL); |
1313 | #endif | 1489 | #endif |
1314 | BUG_ON(ret && !bringup); | 1490 | BUG_ON(ret && !bringup); |
1315 | return ret; | 1491 | return ret; |
@@ -1641,9 +1817,55 @@ static ssize_t show_cpuhp_target(struct device *dev, | |||
1641 | } | 1817 | } |
1642 | static DEVICE_ATTR(target, 0644, show_cpuhp_target, write_cpuhp_target); | 1818 | static DEVICE_ATTR(target, 0644, show_cpuhp_target, write_cpuhp_target); |
1643 | 1819 | ||
1820 | |||
1821 | static ssize_t write_cpuhp_fail(struct device *dev, | ||
1822 | struct device_attribute *attr, | ||
1823 | const char *buf, size_t count) | ||
1824 | { | ||
1825 | struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id); | ||
1826 | struct cpuhp_step *sp; | ||
1827 | int fail, ret; | ||
1828 | |||
1829 | ret = kstrtoint(buf, 10, &fail); | ||
1830 | if (ret) | ||
1831 | return ret; | ||
1832 | |||
1833 | /* | ||
1834 | * Cannot fail STARTING/DYING callbacks. | ||
1835 | */ | ||
1836 | if (cpuhp_is_atomic_state(fail)) | ||
1837 | return -EINVAL; | ||
1838 | |||
1839 | /* | ||
1840 | * Cannot fail anything that doesn't have callbacks. | ||
1841 | */ | ||
1842 | mutex_lock(&cpuhp_state_mutex); | ||
1843 | sp = cpuhp_get_step(fail); | ||
1844 | if (!sp->startup.single && !sp->teardown.single) | ||
1845 | ret = -EINVAL; | ||
1846 | mutex_unlock(&cpuhp_state_mutex); | ||
1847 | if (ret) | ||
1848 | return ret; | ||
1849 | |||
1850 | st->fail = fail; | ||
1851 | |||
1852 | return count; | ||
1853 | } | ||
1854 | |||
1855 | static ssize_t show_cpuhp_fail(struct device *dev, | ||
1856 | struct device_attribute *attr, char *buf) | ||
1857 | { | ||
1858 | struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id); | ||
1859 | |||
1860 | return sprintf(buf, "%d\n", st->fail); | ||
1861 | } | ||
1862 | |||
1863 | static DEVICE_ATTR(fail, 0644, show_cpuhp_fail, write_cpuhp_fail); | ||
1864 | |||
1644 | static struct attribute *cpuhp_cpu_attrs[] = { | 1865 | static struct attribute *cpuhp_cpu_attrs[] = { |
1645 | &dev_attr_state.attr, | 1866 | &dev_attr_state.attr, |
1646 | &dev_attr_target.attr, | 1867 | &dev_attr_target.attr, |
1868 | &dev_attr_fail.attr, | ||
1647 | NULL | 1869 | NULL |
1648 | }; | 1870 | }; |
1649 | 1871 | ||