Skip to content

Commit 2a442c9

Browse files
committed
x86: Use common outgoing-CPU-notification code
This commit removes the open-coded CPU-offline notification with new common code. Among other things, this change avoids calling scheduler code using RCU from an offline CPU that RCU is ignoring. It also allows Xen to notice at online time that the CPU did not go offline correctly. Note that Xen has the surviving CPU carry out some cleanup operations, so if the surviving CPU times out, these cleanup operations might have been carried out while the outgoing CPU was still running. It might therefore be unwise to bring this CPU back online, and this commit avoids doing so. Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: <x86@kernel.org> Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Cc: David Vrabel <david.vrabel@citrix.com> Cc: <xen-devel@lists.xenproject.org>
1 parent 8038dad commit 2a442c9

File tree

4 files changed

+44
-45
lines changed

4 files changed

+44
-45
lines changed

arch/x86/include/asm/cpu.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ extern int _debug_hotplug_cpu(int cpu, int action);
3434
#endif
3535
#endif
3636

37-
DECLARE_PER_CPU(int, cpu_state);
38-
3937
int mwait_usable(const struct cpuinfo_x86 *);
4038

4139
#endif /* _ASM_X86_CPU_H */

arch/x86/include/asm/smp.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,12 +150,12 @@ static inline void arch_send_call_function_ipi_mask(const struct cpumask *mask)
150150
}
151151

152152
void cpu_disable_common(void);
153-
void cpu_die_common(unsigned int cpu);
154153
void native_smp_prepare_boot_cpu(void);
155154
void native_smp_prepare_cpus(unsigned int max_cpus);
156155
void native_smp_cpus_done(unsigned int max_cpus);
157156
int native_cpu_up(unsigned int cpunum, struct task_struct *tidle);
158157
int native_cpu_disable(void);
158+
int common_cpu_die(unsigned int cpu);
159159
void native_cpu_die(unsigned int cpu);
160160
void native_play_dead(void);
161161
void play_dead_common(void);

arch/x86/kernel/smpboot.c

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,6 @@
7777
#include <asm/realmode.h>
7878
#include <asm/misc.h>
7979

80-
/* State of each CPU */
81-
DEFINE_PER_CPU(int, cpu_state) = { 0 };
82-
8380
/* Number of siblings per CPU package */
8481
int smp_num_siblings = 1;
8582
EXPORT_SYMBOL(smp_num_siblings);
@@ -257,7 +254,7 @@ static void notrace start_secondary(void *unused)
257254
lock_vector_lock();
258255
set_cpu_online(smp_processor_id(), true);
259256
unlock_vector_lock();
260-
per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
257+
cpu_set_state_online(smp_processor_id());
261258
x86_platform.nmi_init();
262259

263260
/* enable local interrupts */
@@ -948,7 +945,10 @@ int native_cpu_up(unsigned int cpu, struct task_struct *tidle)
948945
*/
949946
mtrr_save_state();
950947

951-
per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
948+
/* x86 CPUs take themselves offline, so delayed offline is OK. */
949+
err = cpu_check_up_prepare(cpu);
950+
if (err && err != -EBUSY)
951+
return err;
952952

953953
/* the FPU context is blank, nobody can own it */
954954
__cpu_disable_lazy_restore(cpu);
@@ -1191,7 +1191,7 @@ void __init native_smp_prepare_boot_cpu(void)
11911191
switch_to_new_gdt(me);
11921192
/* already set me in cpu_online_mask in boot_cpu_init() */
11931193
cpumask_set_cpu(me, cpu_callout_mask);
1194-
per_cpu(cpu_state, me) = CPU_ONLINE;
1194+
cpu_set_state_online(me);
11951195
}
11961196

11971197
void __init native_smp_cpus_done(unsigned int max_cpus)
@@ -1318,14 +1318,10 @@ static void __ref remove_cpu_from_maps(int cpu)
13181318
numa_remove_cpu(cpu);
13191319
}
13201320

1321-
static DEFINE_PER_CPU(struct completion, die_complete);
1322-
13231321
void cpu_disable_common(void)
13241322
{
13251323
int cpu = smp_processor_id();
13261324

1327-
init_completion(&per_cpu(die_complete, smp_processor_id()));
1328-
13291325
remove_siblinginfo(cpu);
13301326

13311327
/* It's now safe to remove this processor from the online map */
@@ -1349,24 +1345,27 @@ int native_cpu_disable(void)
13491345
return 0;
13501346
}
13511347

1352-
void cpu_die_common(unsigned int cpu)
1348+
int common_cpu_die(unsigned int cpu)
13531349
{
1354-
wait_for_completion_timeout(&per_cpu(die_complete, cpu), HZ);
1355-
}
1350+
int ret = 0;
13561351

1357-
void native_cpu_die(unsigned int cpu)
1358-
{
13591352
/* We don't do anything here: idle task is faking death itself. */
13601353

1361-
cpu_die_common(cpu);
1362-
13631354
/* They ack this in play_dead() by setting CPU_DEAD */
1364-
if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
1355+
if (cpu_wait_death(cpu, 5)) {
13651356
if (system_state == SYSTEM_RUNNING)
13661357
pr_info("CPU %u is now offline\n", cpu);
13671358
} else {
13681359
pr_err("CPU %u didn't die...\n", cpu);
1360+
ret = -1;
13691361
}
1362+
1363+
return ret;
1364+
}
1365+
1366+
void native_cpu_die(unsigned int cpu)
1367+
{
1368+
common_cpu_die(cpu);
13701369
}
13711370

13721371
void play_dead_common(void)
@@ -1375,10 +1374,8 @@ void play_dead_common(void)
13751374
reset_lazy_tlbstate();
13761375
amd_e400_remove_cpu(raw_smp_processor_id());
13771376

1378-
mb();
13791377
/* Ack it */
1380-
__this_cpu_write(cpu_state, CPU_DEAD);
1381-
complete(&per_cpu(die_complete, smp_processor_id()));
1378+
(void)cpu_report_death();
13821379

13831380
/*
13841381
* With physical CPU hotplug, we should halt the cpu

arch/x86/xen/smp.c

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,10 @@ static void cpu_bringup(void)
9090

9191
set_cpu_online(cpu, true);
9292

93-
this_cpu_write(cpu_state, CPU_ONLINE);
94-
95-
wmb();
93+
cpu_set_state_online(cpu); /* Implies full memory barrier. */
9694

9795
/* We can take interrupts now: we're officially "up". */
9896
local_irq_enable();
99-
100-
wmb(); /* make sure everything is out */
10197
}
10298

10399
/*
@@ -459,7 +455,13 @@ static int xen_cpu_up(unsigned int cpu, struct task_struct *idle)
459455
xen_setup_timer(cpu);
460456
xen_init_lock_cpu(cpu);
461457

462-
per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
458+
/*
459+
* PV VCPUs are always successfully taken down (see 'while' loop
460+
* in xen_cpu_die()), so -EBUSY is an error.
461+
*/
462+
rc = cpu_check_up_prepare(cpu);
463+
if (rc)
464+
return rc;
463465

464466
/* make sure interrupts start blocked */
465467
per_cpu(xen_vcpu, cpu)->evtchn_upcall_mask = 1;
@@ -479,10 +481,8 @@ static int xen_cpu_up(unsigned int cpu, struct task_struct *idle)
479481
rc = HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL);
480482
BUG_ON(rc);
481483

482-
while(per_cpu(cpu_state, cpu) != CPU_ONLINE) {
484+
while (cpu_report_state(cpu) != CPU_ONLINE)
483485
HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
484-
barrier();
485-
}
486486

487487
return 0;
488488
}
@@ -511,11 +511,11 @@ static void xen_cpu_die(unsigned int cpu)
511511
schedule_timeout(HZ/10);
512512
}
513513

514-
cpu_die_common(cpu);
515-
516-
xen_smp_intr_free(cpu);
517-
xen_uninit_lock_cpu(cpu);
518-
xen_teardown_timer(cpu);
514+
if (common_cpu_die(cpu) == 0) {
515+
xen_smp_intr_free(cpu);
516+
xen_uninit_lock_cpu(cpu);
517+
xen_teardown_timer(cpu);
518+
}
519519
}
520520

521521
static void xen_play_dead(void) /* used only with HOTPLUG_CPU */
@@ -747,6 +747,16 @@ static void __init xen_hvm_smp_prepare_cpus(unsigned int max_cpus)
747747
static int xen_hvm_cpu_up(unsigned int cpu, struct task_struct *tidle)
748748
{
749749
int rc;
750+
751+
/*
752+
* This can happen if CPU was offlined earlier and
753+
* offlining timed out in common_cpu_die().
754+
*/
755+
if (cpu_report_state(cpu) == CPU_DEAD_FROZEN) {
756+
xen_smp_intr_free(cpu);
757+
xen_uninit_lock_cpu(cpu);
758+
}
759+
750760
/*
751761
* xen_smp_intr_init() needs to run before native_cpu_up()
752762
* so that IPI vectors are set up on the booting CPU before
@@ -768,20 +778,14 @@ static int xen_hvm_cpu_up(unsigned int cpu, struct task_struct *tidle)
768778
return rc;
769779
}
770780

771-
static void xen_hvm_cpu_die(unsigned int cpu)
772-
{
773-
xen_cpu_die(cpu);
774-
native_cpu_die(cpu);
775-
}
776-
777781
void __init xen_hvm_smp_init(void)
778782
{
779783
if (!xen_have_vector_callback)
780784
return;
781785
smp_ops.smp_prepare_cpus = xen_hvm_smp_prepare_cpus;
782786
smp_ops.smp_send_reschedule = xen_smp_send_reschedule;
783787
smp_ops.cpu_up = xen_hvm_cpu_up;
784-
smp_ops.cpu_die = xen_hvm_cpu_die;
788+
smp_ops.cpu_die = xen_cpu_die;
785789
smp_ops.send_call_func_ipi = xen_smp_send_call_function_ipi;
786790
smp_ops.send_call_func_single_ipi = xen_smp_send_call_function_single_ipi;
787791
smp_ops.smp_prepare_boot_cpu = xen_smp_prepare_boot_cpu;

0 commit comments

Comments
 (0)