[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [tip:core/rcu] x86: Use common outgoing-CPU-notification code



Commit-ID:  2a442c9c6453d3d043dfd89f2e03a1deff8a6f06
Gitweb:     http://git.kernel.org/tip/2a442c9c6453d3d043dfd89f2e03a1deff8a6f06
Author:     Paul E. McKenney <paulmck@xxxxxxxxxxxxxxxxxx>
AuthorDate: Wed, 25 Feb 2015 11:42:15 -0800
Committer:  Paul E. McKenney <paulmck@xxxxxxxxxxxxxxxxxx>
CommitDate: Wed, 11 Mar 2015 13:22:35 -0700

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@xxxxxxxxxx>
Signed-off-by: Paul E. McKenney <paulmck@xxxxxxxxxxxxxxxxxx>
Cc: <x86@xxxxxxxxxx>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx>
Cc: David Vrabel <david.vrabel@xxxxxxxxxx>
Cc: <xen-devel@xxxxxxxxxxxxxxxxxxxx>
---
 arch/x86/include/asm/cpu.h |  2 --
 arch/x86/include/asm/smp.h |  2 +-
 arch/x86/kernel/smpboot.c  | 39 ++++++++++++++++++---------------------
 arch/x86/xen/smp.c         | 46 +++++++++++++++++++++++++---------------------
 4 files changed, 44 insertions(+), 45 deletions(-)

diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h
index d2b1298..bf2caa1 100644
--- a/arch/x86/include/asm/cpu.h
+++ b/arch/x86/include/asm/cpu.h
@@ -34,8 +34,6 @@ extern int _debug_hotplug_cpu(int cpu, int action);
 #endif
 #endif
 
-DECLARE_PER_CPU(int, cpu_state);
-
 int mwait_usable(const struct cpuinfo_x86 *);
 
 #endif /* _ASM_X86_CPU_H */
diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h
index 8cd1cc3..a5cb4f6 100644
--- a/arch/x86/include/asm/smp.h
+++ b/arch/x86/include/asm/smp.h
@@ -150,12 +150,12 @@ static inline void arch_send_call_function_ipi_mask(const 
struct cpumask *mask)
 }
 
 void cpu_disable_common(void);
-void cpu_die_common(unsigned int cpu);
 void native_smp_prepare_boot_cpu(void);
 void native_smp_prepare_cpus(unsigned int max_cpus);
 void native_smp_cpus_done(unsigned int max_cpus);
 int native_cpu_up(unsigned int cpunum, struct task_struct *tidle);
 int native_cpu_disable(void);
+int common_cpu_die(unsigned int cpu);
 void native_cpu_die(unsigned int cpu);
 void native_play_dead(void);
 void play_dead_common(void);
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index febc6aa..c8fa349 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -77,9 +77,6 @@
 #include <asm/realmode.h>
 #include <asm/misc.h>
 
-/* State of each CPU */
-DEFINE_PER_CPU(int, cpu_state) = { 0 };
-
 /* Number of siblings per CPU package */
 int smp_num_siblings = 1;
 EXPORT_SYMBOL(smp_num_siblings);
@@ -257,7 +254,7 @@ static void notrace start_secondary(void *unused)
        lock_vector_lock();
        set_cpu_online(smp_processor_id(), true);
        unlock_vector_lock();
-       per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
+       cpu_set_state_online(smp_processor_id());
        x86_platform.nmi_init();
 
        /* enable local interrupts */
@@ -948,7 +945,10 @@ int native_cpu_up(unsigned int cpu, struct task_struct 
*tidle)
         */
        mtrr_save_state();
 
-       per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
+       /* x86 CPUs take themselves offline, so delayed offline is OK. */
+       err = cpu_check_up_prepare(cpu);
+       if (err && err != -EBUSY)
+               return err;
 
        /* the FPU context is blank, nobody can own it */
        __cpu_disable_lazy_restore(cpu);
@@ -1191,7 +1191,7 @@ void __init native_smp_prepare_boot_cpu(void)
        switch_to_new_gdt(me);
        /* already set me in cpu_online_mask in boot_cpu_init() */
        cpumask_set_cpu(me, cpu_callout_mask);
-       per_cpu(cpu_state, me) = CPU_ONLINE;
+       cpu_set_state_online(me);
 }
 
 void __init native_smp_cpus_done(unsigned int max_cpus)
@@ -1318,14 +1318,10 @@ static void __ref remove_cpu_from_maps(int cpu)
        numa_remove_cpu(cpu);
 }
 
-static DEFINE_PER_CPU(struct completion, die_complete);
-
 void cpu_disable_common(void)
 {
        int cpu = smp_processor_id();
 
-       init_completion(&per_cpu(die_complete, smp_processor_id()));
-
        remove_siblinginfo(cpu);
 
        /* It's now safe to remove this processor from the online map */
@@ -1349,24 +1345,27 @@ int native_cpu_disable(void)
        return 0;
 }
 
