Skip to content

Commit 1cf4f62

Browse files
committed
cpu/hotplug: Move online calls to hotplugged cpu
Let the hotplugged cpu invoke the setup/teardown callbacks (CPU_ONLINE/CPU_DOWN_PREPARE) itself. Signed-off-by: Thomas Gleixner <[email protected]> Cc: [email protected] Cc: Rik van Riel <[email protected]> Cc: Rafael Wysocki <[email protected]> Cc: "Srivatsa S. Bhat" <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Arjan van de Ven <[email protected]> Cc: Sebastian Siewior <[email protected]> Cc: Rusty Russell <[email protected]> Cc: Steven Rostedt <[email protected]> Cc: Oleg Nesterov <[email protected]> Cc: Tejun Heo <[email protected]> Cc: Andrew Morton <[email protected]> Cc: Paul McKenney <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Paul Turner <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Thomas Gleixner <[email protected]>
1 parent 4cb28ce commit 1cf4f62

File tree

2 files changed

+102
-52
lines changed

2 files changed

+102
-52
lines changed

include/linux/cpuhotplug.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ enum cpuhp_state {
1111
CPUHP_AP_ONLINE,
1212
CPUHP_TEARDOWN_CPU,
1313
CPUHP_CPU_SET_ACTIVE,
14-
CPUHP_SMPBOOT_THREADS,
15-
CPUHP_NOTIFY_ONLINE,
16-
CPUHP_ONLINE_DYN,
17-
CPUHP_ONLINE_DYN_END = CPUHP_ONLINE_DYN + 30,
14+
CPUHP_KICK_AP_THREAD,
15+
CPUHP_BP_ONLINE,
16+
CPUHP_AP_SMPBOOT_THREADS,
17+
CPUHP_AP_NOTIFY_ONLINE,
18+
CPUHP_AP_ONLINE_DYN,
19+
CPUHP_AP_ONLINE_DYN_END = CPUHP_AP_ONLINE_DYN + 30,
1820
CPUHP_ONLINE,
1921
};
2022

kernel/cpu.c

