Some cleanups to cpu offline handling.
authorKeir Fraser <keir.fraser@citrix.com>
Fri, 14 May 2010 17:25:55 +0000 (18:25 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Fri, 14 May 2010 17:25:55 +0000 (18:25 +0100)
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
16 files changed:
xen/arch/ia64/linux-xen/smpboot.c
xen/arch/x86/domain.c
xen/arch/x86/hvm/hvm.c
xen/arch/x86/hvm/svm/svm.c
xen/arch/x86/hvm/vmx/vmcs.c
xen/arch/x86/hvm/vmx/vmx.c
xen/arch/x86/smpboot.c
xen/common/cpu.c
xen/common/softirq.c
xen/common/tasklet.c
xen/include/asm-ia64/linux-xen/asm/smp.h
xen/include/asm-x86/hvm/hvm.h
xen/include/asm-x86/hvm/vmx/vmcs.h
xen/include/asm-x86/smp.h
xen/include/xen/cpu.h
xen/include/xen/smp.h

index 805706241e9f127514c7de81a158707d94928339..20298c52e84390c56cbd72711e0bf4ca96e46ba7 100644 (file)
@@ -721,16 +721,10 @@ remove_siblinginfo(int cpu)
 
 extern void fixup_irqs(void);
 /* must be called with cpucontrol mutex held */
-int __cpu_disable(void)
+void __cpu_disable(void)
 {
        int cpu = smp_processor_id();
 
-       /*
-        * dont permit boot processor for now
-        */
-       if (cpu == 0)
-               return -EBUSY;
-
        remove_siblinginfo(cpu);
        cpu_clear(cpu, cpu_online_map);
 #ifndef XEN
@@ -738,12 +732,11 @@ int __cpu_disable(void)
 #endif
        local_flush_tlb_all();
        cpu_clear(cpu, cpu_callin_map);
-       return 0;
 }
 #else /* !CONFIG_HOTPLUG_CPU */
-int __cpu_disable(void)
+void __cpu_disable(void)
 {
-       return -ENOSYS;
+       BUG();
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
index 57b54f21be8039baecc12cd3b8f463329c5d147d..166a8be31fd925f48123127df2bf5ee406c64465 100644 (file)
@@ -98,15 +98,8 @@ static void default_dead_idle(void)
 
 static void play_dead(void)
 {
-    /*
-     * Flush pending softirqs if any. They can be queued up before this CPU
-     * was taken out of cpu_online_map in __cpu_disable().
-     */
-    do_softirq();
-
     /* This must be done before dead CPU ack */
     cpu_exit_clear();
-    hvm_cpu_down();
     wbinvd();
     mb();
     /* Ack it */
index cfa0643f959b79c7f170c4c0c76c283363f2a876..7f6ba29a065d279a638ae39563fdecc980877325 100644 (file)
@@ -80,7 +80,13 @@ static int cpu_callback(
     switch ( action )
     {
     case CPU_UP_PREPARE:
-        rc = hvm_funcs.cpu_prepare(cpu);
+        rc = hvm_funcs.cpu_up_prepare(cpu);
+        break;
+    case CPU_DYING:
+        hvm_cpu_down();
+        break;
+    case CPU_DEAD:
+        hvm_funcs.cpu_dead(cpu);
         break;
     default:
         break;
index 4231079d131201e18b4e5249f0fa0a74787aa481..194453f03b7fcbf8944f9745e3c6aa138ddc265d 100644 (file)
@@ -818,13 +818,25 @@ static int svm_do_pmu_interrupt(struct cpu_user_regs *regs)
     return vpmu_do_interrupt(regs);
 }
 
-static int svm_cpu_prepare(unsigned int cpu)
+static void svm_cpu_dead(unsigned int cpu)
+{
+    free_xenheap_page(hsa[cpu]);
+    hsa[cpu] = NULL;
+    free_vmcb(root_vmcb[cpu]);
+    root_vmcb[cpu] = NULL;
+}
+
+static int svm_cpu_up_prepare(unsigned int cpu)
 {
     if ( ((hsa[cpu] == NULL) &&
           ((hsa[cpu] = alloc_host_save_area()) == NULL)) ||
          ((root_vmcb[cpu] == NULL) &&
           ((root_vmcb[cpu] = alloc_vmcb()) == NULL)) )
+    {
+        svm_cpu_dead(cpu);
         return -ENOMEM;
+    }
+
     return 0;
 }
 
@@ -842,7 +854,7 @@ static int svm_cpu_up(struct cpuinfo_x86 *c)
         return 0;
     }
 
-    if ( svm_cpu_prepare(cpu) != 0 )
+    if ( svm_cpu_up_prepare(cpu) != 0 )
         return 0;
 
     write_efer(read_efer() | EFER_SVME);
@@ -1328,7 +1340,8 @@ static void svm_invlpg_intercept(unsigned long vaddr)
 
 static struct hvm_function_table __read_mostly svm_function_table = {
     .name                 = "SVM",
-    .cpu_prepare          = svm_cpu_prepare,
+    .cpu_up_prepare       = svm_cpu_up_prepare,
+    .cpu_dead             = svm_cpu_dead,
     .cpu_down             = svm_cpu_down,
     .domain_initialise    = svm_domain_initialise,
     .domain_destroy       = svm_domain_destroy,
index 52594de9319d10f8c2f0ff08d8b54d096973e230..83054e7cc35efca12d50fe7c8d76cdcc1bfce0ff 100644 (file)
@@ -337,7 +337,7 @@ static void vmx_load_vmcs(struct vcpu *v)
     local_irq_restore(flags);
 }
 
-int vmx_cpu_prepare(unsigned int cpu)
+int vmx_cpu_up_prepare(unsigned int cpu)
 {
     if ( per_cpu(host_vmcs, cpu) != NULL )
         return 0;
@@ -350,6 +350,12 @@ int vmx_cpu_prepare(unsigned int cpu)
     return -ENOMEM;
 }
 
+void vmx_cpu_dead(unsigned int cpu)
+{
+    vmx_free_vmcs(per_cpu(host_vmcs, cpu));
+    per_cpu(host_vmcs, cpu) = NULL;
+}
+
 int vmx_cpu_up(void)
 {
     u32 eax, edx;
@@ -398,7 +404,7 @@ int vmx_cpu_up(void)
 
     INIT_LIST_HEAD(&this_cpu(active_vmcs_list));
 
-    if ( vmx_cpu_prepare(cpu) != 0 )
+    if ( vmx_cpu_up_prepare(cpu) != 0 )
         return 0;
 
     switch ( __vmxon(virt_to_maddr(this_cpu(host_vmcs))) )
index b65695378fc9b5b07f8b4d9c88417f0678a19619..d1d82ab6fc4257c1cbd82d7ea52d684a89207821 100644 (file)
@@ -1379,7 +1379,8 @@ static void vmx_set_info_guest(struct vcpu *v)
 
 static struct hvm_function_table __read_mostly vmx_function_table = {
     .name                 = "VMX",
-    .cpu_prepare          = vmx_cpu_prepare,
+    .cpu_up_prepare       = vmx_cpu_up_prepare,
+    .cpu_dead             = vmx_cpu_dead,
     .domain_initialise    = vmx_domain_initialise,
     .domain_destroy       = vmx_domain_destroy,
     .vcpu_initialise      = vmx_vcpu_initialise,
index 50ac6619263df3f90e545cf860499b235a00841f..035e570413b4558628cce8da3a1e11351c4b837c 100644 (file)
@@ -1265,9 +1265,9 @@ remove_siblinginfo(int cpu)
        cpu_clear(cpu, cpu_sibling_setup_map);
 }
 
-extern void fixup_irqs(void);
-int __cpu_disable(void)
+void __cpu_disable(void)
 {
+       extern void fixup_irqs(void);
        int cpu = smp_processor_id();
 
        local_irq_disable();
@@ -1287,8 +1287,6 @@ int __cpu_disable(void)
        fixup_irqs();
 
        cpu_disable_scheduler(cpu);
-
-       return 0;
 }
 
 void __cpu_die(unsigned int cpu)
index 4dfc3351b93b086adbb20a28d110a67734c3e98d..7739a633adcd6a11bb0fa79461615863d466f486 100644 (file)
@@ -68,7 +68,8 @@ static int take_cpu_down(void *unused)
     void *hcpu = (void *)(long)smp_processor_id();
     if ( raw_notifier_call_chain(&cpu_chain, CPU_DYING, hcpu) != NOTIFY_DONE )
         BUG();
-    return __cpu_disable();
+    __cpu_disable();
+    return 0;
 }
 
 int cpu_down(unsigned int cpu)
index fac59818ac965f1b8851b7d617f3ee1a864423a2..0a4f1e791450868da9f493d6df9f30ec9c1062e4 100644 (file)
@@ -38,7 +38,8 @@ static void __do_softirq(unsigned long ignore_mask)
         if ( rcu_pending(cpu) )
             rcu_check_callbacks(cpu);
 
-        if ( (pending = (softirq_pending(cpu) & ~ignore_mask)) == 0 )
+        if ( ((pending = (softirq_pending(cpu) & ~ignore_mask)) == 0)
+             || cpu_is_offline(cpu) )
             break;
 
         i = find_first_set_bit(pending);
index f9b889d717c10be18e082ad11971d559bc0626f1..b898535223daca729c924c7cb0818345b0709f94 100644 (file)
@@ -78,7 +78,7 @@ void do_tasklet(void)
 
     spin_lock_irq(&tasklet_lock);
 
-    if ( unlikely(list_empty(list)) )
+    if ( unlikely(list_empty(list) || cpu_is_offline(cpu)) )
         goto out;
 
     t = list_entry(list->next, struct tasklet, list);
index 7380c773cf196fe17bb2c955bf3134e7feb0a9cb..7cee1a3aa6a135bbe8d7ec46ec71d4e1dda942ff 100644 (file)
@@ -118,10 +118,7 @@ max_xtp (void)
 #define hard_smp_processor_id()                ia64_get_lid()
 
 /* Upping and downing of CPUs */
-extern int __cpu_disable (void);
-extern void __cpu_die (unsigned int cpu);
 extern void cpu_die (void) __attribute__ ((noreturn));
-extern int __cpu_up (unsigned int cpu);
 extern void __init smp_build_cpu_map(void);
 
 extern void __init init_smp_config (void);
index e5d3fdbab651b1b80daf7a2a518fd977e2bea8b3..8d36e4c9f0b8c655fda421f308753f86a746a78b 100644 (file)
@@ -115,7 +115,9 @@ struct hvm_function_table {
     int  (*event_pending)(struct vcpu *v);
     int  (*do_pmu_interrupt)(struct cpu_user_regs *regs);
 
-    int  (*cpu_prepare)(unsigned int cpu);
+    int  (*cpu_up_prepare)(unsigned int cpu);
+    void (*cpu_dead)(unsigned int cpu);
+
     int  (*cpu_up)(void);
     void (*cpu_down)(void);
 
index 29172e0d53bea3b12fef1074e9bf7e327929fafb..8e73573080bfd08daf8f776eb36a149625d8cf27 100644 (file)
@@ -26,7 +26,8 @@
 extern void start_vmx(void);
 extern void vmcs_dump_vcpu(struct vcpu *v);
 extern void setup_vmcs_dump(void);
-extern int  vmx_cpu_prepare(unsigned int cpu);
+extern int  vmx_cpu_up_prepare(unsigned int cpu);
+extern void vmx_cpu_dead(unsigned int cpu);
 extern int  vmx_cpu_up(void);
 extern void vmx_cpu_down(void);
 
index 3c85b8795615aa4a10aa1e4d33889e68904b0986..029b25b6587e55b5f89a5cc64930f5aa9c3b1404 100644 (file)
@@ -93,8 +93,6 @@ static __inline int logical_smp_processor_id(void)
 
 #endif
 
-extern int __cpu_disable(void);
-extern void __cpu_die(unsigned int cpu);
 #endif /* !__ASSEMBLY__ */
 
 #else /* CONFIG_SMP */
index 115dec7896ba674f2ff8c75e65727aba66556af8..7de315290f8f087cd28adcecef5f558b22f7a656 100644 (file)
@@ -17,8 +17,14 @@ void cpu_hotplug_done(void);
 int register_cpu_notifier(struct notifier_block *nb);
 
 /*
- * Notification actions: note that only CPU_{UP,DOWN}_PREPARE may fail ---
- * all other handlers *must* return NOTIFY_DONE.
+ * Possible event sequences for a given CPU:
+ *  CPU_UP_PREPARE -> CPU_UP_CANCELLED        -- failed CPU up
+ *  CPU_UP_PREPARE -> CPU_ONLINE              -- successful CPU up
+ *  CPU_DOWN_PREPARE -> CPU_DOWN_FAILED       -- failed CPU down
+ *  CPU_DOWN_PREPARE -> CPU_DYING -> CPU_DEAD -- successful CPU down
+ * 
+ * Hence note that only CPU_*_PREPARE handlers are allowed to fail. Also note
+ * that once CPU_DYING is delivered, an offline action can no longer fail.
  */
 #define CPU_UP_PREPARE   0x0002 /* CPU is coming up */
 #define CPU_UP_CANCELED  0x0003 /* CPU is no longer coming up */
@@ -36,4 +42,9 @@ int cpu_up(unsigned int cpu);
 int disable_nonboot_cpus(void);
 void enable_nonboot_cpus(void);
 
+/* Private arch-dependent helpers for CPU hotplug. */
+int __cpu_up(unsigned int cpunum);
+void __cpu_disable(void);
+void __cpu_die(unsigned int cpu);
+
 #endif /* __XEN_CPU_H__ */
index f603e001e67bece917ff399f1a34e3acd4805656..7eac790bf75479c9569d589974730573abf1c111 100644 (file)
@@ -20,11 +20,6 @@ extern void smp_send_state_dump(unsigned int cpu);
  */
 extern void smp_prepare_cpus(unsigned int max_cpus);
 
-/*
- * Bring a CPU up
- */
-extern int __cpu_up(unsigned int cpunum);
-
 /*
  * Final polishing of CPUs
  */