Skip to content

Commit 96abb96

Browse files
Peter ZijlstraKAGA-KOKO
authored andcommitted
smp/hotplug: Allow external multi-instance rollback
Currently the rollback of multi-instance states is handled inside cpuhp_invoke_callback(). The problem is that when we want to allow an explicit state change for rollback, we need to return from the function without doing the rollback. Change cpuhp_invoke_callback() to optionally return the multi-instance state, such that rollback can be done from a subsequent call. Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Cc: [email protected] Cc: [email protected] Cc: [email protected] Cc: [email protected] Link: https://lkml.kernel.org/r/[email protected]
1 parent fac1c20 commit 96abb96

File tree

1 file changed

+32
-15
lines changed

1 file changed

+32
-15
lines changed

kernel/cpu.c

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -123,13 +123,16 @@ static struct cpuhp_step *cpuhp_get_step(enum cpuhp_state state)
123123
/**
124124
* cpuhp_invoke_callback _ Invoke the callbacks for a given state
125125
* @cpu: The cpu for which the callback should be invoked
126-
* @step: The step in the state machine
126+
* @state: The state to do callbacks for
127127
* @bringup: True if the bringup callback should be invoked
128+
* @node: For multi-instance, do a single entry callback for install/remove
129+
* @lastp: For multi-instance rollback, remember how far we got
128130
*
129131
* Called from cpu hotplug and from the state register machinery.
130132
*/
131133
static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state,
132-
bool bringup, struct hlist_node *node)
134+
bool bringup, struct hlist_node *node,
135+
struct hlist_node **lastp)
133136
{
134137
struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
135138
struct cpuhp_step *step = cpuhp_get_step(state);
@@ -138,6 +141,7 @@ static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state,
138141
int ret, cnt;
139142

140143
if (!step->multi_instance) {
144+
WARN_ON_ONCE(lastp && *lastp);
141145
cb = bringup ? step->startup.single : step->teardown.single;
142146
if (!cb)
143147
return 0;
@@ -152,6 +156,7 @@ static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state,
152156

153157
/* Single invocation for instance add/remove */
154158
if (node) {
159+
WARN_ON_ONCE(lastp && *lastp);
155160
trace_cpuhp_multi_enter(cpu, st->target, state, cbm, node);
156161
ret = cbm(cpu, node);
157162
trace_cpuhp_exit(cpu, st->state, state, ret);
@@ -161,13 +166,23 @@ static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state,
161166
/* State transition. Invoke on all instances */
162167
cnt = 0;
163168
hlist_for_each(node, &step->list) {
169+
if (lastp && node == *lastp)
170+
break;
171+
164172
trace_cpuhp_multi_enter(cpu, st->target, state, cbm, node);
165173
ret = cbm(cpu, node);
166174
trace_cpuhp_exit(cpu, st->state, state, ret);
167-
if (ret)
168-
goto err;
175+
if (ret) {
176+
if (!lastp)
177+
goto err;
178+
179+
*lastp = node;
180+
return ret;
181+
}
169182
cnt++;
170183
}
184+
if (lastp)
185+
*lastp = NULL;
171186
return 0;
172187
err:
173188
/* Rollback the instances if one failed */
@@ -323,7 +338,7 @@ static void undo_cpu_down(unsigned int cpu, struct cpuhp_cpu_state *st)
323338
struct cpuhp_step *step = cpuhp_get_step(st->state);
324339

325340
if (!step->skip_onerr)
326-
cpuhp_invoke_callback(cpu, st->state, true, NULL);
341+
cpuhp_invoke_callback(cpu, st->state, true, NULL, NULL);
327342
}
328343
}
329344

@@ -334,7 +349,7 @@ static int cpuhp_down_callbacks(unsigned int cpu, struct cpuhp_cpu_state *st,
334349
int ret = 0;
335350

336351
for (; st->state > target; st->state--) {
337-
ret = cpuhp_invoke_callback(cpu, st->state, false, NULL);
352+
ret = cpuhp_invoke_callback(cpu, st->state, false, NULL, NULL);
338353
if (ret) {
339354
st->target = prev_state;
340355
undo_cpu_down(cpu, st);
@@ -350,7 +365,7 @@ static void undo_cpu_up(unsigned int cpu, struct cpuhp_cpu_state *st)
350365
struct cpuhp_step *step = cpuhp_get_step(st->state);
351366

352367
if (!step->skip_onerr)
353-
cpuhp_invoke_callback(cpu, st->state, false, NULL);
368+
cpuhp_invoke_callback(cpu, st->state, false, NULL, NULL);
354369
}
355370
}
356371

@@ -362,7 +377,7 @@ static int cpuhp_up_callbacks(unsigned int cpu, struct cpuhp_cpu_state *st,
362377

363378
while (st->state < target) {
364379
st->state++;
365-
ret = cpuhp_invoke_callback(cpu, st->state, true, NULL);
380+
ret = cpuhp_invoke_callback(cpu, st->state, true, NULL, NULL);
366381
if (ret) {
367382
st->target = prev_state;
368383
undo_cpu_up(cpu, st);
@@ -428,11 +443,13 @@ static void cpuhp_thread_fun(unsigned int cpu)
428443
if (st->cb_state < CPUHP_AP_ONLINE) {
429444
local_irq_disable();
430445
ret = cpuhp_invoke_callback(cpu, st->cb_state,
431-
st->bringup, st->node);
446+
st->bringup, st->node,
447+
NULL);
432448
local_irq_enable();
433449
} else {
434450
ret = cpuhp_invoke_callback(cpu, st->cb_state,
435-
st->bringup, st->node);
451+
st->bringup, st->node,
452+
NULL);
436453
}
437454
} else if (st->rollback) {
438455
BUG_ON(st->state < CPUHP_AP_ONLINE_IDLE);
@@ -472,7 +489,7 @@ cpuhp_invoke_ap_callback(int cpu, enum cpuhp_state state, bool bringup,
472489
* we invoke the thread function directly.
473490
*/
474491
if (!st->thread)
475-
return cpuhp_invoke_callback(cpu, state, bringup, node);
492+
return cpuhp_invoke_callback(cpu, state, bringup, node, NULL);
476493

477494
st->cb_state = state;
478495
st->single = true;
@@ -595,7 +612,7 @@ static int take_cpu_down(void *_param)
595612
st->state--;
596613
/* Invoke the former CPU_DYING callbacks */
597614
for (; st->state > target; st->state--)
598-
cpuhp_invoke_callback(cpu, st->state, false, NULL);
615+
cpuhp_invoke_callback(cpu, st->state, false, NULL, NULL);
599616

600617
/* Give up timekeeping duties */
601618
tick_handover_do_timer();
@@ -776,7 +793,7 @@ void notify_cpu_starting(unsigned int cpu)
776793
rcu_cpu_starting(cpu); /* Enables RCU usage on this CPU. */
777794
while (st->state < target) {
778795
st->state++;
779-
cpuhp_invoke_callback(cpu, st->state, true, NULL);
796+
cpuhp_invoke_callback(cpu, st->state, true, NULL, NULL);
780797
}
781798
}
782799

@@ -1307,9 +1324,9 @@ static int cpuhp_issue_call(int cpu, enum cpuhp_state state, bool bringup,
13071324
if (cpuhp_is_ap_state(state))
13081325
ret = cpuhp_invoke_ap_callback(cpu, state, bringup, node);
13091326
else
1310-
ret = cpuhp_invoke_callback(cpu, state, bringup, node);
1327+
ret = cpuhp_invoke_callback(cpu, state, bringup, node, NULL);
13111328
#else
1312-
ret = cpuhp_invoke_callback(cpu, state, bringup, node);
1329+
ret = cpuhp_invoke_callback(cpu, state, bringup, node, NULL);
13131330
#endif
13141331
BUG_ON(ret && !bringup);
13151332
return ret;

0 commit comments

Comments
 (0)