Lines changed: 96 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ static int cpuhp_should_run(unsigned int cpu)
429429
/* Execute the teardown callbacks. Used to be CPU_DOWN_PREPARE */
430430
static int cpuhp_ap_offline(unsigned int cpu, struct cpuhp_cpu_state *st)
431431
{
432-
enum cpuhp_state target = max((int)st->target, CPUHP_AP_ONLINE);
432+
enum cpuhp_state target = max((int)st->target, CPUHP_TEARDOWN_CPU);
433433

434434
return cpuhp_down_callbacks(cpu, st, cpuhp_ap_states, target);
435435
}
@@ -469,6 +469,9 @@ static void cpuhp_thread_fun(unsigned int cpu)
469469
ret = cpuhp_invoke_callback(cpu, st->cb_state, st->cb);
470470
}
471471
} else {
472+
/* Cannot happen .... */
473+
BUG_ON(st->state < CPUHP_KICK_AP_THREAD);
474+
472475
/* Regular hotplug work */
473476
if (st->state < st->target)
474477
ret = cpuhp_ap_online(cpu, st);
@@ -502,12 +505,8 @@ static int cpuhp_invoke_ap_callback(int cpu, enum cpuhp_state state,
502505
}
503506

504507
/* Regular hotplug invocation of the AP hotplug thread */
505-
static int cpuhp_kick_ap_work(unsigned int cpu)
508+
static void __cpuhp_kick_ap_work(struct cpuhp_cpu_state *st)
506509
{
507-
struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
508-
enum cpuhp_state state = st->state;
509-
510-
trace_cpuhp_enter(cpu, st->target, state, cpuhp_kick_ap_work);
511510
st->result = 0;
512511
st->cb = NULL;
513512
/*
@@ -517,6 +516,15 @@ static int cpuhp_kick_ap_work(unsigned int cpu)
517516
smp_mb();
518517
st->should_run = true;
519518
wake_up_process(st->thread);
519+
}
520+
521+
static int cpuhp_kick_ap_work(unsigned int cpu)
522+
{
523+
struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
524+
enum cpuhp_state state = st->state;
525+
526+
trace_cpuhp_enter(cpu, st->target, state, cpuhp_kick_ap_work);
527+
__cpuhp_kick_ap_work(st);
520528
wait_for_completion(&st->done);
521529
trace_cpuhp_exit(cpu, st->state, state, st->result);
522530
return st->result;
@@ -688,6 +696,9 @@ static int takedown_cpu(unsigned int cpu)
688696
else
689697
synchronize_rcu();
690698

699+
/* Park the hotplug thread */
700+
kthread_park(per_cpu_ptr(&cpuhp_state, cpu)->thread);
701+
691702
/*
692703
* Prevent irq alloc/free while the dying cpu reorganizes the
693704
* interrupt affinities.
@@ -765,10 +776,34 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen,
765776

766777
prev_state = st->state;
767778
st->target = target;
779+
/*
780+
* If the current CPU state is in the range of the AP hotplug thread,
781+
* then we need to kick the thread.
782+
*/
783+
if (st->state >= CPUHP_KICK_AP_THREAD) {
784+
ret = cpuhp_kick_ap_work(cpu);
785+
/*
786+
* The AP side has done the error rollback already. Just
787+
* return the error code..
788+
*/
789+
if (ret)
790+
goto out;
791+
792+
/*
793+
* We might have stopped still in the range of the AP hotplug
794+
* thread. Nothing to do anymore.
795+
*/
796+
if (st->state >= CPUHP_KICK_AP_THREAD)
797+
goto out;
798+
}
799+
/*
800+
* The AP brought itself down below CPUHP_KICK_AP_THREAD. So we need
801+
* to do the further cleanups.
802+
*/
768803
ret = cpuhp_down_callbacks(cpu, st, cpuhp_bp_states, target);
769804

770805
hasdied = prev_state != st->state && st->state == CPUHP_OFFLINE;
771-
806+
out:
772807
cpu_hotplug_done();
773808
/* This post dead nonsense must die */
774809
if (!ret && hasdied)
@@ -828,10 +863,13 @@ void notify_cpu_starting(unsigned int cpu)
828863
*/
829864
static int cpuhp_set_cpu_active(unsigned int cpu)
830865
{
866+
struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
867+
831868
/* The cpu is marked online, set it active now */
832869
set_cpu_active(cpu, true);
833-
/* Unpark the stopper thread */
870+
/* Unpark the stopper thread and the hotplug thread */
834871
stop_machine_unpark(cpu);
872+
kthread_unpark(st->thread);
835873
return 0;
836874
}
837875

@@ -868,6 +906,26 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen, enum cpuhp_state target)
868906
cpuhp_tasks_frozen = tasks_frozen;
869907

870908
st->target = target;
909+
/*
910+
* If the current CPU state is in the range of the AP hotplug thread,
911+
* then we need to kick the thread once more.
912+
*/
913+
if (st->state >= CPUHP_KICK_AP_THREAD) {
914+
ret = cpuhp_kick_ap_work(cpu);
915+
/*
916+
* The AP side has done the error rollback already. Just
917+
* return the error code..
918+
*/
919+
if (ret)
920+
goto out;
921+
}
922+
923+
/*
924+
* Try to reach the target state. We max out on the BP at
925+
* CPUHP_KICK_AP_THREAD. After that the AP hotplug thread is
926+
* responsible for bringing it up to the target state.
927+
*/
928+
target = min((int)target, CPUHP_KICK_AP_THREAD);
871929
ret = cpuhp_up_callbacks(cpu, st, cpuhp_bp_states, target);
872930
out:
873931
cpu_hotplug_done();
@@ -1093,19 +1151,13 @@ static struct cpuhp_step cpuhp_bp_states[] = {
10931151
.startup = cpuhp_set_cpu_active,
10941152
.teardown = NULL,
10951153
},
1096-
[CPUHP_SMPBOOT_THREADS] = {
1097-
.name = "smpboot:threads",
1098-
.startup = smpboot_unpark_threads,
1099-
.teardown = smpboot_park_threads,
1100-
},
1101-
[CPUHP_NOTIFY_ONLINE] = {
1102-
.name = "notify:online",
1103-
.startup = notify_online,
1104-
.teardown = notify_down_prepare,
1105-
.cant_stop = true,
1154+
[CPUHP_KICK_AP_THREAD] = {
1155+
.name = "cpuhp:kickthread",
1156+
.startup = cpuhp_kick_ap_work,
1157+
.teardown = cpuhp_kick_ap_work,
11061158
},
11071159
#endif
1108-
[CPUHP_ONLINE] = {
1160+
[CPUHP_BP_ONLINE] = {
11091161
.name = "online",
11101162
.startup = NULL,
11111163
.teardown = NULL,
@@ -1122,6 +1174,16 @@ static struct cpuhp_step cpuhp_ap_states[] = {
11221174
.skip_onerr = true,
11231175
.cant_stop = true,
11241176
},
1177+
[CPUHP_AP_SMPBOOT_THREADS] = {
1178+
.name = "smpboot:threads",
1179+
.startup = smpboot_unpark_threads,
1180+
.teardown = smpboot_park_threads,
1181+
},
1182+
[CPUHP_AP_NOTIFY_ONLINE] = {
1183+
.name = "notify:online",
1184+
.startup = notify_online,
1185+
.teardown = notify_down_prepare,
1186+
},
11251187
#endif
11261188
[CPUHP_ONLINE] = {
11271189
.name = "online",
@@ -1140,7 +1202,9 @@ static int cpuhp_cb_check(enum cpuhp_state state)
11401202

11411203
static bool cpuhp_is_ap_state(enum cpuhp_state state)
11421204
{
1143-
return (state >= CPUHP_AP_OFFLINE && state <= CPUHP_AP_ONLINE);
1205+
if (state >= CPUHP_AP_OFFLINE && state <= CPUHP_AP_ONLINE)
1206+
return true;
1207+
return state > CPUHP_BP_ONLINE;
11441208
}
11451209

11461210
static struct cpuhp_step *cpuhp_get_step(enum cpuhp_state state)
@@ -1172,14 +1236,6 @@ static void *cpuhp_get_teardown_cb(enum cpuhp_state state)
11721236
return cpuhp_get_step(state)->teardown;
11731237
}
11741238

1175-
/* Helper function to run callback on the target cpu */
1176-
static void cpuhp_on_cpu_cb(void *__cb)
1177-
{
1178-
int (*cb)(unsigned int cpu) = __cb;
1179-
1180-
BUG_ON(cb(smp_processor_id()));
1181-
}
1182-
11831239
/*
11841240
* Call the startup/teardown function for a step either on the AP or
11851241
* on the current CPU.
@@ -1191,26 +1247,18 @@ static int cpuhp_issue_call(int cpu, enum cpuhp_state state,
11911247

11921248
if (!cb)
11931249
return 0;
1194-
1195-
/*
1196-
* This invokes the callback directly for now. In a later step we
1197-
* convert that to use cpuhp_invoke_callback().
1198-
*/
1199-
if (cpuhp_is_ap_state(state)) {
1200-
/*
1201-
* Note, that a function called on the AP is not
1202-
* allowed to fail.
1203-
*/
1204-
if (cpu_online(cpu))
1205-
smp_call_function_single(cpu, cpuhp_on_cpu_cb, cb, 1);
1206-
return 0;
1207-
}
1208-
12091250
/*
12101251
* The non AP bound callbacks can fail on bringup. On teardown
12111252
* e.g. module removal we crash for now.
12121253
*/
1213-
ret = cb(cpu);
1254+
#ifdef CONFIG_SMP
1255+
if (cpuhp_is_ap_state(state))
1256+
ret = cpuhp_invoke_ap_callback(cpu, state, cb);
1257+
else
1258+
ret = cpuhp_invoke_callback(cpu, state, cb);
1259+
#else
1260+
ret = cpuhp_invoke_callback(cpu, state, cb);
1261+
#endif
12141262
BUG_ON(ret && !bringup);
12151263
return ret;
12161264
}
@@ -1252,11 +1300,11 @@ static int cpuhp_reserve_state(enum cpuhp_state state)
12521300
enum cpuhp_state i;
12531301

12541302
mutex_lock(&cpuhp_state_mutex);
1255-
for (i = CPUHP_ONLINE_DYN; i <= CPUHP_ONLINE_DYN_END; i++) {
1256-
if (cpuhp_bp_states[i].name)
1303+
for (i = CPUHP_AP_ONLINE_DYN; i <= CPUHP_AP_ONLINE_DYN_END; i++) {
1304+
if (cpuhp_ap_states[i].name)
12571305
continue;
12581306

1259-
cpuhp_bp_states[i].name = "Reserved";
1307+
cpuhp_ap_states[i].name = "Reserved";
12601308
mutex_unlock(&cpuhp_state_mutex);
12611309
return i;
12621310
}
@@ -1289,7 +1337,7 @@ int __cpuhp_setup_state(enum cpuhp_state state,
12891337
get_online_cpus();
12901338

12911339
/* currently assignments for the ONLINE state are possible */
1292-
if (state == CPUHP_ONLINE_DYN) {
1340+
if (state == CPUHP_AP_ONLINE_DYN) {
12931341
dyn_state = 1;
12941342
ret = cpuhp_reserve_state(state);
12951343
if (ret < 0)

0 commit comments

Comments
 (0)