smp/hotplug: Differentiate the AP completion between up and down

With lockdep-crossrelease we get deadlock reports that span cpu-up and
cpu-down chains. Such deadlocks cannot possibly happen because cpu-up
and cpu-down are globally serialized.

takedown_cpu()
irq_lock_sparse()
wait_for_completion(&st->done)

cpuhp_thread_fun
cpuhp_up_callback
cpuhp_invoke_callback
irq_affinity_online_cpu
irq_local_spare()
irq_unlock_sparse()
complete(&st->done)

Now that we have consistent AP state, we can trivially separate the
AP completion between up and down using st->bringup.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: max.byungchul.park@gmail.com
Cc: bigeasy@linutronix.de
Cc: efault@gmx.de
Cc: rostedt@goodmis.org
Link: https://lkml.kernel.org/r/20170920170546.872472799@infradead.org


authored by

Peter Zijlstra and committed by
Thomas Gleixner
5ebe7742 5f4b55e1

+32 -17
+32 -17
kernel/cpu.c
··· 46 * @bringup: Single callback bringup or teardown selector 47 * @cb_state: The state for a single callback (install/uninstall) 48 * @result: Result of the operation 49 - * @done: Signal completion to the issuer of the task 50 */ 51 struct cpuhp_cpu_state { 52 enum cpuhp_state state; ··· 62 struct hlist_node *last; 63 enum cpuhp_state cb_state; 64 int result; 65 - struct completion done; 66 #endif 67 }; 68 ··· 130 * purposes as that state is handled explicitly in cpu_down. 131 */ 132 return state > CPUHP_BRINGUP_CPU && state != CPUHP_TEARDOWN_CPU; 133 - } 134 - 135 - /* 136 - * The former STARTING/DYING states, ran with IRQs disabled and must not fail. 137 - */ 138 - static bool cpuhp_is_atomic_state(enum cpuhp_state state) 139 - { 140 - return CPUHP_AP_IDLE_DEAD <= state && state < CPUHP_AP_ONLINE; 141 } 142 143 static struct cpuhp_step *cpuhp_get_step(enum cpuhp_state state) ··· 226 } 227 228 #ifdef CONFIG_SMP 229 /* Serializes the updates to cpu_online_mask, cpu_present_mask */ 230 static DEFINE_MUTEX(cpu_add_remove_lock); 231 bool cpuhp_tasks_frozen; ··· 382 smp_mb(); 383 st->should_run = true; 384 wake_up_process(st->thread); 385 - wait_for_completion(&st->done); 386 } 387 388 static int cpuhp_kick_ap(struct cpuhp_cpu_state *st, enum cpuhp_state target) ··· 405 struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 406 407 /* Wait for the CPU to reach CPUHP_AP_ONLINE_IDLE */ 408 - wait_for_completion(&st->done); 409 if (WARN_ON_ONCE((!cpu_online(cpu)))) 410 return -ECANCELED; 411 ··· 478 { 479 struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 480 481 - init_completion(&st->done); 482 } 483 484 static int cpuhp_should_run(unsigned int cpu) ··· 572 cpuhp_lock_release(bringup); 573 574 if (!st->should_run) 575 - complete(&st->done); 576 } 577 578 /* Invoke a single callback on a remote cpu */ ··· 768 * 769 * Wait for the stop thread to go away. 770 */ 771 - wait_for_completion(&st->done); 772 BUG_ON(st->state != CPUHP_AP_IDLE_DEAD); 773 774 /* Interrupts are moved away from the dying cpu, reenable alloc/free */ ··· 787 { 788 struct cpuhp_cpu_state *st = arg; 789 790 - complete(&st->done); 791 } 792 793 void cpuhp_report_idle_dead(void) ··· 954 return; 955 956 st->state = CPUHP_AP_ONLINE_IDLE; 957 - complete(&st->done); 958 } 959 960 /* Requires cpu_add_remove_lock to be held */
··· 46 * @bringup: Single callback bringup or teardown selector 47 * @cb_state: The state for a single callback (install/uninstall) 48 * @result: Result of the operation 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 51 */ 52 struct cpuhp_cpu_state { 53 enum cpuhp_state state; ··· 61 struct hlist_node *last; 62 enum cpuhp_state cb_state; 63 int result; 64 + struct completion done_up; 65 + struct completion done_down; 66 #endif 67 }; 68 ··· 128 * purposes as that state is handled explicitly in cpu_down. 129 */ 130 return state > CPUHP_BRINGUP_CPU && state != CPUHP_TEARDOWN_CPU; 131 } 132 133 static struct cpuhp_step *cpuhp_get_step(enum cpuhp_state state) ··· 232 } 233 234 #ifdef CONFIG_SMP 235 + static inline void wait_for_ap_thread(struct cpuhp_cpu_state *st, bool bringup) 236 + { 237 + struct completion *done = bringup ? &st->done_up : &st->done_down; 238 + wait_for_completion(done); 239 + } 240 + 241 + static inline void complete_ap_thread(struct cpuhp_cpu_state *st, bool bringup) 242 + { 243 + struct completion *done = bringup ? &st->done_up : &st->done_down; 244 + complete(done); 245 + } 246 + 247 + /* 248 + * The former STARTING/DYING states, ran with IRQs disabled and must not fail. 249 + */ 250 + static bool cpuhp_is_atomic_state(enum cpuhp_state state) 251 + { 252 + return CPUHP_AP_IDLE_DEAD <= state && state < CPUHP_AP_ONLINE; 253 + } 254 + 255 /* Serializes the updates to cpu_online_mask, cpu_present_mask */ 256 static DEFINE_MUTEX(cpu_add_remove_lock); 257 bool cpuhp_tasks_frozen; ··· 368 smp_mb(); 369 st->should_run = true; 370 wake_up_process(st->thread); 371 + wait_for_ap_thread(st, st->bringup); 372 } 373 374 static int cpuhp_kick_ap(struct cpuhp_cpu_state *st, enum cpuhp_state target) ··· 391 struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 392 393 /* Wait for the CPU to reach CPUHP_AP_ONLINE_IDLE */ 394 + wait_for_ap_thread(st, true); 395 if (WARN_ON_ONCE((!cpu_online(cpu)))) 396 return -ECANCELED; 397 ··· 464 { 465 struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 466 467 + init_completion(&st->done_up); 468 + init_completion(&st->done_down); 469 } 470 471 static int cpuhp_should_run(unsigned int cpu) ··· 557 cpuhp_lock_release(bringup); 558 559 if (!st->should_run) 560 + complete_ap_thread(st, bringup); 561 } 562 563 /* Invoke a single callback on a remote cpu */ ··· 753 * 754 * Wait for the stop thread to go away. 755 */ 756 + wait_for_ap_thread(st, false); 757 BUG_ON(st->state != CPUHP_AP_IDLE_DEAD); 758 759 /* Interrupts are moved away from the dying cpu, reenable alloc/free */ ··· 772 { 773 struct cpuhp_cpu_state *st = arg; 774 775 + complete_ap_thread(st, false); 776 } 777 778 void cpuhp_report_idle_dead(void) ··· 939 return; 940 941 st->state = CPUHP_AP_ONLINE_IDLE; 942 + complete_ap_thread(st, true); 943 } 944 945 /* Requires cpu_add_remove_lock to be held */