Fix CPU hotplug after percpu data handling changes.
authorKeir Fraser <keir.fraser@citrix.com>
Wed, 19 May 2010 10:15:26 +0000 (11:15 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Wed, 19 May 2010 10:15:26 +0000 (11:15 +0100)
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
xen/arch/ia64/linux-xen/smpboot.c
xen/arch/ia64/xen/xensetup.c
xen/arch/x86/setup.c
xen/arch/x86/smpboot.c
xen/common/domain.c
xen/common/sched_sedf.c
xen/common/schedule.c
xen/include/xen/domain.h
xen/include/xen/sched-if.h

index 20298c52e84390c56cbd72711e0bf4ca96e46ba7..57454d8e7f4e86342d8d6b02b5afa5a918fc599b 100644 (file)
@@ -526,7 +526,7 @@ do_rest:
 #else
        struct vcpu *v;
 
-       v = alloc_idle_vcpu(cpu);
+       v = idle_vcpu[cpu];
        BUG_ON(v == NULL);
 
        //printf ("do_boot_cpu: cpu=%d, domain=%p, vcpu=%p\n", cpu, idle, v);
index e3d9d3601153d27d8f3b20f68e89920b5fd58068..33ceacde29ed972806b4febbc76bb6dec17a99e1 100644 (file)
@@ -341,7 +341,6 @@ void __init start_kernel(void)
     unsigned long dom0_memory_start, dom0_memory_size;
     unsigned long dom0_initrd_start, dom0_initrd_size;
     unsigned long md_end, relo_start, relo_end, relo_size = 0;
-    struct domain *idle_domain;
     struct vcpu *dom0_vcpu0;
     efi_memory_desc_t *kern_md, *last_md, *md;
     unsigned long xenheap_phys_end;
@@ -560,15 +559,8 @@ skip_move:
 
     late_setup_arch(&cmdline);
 
-    scheduler_init();
     idle_vcpu[0] = (struct vcpu*) ia64_r13;
-    idle_domain = domain_create(IDLE_DOMAIN_ID, 0, 0);
-    if ( idle_domain == NULL )
-        BUG();
-    idle_domain->vcpu = idle_vcpu;
-    idle_domain->max_vcpus = NR_CPUS;
-    if ( alloc_vcpu(idle_domain, 0, 0) == NULL )
-        BUG();
+    scheduler_init();
 
     alloc_dom_xen_and_dom_io();
     setup_per_cpu_areas();
index 89994066424d45a3a905e4ad509d7e3982cf8b51..34162f6bdbd7286f76f8982360efeec4de316847 100644 (file)
@@ -189,22 +189,9 @@ extern char __init_begin[], __init_end[], __bss_start[];
 
 static void __init init_idle_domain(void)
 {
-    struct domain *idle_domain;
-
-    /* Domain creation requires that scheduler structures are initialised. */
     scheduler_init();
-
-    idle_domain = domain_create(IDLE_DOMAIN_ID, 0, 0);
-    if ( idle_domain == NULL )
-        BUG();
-    idle_domain->vcpu = idle_vcpu;
-    idle_domain->max_vcpus = NR_CPUS;
-    if ( alloc_vcpu(idle_domain, 0, 0) == NULL )
-        BUG();
-
     set_current(idle_vcpu[0]);
     this_cpu(curr_vcpu) = current;
-
     setup_idle_pagetable();
 }
 
index 2787a31b55c7346d4f8cd245d0e5ba3579283eaf..69efba68c63b21450f47e119aeb99c12b8fbb1d9 100644 (file)
@@ -678,9 +678,6 @@ static int cpu_smpboot_alloc(unsigned int cpu)
     struct page_info *page;
 #endif
 
-    if ( alloc_idle_vcpu(cpu) == NULL )
-        goto oom;
-
     stack_base[cpu] = alloc_xenheap_pages(STACK_ORDER, 0);
     if ( stack_base[cpu] == NULL )
         goto oom;
index a85f51eb7bdce4e46bd3cd689b9a497bb147a1da..32f761f2f3a7abc1fa3642907363054fb6b2c77e 100644 (file)
@@ -194,12 +194,6 @@ struct vcpu *alloc_vcpu(
     return v;
 }
 
-struct vcpu *alloc_idle_vcpu(unsigned int cpu_id)
-{
-    return idle_vcpu[cpu_id] ?: alloc_vcpu(idle_vcpu[0]->domain,
-                                           cpu_id, cpu_id);
-}
-
 static unsigned int __read_mostly extra_dom0_irqs = 256;
 static unsigned int __read_mostly extra_domU_irqs = 32;
 static void __init parse_extra_guest_irqs(const char *s)
index a9d107b546c48cac51edd45cea70ca9aa78d304f..8795f6777460c161b7f4eb532463a542ed23bc34 100644 (file)
@@ -123,7 +123,7 @@ struct sedf_cpu_info {
 #define RUNQ(cpu)      (&CPU_INFO(cpu)->runnableq)
 #define WAITQ(cpu)     (&CPU_INFO(cpu)->waitq)
 #define EXTRAQ(cpu,i)  (&(CPU_INFO(cpu)->extraq[i]))
-#define IDLETASK(cpu)  ((struct vcpu *)per_cpu(schedule_data, cpu).idle)
+#define IDLETASK(cpu)  (idle_vcpu[cpu])
 
 #define PERIOD_BEGIN(inf) ((inf)->deadl_abs - (inf)->period)
 
index 9ea3137ffb0fc205b3964d4161e7fb1773cc99c4..f93dc51276b921a5c16c3b4b75d76ec748265fd8 100644 (file)
@@ -211,28 +211,15 @@ int sched_init_vcpu(struct vcpu *v, unsigned int processor)
     if ( is_idle_domain(d) )
     {
         per_cpu(schedule_data, v->processor).curr = v;
-        per_cpu(schedule_data, v->processor).idle = v;
         v->is_running = 1;
     }
 
     TRACE_2D(TRC_SCHED_DOM_ADD, v->domain->domain_id, v->vcpu_id);
 
-    if ( unlikely(per_cpu(schedule_data, v->processor).sched_priv == NULL)
-         && (DOM2OP(d)->alloc_pdata != NULL) )
-    {
-        per_cpu(schedule_data, v->processor).sched_priv =
-            SCHED_OP(DOM2OP(d), alloc_pdata, processor);
-        if ( per_cpu(schedule_data, v->processor).sched_priv == NULL )
-            return 1;
-    }
-
     v->sched_priv = SCHED_OP(DOM2OP(d), alloc_vdata, v, d->sched_priv);
     if ( v->sched_priv == NULL )
         return 1;
 
-    if ( is_idle_domain(d) )
-        per_cpu(schedule_data, v->processor).sched_idlevpriv = v->sched_priv;
-
     return 0;
 }
 
@@ -1090,39 +1077,73 @@ const struct scheduler *scheduler_get_by_id(unsigned int id)
     return NULL;
 }
 
-static int cpu_callback(
+static int cpu_schedule_up(unsigned int cpu)
+{
+    struct schedule_data *sd = &per_cpu(schedule_data, cpu);
+
+    per_cpu(scheduler, cpu) = &ops;
+    spin_lock_init(&sd->_lock);
+    sd->schedule_lock = &sd->_lock;
+    sd->curr = idle_vcpu[cpu];
+    init_timer(&sd->s_timer, s_timer_fn, NULL, cpu);
+    atomic_set(&sd->urgent_count, 0);
+
+    /* Boot CPU is dealt with later in schedule_init(). */
+    if ( cpu == 0 )
+        return 0;
+
+    if ( idle_vcpu[cpu] == NULL )
+        alloc_vcpu(idle_vcpu[0]->domain, cpu, cpu);
+    if ( idle_vcpu[cpu] == NULL )
+        return -ENOMEM;
+
+    if ( (ops.alloc_pdata != NULL) &&
+         ((sd->sched_priv = ops.alloc_pdata(&ops, cpu)) == NULL) )
+        return -ENOMEM;
+
+    return 0;
+}
+
+static void cpu_schedule_down(unsigned int cpu)
+{
+    struct schedule_data *sd = &per_cpu(schedule_data, cpu);
+
+    if ( sd->sched_priv != NULL )
+        SCHED_OP(&ops, free_pdata, sd->sched_priv, cpu);
+
+    kill_timer(&sd->s_timer);
+}
+
+static int cpu_schedule_callback(
     struct notifier_block *nfb, unsigned long action, void *hcpu)
 {
     unsigned int cpu = (unsigned long)hcpu;
+    int rc = 0;
 
     switch ( action )
     {
     case CPU_UP_PREPARE:
-        per_cpu(scheduler, cpu) = &ops;
-        spin_lock_init(&per_cpu(schedule_data, cpu)._lock);
-        per_cpu(schedule_data, cpu).schedule_lock
-            = &per_cpu(schedule_data, cpu)._lock;
-        init_timer(&per_cpu(schedule_data, cpu).s_timer,
-                   s_timer_fn, NULL, cpu);
+        rc = cpu_schedule_up(cpu);
         break;
+    case CPU_UP_CANCELED:
     case CPU_DEAD:
-        kill_timer(&per_cpu(schedule_data, cpu).s_timer);
+        cpu_schedule_down(cpu);
         break;
     default:
         break;
     }
 
-    return NOTIFY_DONE;
+    return !rc ? NOTIFY_DONE : notifier_from_errno(rc);
 }
 
-static struct notifier_block cpu_nfb = {
-    .notifier_call = cpu_callback
+static struct notifier_block cpu_schedule_nfb = {
+    .notifier_call = cpu_schedule_callback
 };
 
 /* Initialise the data structures. */
 void __init scheduler_init(void)
 {
-    void *hcpu = (void *)(long)smp_processor_id();
+    struct domain *idle_domain;
     int i;
 
     open_softirq(SCHEDULE_SOFTIRQ, schedule);
@@ -1140,53 +1161,54 @@ void __init scheduler_init(void)
         ops = *schedulers[0];
     }
 
-    cpu_callback(&cpu_nfb, CPU_UP_PREPARE, hcpu);
-    register_cpu_notifier(&cpu_nfb);
+    if ( cpu_schedule_up(0) )
+        BUG();
+    register_cpu_notifier(&cpu_schedule_nfb);
 
     printk("Using scheduler: %s (%s)\n", ops.name, ops.opt_name);
     if ( SCHED_OP(&ops, init) )
         panic("scheduler returned error on init\n");
+
+    idle_domain = domain_create(IDLE_DOMAIN_ID, 0, 0);
+    BUG_ON(idle_domain == NULL);
+    idle_domain->vcpu = idle_vcpu;
+    idle_domain->max_vcpus = NR_CPUS;
+    if ( alloc_vcpu(idle_domain, 0, 0) == NULL )
+        BUG();
+    if ( ops.alloc_pdata &&
+         !(this_cpu(schedule_data).sched_priv = ops.alloc_pdata(&ops, 0)) )
+        BUG();
 }
 
 void schedule_cpu_switch(unsigned int cpu, struct cpupool *c)
 {
     unsigned long flags;
-    struct vcpu *v;
-    void *ppriv, *ppriv_old, *vpriv = NULL;
+    struct vcpu *idle;
+    void *ppriv, *ppriv_old, *vpriv, *vpriv_old;
     struct scheduler *old_ops = per_cpu(scheduler, cpu);
     struct scheduler *new_ops = (c == NULL) ? &ops : c->sched;
 
     if ( old_ops == new_ops )
         return;
 
-    v = per_cpu(schedule_data, cpu).idle;
+    idle = idle_vcpu[cpu];
     ppriv = SCHED_OP(new_ops, alloc_pdata, cpu);
-    if ( c != NULL )
-        vpriv = SCHED_OP(new_ops, alloc_vdata, v, v->domain->sched_priv);
+    vpriv = SCHED_OP(new_ops, alloc_vdata, idle, idle->domain->sched_priv);
 
     spin_lock_irqsave(per_cpu(schedule_data, cpu).schedule_lock, flags);
 
-    if ( c == NULL )
-    {
-        vpriv = v->sched_priv;
-        v->sched_priv = per_cpu(schedule_data, cpu).sched_idlevpriv;
-    }
-    else
-    {
-        v->sched_priv = vpriv;
-        vpriv = NULL;
-    }
     SCHED_OP(old_ops, tick_suspend, cpu);
+    vpriv_old = idle->sched_priv;
+    idle->sched_priv = vpriv;
     per_cpu(scheduler, cpu) = new_ops;
     ppriv_old = per_cpu(schedule_data, cpu).sched_priv;
     per_cpu(schedule_data, cpu).sched_priv = ppriv;
     SCHED_OP(new_ops, tick_resume, cpu);
-    SCHED_OP(new_ops, insert_vcpu, v);
+    SCHED_OP(new_ops, insert_vcpu, idle);
 
     spin_unlock_irqrestore(per_cpu(schedule_data, cpu).schedule_lock, flags);
 
-    if ( vpriv != NULL )
-        SCHED_OP(old_ops, free_vdata, vpriv);
+    SCHED_OP(old_ops, free_vdata, vpriv);
     SCHED_OP(old_ops, free_pdata, ppriv_old, cpu);
 }
 
index 0b62c22afee703a13d04fb3931346b61eb869ad7..edffd1f46b6e8fbda69a21effec77167f02bbc23 100644 (file)
@@ -14,7 +14,6 @@ struct vcpu *alloc_vcpu(
     struct domain *d, unsigned int vcpu_id, unsigned int cpu_id);
 int boot_vcpu(
     struct domain *d, int vcpuid, vcpu_guest_context_u ctxt);
-struct vcpu *alloc_idle_vcpu(unsigned int cpu_id);
 struct vcpu *alloc_dom0_vcpu0(void);
 void vcpu_reset(struct vcpu *v);
 
index c6ed8ba1b9ecfb4b25406297c1e9d20fdd16d40b..b1c2b724719f1ebcbd43694a2c10fcec18ac7bda 100644 (file)
@@ -30,12 +30,10 @@ struct schedule_data {
     spinlock_t         *schedule_lock,
                        _lock;
     struct vcpu        *curr;           /* current task                    */
-    struct vcpu        *idle;           /* idle task for this cpu          */
     void               *sched_priv;
-    void               *sched_idlevpriv; /* default scheduler vcpu data    */
     struct timer        s_timer;        /* scheduling timer                */
     atomic_t            urgent_count;   /* how many urgent vcpus           */
-} __cacheline_aligned;
+};
 
 DECLARE_PER_CPU(struct schedule_data, schedule_data);
 DECLARE_PER_CPU(struct scheduler *, scheduler);