Skip to contentSkip to conversation

Cpupools: hypervisor part

PATCH In review Juergen Gross 2 participants 2 messages Apr 20, 2010

lore
Share & tools
lore
#0 lore raw

PATCH 1/6 Cpupools: hypervisor part

Signature · 6 lines
-- 
Juergen Gross                 Principal Developer Operating Systems
TSP ES&S SWE OS6                       Telephone: +49 (0) 89 3222 2967
Fujitsu Technology Solutions              e-mail: [email protected]
Domagkstr. 28                           Internet: ts.fujitsu.com
D-80807 Muenchen                 Company details: ts.fujitsu.com/imprint.html
Signed-off-by [email protected]
xen/arch/x86/domain_build.c +8 -3
diff -r fadf63ab49e7 xen/arch/x86/domain_build.c
@@ -9,6 +9,7 @@
 #include <xen/lib.h>
 #include <xen/ctype.h>
 #include <xen/sched.h>
+#include <xen/sched-if.h>
 #include <xen/smp.h>
 #include <xen/delay.h>
 #include <xen/event.h>
@@ -84,7 +85,7 @@ struct vcpu *__init alloc_dom0_vcpu0(voi
 struct vcpu *__init alloc_dom0_vcpu0(void)
 {
     if ( opt_dom0_max_vcpus == 0 )
-        opt_dom0_max_vcpus = num_online_cpus();
+        opt_dom0_max_vcpus = num_cpupool_cpus(cpupool0);
     if ( opt_dom0_max_vcpus > MAX_VIRT_CPUS )
         opt_dom0_max_vcpus = MAX_VIRT_CPUS;
 
@@ -277,7 +278,7 @@ int __init construct_dom0(
     unsigned long _initrd_start, unsigned long initrd_len,
     char *cmdline)
 {
-    int i, rc, compatible, compat32, order, machine;
+    int i, cpu, rc, compatible, compat32, order, machine;
     struct cpu_user_regs *regs;
     unsigned long pfn, mfn;
     unsigned long nr_pages;
@@ -776,8 +777,12 @@ int __init construct_dom0(
 
     printk("Dom0 has maximum %u VCPUs\n", opt_dom0_max_vcpus);
 
+    cpu = first_cpu(cpupool0->cpu_valid);
     for ( i = 1; i < opt_dom0_max_vcpus; i++ )
-        (void)alloc_vcpu(d, i, i % num_online_cpus());
+    {
+        cpu = cycle_cpu(cpu, cpupool0->cpu_valid);
+        (void)alloc_vcpu(d, i, cpu);
+    }
 
     /* Set up CR3 value for write_ptbase */
     if ( paging_mode_enabled(d) )
xen/arch/x86/mm.c +3 -3
diff -r fadf63ab49e7 xen/arch/x86/mm.c
@@ -242,7 +242,7 @@ void __init arch_init_memory(void)
      * Any Xen-heap pages that we will allow to be mapped will have
      * their domain field set to dom_xen.
      */
-    dom_xen = domain_create(DOMID_XEN, DOMCRF_dummy, 0);
+    dom_xen = domain_create(DOMID_XEN, CPUPOOLID_NONE, DOMCRF_dummy, 0);
     BUG_ON(dom_xen == NULL);
 
     /*
@@ -250,14 +250,14 @@ void __init arch_init_memory(void)
      * This domain owns I/O pages that are within the range of the page_info
      * array. Mappings occur at the priv of the caller.
      */
-    dom_io = domain_create(DOMID_IO, DOMCRF_dummy, 0);
+    dom_io = domain_create(DOMID_IO, CPUPOOLID_NONE, DOMCRF_dummy, 0);
     BUG_ON(dom_io == NULL);
     
     /*
      * Initialise our DOMID_IO domain.
      * This domain owns sharable pages.
      */
-    dom_cow = domain_create(DOMID_COW, DOMCRF_dummy, 0);
+    dom_cow = domain_create(DOMID_COW, CPUPOOLID_NONE, DOMCRF_dummy, 0);
     BUG_ON(dom_cow == NULL);
 
     /* First 1MB of RAM is historically marked as I/O. */
xen/arch/x86/platform_hypercall.c +3 -2
diff -r fadf63ab49e7 xen/arch/x86/platform_hypercall.c
@@ -19,6 +19,7 @@
 #include <xen/iocap.h>
 #include <xen/guest_access.h>
 #include <xen/acpi.h>
+#include <xen/sched-if.h>
 #include <asm/current.h>
 #include <public/platform.h>
 #include <acpi/cpufreq/processor_perf.h>
@@ -407,7 +408,7 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xe
         g_info = &op->u.pcpu_info;
 
         /* spin_trylock() avoids deadlock with stop_machine_run(). */
-        if ( !spin_trylock(&cpu_add_remove_lock) )
+        if ( !spin_trylock(&cpupool_lock) )
         {
             ret = -EBUSY;
             break;
@@ -430,7 +431,7 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xe
 
         g_info->max_present = last_cpu(cpu_present_map);
 
-        spin_unlock(&cpu_add_remove_lock);
+        spin_unlock(&cpupool_lock);
 
         ret = copy_to_guest(u_xenpf_op, op, 1) ? -EFAULT : 0;
     }
xen/arch/x86/setup.c +8 -2
diff -r fadf63ab49e7 xen/arch/x86/setup.c
@@ -2,6 +2,7 @@
 #include <xen/init.h>
 #include <xen/lib.h>
 #include <xen/sched.h>
+#include <xen/sched-if.h>
 #include <xen/domain.h>
 #include <xen/serial.h>
 #include <xen/softirq.h>
@@ -245,7 +246,7 @@ static void __init init_idle_domain(void
     /* Domain creation requires that scheduler structures are initialised. */
     scheduler_init();
 
-    idle_domain = domain_create(IDLE_DOMAIN_ID, 0, 0);
+    idle_domain = domain_create(IDLE_DOMAIN_ID, CPUPOOLID_NONE, 0, 0);
     if ( idle_domain == NULL )
         BUG();
     idle_domain->vcpu = idle_vcpu;
@@ -1093,8 +1094,13 @@ void __init __start_xen(unsigned long mb
     if ( !tboot_protect_mem_regions() )
         panic("Could not protect TXT memory regions\n");
 
+    /* Create initial cpupool 0. */
+    cpupool0 = cpupool_create(0, NULL);
+    if ( (cpupool0 == NULL) || cpupool0_cpu_assign(cpupool0) )
+        panic("Error creating cpupool 0\n");
+
     /* Create initial domain 0. */
-    dom0 = domain_create(0, DOMCRF_s3_integrity, DOM0_SSIDREF);
+    dom0 = domain_create(0, 0, DOMCRF_s3_integrity, DOM0_SSIDREF);
     if ( (dom0 == NULL) || (alloc_dom0_vcpu0() == NULL) )
         panic("Error creating domain 0\n");
 
xen/arch/x86/smpboot.c +16 -13
diff -r fadf63ab49e7 xen/arch/x86/smpboot.c
@@ -39,6 +39,7 @@
 #include <xen/mm.h>
 #include <xen/domain.h>
 #include <xen/sched.h>
+#include <xen/sched-if.h>
 #include <xen/irq.h>
 #include <xen/delay.h>
 #include <xen/softirq.h>
@@ -105,7 +106,6 @@ DEFINE_PER_CPU(int, cpu_state) = { 0 };
 DEFINE_PER_CPU(int, cpu_state) = { 0 };
 
 void *stack_base[NR_CPUS];
-DEFINE_SPINLOCK(cpu_add_remove_lock);
 
 /*
  * The bootstrap kernel entry code has set these up. Save them for
@@ -822,7 +822,7 @@ wakeup_secondary_cpu(int phys_apicid, un
 
 extern cpumask_t cpu_initialized;
 /*
- * Caller should hold cpu_add_remove_lock if not called when booting
+ * Caller should hold cpupool_lock if not called when booting
  */
 int alloc_cpu_id(void)
 {
@@ -986,8 +986,10 @@ static int __devinit do_boot_cpu(int api
 		cpucount--;
 
 		/* Mark the CPU as non-present */
+		spin_lock(&cpupool_lock);
 		x86_cpu_to_apicid[cpu] = BAD_APICID;
 		cpu_clear(cpu, cpu_present_map);
+		spin_unlock(&cpupool_lock);
 	} else {
 	}
 
@@ -1307,10 +1309,11 @@ int __cpu_disable(void)
 	sync_local_execstate();
 
 	/* It's now safe to remove this processor from the online map */
+	cpu_clear(cpu, cpupool0->cpu_valid);
 	cpu_clear(cpu, cpu_online_map);
 	fixup_irqs();
 
-	cpu_disable_scheduler();
+	cpu_disable_scheduler(cpu, 0);
 
 	return 0;
 }
@@ -1344,10 +1347,9 @@ int cpu_down(unsigned int cpu)
 	int err = 0;
 
 	/* spin_trylock() avoids deadlock with stop_machine_run(). */
-	if (!spin_trylock(&cpu_add_remove_lock))
+	if (!spin_trylock(&cpupool_lock))
 		return -EBUSY;
-
-	if (num_online_cpus() == 1) {
+	if ((!cpu_isset(cpu, cpupool0->cpu_valid)) || (cpus_weight(cpupool0->cpu_valid) == 1)) {
 		err = -EBUSY;
 		goto out;
 	}
@@ -1381,7 +1383,7 @@ out:
 out:
 	if (!err)
 		send_guest_global_virq(dom0, VIRQ_PCPU_STATE);
-	spin_unlock(&cpu_add_remove_lock);
+	spin_unlock(&cpupool_lock);
 	return err;
 }
 
@@ -1390,7 +1392,7 @@ int cpu_up(unsigned int cpu)
 	int err = 0;
 
 	/* spin_trylock() avoids deadlock with stop_machine_run(). */
-	if (!spin_trylock(&cpu_add_remove_lock))
+	if (!spin_trylock(&cpupool_lock))
 	    return -EBUSY;
 
 	if (cpu_online(cpu)) {
@@ -1408,7 +1410,7 @@ out:
 out:
 	if (!err)
 		send_guest_global_virq(dom0, VIRQ_PCPU_STATE);
-	spin_unlock(&cpu_add_remove_lock);
+	spin_unlock(&cpupool_lock);
 	return err;
 }
 
@@ -1494,14 +1496,14 @@ int cpu_add(uint32_t apic_id, uint32_t a
 		return -EEXIST;
 
 	/* spin_trylock() avoids deadlock with stop_machine_run(). */
-	if (!spin_trylock(&cpu_add_remove_lock))
+	if (!spin_trylock(&cpupool_lock))
 		return -EBUSY;
 
 	cpu = mp_register_lapic(apic_id, 1);
 
 	if (cpu < 0)
 	{
-		spin_unlock(&cpu_add_remove_lock);
+		spin_unlock(&cpupool_lock);
 		return cpu;
 	}
 
@@ -1518,7 +1520,7 @@ int cpu_add(uint32_t apic_id, uint32_t a
 				"Setup node failed for pxm %x\n", pxm);
 			x86_acpiid_to_apicid[acpi_id] = 0xff;
 			mp_unregister_lapic(apic_id, cpu);
-			spin_unlock(&cpu_add_remove_lock);
+			spin_unlock(&cpupool_lock);
 			return node;
 		}
 		apicid_to_node[apic_id] = node;
@@ -1526,7 +1528,7 @@ int cpu_add(uint32_t apic_id, uint32_t a
 
 	srat_detect_node(cpu);
 	numa_add_cpu(cpu);
-	spin_unlock(&cpu_add_remove_lock);
+	spin_unlock(&cpupool_lock);
 	dprintk(XENLOG_INFO, "Add CPU %x with index %x\n", apic_id, cpu);
 	return cpu;
 }
@@ -1570,6 +1572,7 @@ int __devinit __cpu_up(unsigned int cpu)
 		process_pending_softirqs();
 	}
 
+	cpupool_cpu_add(cpu);
 	cpufreq_add_cpu(cpu);
 	return 0;
 }
xen/common/Makefile +1 -0
diff -r fadf63ab49e7 xen/common/Makefile
@@ -1,5 +1,6 @@ obj-y += bitmap.o
 obj-y += bitmap.o
 obj-y += cpu.o
+obj-y += cpupool.o
 obj-y += domctl.o
 obj-y += domain.o
 obj-y += event_channel.o
xen/common/cpupool.c new file +580 -0

580 lines not on this page · raw message

xen/common/domain.c +8 -1
diff -r fadf63ab49e7 xen/common/domain.c
@@ -150,6 +150,8 @@ struct vcpu *alloc_vcpu(
 
     tasklet_init(&v->continue_hypercall_tasklet, NULL, 0);
 
+    tasklet_init(&v->continue_hypercall_tasklet, NULL, 0);
+
     if ( is_idle_domain(d) )
     {
         v->runstate.state = RUNSTATE_running;
@@ -212,7 +214,7 @@ custom_param("extra_guest_irqs", parse_e
 custom_param("extra_guest_irqs", parse_extra_guest_irqs);
 
 struct domain *domain_create(
-    domid_t domid, unsigned int domcr_flags, ssidref_t ssidref)
+    domid_t domid, int poolid, unsigned int domcr_flags, ssidref_t ssidref)
 {
     struct domain *d, **pd;
     enum { INIT_xsm = 1u<<0, INIT_rangeset = 1u<<1, INIT_evtchn = 1u<<2,
@@ -291,6 +293,9 @@ struct domain *domain_create(
     d->iomem_caps = rangeset_new(d, "I/O Memory", RANGESETF_prettyprint_hex);
     d->irq_caps   = rangeset_new(d, "Interrupts", 0);
     if ( (d->iomem_caps == NULL) || (d->irq_caps == NULL) )
+        goto fail;
+
+    if ( cpupool_add_domain(d, poolid) != 0 )
         goto fail;
 
     if ( sched_init_domain(d) != 0 )
@@ -600,6 +605,8 @@ static void complete_domain_destroy(stru
     arch_domain_destroy(d);
 
     rangeset_domain_destroy(d);
+
+    cpupool_rm_domain(d);
 
     sched_destroy_domain(d);
 
xen/common/domctl.c +27 -6
diff -r fadf63ab49e7 xen/common/domctl.c
@@ -11,6 +11,7 @@
 #include <xen/lib.h>
 #include <xen/mm.h>
 #include <xen/sched.h>
+#include <xen/sched-if.h>
 #include <xen/domain.h>
 #include <xen/event.h>
 #include <xen/domain_page.h>
@@ -140,10 +141,12 @@ void getdomaininfo(struct domain *d, str
     info->shared_info_frame = mfn_to_gmfn(d, __pa(d->shared_info)>>PAGE_SHIFT);
     BUG_ON(SHARED_M2P(info->shared_info_frame));
 
+    info->cpupool = d->cpupool ? d->cpupool->cpupool_id : CPUPOOLID_NONE;
+
     memcpy(info->handle, d->handle, sizeof(xen_domain_handle_t));
 }
 
-static unsigned int default_vcpu0_location(void)
+static unsigned int default_vcpu0_location(cpumask_t *online)
 {
     struct domain *d;
     struct vcpu   *v;
@@ -173,7 +176,7 @@ static unsigned int default_vcpu0_locati
     if ( cpus_weight(per_cpu(cpu_sibling_map, 0)) > 1 )
         cpu = next_cpu(cpu, per_cpu(cpu_sibling_map, 0));
     cpu_exclude_map = per_cpu(cpu_sibling_map, 0);
-    for_each_online_cpu ( i )
+    for_each_cpu_mask(i, *online)
     {
         if ( cpu_isset(i, cpu_exclude_map) )
             continue;
@@ -388,12 +391,14 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc
         domid_t        dom;
         static domid_t rover = 0;
         unsigned int domcr_flags;
+        int            pool = 0;
 
         ret = -EINVAL;
         if ( supervisor_mode_kernel ||
              (op->u.createdomain.flags &
              ~(XEN_DOMCTL_CDF_hvm_guest | XEN_DOMCTL_CDF_hap |
-               XEN_DOMCTL_CDF_s3_integrity | XEN_DOMCTL_CDF_oos_off)) )
+               XEN_DOMCTL_CDF_s3_integrity | XEN_DOMCTL_CDF_oos_off |
+               XEN_DOMCTL_CDF_pool)) )
             break;
 
         dom = op->domain;
@@ -429,9 +434,15 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc
             domcr_flags |= DOMCRF_s3_integrity;
         if ( op->u.createdomain.flags & XEN_DOMCTL_CDF_oos_off )
             domcr_flags |= DOMCRF_oos_off;
+        if ( op->u.createdomain.flags & XEN_DOMCTL_CDF_pool )
+            pool = op->u.createdomain.cpupool;
+
+        ret = -EINVAL;
+        if ( pool == CPUPOOLID_NONE )
+            break;
 
         ret = -ENOMEM;
-        d = domain_create(dom, domcr_flags, op->u.createdomain.ssidref);
+        d = domain_create(dom, pool, domcr_flags, op->u.createdomain.ssidref);
         if ( d == NULL )
             break;
 
@@ -450,6 +461,7 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc
     {
         struct domain *d;
         unsigned int i, max = op->u.max_vcpus.max, cpu;
+        cpumask_t *online;
 
         ret = -ESRCH;
         if ( (d = rcu_lock_domain_by_id(op->domain)) == NULL )
@@ -498,6 +510,7 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc
             goto maxvcpu_out;
 
         ret = -ENOMEM;
+        online = (d->cpupool == NULL) ? &cpu_online_map : &d->cpupool->cpu_valid;
         if ( max > d->max_vcpus )
         {
             struct vcpu **vcpus;
@@ -521,8 +534,8 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc
                 continue;
 
             cpu = (i == 0) ?
-                default_vcpu0_location() :
-                cycle_cpu(d->vcpu[i-1]->processor, cpu_online_map);
+                default_vcpu0_location(online) :
+                cycle_cpu(d->vcpu[i-1]->processor, *online);
 
             if ( alloc_vcpu(d, i, cpu) == NULL )
                 goto maxvcpu_out;
@@ -961,6 +974,14 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc
     }
     break;
 
+    case XEN_DOMCTL_cpupool_op:
+    {
+        ret = cpupool_do_domctl(&op->u.cpupool_op);
+        if ( (ret == 0) && copy_to_guest(u_domctl, op, 1) )
+            ret = -EFAULT;
+    }
+    break;
+
     default:
         ret = arch_do_domctl(op, u_domctl);
         break;
xen/common/sched_credit.c +276 -139

864 lines not on this page · raw message

xen/common/sched_credit2.c +189 -114

607 lines not on this page · raw message

xen/common/sched_sedf.c +104 -52

278 lines not on this page · raw message

xen/common/schedule.c +254 -46

304 lines not on this page · raw message

xen/include/asm-x86/smp.h +0 -1
diff -r fadf63ab49e7 xen/include/asm-x86/smp.h

Lines of this file are not shown. View the raw message.

xen/include/public/domctl.h +33 -2
diff -r fadf63ab49e7 xen/include/public/domctl.h

Lines of this file are not shown. View the raw message.

xen/include/xen/sched-if.h +48 -15

63 lines not on this page · raw message

xen/include/xen/sched.h +21 -2
diff -r fadf63ab49e7 xen/include/xen/sched.h

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel

Part of the diff is not shown here. View the raw message.

#1 lore raw

Juergen,

I don't think there's any need to change the domain creation interfaces. Drop new domains into a default pool, and then they can moved out (even immediately) by further control operations. This will avoid changes to the domain-creation public and private interfaces.

Also, you merge the cpu_add_remove_lock into a new cpupool_lock. That's not actually safe since cpu_add_remove_lock is held on entry to stopmachine_run(). Hence I assume now cpupool_lock is, and the only way to avoid deadlock possibilities would be for everyone to only spin_trylock on cpupool_lock, which isn't the case in your patch. Otherwise stopmachine_run can hang waiting for a CPU to enter its smr handler, while that CPU is waiting for the cpupool_lock to be released: a deadlock scenario.

I think you'll really need to find a method of synchronisation with cpu hotplug which does not involve a lock that is held across stopmachine_run(). My first suggestion in this respect would be to take a look at cpu_disable_scheduler(). This function deschedules vcpus from a cpu being offlined, and notice you can go fairly hogwild with minimal locking restrictions because everyone else is in a stopmachine 'safe place' with irqs disabled. So they cannot concurrently conflict with you.

So hooking yourself off cpu_disable_scheduler(), or adding some other new call-out from the end of __cpu_disable(), is quite probably the way to go to update cpupool info, break affinities, or whatever else you need to do.

-- Keir

On 20/04/2010 10:38, "Juergen Gross" <[email protected]> wrote: