Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cpu/hotplug: Rework callback invocation logic

This is preparation for the following patch.
This rework here changes the arguments of cpuhp_invoke_callback(). It
passes now `state' and whether `startup' or `teardown' callback should
be invoked. The callback then is looked up by the function.

The following is a clanup of callers:
- cpuhp_issue_call() has one argument less
- struct cpuhp_cpu_state (which is used by the hotplug thread) gets also
its callback removed. The decision if it is a single callback
invocation moved to the `single' variable. Also a `bringup' variable
has been added to distinguish between startup and teardown callback.
- take_cpu_down() needs to start one step earlier. We always get here
via CPUHP_TEARDOWN_CPU callback. Before that change cpuhp_ap_states +
CPUHP_TEARDOWN_CPU pointed to an empty entry because TEARDOWN is saved
in bp_states for this reason. Now that we use cpuhp_get_step() to
lookup the state we must explicitly skip it in order not to invoke it
twice.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: rt@linutronix.de
Link: http://lkml.kernel.org/r/1471024183-12666-2-git-send-email-bigeasy@linutronix.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

+80 -82
+80 -82
kernel/cpu.c
··· 37 37 * @thread: Pointer to the hotplug thread 38 38 * @should_run: Thread should execute 39 39 * @rollback: Perform a rollback 40 - * @cb_stat: The state for a single callback (install/uninstall) 41 - * @cb: Single callback function (install/uninstall) 40 + * @single: Single callback invocation 41 + * @bringup: Single callback bringup or teardown selector 42 + * @cb_state: The state for a single callback (install/uninstall) 42 43 * @result: Result of the operation 43 44 * @done: Signal completion to the issuer of the task 44 45 */ ··· 50 49 struct task_struct *thread; 51 50 bool should_run; 52 51 bool rollback; 52 + bool single; 53 + bool bringup; 53 54 enum cpuhp_state cb_state; 54 - int (*cb)(unsigned int cpu); 55 55 int result; 56 56 struct completion done; 57 57 #endif ··· 81 79 static struct cpuhp_step cpuhp_bp_states[]; 82 80 static struct cpuhp_step cpuhp_ap_states[]; 83 81 82 + static bool cpuhp_is_ap_state(enum cpuhp_state state) 83 + { 84 + /* 85 + * The extra check for CPUHP_TEARDOWN_CPU is only for documentation 86 + * purposes as that state is handled explicitly in cpu_down. 87 + */ 88 + return state > CPUHP_BRINGUP_CPU && state != CPUHP_TEARDOWN_CPU; 89 + } 90 + 91 + static struct cpuhp_step *cpuhp_get_step(enum cpuhp_state state) 92 + { 93 + struct cpuhp_step *sp; 94 + 95 + sp = cpuhp_is_ap_state(state) ? cpuhp_ap_states : cpuhp_bp_states; 96 + return sp + state; 97 + } 98 + 84 99 /** 85 100 * cpuhp_invoke_callback _ Invoke the callbacks for a given state 86 101 * @cpu: The cpu for which the callback should be invoked 87 102 * @step: The step in the state machine 88 - * @cb: The callback function to invoke 103 + * @bringup: True if the bringup callback should be invoked 89 104 * 90 105 * Called from cpu hotplug and from the state register machinery 91 106 */ 92 - static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state step, 93 - int (*cb)(unsigned int)) 107 + static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state, 108 + bool bringup) 94 109 { 95 110 struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 111 + struct cpuhp_step *step = cpuhp_get_step(state); 112 + int (*cb)(unsigned int cpu) = bringup ? step->startup : step->teardown; 96 113 int ret = 0; 97 114 98 115 if (cb) { 99 - trace_cpuhp_enter(cpu, st->target, step, cb); 116 + trace_cpuhp_enter(cpu, st->target, state, cb); 100 117 ret = cb(cpu); 101 - trace_cpuhp_exit(cpu, st->state, step, ret); 118 + trace_cpuhp_exit(cpu, st->state, state, ret); 102 119 } 103 120 return ret; 104 121 } ··· 392 371 /* 393 372 * Hotplug state machine related functions 394 373 */ 395 - static void undo_cpu_down(unsigned int cpu, struct cpuhp_cpu_state *st, 396 - struct cpuhp_step *steps) 374 + static void undo_cpu_down(unsigned int cpu, struct cpuhp_cpu_state *st) 397 375 { 398 376 for (st->state++; st->state < st->target; st->state++) { 399 - struct cpuhp_step *step = steps + st->state; 377 + struct cpuhp_step *step = cpuhp_get_step(st->state); 400 378 401 379 if (!step->skip_onerr) 402 - cpuhp_invoke_callback(cpu, st->state, step->startup); 380 + cpuhp_invoke_callback(cpu, st->state, true); 403 381 } 404 382 } 405 383 406 384 static int cpuhp_down_callbacks(unsigned int cpu, struct cpuhp_cpu_state *st, 407 - struct cpuhp_step *steps, enum cpuhp_state target) 385 + enum cpuhp_state target) 408 386 { 409 387 enum cpuhp_state prev_state = st->state; 410 388 int ret = 0; 411 389 412 390 for (; st->state > target; st->state--) { 413 - struct cpuhp_step *step = steps + st->state; 414 - 415 - ret = cpuhp_invoke_callback(cpu, st->state, step->teardown); 391 + ret = cpuhp_invoke_callback(cpu, st->state, false); 416 392 if (ret) { 417 393 st->target = prev_state; 418 - undo_cpu_down(cpu, st, steps); 394 + undo_cpu_down(cpu, st); 419 395 break; 420 396 } 421 397 } 422 398 return ret; 423 399 } 424 400 425 - static void undo_cpu_up(unsigned int cpu, struct cpuhp_cpu_state *st, 426 - struct cpuhp_step *steps) 401 + static void undo_cpu_up(unsigned int cpu, struct cpuhp_cpu_state *st) 427 402 { 428 403 for (st->state--; st->state > st->target; st->state--) { 429 - struct cpuhp_step *step = steps + st->state; 404 + struct cpuhp_step *step = cpuhp_get_step(st->state); 430 405 431 406 if (!step->skip_onerr) 432 - cpuhp_invoke_callback(cpu, st->state, step->teardown); 407 + cpuhp_invoke_callback(cpu, st->state, false); 433 408 } 434 409 } 435 410 436 411 static int cpuhp_up_callbacks(unsigned int cpu, struct cpuhp_cpu_state *st, 437 - struct cpuhp_step *steps, enum cpuhp_state target) 412 + enum cpuhp_state target) 438 413 { 439 414 enum cpuhp_state prev_state = st->state; 440 415 int ret = 0; 441 416 442 417 while (st->state < target) { 443 - struct cpuhp_step *step; 444 - 445 418 st->state++; 446 - step = steps + st->state; 447 - ret = cpuhp_invoke_callback(cpu, st->state, step->startup); 419 + ret = cpuhp_invoke_callback(cpu, st->state, true); 448 420 if (ret) { 449 421 st->target = prev_state; 450 - undo_cpu_up(cpu, st, steps); 422 + undo_cpu_up(cpu, st); 451 423 break; 452 424 } 453 425 } ··· 469 455 { 470 456 enum cpuhp_state target = max((int)st->target, CPUHP_TEARDOWN_CPU); 471 457 472 - return cpuhp_down_callbacks(cpu, st, cpuhp_ap_states, target); 458 + return cpuhp_down_callbacks(cpu, st, target); 473 459 } 474 460 475 461 /* Execute the online startup callbacks. Used to be CPU_ONLINE */ 476 462 static int cpuhp_ap_online(unsigned int cpu, struct cpuhp_cpu_state *st) 477 463 { 478 - return cpuhp_up_callbacks(cpu, st, cpuhp_ap_states, st->target); 464 + return cpuhp_up_callbacks(cpu, st, st->target); 479 465 } 480 466 481 467 /* ··· 498 484 st->should_run = false; 499 485 500 486 /* Single callback invocation for [un]install ? */ 501 - if (st->cb) { 487 + if (st->single) { 502 488 if (st->cb_state < CPUHP_AP_ONLINE) { 503 489 local_irq_disable(); 504 - ret = cpuhp_invoke_callback(cpu, st->cb_state, st->cb); 490 + ret = cpuhp_invoke_callback(cpu, st->cb_state, 491 + st->bringup); 505 492 local_irq_enable(); 506 493 } else { 507 - ret = cpuhp_invoke_callback(cpu, st->cb_state, st->cb); 494 + ret = cpuhp_invoke_callback(cpu, st->cb_state, 495 + st->bringup); 508 496 } 509 497 } else if (st->rollback) { 510 498 BUG_ON(st->state < CPUHP_AP_ONLINE_IDLE); 511 499 512 - undo_cpu_down(cpu, st, cpuhp_ap_states); 500 + undo_cpu_down(cpu, st); 513 501 /* 514 502 * This is a momentary workaround to keep the notifier users 515 503 * happy. Will go away once we got rid of the notifiers. ··· 533 517 } 534 518 535 519 /* Invoke a single callback on a remote cpu */ 536 - static int cpuhp_invoke_ap_callback(int cpu, enum cpuhp_state state, 537 - int (*cb)(unsigned int)) 520 + static int 521 + cpuhp_invoke_ap_callback(int cpu, enum cpuhp_state state, bool bringup) 538 522 { 539 523 struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 540 524 ··· 546 530 * we invoke the thread function directly. 547 531 */ 548 532 if (!st->thread) 549 - return cpuhp_invoke_callback(cpu, state, cb); 533 + return cpuhp_invoke_callback(cpu, state, bringup); 550 534 551 535 st->cb_state = state; 552 - st->cb = cb; 536 + st->single = true; 537 + st->bringup = bringup; 538 + 553 539 /* 554 540 * Make sure the above stores are visible before should_run becomes 555 541 * true. Paired with the mb() above in cpuhp_thread_fun() ··· 567 549 static void __cpuhp_kick_ap_work(struct cpuhp_cpu_state *st) 568 550 { 569 551 st->result = 0; 570 - st->cb = NULL; 552 + st->single = false; 571 553 /* 572 554 * Make sure the above stores are visible before should_run becomes 573 555 * true. Paired with the mb() above in cpuhp_thread_fun() ··· 718 700 if (err < 0) 719 701 return err; 720 702 703 + /* 704 + * We get here while we are in CPUHP_TEARDOWN_CPU state and we must not 705 + * do this step again. 706 + */ 707 + WARN_ON(st->state != CPUHP_TEARDOWN_CPU); 708 + st->state--; 721 709 /* Invoke the former CPU_DYING callbacks */ 722 - for (; st->state > target; st->state--) { 723 - struct cpuhp_step *step = cpuhp_ap_states + st->state; 710 + for (; st->state > target; st->state--) 711 + cpuhp_invoke_callback(cpu, st->state, false); 724 712 725 - cpuhp_invoke_callback(cpu, st->state, step->teardown); 726 - } 727 713 /* Give up timekeeping duties */ 728 714 tick_handover_do_timer(); 729 715 /* Park the stopper thread */ ··· 866 844 * The AP brought itself down to CPUHP_TEARDOWN_CPU. So we need 867 845 * to do the further cleanups. 868 846 */ 869 - ret = cpuhp_down_callbacks(cpu, st, cpuhp_bp_states, target); 847 + ret = cpuhp_down_callbacks(cpu, st, target); 870 848 if (ret && st->state > CPUHP_TEARDOWN_CPU && st->state < prev_state) { 871 849 st->target = prev_state; 872 850 st->rollback = true; ··· 920 898 enum cpuhp_state target = min((int)st->target, CPUHP_AP_ONLINE); 921 899 922 900 while (st->state < target) { 923 - struct cpuhp_step *step; 924 - 925 901 st->state++; 926 - step = cpuhp_ap_states + st->state; 927 - cpuhp_invoke_callback(cpu, st->state, step->startup); 902 + cpuhp_invoke_callback(cpu, st->state, true); 928 903 } 929 904 } 930 905 ··· 1006 987 * responsible for bringing it up to the target state. 1007 988 */ 1008 989 target = min((int)target, CPUHP_BRINGUP_CPU); 1009 - ret = cpuhp_up_callbacks(cpu, st, cpuhp_bp_states, target); 990 + ret = cpuhp_up_callbacks(cpu, st, target); 1010 991 out: 1011 992 cpu_hotplug_done(); 1012 993 return ret; ··· 1383 1364 return 0; 1384 1365 } 1385 1366 1386 - static bool cpuhp_is_ap_state(enum cpuhp_state state) 1387 - { 1388 - /* 1389 - * The extra check for CPUHP_TEARDOWN_CPU is only for documentation 1390 - * purposes as that state is handled explicitely in cpu_down. 1391 - */ 1392 - return state > CPUHP_BRINGUP_CPU && state != CPUHP_TEARDOWN_CPU; 1393 - } 1394 - 1395 - static struct cpuhp_step *cpuhp_get_step(enum cpuhp_state state) 1396 - { 1397 - struct cpuhp_step *sp; 1398 - 1399 - sp = cpuhp_is_ap_state(state) ? cpuhp_ap_states : cpuhp_bp_states; 1400 - return sp + state; 1401 - } 1402 - 1403 1367 static void cpuhp_store_callbacks(enum cpuhp_state state, 1404 1368 const char *name, 1405 1369 int (*startup)(unsigned int cpu), ··· 1408 1406 * Call the startup/teardown function for a step either on the AP or 1409 1407 * on the current CPU. 1410 1408 */ 1411 - static int cpuhp_issue_call(int cpu, enum cpuhp_state state, 1412 - int (*cb)(unsigned int), bool bringup) 1409 + static int cpuhp_issue_call(int cpu, enum cpuhp_state state, bool bringup) 1413 1410 { 1411 + struct cpuhp_step *sp = cpuhp_get_step(state); 1414 1412 int ret; 1415 1413 1416 - if (!cb) 1414 + if ((bringup && !sp->startup) || (!bringup && !sp->teardown)) 1417 1415 return 0; 1418 1416 /* 1419 1417 * The non AP bound callbacks can fail on bringup. On teardown ··· 1421 1419 */ 1422 1420 #ifdef CONFIG_SMP 1423 1421 if (cpuhp_is_ap_state(state)) 1424 - ret = cpuhp_invoke_ap_callback(cpu, state, cb); 1422 + ret = cpuhp_invoke_ap_callback(cpu, state, bringup); 1425 1423 else 1426 - ret = cpuhp_invoke_callback(cpu, state, cb); 1424 + ret = cpuhp_invoke_callback(cpu, state, bringup); 1427 1425 #else 1428 - ret = cpuhp_invoke_callback(cpu, state, cb); 1426 + ret = cpuhp_invoke_callback(cpu, state, bringup); 1429 1427 #endif 1430 1428 BUG_ON(ret && !bringup); 1431 1429 return ret; ··· 1436 1434 * 1437 1435 * Note: The teardown callbacks for rollback are not allowed to fail! 1438 1436 */ 1439 - static void cpuhp_rollback_install(int failedcpu, enum cpuhp_state state, 1440 - int (*teardown)(unsigned int cpu)) 1437 + static void cpuhp_rollback_install(int failedcpu, enum cpuhp_state state) 1441 1438 { 1442 1439 int cpu; 1443 - 1444 - if (!teardown) 1445 - return; 1446 1440 1447 1441 /* Roll back the already executed steps on the other cpus */ 1448 1442 for_each_present_cpu(cpu) { ··· 1450 1452 1451 1453 /* Did we invoke the startup call on that cpu ? */ 1452 1454 if (cpustate >= state) 1453 - cpuhp_issue_call(cpu, state, teardown, false); 1455 + cpuhp_issue_call(cpu, state, false); 1454 1456 } 1455 1457 } 1456 1458 ··· 1525 1527 if (cpustate < state) 1526 1528 continue; 1527 1529 1528 - ret = cpuhp_issue_call(cpu, state, startup, true); 1530 + ret = cpuhp_issue_call(cpu, state, true); 1529 1531 if (ret) { 1530 - cpuhp_rollback_install(cpu, state, teardown); 1532 + if (teardown) 1533 + cpuhp_rollback_install(cpu, state); 1531 1534 cpuhp_store_callbacks(state, NULL, NULL, NULL); 1532 1535 goto out; 1533 1536 } ··· 1552 1553 */ 1553 1554 void __cpuhp_remove_state(enum cpuhp_state state, bool invoke) 1554 1555 { 1555 - int (*teardown)(unsigned int cpu) = cpuhp_get_teardown_cb(state); 1556 1556 int cpu; 1557 1557 1558 1558 BUG_ON(cpuhp_cb_check(state)); 1559 1559 1560 1560 get_online_cpus(); 1561 1561 1562 - if (!invoke || !teardown) 1562 + if (!invoke || !cpuhp_get_teardown_cb(state)) 1563 1563 goto remove; 1564 1564 1565 1565 /* ··· 1571 1573 int cpustate = st->state; 1572 1574 1573 1575 if (cpustate >= state) 1574 - cpuhp_issue_call(cpu, state, teardown, false); 1576 + cpuhp_issue_call(cpu, state, false); 1575 1577 } 1576 1578 remove: 1577 1579 cpuhp_store_callbacks(state, NULL, NULL, NULL);