summaryrefslogtreecommitdiff
path: root/docs/api_extension
diff options
context:
space:
mode:
authorEric Blake <eblake@redhat.com>2010-10-20 10:04:19 -0600
committerEric Blake <eblake@redhat.com>2010-10-26 13:43:57 -0600
commit66a04090673a5e21700d11bdea0084f1ee870c24 (patch)
tree8b7449f0f4a46905ad361a960fc2c6b95b00aeb3 /docs/api_extension
parent8efebd1761700a0cc32736829aead7807cc7865d (diff)
downloadlibvirt-66a04090673a5e21700d11bdea0084f1ee870c24.tar.gz
docs: revamp api_extension example, using vcpu patch series
* docs/api_extension/*: Replace example files. * docs/api_extension.html.in: Rewrite to match new example files.
Diffstat (limited to 'docs/api_extension')
-rw-r--r--docs/api_extension/0001-Step-1-of-15-add-to-xml.patch145
-rw-r--r--docs/api_extension/0001-Step-1-of-8-Define-the-public-API.patch44
-rw-r--r--docs/api_extension/0002-Step-2-of-15-add-new-public-API.patch62
-rw-r--r--docs/api_extension/0002-Step-2-of-8-Define-the-internal-driver-API.patch36
-rw-r--r--docs/api_extension/0003-Step-3-of-15-define-internal-driver-API.patch222
-rw-r--r--docs/api_extension/0003-Step-3-of-8-Implement-the-public-API.patch119
-rw-r--r--docs/api_extension/0004-Step-4-of-15-implement-the-public-APIs.patch188
-rw-r--r--docs/api_extension/0004-Step-4-of-8-Define-the-wire-protocol-format.patch47
-rw-r--r--docs/api_extension/0005-Step-5-of-15-implement-the-remote-protocol.patch421
-rw-r--r--docs/api_extension/0005-Step-5-of-8-Implement-the-RPC-client.patch84
-rw-r--r--docs/api_extension/0006-Step-6-of-15-make-old-API-trivially-wrap-to-new-API.patch735
-rw-r--r--docs/api_extension/0006-Step-6-of-8-Implement-the-server-side-dispatcher.patch70
-rw-r--r--docs/api_extension/0007-Step-7-of-15-add-virsh-support.patch388
-rw-r--r--docs/api_extension/0007-Step-7-of-8-Implement-the-driver-methods.patch1171
-rw-r--r--docs/api_extension/0008-Step-8-of-15-support-new-xml.patch519
-rw-r--r--docs/api_extension/0008-Step-8-of-8-Add-virsh-support.patch131
-rw-r--r--docs/api_extension/0009-Step-9-of-15-support-all-flags-in-test-driver.patch197
-rw-r--r--docs/api_extension/0010-Step-10-of-15-improve-vcpu-support-in-qemu-command-line.patch122
-rw-r--r--docs/api_extension/0011-Step-11-of-15-complete-vcpu-support-in-qemu-driver.patch169
-rw-r--r--docs/api_extension/0012-Step-12-of-15-improve-vcpu-support-in-xen-command-line.patch294
-rw-r--r--docs/api_extension/0013-Step-13-of-15-improve-support-for-getting-xen-vcpu-counts.patch216
-rw-r--r--docs/api_extension/0014-Step-14-of-15-improve-support-for-setting-xen-vcpu-counts.patch342
-rw-r--r--docs/api_extension/0015-Step-15-of-15-remove-dead-xen-code.patch228
23 files changed, 4248 insertions, 1702 deletions
diff --git a/docs/api_extension/0001-Step-1-of-15-add-to-xml.patch b/docs/api_extension/0001-Step-1-of-15-add-to-xml.patch
new file mode 100644
index 0000000000..9fee869d11
--- /dev/null
+++ b/docs/api_extension/0001-Step-1-of-15-add-to-xml.patch
@@ -0,0 +1,145 @@
+From a74f4e44649906dcd82151f7ef837f66d7fa2ab1 Mon Sep 17 00:00:00 2001
+From: Eric Blake <eblake@redhat.com>
+Date: Mon, 27 Sep 2010 17:36:06 -0600
+Subject: [PATCH 01/15] vcpu: add current attribute to <vcpu> element
+
+Syntax agreed on in
+https://www.redhat.com/archives/libvir-list/2010-September/msg00476.html
+
+<domain ...>
+ <vcpu current='x'>y</vcpu>
+...
+
+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 @@
+ &lt;swap_hard_limit&gt;2097152&lt;/swap_hard_limit&gt;
+ &lt;min_guarantee&gt;65536&lt;/min_guarantee&gt;
+ &lt;/memtune&gt;
+- &lt;vcpu cpuset="1-4,^3,6"&gt;2&lt;/vcpu&gt;
++ &lt;vcpu cpuset="1-4,^3,6" current="1"&gt;2&lt;/vcpu&gt;
+ ...</pre>
+
+ <dl>
+@@ -238,7 +238,7 @@
+ minimum memory allocation for the guest. The units for this value are
+ kilobytes (i.e. blocks of 1024 bytes)</dd>
+ <dt><code>vcpu</code></dt>
+- <dd>The content of this element defines the number of virtual
++ <dd>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. <span class="since">Since
+ 0.4.4</span>, 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. <span class="since">Since
++ 0.8.5</span>, the optional attribute <code>current</code> can
++ be used to specify whether fewer than the maximum number of
++ virtual CPUs should be enabled.
+ </dd>
+ </dl>
+
+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 @@
+ <ref name="cpuset"/>
+ </attribute>
+ </optional>
++ <optional>
++ <attribute name="current">
++ <ref name="countCPU"/>
++ </attribute>
++ </optional>
+ <ref name="countCPU"/>
+ </element>
+ </optional>
+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 @@
++<domain type='qemu'>
++ <name>QEMUGuest1</name>
++ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
++ <memory>219200</memory>
++ <currentMemory>219200</currentMemory>
++ <vcpu current='1'>2</vcpu>
++ <os>
++ <type arch='i686' machine='pc'>hvm</type>
++ <boot dev='hd'/>
++ </os>
++ <cpu>
++ <topology sockets='2' cores='1' threads='1'/>
++ </cpu>
++ <clock offset='utc'/>
++ <on_poweroff>destroy</on_poweroff>
++ <on_reboot>restart</on_reboot>
++ <on_crash>destroy</on_crash>
++ <devices>
++ <emulator>/usr/bin/qemu</emulator>
++ <disk type='block' device='disk'>
++ <source dev='/dev/HostVG/QEMUGuest1'/>
++ <target dev='hda' bus='ide'/>
++ <address type='drive' controller='0' bus='0' unit='0'/>
++ </disk>
++ <controller type='ide' index='0'/>
++ <memballoon model='virtio'/>
++ </devices>
++</domain>
+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 @@
++<domain type='xen' id='15'>
++ <name>pvtest</name>
++ <uuid>596a5d2171f48fb2e068e2386a5c413e</uuid>
++ <os>
++ <type>linux</type>
++ <kernel>/var/lib/xen/vmlinuz.2Dn2YT</kernel>
++ <initrd>/var/lib/xen/initrd.img.0u-Vhq</initrd>
++ <cmdline> method=http://download.fedora.devel.redhat.com/pub/fedora/linux/core/test/5.91/x86_64/os </cmdline>
++ </os>
++ <memory>430080</memory>
++ <vcpu current='2'>4</vcpu>
++ <on_poweroff>destroy</on_poweroff>
++ <on_reboot>destroy</on_reboot>
++ <on_crash>destroy</on_crash>
++ <devices>
++ <disk type='file' device='disk'>
++ <source file='/root/some.img'/>
++ <target dev='xvda'/>
++ </disk>
++ <console tty='/dev/pts/4'/>
++ </devices>
++</domain>
+--
+1.7.2.3
+
diff --git a/docs/api_extension/0001-Step-1-of-8-Define-the-public-API.patch b/docs/api_extension/0001-Step-1-of-8-Define-the-public-API.patch
deleted file mode 100644
index 1e6ff0d058..0000000000
--- a/docs/api_extension/0001-Step-1-of-8-Define-the-public-API.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-From 2ae8fd62a1e5e085b7902da9bc207b806d84fd91 Mon Sep 17 00:00:00 2001
-From: David Allan <dallan@redhat.com>
-Date: Tue, 19 May 2009 16:16:11 -0400
-Subject: [PATCH] Step 1 of 8 Define the public API
-
----
- include/libvirt/libvirt.h.in | 6 ++++++
- src/libvirt_public.syms | 6 ++++++
- 2 files changed, 12 insertions(+), 0 deletions(-)
-
-diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
-index a028b21..2f7076f 100644
---- a/include/libvirt/libvirt.h.in
-+++ b/include/libvirt/libvirt.h.in
-@@ -1124,6 +1124,12 @@ int virNodeDeviceDettach (virNodeDevicePtr dev);
- int virNodeDeviceReAttach (virNodeDevicePtr dev);
- int virNodeDeviceReset (virNodeDevicePtr dev);
-
-+virNodeDevicePtr virNodeDeviceCreateXML (virConnectPtr conn,
-+ const char *xmlDesc,
-+ unsigned int flags);
-+
-+int virNodeDeviceDestroy (virNodeDevicePtr dev);
-+
- /*
- * Domain Event Notification
- */
-diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
-index f7ebbc3..b8f9128 100644
---- a/src/libvirt_public.syms
-+++ b/src/libvirt_public.syms
-@@ -258,4 +258,10 @@ LIBVIRT_0.6.1 {
- virNodeGetSecurityModel;
- } LIBVIRT_0.6.0;
-
-+LIBVIRT_0.6.3 {
-+ global:
-+ virNodeDeviceCreateXML;
-+ virNodeDeviceDestroy;
-+} LIBVIRT_0.6.1;
-+
- # .... define new API here using predicted next version number ....
---
-1.6.0.6
diff --git a/docs/api_extension/0002-Step-2-of-15-add-new-public-API.patch b/docs/api_extension/0002-Step-2-of-15-add-new-public-API.patch
new file mode 100644
index 0000000000..df93440a31
--- /dev/null
+++ b/docs/api_extension/0002-Step-2-of-15-add-new-public-API.patch
@@ -0,0 +1,62 @@
+From ea3f5c68093429c6ad507b45689cdf209c2c257b Mon Sep 17 00:00:00 2001
+From: Eric Blake <eblake@redhat.com>
+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/docs/api_extension/0002-Step-2-of-8-Define-the-internal-driver-API.patch b/docs/api_extension/0002-Step-2-of-8-Define-the-internal-driver-API.patch
deleted file mode 100644
index 574ce4082b..0000000000
--- a/docs/api_extension/0002-Step-2-of-8-Define-the-internal-driver-API.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From b26d7fc2d64e7e6e4d3ea2b43361015d3620d7a6 Mon Sep 17 00:00:00 2001
-From: David Allan <dallan@redhat.com>
-Date: Tue, 19 May 2009 16:19:14 -0400
-Subject: [PATCH] Step 2 of 8 Define the internal driver API
-
----
- src/driver.h | 7 +++++++
- 1 files changed, 7 insertions(+), 0 deletions(-)
-
-diff --git a/src/driver.h b/src/driver.h
-index 39dc413..c357b76 100644
---- a/src/driver.h
-+++ b/src/driver.h
-@@ -684,6 +684,11 @@ typedef int (*virDevMonDeviceListCaps)(virNodeDevicePtr dev,
- char **const names,
- int maxnames);
-
-+typedef virNodeDevicePtr (*virDrvNodeDeviceCreateXML)(virConnectPtr conn,
-+ const char *xmlDesc,
-+ unsigned int flags);
-+typedef int (*virDrvNodeDeviceDestroy)(virNodeDevicePtr dev);
-+
- /**
- * _virDeviceMonitor:
- *
-@@ -702,6 +707,8 @@ struct _virDeviceMonitor {
- virDevMonDeviceGetParent deviceGetParent;
- virDevMonDeviceNumOfCaps deviceNumOfCaps;
- virDevMonDeviceListCaps deviceListCaps;
-+ virDrvNodeDeviceCreateXML deviceCreateXML;
-+ virDrvNodeDeviceDestroy deviceDestroy;
- };
-
- /*
---
-1.6.0.6
diff --git a/docs/api_extension/0003-Step-3-of-15-define-internal-driver-API.patch b/docs/api_extension/0003-Step-3-of-15-define-internal-driver-API.patch
new file mode 100644
index 0000000000..2156d974c5
--- /dev/null
+++ b/docs/api_extension/0003-Step-3-of-15-define-internal-driver-API.patch
@@ -0,0 +1,222 @@
+From dd255d64053e9960cd375994ce8f056522e12acc Mon Sep 17 00:00:00 2001
+From: Eric Blake <eblake@redhat.com>
+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/docs/api_extension/0003-Step-3-of-8-Implement-the-public-API.patch b/docs/api_extension/0003-Step-3-of-8-Implement-the-public-API.patch
deleted file mode 100644
index cb7d1252cb..0000000000
--- a/docs/api_extension/0003-Step-3-of-8-Implement-the-public-API.patch
+++ /dev/null
@@ -1,119 +0,0 @@
-From fc585594a207dfb9149e7d3d01c9eb1c79b6d52d Mon Sep 17 00:00:00 2001
-From: David Allan <dallan@redhat.com>
-Date: Tue, 19 May 2009 16:22:23 -0400
-Subject: [PATCH] Step 3 of 8 Implement the public API
-
----
- src/libvirt.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 1 files changed, 97 insertions(+), 0 deletions(-)
-
-diff --git a/src/libvirt.c b/src/libvirt.c
-index f3d4484..ded18a7 100644
---- a/src/libvirt.c
-+++ b/src/libvirt.c
-@@ -7509,6 +7509,103 @@ error:
- }
-
-
-+/**
-+ * virNodeDeviceCreateXML:
-+ * @conn: pointer to the hypervisor connection
-+ * @xmlDesc: string containing an XML description of the device to be created
-+ * @flags: callers should always pass 0
-+ *
-+ * Create a new device on the VM host machine, for example, virtual
-+ * HBAs created using vport_create.
-+ *
-+ * Returns a node device object if successful, NULL in case of failure
-+ */
-+virNodeDevicePtr
-+virNodeDeviceCreateXML(virConnectPtr conn,
-+ const char *xmlDesc,
-+ unsigned int flags)
-+{
-+ VIR_DEBUG("conn=%p, xmlDesc=%s, flags=%d", conn, xmlDesc, flags);
-+
-+ virResetLastError();
-+
-+ if (!VIR_IS_CONNECT(conn)) {
-+ virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
-+ return NULL;
-+ }
-+
-+ if (conn->flags & VIR_CONNECT_RO) {
-+ virLibConnError(conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-+ goto error;
-+ }
-+
-+ if (xmlDesc == NULL) {
-+ virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-+ goto error;
-+ }
-+
-+ if (conn->deviceMonitor &&
-+ conn->deviceMonitor->deviceCreateXML) {
-+ virNodeDevicePtr dev = conn->deviceMonitor->deviceCreateXML(conn, xmlDesc, flags);
-+ if (dev == NULL)
-+ goto error;
-+ return dev;
-+ }
-+
-+ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
-+
-+error:
-+ /* Copy to connection error object for back compatability */
-+ virSetConnError(conn);
-+ return NULL;
-+}
-+
-+
-+/**
-+ * virNodeDeviceDestroy:
-+ * @dev: a device object
-+ *
-+ * Destroy the device object. The virtual device is removed from the host operating system.
-+ * This function may require privileged access
-+ *
-+ * Returns 0 in case of success and -1 in case of failure.
-+ */
-+int
-+virNodeDeviceDestroy(virNodeDevicePtr dev)
-+{
-+ DEBUG("dev=%p", dev);
-+
-+ virResetLastError();
-+
-+ if (!VIR_IS_CONNECTED_NODE_DEVICE(dev)) {
-+ virLibNodeDeviceError(NULL, VIR_ERR_INVALID_NODE_DEVICE, __FUNCTION__);
-+ return (-1);
-+ }
-+
-+ if (dev->conn->flags & VIR_CONNECT_RO) {
-+ virLibConnError(dev->conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-+ goto error;
-+ }
-+
-+ if (dev->conn->deviceMonitor &&
-+ dev->conn->deviceMonitor->deviceDestroy) {
-+ int retval = dev->conn->deviceMonitor->deviceDestroy(dev);
-+ if (retval < 0) {
-+ goto error;
-+ }
-+
-+ return 0;
-+ }
-+
-+ virLibConnError (dev->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
-+
-+error:
-+ /* Copy to connection error object for back compatability */
-+ virSetConnError(dev->conn);
-+ return -1;
-+}
-+
-+
- /*
- * Domain Event Notification
- */
---
-1.6.0.6
diff --git a/docs/api_extension/0004-Step-4-of-15-implement-the-public-APIs.patch b/docs/api_extension/0004-Step-4-of-15-implement-the-public-APIs.patch
new file mode 100644
index 0000000000..96c34396a8
--- /dev/null
+++ b/docs/api_extension/0004-Step-4-of-15-implement-the-public-APIs.patch
@@ -0,0 +1,188 @@
+From 9d2c60799271d605f82dfd4bfa6ed7d14ad87e26 Mon Sep 17 00:00:00 2001
+From: Eric Blake <eblake@redhat.com>
+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;
++ 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;
++ 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/docs/api_extension/0004-Step-4-of-8-Define-the-wire-protocol-format.patch b/docs/api_extension/0004-Step-4-of-8-Define-the-wire-protocol-format.patch
deleted file mode 100644
index 5d99d5cb27..0000000000
--- a/docs/api_extension/0004-Step-4-of-8-Define-the-wire-protocol-format.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From bce8f1243b0454c0d70e3db832a039d22faab09a Mon Sep 17 00:00:00 2001
-From: David Allan <dallan@redhat.com>
-Date: Wed, 20 May 2009 13:58:58 -0400
-Subject: [PATCH] Step 4 of 8 Define the wire protocol format
-
----
- qemud/remote_protocol.x | 18 +++++++++++++++++-
- 1 files changed, 17 insertions(+), 1 deletions(-)
-
-diff --git a/qemud/remote_protocol.x b/qemud/remote_protocol.x
-index 2d8e6a2..2c79949 100644
---- a/qemud/remote_protocol.x
-+++ b/qemud/remote_protocol.x
-@@ -1109,6 +1109,19 @@ struct remote_node_device_reset_args {
- remote_nonnull_string name;
- };
-
-+struct remote_node_device_create_xml_args {
-+ remote_nonnull_string xml_desc;
-+ int flags;
-+};
-+
-+struct remote_node_device_create_xml_ret {
-+ remote_nonnull_node_device dev;
-+};
-+
-+struct remote_node_device_destroy_args {
-+ remote_nonnull_string name;
-+};
-+
-
- /**
- * Events Register/Deregister:
-@@ -1270,7 +1283,10 @@ enum remote_procedure {
- REMOTE_PROC_NODE_DEVICE_RESET = 120,
-
- REMOTE_PROC_DOMAIN_GET_SECURITY_LABEL = 121,
-- REMOTE_PROC_NODE_GET_SECURITY_MODEL = 122
-+ REMOTE_PROC_NODE_GET_SECURITY_MODEL = 122,
-+
-+ REMOTE_PROC_NODE_DEVICE_CREATE_XML = 123,
-+ REMOTE_PROC_NODE_DEVICE_DESTROY = 124
- };
-
- /* Custom RPC structure. */
---
-1.6.0.6
diff --git a/docs/api_extension/0005-Step-5-of-15-implement-the-remote-protocol.patch b/docs/api_extension/0005-Step-5-of-15-implement-the-remote-protocol.patch
new file mode 100644
index 0000000000..77912a033d
--- /dev/null
+++ b/docs/api_extension/0005-Step-5-of-15-implement-the-remote-protocol.patch
@@ -0,0 +1,421 @@
+From eb826444f90c2563dadf148630b0cd6a9b41ba1e Mon Sep 17 00:00:00 2001
+From: Eric Blake <eblake@redhat.com>
+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/docs/api_extension/0005-Step-5-of-8-Implement-the-RPC-client.patch b/docs/api_extension/0005-Step-5-of-8-Implement-the-RPC-client.patch
deleted file mode 100644
index cd079f48c8..0000000000
--- a/docs/api_extension/0005-Step-5-of-8-Implement-the-RPC-client.patch
+++ /dev/null
@@ -1,84 +0,0 @@
-From ff272552c297966ace3492aefe91fc830152251a Mon Sep 17 00:00:00 2001
-From: David Allan <dallan@redhat.com>
-Date: Tue, 19 May 2009 16:26:12 -0400
-Subject: [PATCH] Step 5 of 8 Implement the RPC client
-
----
- src/remote_internal.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++
- 1 files changed, 55 insertions(+), 0 deletions(-)
-
-diff --git a/src/remote_internal.c b/src/remote_internal.c
-index 4b3afb0..e665ef8 100644
---- a/src/remote_internal.c
-+++ b/src/remote_internal.c
-@@ -4978,6 +4978,59 @@ done:
- }
-
-
-+static virNodeDevicePtr
-+remoteNodeDeviceCreateXML(virConnectPtr conn,
-+ const char *xmlDesc,
-+ unsigned int flags)
-+{
-+ remote_node_device_create_xml_args args;
-+ remote_node_device_create_xml_ret ret;
-+ virNodeDevicePtr dev = NULL;
-+ struct private_data *priv = conn->privateData;
-+
-+ remoteDriverLock(priv);
-+
-+ memset(&ret, 0, sizeof ret);
-+ args.xml_desc = (char *)xmlDesc;
-+ args.flags = flags;
-+
-+ if (call(conn, priv, 0, REMOTE_PROC_NODE_DEVICE_CREATE_XML,
-+ (xdrproc_t) xdr_remote_node_device_create_xml_args, (char *) &args,
-+ (xdrproc_t) xdr_remote_node_device_create_xml_ret, (char *) &ret) == -1)
-+ goto done;
-+
-+ dev = get_nonnull_node_device(conn, ret.dev);
-+ xdr_free ((xdrproc_t) xdr_remote_node_device_create_xml_ret, (char *) &ret);
-+
-+done:
-+ remoteDriverUnlock(priv);
-+ return dev;
-+}
-+
-+static int
-+remoteNodeDeviceDestroy(virNodeDevicePtr dev)
-+{
-+ int rv = -1;
-+ remote_node_device_destroy_args args;
-+ struct private_data *priv = dev->conn->privateData;
-+
-+ remoteDriverLock(priv);
-+
-+ args.name = dev->name;
-+
-+ if (call(dev->conn, priv, 0, REMOTE_PROC_NODE_DEVICE_DESTROY,
-+ (xdrproc_t) xdr_remote_node_device_destroy_args, (char *) &args,
-+ (xdrproc_t) xdr_void, (char *) NULL) == -1)
-+ goto done;
-+
-+ rv = 0;
-+
-+done:
-+ remoteDriverUnlock(priv);
-+ return rv;
-+}
-+
-+
- /*----------------------------------------------------------------------*/
-
- static int
-@@ -6982,6 +7035,8 @@ static virDeviceMonitor dev_monitor = {
- .deviceGetParent = remoteNodeDeviceGetParent,
- .deviceNumOfCaps = remoteNodeDeviceNumOfCaps,
- .deviceListCaps = remoteNodeDeviceListCaps,
-+ .deviceCreateXML = remoteNodeDeviceCreateXML,
-+ .deviceDestroy = remoteNodeDeviceDestroy
- };
-
-
---
-1.6.0.6
diff --git a/docs/api_extension/0006-Step-6-of-15-make-old-API-trivially-wrap-to-new-API.patch b/docs/api_extension/0006-Step-6-of-15-make-old-API-trivially-wrap-to-new-API.patch
new file mode 100644
index 0000000000..1ef51fef46
--- /dev/null
+++ b/docs/api_extension/0006-Step-6-of-15-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 <eblake@redhat.com>
+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/docs/api_extension/0006-Step-6-of-8-Implement-the-server-side-dispatcher.patch b/docs/api_extension/0006-Step-6-of-8-Implement-the-server-side-dispatcher.patch
deleted file mode 100644
index 30d1678fe8..0000000000
--- a/docs/api_extension/0006-Step-6-of-8-Implement-the-server-side-dispatcher.patch
+++ /dev/null
@@ -1,70 +0,0 @@
-From 4c5166df583459574526841234d61d6ae5be19a0 Mon Sep 17 00:00:00 2001
-From: David Allan <dallan@redhat.com>
-Date: Tue, 19 May 2009 16:26:55 -0400
-Subject: [PATCH] Step 6 of 8 Implement the server side dispatcher
-
----
- qemud/remote.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
- 1 files changed, 48 insertions(+), 0 deletions(-)
-
-diff --git a/qemud/remote.c b/qemud/remote.c
-index e27820f..8d24a3a 100644
---- a/qemud/remote.c
-+++ b/qemud/remote.c
-@@ -4323,6 +4323,54 @@ remoteDispatchNodeDeviceReset (struct qemud_server *server ATTRIBUTE_UNUSED,
- }
-
-
-+static int
-+remoteDispatchNodeDeviceCreateXml(struct qemud_server *server ATTRIBUTE_UNUSED,
-+ struct qemud_client *client ATTRIBUTE_UNUSED,
-+ virConnectPtr conn,
-+ remote_error *rerr,
-+ remote_node_device_create_xml_args *args,
-+ remote_node_device_create_xml_ret *ret)
-+{
-+ virNodeDevicePtr dev;
-+
-+ dev = virNodeDeviceCreateXML (conn, args->xml_desc, args->flags);
-+ if (dev == NULL) {
-+ remoteDispatchConnError(rerr, conn);
-+ return -1;
-+ }
-+
-+ make_nonnull_node_device (&ret->dev, dev);
-+ virNodeDeviceFree(dev);
-+
-+ return 0;
-+}
-+
-+
-+static int
-+remoteDispatchNodeDeviceDestroy(struct qemud_server *server ATTRIBUTE_UNUSED,
-+ struct qemud_client *client ATTRIBUTE_UNUSED,
-+ virConnectPtr conn,
-+ remote_error *rerr,
-+ remote_node_device_destroy_args *args,
-+ void *ret ATTRIBUTE_UNUSED)
-+{
-+ virNodeDevicePtr dev;
-+
-+ dev = virNodeDeviceLookupByName(conn, args->name);
-+ if (dev == NULL) {
-+ remoteDispatchFormatError(rerr, "%s", _("node_device not found"));
-+ return -1;
-+ }
-+
-+ if (virNodeDeviceDestroy(dev) == -1) {
-+ remoteDispatchConnError(rerr, conn);
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-+
-+
- /**************************
- * Async Events
- **************************/
---
-1.6.0.6
diff --git a/docs/api_extension/0007-Step-7-of-15-add-virsh-support.patch b/docs/api_extension/0007-Step-7-of-15-add-virsh-support.patch
new file mode 100644
index 0000000000..8c5494e04d
--- /dev/null
+++ b/docs/api_extension/0007-Step-7-of-15-add-virsh-support.patch
@@ -0,0 +1,388 @@
+From bf945ee97b72d3b0c4fc2da04530f5294f529d66 Mon Sep 17 00:00:00 2001
+From: Eric Blake <eblake@redhat.com>
+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, "<vcpu"))) {
++ tmp = strchr(tmp, '>');
++ 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, "<vcpu"))) {
++ end = strchr(tmp, '>');
++ 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<migrate> optional I<--live> I<--suspend> I<domain-id> I<desturi> I<migrateuri>
++=item B<maxvcpus> optional I<type>
++
++Provide the maximum number of virtual CPUs supported for a guest VM on
++this connection. If provided, the I<type> parameter must be a valid
++type attribute for the <domain> element of XML.
++
++=item B<migrate> optional I<--live> I<--suspend> I<domain-id> I<desturi>
++I<migrateuri>
+
+ Migrate domain to another host. Add --live for live migration; --suspend
+ leaves the domain paused on the destination host. The I<desturi> 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<setvcpus> I<domain-id> I<count>
++=item B<setvcpus> I<domain-id> I<count> optional I<--maximum> I<--config>
++I<--live>
+
+ Change the number of virtual CPUs active in the guest domain. Note that
+ I<count> 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<shutdown> I<domain-id>
+
+ 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<domain-id>.
+
++=item B<vcpucount> I<domain-id> optional I<--maximum> I<--current>
++I<--config> I<--live>
++
++Print information about the virtual cpu counts of the given
++I<domain-id>. 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<setvcpus>, 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<vcpuinfo> I<domain-id>
+
+ Returns basic information about the domain virtual CPUs, like the number of
+--
+1.7.2.3
+
diff --git a/docs/api_extension/0007-Step-7-of-8-Implement-the-driver-methods.patch b/docs/api_extension/0007-Step-7-of-8-Implement-the-driver-methods.patch
deleted file mode 100644
index ff1124f0b8..0000000000
--- a/docs/api_extension/0007-Step-7-of-8-Implement-the-driver-methods.patch
+++ /dev/null
@@ -1,1171 +0,0 @@
-From 04d20a662109de6727232eb1213627877bb9662f Mon Sep 17 00:00:00 2001
-From: David Allan <dallan@redhat.com>
-Date: Tue, 19 May 2009 16:35:15 -0400
-Subject: [PATCH] Step 7 of 8 Implement the driver methods
-
----
- src/Makefile.am | 4 +-
- src/node_device.c | 430 +++++++++++++++++++++++++++++++++++++++++++
- src/node_device.h | 13 ++
- src/node_device_conf.c | 136 ++++++++++++--
- src/node_device_conf.h | 22 ++-
- src/node_device_hal.c | 5 +
- src/node_device_hal.h | 40 ++++
- src/node_device_hal_linux.c | 170 +++++++++++++++++
- src/qemu_driver.c | 2 +-
- src/storage_backend.c | 24 +--
- src/xen_unified.c | 2 +-
- tests/nodedevxml2xmltest.c | 2 +-
- 12 files changed, 810 insertions(+), 40 deletions(-)
- create mode 100644 src/node_device_hal.h
- create mode 100644 src/node_device_hal_linux.c
-
-diff --git a/src/Makefile.am b/src/Makefile.am
-index fd692b4..39fabce 100644
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -188,7 +188,9 @@ NODE_DEVICE_DRIVER_SOURCES = \
- node_device.c node_device.h
-
- NODE_DEVICE_DRIVER_HAL_SOURCES = \
-- node_device_hal.c
-+ node_device_hal.c \
-+ node_device_hal_linux.c
-+
- NODE_DEVICE_DRIVER_DEVKIT_SOURCES = \
- node_device_devkit.c
-
-diff --git a/src/node_device.c b/src/node_device.c
-index b84729f..4f73baf 100644
---- a/src/node_device.c
-+++ b/src/node_device.c
-@@ -25,6 +25,8 @@
-
- #include <unistd.h>
- #include <errno.h>
-+#include <fcntl.h>
-+#include <time.h>
-
- #include "virterror_internal.h"
- #include "datatypes.h"
-@@ -133,6 +135,53 @@ cleanup:
- return ret;
- }
-
-+
-+static virNodeDevicePtr
-+nodeDeviceLookupByWWN(virConnectPtr conn,
-+ const char *wwnn,
-+ const char *wwpn)
-+{
-+ unsigned int i;
-+ virDeviceMonitorStatePtr driver = conn->devMonPrivateData;
-+ virNodeDeviceObjListPtr devs = &driver->devs;
-+ virNodeDevCapsDefPtr cap = NULL;
-+ virNodeDeviceObjPtr obj = NULL;
-+ virNodeDevicePtr dev = NULL;
-+
-+ nodeDeviceLock(driver);
-+
-+ for (i = 0; i < devs->count; i++) {
-+
-+ obj = devs->objs[i];
-+ virNodeDeviceObjLock(obj);
-+ cap = obj->def->caps;
-+
-+ while (cap) {
-+
-+ if (cap->type == VIR_NODE_DEV_CAP_SCSI_HOST) {
-+ if (cap->data.scsi_host.flags &
-+ VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) {
-+
-+ if (STREQ(cap->data.scsi_host.wwnn, wwnn) &&
-+ STREQ(cap->data.scsi_host.wwpn, wwpn)) {
-+ dev = virGetNodeDevice(conn, obj->def->name);
-+ virNodeDeviceObjUnlock(obj);
-+ goto out;
-+ }
-+ }
-+ }
-+ cap = cap->next;
-+ }
-+
-+ virNodeDeviceObjUnlock(obj);
-+ }
-+
-+out:
-+ nodeDeviceUnlock(driver);
-+ return dev;
-+}
-+
-+
- static char *nodeDeviceDumpXML(virNodeDevicePtr dev,
- unsigned int flags ATTRIBUTE_UNUSED)
- {
-@@ -258,6 +307,385 @@ cleanup:
- }
-
-
-+static int
-+nodeDeviceVportCreateDelete(virConnectPtr conn,
-+ const int parent_host,
-+ const char *wwpn,
-+ const char *wwnn,
-+ int operation)
-+{
-+ int fd = -1;
-+ int retval = 0;
-+ char *operation_path = NULL, *vport_name = NULL;
-+ const char *operation_file = NULL;
-+ size_t towrite = 0;
-+ unsigned int written = 0;
-+
-+ switch (operation) {
-+ case VPORT_CREATE:
-+ operation_file = LINUX_SYSFS_VPORT_CREATE_POSTFIX;
-+ break;
-+ case VPORT_DELETE:
-+ operation_file = LINUX_SYSFS_VPORT_DELETE_POSTFIX;
-+ break;
-+ default:
-+ virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR,
-+ _("Invalid vport operation (%d)"), operation);
-+ retval = -1;
-+ goto cleanup;
-+ break;
-+ }
-+
-+ if (virAsprintf(&operation_path,
-+ "%shost%d%s",
-+ LINUX_SYSFS_FC_HOST_PREFIX,
-+ parent_host,
-+ operation_file) < 0) {
-+
-+ virReportOOMError();
-+ retval = -1;
-+ goto cleanup;
-+ }
-+
-+ VIR_DEBUG("Vport operation path is '%s'", operation_path);
-+
-+ fd = open(operation_path, O_WRONLY);
-+
-+ if (fd < 0) {
-+ virReportSystemError(errno,
-+ _("Could not open '%s' for vport operation"),
-+ operation_path);
-+ retval = -1;
-+ goto cleanup;
-+ }
-+
-+ if (virAsprintf(&vport_name,
-+ "%s:%s",
-+ wwpn,
-+ wwnn) < 0) {
-+
-+ virReportOOMError();
-+ retval = -1;
-+ goto cleanup;
-+ }
-+
-+ towrite = strlen(vport_name);
-+ written = safewrite(fd, vport_name, towrite);
-+ if (written != towrite) {
-+ virReportSystemError(errno,
-+ _("Write of '%s' to '%s' during "
-+ "vport create/delete failed "
-+ "(towrite: %lu written: %d)"),
-+ vport_name, operation_path,
-+ towrite, written);
-+ retval = -1;
-+ }
-+
-+cleanup:
-+ if (fd != -1) {
-+ close(fd);
-+ }
-+ VIR_FREE(vport_name);
-+ VIR_FREE(operation_path);
-+ VIR_DEBUG("%s", _("Vport operation complete"));
-+ return retval;
-+}
-+
-+
-+static int
-+get_wwns(virConnectPtr conn,
-+ virNodeDeviceDefPtr def,
-+ char **wwnn,
-+ char **wwpn)
-+{
-+ virNodeDevCapsDefPtr cap = NULL;
-+ int ret = 0;
-+
-+ cap = def->caps;
-+ while (cap != NULL) {
-+ if (cap->type == VIR_NODE_DEV_CAP_SCSI_HOST &&
-+ cap->data.scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) {
-+ *wwnn = strdup(cap->data.scsi_host.wwnn);
-+ *wwpn = strdup(cap->data.scsi_host.wwpn);
-+ break;
-+ }
-+
-+ cap = cap->next;
-+ }
-+
-+ if (cap == NULL) {
-+ virNodeDeviceReportError(conn, VIR_ERR_NO_SUPPORT,
-+ "%s", _("Device is not a fibre channel HBA"));
-+ ret = -1;
-+ }
-+
-+ if (*wwnn == NULL || *wwpn == NULL) {
-+ /* Free the other one, if allocated... */
-+ VIR_FREE(wwnn);
-+ VIR_FREE(wwpn);
-+ ret = -1;
-+ virReportOOMError();
-+ }
-+
-+ return ret;
-+}
-+
-+
-+static int
-+get_parent_host(virConnectPtr conn,
-+ virDeviceMonitorStatePtr driver,
-+ const char *dev_name,
-+ const char *parent_name,
-+ int *parent_host)
-+{
-+ virNodeDeviceObjPtr parent = NULL;
-+ virNodeDevCapsDefPtr cap = NULL;
-+ int ret = 0;
-+
-+ parent = virNodeDeviceFindByName(&driver->devs, parent_name);
-+ if (parent == NULL) {
-+ virNodeDeviceReportError(conn, VIR_ERR_INVALID_NODE_DEVICE,
-+ _("Could not find parent device for '%s'"),
-+ dev_name);
-+ ret = -1;
-+ goto out;
-+ }
-+
-+ cap = parent->def->caps;
-+ while (cap != NULL) {
-+ if (cap->type == VIR_NODE_DEV_CAP_SCSI_HOST &&
-+ (cap->data.scsi_host.flags &
-+ VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS)) {
-+ *parent_host = cap->data.scsi_host.host;
-+ break;
-+ }
-+
-+ cap = cap->next;
-+ }
-+
-+ if (cap == NULL) {
-+ virNodeDeviceReportError(conn, VIR_ERR_INVALID_NODE_DEVICE,
-+ _("Device %s is not capable of vport operations"),
-+ parent->def->name);
-+ ret = -1;
-+ }
-+
-+ virNodeDeviceObjUnlock(parent);
-+
-+out:
-+ return ret;
-+}
-+
-+
-+static int
-+get_time(virConnectPtr conn, time_t *t)
-+{
-+ int ret = 0;
-+
-+ *t = time(NULL);
-+ if (*t == (time_t)-1) {
-+ virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR,
-+ "%s", _("Could not get current time"));
-+
-+ *t = 0;
-+ ret = -1;
-+ }
-+
-+ return ret;
-+}
-+
-+
-+/* When large numbers of devices are present on the host, it's
-+ * possible for udev not to realize that it has work to do before we
-+ * get here. We thus keep trying to find the new device we just
-+ * created for up to LINUX_NEW_DEVICE_WAIT_TIME. Note that udev's
-+ * default settle time is 180 seconds, so once udev realizes that it
-+ * has work to do, it might take that long for the udev wait to
-+ * return. Thus the total maximum time for this function to return is
-+ * the udev settle time plus LINUX_NEW_DEVICE_WAIT_TIME.
-+ *
-+ * This whole area is a race, but if we retry the udev wait for
-+ * LINUX_NEW_DEVICE_WAIT_TIME seconds and there's still no device,
-+ * it's probably safe to assume it's not going to appear.
-+ */
-+static virNodeDevicePtr
-+find_new_device(virConnectPtr conn, const char *wwnn, const char *wwpn)
-+{
-+ virDeviceMonitorStatePtr driver = conn->devMonPrivateData;
-+ virNodeDevicePtr dev = NULL;
-+ time_t start = 0, now = 0;
-+
-+ /* The thread that creates the device takes the driver lock, so we
-+ * must release it in order to allow the device to be created.
-+ * We're not doing anything with the driver pointer at this point,
-+ * so it's safe to release it, assuming that the pointer itself
-+ * doesn't become invalid. */
-+ nodeDeviceUnlock(driver);
-+
-+ get_time(conn, &start);
-+
-+ while ((now - start) < LINUX_NEW_DEVICE_WAIT_TIME) {
-+
-+ virNodeDeviceWaitForDevices(conn);
-+
-+ dev = nodeDeviceLookupByWWN(conn, wwnn, wwpn);
-+
-+ if (dev != NULL) {
-+ break;
-+ }
-+
-+ sleep(5);
-+ if (get_time(conn, &now) == -1) {
-+ break;
-+ }
-+ }
-+
-+ nodeDeviceLock(driver);
-+
-+ return dev;
-+}
-+
-+static virNodeDevicePtr
-+nodeDeviceCreateXML(virConnectPtr conn,
-+ const char *xmlDesc,
-+ unsigned int flags ATTRIBUTE_UNUSED)
-+{
-+ virDeviceMonitorStatePtr driver = conn->devMonPrivateData;
-+ virNodeDeviceDefPtr def = NULL;
-+ char *wwnn = NULL, *wwpn = NULL;
-+ int parent_host = -1;
-+ virNodeDevicePtr dev = NULL;
-+
-+ nodeDeviceLock(driver);
-+
-+ def = virNodeDeviceDefParseString(conn, xmlDesc, CREATE_DEVICE);
-+ if (def == NULL) {
-+ goto cleanup;
-+ }
-+
-+ if (get_wwns(conn, def, &wwnn, &wwpn) == -1) {
-+ goto cleanup;
-+ }
-+
-+ if (get_parent_host(conn,
-+ driver,
-+ def->name,
-+ def->parent,
-+ &parent_host) == -1) {
-+ goto cleanup;
-+ }
-+
-+ if (nodeDeviceVportCreateDelete(conn,
-+ parent_host,
-+ wwpn,
-+ wwnn,
-+ VPORT_CREATE) == -1) {
-+ goto cleanup;
-+ }
-+
-+ dev = find_new_device(conn, wwnn, wwpn);
-+ /* We don't check the return value, because one way or another,
-+ * we're returning what we get... */
-+
-+ if (dev == NULL) {
-+ virNodeDeviceReportError(conn, VIR_ERR_NO_NODE_DEVICE, NULL);
-+ }
-+
-+cleanup:
-+ nodeDeviceUnlock(driver);
-+ virNodeDeviceDefFree(def);
-+ VIR_FREE(wwnn);
-+ VIR_FREE(wwpn);
-+ return dev;
-+}
-+
-+
-+static int
-+nodeDeviceDestroy(virNodeDevicePtr dev)
-+{
-+ int ret = 0;
-+ virDeviceMonitorStatePtr driver = dev->conn->devMonPrivateData;
-+ virNodeDeviceObjPtr obj = NULL;
-+ char *parent_name = NULL, *wwnn = NULL, *wwpn = NULL;
-+ int parent_host = -1;
-+
-+ nodeDeviceLock(driver);
-+ obj = virNodeDeviceFindByName(&driver->devs, dev->name);
-+ nodeDeviceUnlock(driver);
-+
-+ if (!obj) {
-+ virNodeDeviceReportError(dev->conn, VIR_ERR_NO_NODE_DEVICE, NULL);
-+ goto out;
-+ }
-+
-+ if (get_wwns(dev->conn, obj->def, &wwnn, &wwpn) == -1) {
-+ goto out;
-+ }
-+
-+ parent_name = strdup(obj->def->parent);
-+
-+ /* get_parent_host will cause the device object's lock to be
-+ * taken, so we have to dup the parent's name and drop the lock
-+ * before calling it. We don't need the reference to the object
-+ * any more once we have the parent's name. */
-+ virNodeDeviceObjUnlock(obj);
-+ obj = NULL;
-+
-+ if (parent_name == NULL) {
-+ virReportOOMError();
-+ goto out;
-+ }
-+
-+ if (get_parent_host(dev->conn,
-+ driver,
-+ dev->name,
-+ parent_name,
-+ &parent_host) == -1) {
-+ goto out;
-+ }
-+
-+ if (nodeDeviceVportCreateDelete(dev->conn,
-+ parent_host,
-+ wwpn,
-+ wwnn,
-+ VPORT_DELETE) == -1) {
-+ goto out;
-+ }
-+
-+out:
-+ VIR_FREE(parent_name);
-+ VIR_FREE(wwnn);
-+ VIR_FREE(wwpn);
-+ return ret;
-+}
-+
-+
-+#if defined(UDEVADM) || defined(UDEVSETTLE)
-+void virNodeDeviceWaitForDevices(virConnectPtr conn)
-+{
-+#ifdef UDEVADM
-+ const char *const settleprog[] = { UDEVADM, "settle", NULL };
-+#else
-+ const char *const settleprog[] = { UDEVSETTLE, NULL };
-+#endif
-+ int exitstatus;
-+
-+ if (access(settleprog[0], X_OK) != 0)
-+ return;
-+
-+ /*
-+ * NOTE: we ignore errors here; this is just to make sure that any device
-+ * nodes that are being created finish before we try to scan them.
-+ * If this fails for any reason, we still have the backup of polling for
-+ * 5 seconds for device nodes.
-+ */
-+ virRun(settleprog, &exitstatus);
-+}
-+#else
-+void virNodeDeviceWaitForDevices(virConnectPtr conn ATTRIBUTE_UNUSED) {}
-+#endif
-+
-+
- void registerCommonNodeFuncs(virDeviceMonitorPtr driver)
- {
- driver->numOfDevices = nodeNumOfDevices;
-@@ -267,6 +695,8 @@ void registerCommonNodeFuncs(virDeviceMonitorPtr driver)
- driver->deviceGetParent = nodeDeviceGetParent;
- driver->deviceNumOfCaps = nodeDeviceNumOfCaps;
- driver->deviceListCaps = nodeDeviceListCaps;
-+ driver->deviceCreateXML = nodeDeviceCreateXML;
-+ driver->deviceDestroy = nodeDeviceDestroy;
- }
-
-
-diff --git a/src/node_device.h b/src/node_device.h
-index 9496120..882ba0f 100644
---- a/src/node_device.h
-+++ b/src/node_device.h
-@@ -28,6 +28,17 @@
- #include "driver.h"
- #include "node_device_conf.h"
-
-+#define LINUX_SYSFS_SCSI_HOST_PREFIX "/sys/class/scsi_host"
-+#define LINUX_SYSFS_SCSI_HOST_POSTFIX "device"
-+#define LINUX_SYSFS_FC_HOST_PREFIX "/sys/class/fc_host/"
-+
-+#define VPORT_CREATE 0
-+#define VPORT_DELETE 1
-+#define LINUX_SYSFS_VPORT_CREATE_POSTFIX "/vport_create"
-+#define LINUX_SYSFS_VPORT_DELETE_POSTFIX "/vport_delete"
-+
-+#define LINUX_NEW_DEVICE_WAIT_TIME 60
-+
- #ifdef HAVE_HAL
- int halNodeRegister(void);
- #endif
-@@ -42,4 +53,6 @@ void registerCommonNodeFuncs(virDeviceMonitorPtr mon);
-
- int nodedevRegister(void);
-
-+void virNodeDeviceWaitForDevices(virConnectPtr conn);
-+
- #endif /* __VIR_NODE_DEVICE_H__ */
-diff --git a/src/node_device_conf.c b/src/node_device_conf.c
-index 6e04112..5b35b60 100644
---- a/src/node_device_conf.c
-+++ b/src/node_device_conf.c
-@@ -53,9 +53,34 @@ VIR_ENUM_IMPL(virNodeDevNetCap, VIR_NODE_DEV_CAP_NET_LAST,
- "80203",
- "80211")
-
-+VIR_ENUM_IMPL(virNodeDevHBACap, VIR_NODE_DEV_CAP_HBA_LAST,
-+ "fc_host",
-+ "vport_ops")
-
- #define virNodeDeviceLog(msg...) fprintf(stderr, msg)
-
-+static int
-+virNodeDevCapsDefParseString(virConnectPtr conn,
-+ const char *xpath,
-+ xmlXPathContextPtr ctxt,
-+ char **string,
-+ virNodeDeviceDefPtr def,
-+ const char *missing_error_fmt)
-+{
-+ char *s;
-+
-+ s = virXPathString(xpath, ctxt);
-+ if (s == NULL) {
-+ virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR,
-+ missing_error_fmt,
-+ def->name);
-+ return -1;
-+ }
-+
-+ *string = s;
-+ return 0;
-+}
-+
- virNodeDeviceObjPtr virNodeDeviceFindByName(const virNodeDeviceObjListPtr devs,
- const char *name)
- {
-@@ -302,6 +327,18 @@ char *virNodeDeviceDefFormat(virConnectPtr conn,
- case VIR_NODE_DEV_CAP_SCSI_HOST:
- virBufferVSprintf(&buf, " <host>%d</host>\n",
- data->scsi_host.host);
-+ if (data->scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) {
-+ virBufferAddLit(&buf, " <capability type='fc_host'>\n");
-+ virBufferVSprintf(&buf,
-+ " <wwnn>%s</wwnn>\n", data->scsi_host.wwnn);
-+ virBufferVSprintf(&buf,
-+ " <wwpn>%s</wwpn>\n", data->scsi_host.wwpn);
-+ virBufferAddLit(&buf, " </capability>\n");
-+ }
-+ if (data->scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS) {
-+ virBufferAddLit(&buf, " <capability type='vport_ops' />\n");
-+ }
-+
- break;
- case VIR_NODE_DEV_CAP_SCSI:
- virBufferVSprintf(&buf, " <host>%d</host>\n", data->scsi.host);
-@@ -561,26 +598,91 @@ virNodeDevCapScsiHostParseXML(virConnectPtr conn,
- xmlXPathContextPtr ctxt,
- virNodeDeviceDefPtr def,
- xmlNodePtr node,
-- union _virNodeDevCapData *data)
-+ union _virNodeDevCapData *data,
-+ int create)
- {
-- xmlNodePtr orignode;
-- int ret = -1;
-+ xmlNodePtr orignode, *nodes = NULL;
-+ int ret = -1, n = 0, i;
-+ char *type = NULL;
-
- orignode = ctxt->node;
- ctxt->node = node;
-
-- if (virNodeDevCapsDefParseULong(conn, "number(./host[1])", ctxt,
-+ if (create == EXISTING_DEVICE &&
-+ virNodeDevCapsDefParseULong(conn, "number(./host[1])", ctxt,
- &data->scsi_host.host, def,
- _("no SCSI host ID supplied for '%s'"),
-- _("invalid SCSI host ID supplied for '%s'")) < 0)
-+ _("invalid SCSI host ID supplied for '%s'")) < 0) {
- goto out;
-+ }
-+
-+ if ((n = virXPathNodeSet("./capability", ctxt, &nodes)) < 0) {
-+ virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR,
-+ _("error parsing SCSI host capabilities for '%s'"),
-+ def->name);
-+ goto out;
-+ }
-+
-+ for (i = 0 ; i < n ; i++) {
-+ type = virXMLPropString(nodes[i], "type");
-+
-+ if (!type) {
-+ virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR,
-+ _("missing SCSI host capability type for '%s'"),
-+ def->name);
-+ goto out;
-+ }
-+
-+ if (STREQ(type, "vport_ops")) {
-+
-+ data->scsi_host.flags |= VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS;
-+
-+ } else if (STREQ(type, "fc_host")) {
-+
-+ xmlNodePtr orignode2;
-+
-+ data->scsi_host.flags |= VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST;
-+
-+ orignode2 = ctxt->node;
-+ ctxt->node = nodes[i];
-+
-+ if (virNodeDevCapsDefParseString(conn, "string(./wwnn[1])",
-+ ctxt,
-+ &data->scsi_host.wwnn,
-+ def,
-+ _("no WWNN supplied for '%s'")) < 0) {
-+ goto out;
-+ }
-+
-+ if (virNodeDevCapsDefParseString(conn, "string(./wwpn[1])",
-+ ctxt,
-+ &data->scsi_host.wwpn,
-+ def,
-+ _("no WWPN supplied for '%s'")) < 0) {
-+ goto out;
-+ }
-+
-+ ctxt->node = orignode2;
-+
-+ } else {
-+ virNodeDeviceReportError(conn, VIR_ERR_INTERNAL_ERROR,
-+ _("unknown SCSI host capability type '%s' for '%s'"),
-+ type, def->name);
-+ goto out;
-+ }
-+
-+ VIR_FREE(type);
-+ }
-
- ret = 0;
-+
- out:
-+ VIR_FREE(type);
- ctxt->node = orignode;
- return ret;
- }
-
-+
- static int
- virNodeDevCapNetParseXML(virConnectPtr conn,
- xmlXPathContextPtr ctxt,
-@@ -848,7 +950,8 @@ static virNodeDevCapsDefPtr
- virNodeDevCapsDefParseXML(virConnectPtr conn,
- xmlXPathContextPtr ctxt,
- virNodeDeviceDefPtr def,
-- xmlNodePtr node)
-+ xmlNodePtr node,
-+ int create)
- {
- virNodeDevCapsDefPtr caps;
- char *tmp;
-@@ -892,7 +995,7 @@ virNodeDevCapsDefParseXML(virConnectPtr conn,
- ret = virNodeDevCapNetParseXML(conn, ctxt, def, node, &caps->data);
- break;
- case VIR_NODE_DEV_CAP_SCSI_HOST:
-- ret = virNodeDevCapScsiHostParseXML(conn, ctxt, def, node, &caps->data);
-+ ret = virNodeDevCapScsiHostParseXML(conn, ctxt, def, node, &caps->data, create);
- break;
- case VIR_NODE_DEV_CAP_SCSI:
- ret = virNodeDevCapScsiParseXML(conn, ctxt, def, node, &caps->data);
-@@ -918,7 +1021,7 @@ error:
- }
-
- static virNodeDeviceDefPtr
--virNodeDeviceDefParseXML(virConnectPtr conn, xmlXPathContextPtr ctxt)
-+virNodeDeviceDefParseXML(virConnectPtr conn, xmlXPathContextPtr ctxt, int create)
- {
- virNodeDeviceDefPtr def;
- virNodeDevCapsDefPtr *next_cap;
-@@ -931,7 +1034,12 @@ virNodeDeviceDefParseXML(virConnectPtr conn, xmlXPathContextPtr ctxt)
- }
-
- /* Extract device name */
-- def->name = virXPathString("string(./name[1])", ctxt);
-+ if (create == EXISTING_DEVICE) {
-+ def->name = virXPathString("string(./name[1])", ctxt);
-+ } else {
-+ def->name = strdup("new device");
-+ }
-+
- if (!def->name) {
- virNodeDeviceReportError(conn, VIR_ERR_NO_NAME, NULL);
- goto error;
-@@ -951,7 +1059,7 @@ virNodeDeviceDefParseXML(virConnectPtr conn, xmlXPathContextPtr ctxt)
-
- next_cap = &def->caps;
- for (i = 0 ; i < n ; i++) {
-- *next_cap = virNodeDevCapsDefParseXML(conn, ctxt, def, nodes[i]);
-+ *next_cap = virNodeDevCapsDefParseXML(conn, ctxt, def, nodes[i], create);
- if (!*next_cap) {
- VIR_FREE(nodes);
- goto error;
-@@ -969,7 +1077,7 @@ virNodeDeviceDefParseXML(virConnectPtr conn, xmlXPathContextPtr ctxt)
- }
-
- static virNodeDeviceDefPtr
--virNodeDeviceDefParseNode(virConnectPtr conn, xmlDocPtr xml, xmlNodePtr root)
-+virNodeDeviceDefParseNode(virConnectPtr conn, xmlDocPtr xml, xmlNodePtr root, int create)
- {
- xmlXPathContextPtr ctxt = NULL;
- virNodeDeviceDefPtr def = NULL;
-@@ -987,7 +1095,7 @@ virNodeDeviceDefParseNode(virConnectPtr conn, xmlDocPtr xml, xmlNodePtr root)
- }
-
- ctxt->node = root;
-- def = virNodeDeviceDefParseXML(conn, ctxt);
-+ def = virNodeDeviceDefParseXML(conn, ctxt, create);
-
- cleanup:
- xmlXPathFreeContext(ctxt);
-@@ -1015,7 +1123,7 @@ catchXMLError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
- }
-
- virNodeDeviceDefPtr
--virNodeDeviceDefParseString(virConnectPtr conn, const char *str)
-+virNodeDeviceDefParseString(virConnectPtr conn, const char *str, int create)
- {
- xmlParserCtxtPtr pctxt;
- xmlDocPtr xml = NULL;
-@@ -1046,7 +1154,7 @@ virNodeDeviceDefParseString(virConnectPtr conn, const char *str)
- goto cleanup;
- }
-
-- def = virNodeDeviceDefParseNode(conn, xml, root);
-+ def = virNodeDeviceDefParseNode(conn, xml, root, create);
-
- cleanup:
- xmlFreeParserCtxt(pctxt);
-diff --git a/src/node_device_conf.h b/src/node_device_conf.h
-index 26e5558..62b4e71 100644
---- a/src/node_device_conf.h
-+++ b/src/node_device_conf.h
-@@ -28,6 +28,9 @@
- #include "util.h"
- #include "threads.h"
-
-+#define CREATE_DEVICE 1
-+#define EXISTING_DEVICE 0
-+
- enum virNodeDevCapType {
- /* Keep in sync with VIR_ENUM_IMPL in node_device_conf.c */
- VIR_NODE_DEV_CAP_SYSTEM, /* System capability */
-@@ -48,8 +51,16 @@ enum virNodeDevNetCapType {
- VIR_NODE_DEV_CAP_NET_LAST
- };
-
-+enum virNodeDevHBACapType {
-+ /* Keep in sync with VIR_ENUM_IMPL in node_device_conf.c */
-+ VIR_NODE_DEV_CAP_HBA_FC_HOST, /* fibre channel HBA */
-+ VIR_NODE_DEV_CAP_HBA_VPORT_OPS, /* capable of vport operations */
-+ VIR_NODE_DEV_CAP_HBA_LAST
-+};
-+
- VIR_ENUM_DECL(virNodeDevCap)
- VIR_ENUM_DECL(virNodeDevNetCap)
-+VIR_ENUM_DECL(virNodeDevHBACap)
-
- enum virNodeDevStorageCapFlags {
- VIR_NODE_DEV_CAP_STORAGE_REMOVABLE = (1 << 0),
-@@ -57,6 +68,11 @@ enum virNodeDevStorageCapFlags {
- VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE = (1 << 2),
- };
-
-+enum virNodeDevScsiHostCapFlags {
-+ VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST = (1 << 0),
-+ VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS = (1 << 1),
-+};
-+
- typedef struct _virNodeDevCapsDef virNodeDevCapsDef;
- typedef virNodeDevCapsDef *virNodeDevCapsDefPtr;
- struct _virNodeDevCapsDef {
-@@ -108,6 +124,9 @@ struct _virNodeDevCapsDef {
- } net;
- struct {
- unsigned host;
-+ char *wwnn;
-+ char *wwpn;
-+ unsigned flags;
- } scsi_host;
- struct {
- unsigned host;
-@@ -185,7 +204,8 @@ char *virNodeDeviceDefFormat(virConnectPtr conn,
- const virNodeDeviceDefPtr def);
-
- virNodeDeviceDefPtr virNodeDeviceDefParseString(virConnectPtr conn,
-- const char *str);
-+ const char *str,
-+ int create);
-
- void virNodeDeviceDefFree(virNodeDeviceDefPtr def);
-
-diff --git a/src/node_device_hal.c b/src/node_device_hal.c
-index b214f60..5927ba1 100644
---- a/src/node_device_hal.c
-+++ b/src/node_device_hal.c
-@@ -28,6 +28,7 @@
- #include <libhal.h>
-
- #include "node_device_conf.h"
-+#include "node_device_hal.h"
- #include "virterror_internal.h"
- #include "driver.h"
- #include "datatypes.h"
-@@ -37,6 +38,8 @@
- #include "logging.h"
- #include "node_device.h"
-
-+#define VIR_FROM_THIS VIR_FROM_NODEDEV
-+
- /*
- * Host device enumeration (HAL implementation)
- */
-@@ -215,6 +218,8 @@ static int gather_scsi_host_cap(LibHalContext *ctx, const char *udi,
- union _virNodeDevCapData *d)
- {
- (void)get_int_prop(ctx, udi, "scsi_host.host", (int *)&d->scsi_host.host);
-+ (void)check_fc_host(d);
-+ (void)check_vport_capable(d);
- return 0;
- }
-
-diff --git a/src/node_device_hal.h b/src/node_device_hal.h
-new file mode 100644
-index 0000000..0b4a2ef
---- /dev/null
-+++ b/src/node_device_hal.h
-@@ -0,0 +1,40 @@
-+/*
-+ * node_device_hal.h: node device enumeration - HAL-based implementation
-+ *
-+ * Copyright (C) 2009 Red Hat, Inc.
-+ *
-+ * This library is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ *
-+ */
-+
-+#ifndef __VIR_NODE_DEVICE_HAL_H__
-+#define __VIR_NODE_DEVICE_HAL_H__
-+
-+#ifdef __linux__
-+
-+#define check_fc_host(d) check_fc_host_linux(d)
-+int check_fc_host_linux(union _virNodeDevCapData *d);
-+
-+#define check_vport_capable(d) check_vport_capable_linux(d)
-+int check_vport_capable_linux(union _virNodeDevCapData *d);
-+
-+#else /* __linux__ */
-+
-+#define check_fc_host(d)
-+#define check_vport_capable(d)
-+
-+#endif /* __linux__ */
-+
-+#endif /* __VIR_NODE_DEVICE_HAL_H__ */
-diff --git a/src/node_device_hal_linux.c b/src/node_device_hal_linux.c
-new file mode 100644
-index 0000000..1deb6d2
---- /dev/null
-+++ b/src/node_device_hal_linux.c
-@@ -0,0 +1,170 @@
-+/*
-+ * node_device_hal_linuc.c: Linux specific code to gather device data
-+ * not available through HAL.
-+ *
-+ * Copyright (C) 2009 Red Hat, Inc.
-+ *
-+ * This library is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ *
-+ */
-+
-+#include <config.h>
-+
-+#include <fcntl.h>
-+
-+#include "node_device.h"
-+#include "node_device_hal.h"
-+#include "virterror_internal.h"
-+#include "memory.h"
-+#include "logging.h"
-+
-+#define VIR_FROM_THIS VIR_FROM_NODEDEV
-+
-+#ifdef __linux__
-+
-+int check_fc_host_linux(union _virNodeDevCapData *d)
-+{
-+ char *sysfs_path = NULL;
-+ char *wwnn_path = NULL;
-+ char *wwpn_path = NULL;
-+ char *p = NULL;
-+ int fd = -1;
-+ char buf[64];
-+ struct stat st;
-+
-+ VIR_DEBUG("Checking if host%d is an FC HBA", d->scsi_host.host);
-+
-+ if (virAsprintf(&sysfs_path, "%s/host%d",
-+ LINUX_SYSFS_FC_HOST_PREFIX,
-+ d->scsi_host.host) < 0) {
-+ virReportOOMError();
-+ goto out;
-+ }
-+
-+ if (stat(sysfs_path, &st) != 0) {
-+ /* Not an FC HBA */
-+ goto out;
-+ }
-+
-+ d->scsi_host.flags |= VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST;
-+
-+ if (virAsprintf(&wwnn_path, "%s/node_name",
-+ sysfs_path) < 0) {
-+ virReportOOMError();
-+ goto out;
-+ }
-+
-+ if ((fd = open(wwnn_path, O_RDONLY)) < 0) {
-+ goto out;
-+ }
-+
-+ memset(buf, 0, sizeof(buf));
-+ if (saferead(fd, buf, sizeof(buf)) < 0) {
-+ goto out;
-+ }
-+
-+ close(fd);
-+ fd = -1;
-+
-+ p = strstr(buf, "0x");
-+ if (p != NULL) {
-+ p += strlen("0x");
-+ } else {
-+ p = buf;
-+ }
-+
-+ d->scsi_host.wwnn = strndup(p, sizeof(buf));
-+ if (d->scsi_host.wwnn == NULL) {
-+ virReportOOMError();
-+ goto out;
-+ }
-+
-+ p = strchr(d->scsi_host.wwnn, '\n');
-+ if (p != NULL) {
-+ *p = '\0';
-+ }
-+
-+ if (virAsprintf(&wwpn_path, "%s/port_name",
-+ sysfs_path) < 0) {
-+ virReportOOMError();
-+ goto out;
-+ }
-+
-+ if ((fd = open(wwpn_path, O_RDONLY)) < 0) {
-+ goto out;
-+ }
-+
-+ memset(buf, 0, sizeof(buf));
-+ if (saferead(fd, buf, sizeof(buf)) < 0) {
-+ goto out;
-+ }
-+
-+ close(fd);
-+ fd = -1;
-+
-+ p = strstr(buf, "0x");
-+ if (p != NULL) {
-+ p += strlen("0x");
-+ } else {
-+ p = buf;
-+ }
-+
-+ d->scsi_host.wwpn = strndup(p, sizeof(buf));
-+ if (d->scsi_host.wwpn == NULL) {
-+ virReportOOMError();
-+ goto out;
-+ }
-+
-+ p = strchr(d->scsi_host.wwpn, '\n');
-+ if (p != NULL) {
-+ *p = '\0';
-+ }
-+
-+out:
-+ if (fd != -1) {
-+ close(fd);
-+ }
-+ VIR_FREE(sysfs_path);
-+ VIR_FREE(wwnn_path);
-+ VIR_FREE(wwpn_path);
-+ return 0;
-+}
-+
-+
-+int check_vport_capable_linux(union _virNodeDevCapData *d)
-+{
-+ char *sysfs_path = NULL;
-+ struct stat st;
-+
-+ if (virAsprintf(&sysfs_path, "%s/host%d/vport_create",
-+ LINUX_SYSFS_FC_HOST_PREFIX,
-+ d->scsi_host.host) < 0) {
-+ virReportOOMError();
-+ goto out;
-+ }
-+
-+ if (stat(sysfs_path, &st) != 0) {
-+ /* Not a vport capable HBA */
-+ goto out;
-+ }
-+
-+ d->scsi_host.flags |= VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS;
-+
-+out:
-+ VIR_FREE(sysfs_path);
-+ return 0;
-+}
-+
-+#endif /* __linux__ */
-diff --git a/src/qemu_driver.c b/src/qemu_driver.c
-index bd60b29..057e97b 100644
---- a/src/qemu_driver.c
-+++ b/src/qemu_driver.c
-@@ -5089,7 +5089,7 @@ qemudNodeDeviceGetPciInfo (virNodeDevicePtr dev,
- if (!xml)
- goto out;
-
-- def = virNodeDeviceDefParseString(dev->conn, xml);
-+ def = virNodeDeviceDefParseString(dev->conn, xml, EXISTING_DEVICE);
- if (!def)
- goto out;
-
-diff --git a/src/storage_backend.c b/src/storage_backend.c
-index b154140..74759cf 100644
---- a/src/storage_backend.c
-+++ b/src/storage_backend.c
-@@ -46,6 +46,7 @@
- #include "virterror_internal.h"
- #include "util.h"
- #include "memory.h"
-+#include "node_device.h"
-
- #include "storage_backend.h"
-
-@@ -245,30 +246,11 @@ virStorageBackendUpdateVolTargetInfoFD(virConnectPtr conn,
- return 0;
- }
-
--#if defined(UDEVADM) || defined(UDEVSETTLE)
- void virStorageBackendWaitForDevices(virConnectPtr conn)
- {
--#ifdef UDEVADM
-- const char *const settleprog[] = { UDEVADM, "settle", NULL };
--#else
-- const char *const settleprog[] = { UDEVSETTLE, NULL };
--#endif
-- int exitstatus;
--
-- if (access(settleprog[0], X_OK) != 0)
-- return;
--
-- /*
-- * NOTE: we ignore errors here; this is just to make sure that any device
-- * nodes that are being created finish before we try to scan them.
-- * If this fails for any reason, we still have the backup of polling for
-- * 5 seconds for device nodes.
-- */
-- virRun(settleprog, &exitstatus);
-+ virNodeDeviceWaitForDevices(conn);
-+ return;
- }
--#else
--void virStorageBackendWaitForDevices(virConnectPtr conn ATTRIBUTE_UNUSED) {}
--#endif
-
- /*
- * Given a volume path directly in /dev/XXX, iterate over the
-diff --git a/src/xen_unified.c b/src/xen_unified.c
-index e708980..8da4e23 100644
---- a/src/xen_unified.c
-+++ b/src/xen_unified.c
-@@ -1439,7 +1439,7 @@ xenUnifiedNodeDeviceGetPciInfo (virNodeDevicePtr dev,
- if (!xml)
- goto out;
-
-- def = virNodeDeviceDefParseString(dev->conn, xml);
-+ def = virNodeDeviceDefParseString(dev->conn, xml, EXISTING_DEVICE);
- if (!def)
- goto out;
-
-diff --git a/tests/nodedevxml2xmltest.c b/tests/nodedevxml2xmltest.c
-index 29cdb9e..7621212 100644
---- a/tests/nodedevxml2xmltest.c
-+++ b/tests/nodedevxml2xmltest.c
-@@ -29,7 +29,7 @@ static int testCompareXMLToXMLFiles(const char *xml) {
- if (virtTestLoadFile(xml, &xmlPtr, MAX_FILE) < 0)
- goto fail;
-
-- if (!(dev = virNodeDeviceDefParseString(NULL, xmlData)))
-+ if (!(dev = virNodeDeviceDefParseString(NULL, xmlData, EXISTING_DEVICE)))
- goto fail;
-
- if (!(actual = virNodeDeviceDefFormat(NULL, dev)))
---
-1.6.0.6
diff --git a/docs/api_extension/0008-Step-8-of-15-support-new-xml.patch b/docs/api_extension/0008-Step-8-of-15-support-new-xml.patch
new file mode 100644
index 0000000000..821cfa55ce
--- /dev/null
+++ b/docs/api_extension/0008-Step-8-of-15-support-new-xml.patch
@@ -0,0 +1,519 @@
+From 4617eedfaeee2b187a1f14691d25746ba3ff31b6 Mon Sep 17 00:00:00 2001
+From: Eric Blake <eblake@redhat.com>
+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) {
+- virBufferVSprintf(&buf, " <vcpu>%lu</vcpu>\n", def->vcpus);
+- } else {
++ virBufferAddLit(&buf, " <vcpu");
++ if (!allones) {
+ char *cpumask = NULL;
+ if ((cpumask =
+ virDomainCpuSetFormat(def->cpumask, def->cpumasklen)) == NULL)
+ goto cleanup;
+- virBufferVSprintf(&buf, " <vcpu cpuset='%s'>%lu</vcpu>\n",
+- cpumask, def->vcpus);
++ virBufferVSprintf(&buf, " cpuset='%s'", cpumask);
+ VIR_FREE(cpumask);
+ }
++ if (def->vcpus != def->maxvcpus)
++ virBufferVSprintf(&buf, " current='%u'", def->vcpus);
++ virBufferVSprintf(&buf, ">%u</vcpu>\n", def->maxvcpus);
+
+ if (def->os.bootloader) {
+ virBufferEscapeString(&buf, " <bootloader>%s</bootloader>\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 = <value> <=> uuid.bios = "<value>"
+ def->name = <value> <=> displayName = "<value>"
+ def->mem.max_balloon = <value kilobyte> <=> memsize = "<value megabyte>" # must be a multiple of 4, defaults to 32
+ def->mem.cur_balloon = <value kilobyte> <=> sched.mem.max = "<value megabyte>" # defaults to "unlimited" -> def->mem.cur_balloon = def->mem.max_balloon
+-def->vcpus = <value> <=> numvcpus = "<value>" # must be 1 or a multiple of 2, defaults to 1
++def->maxvcpus = <value> <=> numvcpus = "<value>" # must be 1 or a multiple of 2, defaults to 1
+ def->cpumask = <uint list> <=> sched.cpu.affinity = "<uint list>"
+
+
+@@ -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;
+ }
+
+- virBufferVSprintf(&buffer, "numvcpus = \"%d\"\n", (int)def->vcpus);
++ virBufferVSprintf(&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;
+- virBufferVSprintf(&buf,"#OpenNebula Template automatically generated by libvirt\nNAME = %s\nCPU = %ld\nMEMORY = %ld\n",
++ virBufferVSprintf(&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;
+
+- virBufferVSprintf(&buf, "%lu", def->vcpus);
++ virBufferVSprintf(&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,
+ virBufferVSprintf(&buf, ",threads=%u", def->cpu->threads);
+ }
+ else {
+- virBufferVSprintf(&buf, ",sockets=%lu", def->vcpus);
++ virBufferVSprintf(&buf, ",sockets=%u", def->maxvcpus);
+ virBufferVSprintf(&buf, ",cores=%u", 1);
+ virBufferVSprintf(&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,
+ virBufferVSprintf(&buf, "(name '%s')", def->name);
+ virBufferVSprintf(&buf, "(memory %lu)(maxmem %lu)",
+ def->mem.cur_balloon/1024, def->mem.max_balloon/1024);
+- virBufferVSprintf(&buf, "(vcpus %lu)", def->vcpus);
++ virBufferVSprintf(&buf, "(vcpus %u)", def->maxvcpus);
+
+ if (def->cpumask) {
+ char *ranges = virDomainCpuSetFormat(def->cpumask, def->cpumasklen);
+@@ -5761,7 +5762,7 @@ xenDaemonFormatSxpr(virConnectPtr conn,
+ else
+ virBufferVSprintf(&buf, "(kernel '%s')", def->os.loader);
+
+- virBufferVSprintf(&buf, "(vcpus %lu)", def->vcpus);
++ virBufferVSprintf(&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/docs/api_extension/0008-Step-8-of-8-Add-virsh-support.patch b/docs/api_extension/0008-Step-8-of-8-Add-virsh-support.patch
deleted file mode 100644
index 7d45d7a3bb..0000000000
--- a/docs/api_extension/0008-Step-8-of-8-Add-virsh-support.patch
+++ /dev/null
@@ -1,131 +0,0 @@
-From 193cc4abbb6c2fc5557d3699f86ff0103d5a21ef Mon Sep 17 00:00:00 2001
-From: David Allan <dallan@redhat.com>
-Date: Tue, 19 May 2009 16:47:31 -0400
-Subject: [PATCH 8/8] Step 8 of 8 Add virsh support
-
----
- src/virsh.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- 1 files changed, 103 insertions(+), 0 deletions(-)
-
-diff --git a/src/virsh.c b/src/virsh.c
-index cb32ede..ab2a2b7 100644
---- a/src/virsh.c
-+++ b/src/virsh.c
-@@ -2962,6 +2962,106 @@ cmdPoolCreate(vshControl *ctl, const vshCmd *cmd)
-
-
- /*
-+ * "nodedev-create" command
-+ */
-+static const vshCmdInfo info_node_device_create[] = {
-+ {"help", N_("create a device defined by an XML file on the node")},
-+ {"desc", N_("Create a device on the node. Note that this "
-+ "command creates devices on the physical host "
-+ "that can then be assigned to a virtual machine.")},
-+ {NULL, NULL}
-+};
-+
-+static const vshCmdOptDef opts_node_device_create[] = {
-+ {"file", VSH_OT_DATA, VSH_OFLAG_REQ,
-+ N_("file containing an XML description of the device")},
-+ {NULL, 0, 0, NULL}
-+};
-+
-+static int
-+cmdNodeDeviceCreate(vshControl *ctl, const vshCmd *cmd)
-+{
-+ virNodeDevicePtr dev = NULL;
-+ char *from;
-+ int found = 0;
-+ int ret = TRUE;
-+ char *buffer;
-+
-+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
-+ return FALSE;
-+
-+ from = vshCommandOptString(cmd, "file", &found);
-+ if (!found) {
-+ return FALSE;
-+ }
-+
-+ if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) {
-+ return FALSE;
-+ }
-+
-+ dev = virNodeDeviceCreateXML(ctl->conn, buffer, 0);
-+ free (buffer);
-+
-+ if (dev != NULL) {
-+ vshPrint(ctl, _("Node device %s created from %s\n"),
-+ virNodeDeviceGetName(dev), from);
-+ } else {
-+ vshError(ctl, FALSE, _("Failed to create node device from %s"), from);
-+ ret = FALSE;
-+ }
-+
-+ return ret;
-+}
-+
-+
-+/*
-+ * "nodedev-destroy" command
-+ */
-+static const vshCmdInfo info_node_device_destroy[] = {
-+ {"help", N_("destroy a device on the node")},
-+ {"desc", N_("Destroy a device on the node. Note that this "
-+ "command destroys devices on the physical host")},
-+ {NULL, NULL}
-+};
-+
-+static const vshCmdOptDef opts_node_device_destroy[] = {
-+ {"name", VSH_OT_DATA, VSH_OFLAG_REQ,
-+ N_("name of the device to be destroyed")},
-+ {NULL, 0, 0, NULL}
-+};
-+
-+static int
-+cmdNodeDeviceDestroy(vshControl *ctl, const vshCmd *cmd)
-+{
-+ virNodeDevicePtr dev = NULL;
-+ int ret = TRUE;
-+ int found = 0;
-+ char *name;
-+
-+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) {
-+ return FALSE;
-+ }
-+
-+ name = vshCommandOptString(cmd, "name", &found);
-+ if (!found) {
-+ return FALSE;
-+ }
-+
-+ dev = virNodeDeviceLookupByName(ctl->conn, name);
-+
-+ if (virNodeDeviceDestroy(dev) == 0) {
-+ vshPrint(ctl, _("Destroyed node device '%s'\n"), name);
-+ } else {
-+ vshError(ctl, FALSE, _("Failed to destroy node device '%s'"), name);
-+ ret = FALSE;
-+ }
-+
-+ virNodeDeviceFree(dev);
-+ return ret;
-+}
-+
-+
-+/*
- * XML Building helper for pool-define-as and pool-create-as
- */
- static const vshCmdOptDef opts_pool_X_as[] = {
-@@ -5895,6 +5996,8 @@ static const vshCmdDef commands[] = {
- {"nodedev-dettach", cmdNodeDeviceDettach, opts_node_device_dettach, info_node_device_dettach},
- {"nodedev-reattach", cmdNodeDeviceReAttach, opts_node_device_reattach, info_node_device_reattach},
- {"nodedev-reset", cmdNodeDeviceReset, opts_node_device_reset, info_node_device_reset},
-+ {"nodedev-create", cmdNodeDeviceCreate, opts_node_device_create, info_node_device_create},
-+ {"nodedev-destroy", cmdNodeDeviceDestroy, opts_node_device_destroy, info_node_device_destroy},
-
- {"pool-autostart", cmdPoolAutostart, opts_pool_autostart, info_pool_autostart},
- {"pool-build", cmdPoolBuild, opts_pool_build, info_pool_build},
---
-1.6.0.6
diff --git a/docs/api_extension/0009-Step-9-of-15-support-all-flags-in-test-driver.patch b/docs/api_extension/0009-Step-9-of-15-support-all-flags-in-test-driver.patch
new file mode 100644
index 0000000000..1aa3984502
--- /dev/null
+++ b/docs/api_extension/0009-Step-9-of-15-support-all-flags-in-test-driver.patch
@@ -0,0 +1,197 @@
+From 6c9e6b956453d0f0c4ff542ef8a184d663a39266 Mon Sep 17 00:00:00 2001
+From: Eric Blake <eblake@redhat.com>
+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/docs/api_extension/0010-Step-10-of-15-improve-vcpu-support-in-qemu-command-line.patch b/docs/api_extension/0010-Step-10-of-15-improve-vcpu-support-in-qemu-command-line.patch
new file mode 100644
index 0000000000..e0829918ad
--- /dev/null
+++ b/docs/api_extension/0010-Step-10-of-15-improve-vcpu-support-in-qemu-command-line.patch
@@ -0,0 +1,122 @@
+From d67c189e80e6aef7adf13e5763365555cfc1a02a Mon Sep 17 00:00:00 2001
+From: Eric Blake <eblake@redhat.com>
+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,
+ virBufferVSprintf(&buf, "%u", def->vcpus);
+
+ if ((qemuCmdFlags & QEMUD_CMD_FLAG_SMP_TOPOLOGY)) {
++ if (def->vcpus != def->maxvcpus)
++ virBufferVSprintf(&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,
+ virBufferVSprintf(&buf, ",cores=%u", 1);
+ virBufferVSprintf(&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/docs/api_extension/0011-Step-11-of-15-complete-vcpu-support-in-qemu-driver.patch b/docs/api_extension/0011-Step-11-of-15-complete-vcpu-support-in-qemu-driver.patch
new file mode 100644
index 0000000000..251008fd01
--- /dev/null
+++ b/docs/api_extension/0011-Step-11-of-15-complete-vcpu-support-in-qemu-driver.patch
@@ -0,0 +1,169 @@
+From 28a3605906385cba43df77051dc26e865f237b09 Mon Sep 17 00:00:00 2001
+From: Eric Blake <eblake@redhat.com>
+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/docs/api_extension/0012-Step-12-of-15-improve-vcpu-support-in-xen-command-line.patch b/docs/api_extension/0012-Step-12-of-15-improve-vcpu-support-in-xen-command-line.patch
new file mode 100644
index 0000000000..f8764b326f
--- /dev/null
+++ b/docs/api_extension/0012-Step-12-of-15-improve-vcpu-support-in-xen-command-line.patch
@@ -0,0 +1,294 @@
+From 0fab10e5ed971ab4f960a53e9640b0672f4b8ac3 Mon Sep 17 00:00:00 2001
+From: Eric Blake <eblake@redhat.com>
+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 <xen/dom0_ops.h>
+@@ -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,
+ virBufferVSprintf(&buf, "(memory %lu)(maxmem %lu)",
+ def->mem.cur_balloon/1024, def->mem.max_balloon/1024);
+ virBufferVSprintf(&buf, "(vcpus %u)", def->maxvcpus);
++ /* Computing the vcpu_avail bitmask works because MAX_VIRT_CPUS is 32. */
++ if (def->vcpus < def->maxvcpus)
++ virBufferVSprintf(&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,
+ virBufferVSprintf(&buf, "(kernel '%s')", def->os.loader);
+
+ virBufferVSprintf(&buf, "(vcpus %u)", def->maxvcpus);
++ if (def->vcpus < def->maxvcpus)
++ virBufferVSprintf(&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 @@
++<domain type='xen' id='6'>
++ <name>pvtest</name>
++ <uuid>596a5d21-71f4-8fb2-e068-e2386a5c413e</uuid>
++ <memory>430080</memory>
++ <currentMemory>430080</currentMemory>
++ <vcpu current='2'>4</vcpu>
++ <os>
++ <type>linux</type>
++ <kernel>/var/lib/xen/vmlinuz.2Dn2YT</kernel>
++ <initrd>/var/lib/xen/initrd.img.0u-Vhq</initrd>
++ <cmdline> method=http://download.fedora.devel.redhat.com/pub/fedora/linux/core/test/5.91/x86_64/os </cmdline>
++ </os>
++ <clock offset='utc'/>
++ <on_poweroff>destroy</on_poweroff>
++ <on_reboot>destroy</on_reboot>
++ <on_crash>destroy</on_crash>
++ <devices>
++ <disk type='file' device='disk'>
++ <driver name='file'/>
++ <source file='/root/some.img'/>
++ <target dev='xvda' bus='xen'/>
++ </disk>
++ <console type='pty'>
++ <target type='xen' port='0'/>
++ </console>
++ </devices>
++</domain>
+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 @@
++<domain type='xen'>
++ <name>XenGuest1</name>
++ <uuid>c7a5fdb0-cdaf-9455-926a-d65c16db1809</uuid>
++ <memory>592896</memory>
++ <currentMemory>403456</currentMemory>
++ <vcpu current='2'>4</vcpu>
++ <bootloader>/usr/bin/pygrub</bootloader>
++ <os>
++ <type arch='i686' machine='xenpv'>linux</type>
++ </os>
++ <clock offset='utc'/>
++ <on_poweroff>destroy</on_poweroff>
++ <on_reboot>restart</on_reboot>
++ <on_crash>restart</on_crash>
++ <devices>
++ <disk type='block' device='disk'>
++ <driver name='phy'/>
++ <source dev='/dev/HostVG/XenGuest1'/>
++ <target dev='xvda' bus='xen'/>
++ </disk>
++ <interface type='bridge'>
++ <mac address='00:16:3e:66:94:9c'/>
++ <source bridge='br0'/>
++ <script path='vif-bridge'/>
++ </interface>
++ <console type='pty'>
++ <target type='xen' port='0'/>
++ </console>
++ <input type='mouse' bus='xen'/>
++ <graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1' passwd='123poi'/>
++ </devices>
++</domain>
+diff --git a/tests/xmconfigtest.c b/tests/xmconfigtest.c
+index 221b322..ea00747 100644
+--- a/tests/xmconfigtest.c
++++ b/tests/xmconfigtest.c
+@@ -210,6 +210,7 @@ mymain(int argc, char **argv)
+ DO_TEST("paravirt-new-pvfb-vncdisplay", 3);
+ DO_TEST("paravirt-net-e1000", 3);
+ DO_TEST("paravirt-net-vifname", 3);
++ DO_TEST("paravirt-vcpu", 2);
+ DO_TEST("fullvirt-old-cdrom", 1);
+ DO_TEST("fullvirt-new-cdrom", 2);
+ DO_TEST("fullvirt-utc", 2);
+diff --git a/tests/xml2sexprdata/xml2sexpr-pv-vcpus.sexpr b/tests/xml2sexprdata/xml2sexpr-pv-vcpus.sexpr
+new file mode 100644
+index 0000000..e886545
+--- /dev/null
++++ b/tests/xml2sexprdata/xml2sexpr-pv-vcpus.sexpr
+@@ -0,0 +1 @@
++(vm (name 'pvtest')(memory 420)(maxmem 420)(vcpus 4)(vcpu_avail 3)(uuid '596a5d21-71f4-8fb2-e068-e2386a5c413e')(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'))))
+\ No newline at end of file
+diff --git a/tests/xml2sexprtest.c b/tests/xml2sexprtest.c
+index 77cf760..9cf8d39 100644
+--- a/tests/xml2sexprtest.c
++++ b/tests/xml2sexprtest.c
+@@ -118,6 +118,7 @@ mymain(int argc, char **argv)
+ DO_TEST("pv-vfb-new", "pv-vfb-new", "pvtest", 3);
+ DO_TEST("pv-vfb-new-auto", "pv-vfb-new-auto", "pvtest", 3);
+ DO_TEST("pv-bootloader", "pv-bootloader", "pvtest", 1);
++ DO_TEST("pv-vcpus", "pv-vcpus", "pvtest", 1);
+
+ DO_TEST("disk-file", "disk-file", "pvtest", 2);
+ DO_TEST("disk-block", "disk-block", "pvtest", 2);
+--
+1.7.2.3
+
diff --git a/docs/api_extension/0013-Step-13-of-15-improve-support-for-getting-xen-vcpu-counts.patch b/docs/api_extension/0013-Step-13-of-15-improve-support-for-getting-xen-vcpu-counts.patch
new file mode 100644
index 0000000000..047bc7bf25
--- /dev/null
+++ b/docs/api_extension/0013-Step-13-of-15-improve-support-for-getting-xen-vcpu-counts.patch
@@ -0,0 +1,216 @@
+From 290ea33111be7bdf1f1381b90de33eb0e67c1a15 Mon Sep 17 00:00:00 2001
+From: Eric Blake <eblake@redhat.com>
+Date: Wed, 6 Oct 2010 17:54:41 -0600
+Subject: [PATCH 13/15] vcpu: improve support for getting xen vcpu counts
+
+* src/xen/xen_driver.c (xenUnifiedDomainGetVcpusFlags): Support
+more flags.
+* src/xen/xend_internal.h (xenDaemonDomainGetVcpusFlags): New
+prototype.
+* src/xen/xm_internal.h (xenXMDomainGetVcpusFlags): Likewise.
+* src/xen/xend_internal.c (virDomainGetVcpusFlags): New function.
+* src/xen/xm_internal.c (xenXMDomainGetVcpusFlags): Likewise.
+---
+ src/xen/xen_driver.c | 31 +++++++++++++++++++--------
+ src/xen/xend_internal.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++
+ src/xen/xend_internal.h | 2 +
+ src/xen/xm_internal.c | 47 ++++++++++++++++++++++++++++++++++++++++++
+ src/xen/xm_internal.h | 1 +
+ 5 files changed, 124 insertions(+), 9 deletions(-)
+
+diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c
+index d6c9c57..fe2ff86 100644
+--- a/src/xen/xen_driver.c
++++ b/src/xen/xen_driver.c
+@@ -1142,20 +1142,33 @@ static int
+ xenUnifiedDomainGetVcpusFlags (virDomainPtr dom, unsigned int flags)
+ {
+ GET_PRIVATE(dom->conn);
+- int i, ret;
++ int ret;
+
+- if (flags != (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
+- xenUnifiedError(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)) {
++ xenUnifiedError(VIR_ERR_INVALID_ARG,
++ _("invalid flag combination: (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);
+- if (ret != 0) return ret;
+- }
++ if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
++ ret = xenDaemonDomainGetVcpusFlags(dom, flags);
++ if (ret != -2)
++ return ret;
++ }
++ if (priv->opened[XEN_UNIFIED_XM_OFFSET]) {
++ ret = xenXMDomainGetVcpusFlags(dom, flags);
++ if (ret != -2)
++ return ret;
++ }
++ if (flags == (VIR_DOMAIN_VCPU_CONFIG | VIR_DOMAIN_VCPU_MAXIMUM))
++ return xenHypervisorGetVcpuMax(dom);
+
++ xenUnifiedError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return -1;
+ }
+
+diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c
+index dfc6415..3642296 100644
+--- a/src/xen/xend_internal.c
++++ b/src/xen/xend_internal.c
+@@ -3620,6 +3620,58 @@ xenDaemonDomainPinVcpu(virDomainPtr domain, unsigned int vcpu,
+ }
+
+ /**
++ * xenDaemonDomainGetVcpusFlags:
++ * @domain: pointer to domain object
++ * @flags: bitwise-ORd from virDomainVcpuFlags
++ *
++ * Extract information about virtual CPUs of domain according to flags.
++ *
++ * Returns the number of vcpus on success, -1 if an error message was
++ * issued, and -2 if the unified driver should keep trying.
++
++ */
++int
++xenDaemonDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
++{
++ struct sexpr *root;
++ int ret;
++ xenUnifiedPrivatePtr priv;
++
++ if (domain == NULL || domain->conn == NULL || domain->name == NULL) {
++ virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
++ return -1;
++ }
++
++ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
++
++ /* If xendConfigVersion is 2, then we can only report _LIVE (and
++ * xm_internal reports _CONFIG). If it is 3, then _LIVE and
++ * _CONFIG are always in sync for a running system. */
++ if (domain->id < 0 && priv->xendConfigVersion < 3)
++ return -2;
++ if (domain->id < 0 && (flags & VIR_DOMAIN_VCPU_LIVE)) {
++ virXendError(VIR_ERR_OPERATION_INVALID, "%s",
++ _("domain not active"));
++ return -1;
++ }
++
++ root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
++ if (root == NULL)
++ return -1;
++
++ ret = sexpr_int(root, "domain/vcpus");
++ if (!(flags & VIR_DOMAIN_VCPU_MAXIMUM)) {
++ int vcpus = count_one_bits(sexpr_int(root, "domain/vcpu_avail"));
++ if (vcpus)
++ ret = MIN(vcpus, ret);
++ }
++ if (!ret)
++ ret = -2;
++ sexpr_free(root);
++ return ret;
++}
++
++/**
+ * virDomainGetVcpus:
+ * @domain: pointer to domain object, or NULL for Domain0
+ * @info: pointer to an array of virVcpuInfo structures (OUT)
+diff --git a/src/xen/xend_internal.h b/src/xen/xend_internal.h
+index c757716..923cebd 100644
+--- a/src/xen/xend_internal.h
++++ b/src/xen/xend_internal.h
+@@ -155,6 +155,8 @@ int xenDaemonDomainPinVcpu (virDomainPtr domain,
+ unsigned int vcpu,
+ unsigned char *cpumap,
+ int maplen);
++int xenDaemonDomainGetVcpusFlags (virDomainPtr domain,
++ unsigned int flags);
+ int xenDaemonDomainGetVcpus (virDomainPtr domain,
+ virVcpuInfoPtr info,
+ int maxinfo,
+diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c
+index f7121ab..4ea4245 100644
+--- a/src/xen/xm_internal.c
++++ b/src/xen/xm_internal.c
+@@ -1671,6 +1671,53 @@ cleanup:
+ }
+
+ /**
++ * xenXMDomainGetVcpusFlags:
++ * @domain: pointer to domain object
++ * @flags: bitwise-ORd from virDomainVcpuFlags
++ *
++ * Extract information about virtual CPUs of domain according to flags.
++ *
++ * Returns the number of vcpus on success, -1 if an error message was
++ * issued, and -2 if the unified driver should keep trying.
++ */
++int
++xenXMDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
++{
++ xenUnifiedPrivatePtr priv;
++ const char *filename;
++ xenXMConfCachePtr entry;
++ int ret = -2;
++
++ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
++ xenXMError(VIR_ERR_INVALID_ARG, __FUNCTION__);
++ return -1;
++ }
++
++ if (domain->id != -1)
++ return -2;
++ if (flags & VIR_DOMAIN_VCPU_LIVE) {
++ xenXMError(VIR_ERR_OPERATION_FAILED, "%s", _("domain not active"));
++ return -1;
++ }
++
++ priv = domain->conn->privateData;
++ xenUnifiedLock(priv);
++
++ if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
++ goto cleanup;
++
++ if (!(entry = virHashLookup(priv->configCache, filename)))
++ goto cleanup;
++
++ ret = ((flags & VIR_DOMAIN_VCPU_MAXIMUM) ? entry->def->maxvcpus
++ : entry->def->vcpus);
++
++cleanup:
++ xenUnifiedUnlock(priv);
++ return ret;
++}
++
++/**
+ * xenXMDomainPinVcpu:
+ * @domain: pointer to domain object
+ * @vcpu: virtual CPU number (reserved)
+diff --git a/src/xen/xm_internal.h b/src/xen/xm_internal.h
+index 3ad3456..3295fbd 100644
+--- a/src/xen/xm_internal.h
++++ b/src/xen/xm_internal.h
+@@ -45,6 +45,7 @@ int xenXMDomainSetMemory(virDomainPtr domain, unsigned long memory);
+ int xenXMDomainSetMaxMemory(virDomainPtr domain, unsigned long memory);
+ unsigned long xenXMDomainGetMaxMemory(virDomainPtr domain);
+ int xenXMDomainSetVcpus(virDomainPtr domain, unsigned int vcpus);
++int xenXMDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags);
+ int xenXMDomainPinVcpu(virDomainPtr domain, unsigned int vcpu,
+ unsigned char *cpumap, int maplen);
+ virDomainPtr xenXMDomainLookupByName(virConnectPtr conn, const char *domname);
+--
+1.7.2.3
+
diff --git a/docs/api_extension/0014-Step-14-of-15-improve-support-for-setting-xen-vcpu-counts.patch b/docs/api_extension/0014-Step-14-of-15-improve-support-for-setting-xen-vcpu-counts.patch
new file mode 100644
index 0000000000..76dc948b23
--- /dev/null
+++ b/docs/api_extension/0014-Step-14-of-15-improve-support-for-setting-xen-vcpu-counts.patch
@@ -0,0 +1,342 @@
+From e443a003129a172a7332f3cb6e40b3c39363ed5e Mon Sep 17 00:00:00 2001
+From: Eric Blake <eblake@redhat.com>
+Date: Thu, 14 Oct 2010 16:17:18 -0600
+Subject: [PATCH 14/15] vcpu: improve support for setting xen vcpu counts
+
+Tested with RHEL 5.6 (xendConfigVersion 2, where xend_internal
+controls live domains and xm_internal controls inactive domains).
+Hopefully this works with xendConfigVersion 3 (where xend_internal
+controls everything).
+
+* src/xen/xen_driver.c (xenUnifiedDomainSetVcpusFlags): Support
+more flags.
+(xenUnifiedGetMaxVcpus): Export.
+* src/xen/xm_internal.h (xenXMDomainSetVcpusFlags): New prototype.
+* src/xen/xend_internal.h (xenDaemonDomainSetVcpusFlags): Likewise.
+* src/xen/xen_driver.h (xenUnifiedGetMaxVcpus): Likewise.
+* src/xen/xm_internal.c (xenXMDomainSetVcpusFlags): New function.
+* src/xen/xend_internal.c (xenDaemonDomainSetVcpusFlags): Likewise.
+---
+ src/xen/xen_driver.c | 60 ++++++++++++++++++++++++---------
+ src/xen/xen_driver.h | 1 +
+ src/xen/xend_internal.c | 76 +++++++++++++++++++++++++++++++++++++++++++
+ src/xen/xend_internal.h | 3 ++
+ src/xen/xm_internal.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++
+ src/xen/xm_internal.h | 2 +
+ 6 files changed, 208 insertions(+), 17 deletions(-)
+
+diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c
+index fe2ff86..66e8518 100644
+--- a/src/xen/xen_driver.c
++++ b/src/xen/xen_driver.c
+@@ -508,7 +508,7 @@ xenUnifiedIsSecure(virConnectPtr conn)
+ return ret;
+ }
+
+-static int
++int
+ xenUnifiedGetMaxVcpus (virConnectPtr conn, const char *type)
+ {
+ GET_PRIVATE(conn);
+@@ -1073,36 +1073,62 @@ xenUnifiedDomainSetVcpusFlags (virDomainPtr dom, unsigned int nvcpus,
+ unsigned int flags)
+ {
+ GET_PRIVATE(dom->conn);
+- int i;
++ int ret;
++
++ virCheckFlags(VIR_DOMAIN_VCPU_LIVE |
++ VIR_DOMAIN_VCPU_CONFIG |
++ VIR_DOMAIN_VCPU_MAXIMUM, -1);
+
+- if (flags != VIR_DOMAIN_VCPU_LIVE) {
+- xenUnifiedError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"),
+- flags);
++ /* 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)) {
++ xenUnifiedError(VIR_ERR_INVALID_ARG,
++ _("invalid flag combination: (0x%x)"), flags);
++ return -1;
++ }
++ if (!nvcpus || (unsigned short) nvcpus != nvcpus) {
++ xenUnifiedError(VIR_ERR_INVALID_ARG,
++ _("argument out of range: %d"), nvcpus);
+ return -1;
+ }
+
+ /* Try non-hypervisor methods first, then hypervisor direct method
+ * as a last resort.
+ */
+- for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
+- if (i != XEN_UNIFIED_HYPERVISOR_OFFSET &&
+- priv->opened[i] &&
+- drivers[i]->domainSetVcpus &&
+- drivers[i]->domainSetVcpus (dom, nvcpus) == 0)
+- return 0;
+-
+- if (priv->opened[XEN_UNIFIED_HYPERVISOR_OFFSET] &&
+- drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainSetVcpus &&
+- drivers[XEN_UNIFIED_HYPERVISOR_OFFSET]->domainSetVcpus (dom, nvcpus) == 0)
+- return 0;
++ if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
++ ret = xenDaemonDomainSetVcpusFlags(dom, nvcpus, flags);
++ if (ret != -2)
++ return ret;
++ }
++ if (priv->opened[XEN_UNIFIED_XM_OFFSET]) {
++ ret = xenXMDomainSetVcpusFlags(dom, nvcpus, flags);
++ if (ret != -2)
++ return ret;
++ }
++ if (flags == VIR_DOMAIN_VCPU_LIVE)
++ return xenHypervisorSetVcpus(dom, nvcpus);
+
++ xenUnifiedError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return -1;
+ }
+
+ static int
+ xenUnifiedDomainSetVcpus (virDomainPtr dom, unsigned int nvcpus)
+ {
+- return xenUnifiedDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE);
++ unsigned int flags = VIR_DOMAIN_VCPU_LIVE;
++ xenUnifiedPrivatePtr priv;
++
++ /* Per the documented API, it is hypervisor-dependent whether this
++ * affects just _LIVE or _LIVE|_CONFIG; in xen's case, that
++ * depends on xendConfigVersion. */
++ if (dom) {
++ priv = dom->conn->privateData;
++ if (priv->xendConfigVersion >= 3)
++ flags |= VIR_DOMAIN_VCPU_CONFIG;
++ }
++ return xenUnifiedDomainSetVcpusFlags(dom, nvcpus, flags);
+ }
+
+ static int
+diff --git a/src/xen/xen_driver.h b/src/xen/xen_driver.h
+index 3e7c1d0..115a26a 100644
+--- a/src/xen/xen_driver.h
++++ b/src/xen/xen_driver.h
+@@ -220,6 +220,7 @@ int xenUnifiedRemoveDomainInfo(xenUnifiedDomainInfoListPtr info,
+ void xenUnifiedDomainEventDispatch (xenUnifiedPrivatePtr priv,
+ virDomainEventPtr event);
+ unsigned long xenUnifiedVersion(void);
++int xenUnifiedGetMaxVcpus(virConnectPtr conn, const char *type);
+
+ # ifndef PROXY
+ void xenUnifiedLock(xenUnifiedPrivatePtr priv);
+diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c
+index 3642296..55c2cc4 100644
+--- a/src/xen/xend_internal.c
++++ b/src/xen/xend_internal.c
+@@ -3535,6 +3535,82 @@ xenDaemonLookupByID(virConnectPtr conn, int id) {
+ }
+
+ /**
++ * xenDaemonDomainSetVcpusFlags:
++ * @domain: pointer to domain object
++ * @nvcpus: the new number of virtual CPUs for this domain
++ * @flags: bitwise-ORd from virDomainVcpuFlags
++ *
++ * Change virtual CPUs allocation of domain according to flags.
++ *
++ * Returns 0 on success, -1 if an error message was issued, and -2 if
++ * the unified driver should keep trying.
++ */
++int
++xenDaemonDomainSetVcpusFlags(virDomainPtr domain, unsigned int vcpus,
++ unsigned int flags)
++{
++ char buf[VIR_UUID_BUFLEN];
++ xenUnifiedPrivatePtr priv;
++ int max;
++
++ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
++ || (vcpus < 1)) {
++ virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
++ return (-1);
++ }
++
++ priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
++
++ if ((domain->id < 0 && priv->xendConfigVersion < 3) ||
++ (flags & VIR_DOMAIN_VCPU_MAXIMUM))
++ return -2;
++
++ /* With xendConfigVersion 2, only _LIVE is supported. With
++ * xendConfigVersion 3, only _LIVE|_CONFIG is supported for
++ * running domains, or _CONFIG for inactive domains. */
++ if (priv->xendConfigVersion < 3) {
++ if (flags & VIR_DOMAIN_VCPU_CONFIG) {
++ virXendError(VIR_ERR_OPERATION_INVALID, "%s",
++ _("Xend version does not support modifying "
++ "persistent config"));
++ return -1;
++ }
++ } else if (domain->id < 0) {
++ if (flags & VIR_DOMAIN_VCPU_LIVE) {
++ virXendError(VIR_ERR_OPERATION_INVALID, "%s",
++ _("domain not running"));
++ return -1;
++ }
++ } else {
++ if ((flags & (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) !=
++ (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) {
++ virXendError(VIR_ERR_OPERATION_INVALID, "%s",
++ _("Xend only supports modifying both live and "
++ "persistent config"));
++ }
++ }
++
++ /* Unfortunately, xend_op does not validate whether this exceeds
++ * the maximum. */
++ flags |= VIR_DOMAIN_VCPU_MAXIMUM;
++ if ((max = xenDaemonDomainGetVcpusFlags(domain, flags)) < 0) {
++ virXendError(VIR_ERR_OPERATION_INVALID, "%s",
++ _("could not determin max vcpus for the domain"));
++ return -1;
++ }
++ if (vcpus > max) {
++ virXendError(VIR_ERR_INVALID_ARG,
++ _("requested vcpus is greater than max allowable"
++ " vcpus for the domain: %d > %d"), vcpus, max);
++ return -1;
++ }
++
++ snprintf(buf, sizeof(buf), "%d", vcpus);
++ return xend_op(domain->conn, domain->name, "op", "set_vcpus", "vcpus",
++ buf, NULL);
++}
++
++/**
+ * xenDaemonDomainSetVcpus:
+ * @domain: pointer to domain object
+ * @nvcpus: the new number of virtual CPUs for this domain
+diff --git a/src/xen/xend_internal.h b/src/xen/xend_internal.h
+index 923cebd..53f5d2c 100644
+--- a/src/xen/xend_internal.h
++++ b/src/xen/xend_internal.h
+@@ -151,6 +151,9 @@ int xenDaemonDomainUndefine(virDomainPtr domain);
+
+ int xenDaemonDomainSetVcpus (virDomainPtr domain,
+ unsigned int vcpus);
++int xenDaemonDomainSetVcpusFlags (virDomainPtr domain,
++ unsigned int vcpus,
++ unsigned int flags);
+ int xenDaemonDomainPinVcpu (virDomainPtr domain,
+ unsigned int vcpu,
+ unsigned char *cpumap,
+diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c
+index 4ea4245..2b8e51e 100644
+--- a/src/xen/xm_internal.c
++++ b/src/xen/xm_internal.c
+@@ -1670,6 +1670,89 @@ cleanup:
+ return ret;
+ }
+
++/*
++ * xenXMDomainSetVcpusFlags:
++ * @domain: pointer to domain object
++ * @nvcpus: number of vcpus
++ * @flags: bitwise-ORd from virDomainVcpuFlags
++ *
++ * Change virtual CPUs allocation of domain according to flags.
++ *
++ * Returns 0 on success, -1 if an error message was issued, and -2 if
++ * the unified driver should keep trying.
++ */
++int
++xenXMDomainSetVcpusFlags(virDomainPtr domain, unsigned int vcpus,
++ unsigned int flags)
++{
++ xenUnifiedPrivatePtr priv;
++ const char *filename;
++ xenXMConfCachePtr entry;
++ int ret = -1;
++ int max;
++
++ if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
++ xenXMError(VIR_ERR_INVALID_ARG, __FUNCTION__);
++ return -1;
++ }
++ if (domain->conn->flags & VIR_CONNECT_RO) {
++ xenXMError(VIR_ERR_OPERATION_DENIED, __FUNCTION__);
++ return -1;
++ }
++ if (domain->id != -1)
++ return -2;
++ if (flags & VIR_DOMAIN_VCPU_LIVE) {
++ xenXMError(VIR_ERR_OPERATION_INVALID, "%s",
++ _("domain is not running"));
++ return -1;
++ }
++
++ priv = domain->conn->privateData;
++ xenUnifiedLock(priv);
++
++ if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
++ goto cleanup;
++
++ if (!(entry = virHashLookup(priv->configCache, filename)))
++ goto cleanup;
++
++ /* Hypervisor maximum. */
++ if ((max = xenUnifiedGetMaxVcpus(domain->conn, NULL)) < 0) {
++ xenXMError(VIR_ERR_INTERNAL_ERROR, "%s",
++ _("could not determin max vcpus for the domain"));
++ goto cleanup;
++ }
++ /* Can't specify a current larger than stored maximum; but
++ * reducing maximum can silently reduce current. */
++ if (!(flags & VIR_DOMAIN_VCPU_MAXIMUM))
++ max = entry->def->maxvcpus;
++ if (vcpus > max) {
++ xenXMError(VIR_ERR_INVALID_ARG,
++ _("requested vcpus is greater than max allowable"
++ " vcpus for the domain: %d > %d"), vcpus, max);
++ goto cleanup;
++ }
++
++ if (flags & VIR_DOMAIN_VCPU_MAXIMUM) {
++ entry->def->maxvcpus = vcpus;
++ if (entry->def->vcpus > vcpus)
++ entry->def->vcpus = vcpus;
++ } else {
++ 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!
++ */
++ if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
++ goto cleanup;
++ ret = 0;
++
++cleanup:
++ xenUnifiedUnlock(priv);
++ return ret;
++}
++
+ /**
+ * xenXMDomainGetVcpusFlags:
+ * @domain: pointer to domain object
+diff --git a/src/xen/xm_internal.h b/src/xen/xm_internal.h
+index 3295fbd..a46e1a2 100644
+--- a/src/xen/xm_internal.h
++++ b/src/xen/xm_internal.h
+@@ -45,6 +45,8 @@ int xenXMDomainSetMemory(virDomainPtr domain, unsigned long memory);
+ int xenXMDomainSetMaxMemory(virDomainPtr domain, unsigned long memory);
+ unsigned long xenXMDomainGetMaxMemory(virDomainPtr domain);
+ int xenXMDomainSetVcpus(virDomainPtr domain, unsigned int vcpus);
++int xenXMDomainSetVcpusFlags(virDomainPtr domain, unsigned int vcpus,
++ unsigned int flags);
+ int xenXMDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags);
+ int xenXMDomainPinVcpu(virDomainPtr domain, unsigned int vcpu,
+ unsigned char *cpumap, int maplen);
+--
+1.7.2.3
+
diff --git a/docs/api_extension/0015-Step-15-of-15-remove-dead-xen-code.patch b/docs/api_extension/0015-Step-15-of-15-remove-dead-xen-code.patch
new file mode 100644
index 0000000000..56b99a3355
--- /dev/null
+++ b/docs/api_extension/0015-Step-15-of-15-remove-dead-xen-code.patch
@@ -0,0 +1,228 @@
+From b013788742183afec9aa5068d3cfd185a3b5c62e Mon Sep 17 00:00:00 2001
+From: Eric Blake <eblake@redhat.com>
+Date: Thu, 7 Oct 2010 08:59:27 -0600
+Subject: [PATCH 15/15] vcpu: remove dead xen code
+
+* src/xen/xen_driver.h (xenUnifiedDriver): Remove now-unused
+domainGetMaxVcpus, domainSetVcpus.
+* src/xen/proxy_internal.c (xenProxyDriver): Likewise.
+* src/xen/xen_hypervisor.c (xenHypervisorDriver): Likewise.
+* src/xen/xen_inotify.c (xenInotifyDriver): Likewise.
+* src/xen/xend_internal.c (xenDaemonDriver)
+(xenDaemonDomainSetVcpus): Likewise.
+* src/xen/xm_internal.c (xenXMDriver, xenXMDomainSetVcpus):
+Likewise.
+* src/xen/xs_internal.c (xenStoreDriver): Likewise.
+---
+ src/xen/proxy_internal.c | 2 --
+ src/xen/xen_driver.h | 4 +---
+ src/xen/xen_hypervisor.c | 2 --
+ src/xen/xen_inotify.c | 2 --
+ src/xen/xend_internal.c | 33 ---------------------------------
+ src/xen/xm_internal.c | 43 -------------------------------------------
+ src/xen/xs_internal.c | 2 --
+ 7 files changed, 1 insertions(+), 87 deletions(-)
+
+diff --git a/src/xen/proxy_internal.c b/src/xen/proxy_internal.c
+index 335dfc4..4033727 100644
+--- a/src/xen/proxy_internal.c
++++ b/src/xen/proxy_internal.c
+@@ -67,10 +67,8 @@ struct xenUnifiedDriver xenProxyDriver = {
+ NULL, /* domainSave */
+ NULL, /* domainRestore */
+ NULL, /* domainCoreDump */
+- NULL, /* domainSetVcpus */
+ NULL, /* domainPinVcpu */
+ NULL, /* domainGetVcpus */
+- NULL, /* domainGetMaxVcpus */
+ NULL, /* listDefinedDomains */
+ NULL, /* numOfDefinedDomains */
+ NULL, /* domainCreate */
+diff --git a/src/xen/xen_driver.h b/src/xen/xen_driver.h
+index 115a26a..53f97d4 100644
+--- a/src/xen/xen_driver.h
++++ b/src/xen/xen_driver.h
+@@ -1,7 +1,7 @@
+ /*
+ * xen_unified.c: Unified Xen driver.
+ *
+- * Copyright (C) 2007 Red Hat, Inc.
++ * Copyright (C) 2007, 2010 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+@@ -84,10 +84,8 @@ struct xenUnifiedDriver {
+ virDrvDomainSave domainSave;
+ virDrvDomainRestore domainRestore;
+ virDrvDomainCoreDump domainCoreDump;
+- virDrvDomainSetVcpus domainSetVcpus;
+ virDrvDomainPinVcpu domainPinVcpu;
+ virDrvDomainGetVcpus domainGetVcpus;
+- virDrvDomainGetMaxVcpus domainGetMaxVcpus;
+ virDrvListDefinedDomains listDefinedDomains;
+ virDrvNumOfDefinedDomains numOfDefinedDomains;
+ virDrvDomainCreate domainCreate;
+diff --git a/src/xen/xen_hypervisor.c b/src/xen/xen_hypervisor.c
+index 6246513..3797865 100644
+--- a/src/xen/xen_hypervisor.c
++++ b/src/xen/xen_hypervisor.c
+@@ -784,10 +784,8 @@ struct xenUnifiedDriver xenHypervisorDriver = {
+ NULL, /* domainSave */
+ NULL, /* domainRestore */
+ NULL, /* domainCoreDump */
+- xenHypervisorSetVcpus, /* domainSetVcpus */
+ xenHypervisorPinVcpu, /* domainPinVcpu */
+ xenHypervisorGetVcpus, /* domainGetVcpus */
+- xenHypervisorGetVcpuMax, /* domainGetMaxVcpus */
+ NULL, /* listDefinedDomains */
+ NULL, /* numOfDefinedDomains */
+ NULL, /* domainCreate */
+diff --git a/src/xen/xen_inotify.c b/src/xen/xen_inotify.c
+index d24b20f..9507061 100644
+--- a/src/xen/xen_inotify.c
++++ b/src/xen/xen_inotify.c
+@@ -71,10 +71,8 @@ struct xenUnifiedDriver xenInotifyDriver = {
+ NULL, /* domainSave */
+ NULL, /* domainRestore */
+ NULL, /* domainCoreDump */
+- NULL, /* domainSetVcpus */
+ NULL, /* domainPinVcpu */
+ NULL, /* domainGetVcpus */
+- NULL, /* domainGetMaxVcpus */
+ NULL, /* listDefinedDomains */
+ NULL, /* numOfDefinedDomains */
+ NULL, /* domainCreate */
+diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c
+index 55c2cc4..b90c331 100644
+--- a/src/xen/xend_internal.c
++++ b/src/xen/xend_internal.c
+@@ -3611,37 +3611,6 @@ xenDaemonDomainSetVcpusFlags(virDomainPtr domain, unsigned int vcpus,
+ }
+
+ /**
+- * xenDaemonDomainSetVcpus:
+- * @domain: pointer to domain object
+- * @nvcpus: the new number of virtual CPUs for this domain
+- *
+- * Dynamically change the number of virtual CPUs used by the domain.
+- *
+- * Returns 0 for success; -1 (with errno) on error
+- */
+-int
+-xenDaemonDomainSetVcpus(virDomainPtr domain, unsigned int vcpus)
+-{
+- char buf[VIR_UUID_BUFLEN];
+- xenUnifiedPrivatePtr priv;
+-
+- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
+- || (vcpus < 1)) {
+- virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+- return (-1);
+- }
+-
+- priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+-
+- if (domain->id < 0 && priv->xendConfigVersion < 3)
+- return(-1);
+-
+- snprintf(buf, sizeof(buf), "%d", vcpus);
+- return(xend_op(domain->conn, domain->name, "op", "set_vcpus", "vcpus",
+- buf, NULL));
+-}
+-
+-/**
+ * xenDaemonDomainPinCpu:
+ * @domain: pointer to domain object
+ * @vcpu: virtual CPU number
+@@ -5213,10 +5182,8 @@ struct xenUnifiedDriver xenDaemonDriver = {
+ xenDaemonDomainSave, /* domainSave */
+ xenDaemonDomainRestore, /* domainRestore */
+ xenDaemonDomainCoreDump, /* domainCoreDump */
+- xenDaemonDomainSetVcpus, /* domainSetVcpus */
+ xenDaemonDomainPinVcpu, /* domainPinVcpu */
+ xenDaemonDomainGetVcpus, /* domainGetVcpus */
+- NULL, /* domainGetMaxVcpus */
+ xenDaemonListDefinedDomains, /* listDefinedDomains */
+ xenDaemonNumOfDefinedDomains,/* numOfDefinedDomains */
+ xenDaemonDomainCreate, /* domainCreate */
+diff --git a/src/xen/xm_internal.c b/src/xen/xm_internal.c
+index 2b8e51e..430d40b 100644
+--- a/src/xen/xm_internal.c
++++ b/src/xen/xm_internal.c
+@@ -103,10 +103,8 @@ struct xenUnifiedDriver xenXMDriver = {
+ NULL, /* domainSave */
+ NULL, /* domainRestore */
+ NULL, /* domainCoreDump */
+- xenXMDomainSetVcpus, /* domainSetVcpus */
+ xenXMDomainPinVcpu, /* domainPinVcpu */
+ NULL, /* domainGetVcpus */
+- NULL, /* domainGetMaxVcpus */
+ xenXMListDefinedDomains, /* listDefinedDomains */
+ xenXMNumOfDefinedDomains, /* numOfDefinedDomains */
+ xenXMDomainCreate, /* domainCreate */
+@@ -1630,47 +1628,6 @@ cleanup:
+ }
+
+ /*
+- * Set the VCPU count in config
+- */
+-int xenXMDomainSetVcpus(virDomainPtr domain, unsigned int vcpus) {
+- xenUnifiedPrivatePtr priv;
+- const char *filename;
+- xenXMConfCachePtr entry;
+- int ret = -1;
+-
+- if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
+- xenXMError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+- return (-1);
+- }
+- if (domain->conn->flags & VIR_CONNECT_RO)
+- return (-1);
+- if (domain->id != -1)
+- return (-1);
+-
+- priv = domain->conn->privateData;
+- xenUnifiedLock(priv);
+-
+- if (!(filename = virHashLookup(priv->nameConfigMap, domain->name)))
+- goto cleanup;
+-
+- if (!(entry = virHashLookup(priv->configCache, filename)))
+- goto cleanup;
+-
+- 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!
+- */
+- if (xenXMConfigSaveFile(domain->conn, entry->filename, entry->def) < 0)
+- goto cleanup;
+- ret = 0;
+-
+-cleanup:
+- xenUnifiedUnlock(priv);
+- return ret;
+-}
+-
+-/*
+ * xenXMDomainSetVcpusFlags:
+ * @domain: pointer to domain object
+ * @nvcpus: number of vcpus
+diff --git a/src/xen/xs_internal.c b/src/xen/xs_internal.c
+index 9296f25..a9817b1 100644
+--- a/src/xen/xs_internal.c
++++ b/src/xen/xs_internal.c
+@@ -67,10 +67,8 @@ struct xenUnifiedDriver xenStoreDriver = {
+ NULL, /* domainSave */
+ NULL, /* domainRestore */
+ NULL, /* domainCoreDump */
+- NULL, /* domainSetVcpus */
+ NULL, /* domainPinVcpu */
+ NULL, /* domainGetVcpus */
+- NULL, /* domainGetMaxVcpus */
+ NULL, /* listDefinedDomains */
+ NULL, /* numOfDefinedDomains */
+ NULL, /* domainCreate */
+--
+1.7.2.3
+