This new cfg field was addded in 4.0 by 68a94cf528e6 "xm: Add maxvcpus
support" and, more crucially these day, it is what xl supports.
This removes the MAX_VIRT_CPUS limitation for such versions of Xen
(since maxvcpus is simply a count, not a bit mask) which is
particularly crucial on ARM where MAX_VIRT_CPUS == 1 (since all guests
are expected to support vcpu placement, and therefore only the boot
vcpu's info lives in the shared info page).
Add a new test case to both XM and XL config tests covering this case.
Note that although xm gained support for maxvcpus in Xen 4.0 the
xend_config_format was never bumped beyond 4 and the internal handling
remained in terms of vcpu_avail. Therefore the support for
xend >= XEND_CONFIG_VERSION_4_0_0 is somewhat theoretical.
Signed-off-by: Ian Campbell <ian.campbell(a)citrix.com>
---
src/xenconfig/xen_common.c | 72 ++++++++++++++++++++-------
src/xenconfig/xen_xm.c | 7 +++
tests/xlconfigdata/test-paravirt-maxvcpus.cfg | 13 +++++
tests/xlconfigdata/test-paravirt-maxvcpus.xml | 28 +++++++++++
tests/xlconfigtest.c | 1 +
tests/xmconfigdata/test-paravirt-maxvcpus.cfg | 13 +++++
tests/xmconfigdata/test-paravirt-maxvcpus.xml | 30 +++++++++++
tests/xmconfigtest.c | 1 +
8 files changed, 146 insertions(+), 19 deletions(-)
create mode 100644 tests/xlconfigdata/test-paravirt-maxvcpus.cfg
create mode 100644 tests/xlconfigdata/test-paravirt-maxvcpus.xml
create mode 100644 tests/xmconfigdata/test-paravirt-maxvcpus.cfg
create mode 100644 tests/xmconfigdata/test-paravirt-maxvcpus.xml
diff --git a/src/xenconfig/xen_common.c b/src/xenconfig/xen_common.c
index 0890c73..6f2afcc 100644
--- a/src/xenconfig/xen_common.c
+++ b/src/xenconfig/xen_common.c
@@ -492,24 +492,49 @@ xenParsePCI(virConfPtr conf, virDomainDefPtr def)
static int
-xenParseCPUFeatures(virConfPtr conf, virDomainDefPtr def)
+xenParseCPUFeatures(virConfPtr conf, virDomainDefPtr def,
+ int xendConfigVersion)
{
unsigned long count = 0;
const char *str = NULL;
int val = 0;
- if (xenConfigGetULong(conf, "vcpus", &count, 1) < 0 ||
- MAX_VIRT_CPUS < count)
- return -1;
+ /*
+ * xend prior to 4.0 understands vcpus as maxvcpus and vcpu_avail
+ * as a bit map of which cpus are online (default is all).
+ *
+ * xend from 4.0 onwards understands maxvcpus as maxvcpus and
+ * vcpus as the number which are online (from 0..N-1). The
+ * upstream commit (68a94cf528e6 "xm: Add maxvcpus support")
+ * claims that if maxvcpus is omitted then the old behaviour
+ * (i.e. obeying vcpu_avail) is retained, but AFAICT it was not,
+ * in this case vcpu==maxcpus==online cpus. This is good for us
+ * because handling anything else would be fiddly.
+ *
+ * xl understands vcpus + maxvcpus, but not vcpu_avail
+ * (ever).
+ */
+ if (xendConfigVersion < XEND_CONFIG_VERSION_4_0_0) {
+ if (xenConfigGetULong(conf, "vcpus", &count, 1) < 0 ||
+ MAX_VIRT_CPUS < count)
+ return -1;
+ def->maxvcpus = count;
- def->maxvcpus = count;
- if (xenConfigGetULong(conf, "vcpu_avail", &count, -1) < 0)
- return -1;
+ if (xenConfigGetULong(conf, "vcpu_avail", &count, -1) < 0)
+ return -1;
+ def->vcpus = MIN(count_one_bits_l(count), def->maxvcpus);
+ } else {
+ if (xenConfigGetULong(conf, "vcpus", &count, 1) < 0)
+ return -1;
+ def->vcpus = count;
+
+ if (xenConfigGetULong(conf, "maxvcpus", &count, def->vcpus) <
0)
+ return -1;
+ def->maxvcpus = count;
+ }
- def->vcpus = MIN(count_one_bits_l(count), def->maxvcpus);
if (xenConfigGetString(conf, "cpus", &str, NULL) < 0)
return -1;
-
if (str && (virBitmapParse(str, 0, &def->cpumask, 4096) < 0))
return -1;
@@ -1032,7 +1057,7 @@ xenParseConfigCommon(virConfPtr conf,
if (xenParseEventsActions(conf, def) < 0)
return -1;
- if (xenParseCPUFeatures(conf, def) < 0)
+ if (xenParseCPUFeatures(conf, def, xendConfigVersion) < 0)
return -1;
if (xenParseTimeOffset(conf, def, xendConfigVersion) < 0)
@@ -1519,19 +1544,28 @@ xenFormatCharDev(virConfPtr conf, virDomainDefPtr def)
static int
-xenFormatCPUAllocation(virConfPtr conf, virDomainDefPtr def)
+xenFormatCPUAllocation(virConfPtr conf, virDomainDefPtr def,
+ int xendConfigVersion)
{
int ret = -1;
char *cpus = NULL;
- if (xenConfigSetInt(conf, "vcpus", def->maxvcpus) < 0)
- goto cleanup;
+ if (xendConfigVersion >= XEND_CONFIG_VERSION_4_0_0) {
+ if (def->vcpus < def->maxvcpus &&
+ xenConfigSetInt(conf, "maxvcpus", def->maxvcpus) < 0)
+ goto cleanup;
+ if (xenConfigSetInt(conf, "vcpus", def->vcpus) < 0)
+ goto cleanup;
+ } else {
+ if (xenConfigSetInt(conf, "vcpus", def->maxvcpus) < 0)
+ goto cleanup;
- /* Computing the vcpu_avail bitmask works because MAX_VIRT_CPUS is
- either 32, or 64 on a platform where long is big enough. */
- if (def->vcpus < def->maxvcpus &&
- xenConfigSetInt(conf, "vcpu_avail", (1UL << def->vcpus) - 1)
< 0)
- goto cleanup;
+ /* Computing the vcpu_avail bitmask works because MAX_VIRT_CPUS is
+ either 32, or 64 on a platform where long is big enough. */
+ if (def->vcpus < def->maxvcpus &&
+ xenConfigSetInt(conf, "vcpu_avail", (1UL << def->vcpus) -
1) < 0)
+ goto cleanup;
+ }
if ((def->cpumask != NULL) &&
((cpus = virBitmapFormat(def->cpumask)) == NULL)) {
@@ -1826,7 +1860,7 @@ xenFormatConfigCommon(virConfPtr conf,
if (xenFormatMem(conf, def) < 0)
return -1;
- if (xenFormatCPUAllocation(conf, def) < 0)
+ if (xenFormatCPUAllocation(conf, def, xendConfigVersion) < 0)
return -1;
if (xenFormatCPUFeatures(conf, def, xendConfigVersion) < 0)
diff --git a/src/xenconfig/xen_xm.c b/src/xenconfig/xen_xm.c
index a4d1203..a2981f7 100644
--- a/src/xenconfig/xen_xm.c
+++ b/src/xenconfig/xen_xm.c
@@ -482,6 +482,13 @@ xenParseXM(virConfPtr conf,
if (xenParseConfigCommon(conf, def, caps, xendConfigVersion) < 0)
goto cleanup;
+ /*
+ * xend vcpu_avail field is an integer bitmap, so cannot handle more than
+ * MAX_VIRT_CPUS.
+ */
+ if (MAX_VIRT_CPUS < def->maxvcpus || MAX_VIRT_CPUS < def->vcpus)
+ goto cleanup;
+
if (xenParseXMOS(conf, def) < 0)
goto cleanup;
diff --git a/tests/xlconfigdata/test-paravirt-maxvcpus.cfg
b/tests/xlconfigdata/test-paravirt-maxvcpus.cfg
new file mode 100644
index 0000000..d506b75
--- /dev/null
+++ b/tests/xlconfigdata/test-paravirt-maxvcpus.cfg
@@ -0,0 +1,13 @@
+name = "XenGuest1"
+uuid = "45b60f51-88a9-47a8-a3b3-5e66d71b2283"
+maxmem = 512
+memory = 512
+maxvcpus = 8
+vcpus = 4
+localtime = 0
+on_poweroff = "preserve"
+on_reboot = "restart"
+on_crash = "preserve"
+vif = [ "mac=5a:36:0e:be:00:09" ]
+bootloader = "/usr/bin/pygrub"
+disk = [ "/var/lib/xen/images/debian/disk.qcow2,qcow2,xvda,w,backendtype=qdisk"
]
diff --git a/tests/xlconfigdata/test-paravirt-maxvcpus.xml
b/tests/xlconfigdata/test-paravirt-maxvcpus.xml
new file mode 100644
index 0000000..2e1f8f8
--- /dev/null
+++ b/tests/xlconfigdata/test-paravirt-maxvcpus.xml
@@ -0,0 +1,28 @@
+<domain type='xen'>
+ <name>XenGuest1</name>
+ <uuid>45b60f51-88a9-47a8-a3b3-5e66d71b2283</uuid>
+ <memory unit='KiB'>524288</memory>
+ <currentMemory unit='KiB'>524288</currentMemory>
+ <vcpu placement='static' current='4'>8</vcpu>
+ <bootloader>/usr/bin/pygrub</bootloader>
+ <os>
+ <type arch='x86_64' machine='xenpv'>linux</type>
+ </os>
+ <clock offset='utc' adjustment='reset'/>
+ <on_poweroff>preserve</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>preserve</on_crash>
+ <devices>
+ <disk type='file' device='disk'>
+ <driver name='qemu' type='qcow2'/>
+ <source file='/var/lib/xen/images/debian/disk.qcow2'/>
+ <target dev='xvda' bus='xen'/>
+ </disk>
+ <interface type='ethernet'>
+ <mac address='5a:36:0e:be:00:09'/>
+ </interface>
+ <console type='pty'>
+ <target type='xen' port='0'/>
+ </console>
+ </devices>
+</domain>
diff --git a/tests/xlconfigtest.c b/tests/xlconfigtest.c
index 08c43fb..b6f9b84 100644
--- a/tests/xlconfigtest.c
+++ b/tests/xlconfigtest.c
@@ -193,6 +193,7 @@ mymain(void)
ret = -1; \
} while (0)
+ DO_TEST("paravirt-maxvcpus", 5);
DO_TEST("new-disk", 5);
DO_TEST("spice", 5);
DO_TEST("spice-features", 5);
diff --git a/tests/xmconfigdata/test-paravirt-maxvcpus.cfg
b/tests/xmconfigdata/test-paravirt-maxvcpus.cfg
new file mode 100644
index 0000000..8d1ac4d
--- /dev/null
+++ b/tests/xmconfigdata/test-paravirt-maxvcpus.cfg
@@ -0,0 +1,13 @@
+name = "XenGuest1"
+uuid = "c7a5fdb0-cdaf-9455-926a-d65c16db1809"
+maxmem = 579
+memory = 394
+maxvcpus = 4
+vcpus = 2
+localtime = 0
+on_poweroff = "destroy"
+on_reboot = "restart"
+on_crash = "restart"
+vif = [ "mac=00:16:3e:66:94:9c,bridge=br0,script=vif-bridge" ]
+bootloader = "/usr/bin/pygrub"
+disk = [ "phy:/dev/HostVG/XenGuest1,xvda,w" ]
diff --git a/tests/xmconfigdata/test-paravirt-maxvcpus.xml
b/tests/xmconfigdata/test-paravirt-maxvcpus.xml
new file mode 100644
index 0000000..52463d8
--- /dev/null
+++ b/tests/xmconfigdata/test-paravirt-maxvcpus.xml
@@ -0,0 +1,30 @@
+<domain type='xen'>
+ <name>XenGuest1</name>
+ <uuid>c7a5fdb0-cdaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>592896</memory>
+ <currentMemory unit='KiB'>403456</currentMemory>
+ <vcpu placement='static' current='2'>4</vcpu>
+ <bootloader>/usr/bin/pygrub</bootloader>
+ <os>
+ <type arch='i686' machine='xenpv'>linux</type>
+ </os>
+ <clock offset='utc' adjustment='reset'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>restart</on_crash>
+ <devices>
+ <disk type='block' device='disk'>
+ <driver name='phy'/>
+ <source dev='/dev/HostVG/XenGuest1'/>
+ <target dev='xvda' bus='xen'/>
+ </disk>
+ <interface type='bridge'>
+ <mac address='00:16:3e:66:94:9c'/>
+ <source bridge='br0'/>
+ <script path='vif-bridge'/>
+ </interface>
+ <console type='pty'>
+ <target type='xen' port='0'/>
+ </console>
+ </devices>
+</domain>
diff --git a/tests/xmconfigtest.c b/tests/xmconfigtest.c
index 79b09ca..ff1f52b 100644
--- a/tests/xmconfigtest.c
+++ b/tests/xmconfigtest.c
@@ -220,6 +220,7 @@ mymain(void)
DO_TEST("paravirt-net-e1000", 3);
DO_TEST("paravirt-net-vifname", 3);
DO_TEST("paravirt-vcpu", 2);
+ DO_TEST("paravirt-maxvcpus", 5);
DO_TEST("fullvirt-old-cdrom", 1);
DO_TEST("fullvirt-new-cdrom", 2);
DO_TEST("fullvirt-utc", 2);
--
2.1.4