-void cpu_die_common(unsigned int cpu)
+int common_cpu_die(unsigned int cpu)
 {
-       wait_for_completion_timeout(&per_cpu(die_complete, cpu), HZ);
-}
+       int ret = 0;
 
-void native_cpu_die(unsigned int cpu)
-{
        /* We don't do anything here: idle task is faking death itself. */
 
-       cpu_die_common(cpu);
-
        /* They ack this in play_dead() by setting CPU_DEAD */
-       if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
+       if (cpu_wait_death(cpu, 5)) {
                if (system_state == SYSTEM_RUNNING)
                        pr_info("CPU %u is now offline\n", cpu);
        } else {
                pr_err("CPU %u didn't die...\n", cpu);
+               ret = -1;
        }
+
+       return ret;
+}
+
+void native_cpu_die(unsigned int cpu)
+{
+       common_cpu_die(cpu);
 }
 
 void play_dead_common(void)
@@ -1375,10 +1374,8 @@ void play_dead_common(void)
        reset_lazy_tlbstate();
        amd_e400_remove_cpu(raw_smp_processor_id());
 
-       mb();
        /* Ack it */
-       __this_cpu_write(cpu_state, CPU_DEAD);
-       complete(&per_cpu(die_complete, smp_processor_id()));
+       (void)cpu_report_death();
 
        /*
         * With physical CPU hotplug, we should halt the cpu
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index 08e8489..1c5e760 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -90,14 +90,10 @@ static void cpu_bringup(void)
 
        set_cpu_online(cpu, true);
 
-       this_cpu_write(cpu_state, CPU_ONLINE);
-
-       wmb();
+       cpu_set_state_online(cpu);  /* Implies full memory barrier. */
 
        /* We can take interrupts now: we're officially "up". */
        local_irq_enable();
-
-       wmb();                  /* make sure everything is out */
 }
 
 /*
@@ -459,7 +455,13 @@ static int xen_cpu_up(unsigned int cpu, struct task_struct 
*idle)
        xen_setup_timer(cpu);
        xen_init_lock_cpu(cpu);
 
-       per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
+       /*
+        * PV VCPUs are always successfully taken down (see 'while' loop
+        * in xen_cpu_die()), so -EBUSY is an error.
+        */
+       rc = cpu_check_up_prepare(cpu);
+       if (rc)
+               return rc;
 
        /* make sure interrupts start blocked */
        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)
        rc = HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL);
        BUG_ON(rc);
 
-       while(per_cpu(cpu_state, cpu) != CPU_ONLINE) {
+       while (cpu_report_state(cpu) != CPU_ONLINE)
                HYPERVISOR_sched_op(SCHEDOP_yield, NULL);
-               barrier();
-       }
 
        return 0;
 }
@@ -511,11 +511,11 @@ static void xen_cpu_die(unsigned int cpu)
                schedule_timeout(HZ/10);
        }
 
-       cpu_die_common(cpu);
-
-       xen_smp_intr_free(cpu);
-       xen_uninit_lock_cpu(cpu);
-       xen_teardown_timer(cpu);
+       if (common_cpu_die(cpu) == 0) {
+               xen_smp_intr_free(cpu);
+               xen_uninit_lock_cpu(cpu);
+               xen_teardown_timer(cpu);
+       }
 }
 
 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)
 static int xen_hvm_cpu_up(unsigned int cpu, struct task_struct *tidle)
 {
        int rc;
+
+       /*
+        * This can happen if CPU was offlined earlier and
+        * offlining timed out in common_cpu_die().
+        */
+       if (cpu_report_state(cpu) == CPU_DEAD_FROZEN) {
+               xen_smp_intr_free(cpu);
+               xen_uninit_lock_cpu(cpu);
+       }
+
        /*
         * xen_smp_intr_init() needs to run before native_cpu_up()
         * so that IPI vectors are set up on the booting CPU before
@@ -768,12 +778,6 @@ static int xen_hvm_cpu_up(unsigned int cpu, struct 
task_struct *tidle)
        return rc;
 }
 
-static void xen_hvm_cpu_die(unsigned int cpu)
-{
-       xen_cpu_die(cpu);
-       native_cpu_die(cpu);
-}
-
 void __init xen_hvm_smp_init(void)
 {
        if (!xen_have_vector_callback)
@@ -781,7 +785,7 @@ void __init xen_hvm_smp_init(void)
        smp_ops.smp_prepare_cpus = xen_hvm_smp_prepare_cpus;
        smp_ops.smp_send_reschedule = xen_smp_send_reschedule;
        smp_ops.cpu_up = xen_hvm_cpu_up;
-       smp_ops.cpu_die = xen_hvm_cpu_die;
+       smp_ops.cpu_die = xen_cpu_die;
        smp_ops.send_call_func_ipi = xen_smp_send_call_function_ipi;
        smp_ops.send_call_func_single_ipi = 
xen_smp_send_call_function_single_ipi;
        smp_ops.smp_prepare_boot_cpu = xen_smp_prepare_boot_cpu;

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.