From e10da2f6d43593db062eab138fc5d138fe60a191 Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Apr 27 2012 20:56:05 +0000 Subject: Rebased to version 0.9.11.3 Abide URI username when connecting to hypervisor (bz 811397) Fix managed USB mode (bz 814866) Fix crash connecting to ESX host (bz 811891) --- diff --git a/foo/docs/api_extension/0001-add-to-xml.patch b/foo/docs/api_extension/0001-add-to-xml.patch new file mode 100644 index 0000000..9fee869 --- /dev/null +++ b/foo/docs/api_extension/0001-add-to-xml.patch @@ -0,0 +1,145 @@ +From a74f4e44649906dcd82151f7ef837f66d7fa2ab1 Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Mon, 27 Sep 2010 17:36:06 -0600 +Subject: [PATCH 01/15] vcpu: add current attribute to element + +Syntax agreed on in +https://www.redhat.com/archives/libvir-list/2010-September/msg00476.html + + + y +... + +can now be used to specify 1 <= x <= y current vcpus, in relation +to the boot-time max of y vcpus. If current is omitted, then +current and max are assumed to be the same value. + +* docs/schemas/domain.rng: Add new attribute. +* docs/formatdomain.html.in: Document it. +* tests/qemuxml2argvdata/qemuxml2argv-smp.xml: Add to +domainschematest. +* tests/xml2sexprdata/xml2sexpr-pv-vcpus.xml: Likewise. +--- + docs/formatdomain.html.in | 9 +++++-- + docs/schemas/domain.rng | 5 ++++ + tests/qemuxml2argvdata/qemuxml2argv-smp.xml | 28 +++++++++++++++++++++++++++ + tests/xml2sexprdata/xml2sexpr-pv-vcpus.xml | 22 +++++++++++++++++++++ + 4 files changed, 61 insertions(+), 3 deletions(-) + create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smp.xml + create mode 100644 tests/xml2sexprdata/xml2sexpr-pv-vcpus.xml + +diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in +index a8a1fac..96de121 100644 +--- a/docs/formatdomain.html.in ++++ b/docs/formatdomain.html.in +@@ -200,7 +200,7 @@ + <swap_hard_limit>2097152</swap_hard_limit> + <min_guarantee>65536</min_guarantee> + </memtune> +- <vcpu cpuset="1-4,^3,6">2</vcpu> ++ <vcpu cpuset="1-4,^3,6" current="1">2</vcpu> + ... + +
+@@ -238,7 +238,7 @@ + minimum memory allocation for the guest. The units for this value are + kilobytes (i.e. blocks of 1024 bytes) +
vcpu
+-
The content of this element defines the number of virtual ++
The content of this element defines the maximum number of virtual + CPUs allocated for the guest OS, which must be between 1 and + the maximum supported by the hypervisor. Since + 0.4.4, this element can contain an optional +@@ -246,7 +246,10 @@ + list of physical CPU numbers that virtual CPUs can be pinned + to. Each element in that list is either a single CPU number, + a range of CPU numbers, or a caret followed by a CPU number to +- be excluded from a previous range. ++ be excluded from a previous range. Since ++ 0.8.5, the optional attribute current can ++ be used to specify whether fewer than the maximum number of ++ virtual CPUs should be enabled. +
+
+ +diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng +index f230263..a934a77 100644 +--- a/docs/schemas/domain.rng ++++ b/docs/schemas/domain.rng +@@ -337,6 +337,11 @@ + + + ++ ++ ++ ++ ++ + + + +diff --git a/tests/qemuxml2argvdata/qemuxml2argv-smp.xml b/tests/qemuxml2argvdata/qemuxml2argv-smp.xml +new file mode 100644 +index 0000000..975f873 +--- /dev/null ++++ b/tests/qemuxml2argvdata/qemuxml2argv-smp.xml +@@ -0,0 +1,28 @@ ++ ++ QEMUGuest1 ++ c7a5fdbd-edaf-9455-926a-d65c16db1809 ++ 219200 ++ 219200 ++ 2 ++ ++ hvm ++ ++ ++ ++ ++ ++ ++ destroy ++ restart ++ destroy ++ ++ /usr/bin/qemu ++ ++ ++ ++
++ ++ ++ ++ ++ +diff --git a/tests/xml2sexprdata/xml2sexpr-pv-vcpus.xml b/tests/xml2sexprdata/xml2sexpr-pv-vcpus.xml +new file mode 100644 +index 0000000..d061e11 +--- /dev/null ++++ b/tests/xml2sexprdata/xml2sexpr-pv-vcpus.xml +@@ -0,0 +1,22 @@ ++ ++ pvtest ++ 596a5d2171f48fb2e068e2386a5c413e ++ ++ linux ++ /var/lib/xen/vmlinuz.2Dn2YT ++ /var/lib/xen/initrd.img.0u-Vhq ++ method=http://download.fedora.devel.redhat.com/pub/fedora/linux/core/test/5.91/x86_64/os ++ ++ 430080 ++ 4 ++ destroy ++ destroy ++ destroy ++ ++ ++ ++ ++ ++ ++ ++ +-- +1.7.2.3 + diff --git a/foo/docs/api_extension/0002-add-new-public-API.patch b/foo/docs/api_extension/0002-add-new-public-API.patch new file mode 100644 index 0000000..df93440 --- /dev/null +++ b/foo/docs/api_extension/0002-add-new-public-API.patch @@ -0,0 +1,62 @@ +From ea3f5c68093429c6ad507b45689cdf209c2c257b Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Fri, 24 Sep 2010 16:48:45 -0600 +Subject: [PATCH 02/15] vcpu: add new public API + +API agreed on in +https://www.redhat.com/archives/libvir-list/2010-September/msg00456.html, +but modified for enum names to be consistent with virDomainDeviceModifyFlags. + +* include/libvirt/libvirt.h.in (virDomainVcpuFlags) +(virDomainSetVcpusFlags, virDomainGetVcpusFlags): New +declarations. +* src/libvirt_public.syms: Export new symbols. +--- + include/libvirt/libvirt.h.in | 15 +++++++++++++++ + src/libvirt_public.syms | 2 ++ + 2 files changed, 17 insertions(+), 0 deletions(-) + +diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in +index 2eba61e..d0cc4c0 100644 +--- a/include/libvirt/libvirt.h.in ++++ b/include/libvirt/libvirt.h.in +@@ -915,8 +915,23 @@ struct _virVcpuInfo { + }; + typedef virVcpuInfo *virVcpuInfoPtr; + ++/* Flags for controlling virtual CPU hot-plugging. */ ++typedef enum { ++ /* Must choose at least one of these two bits; SetVcpus can choose both */ ++ VIR_DOMAIN_VCPU_LIVE = (1 << 0), /* Affect active domain */ ++ VIR_DOMAIN_VCPU_CONFIG = (1 << 1), /* Affect next boot */ ++ ++ /* Additional flags to be bit-wise OR'd in */ ++ VIR_DOMAIN_VCPU_MAXIMUM = (1 << 2), /* Max rather than current count */ ++} virDomainVcpuFlags; ++ + int virDomainSetVcpus (virDomainPtr domain, + unsigned int nvcpus); ++int virDomainSetVcpusFlags (virDomainPtr domain, ++ unsigned int nvcpus, ++ unsigned int flags); ++int virDomainGetVcpusFlags (virDomainPtr domain, ++ unsigned int flags); + + int virDomainPinVcpu (virDomainPtr domain, + unsigned int vcpu, +diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms +index fceb516..a8091b1 100644 +--- a/src/libvirt_public.syms ++++ b/src/libvirt_public.syms +@@ -409,6 +409,8 @@ LIBVIRT_0.8.5 { + global: + virDomainSetMemoryParameters; + virDomainGetMemoryParameters; ++ virDomainGetVcpusFlags; ++ virDomainSetVcpusFlags; + } LIBVIRT_0.8.2; + + # .... define new API here using predicted next version number .... +-- +1.7.2.3 + diff --git a/foo/docs/api_extension/0003-define-internal-driver-API.patch b/foo/docs/api_extension/0003-define-internal-driver-API.patch new file mode 100644 index 0000000..2156d97 --- /dev/null +++ b/foo/docs/api_extension/0003-define-internal-driver-API.patch @@ -0,0 +1,222 @@ +From dd255d64053e9960cd375994ce8f056522e12acc Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Mon, 27 Sep 2010 09:18:22 -0600 +Subject: [PATCH 03/15] vcpu: define internal driver API + +* src/driver.h (virDrvDomainSetVcpusFlags) +(virDrvDomainGetVcpusFlags): New typedefs. +(_virDriver): New callback members. +* src/esx/esx_driver.c (esxDriver): Add stub for driver. +* src/lxc/lxc_driver.c (lxcDriver): Likewise. +* src/opennebula/one_driver.c (oneDriver): Likewise. +* src/openvz/openvz_driver.c (openvzDriver): Likewise. +* src/phyp/phyp_driver.c (phypDriver): Likewise. +* src/qemu/qemu_driver.c (qemuDriver): Likewise. +* src/remote/remote_driver.c (remote_driver): Likewise. +* src/test/test_driver.c (testDriver): Likewise. +* src/uml/uml_driver.c (umlDriver): Likewise. +* src/vbox/vbox_tmpl.c (Driver): Likewise. +* src/xen/xen_driver.c (xenUnifiedDriver): Likewise. +* src/xenapi/xenapi_driver.c (xenapiDriver): Likewise. +--- + src/driver.h | 9 +++++++++ + src/esx/esx_driver.c | 2 ++ + src/lxc/lxc_driver.c | 2 ++ + src/opennebula/one_driver.c | 2 ++ + src/openvz/openvz_driver.c | 2 ++ + src/phyp/phyp_driver.c | 2 ++ + src/qemu/qemu_driver.c | 2 ++ + src/remote/remote_driver.c | 2 ++ + src/test/test_driver.c | 2 ++ + src/uml/uml_driver.c | 2 ++ + src/vbox/vbox_tmpl.c | 2 ++ + src/xen/xen_driver.c | 2 ++ + src/xenapi/xenapi_driver.c | 2 ++ + 13 files changed, 33 insertions(+), 0 deletions(-) + +diff --git a/src/driver.h b/src/driver.h +index 32aeb04..79a96c1 100644 +--- a/src/driver.h ++++ b/src/driver.h +@@ -185,6 +185,13 @@ typedef int + (*virDrvDomainSetVcpus) (virDomainPtr domain, + unsigned int nvcpus); + typedef int ++ (*virDrvDomainSetVcpusFlags) (virDomainPtr domain, ++ unsigned int nvcpus, ++ unsigned int flags); ++typedef int ++ (*virDrvDomainGetVcpusFlags) (virDomainPtr domain, ++ unsigned int flags); ++typedef int + (*virDrvDomainPinVcpu) (virDomainPtr domain, + unsigned int vcpu, + unsigned char *cpumap, +@@ -520,6 +527,8 @@ struct _virDriver { + virDrvDomainRestore domainRestore; + virDrvDomainCoreDump domainCoreDump; + virDrvDomainSetVcpus domainSetVcpus; ++ virDrvDomainSetVcpusFlags domainSetVcpusFlags; ++ virDrvDomainGetVcpusFlags domainGetVcpusFlags; + virDrvDomainPinVcpu domainPinVcpu; + virDrvDomainGetVcpus domainGetVcpus; + virDrvDomainGetMaxVcpus domainGetMaxVcpus; +diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c +index 1b4ee29..2a32374 100644 +--- a/src/esx/esx_driver.c ++++ b/src/esx/esx_driver.c +@@ -4160,6 +4160,8 @@ static virDriver esxDriver = { + NULL, /* domainRestore */ + NULL, /* domainCoreDump */ + esxDomainSetVcpus, /* domainSetVcpus */ ++ NULL, /* domainSetVcpusFlags */ ++ NULL, /* domainGetVcpusFlags */ + NULL, /* domainPinVcpu */ + NULL, /* domainGetVcpus */ + esxDomainGetMaxVcpus, /* domainGetMaxVcpus */ +diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c +index df814da..7563a8c 100644 +--- a/src/lxc/lxc_driver.c ++++ b/src/lxc/lxc_driver.c +@@ -2768,6 +2768,8 @@ static virDriver lxcDriver = { + NULL, /* domainRestore */ + NULL, /* domainCoreDump */ + NULL, /* domainSetVcpus */ ++ NULL, /* domainSetVcpusFlags */ ++ NULL, /* domainGetVcpusFlags */ + NULL, /* domainPinVcpu */ + NULL, /* domainGetVcpus */ + NULL, /* domainGetMaxVcpus */ +diff --git a/src/opennebula/one_driver.c b/src/opennebula/one_driver.c +index ced9a38..199fca3 100644 +--- a/src/opennebula/one_driver.c ++++ b/src/opennebula/one_driver.c +@@ -751,6 +751,8 @@ static virDriver oneDriver = { + NULL, /* domainRestore */ + NULL, /* domainCoreDump */ + NULL, /* domainSetVcpus */ ++ NULL, /* domainSetVcpusFlags */ ++ NULL, /* domainGetVcpusFlags */ + NULL, /* domainPinVcpu */ + NULL, /* domainGetVcpus */ + NULL, /* domainGetMaxVcpus */ +diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c +index 92cf4a1..9d19aeb 100644 +--- a/src/openvz/openvz_driver.c ++++ b/src/openvz/openvz_driver.c +@@ -1590,6 +1590,8 @@ static virDriver openvzDriver = { + NULL, /* domainRestore */ + NULL, /* domainCoreDump */ + openvzDomainSetVcpus, /* domainSetVcpus */ ++ NULL, /* domainSetVcpusFlags */ ++ NULL, /* domainGetVcpusFlags */ + NULL, /* domainPinVcpu */ + NULL, /* domainGetVcpus */ + openvzDomainGetMaxVcpus, /* domainGetMaxVcpus */ +diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c +index e63d8d9..6e0a5e9 100644 +--- a/src/phyp/phyp_driver.c ++++ b/src/phyp/phyp_driver.c +@@ -3941,6 +3941,8 @@ static virDriver phypDriver = { + NULL, /* domainRestore */ + NULL, /* domainCoreDump */ + phypDomainSetCPU, /* domainSetVcpus */ ++ NULL, /* domainSetVcpusFlags */ ++ NULL, /* domainGetVcpusFlags */ + NULL, /* domainPinVcpu */ + NULL, /* domainGetVcpus */ + phypGetLparCPUMAX, /* domainGetMaxVcpus */ +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index abd8e9d..3d17e04 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -12938,6 +12938,8 @@ static virDriver qemuDriver = { + qemudDomainRestore, /* domainRestore */ + qemudDomainCoreDump, /* domainCoreDump */ + qemudDomainSetVcpus, /* domainSetVcpus */ ++ NULL, /* domainSetVcpusFlags */ ++ NULL, /* domainGetVcpusFlags */ + qemudDomainPinVcpu, /* domainPinVcpu */ + qemudDomainGetVcpus, /* domainGetVcpus */ + qemudDomainGetMaxVcpus, /* domainGetMaxVcpus */ +diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c +index 0b10406..1a687ad 100644 +--- a/src/remote/remote_driver.c ++++ b/src/remote/remote_driver.c +@@ -10468,6 +10468,8 @@ static virDriver remote_driver = { + remoteDomainRestore, /* domainRestore */ + remoteDomainCoreDump, /* domainCoreDump */ + remoteDomainSetVcpus, /* domainSetVcpus */ ++ NULL, /* domainSetVcpusFlags */ ++ NULL, /* domainGetVcpusFlags */ + remoteDomainPinVcpu, /* domainPinVcpu */ + remoteDomainGetVcpus, /* domainGetVcpus */ + remoteDomainGetMaxVcpus, /* domainGetMaxVcpus */ +diff --git a/src/test/test_driver.c b/src/test/test_driver.c +index 7d4d119..6a00558 100644 +--- a/src/test/test_driver.c ++++ b/src/test/test_driver.c +@@ -5260,6 +5260,8 @@ static virDriver testDriver = { + testDomainRestore, /* domainRestore */ + testDomainCoreDump, /* domainCoreDump */ + testSetVcpus, /* domainSetVcpus */ ++ NULL, /* domainSetVcpusFlags */ ++ NULL, /* domainGetVcpusFlags */ + testDomainPinVcpu, /* domainPinVcpu */ + testDomainGetVcpus, /* domainGetVcpus */ + testDomainGetMaxVcpus, /* domainGetMaxVcpus */ +diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c +index 3dcd321..5161012 100644 +--- a/src/uml/uml_driver.c ++++ b/src/uml/uml_driver.c +@@ -2129,6 +2129,8 @@ static virDriver umlDriver = { + NULL, /* domainRestore */ + NULL, /* domainCoreDump */ + NULL, /* domainSetVcpus */ ++ NULL, /* domainSetVcpusFlags */ ++ NULL, /* domainGetVcpusFlags */ + NULL, /* domainPinVcpu */ + NULL, /* domainGetVcpus */ + NULL, /* domainGetMaxVcpus */ +diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c +index 7e7d8e4..cb9193a 100644 +--- a/src/vbox/vbox_tmpl.c ++++ b/src/vbox/vbox_tmpl.c +@@ -8267,6 +8267,8 @@ virDriver NAME(Driver) = { + NULL, /* domainRestore */ + NULL, /* domainCoreDump */ + vboxDomainSetVcpus, /* domainSetVcpus */ ++ NULL, /* domainSetVcpusFlags */ ++ NULL, /* domainGetVcpusFlags */ + NULL, /* domainPinVcpu */ + NULL, /* domainGetVcpus */ + vboxDomainGetMaxVcpus, /* domainGetMaxVcpus */ +diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c +index c2a4de3..7d67ced 100644 +--- a/src/xen/xen_driver.c ++++ b/src/xen/xen_driver.c +@@ -1951,6 +1951,8 @@ static virDriver xenUnifiedDriver = { + xenUnifiedDomainRestore, /* domainRestore */ + xenUnifiedDomainCoreDump, /* domainCoreDump */ + xenUnifiedDomainSetVcpus, /* domainSetVcpus */ ++ NULL, /* domainSetVcpusFlags */ ++ NULL, /* domainGetVcpusFlags */ + xenUnifiedDomainPinVcpu, /* domainPinVcpu */ + xenUnifiedDomainGetVcpus, /* domainGetVcpus */ + xenUnifiedDomainGetMaxVcpus, /* domainGetMaxVcpus */ +diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c +index e62a139..753169c 100644 +--- a/src/xenapi/xenapi_driver.c ++++ b/src/xenapi/xenapi_driver.c +@@ -1754,6 +1754,8 @@ static virDriver xenapiDriver = { + NULL, /* domainRestore */ + NULL, /* domainCoreDump */ + xenapiDomainSetVcpus, /* domainSetVcpus */ ++ NULL, /* domainSetVcpusFlags */ ++ NULL, /* domainGetVcpusFlags */ + xenapiDomainPinVcpu, /* domainPinVcpu */ + xenapiDomainGetVcpus, /* domainGetVcpus */ + xenapiDomainGetMaxVcpus, /* domainGetMaxVcpus */ +-- +1.7.2.3 + diff --git a/foo/docs/api_extension/0004-implement-the-public-APIs.patch b/foo/docs/api_extension/0004-implement-the-public-APIs.patch new file mode 100644 index 0000000..7f13f0a --- /dev/null +++ b/foo/docs/api_extension/0004-implement-the-public-APIs.patch @@ -0,0 +1,188 @@ +From 9d2c60799271d605f82dfd4bfa6ed7d14ad87e26 Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Mon, 27 Sep 2010 09:37:22 -0600 +Subject: [PATCH 04/15] vcpu: implement the public APIs + +Factors common checks (such as nonzero vcpu count) up front, but +drivers will still need to do additional flag checks. + +* src/libvirt.c (virDomainSetVcpusFlags, virDomainGetVcpusFlags): +New functions. +(virDomainSetVcpus, virDomainGetMaxVcpus): Refer to new API. +--- + src/libvirt.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- + 1 files changed, 134 insertions(+), 6 deletions(-) + +diff --git a/src/libvirt.c b/src/libvirt.c +index 629d97b..1b39210 100644 +--- a/src/libvirt.c ++++ b/src/libvirt.c +@@ -5192,7 +5192,9 @@ error: + * This function requires privileged access to the hypervisor. + * + * This command only changes the runtime configuration of the domain, +- * so can only be called on an active domain. ++ * so can only be called on an active domain. It is hypervisor-dependent ++ * whether it also affects persistent configuration; for more control, ++ * use virDomainSetVcpusFlags(). + * + * Returns 0 in case of success, -1 in case of failure. + */ +@@ -5237,13 +5239,139 @@ error: + } + + /** ++ * virDomainSetVcpusFlags: ++ * @domain: pointer to domain object, or NULL for Domain0 ++ * @nvcpus: the new number of virtual CPUs for this domain, must be at least 1 ++ * @flags: an OR'ed set of virDomainVcpuFlags ++ * ++ * Dynamically change the number of virtual CPUs used by the domain. ++ * Note that this call may fail if the underlying virtualization hypervisor ++ * does not support it or if growing the number is arbitrary limited. ++ * This function requires privileged access to the hypervisor. ++ * ++ * @flags must include VIR_DOMAIN_VCPU_LIVE to affect a running ++ * domain (which may fail if domain is not active), or ++ * VIR_DOMAIN_VCPU_CONFIG to affect the next boot via the XML ++ * description of the domain. Both flags may be set. ++ * ++ * If @flags includes VIR_DOMAIN_VCPU_MAXIMUM, then ++ * VIR_DOMAIN_VCPU_LIVE must be clear, and only the maximum virtual ++ * CPU limit is altered; generally, this value must be less than or ++ * equal to virConnectGetMaxVcpus(). Otherwise, this call affects the ++ * current virtual CPU limit, which must be less than or equal to the ++ * maximum limit. ++ * ++ * Returns 0 in case of success, -1 in case of failure. ++ */ ++ ++int ++virDomainSetVcpusFlags(virDomainPtr domain, unsigned int nvcpus, ++ unsigned int flags) ++{ ++ virConnectPtr conn; ++ VIR_DEBUG("domain=%p, nvcpus=%u, flags=%u", domain, nvcpus, flags); ++ ++ virResetLastError(); ++ ++ if (!VIR_IS_CONNECTED_DOMAIN(domain)) { ++ virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); ++ virDispatchError(NULL); ++ return (-1); ++ } ++ if (domain->conn->flags & VIR_CONNECT_RO) { ++ virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__); ++ goto error; ++ } ++ ++ /* Perform some argument validation common to all implementations. */ ++ if (nvcpus < 1 || (unsigned short) nvcpus != nvcpus || ++ (flags & (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) == 0) { ++ virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__); ++ goto error; ++ } ++ conn = domain->conn; ++ ++ if (conn->driver->domainSetVcpusFlags) { ++ int ret; ++ ret = conn->driver->domainSetVcpusFlags (domain, nvcpus, flags); ++ if (ret < 0) ++ goto error; ++ return ret; ++ } ++ ++ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); ++ ++error: ++ virDispatchError(domain->conn); ++ return -1; ++} ++ ++/** ++ * virDomainGetVcpusFlags: ++ * @domain: pointer to domain object, or NULL for Domain0 ++ * @flags: an OR'ed set of virDomainVcpuFlags ++ * ++ * Query the number of virtual CPUs used by the domain. Note that ++ * this call may fail if the underlying virtualization hypervisor does ++ * not support it. This function requires privileged access to the ++ * hypervisor. ++ * ++ * @flags must include either VIR_DOMAIN_VCPU_ACTIVE to query a ++ * running domain (which will fail if domain is not active), or ++ * VIR_DOMAIN_VCPU_PERSISTENT to query the XML description of the ++ * domain. It is an error to set both flags. ++ * ++ * If @flags includes VIR_DOMAIN_VCPU_MAXIMUM, then the maximum ++ * virtual CPU limit is queried. Otherwise, this call queries the ++ * current virtual CPU limit. ++ * ++ * Returns 0 in case of success, -1 in case of failure. ++ */ ++ ++int ++virDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags) ++{ ++ virConnectPtr conn; ++ VIR_DEBUG("domain=%p, flags=%u", domain, flags); ++ ++ virResetLastError(); ++ ++ if (!VIR_IS_CONNECTED_DOMAIN(domain)) { ++ virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); ++ virDispatchError(NULL); ++ return (-1); ++ } ++ ++ /* Exactly one of these two flags should be set. */ ++ if (!(flags & VIR_DOMAIN_VCPU_LIVE) == !(flags & VIR_DOMAIN_VCPU_CONFIG)) { ++ virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__); ++ goto error; ++ } ++ conn = domain->conn; ++ ++ if (conn->driver->domainGetVcpusFlags) { ++ int ret; ++ ret = conn->driver->domainGetVcpusFlags (domain, flags); ++ if (ret < 0) ++ goto error; ++ return ret; ++ } ++ ++ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); ++ ++error: ++ virDispatchError(domain->conn); ++ return -1; ++} ++ ++/** + * virDomainPinVcpu: + * @domain: pointer to domain object, or NULL for Domain0 + * @vcpu: virtual CPU number + * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN) +- * Each bit set to 1 means that corresponding CPU is usable. +- * Bytes are stored in little-endian order: CPU0-7, 8-15... +- * In each byte, lowest CPU number is least significant bit. ++ * Each bit set to 1 means that corresponding CPU is usable. ++ * Bytes are stored in little-endian order: CPU0-7, 8-15... ++ * In each byte, lowest CPU number is least significant bit. + * @maplen: number of bytes in cpumap, from 1 up to size of CPU map in + * underlying virtualization system (Xen...). + * If maplen < size, missing bytes are set to zero. +@@ -5371,9 +5499,9 @@ error: + * + * Provides the maximum number of virtual CPUs supported for + * the guest VM. If the guest is inactive, this is basically +- * the same as virConnectGetMaxVcpus. If the guest is running ++ * the same as virConnectGetMaxVcpus(). If the guest is running + * this will reflect the maximum number of virtual CPUs the +- * guest was booted with. ++ * guest was booted with. For more details, see virDomainGetVcpusFlags(). + * + * Returns the maximum of virtual CPU or -1 in case of error. + */ +-- +1.7.2.3 + diff --git a/foo/docs/api_extension/0005-implement-the-remote-protocol.patch b/foo/docs/api_extension/0005-implement-the-remote-protocol.patch new file mode 100644 index 0000000..77912a0 --- /dev/null +++ b/foo/docs/api_extension/0005-implement-the-remote-protocol.patch @@ -0,0 +1,421 @@ +From eb826444f90c2563dadf148630b0cd6a9b41ba1e Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Mon, 27 Sep 2010 10:10:06 -0600 +Subject: [PATCH 05/15] vcpu: implement the remote protocol + +Done by editing the first three files, then running +'make -C src rpcgen', then editing src/remote_protocol-structs +to match. + +* daemon/remote.c (remoteDispatchDomainSetVcpusFlags) +(remoteDispatchDomainGetVcpusFlags): New functions. +* src/remote/remote_driver.c (remoteDomainSetVcpusFlags) +(remoteDomainGetVcpusFlags, remote_driver): Client side +serialization. +* src/remote/remote_protocol.x +(remote_domain_set_vcpus_flags_args) +(remote_domain_get_vcpus_flags_args) +(remote_domain_get_vcpus_flags_ret) +(REMOTE_PROC_DOMAIN_SET_VCPUS_FLAGS) +(REMOTE_PROC_DOMAIN_GET_VCPUS_FLAGS): Define wire format. +* daemon/remote_dispatch_args.h: Regenerate. +* daemon/remote_dispatch_prototypes.h: Likewise. +* daemon/remote_dispatch_table.h: Likewise. +* src/remote/remote_protocol.c: Likewise. +* src/remote/remote_protocol.h: Likewise. +* src/remote_protocol-structs: Likewise. +--- + daemon/remote.c | 53 ++++++++++++++++++++++++++++++++ + daemon/remote_dispatch_args.h | 2 + + daemon/remote_dispatch_prototypes.h | 16 ++++++++++ + daemon/remote_dispatch_ret.h | 1 + + daemon/remote_dispatch_table.h | 10 ++++++ + src/remote/remote_driver.c | 57 +++++++++++++++++++++++++++++++++- + src/remote/remote_protocol.c | 33 ++++++++++++++++++++ + src/remote/remote_protocol.h | 26 ++++++++++++++++ + src/remote/remote_protocol.x | 19 +++++++++++- + src/remote_protocol-structs | 12 +++++++ + 10 files changed, 226 insertions(+), 3 deletions(-) + +diff --git a/daemon/remote.c b/daemon/remote.c +index 7a96e29..323f00c 100644 +--- a/daemon/remote.c ++++ b/daemon/remote.c +@@ -1751,6 +1751,33 @@ oom: + } + + static int ++remoteDispatchDomainGetVcpusFlags (struct qemud_server *server ATTRIBUTE_UNUSED, ++ struct qemud_client *client ATTRIBUTE_UNUSED, ++ virConnectPtr conn, ++ remote_message_header *hdr ATTRIBUTE_UNUSED, ++ remote_error *rerr, ++ remote_domain_get_vcpus_flags_args *args, ++ remote_domain_get_vcpus_flags_ret *ret) ++{ ++ virDomainPtr dom; ++ ++ dom = get_nonnull_domain (conn, args->dom); ++ if (dom == NULL) { ++ remoteDispatchConnError(rerr, conn); ++ return -1; ++ } ++ ++ ret->num = virDomainGetVcpusFlags (dom, args->flags); ++ if (ret->num == -1) { ++ virDomainFree(dom); ++ remoteDispatchConnError(rerr, conn); ++ return -1; ++ } ++ virDomainFree(dom); ++ return 0; ++} ++ ++static int + remoteDispatchDomainMigratePrepare (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, +@@ -2568,6 +2595,32 @@ remoteDispatchDomainSetVcpus (struct qemud_server *server ATTRIBUTE_UNUSED, + } + + static int ++remoteDispatchDomainSetVcpusFlags (struct qemud_server *server ATTRIBUTE_UNUSED, ++ struct qemud_client *client ATTRIBUTE_UNUSED, ++ virConnectPtr conn, ++ remote_message_header *hdr ATTRIBUTE_UNUSED, ++ remote_error *rerr, ++ remote_domain_set_vcpus_flags_args *args, ++ void *ret ATTRIBUTE_UNUSED) ++{ ++ virDomainPtr dom; ++ ++ dom = get_nonnull_domain (conn, args->dom); ++ if (dom == NULL) { ++ remoteDispatchConnError(rerr, conn); ++ return -1; ++ } ++ ++ if (virDomainSetVcpusFlags (dom, args->nvcpus, args->flags) == -1) { ++ virDomainFree(dom); ++ remoteDispatchConnError(rerr, conn); ++ return -1; ++ } ++ virDomainFree(dom); ++ return 0; ++} ++ ++static int + remoteDispatchDomainShutdown (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, +diff --git a/daemon/remote_dispatch_args.h b/daemon/remote_dispatch_args.h +index d8528b6..9583e9c 100644 +--- a/daemon/remote_dispatch_args.h ++++ b/daemon/remote_dispatch_args.h +@@ -167,3 +167,5 @@ + remote_domain_create_with_flags_args val_remote_domain_create_with_flags_args; + remote_domain_set_memory_parameters_args val_remote_domain_set_memory_parameters_args; + remote_domain_get_memory_parameters_args val_remote_domain_get_memory_parameters_args; ++ remote_domain_set_vcpus_flags_args val_remote_domain_set_vcpus_flags_args; ++ remote_domain_get_vcpus_flags_args val_remote_domain_get_vcpus_flags_args; +diff --git a/daemon/remote_dispatch_prototypes.h b/daemon/remote_dispatch_prototypes.h +index b674bb4..6b35851 100644 +--- a/daemon/remote_dispatch_prototypes.h ++++ b/daemon/remote_dispatch_prototypes.h +@@ -306,6 +306,14 @@ static int remoteDispatchDomainGetVcpus( + remote_error *err, + remote_domain_get_vcpus_args *args, + remote_domain_get_vcpus_ret *ret); ++static int remoteDispatchDomainGetVcpusFlags( ++ struct qemud_server *server, ++ struct qemud_client *client, ++ virConnectPtr conn, ++ remote_message_header *hdr, ++ remote_error *err, ++ remote_domain_get_vcpus_flags_args *args, ++ remote_domain_get_vcpus_flags_ret *ret); + static int remoteDispatchDomainHasCurrentSnapshot( + struct qemud_server *server, + struct qemud_client *client, +@@ -554,6 +562,14 @@ static int remoteDispatchDomainSetVcpus( + remote_error *err, + remote_domain_set_vcpus_args *args, + void *ret); ++static int remoteDispatchDomainSetVcpusFlags( ++ struct qemud_server *server, ++ struct qemud_client *client, ++ virConnectPtr conn, ++ remote_message_header *hdr, ++ remote_error *err, ++ remote_domain_set_vcpus_flags_args *args, ++ void *ret); + static int remoteDispatchDomainShutdown( + struct qemud_server *server, + struct qemud_client *client, +diff --git a/daemon/remote_dispatch_ret.h b/daemon/remote_dispatch_ret.h +index 17c9bca..3723b00 100644 +--- a/daemon/remote_dispatch_ret.h ++++ b/daemon/remote_dispatch_ret.h +@@ -136,3 +136,4 @@ + remote_domain_get_block_info_ret val_remote_domain_get_block_info_ret; + remote_domain_create_with_flags_ret val_remote_domain_create_with_flags_ret; + remote_domain_get_memory_parameters_ret val_remote_domain_get_memory_parameters_ret; ++ remote_domain_get_vcpus_flags_ret val_remote_domain_get_vcpus_flags_ret; +diff --git a/daemon/remote_dispatch_table.h b/daemon/remote_dispatch_table.h +index 47d95eb..dd2adc7 100644 +--- a/daemon/remote_dispatch_table.h ++++ b/daemon/remote_dispatch_table.h +@@ -997,3 +997,13 @@ + .args_filter = (xdrproc_t) xdr_remote_domain_get_memory_parameters_args, + .ret_filter = (xdrproc_t) xdr_remote_domain_get_memory_parameters_ret, + }, ++{ /* DomainSetVcpusFlags => 199 */ ++ .fn = (dispatch_fn) remoteDispatchDomainSetVcpusFlags, ++ .args_filter = (xdrproc_t) xdr_remote_domain_set_vcpus_flags_args, ++ .ret_filter = (xdrproc_t) xdr_void, ++}, ++{ /* DomainGetVcpusFlags => 200 */ ++ .fn = (dispatch_fn) remoteDispatchDomainGetVcpusFlags, ++ .args_filter = (xdrproc_t) xdr_remote_domain_get_vcpus_flags_args, ++ .ret_filter = (xdrproc_t) xdr_remote_domain_get_vcpus_flags_ret, ++}, +diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c +index 1a687ad..37c37ef 100644 +--- a/src/remote/remote_driver.c ++++ b/src/remote/remote_driver.c +@@ -2580,6 +2580,59 @@ done: + } + + static int ++remoteDomainSetVcpusFlags (virDomainPtr domain, unsigned int nvcpus, ++ unsigned int flags) ++{ ++ int rv = -1; ++ remote_domain_set_vcpus_flags_args args; ++ struct private_data *priv = domain->conn->privateData; ++ ++ remoteDriverLock(priv); ++ ++ make_nonnull_domain (&args.dom, domain); ++ args.nvcpus = nvcpus; ++ args.flags = flags; ++ ++ if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_SET_VCPUS_FLAGS, ++ (xdrproc_t) xdr_remote_domain_set_vcpus_flags_args, ++ (char *) &args, ++ (xdrproc_t) xdr_void, (char *) NULL) == -1) ++ goto done; ++ ++ rv = 0; ++ ++done: ++ remoteDriverUnlock(priv); ++ return rv; ++} ++ ++static int ++remoteDomainGetVcpusFlags (virDomainPtr domain, unsigned int flags) ++{ ++ int rv = -1; ++ remote_domain_get_vcpus_flags_args args; ++ remote_domain_get_vcpus_flags_ret ret; ++ struct private_data *priv = domain->conn->privateData; ++ ++ remoteDriverLock(priv); ++ ++ make_nonnull_domain (&args.dom, domain); ++ args.flags = flags; ++ ++ memset (&ret, 0, sizeof ret); ++ if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_VCPUS_FLAGS, ++ (xdrproc_t) xdr_remote_domain_get_vcpus_flags_args, (char *) &args, ++ (xdrproc_t) xdr_remote_domain_get_vcpus_flags_ret, (char *) &ret) == -1) ++ goto done; ++ ++ rv = ret.num; ++ ++done: ++ remoteDriverUnlock(priv); ++ return rv; ++} ++ ++static int + remoteDomainPinVcpu (virDomainPtr domain, + unsigned int vcpu, + unsigned char *cpumap, +@@ -10468,8 +10521,8 @@ static virDriver remote_driver = { + remoteDomainRestore, /* domainRestore */ + remoteDomainCoreDump, /* domainCoreDump */ + remoteDomainSetVcpus, /* domainSetVcpus */ +- NULL, /* domainSetVcpusFlags */ +- NULL, /* domainGetVcpusFlags */ ++ remoteDomainSetVcpusFlags, /* domainSetVcpusFlags */ ++ remoteDomainGetVcpusFlags, /* domainGetVcpusFlags */ + remoteDomainPinVcpu, /* domainPinVcpu */ + remoteDomainGetVcpus, /* domainGetVcpus */ + remoteDomainGetMaxVcpus, /* domainGetMaxVcpus */ +diff --git a/src/remote/remote_protocol.c b/src/remote/remote_protocol.c +index 5c55713..38ea050 100644 +--- a/src/remote/remote_protocol.c ++++ b/src/remote/remote_protocol.c +@@ -1355,6 +1355,39 @@ xdr_remote_domain_set_vcpus_args (XDR *xdrs, remote_domain_set_vcpus_args *objp) + } + + bool_t ++xdr_remote_domain_set_vcpus_flags_args (XDR *xdrs, remote_domain_set_vcpus_flags_args *objp) ++{ ++ ++ if (!xdr_remote_nonnull_domain (xdrs, &objp->dom)) ++ return FALSE; ++ if (!xdr_u_int (xdrs, &objp->nvcpus)) ++ return FALSE; ++ if (!xdr_u_int (xdrs, &objp->flags)) ++ return FALSE; ++ return TRUE; ++} ++ ++bool_t ++xdr_remote_domain_get_vcpus_flags_args (XDR *xdrs, remote_domain_get_vcpus_flags_args *objp) ++{ ++ ++ if (!xdr_remote_nonnull_domain (xdrs, &objp->dom)) ++ return FALSE; ++ if (!xdr_u_int (xdrs, &objp->flags)) ++ return FALSE; ++ return TRUE; ++} ++ ++bool_t ++xdr_remote_domain_get_vcpus_flags_ret (XDR *xdrs, remote_domain_get_vcpus_flags_ret *objp) ++{ ++ ++ if (!xdr_int (xdrs, &objp->num)) ++ return FALSE; ++ return TRUE; ++} ++ ++bool_t + xdr_remote_domain_pin_vcpu_args (XDR *xdrs, remote_domain_pin_vcpu_args *objp) + { + char **objp_cpp0 = (char **) (void *) &objp->cpumap.cpumap_val; +diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h +index 756da11..d75e76c 100644 +--- a/src/remote/remote_protocol.h ++++ b/src/remote/remote_protocol.h +@@ -750,6 +750,24 @@ struct remote_domain_set_vcpus_args { + }; + typedef struct remote_domain_set_vcpus_args remote_domain_set_vcpus_args; + ++struct remote_domain_set_vcpus_flags_args { ++ remote_nonnull_domain dom; ++ u_int nvcpus; ++ u_int flags; ++}; ++typedef struct remote_domain_set_vcpus_flags_args remote_domain_set_vcpus_flags_args; ++ ++struct remote_domain_get_vcpus_flags_args { ++ remote_nonnull_domain dom; ++ u_int flags; ++}; ++typedef struct remote_domain_get_vcpus_flags_args remote_domain_get_vcpus_flags_args; ++ ++struct remote_domain_get_vcpus_flags_ret { ++ int num; ++}; ++typedef struct remote_domain_get_vcpus_flags_ret remote_domain_get_vcpus_flags_ret; ++ + struct remote_domain_pin_vcpu_args { + remote_nonnull_domain dom; + int vcpu; +@@ -2281,6 +2299,8 @@ enum remote_procedure { + REMOTE_PROC_DOMAIN_CREATE_WITH_FLAGS = 196, + REMOTE_PROC_DOMAIN_SET_MEMORY_PARAMETERS = 197, + REMOTE_PROC_DOMAIN_GET_MEMORY_PARAMETERS = 198, ++ REMOTE_PROC_DOMAIN_SET_VCPUS_FLAGS = 199, ++ REMOTE_PROC_DOMAIN_GET_VCPUS_FLAGS = 200, + }; + typedef enum remote_procedure remote_procedure; + +@@ -2422,6 +2442,9 @@ extern bool_t xdr_remote_domain_define_xml_args (XDR *, remote_domain_define_xm + extern bool_t xdr_remote_domain_define_xml_ret (XDR *, remote_domain_define_xml_ret*); + extern bool_t xdr_remote_domain_undefine_args (XDR *, remote_domain_undefine_args*); + extern bool_t xdr_remote_domain_set_vcpus_args (XDR *, remote_domain_set_vcpus_args*); ++extern bool_t xdr_remote_domain_set_vcpus_flags_args (XDR *, remote_domain_set_vcpus_flags_args*); ++extern bool_t xdr_remote_domain_get_vcpus_flags_args (XDR *, remote_domain_get_vcpus_flags_args*); ++extern bool_t xdr_remote_domain_get_vcpus_flags_ret (XDR *, remote_domain_get_vcpus_flags_ret*); + extern bool_t xdr_remote_domain_pin_vcpu_args (XDR *, remote_domain_pin_vcpu_args*); + extern bool_t xdr_remote_domain_get_vcpus_args (XDR *, remote_domain_get_vcpus_args*); + extern bool_t xdr_remote_domain_get_vcpus_ret (XDR *, remote_domain_get_vcpus_ret*); +@@ -2762,6 +2785,9 @@ extern bool_t xdr_remote_domain_define_xml_args (); + extern bool_t xdr_remote_domain_define_xml_ret (); + extern bool_t xdr_remote_domain_undefine_args (); + extern bool_t xdr_remote_domain_set_vcpus_args (); ++extern bool_t xdr_remote_domain_set_vcpus_flags_args (); ++extern bool_t xdr_remote_domain_get_vcpus_flags_args (); ++extern bool_t xdr_remote_domain_get_vcpus_flags_ret (); + extern bool_t xdr_remote_domain_pin_vcpu_args (); + extern bool_t xdr_remote_domain_get_vcpus_args (); + extern bool_t xdr_remote_domain_get_vcpus_ret (); +diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x +index e80fb5f..d57e6d0 100644 +--- a/src/remote/remote_protocol.x ++++ b/src/remote/remote_protocol.x +@@ -768,6 +768,21 @@ struct remote_domain_set_vcpus_args { + int nvcpus; + }; + ++struct remote_domain_set_vcpus_flags_args { ++ remote_nonnull_domain dom; ++ unsigned int nvcpus; ++ unsigned int flags; ++}; ++ ++struct remote_domain_get_vcpus_flags_args { ++ remote_nonnull_domain dom; ++ unsigned int flags; ++}; ++ ++struct remote_domain_get_vcpus_flags_ret { ++ int num; ++}; ++ + struct remote_domain_pin_vcpu_args { + remote_nonnull_domain dom; + int vcpu; +@@ -2062,7 +2077,9 @@ enum remote_procedure { + REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON = 195, + REMOTE_PROC_DOMAIN_CREATE_WITH_FLAGS = 196, + REMOTE_PROC_DOMAIN_SET_MEMORY_PARAMETERS = 197, +- REMOTE_PROC_DOMAIN_GET_MEMORY_PARAMETERS = 198 ++ REMOTE_PROC_DOMAIN_GET_MEMORY_PARAMETERS = 198, ++ REMOTE_PROC_DOMAIN_SET_VCPUS_FLAGS = 199, ++ REMOTE_PROC_DOMAIN_GET_VCPUS_FLAGS = 200 + + /* + * Notice how the entries are grouped in sets of 10 ? +diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs +index 838423e..d505886 100644 +--- a/src/remote_protocol-structs ++++ b/src/remote_protocol-structs +@@ -461,6 +461,18 @@ struct remote_domain_set_vcpus_args { + remote_nonnull_domain dom; + int nvcpus; + }; ++struct remote_domain_set_vcpus_flags_args { ++ remote_nonnull_domain dom; ++ u_int nvcpus; ++ u_int flags; ++}; ++struct remote_domain_get_vcpus_flags_args { ++ remote_nonnull_domain dom; ++ u_int flags; ++}; ++struct remote_domain_get_vcpus_flags_ret { ++ int num; ++}; + struct remote_domain_pin_vcpu_args { + remote_nonnull_domain dom; + int vcpu; +-- +1.7.2.3 + diff --git a/foo/docs/api_extension/0006-make-old-API-trivially-wrap-to-new-API.patch b/foo/docs/api_extension/0006-make-old-API-trivially-wrap-to-new-API.patch new file mode 100644 index 0000000..1ef51fe --- /dev/null +++ b/foo/docs/api_extension/0006-make-old-API-trivially-wrap-to-new-API.patch @@ -0,0 +1,735 @@ +From 50c51f13e2af04afac46e181c4ed62581545a488 Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Mon, 27 Sep 2010 16:37:53 -0600 +Subject: [PATCH 06/15] vcpu: make old API trivially wrap to new API + +Note - this wrapping is completely mechanical; the old API will +function identically, since the new API validates that the exact +same flags are provided by the old API. On a per-driver basis, +it may make sense to have the old API pass a different set of flags, +but that should be done in the per-driver patch that implements +the full range of flag support in the new API. + +* src/esx/esx_driver.c (esxDomainSetVcpus, escDomainGetMaxVpcus): +Move guts... +(esxDomainSetVcpusFlags, esxDomainGetVcpusFlags): ...to new +functions. +(esxDriver): Trivially support the new API. +* src/openvz/openvz_driver.c (openvzDomainSetVcpus) +(openvzDomainSetVcpusFlags, openvzDomainGetMaxVcpus) +(openvzDomainGetVcpusFlags, openvzDriver): Likewise. +* src/phyp/phyp_driver.c (phypDomainSetCPU) +(phypDomainSetVcpusFlags, phypGetLparCPUMAX) +(phypDomainGetVcpusFlags, phypDriver): Likewise. +* src/qemu/qemu_driver.c (qemudDomainSetVcpus) +(qemudDomainSetVcpusFlags, qemudDomainGetMaxVcpus) +(qemudDomainGetVcpusFlags, qemuDriver): Likewise. +* src/test/test_driver.c (testSetVcpus, testDomainSetVcpusFlags) +(testDomainGetMaxVcpus, testDomainGetVcpusFlags, testDriver): +Likewise. +* src/vbox/vbox_tmpl.c (vboxDomainSetVcpus) +(vboxDomainSetVcpusFlags, virDomainGetMaxVcpus) +(virDomainGetVcpusFlags, virDriver): Likewise. +* src/xen/xen_driver.c (xenUnifiedDomainSetVcpus) +(xenUnifiedDomainSetVcpusFlags, xenUnifiedDomainGetMaxVcpus) +(xenUnifiedDomainGetVcpusFlags, xenUnifiedDriver): Likewise. +* src/xenapi/xenapi_driver.c (xenapiDomainSetVcpus) +(xenapiDomainSetVcpusFlags, xenapiDomainGetMaxVcpus) +(xenapiDomainGetVcpusFlags, xenapiDriver): Likewise. +(xenapiError): New helper macro. +--- + src/esx/esx_driver.c | 32 +++++++++++++++++++--- + src/openvz/openvz_driver.c | 34 +++++++++++++++++++++--- + src/phyp/phyp_driver.c | 32 ++++++++++++++++++++--- + src/qemu/qemu_driver.c | 38 +++++++++++++++++++++++++--- + src/test/test_driver.c | 36 ++++++++++++++++++++++--- + src/vbox/vbox_tmpl.c | 36 +++++++++++++++++++++++--- + src/xen/xen_driver.c | 34 ++++++++++++++++++++++--- + src/xenapi/xenapi_driver.c | 60 ++++++++++++++++++++++++++++++++++++++------ + 8 files changed, 263 insertions(+), 39 deletions(-) + +diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c +index 2a32374..b3e1284 100644 +--- a/src/esx/esx_driver.c ++++ b/src/esx/esx_driver.c +@@ -2384,7 +2384,8 @@ esxDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) + + + static int +-esxDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus) ++esxDomainSetVcpusFlags(virDomainPtr domain, unsigned int nvcpus, ++ unsigned int flags) + { + int result = -1; + esxPrivate *priv = domain->conn->privateData; +@@ -2394,6 +2395,11 @@ esxDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus) + esxVI_ManagedObjectReference *task = NULL; + esxVI_TaskInfoState taskInfoState; + ++ if (flags != VIR_DOMAIN_VCPU_LIVE) { ++ ESX_ERROR(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags); ++ return -1; ++ } ++ + if (nvcpus < 1) { + ESX_ERROR(VIR_ERR_INVALID_ARG, "%s", + _("Requested number of virtual CPUs must at least be 1")); +@@ -2453,15 +2459,26 @@ esxDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus) + } + + ++static int ++esxDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus) ++{ ++ return esxDomainSetVcpusFlags(domain, nvcpus, VIR_DOMAIN_VCPU_LIVE); ++} ++ + + static int +-esxDomainGetMaxVcpus(virDomainPtr domain) ++esxDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags) + { + esxPrivate *priv = domain->conn->privateData; + esxVI_String *propertyNameList = NULL; + esxVI_ObjectContent *hostSystem = NULL; + esxVI_DynamicProperty *dynamicProperty = NULL; + ++ if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) { ++ ESX_ERROR(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags); ++ return -1; ++ } ++ + if (priv->maxVcpus > 0) { + return priv->maxVcpus; + } +@@ -2507,7 +2524,12 @@ esxDomainGetMaxVcpus(virDomainPtr domain) + return priv->maxVcpus; + } + +- ++static int ++esxDomainGetMaxVcpus(virDomainPtr domain) ++{ ++ return esxDomainGetVcpusFlags(domain, (VIR_DOMAIN_VCPU_LIVE | ++ VIR_DOMAIN_VCPU_MAXIMUM)); ++} + + static char * + esxDomainDumpXML(virDomainPtr domain, int flags) +@@ -4160,8 +4182,8 @@ static virDriver esxDriver = { + NULL, /* domainRestore */ + NULL, /* domainCoreDump */ + esxDomainSetVcpus, /* domainSetVcpus */ +- NULL, /* domainSetVcpusFlags */ +- NULL, /* domainGetVcpusFlags */ ++ esxDomainSetVcpusFlags, /* domainSetVcpusFlags */ ++ esxDomainGetVcpusFlags, /* domainGetVcpusFlags */ + NULL, /* domainPinVcpu */ + NULL, /* domainGetVcpus */ + esxDomainGetMaxVcpus, /* domainGetMaxVcpus */ +diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c +index 9d19aeb..0f3cfdf 100644 +--- a/src/openvz/openvz_driver.c ++++ b/src/openvz/openvz_driver.c +@@ -67,7 +67,6 @@ + static int openvzGetProcessInfo(unsigned long long *cpuTime, int vpsid); + static int openvzGetMaxVCPUs(virConnectPtr conn, const char *type); + static int openvzDomainGetMaxVcpus(virDomainPtr dom); +-static int openvzDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus); + static int openvzDomainSetVcpusInternal(virDomainObjPtr vm, + unsigned int nvcpus); + static int openvzDomainSetMemoryInternal(virDomainObjPtr vm, +@@ -1211,11 +1210,24 @@ static int openvzGetMaxVCPUs(virConnectPtr conn ATTRIBUTE_UNUSED, + return -1; + } + ++static int ++openvzDomainGetVcpusFlags(virDomainPtr dom ATTRIBUTE_UNUSED, ++ unsigned int flags) ++{ ++ if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) { ++ openvzError(VIR_ERR_INVALID_ARG, _("unsupported flags (0x%x)"), flags); ++ return -1; ++ } + +-static int openvzDomainGetMaxVcpus(virDomainPtr dom ATTRIBUTE_UNUSED) { + return openvzGetMaxVCPUs(NULL, "openvz"); + } + ++static int openvzDomainGetMaxVcpus(virDomainPtr dom) ++{ ++ return openvzDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE | ++ VIR_DOMAIN_VCPU_MAXIMUM)); ++} ++ + static int openvzDomainSetVcpusInternal(virDomainObjPtr vm, + unsigned int nvcpus) + { +@@ -1241,12 +1253,18 @@ static int openvzDomainSetVcpusInternal(virDomainObjPtr vm, + return 0; + } + +-static int openvzDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus) ++static int openvzDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus, ++ unsigned int flags) + { + virDomainObjPtr vm; + struct openvz_driver *driver = dom->conn->privateData; + int ret = -1; + ++ if (flags != VIR_DOMAIN_VCPU_LIVE) { ++ openvzError(VIR_ERR_INVALID_ARG, _("unsupported flags (0x%x)"), flags); ++ return -1; ++ } ++ + openvzDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + openvzDriverUnlock(driver); +@@ -1272,6 +1290,12 @@ cleanup: + return ret; + } + ++static int ++openvzDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus) ++{ ++ return openvzDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE); ++} ++ + static virDrvOpenStatus openvzOpen(virConnectPtr conn, + virConnectAuthPtr auth ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED) +@@ -1590,8 +1614,8 @@ static virDriver openvzDriver = { + NULL, /* domainRestore */ + NULL, /* domainCoreDump */ + openvzDomainSetVcpus, /* domainSetVcpus */ +- NULL, /* domainSetVcpusFlags */ +- NULL, /* domainGetVcpusFlags */ ++ openvzDomainSetVcpusFlags, /* domainSetVcpusFlags */ ++ openvzDomainGetVcpusFlags, /* domainGetVcpusFlags */ + NULL, /* domainPinVcpu */ + NULL, /* domainGetVcpus */ + openvzDomainGetMaxVcpus, /* domainGetMaxVcpus */ +diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c +index 6e0a5e9..e284ae0 100644 +--- a/src/phyp/phyp_driver.c ++++ b/src/phyp/phyp_driver.c +@@ -1497,15 +1497,27 @@ phypGetLparCPU(virConnectPtr conn, const char *managed_system, int lpar_id) + } + + static int +-phypGetLparCPUMAX(virDomainPtr dom) ++phypDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags) + { + phyp_driverPtr phyp_driver = dom->conn->privateData; + char *managed_system = phyp_driver->managed_system; + ++ if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) { ++ PHYP_ERROR(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags); ++ return -1; ++ } ++ + return phypGetLparCPUGeneric(dom->conn, managed_system, dom->id, 1); + } + + static int ++phypGetLparCPUMAX(virDomainPtr dom) ++{ ++ return phypDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE | ++ VIR_DOMAIN_VCPU_MAXIMUM)); ++} ++ ++static int + phypGetRemoteSlot(virConnectPtr conn, const char *managed_system, + const char *lpar_name) + { +@@ -3831,7 +3843,8 @@ phypConnectGetCapabilities(virConnectPtr conn) + } + + static int +-phypDomainSetCPU(virDomainPtr dom, unsigned int nvcpus) ++phypDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus, ++ unsigned int flags) + { + ConnectionData *connection_data = dom->conn->networkPrivateData; + phyp_driverPtr phyp_driver = dom->conn->privateData; +@@ -3846,6 +3859,11 @@ phypDomainSetCPU(virDomainPtr dom, unsigned int nvcpus) + unsigned int amount = 0; + virBuffer buf = VIR_BUFFER_INITIALIZER; + ++ if (flags != VIR_DOMAIN_VCPU_LIVE) { ++ PHYP_ERROR(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags); ++ return -1; ++ } ++ + if ((ncpus = phypGetLparCPU(dom->conn, managed_system, dom->id)) == 0) + return 0; + +@@ -3891,6 +3909,12 @@ phypDomainSetCPU(virDomainPtr dom, unsigned int nvcpus) + + } + ++static int ++phypDomainSetCPU(virDomainPtr dom, unsigned int nvcpus) ++{ ++ return phypDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE); ++} ++ + static virDrvOpenStatus + phypVIOSDriverOpen(virConnectPtr conn, + virConnectAuthPtr auth ATTRIBUTE_UNUSED, +@@ -3941,8 +3965,8 @@ static virDriver phypDriver = { + NULL, /* domainRestore */ + NULL, /* domainCoreDump */ + phypDomainSetCPU, /* domainSetVcpus */ +- NULL, /* domainSetVcpusFlags */ +- NULL, /* domainGetVcpusFlags */ ++ phypDomainSetVcpusFlags, /* domainSetVcpusFlags */ ++ phypDomainGetVcpusFlags, /* domainGetVcpusFlags */ + NULL, /* domainPinVcpu */ + NULL, /* domainGetVcpus */ + phypGetLparCPUMAX, /* domainGetMaxVcpus */ +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index 3d17e04..7a2ea8f 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -5934,13 +5934,22 @@ unsupported: + } + + +-static int qemudDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus) { ++static int ++qemudDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus, ++ unsigned int flags) ++{ + struct qemud_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + const char * type; + int max; + int ret = -1; + ++ if (flags != VIR_DOMAIN_VCPU_LIVE) { ++ qemuReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), ++ flags); ++ return -1; ++ } ++ + qemuDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + qemuDriverUnlock(driver); +@@ -5994,6 +6003,12 @@ cleanup: + return ret; + } + ++static int ++qemudDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus) ++{ ++ return qemudDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE); ++} ++ + + static int + qemudDomainPinVcpu(virDomainPtr dom, +@@ -6150,12 +6165,20 @@ cleanup: + } + + +-static int qemudDomainGetMaxVcpus(virDomainPtr dom) { ++static int ++qemudDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags) ++{ + struct qemud_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + const char *type; + int ret = -1; + ++ if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) { ++ qemuReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), ++ flags); ++ return -1; ++ } ++ + qemuDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + qemuDriverUnlock(driver); +@@ -6183,6 +6206,13 @@ cleanup: + return ret; + } + ++static int ++qemudDomainGetMaxVcpus(virDomainPtr dom) ++{ ++ return qemudDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE | ++ VIR_DOMAIN_VCPU_MAXIMUM)); ++} ++ + static int qemudDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel) + { + struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; +@@ -12938,8 +12968,8 @@ static virDriver qemuDriver = { + qemudDomainRestore, /* domainRestore */ + qemudDomainCoreDump, /* domainCoreDump */ + qemudDomainSetVcpus, /* domainSetVcpus */ +- NULL, /* domainSetVcpusFlags */ +- NULL, /* domainGetVcpusFlags */ ++ qemudDomainSetVcpusFlags, /* domainSetVcpusFlags */ ++ qemudDomainGetVcpusFlags, /* domainGetVcpusFlags */ + qemudDomainPinVcpu, /* domainPinVcpu */ + qemudDomainGetVcpus, /* domainGetVcpus */ + qemudDomainGetMaxVcpus, /* domainGetMaxVcpus */ +diff --git a/src/test/test_driver.c b/src/test/test_driver.c +index 6a00558..b70c80d 100644 +--- a/src/test/test_driver.c ++++ b/src/test/test_driver.c +@@ -2029,17 +2029,37 @@ cleanup: + return ret; + } + +-static int testDomainGetMaxVcpus(virDomainPtr domain) ++static int ++testDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags) + { ++ if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) { ++ testError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags); ++ return -1; ++ } ++ + return testGetMaxVCPUs(domain->conn, "test"); + } + +-static int testSetVcpus(virDomainPtr domain, +- unsigned int nrCpus) { ++static int ++testDomainGetMaxVcpus(virDomainPtr domain) ++{ ++ return testDomainGetVcpusFlags(domain, (VIR_DOMAIN_VCPU_LIVE | ++ VIR_DOMAIN_VCPU_MAXIMUM)); ++} ++ ++static int ++testDomainSetVcpusFlags(virDomainPtr domain, unsigned int nrCpus, ++ unsigned int flags) ++{ + testConnPtr privconn = domain->conn->privateData; + virDomainObjPtr privdom = NULL; + int ret = -1, maxvcpus; + ++ if (flags != VIR_DOMAIN_VCPU_LIVE) { ++ testError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags); ++ return -1; ++ } ++ + /* Do this first before locking */ + maxvcpus = testDomainGetMaxVcpus(domain); + if (maxvcpus < 0) +@@ -2082,6 +2102,12 @@ cleanup: + return ret; + } + ++static int ++testSetVcpus(virDomainPtr domain, unsigned int nrCpus) ++{ ++ return testDomainSetVcpusFlags(domain, nrCpus, VIR_DOMAIN_VCPU_LIVE); ++} ++ + static int testDomainGetVcpus(virDomainPtr domain, + virVcpuInfoPtr info, + int maxinfo, +@@ -5260,8 +5286,8 @@ static virDriver testDriver = { + testDomainRestore, /* domainRestore */ + testDomainCoreDump, /* domainCoreDump */ + testSetVcpus, /* domainSetVcpus */ +- NULL, /* domainSetVcpusFlags */ +- NULL, /* domainGetVcpusFlags */ ++ testDomainSetVcpusFlags, /* domainSetVcpusFlags */ ++ testDomainGetVcpusFlags, /* domainGetVcpusFlags */ + testDomainPinVcpu, /* domainPinVcpu */ + testDomainGetVcpus, /* domainGetVcpus */ + testDomainGetMaxVcpus, /* domainGetMaxVcpus */ +diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c +index cb9193a..0cbe8b3 100644 +--- a/src/vbox/vbox_tmpl.c ++++ b/src/vbox/vbox_tmpl.c +@@ -1839,13 +1839,21 @@ cleanup: + return ret; + } + +-static int vboxDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus) { ++static int ++vboxDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus, ++ unsigned int flags) ++{ + VBOX_OBJECT_CHECK(dom->conn, int, -1); + IMachine *machine = NULL; + vboxIID *iid = NULL; + PRUint32 CPUCount = nvcpus; + nsresult rc; + ++ if (flags != VIR_DOMAIN_VCPU_LIVE) { ++ vboxError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags); ++ return -1; ++ } ++ + #if VBOX_API_VERSION == 2002 + if (VIR_ALLOC(iid) < 0) { + virReportOOMError(); +@@ -1887,11 +1895,24 @@ cleanup: + return ret; + } + +-static int vboxDomainGetMaxVcpus(virDomainPtr dom) { ++static int ++vboxDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus) ++{ ++ return vboxDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE); ++} ++ ++static int ++vboxDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags) ++{ + VBOX_OBJECT_CHECK(dom->conn, int, -1); + ISystemProperties *systemProperties = NULL; + PRUint32 maxCPUCount = 0; + ++ if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) { ++ vboxError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags); ++ return -1; ++ } ++ + /* Currently every domain supports the same number of max cpus + * as that supported by vbox and thus take it directly from + * the systemproperties. +@@ -1909,6 +1930,13 @@ static int vboxDomainGetMaxVcpus(virDomainPtr dom) { + return ret; + } + ++static int ++vboxDomainGetMaxVcpus(virDomainPtr dom) ++{ ++ return vboxDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE | ++ VIR_DOMAIN_VCPU_MAXIMUM)); ++} ++ + static char *vboxDomainDumpXML(virDomainPtr dom, int flags) { + VBOX_OBJECT_CHECK(dom->conn, char *, NULL); + virDomainDefPtr def = NULL; +@@ -8267,8 +8295,8 @@ virDriver NAME(Driver) = { + NULL, /* domainRestore */ + NULL, /* domainCoreDump */ + vboxDomainSetVcpus, /* domainSetVcpus */ +- NULL, /* domainSetVcpusFlags */ +- NULL, /* domainGetVcpusFlags */ ++ vboxDomainSetVcpusFlags, /* domainSetVcpusFlags */ ++ vboxDomainGetVcpusFlags, /* domainGetVcpusFlags */ + NULL, /* domainPinVcpu */ + NULL, /* domainGetVcpus */ + vboxDomainGetMaxVcpus, /* domainGetMaxVcpus */ +diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c +index 7d67ced..d6c9c57 100644 +--- a/src/xen/xen_driver.c ++++ b/src/xen/xen_driver.c +@@ -1069,11 +1069,18 @@ xenUnifiedDomainCoreDump (virDomainPtr dom, const char *to, int flags) + } + + static int +-xenUnifiedDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus) ++xenUnifiedDomainSetVcpusFlags (virDomainPtr dom, unsigned int nvcpus, ++ unsigned int flags) + { + GET_PRIVATE(dom->conn); + int i; + ++ if (flags != VIR_DOMAIN_VCPU_LIVE) { ++ xenUnifiedError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), ++ flags); ++ return -1; ++ } ++ + /* Try non-hypervisor methods first, then hypervisor direct method + * as a last resort. + */ +@@ -1093,6 +1100,12 @@ xenUnifiedDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus) + } + + static int ++xenUnifiedDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus) ++{ ++ return xenUnifiedDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE); ++} ++ ++static int + xenUnifiedDomainPinVcpu (virDomainPtr dom, unsigned int vcpu, + unsigned char *cpumap, int maplen) + { +@@ -1126,11 +1139,17 @@ xenUnifiedDomainGetVcpus (virDomainPtr dom, + } + + static int +-xenUnifiedDomainGetMaxVcpus (virDomainPtr dom) ++xenUnifiedDomainGetVcpusFlags (virDomainPtr dom, unsigned int flags) + { + GET_PRIVATE(dom->conn); + int i, ret; + ++ if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) { ++ xenUnifiedError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), ++ flags); ++ return -1; ++ } ++ + for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i) + if (priv->opened[i] && drivers[i]->domainGetMaxVcpus) { + ret = drivers[i]->domainGetMaxVcpus (dom); +@@ -1140,6 +1159,13 @@ xenUnifiedDomainGetMaxVcpus (virDomainPtr dom) + return -1; + } + ++static int ++xenUnifiedDomainGetMaxVcpus (virDomainPtr dom) ++{ ++ return xenUnifiedDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE | ++ VIR_DOMAIN_VCPU_MAXIMUM)); ++} ++ + static char * + xenUnifiedDomainDumpXML (virDomainPtr dom, int flags) + { +@@ -1951,8 +1977,8 @@ static virDriver xenUnifiedDriver = { + xenUnifiedDomainRestore, /* domainRestore */ + xenUnifiedDomainCoreDump, /* domainCoreDump */ + xenUnifiedDomainSetVcpus, /* domainSetVcpus */ +- NULL, /* domainSetVcpusFlags */ +- NULL, /* domainGetVcpusFlags */ ++ xenUnifiedDomainSetVcpusFlags, /* domainSetVcpusFlags */ ++ xenUnifiedDomainGetVcpusFlags, /* domainGetVcpusFlags */ + xenUnifiedDomainPinVcpu, /* domainPinVcpu */ + xenUnifiedDomainGetVcpus, /* domainGetVcpus */ + xenUnifiedDomainGetMaxVcpus, /* domainGetMaxVcpus */ +diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c +index 753169c..7d4ab8d 100644 +--- a/src/xenapi/xenapi_driver.c ++++ b/src/xenapi/xenapi_driver.c +@@ -40,6 +40,11 @@ + #include "xenapi_driver_private.h" + #include "xenapi_utils.h" + ++#define VIR_FROM_THIS VIR_FROM_XENAPI ++ ++#define xenapiError(code, ...) \ ++ virReportErrorHelper(NULL, VIR_FROM_THIS, code, __FILE__, \ ++ __FUNCTION__, __LINE__, __VA_ARGS__) + + /* + * getCapsObject +@@ -987,19 +992,26 @@ xenapiDomainGetInfo (virDomainPtr dom, virDomainInfoPtr info) + + + /* +- * xenapiDomainSetVcpus ++ * xenapiDomainSetVcpusFlags + * + * Sets the VCPUs on the domain + * Return 0 on success or -1 in case of error + */ + static int +-xenapiDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus) ++xenapiDomainSetVcpusFlags (virDomainPtr dom, unsigned int nvcpus, ++ unsigned int flags) + { +- + /* vm.set_vcpus_max */ + xen_vm vm; + xen_vm_set *vms; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; ++ ++ if (flags != VIR_DOMAIN_VCPU_LIVE) { ++ xenapiError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), ++ flags); ++ return -1; ++ } ++ + if (xen_vm_get_by_name_label(session, &vms, dom->name) && vms->size > 0) { + if (vms->size != 1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, +@@ -1019,6 +1031,18 @@ xenapiDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus) + } + + /* ++ * xenapiDomainSetVcpus ++ * ++ * Sets the VCPUs on the domain ++ * Return 0 on success or -1 in case of error ++ */ ++static int ++xenapiDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus) ++{ ++ return xenapiDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE); ++} ++ ++/* + * xenapiDomainPinVcpu + * + * Dynamically change the real CPUs which can be allocated to a virtual CPU +@@ -1140,19 +1164,26 @@ xenapiDomainGetVcpus (virDomainPtr dom, + } + + /* +- * xenapiDomainGetMaxVcpus ++ * xenapiDomainGetVcpusFlags + * + * +- * Returns maximum number of Vcpus on success or -1 in case of error ++ * Returns Vcpus count on success or -1 in case of error + */ + static int +-xenapiDomainGetMaxVcpus (virDomainPtr dom) ++xenapiDomainGetVcpusFlags (virDomainPtr dom, unsigned int flags) + { + xen_vm vm; + xen_vm_set *vms; + int64_t maxvcpu = 0; + enum xen_vm_power_state state; + xen_session *session = ((struct _xenapiPrivate *)(dom->conn->privateData))->session; ++ ++ if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) { ++ xenapiError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), ++ flags); ++ return -1; ++ } ++ + if (xen_vm_get_by_name_label(session, &vms, dom->name) && vms->size > 0) { + if (vms->size != 1) { + xenapiSessionErrorHandler(dom->conn, VIR_ERR_INTERNAL_ERROR, +@@ -1176,6 +1207,19 @@ xenapiDomainGetMaxVcpus (virDomainPtr dom) + } + + /* ++ * xenapiDomainGetMaxVcpus ++ * ++ * ++ * Returns maximum number of Vcpus on success or -1 in case of error ++ */ ++static int ++xenapiDomainGetMaxVcpus (virDomainPtr dom) ++{ ++ return xenapiDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_LIVE | ++ VIR_DOMAIN_VCPU_MAXIMUM)); ++} ++ ++/* + * xenapiDomainDumpXML + * + * +@@ -1754,8 +1798,8 @@ static virDriver xenapiDriver = { + NULL, /* domainRestore */ + NULL, /* domainCoreDump */ + xenapiDomainSetVcpus, /* domainSetVcpus */ +- NULL, /* domainSetVcpusFlags */ +- NULL, /* domainGetVcpusFlags */ ++ xenapiDomainSetVcpusFlags, /* domainSetVcpusFlags */ ++ xenapiDomainGetVcpusFlags, /* domainGetVcpusFlags */ + xenapiDomainPinVcpu, /* domainPinVcpu */ + xenapiDomainGetVcpus, /* domainGetVcpus */ + xenapiDomainGetMaxVcpus, /* domainGetMaxVcpus */ +-- +1.7.2.3 + diff --git a/foo/docs/api_extension/0007-add-virsh-support.patch b/foo/docs/api_extension/0007-add-virsh-support.patch new file mode 100644 index 0000000..8c5494e --- /dev/null +++ b/foo/docs/api_extension/0007-add-virsh-support.patch @@ -0,0 +1,388 @@ +From bf945ee97b72d3b0c4fc2da04530f5294f529d66 Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Wed, 29 Sep 2010 15:20:23 -0600 +Subject: [PATCH 08/15] vcpu: add virsh support + +* tools/virsh.c (cmdSetvcpus): Add new flags. Let invalid +commands through to driver, to ease testing of hypervisor argument +validation. +(cmdMaxvcpus, cmdVcpucount): New commands. +(commands): Add new commands. +* tools/virsh.pod (setvcpus, vcpucount, maxvcpus): Document new +behavior. +--- + tools/virsh.c | 247 ++++++++++++++++++++++++++++++++++++++++++++++++++----- + tools/virsh.pod | 38 ++++++++- + 2 files changed, 262 insertions(+), 23 deletions(-) + +diff --git a/tools/virsh.c b/tools/virsh.c +index 4f8c495..7fb7fbd 100644 +--- a/tools/virsh.c ++++ b/tools/virsh.c +@@ -2281,10 +2281,216 @@ cmdFreecell(vshControl *ctl, const vshCmd *cmd) + } + + /* ++ * "maxvcpus" command ++ */ ++static const vshCmdInfo info_maxvcpus[] = { ++ {"help", N_("connection vcpu maximum")}, ++ {"desc", N_("Show maximum number of virtual CPUs for guests on this connection.")}, ++ {NULL, NULL} ++}; ++ ++static const vshCmdOptDef opts_maxvcpus[] = { ++ {"type", VSH_OT_STRING, 0, N_("domain type")}, ++ {NULL, 0, 0, NULL} ++}; ++ ++static int ++cmdMaxvcpus(vshControl *ctl, const vshCmd *cmd) ++{ ++ char *type; ++ int vcpus; ++ ++ type = vshCommandOptString(cmd, "type", NULL); ++ ++ if (!vshConnectionUsability(ctl, ctl->conn)) ++ return FALSE; ++ ++ vcpus = virConnectGetMaxVcpus(ctl->conn, type); ++ if (vcpus < 0) ++ return FALSE; ++ vshPrint(ctl, "%d\n", vcpus); ++ ++ return TRUE; ++} ++ ++/* ++ * "vcpucount" command ++ */ ++static const vshCmdInfo info_vcpucount[] = { ++ {"help", N_("domain vcpu counts")}, ++ {"desc", N_("Returns the number of virtual CPUs used by the domain.")}, ++ {NULL, NULL} ++}; ++ ++static const vshCmdOptDef opts_vcpucount[] = { ++ {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, ++ {"maximum", VSH_OT_BOOL, 0, N_("get maximum cap on vcpus")}, ++ {"current", VSH_OT_BOOL, 0, N_("get current vcpu usage")}, ++ {"config", VSH_OT_BOOL, 0, N_("get value to be used on next boot")}, ++ {"live", VSH_OT_BOOL, 0, N_("get value from running domain")}, ++ {NULL, 0, 0, NULL} ++}; ++ ++static int ++cmdVcpucount(vshControl *ctl, const vshCmd *cmd) ++{ ++ virDomainPtr dom; ++ int ret = TRUE; ++ int maximum = vshCommandOptBool(cmd, "maximum"); ++ int current = vshCommandOptBool(cmd, "current"); ++ int config = vshCommandOptBool(cmd, "config"); ++ int live = vshCommandOptBool(cmd, "live"); ++ bool all = maximum + current + config + live == 0; ++ int count; ++ ++ if (maximum && current) { ++ vshError(ctl, "%s", ++ _("--maximum and --current cannot both be specified")); ++ return FALSE; ++ } ++ if (config && live) { ++ vshError(ctl, "%s", ++ _("--config and --live cannot both be specified")); ++ return FALSE; ++ } ++ /* We want one of each pair of mutually exclusive options; that ++ * is, use of flags requires exactly two options. */ ++ if (maximum + current + config + live == 1) { ++ vshError(ctl, ++ _("when using --%s, either --%s or --%s must be specified"), ++ (maximum ? "maximum" : current ? "current" ++ : config ? "config" : "live"), ++ maximum + current ? "config" : "maximum", ++ maximum + current ? "live" : "current"); ++ return FALSE; ++ } ++ ++ if (!vshConnectionUsability(ctl, ctl->conn)) ++ return FALSE; ++ ++ if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) ++ return FALSE; ++ ++ /* In all cases, try the new API first; if it fails because we are ++ * talking to an older client, try a fallback API before giving ++ * up. */ ++ if (all || (maximum && config)) { ++ count = virDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_MAXIMUM | ++ VIR_DOMAIN_VCPU_CONFIG)); ++ if (count < 0 && (last_error->code == VIR_ERR_NO_SUPPORT ++ || last_error->code == VIR_ERR_INVALID_ARG)) { ++ char *tmp; ++ char *xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_INACTIVE); ++ if (xml && (tmp = strstr(xml, "'); ++ if (!tmp || virStrToLong_i(tmp + 1, &tmp, 10, &count) < 0) ++ count = -1; ++ } ++ VIR_FREE(xml); ++ } ++ ++ if (count < 0) { ++ virshReportError(ctl); ++ ret = FALSE; ++ } else if (all) { ++ vshPrint(ctl, "%-12s %-12s %3d\n", _("maximum"), _("config"), ++ count); ++ } else { ++ vshPrint(ctl, "%d\n", count); ++ } ++ virFreeError(last_error); ++ last_error = NULL; ++ } ++ ++ if (all || (maximum && live)) { ++ count = virDomainGetVcpusFlags(dom, (VIR_DOMAIN_VCPU_MAXIMUM | ++ VIR_DOMAIN_VCPU_LIVE)); ++ if (count < 0 && (last_error->code == VIR_ERR_NO_SUPPORT ++ || last_error->code == VIR_ERR_INVALID_ARG)) { ++ count = virDomainGetMaxVcpus(dom); ++ } ++ ++ if (count < 0) { ++ virshReportError(ctl); ++ ret = FALSE; ++ } else if (all) { ++ vshPrint(ctl, "%-12s %-12s %3d\n", _("maximum"), _("live"), ++ count); ++ } else { ++ vshPrint(ctl, "%d\n", count); ++ } ++ virFreeError(last_error); ++ last_error = NULL; ++ } ++ ++ if (all || (current && config)) { ++ count = virDomainGetVcpusFlags(dom, VIR_DOMAIN_VCPU_CONFIG); ++ if (count < 0 && (last_error->code == VIR_ERR_NO_SUPPORT ++ || last_error->code == VIR_ERR_INVALID_ARG)) { ++ char *tmp, *end; ++ char *xml = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_INACTIVE); ++ if (xml && (tmp = strstr(xml, "'); ++ if (end) { ++ *end = '\0'; ++ tmp = strstr(tmp, "current="); ++ if (!tmp) ++ tmp = end + 1; ++ else { ++ tmp += strlen("current="); ++ tmp += *tmp == '\'' || *tmp == '"'; ++ } ++ } ++ if (!tmp || virStrToLong_i(tmp, &tmp, 10, &count) < 0) ++ count = -1; ++ } ++ VIR_FREE(xml); ++ } ++ ++ if (count < 0) { ++ virshReportError(ctl); ++ ret = FALSE; ++ } else if (all) { ++ vshPrint(ctl, "%-12s %-12s %3d\n", _("current"), _("config"), ++ count); ++ } else { ++ vshPrint(ctl, "%d\n", count); ++ } ++ virFreeError(last_error); ++ last_error = NULL; ++ } ++ ++ if (all || (current && live)) { ++ count = virDomainGetVcpusFlags(dom, VIR_DOMAIN_VCPU_LIVE); ++ if (count < 0 && (last_error->code == VIR_ERR_NO_SUPPORT ++ || last_error->code == VIR_ERR_INVALID_ARG)) { ++ virDomainInfo info; ++ if (virDomainGetInfo(dom, &info) == 0) ++ count = info.nrVirtCpu; ++ } ++ ++ if (count < 0) { ++ virshReportError(ctl); ++ ret = FALSE; ++ } else if (all) { ++ vshPrint(ctl, "%-12s %-12s %3d\n", _("current"), _("live"), ++ count); ++ } else { ++ vshPrint(ctl, "%d\n", count); ++ } ++ virFreeError(last_error); ++ last_error = NULL; ++ } ++ ++ virDomainFree(dom); ++ return ret; ++} ++ ++/* + * "vcpuinfo" command + */ + static const vshCmdInfo info_vcpuinfo[] = { +- {"help", N_("domain vcpu information")}, ++ {"help", N_("detailed domain vcpu information")}, + {"desc", N_("Returns basic information about the domain virtual CPUs.")}, + {NULL, NULL} + }; +@@ -2514,6 +2720,9 @@ static const vshCmdInfo info_setvcpus[] = { + static const vshCmdOptDef opts_setvcpus[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"count", VSH_OT_DATA, VSH_OFLAG_REQ, N_("number of virtual CPUs")}, ++ {"maximum", VSH_OT_BOOL, 0, N_("set maximum limit on next boot")}, ++ {"config", VSH_OT_BOOL, 0, N_("affect next boot")}, ++ {"live", VSH_OT_BOOL, 0, N_("affect running domain")}, + {NULL, 0, 0, NULL} + }; + +@@ -2522,8 +2731,13 @@ cmdSetvcpus(vshControl *ctl, const vshCmd *cmd) + { + virDomainPtr dom; + int count; +- int maxcpu; + int ret = TRUE; ++ int maximum = vshCommandOptBool(cmd, "maximum"); ++ int config = vshCommandOptBool(cmd, "config"); ++ int live = vshCommandOptBool(cmd, "live"); ++ int flags = ((maximum ? VIR_DOMAIN_VCPU_MAXIMUM : 0) | ++ (config ? VIR_DOMAIN_VCPU_CONFIG : 0) | ++ (live ? VIR_DOMAIN_VCPU_LIVE : 0)); + + if (!vshConnectionUsability(ctl, ctl->conn)) + return FALSE; +@@ -2532,26 +2746,15 @@ cmdSetvcpus(vshControl *ctl, const vshCmd *cmd) + return FALSE; + + count = vshCommandOptInt(cmd, "count", &count); +- if (count <= 0) { +- vshError(ctl, "%s", _("Invalid number of virtual CPUs.")); +- virDomainFree(dom); +- return FALSE; +- } +- +- maxcpu = virDomainGetMaxVcpus(dom); +- if (maxcpu <= 0) { +- virDomainFree(dom); +- return FALSE; +- } +- +- if (count > maxcpu) { +- vshError(ctl, "%s", _("Too many virtual CPUs.")); +- virDomainFree(dom); +- return FALSE; +- } + +- if (virDomainSetVcpus(dom, count) != 0) { +- ret = FALSE; ++ if (!flags) { ++ if (virDomainSetVcpus(dom, count) != 0) { ++ ret = FALSE; ++ } ++ } else { ++ if (virDomainSetVcpusFlags(dom, count, flags) < 0) { ++ ret = FALSE; ++ } + } + + virDomainFree(dom); +@@ -9642,6 +9845,7 @@ static const vshCmdDef commands[] = { + {"freecell", cmdFreecell, opts_freecell, info_freecell}, + {"hostname", cmdHostname, NULL, info_hostname}, + {"list", cmdList, opts_list, info_list}, ++ {"maxvcpus", cmdMaxvcpus, opts_maxvcpus, info_maxvcpus}, + {"migrate", cmdMigrate, opts_migrate, info_migrate}, + {"migrate-setmaxdowntime", cmdMigrateSetMaxDowntime, opts_migrate_setmaxdowntime, info_migrate_setmaxdowntime}, + +@@ -9748,6 +9952,7 @@ static const vshCmdDef commands[] = { + {"vol-name", cmdVolName, opts_vol_name, info_vol_name}, + {"vol-key", cmdVolKey, opts_vol_key, info_vol_key}, + ++ {"vcpucount", cmdVcpucount, opts_vcpucount, info_vcpucount}, + {"vcpuinfo", cmdVcpuinfo, opts_vcpuinfo, info_vcpuinfo}, + {"vcpupin", cmdVcpupin, opts_vcpupin, info_vcpupin}, + {"version", cmdVersion, NULL, info_version}, +diff --git a/tools/virsh.pod b/tools/virsh.pod +index 943a563..dbcc680 100644 +--- a/tools/virsh.pod ++++ b/tools/virsh.pod +@@ -443,7 +443,14 @@ Remove the managed save file for a domain if it exists. The next time the + domain is started it will not restore to its previous state but instead will + do a full boot. + +-=item B optional I<--live> I<--suspend> I I I ++=item B optional I ++ ++Provide the maximum number of virtual CPUs supported for a guest VM on ++this connection. If provided, the I parameter must be a valid ++type attribute for the element of XML. ++ ++=item B optional I<--live> I<--suspend> I I ++I + + Migrate domain to another host. Add --live for live migration; --suspend + leaves the domain paused on the destination host. The I is the +@@ -521,7 +528,8 @@ Displays the domain memory parameters. + + Allows you to set the domain memory parameters. LXC and QEMU/KVM supports these parameters. + +-=item B I I ++=item B I I optional I<--maximum> I<--config> ++I<--live> + + Change the number of virtual CPUs active in the guest domain. Note that + I may be limited by host, hypervisor or limit coming from the +@@ -530,6 +538,17 @@ original description of domain. + For Xen, you can only adjust the virtual CPUs of a running domain if + the domain is paravirtualized. + ++If I<--config> is specified, the change will only affect the next ++boot of a domain. If I<--live> is specified, the domain must be ++running, and the change takes place immediately. Both flags may be ++specified, if supported by the hypervisor. If neither flag is given, ++then I<--live> is implied and it is up to the hypervisor whether ++I<--config> is also implied. ++ ++If I<--maximum> is specified, then you must use I<--config> and ++avoid I<--live>; this flag controls the maximum limit of vcpus that ++can be hot-plugged the next time the domain is booted. ++ + =item B I + + Gracefully shuts down a domain. This coordinates with the domain OS +@@ -568,6 +587,21 @@ is not available the processes will provide an exit code of 1. + Undefine the configuration for an inactive domain. Since it's not running + the domain name or UUID must be used as the I. + ++=item B I optional I<--maximum> I<--current> ++I<--config> I<--live> ++ ++Print information about the virtual cpu counts of the given ++I. If no flags are specified, all possible counts are ++listed in a table; otherwise, the output is limited to just the ++numeric value requested. ++ ++I<--maximum> requests information on the maximum cap of vcpus that a ++domain can add via B, while I<--current> shows the current ++usage; these two flags cannot both be specified. I<--config> ++requests information regarding the next time the domain will be ++booted, while I<--live> requires a running domain and lists current ++values; these two flags cannot both be specified. ++ + =item B I + + Returns basic information about the domain virtual CPUs, like the number of +-- +1.7.2.3 + diff --git a/foo/docs/api_extension/0008-support-new-xml.patch b/foo/docs/api_extension/0008-support-new-xml.patch new file mode 100644 index 0000000..276b339 --- /dev/null +++ b/foo/docs/api_extension/0008-support-new-xml.patch @@ -0,0 +1,519 @@ +From 4617eedfaeee2b187a1f14691d25746ba3ff31b6 Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Wed, 29 Sep 2010 10:20:07 -0600 +Subject: [PATCH 07/15] vcpu: support maxvcpu in domain_conf + +Although this patch adds a distinction between maximum vcpus and +current vcpus in the XML, the values should be identical for all +drivers at this point. Only in subsequent per-driver patches will +a distinction be made. + +In general, virDomainGetInfo should prefer the current vcpus. + +* src/conf/domain_conf.h (_virDomainDef): Adjust vcpus to unsigned +short, to match virDomainGetInfo limit. Add maxvcpus member. +* src/conf/domain_conf.c (virDomainDefParseXML) +(virDomainDefFormat): parse and print out vcpu details. +* src/xen/xend_internal.c (xenDaemonParseSxpr) +(xenDaemonFormatSxpr): Manage both vcpu numbers, and require them +to be equal for now. +* src/xen/xm_internal.c (xenXMDomainConfigParse) +(xenXMDomainConfigFormat): Likewise. +* src/phyp/phyp_driver.c (phypDomainDumpXML): Likewise. +* src/openvz/openvz_conf.c (openvzLoadDomains): Likewise. +* src/openvz/openvz_driver.c (openvzDomainDefineXML) +(openvzDomainCreateXML, openvzDomainSetVcpusInternal): Likewise. +* src/vbox/vbox_tmpl.c (vboxDomainDumpXML, vboxDomainDefineXML): +Likewise. +* src/xenapi/xenapi_driver.c (xenapiDomainDumpXML): Likewise. +* src/xenapi/xenapi_utils.c (createVMRecordFromXml): Likewise. +* src/esx/esx_vmx.c (esxVMX_ParseConfig, esxVMX_FormatConfig): +Likewise. +* src/qemu/qemu_conf.c (qemuBuildSmpArgStr) +(qemuParseCommandLineSmp, qemuParseCommandLine): Likewise. +* src/qemu/qemu_driver.c (qemudDomainHotplugVcpus): Likewise. +* src/opennebula/one_conf.c (xmlOneTemplate): Likewise. +--- + src/conf/domain_conf.c | 45 +++++++++++++++++++++++++++++++++++++------ + src/conf/domain_conf.h | 3 +- + src/esx/esx_vmx.c | 24 ++++++++++++++-------- + src/opennebula/one_conf.c | 9 +++++-- + src/openvz/openvz_conf.c | 7 +++-- + src/openvz/openvz_driver.c | 15 +++++++++---- + src/phyp/phyp_driver.c | 2 +- + src/qemu/qemu_conf.c | 14 +++++++++++- + src/qemu/qemu_driver.c | 5 ++- + src/vbox/vbox_tmpl.c | 12 +++++++--- + src/xen/xend_internal.c | 9 ++++--- + src/xen/xm_internal.c | 11 ++++++--- + src/xenapi/xenapi_driver.c | 2 +- + src/xenapi/xenapi_utils.c | 4 +- + 14 files changed, 114 insertions(+), 48 deletions(-) + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index 78d7a6a..a997e06 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -4203,6 +4203,7 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, + int i, n; + long id = -1; + virDomainDefPtr def; ++ unsigned long count; + + if (VIR_ALLOC(def) < 0) { + virReportOOMError(); +@@ -4287,8 +4288,37 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, + &def->mem.swap_hard_limit) < 0) + def->mem.swap_hard_limit = 0; + +- if (virXPathULong("string(./vcpu[1])", ctxt, &def->vcpus) < 0) +- def->vcpus = 1; ++ n = virXPathULong("string(./vcpu[1])", ctxt, &count); ++ if (n == -2) { ++ virDomainReportError(VIR_ERR_XML_ERROR, "%s", ++ _("maximum vcpus must be an integer")); ++ goto error; ++ } else if (n < 0) { ++ def->maxvcpus = 1; ++ } else { ++ def->maxvcpus = count; ++ if (def->maxvcpus != count || count == 0) { ++ virDomainReportError(VIR_ERR_XML_ERROR, ++ _("invalid maxvcpus %lu"), count); ++ goto error; ++ } ++ } ++ ++ n = virXPathULong("string(./vcpu[1]/@current)", ctxt, &count); ++ if (n == -2) { ++ virDomainReportError(VIR_ERR_XML_ERROR, "%s", ++ _("current vcpus must be an integer")); ++ goto error; ++ } else if (n < 0) { ++ def->vcpus = def->maxvcpus; ++ } else { ++ def->vcpus = count; ++ if (def->vcpus != count || count == 0 || def->maxvcpus < count) { ++ virDomainReportError(VIR_ERR_XML_ERROR, ++ _("invalid current vcpus %lu"), count); ++ goto error; ++ } ++ } + + tmp = virXPathString("string(./vcpu[1]/@cpuset)", ctxt); + if (tmp) { +@@ -6462,17 +6492,18 @@ char *virDomainDefFormat(virDomainDefPtr def, + if (def->cpumask[n] != 1) + allones = 0; + +- if (allones) { +- virBufferAsprintf(&buf, " %lu\n", def->vcpus); +- } else { ++ virBufferAddLit(&buf, " cpumask, def->cpumasklen)) == NULL) + goto cleanup; +- virBufferAsprintf(&buf, " %lu\n", +- cpumask, def->vcpus); ++ virBufferAsprintf(&buf, " cpuset='%s'", cpumask); + VIR_FREE(cpumask); + } ++ if (def->vcpus != def->maxvcpus) ++ virBufferAsprintf(&buf, " current='%u'", def->vcpus); ++ virBufferAsprintf(&buf, ">%u\n", def->maxvcpus); + + if (def->os.bootloader) { + virBufferEscapeString(&buf, " %s\n", +diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h +index db09c23..5499f28 100644 +--- a/src/conf/domain_conf.h ++++ b/src/conf/domain_conf.h +@@ -885,7 +885,8 @@ struct _virDomainDef { + unsigned long min_guarantee; + unsigned long swap_hard_limit; + } mem; +- unsigned long vcpus; ++ unsigned short vcpus; ++ unsigned short maxvcpus; + int cpumasklen; + char *cpumask; + +diff --git a/src/esx/esx_vmx.c b/src/esx/esx_vmx.c +index 7ec8c0e..0a26614 100644 +--- a/src/esx/esx_vmx.c ++++ b/src/esx/esx_vmx.c +@@ -50,7 +50,7 @@ def->uuid = <=> uuid.bios = "" + def->name = <=> displayName = "" + def->mem.max_balloon = <=> memsize = "" # must be a multiple of 4, defaults to 32 + def->mem.cur_balloon = <=> sched.mem.max = "" # defaults to "unlimited" -> def->mem.cur_balloon = def->mem.max_balloon +-def->vcpus = <=> numvcpus = "" # must be 1 or a multiple of 2, defaults to 1 ++def->maxvcpus = <=> numvcpus = "" # must be 1 or a multiple of 2, defaults to 1 + def->cpumask = <=> sched.cpu.affinity = "" + + +@@ -1075,7 +1075,7 @@ esxVMX_ParseConfig(esxVMX_Context *ctx, virCapsPtr caps, const char *vmx, + goto cleanup; + } + +- def->vcpus = numvcpus; ++ def->maxvcpus = def->vcpus = numvcpus; + + /* vmx:sched.cpu.affinity -> def:cpumask */ + // VirtualMachine:config.cpuAffinity.affinitySet +@@ -2609,16 +2609,22 @@ esxVMX_FormatConfig(esxVMX_Context *ctx, virCapsPtr caps, virDomainDefPtr def, + (int)(def->mem.cur_balloon / 1024)); + } + +- /* def:vcpus -> vmx:numvcpus */ +- if (def->vcpus <= 0 || (def->vcpus % 2 != 0 && def->vcpus != 1)) { ++ /* def:maxvcpus -> vmx:numvcpus */ ++ if (def->vcpus != def->maxvcpus) { ++ ESX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED, ++ _("No support for domain XML entry 'vcpu' attribute " ++ "'current'")); ++ goto cleanup; ++ } ++ if (def->maxvcpus <= 0 || (def->maxvcpus % 2 != 0 && def->maxvcpus != 1)) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, + _("Expecting domain XML entry 'vcpu' to be an unsigned " + "integer (1 or a multiple of 2) but found %d"), +- (int)def->vcpus); ++ def->maxvcpus); + goto cleanup; + } + +- virBufferAsprintf(&buffer, "numvcpus = \"%d\"\n", (int)def->vcpus); ++ virBufferAsprintf(&buffer, "numvcpus = \"%d\"\n", def->maxvcpus); + + /* def:cpumask -> vmx:sched.cpu.affinity */ + if (def->cpumasklen > 0) { +@@ -2632,11 +2638,11 @@ esxVMX_FormatConfig(esxVMX_Context *ctx, virCapsPtr caps, virDomainDefPtr def, + } + } + +- if (sched_cpu_affinity_length < def->vcpus) { ++ if (sched_cpu_affinity_length < def->maxvcpus) { + ESX_ERROR(VIR_ERR_INTERNAL_ERROR, + _("Expecting domain XML attribute 'cpuset' of entry " +- "'vcpu' to contains at least %d CPU(s)"), +- (int)def->vcpus); ++ "'vcpu' to contain at least %d CPU(s)"), ++ def->maxvcpus); + goto cleanup; + } + +diff --git a/src/opennebula/one_conf.c b/src/opennebula/one_conf.c +index 44e28dc..2079c51 100644 +--- a/src/opennebula/one_conf.c ++++ b/src/opennebula/one_conf.c +@@ -1,5 +1,7 @@ + /*----------------------------------------------------------------------------------*/ +-/* Copyright 2002-2009, Distributed Systems Architecture Group, Universidad ++/* ++ * Copyright (C) 2010 Red Hat, Inc. ++ * Copyright 2002-2009, Distributed Systems Architecture Group, Universidad + * Complutense de Madrid (dsa-research.org) + * + * This library is free software; you can redistribute it and/or +@@ -169,9 +171,10 @@ char* xmlOneTemplate(virDomainDefPtr def) + { + int i; + virBuffer buf= VIR_BUFFER_INITIALIZER; +- virBufferAsprintf(&buf,"#OpenNebula Template automatically generated by libvirt\nNAME = %s\nCPU = %ld\nMEMORY = %ld\n", ++ virBufferAsprintf(&buf,"#OpenNebula Template automatically generated " ++ "by libvirt\nNAME = %s\nCPU = %d\nMEMORY = %ld\n", + def->name, +- def->vcpus, ++ def->maxvcpus, + (def->mem.max_balloon)/1024); + + /*Optional Booting OpenNebula Information:*/ +diff --git a/src/openvz/openvz_conf.c b/src/openvz/openvz_conf.c +index ec11bbc..c84a6f3 100644 +--- a/src/openvz/openvz_conf.c ++++ b/src/openvz/openvz_conf.c +@@ -507,11 +507,12 @@ int openvzLoadDomains(struct openvz_driver *driver) { + veid); + goto cleanup; + } else if (ret > 0) { +- dom->def->vcpus = strtoI(temp); ++ dom->def->maxvcpus = strtoI(temp); + } + +- if (ret == 0 || dom->def->vcpus == 0) +- dom->def->vcpus = openvzGetNodeCPUs(); ++ if (ret == 0 || dom->def->maxvcpus == 0) ++ dom->def->maxvcpus = openvzGetNodeCPUs(); ++ dom->def->vcpus = dom->def->maxvcpus; + + /* XXX load rest of VM config data .... */ + +diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c +index 0f3cfdf..b7c2754 100644 +--- a/src/openvz/openvz_driver.c ++++ b/src/openvz/openvz_driver.c +@@ -925,8 +925,13 @@ openvzDomainDefineXML(virConnectPtr conn, const char *xml) + if (openvzDomainSetNetworkConfig(conn, vm->def) < 0) + goto cleanup; + +- if (vm->def->vcpus > 0) { +- if (openvzDomainSetVcpusInternal(vm, vm->def->vcpus) < 0) { ++ if (vm->def->vcpus != vm->def->maxvcpus) { ++ openvzError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", ++ _("current vcpu count must equal maximum")); ++ goto cleanup; ++ } ++ if (vm->def->maxvcpus > 0) { ++ if (openvzDomainSetVcpusInternal(vm, vm->def->maxvcpus) < 0) { + openvzError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not set number of virtual cpu")); + goto cleanup; +@@ -1019,8 +1024,8 @@ openvzDomainCreateXML(virConnectPtr conn, const char *xml, + vm->def->id = vm->pid; + vm->state = VIR_DOMAIN_RUNNING; + +- if (vm->def->vcpus > 0) { +- if (openvzDomainSetVcpusInternal(vm, vm->def->vcpus) < 0) { ++ if (vm->def->maxvcpus > 0) { ++ if (openvzDomainSetVcpusInternal(vm, vm->def->maxvcpus) < 0) { + openvzError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not set number of virtual cpu")); + goto cleanup; +@@ -1249,7 +1254,7 @@ static int openvzDomainSetVcpusInternal(virDomainObjPtr vm, + return -1; + } + +- vm->def->vcpus = nvcpus; ++ vm->def->maxvcpus = vm->def->vcpus = nvcpus; + return 0; + } + +diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c +index e284ae0..3d0ed11 100644 +--- a/src/phyp/phyp_driver.c ++++ b/src/phyp/phyp_driver.c +@@ -3540,7 +3540,7 @@ phypDomainDumpXML(virDomainPtr dom, int flags) + goto err; + } + +- if ((def.vcpus = ++ if ((def.maxvcpus = def.vcpus = + phypGetLparCPU(dom->conn, managed_system, dom->id)) == 0) { + VIR_ERROR0(_("Unable to determine domain's CPU.")); + goto err; +diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c +index 83c0f83..38c8351 100644 +--- a/src/qemu/qemu_conf.c ++++ b/src/qemu/qemu_conf.c +@@ -3711,7 +3711,7 @@ qemuBuildSmpArgStr(const virDomainDefPtr def, + { + virBuffer buf = VIR_BUFFER_INITIALIZER; + +- virBufferAsprintf(&buf, "%lu", def->vcpus); ++ virBufferAsprintf(&buf, "%u", def->vcpus); + + if ((qemuCmdFlags & QEMUD_CMD_FLAG_SMP_TOPOLOGY)) { + /* sockets, cores, and threads are either all zero +@@ -3722,11 +3722,18 @@ qemuBuildSmpArgStr(const virDomainDefPtr def, + virBufferAsprintf(&buf, ",threads=%u", def->cpu->threads); + } + else { +- virBufferAsprintf(&buf, ",sockets=%lu", def->vcpus); ++ virBufferAsprintf(&buf, ",sockets=%u", def->maxvcpus); + virBufferAsprintf(&buf, ",cores=%u", 1); + virBufferAsprintf(&buf, ",threads=%u", 1); + } + } ++ if (def->vcpus != def->maxvcpus) { ++ virBufferFreeAndReset(&buf); ++ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", ++ _("setting current vcpu count less than maximum is " ++ "not supported yet")); ++ return NULL; ++ } + + if (virBufferError(&buf)) { + virBufferFreeAndReset(&buf); +@@ -6178,6 +6185,8 @@ qemuParseCommandLineSmp(virDomainDefPtr dom, + } + } + ++ dom->maxvcpus = dom->vcpus; ++ + if (sockets && cores && threads) { + virCPUDefPtr cpu; + +@@ -6247,6 +6256,7 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps, + + def->id = -1; + def->mem.cur_balloon = def->mem.max_balloon = 64 * 1024; ++ def->maxvcpus = 1; + def->vcpus = 1; + def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC; + def->features = (1 << VIR_DOMAIN_FEATURE_ACPI) +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index 7a2ea8f..c66dc04 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -2425,8 +2425,9 @@ qemuDetectVcpuPIDs(struct qemud_driver *driver, + + if (ncpupids != vm->def->vcpus) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, +- _("got wrong number of vCPU pids from QEMU monitor. got %d, wanted %d"), +- ncpupids, (int)vm->def->vcpus); ++ _("got wrong number of vCPU pids from QEMU monitor. " ++ "got %d, wanted %d"), ++ ncpupids, vm->def->vcpus); + VIR_FREE(cpupids); + return -1; + } +diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c +index 0cbe8b3..5a859a4 100644 +--- a/src/vbox/vbox_tmpl.c ++++ b/src/vbox/vbox_tmpl.c +@@ -2028,7 +2028,7 @@ static char *vboxDomainDumpXML(virDomainPtr dom, int flags) { + def->mem.max_balloon = memorySize * 1024; + + machine->vtbl->GetCPUCount(machine, &CPUCount); +- def->vcpus = CPUCount; ++ def->maxvcpus = def->vcpus = CPUCount; + + /* Skip cpumasklen, cpumask, onReboot, onPoweroff, onCrash */ + +@@ -4598,11 +4598,15 @@ static virDomainPtr vboxDomainDefineXML(virConnectPtr conn, const char *xml) { + def->mem.cur_balloon, (unsigned)rc); + } + +- rc = machine->vtbl->SetCPUCount(machine, def->vcpus); ++ if (def->vcpus != def->maxvcpus) { ++ vboxError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", ++ _("current vcpu count must equal maximum")); ++ } ++ rc = machine->vtbl->SetCPUCount(machine, def->maxvcpus); + if (NS_FAILED(rc)) { + vboxError(VIR_ERR_INTERNAL_ERROR, +- _("could not set the number of virtual CPUs to: %lu, rc=%08x"), +- def->vcpus, (unsigned)rc); ++ _("could not set the number of virtual CPUs to: %u, rc=%08x"), ++ def->maxvcpus, (unsigned)rc); + } + + #if VBOX_API_VERSION < 3001 +diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c +index 5ffc3c8..456b477 100644 +--- a/src/xen/xend_internal.c ++++ b/src/xen/xend_internal.c +@@ -2190,7 +2190,8 @@ xenDaemonParseSxpr(virConnectPtr conn, + } + } + +- def->vcpus = sexpr_int(root, "domain/vcpus"); ++ def->maxvcpus = sexpr_int(root, "domain/vcpus"); ++ def->vcpus = def->maxvcpus; + + tmp = sexpr_node(root, "domain/on_poweroff"); + if (tmp != NULL) { +@@ -5649,7 +5650,7 @@ xenDaemonFormatSxprInput(virDomainInputDefPtr input, + * + * Generate an SEXPR representing the domain configuration. + * +- * Returns the 0 terminatedi S-Expr string or NULL in case of error. ++ * Returns the 0 terminated S-Expr string or NULL in case of error. + * the caller must free() the returned value. + */ + char * +@@ -5666,7 +5667,7 @@ xenDaemonFormatSxpr(virConnectPtr conn, + virBufferAsprintf(&buf, "(name '%s')", def->name); + virBufferAsprintf(&buf, "(memory %lu)(maxmem %lu)", + def->mem.cur_balloon/1024, def->mem.max_balloon/1024); +- virBufferAsprintf(&buf, "(vcpus %lu)", def->vcpus); ++ virBufferAsprintf(&buf, "(vcpus %u)", def->maxvcpus); + + if (def->cpumask) { + char *ranges = virDomainCpuSetFormat(def->cpumask, def->cpumasklen); +@@ -5761,7 +5762,7 @@ xenDaemonFormatSxpr(virConnectPtr conn, + else + virBufferAsprintf(&buf, "(kernel '%s')", def->os.loader); + +- virBufferAsprintf(&buf, "(vcpus %lu)", def->vcpus); ++ virBufferAsprintf(&buf, "(vcpus %u)", def->maxvcpus); + + for (i = 0 ; i < def->os.nBootDevs ; i++) { + switch (def->os.bootDevs[i]) { +diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c +index 8e42a1c..bf20a64 100644 +--- a/src/xen/xm_internal.c ++++ b/src/xen/xm_internal.c +@@ -678,6 +678,7 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) { + int i; + const char *defaultArch, *defaultMachine; + int vmlocaltime = 0; ++ unsigned long count; + + if (VIR_ALLOC(def) < 0) { + virReportOOMError(); +@@ -770,9 +771,11 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) { + def->mem.cur_balloon *= 1024; + def->mem.max_balloon *= 1024; + +- +- if (xenXMConfigGetULong(conf, "vcpus", &def->vcpus, 1) < 0) ++ if (xenXMConfigGetULong(conf, "vcpus", &count, 1) < 0 || ++ (unsigned short) count != count) + goto cleanup; ++ def->maxvcpus = count; ++ def->vcpus = def->maxvcpus; + + if (xenXMConfigGetString(conf, "cpus", &str, NULL) < 0) + goto cleanup; +@@ -1650,7 +1653,7 @@ int xenXMDomainSetVcpus(virDomainPtr domain, unsigned int vcpus) { + if (!(entry = virHashLookup(priv->configCache, filename))) + goto cleanup; + +- entry->def->vcpus = vcpus; ++ entry->def->maxvcpus = entry->def->vcpus = vcpus; + + /* If this fails, should we try to undo our changes to the + * in-memory representation of the config file. I say not! +@@ -2241,7 +2244,7 @@ virConfPtr xenXMDomainConfigFormat(virConnectPtr conn, + if (xenXMConfigSetInt(conf, "memory", def->mem.cur_balloon / 1024) < 0) + goto no_memory; + +- if (xenXMConfigSetInt(conf, "vcpus", def->vcpus) < 0) ++ if (xenXMConfigSetInt(conf, "vcpus", def->maxvcpus) < 0) + goto no_memory; + + if ((def->cpumask != NULL) && +diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c +index 7d4ab8d..5ccdede 100644 +--- a/src/xenapi/xenapi_driver.c ++++ b/src/xenapi/xenapi_driver.c +@@ -1335,7 +1335,7 @@ xenapiDomainDumpXML (virDomainPtr dom, int flags ATTRIBUTE_UNUSED) + } else { + defPtr->mem.cur_balloon = memory; + } +- defPtr->vcpus = xenapiDomainGetMaxVcpus(dom); ++ defPtr->maxvcpus = defPtr->vcpus = xenapiDomainGetMaxVcpus(dom); + enum xen_on_normal_exit action; + if (xen_vm_get_actions_after_shutdown(session, &action, vm)) { + defPtr->onPoweroff = xenapiNormalExitEnum2virDomainLifecycle(action); +diff --git a/src/xenapi/xenapi_utils.c b/src/xenapi/xenapi_utils.c +index be55491..a7e2a4b 100644 +--- a/src/xenapi/xenapi_utils.c ++++ b/src/xenapi/xenapi_utils.c +@@ -510,8 +510,8 @@ createVMRecordFromXml (virConnectPtr conn, virDomainDefPtr def, + else + (*record)->memory_dynamic_max = (*record)->memory_static_max; + +- if (def->vcpus) { +- (*record)->vcpus_max = (int64_t) def->vcpus; ++ if (def->maxvcpus) { ++ (*record)->vcpus_max = (int64_t) def->maxvcpus; + (*record)->vcpus_at_startup = (int64_t) def->vcpus; + } + if (def->onPoweroff) +-- +1.7.2.3 + diff --git a/foo/docs/api_extension/0009-support-all-flags-in-test-driver.patch b/foo/docs/api_extension/0009-support-all-flags-in-test-driver.patch new file mode 100644 index 0000000..1aa3984 --- /dev/null +++ b/foo/docs/api_extension/0009-support-all-flags-in-test-driver.patch @@ -0,0 +1,197 @@ +From 6c9e6b956453d0f0c4ff542ef8a184d663a39266 Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Mon, 4 Oct 2010 17:01:12 -0600 +Subject: [PATCH 09/15] vcpu: support all flags in test driver + +* src/test/test_driver.c (testDomainGetVcpusFlags) +(testDomainSetVcpusFlags): Support all flags. +(testDomainUpdateVCPUs): Update cpu count here. +--- + src/test/test_driver.c | 128 ++++++++++++++++++++++++++++++++++++++++------- + 1 files changed, 109 insertions(+), 19 deletions(-) + +diff --git a/src/test/test_driver.c b/src/test/test_driver.c +index b70c80d..a9d3d89 100644 +--- a/src/test/test_driver.c ++++ b/src/test/test_driver.c +@@ -450,6 +450,7 @@ testDomainUpdateVCPUs(virConnectPtr conn, + goto cleanup; + } + ++ dom->def->vcpus = nvcpus; + ret = 0; + cleanup: + return ret; +@@ -2032,12 +2033,51 @@ cleanup: + static int + testDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags) + { +- if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) { +- testError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags); ++ testConnPtr privconn = domain->conn->privateData; ++ virDomainObjPtr vm; ++ virDomainDefPtr def; ++ int ret = -1; ++ ++ virCheckFlags(VIR_DOMAIN_VCPU_LIVE | ++ VIR_DOMAIN_VCPU_CONFIG | ++ VIR_DOMAIN_VCPU_MAXIMUM, -1); ++ ++ /* Exactly one of LIVE or CONFIG must be set. */ ++ if (!(flags & VIR_DOMAIN_VCPU_LIVE) == !(flags & VIR_DOMAIN_VCPU_CONFIG)) { ++ testError(VIR_ERR_INVALID_ARG, ++ _("invalid flag combination: (0x%x)"), flags); + return -1; + } + +- return testGetMaxVCPUs(domain->conn, "test"); ++ testDriverLock(privconn); ++ vm = virDomainFindByUUID(&privconn->domains, domain->uuid); ++ testDriverUnlock(privconn); ++ ++ if (!vm) { ++ char uuidstr[VIR_UUID_STRING_BUFLEN]; ++ virUUIDFormat(domain->uuid, uuidstr); ++ testError(VIR_ERR_NO_DOMAIN, ++ _("no domain with matching uuid '%s'"), uuidstr); ++ goto cleanup; ++ } ++ ++ if (flags & VIR_DOMAIN_VCPU_LIVE) { ++ if (!virDomainObjIsActive(vm)) { ++ testError(VIR_ERR_OPERATION_INVALID, "%s", ++ _("domain not active")); ++ goto cleanup; ++ } ++ def = vm->def; ++ } else { ++ def = vm->newDef ? vm->newDef : vm->def; ++ } ++ ++ ret = (flags & VIR_DOMAIN_VCPU_MAXIMUM) ? def->maxvcpus : def->vcpus; ++ ++cleanup: ++ if (vm) ++ virDomainObjUnlock(vm); ++ return ret; + } + + static int +@@ -2053,21 +2093,30 @@ testDomainSetVcpusFlags(virDomainPtr domain, unsigned int nrCpus, + { + testConnPtr privconn = domain->conn->privateData; + virDomainObjPtr privdom = NULL; ++ virDomainDefPtr def; + int ret = -1, maxvcpus; + +- if (flags != VIR_DOMAIN_VCPU_LIVE) { +- testError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags); ++ virCheckFlags(VIR_DOMAIN_VCPU_LIVE | ++ VIR_DOMAIN_VCPU_CONFIG | ++ VIR_DOMAIN_VCPU_MAXIMUM, -1); ++ ++ /* At least one of LIVE or CONFIG must be set. MAXIMUM cannot be ++ * mixed with LIVE. */ ++ if ((flags & (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) == 0 || ++ (flags & (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) == ++ (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) { ++ testError(VIR_ERR_INVALID_ARG, ++ _("invalid flag combination: (0x%x)"), flags); ++ return -1; ++ } ++ if (!nrCpus || (maxvcpus = testGetMaxVCPUs(domain->conn, NULL)) < nrCpus) { ++ testError(VIR_ERR_INVALID_ARG, ++ _("argument out of range: %d"), nrCpus); + return -1; + } +- +- /* Do this first before locking */ +- maxvcpus = testDomainGetMaxVcpus(domain); +- if (maxvcpus < 0) +- goto cleanup; + + testDriverLock(privconn); +- privdom = virDomainFindByName(&privconn->domains, +- domain->name); ++ privdom = virDomainFindByUUID(&privconn->domains, domain->uuid); + testDriverUnlock(privconn); + + if (privdom == NULL) { +@@ -2075,13 +2124,17 @@ testDomainSetVcpusFlags(virDomainPtr domain, unsigned int nrCpus, + goto cleanup; + } + +- if (!virDomainObjIsActive(privdom)) { ++ if (!virDomainObjIsActive(privdom) && (flags & VIR_DOMAIN_VCPU_LIVE)) { + testError(VIR_ERR_OPERATION_INVALID, + "%s", _("cannot hotplug vcpus for an inactive domain")); + goto cleanup; + } + +- /* We allow more cpus in guest than host */ ++ /* We allow more cpus in guest than host, but not more than the ++ * domain's starting limit. */ ++ if ((flags & (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) == ++ VIR_DOMAIN_VCPU_LIVE && privdom->def->maxvcpus < maxvcpus) ++ maxvcpus = privdom->def->maxvcpus; + if (nrCpus > maxvcpus) { + testError(VIR_ERR_INVALID_ARG, + "requested cpu amount exceeds maximum (%d > %d)", +@@ -2089,12 +2142,49 @@ testDomainSetVcpusFlags(virDomainPtr domain, unsigned int nrCpus, + goto cleanup; + } + +- /* Update VCPU state for the running domain */ +- if (testDomainUpdateVCPUs(domain->conn, privdom, nrCpus, 0) < 0) +- goto cleanup; ++ switch (flags) { ++ case VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_CONFIG: ++ def = privdom->def; ++ if (virDomainObjIsActive(privdom)) { ++ if (privdom->newDef) ++ def = privdom->newDef; ++ else { ++ testError(VIR_ERR_OPERATION_INVALID, "%s", ++ _("no persistent state")); ++ goto cleanup; ++ } ++ } ++ def->maxvcpus = nrCpus; ++ if (nrCpus < def->vcpus) ++ def->vcpus = nrCpus; ++ ret = 0; ++ break; + +- privdom->def->vcpus = nrCpus; +- ret = 0; ++ case VIR_DOMAIN_VCPU_CONFIG: ++ def = privdom->def; ++ if (virDomainObjIsActive(privdom)) { ++ if (privdom->newDef) ++ def = privdom->newDef; ++ else { ++ testError(VIR_ERR_OPERATION_INVALID, "%s", ++ _("no persistent state")); ++ goto cleanup; ++ } ++ } ++ def->vcpus = nrCpus; ++ ret = 0; ++ break; ++ ++ case VIR_DOMAIN_VCPU_LIVE: ++ ret = testDomainUpdateVCPUs(domain->conn, privdom, nrCpus, 0); ++ break; ++ ++ case VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG: ++ ret = testDomainUpdateVCPUs(domain->conn, privdom, nrCpus, 0); ++ if (ret == 0 && privdom->newDef) ++ privdom->newDef->vcpus = nrCpus; ++ break; ++ } + + cleanup: + if (privdom) +-- +1.7.2.3 + diff --git a/foo/docs/api_extension/0010-improve-vcpu-support-in-qemu-command-line.patch b/foo/docs/api_extension/0010-improve-vcpu-support-in-qemu-command-line.patch new file mode 100644 index 0000000..02320bb --- /dev/null +++ b/foo/docs/api_extension/0010-improve-vcpu-support-in-qemu-command-line.patch @@ -0,0 +1,122 @@ +From d67c189e80e6aef7adf13e5763365555cfc1a02a Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Wed, 29 Sep 2010 15:58:47 -0600 +Subject: [PATCH 10/15] vcpu: improve vcpu support in qemu command line + +* src/qemu/qemu_conf.c (qemuParseCommandLineSmp): Distinguish +between vcpus and maxvcpus, for new enough qemu. +* tests/qemuargv2xmltest.c (mymain): Add new test. +* tests/qemuxml2argvtest.c (mymain): Likewise. +* tests/qemuxml2xmltest.c (mymain): Likewise. +* tests/qemuxml2argvdata/qemuxml2argv-smp.args: New file. +--- + src/qemu/qemu_conf.c | 13 +++++++++---- + tests/qemuargv2xmltest.c | 2 ++ + tests/qemuxml2argvdata/qemuxml2argv-smp.args | 1 + + tests/qemuxml2argvtest.c | 2 ++ + tests/qemuxml2xmltest.c | 2 ++ + 5 files changed, 16 insertions(+), 4 deletions(-) + create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-smp.args + +diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c +index 38c8351..ffe184b 100644 +--- a/src/qemu/qemu_conf.c ++++ b/src/qemu/qemu_conf.c +@@ -3714,6 +3714,8 @@ qemuBuildSmpArgStr(const virDomainDefPtr def, + virBufferAsprintf(&buf, "%u", def->vcpus); + + if ((qemuCmdFlags & QEMUD_CMD_FLAG_SMP_TOPOLOGY)) { ++ if (def->vcpus != def->maxvcpus) ++ virBufferAsprintf(&buf, ",maxcpus=%u", def->maxvcpus); + /* sockets, cores, and threads are either all zero + * or all non-zero, thus checking one of them is enough */ + if (def->cpu && def->cpu->sockets) { +@@ -3726,12 +3728,12 @@ qemuBuildSmpArgStr(const virDomainDefPtr def, + virBufferAsprintf(&buf, ",cores=%u", 1); + virBufferAsprintf(&buf, ",threads=%u", 1); + } +- } +- if (def->vcpus != def->maxvcpus) { ++ } else if (def->vcpus != def->maxvcpus) { + virBufferFreeAndReset(&buf); ++ /* FIXME - consider hot-unplugging cpus after boot for older qemu */ + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("setting current vcpu count less than maximum is " +- "not supported yet")); ++ "not supported with this QEMU binary")); + return NULL; + } + +@@ -6153,6 +6155,7 @@ qemuParseCommandLineSmp(virDomainDefPtr dom, + unsigned int sockets = 0; + unsigned int cores = 0; + unsigned int threads = 0; ++ unsigned int maxcpus = 0; + int i; + int nkws; + char **kws; +@@ -6180,12 +6183,14 @@ qemuParseCommandLineSmp(virDomainDefPtr dom, + cores = n; + else if (STREQ(kws[i], "threads")) + threads = n; ++ else if (STREQ(kws[i], "maxcpus")) ++ maxcpus = n; + else + goto syntax; + } + } + +- dom->maxvcpus = dom->vcpus; ++ dom->maxvcpus = maxcpus ? maxcpus : dom->vcpus; + + if (sockets && cores && threads) { + virCPUDefPtr cpu; +diff --git a/tests/qemuargv2xmltest.c b/tests/qemuargv2xmltest.c +index 4f9ec84..d941b0b 100644 +--- a/tests/qemuargv2xmltest.c ++++ b/tests/qemuargv2xmltest.c +@@ -221,6 +221,8 @@ mymain(int argc, char **argv) + + DO_TEST("hostdev-pci-address"); + ++ DO_TEST("smp"); ++ + DO_TEST_FULL("restore-v1", 0, "stdio"); + DO_TEST_FULL("restore-v2", 0, "stdio"); + DO_TEST_FULL("restore-v2", 0, "exec:cat"); +diff --git a/tests/qemuxml2argvdata/qemuxml2argv-smp.args b/tests/qemuxml2argvdata/qemuxml2argv-smp.args +new file mode 100644 +index 0000000..3ec8f15 +--- /dev/null ++++ b/tests/qemuxml2argvdata/qemuxml2argv-smp.args +@@ -0,0 +1 @@ ++LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1,maxcpus=2,sockets=2,cores=1,threads=1 -nographic -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -usb +diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c +index 92d5b18..551d6c4 100644 +--- a/tests/qemuxml2argvtest.c ++++ b/tests/qemuxml2argvtest.c +@@ -385,6 +385,8 @@ mymain(int argc, char **argv) + + DO_TEST("qemu-ns", 0); + ++ DO_TEST("smp", QEMUD_CMD_FLAG_SMP_TOPOLOGY); ++ + free(driver.stateDir); + virCapabilitiesFree(driver.caps); + +diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c +index a33d435..cdc4390 100644 +--- a/tests/qemuxml2xmltest.c ++++ b/tests/qemuxml2xmltest.c +@@ -180,6 +180,8 @@ mymain(int argc, char **argv) + DO_TEST("encrypted-disk"); + DO_TEST("memtune"); + ++ DO_TEST("smp"); ++ + /* These tests generate different XML */ + DO_TEST_DIFFERENT("balloon-device-auto"); + DO_TEST_DIFFERENT("channel-virtio-auto"); +-- +1.7.2.3 + diff --git a/foo/docs/api_extension/0011-complete-vcpu-support-in-qemu-driver.patch b/foo/docs/api_extension/0011-complete-vcpu-support-in-qemu-driver.patch new file mode 100644 index 0000000..251008f --- /dev/null +++ b/foo/docs/api_extension/0011-complete-vcpu-support-in-qemu-driver.patch @@ -0,0 +1,169 @@ +From 28a3605906385cba43df77051dc26e865f237b09 Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Wed, 29 Sep 2010 17:40:45 -0600 +Subject: [PATCH 11/15] vcpu: complete vcpu support in qemu driver + +* src/qemu/qemu_driver.c (qemudDomainSetVcpusFlags) +(qemudDomainGetVcpusFlags): Support all feasible flag +combinations. +--- + src/qemu/qemu_driver.c | 100 ++++++++++++++++++++++++++++++++++++++++------- + 1 files changed, 85 insertions(+), 15 deletions(-) + +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index c66dc04..a9e057f 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -5941,13 +5941,27 @@ qemudDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus, + { + struct qemud_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; ++ virDomainDefPtr def; + const char * type; + int max; + int ret = -1; + +- if (flags != VIR_DOMAIN_VCPU_LIVE) { +- qemuReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), +- flags); ++ virCheckFlags(VIR_DOMAIN_VCPU_LIVE | ++ VIR_DOMAIN_VCPU_CONFIG | ++ VIR_DOMAIN_VCPU_MAXIMUM, -1); ++ ++ /* At least one of LIVE or CONFIG must be set. MAXIMUM cannot be ++ * mixed with LIVE. */ ++ if ((flags & (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) == 0 || ++ (flags & (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) == ++ (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) { ++ qemuReportError(VIR_ERR_INVALID_ARG, ++ _("invalid flag combination: (0x%x)"), flags); ++ return -1; ++ } ++ if (!nvcpus || (unsigned short) nvcpus != nvcpus) { ++ qemuReportError(VIR_ERR_INVALID_ARG, ++ _("argument out of range: %d"), nvcpus); + return -1; + } + +@@ -5966,7 +5980,7 @@ qemudDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus, + if (qemuDomainObjBeginJob(vm) < 0) + goto cleanup; + +- if (!virDomainObjIsActive(vm)) { ++ if (!virDomainObjIsActive(vm) && (flags & VIR_DOMAIN_VCPU_LIVE)) { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto endjob; +@@ -5985,6 +5999,11 @@ qemudDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus, + goto endjob; + } + ++ if ((flags & (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) == ++ VIR_DOMAIN_VCPU_LIVE && vm->def->maxvcpus < max) { ++ max = vm->def->maxvcpus; ++ } ++ + if (nvcpus > max) { + qemuReportError(VIR_ERR_INVALID_ARG, + _("requested vcpus is greater than max allowable" +@@ -5992,7 +6011,49 @@ qemudDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus, + goto endjob; + } + +- ret = qemudDomainHotplugVcpus(vm, nvcpus); ++ switch (flags) { ++ case VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_CONFIG: ++ def = vm->def; ++ if (virDomainObjIsActive(vm)) { ++ if (vm->newDef) ++ def = vm->newDef; ++ else{ ++ qemuReportError(VIR_ERR_OPERATION_INVALID, "%s", ++ _("no persistent state")); ++ goto endjob; ++ } ++ } ++ def->maxvcpus = nvcpus; ++ if (nvcpus < vm->newDef->vcpus) ++ def->vcpus = nvcpus; ++ ret = 0; ++ break; ++ ++ case VIR_DOMAIN_VCPU_CONFIG: ++ def = vm->def; ++ if (virDomainObjIsActive(vm)) { ++ if (vm->newDef) ++ def = vm->newDef; ++ else { ++ qemuReportError(VIR_ERR_OPERATION_INVALID, "%s", ++ _("no persistent state")); ++ goto endjob; ++ } ++ } ++ def->vcpus = nvcpus; ++ ret = 0; ++ break; ++ ++ case VIR_DOMAIN_VCPU_LIVE: ++ ret = qemudDomainHotplugVcpus(vm, nvcpus); ++ break; ++ ++ case VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG: ++ ret = qemudDomainHotplugVcpus(vm, nvcpus); ++ if (ret == 0 && vm->newDef) ++ vm->newDef->vcpus = nvcpus; ++ break; ++ } + + endjob: + if (qemuDomainObjEndJob(vm) == 0) +@@ -6171,12 +6232,17 @@ qemudDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags) + { + struct qemud_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; +- const char *type; ++ virDomainDefPtr def; + int ret = -1; + +- if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) { +- qemuReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), +- flags); ++ virCheckFlags(VIR_DOMAIN_VCPU_LIVE | ++ VIR_DOMAIN_VCPU_CONFIG | ++ VIR_DOMAIN_VCPU_MAXIMUM, -1); ++ ++ /* Exactly one of LIVE or CONFIG must be set. */ ++ if (!(flags & VIR_DOMAIN_VCPU_LIVE) == !(flags & VIR_DOMAIN_VCPU_CONFIG)) { ++ qemuReportError(VIR_ERR_INVALID_ARG, ++ _("invalid flag combination: (0x%x)"), flags); + return -1; + } + +@@ -6192,14 +6258,18 @@ qemudDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags) + goto cleanup; + } + +- if (!(type = virDomainVirtTypeToString(vm->def->virtType))) { +- qemuReportError(VIR_ERR_INTERNAL_ERROR, +- _("unknown virt type in domain definition '%d'"), +- vm->def->virtType); +- goto cleanup; ++ if (flags & VIR_DOMAIN_VCPU_LIVE) { ++ if (!virDomainObjIsActive(vm)) { ++ qemuReportError(VIR_ERR_OPERATION_INVALID, "%s", ++ _("domain not active")); ++ goto cleanup; ++ } ++ def = vm->def; ++ } else { ++ def = vm->newDef ? vm->newDef : vm->def; + } + +- ret = qemudGetMaxVCPUs(NULL, type); ++ ret = (flags & VIR_DOMAIN_VCPU_MAXIMUM) ? def->maxvcpus : def->vcpus; + + cleanup: + if (vm) +-- +1.7.2.3 + diff --git a/foo/docs/api_extension/0012-improve-vcpu-support-in-xen-command-line.patch b/foo/docs/api_extension/0012-improve-vcpu-support-in-xen-command-line.patch new file mode 100644 index 0000000..0a7b2fc --- /dev/null +++ b/foo/docs/api_extension/0012-improve-vcpu-support-in-xen-command-line.patch @@ -0,0 +1,294 @@ +From 0fab10e5ed971ab4f960a53e9640b0672f4b8ac3 Mon Sep 17 00:00:00 2001 +From: Eric Blake +Date: Tue, 5 Oct 2010 08:18:52 -0600 +Subject: [PATCH 12/15] vcpu: improve vcpu support in xen command line + +This patch series focuses on xendConfigVersion 2 (xm_internal) and 3 +(xend_internal), but leaves out changes for xenapi drivers. + +See this link for more details about vcpu_avail for xm usage. +http://lists.xensource.com/archives/html/xen-devel/2009-11/msg01061.html + +This relies on the fact that def->maxvcpus can be at most 32 with xen. + +* src/xen/xend_internal.c (xenDaemonParseSxpr) +(sexpr_to_xend_domain_info, xenDaemonFormatSxpr): Use vcpu_avail +when current vcpus is less than maximum. +* src/xen/xm_internal.c (xenXMDomainConfigParse) +(xenXMDomainConfigFormat): Likewise. +* tests/xml2sexprdata/xml2sexpr-pv-vcpus.sexpr: New file. +* tests/sexpr2xmldata/sexpr2xml-pv-vcpus.sexpr: Likewise. +* tests/sexpr2xmldata/sexpr2xml-pv-vcpus.xml: Likewise. +* tests/xmconfigdata/test-paravirt-vcpu.cfg: Likewise. +* tests/xmconfigdata/test-paravirt-vcpu.xml: Likewise. +* tests/xml2sexprtest.c (mymain): New test. +* tests/sexpr2xmltest.c (mymain): Likewise. +* tests/xmconfigtest.c (mymain): Likewise. +--- + src/xen/xend_internal.c | 19 +++++++++++++-- + src/xen/xm_internal.c | 10 ++++++- + tests/sexpr2xmldata/sexpr2xml-pv-vcpus.sexpr | 1 + + tests/sexpr2xmldata/sexpr2xml-pv-vcpus.xml | 27 +++++++++++++++++++++ + tests/sexpr2xmltest.c | 1 + + tests/xmconfigdata/test-paravirt-vcpu.cfg | 17 +++++++++++++ + tests/xmconfigdata/test-paravirt-vcpu.xml | 32 ++++++++++++++++++++++++++ + tests/xmconfigtest.c | 1 + + tests/xml2sexprdata/xml2sexpr-pv-vcpus.sexpr | 1 + + tests/xml2sexprtest.c | 1 + + 10 files changed, 105 insertions(+), 5 deletions(-) + create mode 100644 tests/sexpr2xmldata/sexpr2xml-pv-vcpus.sexpr + create mode 100644 tests/sexpr2xmldata/sexpr2xml-pv-vcpus.xml + create mode 100644 tests/xmconfigdata/test-paravirt-vcpu.cfg + create mode 100644 tests/xmconfigdata/test-paravirt-vcpu.xml + create mode 100644 tests/xml2sexprdata/xml2sexpr-pv-vcpus.sexpr + +diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c +index 456b477..dfc6415 100644 +--- a/src/xen/xend_internal.c ++++ b/src/xen/xend_internal.c +@@ -44,6 +44,7 @@ + #include "xen_hypervisor.h" + #include "xs_internal.h" /* To extract VNC port & Serial console TTY */ + #include "memory.h" ++#include "count-one-bits.h" + + /* required for cpumap_t */ + #include +@@ -2191,7 +2192,9 @@ xenDaemonParseSxpr(virConnectPtr conn, + } + + def->maxvcpus = sexpr_int(root, "domain/vcpus"); +- def->vcpus = def->maxvcpus; ++ def->vcpus = count_one_bits(sexpr_int(root, "domain/vcpu_avail")); ++ if (!def->vcpus || def->maxvcpus < def->vcpus) ++ def->vcpus = def->maxvcpus; + + tmp = sexpr_node(root, "domain/on_poweroff"); + if (tmp != NULL) { +@@ -2433,7 +2436,7 @@ sexpr_to_xend_domain_info(virDomainPtr domain, const struct sexpr *root, + virDomainInfoPtr info) + { + const char *flags; +- ++ int vcpus; + + if ((root == NULL) || (info == NULL)) + return (-1); +@@ -2464,7 +2467,11 @@ sexpr_to_xend_domain_info(virDomainPtr domain, const struct sexpr *root, + info->state = VIR_DOMAIN_NOSTATE; + } + info->cpuTime = sexpr_float(root, "domain/cpu_time") * 1000000000; +- info->nrVirtCpu = sexpr_int(root, "domain/vcpus"); ++ vcpus = sexpr_int(root, "domain/vcpus"); ++ info->nrVirtCpu = count_one_bits(sexpr_int(root, "domain/vcpu_avail")); ++ if (!info->nrVirtCpu || vcpus < info->nrVirtCpu) ++ info->nrVirtCpu = vcpus; ++ + return (0); + } + +@@ -5668,6 +5675,9 @@ xenDaemonFormatSxpr(virConnectPtr conn, + virBufferAsprintf(&buf, "(memory %lu)(maxmem %lu)", + def->mem.cur_balloon/1024, def->mem.max_balloon/1024); + virBufferAsprintf(&buf, "(vcpus %u)", def->maxvcpus); ++ /* Computing the vcpu_avail bitmask works because MAX_VIRT_CPUS is 32. */ ++ if (def->vcpus < def->maxvcpus) ++ virBufferAsprintf(&buf, "(vcpu_avail %u)", (1U << def->vcpus) - 1); + + if (def->cpumask) { + char *ranges = virDomainCpuSetFormat(def->cpumask, def->cpumasklen); +@@ -5763,6 +5773,9 @@ xenDaemonFormatSxpr(virConnectPtr conn, + virBufferAsprintf(&buf, "(kernel '%s')", def->os.loader); + + virBufferAsprintf(&buf, "(vcpus %u)", def->maxvcpus); ++ if (def->vcpus < def->maxvcpus) ++ virBufferAsprintf(&buf, "(vcpu_avail %u)", ++ (1U << def->vcpus) - 1); + + for (i = 0 ; i < def->os.nBootDevs ; i++) { + switch (def->os.bootDevs[i]) { +diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c +index bf20a64..f7121ab 100644 +--- a/src/xen/xm_internal.c ++++ b/src/xen/xm_internal.c +@@ -46,6 +46,7 @@ + #include "util.h" + #include "memory.h" + #include "logging.h" ++#include "count-one-bits.h" + + #define VIR_FROM_THIS VIR_FROM_XENXM + +@@ -772,10 +773,12 @@ xenXMDomainConfigParse(virConnectPtr conn, virConfPtr conf) { + def->mem.max_balloon *= 1024; + + if (xenXMConfigGetULong(conf, "vcpus", &count, 1) < 0 || +- (unsigned short) count != count) ++ MAX_VIRT_CPUS < count) + goto cleanup; + def->maxvcpus = count; +- def->vcpus = def->maxvcpus; ++ if (xenXMConfigGetULong(conf, "vcpu_avail", &count, -1) < 0) ++ goto cleanup; ++ def->vcpus = MIN(count_one_bits(count), def->maxvcpus); + + if (xenXMConfigGetString(conf, "cpus", &str, NULL) < 0) + goto cleanup; +@@ -2246,6 +2249,9 @@ virConfPtr xenXMDomainConfigFormat(virConnectPtr conn, + + if (xenXMConfigSetInt(conf, "vcpus", def->maxvcpus) < 0) + goto no_memory; ++ if (def->vcpus < def->maxvcpus && ++ xenXMConfigSetInt(conf, "vcpu_avail", (1U << def->vcpus) - 1) < 0) ++ goto no_memory; + + if ((def->cpumask != NULL) && + ((cpus = virDomainCpuSetFormat(def->cpumask, +diff --git a/tests/sexpr2xmldata/sexpr2xml-pv-vcpus.sexpr b/tests/sexpr2xmldata/sexpr2xml-pv-vcpus.sexpr +new file mode 100644 +index 0000000..2be6822 +--- /dev/null ++++ b/tests/sexpr2xmldata/sexpr2xml-pv-vcpus.sexpr +@@ -0,0 +1 @@ ++(domain (domid 6)(name 'pvtest')(memory 420)(maxmem 420)(vcpus 4)(vcpu_avail 3)(uuid '596a5d2171f48fb2e068e2386a5c413e')(on_poweroff 'destroy')(on_reboot 'destroy')(on_crash 'destroy')(image (linux (kernel '/var/lib/xen/vmlinuz.2Dn2YT')(ramdisk '/var/lib/xen/initrd.img.0u-Vhq')(args ' method=http://download.fedora.devel.redhat.com/pub/fedora/linux/core/test/5.91/x86_64/os ')))(device (vbd (dev 'xvda')(uname 'file:/root/some.img')(mode 'w')))) +diff --git a/tests/sexpr2xmldata/sexpr2xml-pv-vcpus.xml b/tests/sexpr2xmldata/sexpr2xml-pv-vcpus.xml +new file mode 100644 +index 0000000..0d6bf11 +--- /dev/null ++++ b/tests/sexpr2xmldata/sexpr2xml-pv-vcpus.xml +@@ -0,0 +1,27 @@ ++ ++ pvtest ++ 596a5d21-71f4-8fb2-e068-e2386a5c413e ++ 430080 ++ 430080 ++ 4 ++ ++ linux ++ /var/lib/xen/vmlinuz.2Dn2YT ++ /var/lib/xen/initrd.img.0u-Vhq ++ method=http://download.fedora.devel.redhat.com/pub/fedora/linux/core/test/5.91/x86_64/os ++ ++ ++ destroy ++ destroy ++ destroy ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/tests/sexpr2xmltest.c b/tests/sexpr2xmltest.c +index d62b44f..f100dd8 100644 +--- a/tests/sexpr2xmltest.c ++++ b/tests/sexpr2xmltest.c +@@ -132,6 +132,7 @@ mymain(int argc, char **argv) + DO_TEST("pv-vfb-type-crash", "pv-vfb-type-crash", 3); + DO_TEST("fv-autoport", "fv-autoport", 3); + DO_TEST("pv-bootloader", "pv-bootloader", 1); ++ DO_TEST("pv-vcpus", "pv-vcpus", 1); + + DO_TEST("disk-file", "disk-file", 2); + DO_TEST("disk-block", "disk-block", 2); +diff --git a/tests/xmconfigdata/test-paravirt-vcpu.cfg b/tests/xmconfigdata/test-paravirt-vcpu.cfg +new file mode 100644 +index 0000000..24c78f4 +--- /dev/null ++++ b/tests/xmconfigdata/test-paravirt-vcpu.cfg +@@ -0,0 +1,17 @@ ++name = "XenGuest1" ++uuid = "c7a5fdb0-cdaf-9455-926a-d65c16db1809" ++maxmem = 579 ++memory = 394 ++vcpus = 4 ++vcpu_avail = 3 ++bootloader = "/usr/bin/pygrub" ++on_poweroff = "destroy" ++on_reboot = "restart" ++on_crash = "restart" ++sdl = 0 ++vnc = 1 ++vncunused = 1 ++vnclisten = "127.0.0.1" ++vncpasswd = "123poi" ++disk = [ "phy:/dev/HostVG/XenGuest1,xvda,w" ] ++vif = [ "mac=00:16:3e:66:94:9c,bridge=br0,script=vif-bridge" ] +diff --git a/tests/xmconfigdata/test-paravirt-vcpu.xml b/tests/xmconfigdata/test-paravirt-vcpu.xml +new file mode 100644 +index 0000000..0be9456 +--- /dev/null ++++ b/tests/xmconfigdata/test-paravirt-vcpu.xml +@@ -0,0 +1,32 @@ ++ ++ XenGuest1 ++ c7a5fdb0-cdaf-9455-926a-d65c16db1809 ++ 592896 ++ 403456 ++ 4 ++ /usr/bin/pygrub ++ ++ linux ++ ++ ++ destroy ++ restart ++ restart ++ ++ ++ ++ ++ ++ ++ ++ ++ ++