+
+@@ -1431,6 +1433,39 @@
+ Since 0.8.5 the policy
+ attribute can be omitted and will default to require.
+
++
++
cache
++
Since 3.3.0 the cache
++ element describes the virtual CPU cache. If the element is missing,
++ the hypervisor will use a sensible default.
++
++
++
level
++
This optional attribute specifies which cache level is described
++ by the element. Missing attribute means the element describes all
++ CPU cache levels at once. Mixing cache elements with
++ the level attribute set and those without the
++ attribute is forbidden.
++
++
mode
++
++ The following values are supported:
++
++
emulate
++
The hypervisor will provide a fake CPU cache data.
++
++
passthrough
++
The real CPU cache data reported by the host CPU will be
++ passed through to the virtual CPU.
++
++
disable
++
The virtual CPU will report no CPU cache of the specified
++ level (or no cache at all if the level attribute
++ is missing).
++ QEMU's virtio devices have some attributes related to the virtio transport under
++ the driver element:
++ The iommu attribute enables the use of emulated IOMMU
++ by the device. The attribute ats controls the Address
++ Translation Service support for PCIe devices. This is needed to make use
++ of IOTLB support (see IOMMU device).
++ Possible values are on or off.
++ Since 3.5.0
++
+@@ -5139,6 +5152,12 @@ qemu-kvm -net nic,model=? /dev/null
+ In general you should leave this option alone, unless you
+ are very certain you know what you are doing.
+
++
+ Offloading options for the host and guest can be configured using
+diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
+index 1b66362f17..9e68bbc52d 100644
+--- a/docs/schemas/domaincommon.rng
++++ b/docs/schemas/domaincommon.rng
+@@ -2632,6 +2632,7 @@
+
+
+
+diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
+index 9e68bbc52d..f571af6706 100644
+--- a/docs/schemas/domaincommon.rng
++++ b/docs/schemas/domaincommon.rng
+@@ -3730,6 +3730,11 @@
+
+
+
++
++
++
++
++
+
+
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index bba50cf3fd..4768d02029 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -2292,6 +2292,7 @@ void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def)
+ return;
+
+ virDomainDeviceInfoClear(&def->info);
++ VIR_FREE(def->virtio);
+
+ VIR_FREE(def);
+ }
+@@ -12970,6 +12971,9 @@ virDomainMemballoonDefParseXML(xmlNodePtr node,
+ else if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0)
+ goto error;
+
++ if (virDomainVirtioOptionsParseXML(ctxt, &def->virtio) < 0)
++ goto error;
++
+ cleanup:
+ VIR_FREE(model);
+ VIR_FREE(deflate);
+@@ -19582,6 +19586,10 @@ virDomainMemballoonDefCheckABIStability(virDomainMemballoonDefPtr src,
+ return false;
+ }
+
++ if (src->virtio && dst->virtio &&
++ !virDomainVirtioOptionsCheckABIStability(src->virtio, dst->virtio))
++ return false;
++
+ if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
+ return false;
+
+@@ -22934,6 +22942,22 @@ virDomainMemballoonDefFormat(virBufferPtr buf,
+ return -1;
+ }
+
++ if (def->virtio) {
++ virBuffer driverBuf = VIR_BUFFER_INITIALIZER;
++
++ virDomainVirtioOptionsFormat(&driverBuf, def->virtio);
++
++ if (virBufferCheckError(&driverBuf) < 0) {
++ virBufferFreeAndReset(&childrenBuf);
++ return -1;
++ }
++ if (virBufferUse(&driverBuf)) {
++ virBufferAddLit(&childrenBuf, "\n");
++ }
++ }
++
+ if (!virBufferUse(&childrenBuf)) {
+ virBufferAddLit(buf, "/>\n");
+ } else {
+diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
+index 603d35bd50..f1f9208b91 100644
+--- a/src/conf/domain_conf.h
++++ b/src/conf/domain_conf.h
+@@ -1609,6 +1609,7 @@ struct _virDomainMemballoonDef {
+ virDomainDeviceInfo info;
+ int period; /* seconds between collections */
+ int autodeflate; /* enum virTristateSwitch */
++ virDomainVirtioOptionsPtr virtio;
+ };
+
+ struct _virDomainNVRAMDef {
+diff --git a/tests/qemuxml2argvdata/qemuxml2argv-virtio-options.xml b/tests/qemuxml2argvdata/qemuxml2argv-virtio-options.xml
+index 3357bc6d1b..b16a9847fe 100644
+--- a/tests/qemuxml2argvdata/qemuxml2argv-virtio-options.xml
++++ b/tests/qemuxml2argvdata/qemuxml2argv-virtio-options.xml
+@@ -73,6 +73,7 @@
+
+
+
++
+
+
+ /dev/random
+--
+2.13.1
+
diff --git a/SOURCES/libvirt-audit-Fix-the-output-message-for-shmem.patch b/SOURCES/libvirt-audit-Fix-the-output-message-for-shmem.patch
new file mode 100644
index 0000000..c3e819a
--- /dev/null
+++ b/SOURCES/libvirt-audit-Fix-the-output-message-for-shmem.patch
@@ -0,0 +1,70 @@
+From c71f920357ffb17cd13aaf9a12e8d77d1b29b08c Mon Sep 17 00:00:00 2001
+Message-Id:
+From: Martin Kletzander
+Date: Mon, 5 Jun 2017 17:02:03 +0200
+Subject: [PATCH] audit: Fix the output message for shmem
+
+After some discussion on and off the linux-audit mailing list, we
+should use different fields for the audit messages.
+
+Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1218603
+
+Signed-off-by: Martin Kletzander
+(cherry picked from commit 6d12a1cb2fb0e0152a19518423dceafa7cf088fb)
+Signed-off-by: Martin Kletzander
+Signed-off-by: Jiri Denemark
+---
+ src/conf/domain_audit.c | 24 +++++++++++++-----------
+ 1 file changed, 13 insertions(+), 11 deletions(-)
+
+diff --git a/src/conf/domain_audit.c b/src/conf/domain_audit.c
+index 2d9ff5e3ff..1e667af73c 100644
+--- a/src/conf/domain_audit.c
++++ b/src/conf/domain_audit.c
+@@ -983,15 +983,13 @@ virDomainAuditShmem(virDomainObjPtr vm,
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ char *vmname = virAuditEncode("vm", vm->def->name);
+ const char *srcpath = virDomainAuditChardevPath(&def->server.chr);
+- char *src = virAuditEncode("server", VIR_AUDIT_STR(srcpath));
+- char *shmem = virAuditEncode("shmem", VIR_AUDIT_STR(def->name));
+ const char *virt = virDomainVirtTypeToString(vm->def->virtType);
+- char *size = NULL;
++ char *shmpath = NULL;
+
+ virUUIDFormat(vm->def->uuid, uuidstr);
+
+- if (!vmname || !src || !shmem ||
+- virAsprintfQuiet(&size, "%llu", def->size) < 0) {
++ if (!vmname ||
++ virAsprintfQuiet(&shmpath, "/dev/shm/%s", def->name) < 0) {
+ VIR_WARN("OOM while encoding audit message");
+ goto cleanup;
+ }
+@@ -1002,14 +1000,18 @@ virDomainAuditShmem(virDomainObjPtr vm,
+ virt = "?";
+ }
+
+- VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
+- "virt=%s resrc=shmem reason=%s %s uuid=%s size=%s %s %s",
+- virt, reason, vmname, uuidstr, size, shmem, src);
++ if (def->server.enabled) {
++ VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
++ "virt=%s resrc=ivshmem-socket reason=%s %s uuid=%s path=%s",
++ virt, reason, vmname, uuidstr, VIR_AUDIT_STR(srcpath));
++ } else {
++ VIR_AUDIT(VIR_AUDIT_RECORD_RESOURCE, success,
++ "virt=%s resrc=shmem reason=%s %s uuid=%s size=%llu path=%s",
++ virt, reason, vmname, uuidstr, def->size, VIR_AUDIT_STR(shmpath));
++ }
+
+ cleanup:
+ VIR_FREE(vmname);
+- VIR_FREE(src);
+- VIR_FREE(size);
+- VIR_FREE(shmem);
++ VIR_FREE(shmpath);
+ return;
+ }
+--
+2.13.1
+
diff --git a/SOURCES/libvirt-conf-Add-check-for-non-scsi_host-parent-during-vport-delete.patch b/SOURCES/libvirt-conf-Add-check-for-non-scsi_host-parent-during-vport-delete.patch
new file mode 100644
index 0000000..66afa80
--- /dev/null
+++ b/SOURCES/libvirt-conf-Add-check-for-non-scsi_host-parent-during-vport-delete.patch
@@ -0,0 +1,46 @@
+From aa337656da6b3e44ccaae85ec64538dee80000cf Mon Sep 17 00:00:00 2001
+Message-Id:
+From: John Ferlan
+Date: Thu, 13 Apr 2017 10:38:35 -0400
+Subject: [PATCH] conf: Add check for non scsi_host parent during vport delete
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1420740
+
+If the parent is not a scsi_host, then we can just happily return since
+we won't be removing a vport.
+
+Fixes a bug with the following output:
+
+$ virsh pool-destroy host4_hba_pool
+error: Failed to destroy pool host4_hba_pool
+error: internal error: Invalid adapter name 'pci_0000_10_00_1' for SCSI pool
+
+$
+
+(cherry picked from commit 84f178bdc7ab38011cc1f76759b0a41335285a4f)
+Signed-off-by: John Ferlan
+---
+ src/conf/node_device_conf.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
+index 7d0baa9d1..cc3fad8b9 100644
+--- a/src/conf/node_device_conf.c
++++ b/src/conf/node_device_conf.c
+@@ -2074,6 +2074,13 @@ virNodeDeviceDeleteVport(virConnectPtr conn,
+ if (!(vhba_parent = virNodeDeviceGetParentName(conn, scsi_host_name)))
+ goto cleanup;
+
++ /* If the parent is not a scsi_host, then this is a pool backed
++ * directly to an HBA and there's no vHBA to remove - so we're done */
++ if (!STRPREFIX(vhba_parent, "scsi_host")) {
++ ret = 0;
++ goto cleanup;
++ }
++
+ if (virSCSIHostGetNumber(vhba_parent, &parent_host) < 0)
+ goto cleanup;
+ }
+--
+2.12.2
+
diff --git a/SOURCES/libvirt-conf-Add-save-cookie-callbacks-to-xmlopt.patch b/SOURCES/libvirt-conf-Add-save-cookie-callbacks-to-xmlopt.patch
new file mode 100644
index 0000000..d7101a8
--- /dev/null
+++ b/SOURCES/libvirt-conf-Add-save-cookie-callbacks-to-xmlopt.patch
@@ -0,0 +1,427 @@
+From 7cf2eee78e7e0e08eb1203f7fdb5705aba6b0e42 Mon Sep 17 00:00:00 2001
+Message-Id: <7cf2eee78e7e0e08eb1203f7fdb5705aba6b0e42@dist-git>
+From: Jiri Denemark
+Date: Fri, 2 Jun 2017 00:44:46 +0200
+Subject: [PATCH] conf: Add save cookie callbacks to xmlopt
+
+virDomainXMLOption gains driver specific callbacks for parsing and
+formatting save cookies.
+
+Signed-off-by: Jiri Denemark
+Reviewed-by: Pavel Hrdina
+(cherry picked from commit 25af7e950a9e35a6cffeed32bbcdd95dd7e01035)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1441662
+
+Signed-off-by: Jiri Denemark
+---
+ src/bhyve/bhyve_domain.c | 2 +-
+ src/conf/domain_conf.c | 16 +++++++++++++++-
+ src/conf/domain_conf.h | 7 ++++++-
+ src/conf/snapshot_conf.c | 11 ++++++++++-
+ src/conf/snapshot_conf.h | 2 ++
+ src/libvirt_private.syms | 1 +
+ src/libxl/libxl_conf.c | 2 +-
+ src/lxc/lxc_conf.c | 2 +-
+ src/openvz/openvz_driver.c | 2 +-
+ src/phyp/phyp_driver.c | 2 +-
+ src/qemu/qemu_capabilities.c | 2 +-
+ src/qemu/qemu_conf.c | 3 ++-
+ src/security/virt-aa-helper.c | 2 +-
+ src/test/test_driver.c | 2 +-
+ src/uml/uml_driver.c | 2 +-
+ src/vbox/vbox_common.c | 2 +-
+ src/vmware/vmware_driver.c | 3 ++-
+ src/vmx/vmx.c | 2 +-
+ src/vz/vz_driver.c | 2 +-
+ src/xen/xen_driver.c | 2 +-
+ src/xenapi/xenapi_driver.c | 2 +-
+ tests/bhyveargv2xmltest.c | 2 +-
+ tests/testutils.c | 2 +-
+ 23 files changed, 54 insertions(+), 21 deletions(-)
+
+diff --git a/src/bhyve/bhyve_domain.c b/src/bhyve/bhyve_domain.c
+index 0a99550afa..20c82937b5 100644
+--- a/src/bhyve/bhyve_domain.c
++++ b/src/bhyve/bhyve_domain.c
+@@ -144,7 +144,7 @@ virBhyveDriverCreateXMLConf(bhyveConnPtr driver)
+ virBhyveDriverDomainDefParserConfig.priv = driver;
+ return virDomainXMLOptionNew(&virBhyveDriverDomainDefParserConfig,
+ &virBhyveDriverPrivateDataCallbacks,
+- NULL, NULL);
++ NULL, NULL, NULL);
+ }
+
+ virDomainDefParserConfig virBhyveDriverDomainDefParserConfig = {
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 395dcc0531..b473ce6b1e 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -79,6 +79,9 @@ struct _virDomainXMLOption {
+
+ /* ABI stability callbacks */
+ virDomainABIStability abi;
++
++ /* Private data for save image stored in snapshot XML */
++ virSaveCookieCallbacks saveCookie;
+ };
+
+ #define VIR_DOMAIN_DEF_FORMAT_COMMON_FLAGS \
+@@ -1054,7 +1057,8 @@ virDomainXMLOptionPtr
+ virDomainXMLOptionNew(virDomainDefParserConfigPtr config,
+ virDomainXMLPrivateDataCallbacksPtr priv,
+ virDomainXMLNamespacePtr xmlns,
+- virDomainABIStabilityPtr abi)
++ virDomainABIStabilityPtr abi,
++ virSaveCookieCallbacksPtr saveCookie)
+ {
+ virDomainXMLOptionPtr xmlopt;
+
+@@ -1076,6 +1080,9 @@ virDomainXMLOptionNew(virDomainDefParserConfigPtr config,
+ if (abi)
+ xmlopt->abi = *abi;
+
++ if (saveCookie)
++ xmlopt->saveCookie = *saveCookie;
++
+ /* Technically this forbids to use one of Xerox's MAC address prefixes in
+ * our hypervisor drivers. This shouldn't ever be a problem.
+ *
+@@ -1106,6 +1113,13 @@ virDomainXMLOptionGetNamespace(virDomainXMLOptionPtr xmlopt)
+ }
+
+
++virSaveCookieCallbacksPtr
++virDomainXMLOptionGetSaveCookie(virDomainXMLOptionPtr xmlopt)
++{
++ return &xmlopt->saveCookie;
++}
++
++
+ void
+ virBlkioDeviceArrayClear(virBlkioDevicePtr devices,
+ int ndevices)
+diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
+index d64ef1b6e9..706d106ad9 100644
+--- a/src/conf/domain_conf.h
++++ b/src/conf/domain_conf.h
+@@ -55,6 +55,7 @@
+ # include "virgic.h"
+ # include "virperf.h"
+ # include "virtypedparam.h"
++# include "virsavecookie.h"
+
+ /* forward declarations of all device types, required by
+ * virDomainDeviceDef
+@@ -2549,7 +2550,11 @@ struct _virDomainABIStability {
+ virDomainXMLOptionPtr virDomainXMLOptionNew(virDomainDefParserConfigPtr config,
+ virDomainXMLPrivateDataCallbacksPtr priv,
+ virDomainXMLNamespacePtr xmlns,
+- virDomainABIStabilityPtr abi);
++ virDomainABIStabilityPtr abi,
++ virSaveCookieCallbacksPtr saveCookie);
++
++virSaveCookieCallbacksPtr
++virDomainXMLOptionGetSaveCookie(virDomainXMLOptionPtr xmlopt);
+
+ void virDomainNetGenerateMAC(virDomainXMLOptionPtr xmlopt, virMacAddrPtr mac);
+
+diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c
+index e3bba985d7..6330f7d1f9 100644
+--- a/src/conf/snapshot_conf.c
++++ b/src/conf/snapshot_conf.c
+@@ -102,6 +102,7 @@ void virDomainSnapshotDefFree(virDomainSnapshotDefPtr def)
+ virDomainSnapshotDiskDefClear(&def->disks[i]);
+ VIR_FREE(def->disks);
+ virDomainDefFree(def->dom);
++ virObjectUnref(def->cookie);
+ VIR_FREE(def);
+ }
+
+@@ -214,6 +215,7 @@ virDomainSnapshotDefParse(xmlXPathContextPtr ctxt,
+ char *memorySnapshot = NULL;
+ char *memoryFile = NULL;
+ bool offline = !!(flags & VIR_DOMAIN_SNAPSHOT_PARSE_OFFLINE);
++ virSaveCookieCallbacksPtr saveCookie = virDomainXMLOptionGetSaveCookie(xmlopt);
+
+ if (VIR_ALLOC(def) < 0)
+ goto cleanup;
+@@ -365,6 +367,9 @@ virDomainSnapshotDefParse(xmlXPathContextPtr ctxt,
+ def->current = active != 0;
+ }
+
++ if (!offline && virSaveCookieParse(ctxt, &def->cookie, saveCookie) < 0)
++ goto cleanup;
++
+ ret = def;
+
+ cleanup:
+@@ -691,7 +696,7 @@ char *
+ virDomainSnapshotDefFormat(const char *domain_uuid,
+ virDomainSnapshotDefPtr def,
+ virCapsPtr caps,
+- virDomainXMLOptionPtr xmlopt ATTRIBUTE_UNUSED,
++ virDomainXMLOptionPtr xmlopt,
+ unsigned int flags,
+ int internal)
+ {
+@@ -751,6 +756,10 @@ virDomainSnapshotDefFormat(const char *domain_uuid,
+ virBufferAddLit(&buf, "\n");
+ }
+
++ if (virSaveCookieFormatBuf(&buf, def->cookie,
++ virDomainXMLOptionGetSaveCookie(xmlopt)) < 0)
++ goto error;
++
+ if (internal)
+ virBufferAsprintf(&buf, "%d\n", def->current);
+
+diff --git a/src/conf/snapshot_conf.h b/src/conf/snapshot_conf.h
+index 2ce526fa6b..1d663c77bc 100644
+--- a/src/conf/snapshot_conf.h
++++ b/src/conf/snapshot_conf.h
+@@ -76,6 +76,8 @@ struct _virDomainSnapshotDef {
+
+ virDomainDefPtr dom;
+
++ virObjectPtr cookie;
++
+ /* Internal use. */
+ bool current; /* At most one snapshot in the list should have this set */
+ };
+diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
+index b4769080e8..88e3f4b8ac 100644
+--- a/src/libvirt_private.syms
++++ b/src/libvirt_private.syms
+@@ -533,6 +533,7 @@ virDomainWatchdogActionTypeToString;
+ virDomainWatchdogModelTypeFromString;
+ virDomainWatchdogModelTypeToString;
+ virDomainXMLOptionGetNamespace;
++virDomainXMLOptionGetSaveCookie;
+ virDomainXMLOptionNew;
+
+
+diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c
+index dd345c22cf..28d31db158 100644
+--- a/src/libxl/libxl_conf.c
++++ b/src/libxl/libxl_conf.c
+@@ -2147,5 +2147,5 @@ libxlCreateXMLConf(void)
+ {
+ return virDomainXMLOptionNew(&libxlDomainDefParserConfig,
+ &libxlDomainXMLPrivateDataCallbacks,
+- NULL, NULL);
++ NULL, NULL, NULL);
+ }
+diff --git a/src/lxc/lxc_conf.c b/src/lxc/lxc_conf.c
+index b46fbc58ff..8adc408c32 100644
+--- a/src/lxc/lxc_conf.c
++++ b/src/lxc/lxc_conf.c
+@@ -213,7 +213,7 @@ lxcDomainXMLConfInit(void)
+ return virDomainXMLOptionNew(&virLXCDriverDomainDefParserConfig,
+ &virLXCDriverPrivateDataCallbacks,
+ &virLXCDriverDomainXMLNamespace,
+- NULL);
++ NULL, NULL);
+ }
+
+
+diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c
+index 44a6631a99..4392aa64c0 100644
+--- a/src/openvz/openvz_driver.c
++++ b/src/openvz/openvz_driver.c
+@@ -1493,7 +1493,7 @@ static virDrvOpenStatus openvzConnectOpen(virConnectPtr conn,
+ goto cleanup;
+
+ if (!(driver->xmlopt = virDomainXMLOptionNew(&openvzDomainDefParserConfig,
+- NULL, NULL, NULL)))
++ NULL, NULL, NULL, NULL)))
+ goto cleanup;
+
+ if (openvzLoadDomains(driver) < 0)
+diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c
+index e85f66ffab..32cb681c75 100644
+--- a/src/phyp/phyp_driver.c
++++ b/src/phyp/phyp_driver.c
+@@ -1199,7 +1199,7 @@ phypConnectOpen(virConnectPtr conn,
+ goto failure;
+
+ if (!(phyp_driver->xmlopt = virDomainXMLOptionNew(&virPhypDriverDomainDefParserConfig,
+- NULL, NULL, NULL)))
++ NULL, NULL, NULL, NULL)))
+ goto failure;
+
+ conn->privateData = phyp_driver;
+diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
+index 72d3f25763..29bb9949af 100644
+--- a/src/qemu/qemu_capabilities.c
++++ b/src/qemu/qemu_capabilities.c
+@@ -5027,7 +5027,7 @@ virQEMUCapsInitQMPCommandRun(virQEMUCapsInitQMPCommandPtr cmd,
+ goto ignore;
+ }
+
+- if (!(xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL, NULL)) ||
++ if (!(xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL, NULL, NULL)) ||
+ !(cmd->vm = virDomainObjNew(xmlopt)))
+ goto cleanup;
+
+diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
+index 76eed25277..96956b7779 100644
+--- a/src/qemu/qemu_conf.c
++++ b/src/qemu/qemu_conf.c
+@@ -908,7 +908,8 @@ virQEMUDriverCreateXMLConf(virQEMUDriverPtr driver)
+ return virDomainXMLOptionNew(&virQEMUDriverDomainDefParserConfig,
+ &virQEMUDriverPrivateDataCallbacks,
+ &virQEMUDriverDomainXMLNamespace,
+- &virQEMUDriverDomainABIStability);
++ &virQEMUDriverDomainABIStability,
++ NULL);
+ }
+
+
+diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c
+index 48201d5b8c..97436e5dc7 100644
+--- a/src/security/virt-aa-helper.c
++++ b/src/security/virt-aa-helper.c
+@@ -667,7 +667,7 @@ get_definition(vahControl * ctl, const char *xmlStr)
+ goto exit;
+ }
+
+- if (!(ctl->xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL, NULL))) {
++ if (!(ctl->xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL, NULL, NULL))) {
+ vah_error(ctl, 0, _("Failed to create XML config object"));
+ goto exit;
+ }
+diff --git a/src/test/test_driver.c b/src/test/test_driver.c
+index c8085dd797..4fd14ddee6 100644
+--- a/src/test/test_driver.c
++++ b/src/test/test_driver.c
+@@ -414,7 +414,7 @@ testDriverNew(void)
+ goto error;
+ }
+
+- if (!(ret->xmlopt = virDomainXMLOptionNew(NULL, NULL, &ns, NULL)) ||
++ if (!(ret->xmlopt = virDomainXMLOptionNew(NULL, NULL, &ns, NULL, NULL)) ||
+ !(ret->eventState = virObjectEventStateNew()) ||
+ !(ret->domains = virDomainObjListNew()) ||
+ !(ret->networks = virNetworkObjListNew()))
+diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c
+index ae75daa596..f91ee2961e 100644
+--- a/src/uml/uml_driver.c
++++ b/src/uml/uml_driver.c
+@@ -533,7 +533,7 @@ umlStateInitialize(bool privileged,
+ goto out_of_memory;
+
+ if (!(uml_driver->xmlopt = virDomainXMLOptionNew(¨DriverDomainDefParserConfig,
+- &privcb, NULL, NULL)))
++ &privcb, NULL, NULL, NULL)))
+ goto error;
+
+ if ((uml_driver->inotifyFD = inotify_init()) < 0) {
+diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c
+index c739031660..4a79c43a1a 100644
+--- a/src/vbox/vbox_common.c
++++ b/src/vbox/vbox_common.c
+@@ -139,7 +139,7 @@ vboxDriverObjNew(void)
+
+ if (!(driver->caps = vboxCapsInit()) ||
+ !(driver->xmlopt = virDomainXMLOptionNew(&vboxDomainDefParserConfig,
+- NULL, NULL, NULL)))
++ NULL, NULL, NULL, NULL)))
+ goto cleanup;
+
+ return driver;
+diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c
+index 24e97a4969..525c85edc8 100644
+--- a/src/vmware/vmware_driver.c
++++ b/src/vmware/vmware_driver.c
+@@ -114,7 +114,8 @@ vmwareDomainXMLConfigInit(void)
+ virDomainXMLPrivateDataCallbacks priv = { .alloc = vmwareDataAllocFunc,
+ .free = vmwareDataFreeFunc };
+
+- return virDomainXMLOptionNew(&vmwareDomainDefParserConfig, &priv, NULL, NULL);
++ return virDomainXMLOptionNew(&vmwareDomainDefParserConfig, &priv,
++ NULL, NULL, NULL);
+ }
+
+ static virDrvOpenStatus
+diff --git a/src/vmx/vmx.c b/src/vmx/vmx.c
+index 3289a20026..96507f10f3 100644
+--- a/src/vmx/vmx.c
++++ b/src/vmx/vmx.c
+@@ -591,7 +591,7 @@ virDomainXMLOptionPtr
+ virVMXDomainXMLConfInit(void)
+ {
+ return virDomainXMLOptionNew(&virVMXDomainDefParserConfig, NULL,
+- &virVMXDomainXMLNamespace, NULL);
++ &virVMXDomainXMLNamespace, NULL, NULL);
+ }
+
+ char *
+diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c
+index f0b6722a6e..532a6841f3 100644
+--- a/src/vz/vz_driver.c
++++ b/src/vz/vz_driver.c
+@@ -326,7 +326,7 @@ vzDriverObjNew(void)
+ if (!(driver->caps = vzBuildCapabilities()) ||
+ !(driver->xmlopt = virDomainXMLOptionNew(&vzDomainDefParserConfig,
+ &vzDomainXMLPrivateDataCallbacksPtr,
+- NULL, NULL)) ||
++ NULL, NULL, NULL)) ||
+ !(driver->domains = virDomainObjListNew()) ||
+ !(driver->domainEventState = virObjectEventStateNew()) ||
+ (vzInitVersion(driver) < 0) ||
+diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c
+index 0c160f8370..ab74ba9928 100644
+--- a/src/xen/xen_driver.c
++++ b/src/xen/xen_driver.c
+@@ -401,7 +401,7 @@ virDomainXMLOptionPtr
+ xenDomainXMLConfInit(void)
+ {
+ return virDomainXMLOptionNew(&xenDomainDefParserConfig,
+- NULL, NULL, NULL);
++ NULL, NULL, NULL, NULL);
+ }
+
+
+diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c
+index 5623ddb507..c94fd422f9 100644
+--- a/src/xenapi/xenapi_driver.c
++++ b/src/xenapi/xenapi_driver.c
+@@ -200,7 +200,7 @@ xenapiConnectOpen(virConnectPtr conn, virConnectAuthPtr auth,
+ }
+
+ if (!(privP->xmlopt = virDomainXMLOptionNew(&xenapiDomainDefParserConfig,
+- NULL, NULL, NULL))) {
++ NULL, NULL, NULL, NULL))) {
+ xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Failed to create XML conf object"));
+ goto error;
+diff --git a/tests/bhyveargv2xmltest.c b/tests/bhyveargv2xmltest.c
+index 5d7261a45b..43ef76a594 100644
+--- a/tests/bhyveargv2xmltest.c
++++ b/tests/bhyveargv2xmltest.c
+@@ -131,7 +131,7 @@ mymain(void)
+ return EXIT_FAILURE;
+
+ if ((driver.xmlopt = virDomainXMLOptionNew(NULL, NULL,
+- NULL, NULL)) == NULL)
++ NULL, NULL, NULL)) == NULL)
+ return EXIT_FAILURE;
+
+ # define DO_TEST_FULL(name, flags) \
+diff --git a/tests/testutils.c b/tests/testutils.c
+index b7dc8d8408..0823469068 100644
+--- a/tests/testutils.c
++++ b/tests/testutils.c
+@@ -1136,7 +1136,7 @@ virDomainXMLOptionPtr virTestGenericDomainXMLConfInit(void)
+ {
+ return virDomainXMLOptionNew(&virTestGenericDomainDefParserConfig,
+ &virTestGenericPrivateDataCallbacks,
+- NULL, NULL);
++ NULL, NULL, NULL);
+ }
+
+
+--
+2.13.1
+
diff --git a/SOURCES/libvirt-conf-Add-spapr-pci-host-bridge-controller-model.patch b/SOURCES/libvirt-conf-Add-spapr-pci-host-bridge-controller-model.patch
new file mode 100644
index 0000000..015d42b
--- /dev/null
+++ b/SOURCES/libvirt-conf-Add-spapr-pci-host-bridge-controller-model.patch
@@ -0,0 +1,64 @@
+From 851635352b217b63e7defc703f8a3f2a6719b490 Mon Sep 17 00:00:00 2001
+Message-Id: <851635352b217b63e7defc703f8a3f2a6719b490@dist-git>
+From: Andrea Bolognani
+Date: Mon, 17 Jul 2017 12:09:08 +0200
+Subject: [PATCH] conf: Add 'spapr-pci-host-bridge' controller model
+
+Adding it to the virDomainControllerPCIModelName enumeration
+is enough for existing code to handle it, so parsing and
+formatting will work without further tweaking.
+
+Signed-off-by: Andrea Bolognani
+Reviewed-by: Laine Stump
+(cherry picked from commit 90855eca3f7ceee964727c1d0f54541373d31908)
+
+Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1431193
+
+Signed-off-by: Andrea Bolognani
+Signed-off-by: Jiri Denemark
+---
+ docs/schemas/domaincommon.rng | 2 ++
+ src/conf/domain_conf.c | 1 +
+ src/conf/domain_conf.h | 1 +
+ 3 files changed, 4 insertions(+)
+
+diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
+index 78023ff4af..964e5c5bd5 100644
+--- a/docs/schemas/domaincommon.rng
++++ b/docs/schemas/domaincommon.rng
+@@ -1900,6 +1900,8 @@
+
+
+
++
++ spapr-pci-host-bridge
+
+ pci-bridge
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 8e5c487df8..8a030c9b68 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -349,6 +349,7 @@ VIR_ENUM_IMPL(virDomainControllerPCIModelName,
+ "pxb",
+ "pxb-pcie",
+ "pcie-root-port",
++ "spapr-pci-host-bridge",
+ );
+
+ VIR_ENUM_IMPL(virDomainControllerModelSCSI, VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST,
+diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
+index 4c33b0d15e..e287e6d7f3 100644
+--- a/src/conf/domain_conf.h
++++ b/src/conf/domain_conf.h
+@@ -710,6 +710,7 @@ typedef enum {
+ VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PXB,
+ VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PXB_PCIE,
+ VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCIE_ROOT_PORT,
++ VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE,
+
+ VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_LAST
+ } virDomainControllerPCIModelName;
+--
+2.13.3
+
diff --git a/SOURCES/libvirt-conf-Check-CPU-cache-for-ABI-stability.patch b/SOURCES/libvirt-conf-Check-CPU-cache-for-ABI-stability.patch
new file mode 100644
index 0000000..13fcb60
--- /dev/null
+++ b/SOURCES/libvirt-conf-Check-CPU-cache-for-ABI-stability.patch
@@ -0,0 +1,41 @@
+From b768a8cb9fbd84a96f576d1dd7468f664200683f Mon Sep 17 00:00:00 2001
+Message-Id:
+From: Jiri Denemark
+Date: Wed, 10 May 2017 13:05:16 +0200
+Subject: [PATCH] conf: Check CPU cache for ABI stability
+
+Signed-off-by: Jiri Denemark
+Reviewed-by: Daniel P. Berrange
+(cherry picked from commit 1e9cf6e09ce242c94731bd21707dd3bcd41f854f)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1449595
+
+Signed-off-by: Jiri Denemark
+---
+ src/conf/cpu_conf.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c
+index 1b098c476..a4be5742e 100644
+--- a/src/conf/cpu_conf.c
++++ b/src/conf/cpu_conf.c
+@@ -915,6 +915,16 @@ virCPUDefIsEqual(virCPUDefPtr src,
+ }
+ }
+
++ if ((src->cache && !dst->cache) ||
++ (!src->cache && dst->cache) ||
++ (src->cache && dst->cache &&
++ (src->cache->level != dst->cache->level ||
++ src->cache->mode != dst->cache->mode))) {
++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
++ _("Target CPU cache does not match source"));
++ goto cleanup;
++ }
++
+ identical = true;
+
+ cleanup:
+--
+2.13.0
+
diff --git a/SOURCES/libvirt-conf-Don-t-assign-value-from-.TypeFromString-directly-to-enum.patch b/SOURCES/libvirt-conf-Don-t-assign-value-from-.TypeFromString-directly-to-enum.patch
new file mode 100644
index 0000000..6d2a136
--- /dev/null
+++ b/SOURCES/libvirt-conf-Don-t-assign-value-from-.TypeFromString-directly-to-enum.patch
@@ -0,0 +1,54 @@
+From 8c00ca78eed4ffdb9238b89b58eb5975baf5e339 Mon Sep 17 00:00:00 2001
+Message-Id: <8c00ca78eed4ffdb9238b89b58eb5975baf5e339@dist-git>
+From: Peter Krempa
+Date: Fri, 19 May 2017 12:24:11 +0200
+Subject: [PATCH] conf: Don't assign value from ..TypeFromString directly to
+ enum
+
+Enums are unsigned, so it's impossible to check whether the helper
+returned -1 for invalid conversions.
+
+Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1452454
+(cherry picked from commit 85d62624c5d02c38e00a275dc2b2957584454908)
+
+Signed-off-by: Jiri Denemark
+---
+ src/conf/domain_conf.c | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 1653aa61d..a918ecd59 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -14065,6 +14065,7 @@ virDomainMemoryDefParseXML(xmlNodePtr memdevNode,
+ xmlNodePtr save = ctxt->node;
+ xmlNodePtr node;
+ virDomainMemoryDefPtr def;
++ int val;
+
+ ctxt->node = memdevNode;
+
+@@ -14084,12 +14085,14 @@ virDomainMemoryDefParseXML(xmlNodePtr memdevNode,
+ }
+ VIR_FREE(tmp);
+
+- tmp = virXMLPropString(memdevNode, "access");
+- if (tmp &&
+- (def->access = virDomainMemoryAccessTypeFromString(tmp)) <= 0) {
+- virReportError(VIR_ERR_XML_ERROR,
+- _("invalid access mode '%s'"), tmp);
+- goto error;
++ if ((tmp = virXMLPropString(memdevNode, "access"))) {
++ if ((val = virDomainMemoryAccessTypeFromString(tmp)) <= 0) {
++ virReportError(VIR_ERR_XML_ERROR,
++ _("invalid access mode '%s'"), tmp);
++ goto error;
++ }
++
++ def->access = val;
+ }
+ VIR_FREE(tmp);
+
+--
+2.13.0
+
diff --git a/SOURCES/libvirt-conf-Fix-backwards-migration-of-pSeries-guests.patch b/SOURCES/libvirt-conf-Fix-backwards-migration-of-pSeries-guests.patch
new file mode 100644
index 0000000..cb4a237
--- /dev/null
+++ b/SOURCES/libvirt-conf-Fix-backwards-migration-of-pSeries-guests.patch
@@ -0,0 +1,67 @@
+From 7e3b03cbdee6a9fc694046ea3c98c5cdef941c92 Mon Sep 17 00:00:00 2001
+Message-Id: <7e3b03cbdee6a9fc694046ea3c98c5cdef941c92@dist-git>
+From: Andrea Bolognani
+Date: Tue, 25 Jul 2017 10:29:27 +0200
+Subject: [PATCH] conf: Fix backwards migration of pSeries guests
+
+Recent commits made it so that pci-root controllers for
+pSeries guests are automatically assigned the
+spapr-pci-host-bridge model name; however, that prevents
+guests to migrate to older versions of libvirt which don't
+know about that model name at all, which at the moment is
+all of them :)
+
+To avoid the issue, just strip the model name from PHBs
+when formatting the migratable XML; guests that use more
+than one PHB are not going to be migratable anyway.
+
+Signed-off-by: Andrea Bolognani
+(cherry picked from commit 9b45cd8fab1c7d7d07dd3ae64970b3c93b78e04c)
+
+Conflicts:
+
+ * src/conf/domain_conf.c:
+
+ caused by e146264aaadf5aecf727d8c7b3d85683b55b6c48,
+ which significantly refactored
+ virDomainControllerDefFormat(), not being in the tree.
+
+Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1431193
+
+Signed-off-by: Andrea Bolognani
+Signed-off-by: Jiri Denemark
+---
+ src/conf/domain_conf.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 86415964dc..f28f6aff63 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -21670,6 +21670,23 @@ virDomainControllerDefFormat(virBufferPtr buf,
+ pcihole64 = true;
+ if (def->opts.pciopts.modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE)
+ pciModel = true;
++ /* Historically, libvirt didn't support specifying a model name for
++ * pci-root controllers; starting from 3.6.0, however, pSeries guests
++ * use pci-root controllers with model name spapr-pci-host-bridge to
++ * represent all PHBs, including the default one.
++ *
++ * In order to allow migration of pSeries guests from older libvirt
++ * versions and back, we don't format the model name in the migratable
++ * XML if it's spapr-pci-host-bridge, thus making "no model name" and
++ * "spapr-pci-host-bridge model name" basically equivalent.
++ *
++ * The spapr-pci-host-bridge device is specific to pSeries.
++ */
++ if (def->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT &&
++ def->opts.pciopts.modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE &&
++ flags & VIR_DOMAIN_DEF_FORMAT_MIGRATABLE) {
++ pciModel = false;
++ }
+ if (def->opts.pciopts.chassisNr != -1 ||
+ def->opts.pciopts.chassis != -1 ||
+ def->opts.pciopts.port != -1 ||
+--
+2.13.3
+
diff --git a/SOURCES/libvirt-conf-Implement-isolation-rules.patch b/SOURCES/libvirt-conf-Implement-isolation-rules.patch
new file mode 100644
index 0000000..603e2e0
--- /dev/null
+++ b/SOURCES/libvirt-conf-Implement-isolation-rules.patch
@@ -0,0 +1,164 @@
+From 672fd7d403ef52f10084c5c0b6aaeeb94f6fba2a Mon Sep 17 00:00:00 2001
+Message-Id: <672fd7d403ef52f10084c5c0b6aaeeb94f6fba2a@dist-git>
+From: Andrea Bolognani
+Date: Tue, 18 Jul 2017 12:10:06 +0200
+Subject: [PATCH] conf: Implement isolation rules
+
+These rules will make it possible for libvirt to
+automatically assign PCI addresses in a way that
+respects any isolation constraints devices might
+have.
+
+Signed-off-by: Andrea Bolognani
+Reviewed-by: Laine Stump
+(cherry picked from commit 209dc615e898f027b6dc8fa6acd3aeba5fd465bd)
+
+Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1280542
+
+Signed-off-by: Andrea Bolognani
+Signed-off-by: Jiri Denemark
+---
+ src/conf/domain_addr.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++---
+ src/conf/domain_addr.h | 3 +++
+ 2 files changed, 72 insertions(+), 4 deletions(-)
+
+diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
+index a067493136..d586bb7e47 100644
+--- a/src/conf/domain_addr.c
++++ b/src/conf/domain_addr.c
+@@ -369,6 +369,20 @@ virDomainPCIAddressBusIsFullyReserved(virDomainPCIAddressBusPtr bus)
+ }
+
+
++bool
++virDomainPCIAddressBusIsEmpty(virDomainPCIAddressBusPtr bus)
++{
++ size_t i;
++
++ for (i = bus->minSlot; i <= bus->maxSlot; i++) {
++ if (bus->slot[i].functions)
++ return false;
++ }
++
++ return true;
++}
++
++
+ /* Ensure addr fits in the address set, by expanding it if needed
+ *
+ * Return value:
+@@ -548,7 +562,7 @@ static int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
+ virDomainPCIAddressReserveAddrInternal(virDomainPCIAddressSetPtr addrs,
+ virPCIDeviceAddressPtr addr,
+ virDomainPCIConnectFlags flags,
+- unsigned int isolationGroup ATTRIBUTE_UNUSED,
++ unsigned int isolationGroup,
+ bool fromConfig)
+ {
+ int ret = -1;
+@@ -586,6 +600,26 @@ virDomainPCIAddressReserveAddrInternal(virDomainPCIAddressSetPtr addrs,
+ bus->slot[addr->slot].aggregate = true;
+ }
+
++ if (virDomainPCIAddressBusIsEmpty(bus) && !bus->isolationGroupLocked) {
++ /* The first device decides the isolation group for the
++ * entire bus */
++ bus->isolationGroup = isolationGroup;
++ VIR_DEBUG("PCI bus %.4x:%.2x assigned isolation group %u because of "
++ "first device %s",
++ addr->domain, addr->bus, isolationGroup, addrStr);
++ } else if (bus->isolationGroup != isolationGroup && fromConfig) {
++ /* If this is not the first function and its isolation group
++ * doesn't match the bus', then it should not be using this
++ * address. However, if the address comes from the user then
++ * we comply with the request and change the isolation group
++ * back to the default (because at that point isolation can't
++ * be guaranteed anymore) */
++ bus->isolationGroup = 0;
++ VIR_DEBUG("PCI bus %.4x:%.2x assigned isolation group %u because of "
++ "user assigned address %s",
++ addr->domain, addr->bus, isolationGroup, addrStr);
++ }
++
+ /* mark the requested function as reserved */
+ bus->slot[addr->slot].functions |= (1 << addr->function);
+ VIR_DEBUG("Reserving PCI address %s (aggregate='%s')", addrStr,
+@@ -763,7 +797,7 @@ static int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
+ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs,
+ virPCIDeviceAddressPtr next_addr,
+ virDomainPCIConnectFlags flags,
+- unsigned int isolationGroup ATTRIBUTE_UNUSED,
++ unsigned int isolationGroup,
+ int function)
+ {
+ virPCIDeviceAddress a = { 0 };
+@@ -779,12 +813,17 @@ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs,
+ else
+ a.function = function;
+
+- /* "Begin at the beginning," the King said, very gravely, "and go on
+- * till you come to the end: then stop." */
++ /* When looking for a suitable bus for the device, start by being
++ * very strict and ignoring all those where the isolation groups
++ * don't match. This ensures all devices sharing the same isolation
++ * group will end up on the same bus */
+ for (a.bus = 0; a.bus < addrs->nbuses; a.bus++) {
+ virDomainPCIAddressBusPtr bus = &addrs->buses[a.bus];
+ bool found = false;
+
++ if (bus->isolationGroup != isolationGroup)
++ continue;
++
+ a.slot = bus->minSlot;
+
+ if (virDomainPCIAddressFindUnusedFunctionOnBus(bus, &a, function,
+@@ -796,6 +835,32 @@ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs,
+ goto success;
+ }
+
++ /* We haven't been able to find a perfectly matching bus, but we
++ * might still be able to make this work by altering the isolation
++ * group for a bus that's currently empty. So let's try that */
++ for (a.bus = 0; a.bus < addrs->nbuses; a.bus++) {
++ virDomainPCIAddressBusPtr bus = &addrs->buses[a.bus];
++ bool found = false;
++
++ /* We can only change the isolation group for a bus when
++ * plugging in the first device; moreover, some buses are
++ * prevented from ever changing it */
++ if (!virDomainPCIAddressBusIsEmpty(bus) || bus->isolationGroupLocked)
++ continue;
++
++ a.slot = bus->minSlot;
++
++ if (virDomainPCIAddressFindUnusedFunctionOnBus(bus, &a, function,
++ flags, &found) < 0) {
++ goto error;
++ }
++
++ /* The isolation group for the bus will actually be changed
++ * later, in virDomainPCIAddressReserveAddrInternal() */
++ if (found)
++ goto success;
++ }
++
+ /* There were no free slots after the last used one */
+ if (addrs->dryRun) {
+ /* a is already set to the first new bus */
+diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h
+index 01dbc5114f..ae6a342dbc 100644
+--- a/src/conf/domain_addr.h
++++ b/src/conf/domain_addr.h
+@@ -150,6 +150,9 @@ int virDomainPCIAddressBusSetModel(virDomainPCIAddressBusPtr bus,
+ bool virDomainPCIAddressBusIsFullyReserved(virDomainPCIAddressBusPtr bus)
+ ATTRIBUTE_NONNULL(1);
+
++bool virDomainPCIAddressBusIsEmpty(virDomainPCIAddressBusPtr bus)
++ ATTRIBUTE_NONNULL(1);
++
+ bool virDomainPCIAddressSlotInUse(virDomainPCIAddressSetPtr addrs,
+ virPCIDeviceAddressPtr addr)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+--
+2.13.3
+
diff --git a/SOURCES/libvirt-conf-Introduce-isolation-groups.patch b/SOURCES/libvirt-conf-Introduce-isolation-groups.patch
new file mode 100644
index 0000000..ef6ce9f
--- /dev/null
+++ b/SOURCES/libvirt-conf-Introduce-isolation-groups.patch
@@ -0,0 +1,324 @@
+From 0b739987779a9f197d558f9c3b31d557a564bb6d Mon Sep 17 00:00:00 2001
+Message-Id: <0b739987779a9f197d558f9c3b31d557a564bb6d@dist-git>
+From: Andrea Bolognani
+Date: Tue, 18 Jul 2017 12:10:05 +0200
+Subject: [PATCH] conf: Introduce isolation groups
+
+Isolation groups will eventually allow us to make sure certain
+devices, eg. PCI hostdevs, are assigned to guest PCI buses in
+a way that guarantees improved isolation, error detection and
+recovery for machine types and hypervisors that support it,
+eg. pSeries guest on QEMU.
+
+This patch merely defines storage for the new information
+we're going to need later on and makes sure it is passed from
+the hypervisor driver (QEMU / bhyve) down to the generic PCI
+address allocation code.
+
+Signed-off-by: Andrea Bolognani
+Reviewed-by: Laine Stump
+(cherry picked from commit b8b6abbcd431d02ac106ee729204552d80762aae)
+
+Conflicts:
+
+ * src/conf/device_conf.h:
+
+ caused by 54fa1b44afc8bfe4a36c7c4e3b2fe1fafde0506c, where
+ virDomainDeviceInfo::loadparm is introduced, not being
+ present in the tree;
+
+ * src/conf/domain_conf.c:
+
+ caused mostly by the absence of commit
+ 0c53382d820aac4767895a727c01de23397a6aaa and hence the
+ virDomainSkipBackcompatConsole() function, but
+ 54fa1b44afc8bfe4a36c7c4e3b2fe1fafde0506c mentioned above
+ also plays a role.
+
+Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1280542
+
+Signed-off-by: Andrea Bolognani
+Signed-off-by: Jiri Denemark
+---
+ src/bhyve/bhyve_device.c | 4 ++--
+ src/conf/device_conf.h | 10 ++++++++++
+ src/conf/domain_addr.c | 17 ++++++++++++-----
+ src/conf/domain_addr.h | 9 ++++++++-
+ src/conf/domain_conf.c | 2 ++
+ src/qemu/qemu_domain_address.c | 35 ++++++++++++++++++-----------------
+ 6 files changed, 52 insertions(+), 25 deletions(-)
+
+diff --git a/src/bhyve/bhyve_device.c b/src/bhyve/bhyve_device.c
+index fdfd512e10..03aa6c93bd 100644
+--- a/src/bhyve/bhyve_device.c
++++ b/src/bhyve/bhyve_device.c
+@@ -57,7 +57,7 @@ bhyveCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
+ }
+
+ if (virDomainPCIAddressReserveAddr(addrs, addr,
+- VIR_PCI_CONNECT_TYPE_PCI_DEVICE) < 0) {
++ VIR_PCI_CONNECT_TYPE_PCI_DEVICE, 0) < 0) {
+ goto cleanup;
+ }
+
+@@ -100,7 +100,7 @@ bhyveAssignDevicePCISlots(virDomainDefPtr def,
+ lpc_addr.slot = 0x1;
+
+ if (virDomainPCIAddressReserveAddr(addrs, &lpc_addr,
+- VIR_PCI_CONNECT_TYPE_PCI_DEVICE) < 0) {
++ VIR_PCI_CONNECT_TYPE_PCI_DEVICE, 0) < 0) {
+ goto error;
+ }
+
+diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h
+index a20de853f8..6436a8cf3f 100644
+--- a/src/conf/device_conf.h
++++ b/src/conf/device_conf.h
+@@ -167,6 +167,16 @@ struct _virDomainDeviceInfo {
+ * assignment, never saved and never reported.
+ */
+ int pciConnectFlags; /* enum virDomainPCIConnectFlags */
++
++ /* PCI devices will only be automatically placed on a PCI bus
++ * that shares the same isolation group */
++ unsigned int isolationGroup;
++
++ /* Usually, PCI buses will take on the same isolation group
++ * as the first device that is plugged into them, but in some
++ * cases we might want to prevent that from happening by
++ * locking the isolation group */
++ bool isolationGroupLocked;
+ };
+
+
+diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
+index 8990372ae0..a067493136 100644
+--- a/src/conf/domain_addr.c
++++ b/src/conf/domain_addr.c
+@@ -548,6 +548,7 @@ static int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
+ virDomainPCIAddressReserveAddrInternal(virDomainPCIAddressSetPtr addrs,
+ virPCIDeviceAddressPtr addr,
+ virDomainPCIConnectFlags flags,
++ unsigned int isolationGroup ATTRIBUTE_UNUSED,
+ bool fromConfig)
+ {
+ int ret = -1;
+@@ -600,9 +601,11 @@ virDomainPCIAddressReserveAddrInternal(virDomainPCIAddressSetPtr addrs,
+ int
+ virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs,
+ virPCIDeviceAddressPtr addr,
+- virDomainPCIConnectFlags flags)
++ virDomainPCIConnectFlags flags,
++ unsigned int isolationGroup)
+ {
+- return virDomainPCIAddressReserveAddrInternal(addrs, addr, flags, true);
++ return virDomainPCIAddressReserveAddrInternal(addrs, addr, flags,
++ isolationGroup, true);
+ }
+
+ int
+@@ -638,7 +641,8 @@ virDomainPCIAddressEnsureAddr(virDomainPCIAddressSetPtr addrs,
+ goto cleanup;
+
+ ret = virDomainPCIAddressReserveAddrInternal(addrs, &dev->addr.pci,
+- flags, true);
++ flags, dev->isolationGroup,
++ true);
+ } else {
+ ret = virDomainPCIAddressReserveNextAddr(addrs, dev, flags, -1);
+ }
+@@ -759,6 +763,7 @@ static int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
+ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs,
+ virPCIDeviceAddressPtr next_addr,
+ virDomainPCIConnectFlags flags,
++ unsigned int isolationGroup ATTRIBUTE_UNUSED,
+ int function)
+ {
+ virPCIDeviceAddress a = { 0 };
+@@ -839,10 +844,12 @@ virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs,
+ {
+ virPCIDeviceAddress addr;
+
+- if (virDomainPCIAddressGetNextAddr(addrs, &addr, flags, function) < 0)
++ if (virDomainPCIAddressGetNextAddr(addrs, &addr, flags,
++ dev->isolationGroup, function) < 0)
+ return -1;
+
+- if (virDomainPCIAddressReserveAddrInternal(addrs, &addr, flags, false) < 0)
++ if (virDomainPCIAddressReserveAddrInternal(addrs, &addr, flags,
++ dev->isolationGroup, false) < 0)
+ return -1;
+
+ if (!addrs->dryRun) {
+diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h
+index 49f30332f0..01dbc5114f 100644
+--- a/src/conf/domain_addr.h
++++ b/src/conf/domain_addr.h
+@@ -100,6 +100,12 @@ typedef struct {
+ * bit is set, that function is in use by a device.
+ */
+ virDomainPCIAddressSlot slot[VIR_PCI_ADDRESS_SLOT_LAST + 1];
++
++ /* See virDomainDeviceInfo::isolationGroup */
++ unsigned int isolationGroup;
++
++ /* See virDomainDeviceInfo::isolationGroupLocked */
++ bool isolationGroupLocked;
+ } virDomainPCIAddressBus;
+ typedef virDomainPCIAddressBus *virDomainPCIAddressBusPtr;
+
+@@ -155,7 +161,8 @@ int virDomainPCIAddressSetGrow(virDomainPCIAddressSetPtr addrs,
+
+ int virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs,
+ virPCIDeviceAddressPtr addr,
+- virDomainPCIConnectFlags flags)
++ virDomainPCIConnectFlags flags,
++ unsigned int isolationGroup)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
+ int virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs,
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index f28f6aff63..5941a3a4c4 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -3608,6 +3608,8 @@ void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info)
+ memset(&info->addr, 0, sizeof(info->addr));
+ info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE;
+ VIR_FREE(info->romfile);
++ info->isolationGroup = 0;
++ info->isolationGroupLocked = false;
+ }
+
+
+diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
+index d19ffea7c9..02e214b8dd 100644
+--- a/src/qemu/qemu_domain_address.c
++++ b/src/qemu/qemu_domain_address.c
+@@ -1032,7 +1032,8 @@ qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
+ }
+
+ if (virDomainPCIAddressReserveAddr(addrs, addr,
+- info->pciConnectFlags) < 0) {
++ info->pciConnectFlags,
++ info->isolationGroup) < 0) {
+ goto cleanup;
+ }
+
+@@ -1077,6 +1078,10 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
+ if (virDomainPCIAddressBusSetModel(&addrs->buses[idx], cont->model) < 0)
+ goto error;
+
++ /* Forward the information about isolation groups */
++ addrs->buses[idx].isolationGroup = cont->info.isolationGroup;
++ addrs->buses[idx].isolationGroupLocked = cont->info.isolationGroupLocked;
++
+ if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT)
+ hasPCIeRoot = true;
+ }
+@@ -1193,7 +1198,7 @@ qemuDomainValidateDevicePCISlotsPIIX3(virDomainDefPtr def,
+ if (addrs->nbuses) {
+ memset(&tmp_addr, 0, sizeof(tmp_addr));
+ tmp_addr.slot = 1;
+- if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0)
++ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0)
+ goto cleanup;
+ }
+
+@@ -1228,7 +1233,7 @@ qemuDomainValidateDevicePCISlotsPIIX3(virDomainDefPtr def,
+ goto cleanup;
+ }
+ } else {
+- if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0)
++ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0)
+ goto cleanup;
+ primaryVideo->info.addr.pci = tmp_addr;
+ primaryVideo->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
+@@ -1253,7 +1258,7 @@ qemuDomainValidateDevicePCISlotsPIIX3(virDomainDefPtr def,
+ VIR_DEBUG("PCI address 0:0:2.0 in use, future addition of a video"
+ " device will not be possible without manual"
+ " intervention");
+- } else if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0) {
++ } else if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) {
+ goto cleanup;
+ }
+ }
+@@ -1329,10 +1334,8 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
+ assign = true;
+ }
+ if (assign) {
+- if (virDomainPCIAddressReserveAddr(addrs,
+- &tmp_addr, flags) < 0) {
++ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0)
+ goto cleanup;
+- }
+
+ cont->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
+ cont->info.addr.pci.domain = 0;
+@@ -1354,10 +1357,8 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
+ memset(&tmp_addr, 0, sizeof(tmp_addr));
+ tmp_addr.slot = 0x1E;
+ if (!virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) {
+- if (virDomainPCIAddressReserveAddr(addrs,
+- &tmp_addr, flags) < 0) {
++ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0)
+ goto cleanup;
+- }
+
+ cont->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
+ cont->info.addr.pci.domain = 0;
+@@ -1380,12 +1381,12 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
+ tmp_addr.slot = 0x1F;
+ tmp_addr.function = 0;
+ tmp_addr.multi = VIR_TRISTATE_SWITCH_ON;
+- if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0)
++ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0)
+ goto cleanup;
+
+ tmp_addr.function = 3;
+ tmp_addr.multi = VIR_TRISTATE_SWITCH_ABSENT;
+- if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0)
++ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0)
+ goto cleanup;
+ }
+
+@@ -1419,7 +1420,7 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
+ goto cleanup;
+ }
+ } else {
+- if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0)
++ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0)
+ goto cleanup;
+ primaryVideo->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
+ primaryVideo->info.addr.pci = tmp_addr;
+@@ -1445,8 +1446,7 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
+ " device will not be possible without manual"
+ " intervention");
+ virResetLastError();
+- } else if (virDomainPCIAddressReserveAddr(addrs,
+- &tmp_addr, flags) < 0) {
++ } else if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) {
+ goto cleanup;
+ }
+ }
+@@ -1467,7 +1467,7 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
+ !virDeviceInfoPCIAddressWanted(&sound->info)) {
+ continue;
+ }
+- if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0)
++ if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0)
+ goto cleanup;
+
+ sound->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
+@@ -1671,7 +1671,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def,
+ if (foundAddr) {
+ /* Reserve this function on the slot we found */
+ if (virDomainPCIAddressReserveAddr(addrs, &addr,
+- cont->info.pciConnectFlags) < 0) {
++ cont->info.pciConnectFlags,
++ cont->info.isolationGroup) < 0) {
+ goto error;
+ }
+
+--
+2.13.3
+
diff --git a/SOURCES/libvirt-conf-Introduce-virSaveCookie.patch b/SOURCES/libvirt-conf-Introduce-virSaveCookie.patch
new file mode 100644
index 0000000..fedfc8b
--- /dev/null
+++ b/SOURCES/libvirt-conf-Introduce-virSaveCookie.patch
@@ -0,0 +1,290 @@
+From 5785b4ff7c33f5e2eb16530f20b6b45d8809aae7 Mon Sep 17 00:00:00 2001
+Message-Id: <5785b4ff7c33f5e2eb16530f20b6b45d8809aae7@dist-git>
+From: Jiri Denemark
+Date: Fri, 2 Jun 2017 00:44:06 +0200
+Subject: [PATCH] conf: Introduce virSaveCookie
+
+The code will be used by snapshots and domain save/restore code to store
+additional data for a saved running domain. It is analogous to migration
+cookies, but simple and one way only.
+
+Signed-off-by: Jiri Denemark
+Reviewed-by: Pavel Hrdina
+(cherry picked from commit e37daa1fb69ec30042cbc38d489217edb656bc30)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1441662
+
+Signed-off-by: Jiri Denemark
+---
+ po/POTFILES.in | 1 +
+ src/Makefile.am | 1 +
+ src/conf/virsavecookie.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++
+ src/conf/virsavecookie.h | 62 ++++++++++++++++++++
+ src/libvirt_private.syms | 7 +++
+ 5 files changed, 215 insertions(+)
+ create mode 100644 src/conf/virsavecookie.c
+ create mode 100644 src/conf/virsavecookie.h
+
+diff --git a/po/POTFILES.in b/po/POTFILES.in
+index 064abd5bbb..cf64115719 100644
+--- a/po/POTFILES.in
++++ b/po/POTFILES.in
+@@ -47,6 +47,7 @@ src/conf/virdomainobjlist.c
+ src/conf/virinterfaceobj.c
+ src/conf/virnodedeviceobj.c
+ src/conf/virnwfilterobj.c
++src/conf/virsavecookie.c
+ src/conf/virsecretobj.c
+ src/conf/virstorageobj.c
+ src/cpu/cpu.c
+diff --git a/src/Makefile.am b/src/Makefile.am
+index 75e4344198..53550280bf 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -336,6 +336,7 @@ DOMAIN_CONF_SOURCES = \
+ conf/domain_conf.c conf/domain_conf.h \
+ conf/domain_audit.c conf/domain_audit.h \
+ conf/domain_nwfilter.c conf/domain_nwfilter.h \
++ conf/virsavecookie.c conf/virsavecookie.h \
+ conf/snapshot_conf.c conf/snapshot_conf.h \
+ conf/numa_conf.c conf/numa_conf.h \
+ conf/virdomainobjlist.c conf/virdomainobjlist.h
+diff --git a/src/conf/virsavecookie.c b/src/conf/virsavecookie.c
+new file mode 100644
+index 0000000000..502c04d0f4
+--- /dev/null
++++ b/src/conf/virsavecookie.c
+@@ -0,0 +1,144 @@
++/**
++ * virsavecookie.c: Save cookie handling
++ *
++ * Copyright (C) 2017 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, see
++ * .
++ */
++
++#include
++
++#include "virerror.h"
++#include "virlog.h"
++#include "virobject.h"
++#include "virbuffer.h"
++#include "virxml.h"
++#include "virsavecookie.h"
++
++#define VIR_FROM_THIS VIR_FROM_CONF
++
++VIR_LOG_INIT("conf.savecookie");
++
++
++static int
++virSaveCookieParseNode(xmlXPathContextPtr ctxt,
++ virObjectPtr *obj,
++ virSaveCookieCallbacksPtr saveCookie)
++{
++ *obj = NULL;
++
++ if (!xmlStrEqual(ctxt->node->name, BAD_CAST "cookie")) {
++ virReportError(VIR_ERR_XML_ERROR, "%s",
++ _("XML does not contain expected 'cookie' element"));
++ return -1;
++ }
++
++ if (!saveCookie || !saveCookie->parse)
++ return 0;
++
++ return saveCookie->parse(ctxt, obj);
++}
++
++
++int
++virSaveCookieParse(xmlXPathContextPtr ctxt,
++ virObjectPtr *obj,
++ virSaveCookieCallbacksPtr saveCookie)
++{
++ xmlNodePtr node = ctxt->node;
++ int ret = -1;
++
++ *obj = NULL;
++
++ if (!(ctxt->node = virXPathNode("./cookie", ctxt))) {
++ ret = 0;
++ goto cleanup;
++ }
++
++ ret = virSaveCookieParseNode(ctxt, obj, saveCookie);
++
++ cleanup:
++ ctxt->node = node;
++ return ret;
++}
++
++
++int
++virSaveCookieParseString(const char *xml,
++ virObjectPtr *obj,
++ virSaveCookieCallbacksPtr saveCookie)
++{
++ xmlDocPtr doc = NULL;
++ xmlXPathContextPtr ctxt = NULL;
++ int ret = -1;
++
++ *obj = NULL;
++
++ if (!xml) {
++ ret = 0;
++ goto cleanup;
++ }
++
++ if (!(doc = virXMLParseStringCtxt(xml, _("(save cookie)"), &ctxt)))
++ goto cleanup;
++
++ ret = virSaveCookieParseNode(ctxt, obj, saveCookie);
++
++ cleanup:
++ xmlXPathFreeContext(ctxt);
++ xmlFreeDoc(doc);
++ return ret;
++}
++
++
++int
++virSaveCookieFormatBuf(virBufferPtr buf,
++ virObjectPtr obj,
++ virSaveCookieCallbacksPtr saveCookie)
++{
++ if (!obj || !saveCookie || !saveCookie->format)
++ return 0;
++
++ virBufferAddLit(buf, "\n");
++ virBufferAdjustIndent(buf, 2);
++
++ if (saveCookie->format(buf, obj) < 0)
++ return -1;
++
++ virBufferAdjustIndent(buf, -2);
++ virBufferAddLit(buf, "\n");
++
++ return 0;
++}
++
++
++char *
++virSaveCookieFormat(virObjectPtr obj,
++ virSaveCookieCallbacksPtr saveCookie)
++{
++ virBuffer buf = VIR_BUFFER_INITIALIZER;
++
++ if (virSaveCookieFormatBuf(&buf, obj, saveCookie) < 0)
++ goto error;
++
++ if (virBufferCheckError(&buf) < 0)
++ goto error;
++
++ return virBufferContentAndReset(&buf);
++
++ error:
++ virBufferFreeAndReset(&buf);
++ return NULL;
++}
+diff --git a/src/conf/virsavecookie.h b/src/conf/virsavecookie.h
+new file mode 100644
+index 0000000000..4aed18466c
+--- /dev/null
++++ b/src/conf/virsavecookie.h
+@@ -0,0 +1,62 @@
++/**
++ * virsavecookie.h: Save cookie handling
++ *
++ * Copyright (C) 2017 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, see
++ * .
++ */
++#ifndef __VIR_SAVE_COOKIE_H__
++# define __VIR_SAVE_COOKIE_H__
++
++# include
++
++# include "internal.h"
++# include "virobject.h"
++# include "virbuffer.h"
++
++
++typedef int (*virSaveCookieParseFunc)(xmlXPathContextPtr ctxt,
++ virObjectPtr *obj);
++typedef int (*virSaveCookieFormatFunc)(virBufferPtr buf,
++ virObjectPtr obj);
++
++typedef struct _virSaveCookieCallbacks virSaveCookieCallbacks;
++typedef virSaveCookieCallbacks *virSaveCookieCallbacksPtr;
++struct _virSaveCookieCallbacks {
++ virSaveCookieParseFunc parse;
++ virSaveCookieFormatFunc format;
++};
++
++
++int
++virSaveCookieParse(xmlXPathContextPtr ctxt,
++ virObjectPtr *obj,
++ virSaveCookieCallbacksPtr saveCookie);
++
++int
++virSaveCookieParseString(const char *xml,
++ virObjectPtr *obj,
++ virSaveCookieCallbacksPtr saveCookie);
++
++int
++virSaveCookieFormatBuf(virBufferPtr buf,
++ virObjectPtr obj,
++ virSaveCookieCallbacksPtr saveCookie);
++
++char *
++virSaveCookieFormat(virObjectPtr obj,
++ virSaveCookieCallbacksPtr saveCookie);
++
++#endif /*__VIR_SAVE_COOKIE_H__ */
+diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
+index a578dfba34..b4769080e8 100644
+--- a/src/libvirt_private.syms
++++ b/src/libvirt_private.syms
+@@ -971,6 +971,13 @@ virNWFilterObjTestUnassignDef;
+ virNWFilterObjUnlock;
+
+
++# conf/virsavecookie.h
++virSaveCookieFormat;
++virSaveCookieFormatBuf;
++virSaveCookieParse;
++virSaveCookieParseString;
++
++
+ # conf/virsecretobj.h
+ virSecretLoadAllConfigs;
+ virSecretObjDeleteConfig;
+--
+2.13.1
+
diff --git a/SOURCES/libvirt-conf-Make-error-reporting-in-virCPUDefIsEqual-optional.patch b/SOURCES/libvirt-conf-Make-error-reporting-in-virCPUDefIsEqual-optional.patch
new file mode 100644
index 0000000..7e24d8f
--- /dev/null
+++ b/SOURCES/libvirt-conf-Make-error-reporting-in-virCPUDefIsEqual-optional.patch
@@ -0,0 +1,213 @@
+From c1ad40f4ad3813ff3013efba80983f62113fc092 Mon Sep 17 00:00:00 2001
+Message-Id:
+From: Jiri Denemark
+Date: Wed, 31 May 2017 16:42:42 +0200
+Subject: [PATCH] conf: Make error reporting in virCPUDefIsEqual optional
+
+The function will be used in paths where mismatching CPU defs are not an
+error.
+
+Signed-off-by: Jiri Denemark
+Reviewed-by: Pavel Hrdina
+(cherry picked from commit 25ec7f6fe959f2811bb014a8c1f0c92bdf9ca13d)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1441662
+
+Signed-off-by: Jiri Denemark
+---
+ src/conf/cpu_conf.c | 83 +++++++++++++++++++++++---------------------------
+ src/conf/cpu_conf.h | 3 +-
+ src/conf/domain_conf.c | 2 +-
+ 3 files changed, 41 insertions(+), 47 deletions(-)
+
+diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c
+index a4be5742e3..ffb2e83d67 100644
+--- a/src/conf/cpu_conf.c
++++ b/src/conf/cpu_conf.c
+@@ -811,7 +811,8 @@ virCPUDefAddFeature(virCPUDefPtr def,
+
+ bool
+ virCPUDefIsEqual(virCPUDefPtr src,
+- virCPUDefPtr dst)
++ virCPUDefPtr dst,
++ bool reportError)
+ {
+ bool identical = false;
+ size_t i;
+@@ -819,98 +820,89 @@ virCPUDefIsEqual(virCPUDefPtr src,
+ if (!src && !dst)
+ return true;
+
++#define MISMATCH(fmt, ...) \
++ if (reportError) \
++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, fmt, __VA_ARGS__)
++
+ if ((src && !dst) || (!src && dst)) {
+- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+- _("Target CPU does not match source"));
++ MISMATCH("%s", _("Target CPU does not match source"));
+ goto cleanup;
+ }
+
+ if (src->type != dst->type) {
+- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+- _("Target CPU type %s does not match source %s"),
+- virCPUTypeToString(dst->type),
+- virCPUTypeToString(src->type));
++ MISMATCH(_("Target CPU type %s does not match source %s"),
++ virCPUTypeToString(dst->type),
++ virCPUTypeToString(src->type));
+ goto cleanup;
+ }
+
+ if (src->mode != dst->mode) {
+- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+- _("Target CPU mode %s does not match source %s"),
+- virCPUModeTypeToString(dst->mode),
+- virCPUModeTypeToString(src->mode));
++ MISMATCH(_("Target CPU mode %s does not match source %s"),
++ virCPUModeTypeToString(dst->mode),
++ virCPUModeTypeToString(src->mode));
+ goto cleanup;
+ }
+
+ if (src->arch != dst->arch) {
+- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+- _("Target CPU arch %s does not match source %s"),
+- virArchToString(dst->arch),
+- virArchToString(src->arch));
++ MISMATCH(_("Target CPU arch %s does not match source %s"),
++ virArchToString(dst->arch),
++ virArchToString(src->arch));
+ goto cleanup;
+ }
+
+ if (STRNEQ_NULLABLE(src->model, dst->model)) {
+- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+- _("Target CPU model %s does not match source %s"),
+- NULLSTR(dst->model), NULLSTR(src->model));
++ MISMATCH(_("Target CPU model %s does not match source %s"),
++ NULLSTR(dst->model), NULLSTR(src->model));
+ goto cleanup;
+ }
+
+ if (STRNEQ_NULLABLE(src->vendor, dst->vendor)) {
+- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+- _("Target CPU vendor %s does not match source %s"),
+- NULLSTR(dst->vendor), NULLSTR(src->vendor));
++ MISMATCH(_("Target CPU vendor %s does not match source %s"),
++ NULLSTR(dst->vendor), NULLSTR(src->vendor));
+ goto cleanup;
+ }
+
+ if (STRNEQ_NULLABLE(src->vendor_id, dst->vendor_id)) {
+- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+- _("Target CPU vendor id %s does not match source %s"),
+- NULLSTR(dst->vendor_id), NULLSTR(src->vendor_id));
++ MISMATCH(_("Target CPU vendor id %s does not match source %s"),
++ NULLSTR(dst->vendor_id), NULLSTR(src->vendor_id));
+ goto cleanup;
+ }
+
+ if (src->sockets != dst->sockets) {
+- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+- _("Target CPU sockets %d does not match source %d"),
+- dst->sockets, src->sockets);
++ MISMATCH(_("Target CPU sockets %d does not match source %d"),
++ dst->sockets, src->sockets);
+ goto cleanup;
+ }
+
+ if (src->cores != dst->cores) {
+- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+- _("Target CPU cores %d does not match source %d"),
+- dst->cores, src->cores);
++ MISMATCH(_("Target CPU cores %d does not match source %d"),
++ dst->cores, src->cores);
+ goto cleanup;
+ }
+
+ if (src->threads != dst->threads) {
+- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+- _("Target CPU threads %d does not match source %d"),
+- dst->threads, src->threads);
++ MISMATCH(_("Target CPU threads %d does not match source %d"),
++ dst->threads, src->threads);
+ goto cleanup;
+ }
+
+ if (src->nfeatures != dst->nfeatures) {
+- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+- _("Target CPU feature count %zu does not match source %zu"),
+- dst->nfeatures, src->nfeatures);
++ MISMATCH(_("Target CPU feature count %zu does not match source %zu"),
++ dst->nfeatures, src->nfeatures);
+ goto cleanup;
+ }
+
+ for (i = 0; i < src->nfeatures; i++) {
+ if (STRNEQ(src->features[i].name, dst->features[i].name)) {
+- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+- _("Target CPU feature %s does not match source %s"),
+- dst->features[i].name, src->features[i].name);
++ MISMATCH(_("Target CPU feature %s does not match source %s"),
++ dst->features[i].name, src->features[i].name);
+ goto cleanup;
+ }
+
+ if (src->features[i].policy != dst->features[i].policy) {
+- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+- _("Target CPU feature policy %s does not match source %s"),
+- virCPUFeaturePolicyTypeToString(dst->features[i].policy),
+- virCPUFeaturePolicyTypeToString(src->features[i].policy));
++ MISMATCH(_("Target CPU feature policy %s does not match source %s"),
++ virCPUFeaturePolicyTypeToString(dst->features[i].policy),
++ virCPUFeaturePolicyTypeToString(src->features[i].policy));
+ goto cleanup;
+ }
+ }
+@@ -920,11 +912,12 @@ virCPUDefIsEqual(virCPUDefPtr src,
+ (src->cache && dst->cache &&
+ (src->cache->level != dst->cache->level ||
+ src->cache->mode != dst->cache->mode))) {
+- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+- _("Target CPU cache does not match source"));
++ MISMATCH("%s", _("Target CPU cache does not match source"));
+ goto cleanup;
+ }
+
++#undef MISMATCH
++
+ identical = true;
+
+ cleanup:
+diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h
+index 09438b68b4..b0d891552a 100644
+--- a/src/conf/cpu_conf.h
++++ b/src/conf/cpu_conf.h
+@@ -189,7 +189,8 @@ virCPUDefParseXML(xmlNodePtr node,
+
+ bool
+ virCPUDefIsEqual(virCPUDefPtr src,
+- virCPUDefPtr dst);
++ virCPUDefPtr dst,
++ bool reportError);
+
+ char *
+ virCPUDefFormat(virCPUDefPtr def,
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index bab85c6362..2197330a22 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -20042,7 +20042,7 @@ virDomainDefCheckABIStabilityFlags(virDomainDefPtr src,
+ goto error;
+ }
+
+- if (!virCPUDefIsEqual(src->cpu, dst->cpu))
++ if (!virCPUDefIsEqual(src->cpu, dst->cpu, true))
+ goto error;
+
+ if (!virSysinfoIsEqual(src->sysinfo, dst->sysinfo))
+--
+2.13.1
+
diff --git a/SOURCES/libvirt-conf-Make-virDomainSnapshotDefFormat-easier-to-read.patch b/SOURCES/libvirt-conf-Make-virDomainSnapshotDefFormat-easier-to-read.patch
new file mode 100644
index 0000000..5ed7558
--- /dev/null
+++ b/SOURCES/libvirt-conf-Make-virDomainSnapshotDefFormat-easier-to-read.patch
@@ -0,0 +1,113 @@
+From d1adb920ad7f460e32b1cc68e68120b3c655bc18 Mon Sep 17 00:00:00 2001
+Message-Id:
+From: Jiri Denemark
+Date: Thu, 1 Jun 2017 15:57:55 +0200
+Subject: [PATCH] conf: Make virDomainSnapshotDefFormat easier to read
+
+Signed-off-by: Jiri Denemark
+Reviewed-by: Pavel Hrdina
+(cherry picked from commit 00968dca967f4bf9d4f496e5c971bff3f8147ed8)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1441662
+
+Signed-off-by: Jiri Denemark
+---
+ src/conf/snapshot_conf.c | 30 +++++++++++++++++++++---------
+ 1 file changed, 21 insertions(+), 9 deletions(-)
+
+diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c
+index b6cba5ac38..7daa9b22ad 100644
+--- a/src/conf/snapshot_conf.c
++++ b/src/conf/snapshot_conf.c
+@@ -686,11 +686,13 @@ virDomainSnapshotDiskDefFormat(virBufferPtr buf,
+ virBufferAddLit(buf, "\n");
+ }
+
+-char *virDomainSnapshotDefFormat(const char *domain_uuid,
+- virDomainSnapshotDefPtr def,
+- virCapsPtr caps,
+- unsigned int flags,
+- int internal)
++
++char *
++virDomainSnapshotDefFormat(const char *domain_uuid,
++ virDomainSnapshotDefPtr def,
++ virCapsPtr caps,
++ unsigned int flags,
++ int internal)
+ {
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ size_t i;
+@@ -702,12 +704,14 @@ char *virDomainSnapshotDefFormat(const char *domain_uuid,
+
+ virBufferAddLit(&buf, "\n");
+ virBufferAdjustIndent(&buf, 2);
++
+ virBufferEscapeString(&buf, "%s\n", def->name);
+ if (def->description)
+ virBufferEscapeString(&buf, "%s\n",
+ def->description);
+ virBufferAsprintf(&buf, "%s\n",
+ virDomainSnapshotStateTypeToString(def->state));
++
+ if (def->parent) {
+ virBufferAddLit(&buf, "\n");
+ virBufferAdjustIndent(&buf, 2);
+@@ -715,14 +719,17 @@ char *virDomainSnapshotDefFormat(const char *domain_uuid,
+ virBufferAdjustIndent(&buf, -2);
+ virBufferAddLit(&buf, "\n");
+ }
++
+ virBufferAsprintf(&buf, "%lld\n",
+ def->creationTime);
++
+ if (def->memory) {
+ virBufferAsprintf(&buf, "memory));
+ virBufferEscapeString(&buf, " file='%s'", def->file);
+ virBufferAddLit(&buf, "/>\n");
+ }
++
+ if (def->ndisks) {
+ virBufferAddLit(&buf, "\n");
+ virBufferAdjustIndent(&buf, 2);
+@@ -731,11 +738,10 @@ char *virDomainSnapshotDefFormat(const char *domain_uuid,
+ virBufferAdjustIndent(&buf, -2);
+ virBufferAddLit(&buf, "\n");
+ }
++
+ if (def->dom) {
+- if (virDomainDefFormatInternal(def->dom, caps, flags, &buf) < 0) {
+- virBufferFreeAndReset(&buf);
+- return NULL;
+- }
++ if (virDomainDefFormatInternal(def->dom, caps, flags, &buf) < 0)
++ goto error;
+ } else if (domain_uuid) {
+ virBufferAddLit(&buf, "\n");
+ virBufferAdjustIndent(&buf, 2);
+@@ -743,8 +749,10 @@ char *virDomainSnapshotDefFormat(const char *domain_uuid,
+ virBufferAdjustIndent(&buf, -2);
+ virBufferAddLit(&buf, "\n");
+ }
++
+ if (internal)
+ virBufferAsprintf(&buf, "%d\n", def->current);
++
+ virBufferAdjustIndent(&buf, -2);
+ virBufferAddLit(&buf, "\n");
+
+@@ -752,6 +760,10 @@ char *virDomainSnapshotDefFormat(const char *domain_uuid,
+ return NULL;
+
+ return virBufferContentAndReset(&buf);
++
++ error:
++ virBufferFreeAndReset(&buf);
++ return NULL;
+ }
+
+ /* Snapshot Obj functions */
+--
+2.13.1
+
diff --git a/SOURCES/libvirt-conf-Move-index-number-checking-to-drivers.patch b/SOURCES/libvirt-conf-Move-index-number-checking-to-drivers.patch
new file mode 100644
index 0000000..52cbf17
--- /dev/null
+++ b/SOURCES/libvirt-conf-Move-index-number-checking-to-drivers.patch
@@ -0,0 +1,101 @@
+From 711a3ca4a1c0c9bc31a98cd6afcedeb3107157c8 Mon Sep 17 00:00:00 2001
+Message-Id: <711a3ca4a1c0c9bc31a98cd6afcedeb3107157c8@dist-git>
+From: Andrea Bolognani
+Date: Mon, 17 Jul 2017 12:09:06 +0200
+Subject: [PATCH] conf: Move index number checking to drivers
+
+pSeries guests will soon be allowed to have multiple
+PHBs (pci-root controllers), which of course means that
+all but one of them will have a non-zero index; hence,
+we'll need to relax the current check.
+
+However, right now the check is performed in the conf
+module, which is generic rather than tied to the QEMU
+driver, and where we don't have information such as the
+guest machine type available.
+
+To make this change of behavior possible down the line,
+we need to move the check from the XML parser to the
+drivers. Luckily, only QEMU and bhyve are using PCI
+controllers, so this doesn't result in much duplication.
+
+Signed-off-by: Andrea Bolognani
+Reviewed-by: Laine Stump
+(cherry picked from commit 620c390c7308f61027cf28000fcfcfcb01e3ae89)
+
+Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1431193
+
+Signed-off-by: Andrea Bolognani
+Signed-off-by: Jiri Denemark
+---
+ src/bhyve/bhyve_domain.c | 15 +++++++++++++++
+ src/conf/domain_conf.c | 6 ------
+ src/qemu/qemu_domain.c | 9 +++++++++
+ 3 files changed, 24 insertions(+), 6 deletions(-)
+
+diff --git a/src/bhyve/bhyve_domain.c b/src/bhyve/bhyve_domain.c
+index 20c82937b5..71764554eb 100644
+--- a/src/bhyve/bhyve_domain.c
++++ b/src/bhyve/bhyve_domain.c
+@@ -122,6 +122,21 @@ bhyveDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
+ bhyveDomainDiskDefAssignAddress(driver, disk, def) < 0)
+ return -1;
+ }
++
++ if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) {
++ virDomainControllerDefPtr cont = dev->data.controller;
++
++ if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI &&
++ (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT ||
++ cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) &&
++ cont->idx != 0) {
++ virReportError(VIR_ERR_XML_ERROR, "%s",
++ _("pci-root and pcie-root controllers "
++ "should have index 0"));
++ return -1;
++ }
++ }
++
+ return 0;
+ }
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index d8ca25da38..8e5c487df8 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -9157,12 +9157,6 @@ virDomainControllerDefParseXML(xmlNodePtr node,
+ "have an address"));
+ goto error;
+ }
+- if (def->idx > 0) {
+- virReportError(VIR_ERR_XML_ERROR, "%s",
+- _("pci-root and pcie-root controllers "
+- "should have index 0"));
+- goto error;
+- }
+ if ((rc = virDomainParseScaledValue("./pcihole64", NULL,
+ ctxt, &bytes, 1024,
+ 1024ULL * ULONG_MAX, false)) < 0)
+diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
+index 1528c6a137..87a437eccf 100644
+--- a/src/qemu/qemu_domain.c
++++ b/src/qemu/qemu_domain.c
+@@ -3378,6 +3378,15 @@ qemuDomainControllerDefPostParse(virDomainControllerDefPtr cont,
+ break;
+
+ case VIR_DOMAIN_CONTROLLER_TYPE_PCI:
++ if ((cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT ||
++ cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) &&
++ cont->idx != 0) {
++ virReportError(VIR_ERR_XML_ERROR, "%s",
++ _("pci-root and pcie-root controllers "
++ "should have index 0"));
++ return -1;
++ }
++
+ if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS &&
+ !qemuDomainIsI440FX(def)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+--
+2.13.3
+
diff --git a/SOURCES/libvirt-conf-Move-target-index-validation.patch b/SOURCES/libvirt-conf-Move-target-index-validation.patch
new file mode 100644
index 0000000..6c37fc1
--- /dev/null
+++ b/SOURCES/libvirt-conf-Move-target-index-validation.patch
@@ -0,0 +1,93 @@
+From 3e5618223a9e21597ed9e95edfc79139563be301 Mon Sep 17 00:00:00 2001
+Message-Id: <3e5618223a9e21597ed9e95edfc79139563be301@dist-git>
+From: Andrea Bolognani
+Date: Mon, 21 Aug 2017 14:46:38 +0200
+Subject: [PATCH] conf: Move target index validation
+
+Validation should happen after parsing, so the proper
+location for it is virDomainControllerDefValidate()
+rather than virDomainControllerDefParseXML().
+
+Signed-off-by: Andrea Bolognani
+(cherry picked from commit c9d75d655ae73693a08123aca75677caf579f9e9)
+
+Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1479647
+
+Signed-off-by: Andrea Bolognani
+Signed-off-by: Jiri Denemark
+---
+ src/conf/domain_conf.c | 40 ++++++++++++++++++++++++----------------
+ 1 file changed, 24 insertions(+), 16 deletions(-)
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 7ba2bc01ca..7889f5335c 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -5046,12 +5046,34 @@ static int
+ virDomainControllerDefValidate(const virDomainControllerDef *controller)
+ {
+ if (controller->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) {
++ const virDomainPCIControllerOpts *opts = &controller->opts.pciopts;
++
+ if (controller->idx > 255) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("PCI controller index %d too high, maximum is 255"),
+ controller->idx);
+ return -1;
+ }
++
++ /* Only validate the target index if it's been set */
++ if (opts->targetIndex != -1) {
++
++ if (opts->targetIndex < 0 || opts->targetIndex > 31) {
++ virReportError(VIR_ERR_XML_ERROR,
++ _("PCI controller target index '%d' out of "
++ "range - must be 0-31"),
++ opts->targetIndex);
++ return -1;
++ }
++
++ if ((controller->idx == 0 && opts->targetIndex != 0) ||
++ (controller->idx != 0 && opts->targetIndex == 0)) {
++ virReportError(VIR_ERR_XML_ERROR, "%s",
++ _("Only the PCI controller with index 0 can "
++ "have target index 0, and vice versa"));
++ return -1;
++ }
++ }
+ }
+ return 0;
+ }
+@@ -9292,27 +9314,13 @@ virDomainControllerDefParseXML(xmlNodePtr node,
+ }
+ if (targetIndex) {
+ if (virStrToLong_i(targetIndex, NULL, 0,
+- &def->opts.pciopts.targetIndex) < 0) {
++ &def->opts.pciopts.targetIndex) < 0 ||
++ def->opts.pciopts.targetIndex == -1) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid target index '%s' in PCI controller"),
+ targetIndex);
+ goto error;
+ }
+- if (def->opts.pciopts.targetIndex < 0 ||
+- def->opts.pciopts.targetIndex > 31) {
+- virReportError(VIR_ERR_XML_ERROR,
+- _("PCI controller target index '%s' out of "
+- "range - must be 0-31"),
+- targetIndex);
+- goto error;
+- }
+- if ((def->idx == 0 && def->opts.pciopts.targetIndex != 0) ||
+- (def->idx != 0 && def->opts.pciopts.targetIndex == 0)) {
+- virReportError(VIR_ERR_XML_ERROR, "%s",
+- _("Only the PCI controller with index 0 can "
+- "have target index 0, and vice versa"));
+- goto error;
+- }
+ }
+ if (numaNode >= 0) {
+ if (def->idx == 0) {
+--
+2.14.1
+
diff --git a/SOURCES/libvirt-conf-Move-virDomainPCIAddressBusIsFullyReserved.patch b/SOURCES/libvirt-conf-Move-virDomainPCIAddressBusIsFullyReserved.patch
new file mode 100644
index 0000000..838066c
--- /dev/null
+++ b/SOURCES/libvirt-conf-Move-virDomainPCIAddressBusIsFullyReserved.patch
@@ -0,0 +1,115 @@
+From 9d0d053dc7f8af8ebb3c7fbb3a11335e4b50717b Mon Sep 17 00:00:00 2001
+Message-Id: <9d0d053dc7f8af8ebb3c7fbb3a11335e4b50717b@dist-git>
+From: Andrea Bolognani
+Date: Mon, 17 Jul 2017 12:08:58 +0200
+Subject: [PATCH] conf: Move virDomainPCIAddressBusIsFullyReserved()
+
+This function was private to the QEMU driver and was,
+accordingly, called qemuDomainPCIBusFullyReserved().
+
+However the function is really not QEMU-specific at
+all, so it makes sense to move it closer to the
+virDomainPCIAddressBus struct it operates on.
+
+Signed-off-by: Andrea Bolognani
+Reviewed-by: Laine Stump
+(cherry picked from commit c79f97c83ce1421f79756a9a344e8e77ceeeb1d8)
+
+Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1431193
+
+Signed-off-by: Andrea Bolognani
+Signed-off-by: Jiri Denemark
+---
+ src/conf/domain_addr.c | 14 ++++++++++++++
+ src/conf/domain_addr.h | 3 +++
+ src/libvirt_private.syms | 1 +
+ src/qemu/qemu_domain_address.c | 15 +--------------
+ 4 files changed, 19 insertions(+), 14 deletions(-)
+
+diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
+index 639168effa..0ae1ed93af 100644
+--- a/src/conf/domain_addr.c
++++ b/src/conf/domain_addr.c
+@@ -355,6 +355,20 @@ virDomainPCIAddressBusSetModel(virDomainPCIAddressBusPtr bus,
+ }
+
+
++bool
++virDomainPCIAddressBusIsFullyReserved(virDomainPCIAddressBusPtr bus)
++{
++ size_t i;
++
++ for (i = bus->minSlot; i <= bus->maxSlot; i++) {
++ if (!bus->slot[i].functions)
++ return false;
++ }
++
++ return true;
++}
++
++
+ /* Ensure addr fits in the address set, by expanding it if needed
+ *
+ * Return value:
+diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h
+index f884b8af2b..c90a335919 100644
+--- a/src/conf/domain_addr.h
++++ b/src/conf/domain_addr.h
+@@ -141,6 +141,9 @@ int virDomainPCIAddressBusSetModel(virDomainPCIAddressBusPtr bus,
+ virDomainControllerModelPCI model)
+ ATTRIBUTE_NONNULL(1);
+
++bool virDomainPCIAddressBusIsFullyReserved(virDomainPCIAddressBusPtr bus)
++ ATTRIBUTE_NONNULL(1);
++
+ bool virDomainPCIAddressSlotInUse(virDomainPCIAddressSetPtr addrs,
+ virPCIDeviceAddressPtr addr)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
+index 9c596e3f1c..7876ffb208 100644
+--- a/src/libvirt_private.syms
++++ b/src/libvirt_private.syms
+@@ -105,6 +105,7 @@ virDomainCCWAddressSetFree;
+ virDomainCCWAddressValidate;
+ virDomainGetBlkioParametersAssignFromDef;
+ virDomainPCIAddressAsString;
++virDomainPCIAddressBusIsFullyReserved;
+ virDomainPCIAddressBusSetModel;
+ virDomainPCIAddressEnsureAddr;
+ virDomainPCIAddressFlagsCompatible;
+diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
+index 3da6b7369d..ff57edb564 100644
+--- a/src/qemu/qemu_domain_address.c
++++ b/src/qemu/qemu_domain_address.c
+@@ -1494,19 +1494,6 @@ qemuDomainValidateDevicePCISlotsChipsets(virDomainDefPtr def,
+ }
+
+
+-static bool
+-qemuDomainPCIBusFullyReserved(virDomainPCIAddressBusPtr bus)
+-{
+- size_t i;
+-
+- for (i = bus->minSlot; i <= bus->maxSlot; i++)
+- if (!bus->slot[i].functions)
+- return false;
+-
+- return true;
+-}
+-
+-
+ /*
+ * This assigns static PCI slots to all configured devices.
+ * The ordering here is chosen to match the ordering used
+@@ -2038,7 +2025,7 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
+ bool buses_reserved = true;
+
+ for (i = 0; i < addrs->nbuses; i++) {
+- if (!qemuDomainPCIBusFullyReserved(&addrs->buses[i])) {
++ if (!virDomainPCIAddressBusIsFullyReserved(&addrs->buses[i])) {
+ buses_reserved = false;
+ break;
+ }
+--
+2.13.3
+
diff --git a/SOURCES/libvirt-conf-Parse-and-format-target-index.patch b/SOURCES/libvirt-conf-Parse-and-format-target-index.patch
new file mode 100644
index 0000000..fcc68a5
--- /dev/null
+++ b/SOURCES/libvirt-conf-Parse-and-format-target-index.patch
@@ -0,0 +1,161 @@
+From 4c2b1b9cf0bcd8af7a7d011cd758bb6f11e5477b Mon Sep 17 00:00:00 2001
+Message-Id: <4c2b1b9cf0bcd8af7a7d011cd758bb6f11e5477b@dist-git>
+From: Andrea Bolognani
+Date: Mon, 17 Jul 2017 12:09:09 +0200
+Subject: [PATCH] conf: Parse and format
+
+Signed-off-by: Andrea Bolognani
+Reviewed-by: Laine Stump
+(cherry picked from commit 47dd6e282ab8b0db662092cf0cc53163d805ac4d)
+
+Conflicts:
+ * src/conf/domain_conf.c:
+
+ caused by e146264aaadf5aecf727d8c7b3d85683b55b6c48,
+ which significantly refactored
+ virDomainControllerDefFormat(), not being in the tree.
+
+Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1431193
+
+Signed-off-by: Andrea Bolognani
+Signed-off-by: Jiri Denemark
+---
+ docs/formatdomain.html.in | 6 ++++++
+ docs/schemas/domaincommon.rng | 5 +++++
+ src/conf/domain_conf.c | 32 ++++++++++++++++++++++++++++++++
+ src/conf/domain_conf.h | 1 +
+ 4 files changed, 44 insertions(+)
+
+diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
+index dc8e7d2dc7..bc67a53408 100644
+--- a/docs/formatdomain.html.in
++++ b/docs/formatdomain.html.in
+@@ -3760,6 +3760,12 @@
+ libvirt API to attach host devices to the correct
+ pci-expander-bus when assigning them to the domain).
+
++
index
++
++ pci-root controllers for pSeries guests use this attribute to
++ record the order they will show up in the guest.
++ Since 3.6.0
++
+
+
+ For machine types which provide an implicit PCI bus, the pci-root
+diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
+index 964e5c5bd5..b1461d4c61 100644
+--- a/docs/schemas/domaincommon.rng
++++ b/docs/schemas/domaincommon.rng
+@@ -1945,6 +1945,11 @@
+
+
+
++
++
++
++
++
+
+
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 8a030c9b68..599db5cafe 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -1854,6 +1854,7 @@ virDomainControllerDefNew(virDomainControllerType type)
+ def->opts.pciopts.chassis = -1;
+ def->opts.pciopts.port = -1;
+ def->opts.pciopts.busNr = -1;
++ def->opts.pciopts.targetIndex = -1;
+ def->opts.pciopts.numaNode = -1;
+ break;
+ case VIR_DOMAIN_CONTROLLER_TYPE_IDE:
+@@ -8964,6 +8965,7 @@ virDomainControllerDefParseXML(xmlNodePtr node,
+ char *chassis = NULL;
+ char *port = NULL;
+ char *busNr = NULL;
++ char *targetIndex = NULL;
+ int numaNode = -1;
+ char *ioeventfd = NULL;
+ char *portsStr = NULL;
+@@ -9036,6 +9038,7 @@ virDomainControllerDefParseXML(xmlNodePtr node,
+ chassis = virXMLPropString(cur, "chassis");
+ port = virXMLPropString(cur, "port");
+ busNr = virXMLPropString(cur, "busNr");
++ targetIndex = virXMLPropString(cur, "index");
+ processedTarget = true;
+ }
+ }
+@@ -9254,6 +9257,30 @@ virDomainControllerDefParseXML(xmlNodePtr node,
+ goto error;
+ }
+ }
++ if (targetIndex) {
++ if (virStrToLong_i(targetIndex, NULL, 0,
++ &def->opts.pciopts.targetIndex) < 0) {
++ virReportError(VIR_ERR_XML_ERROR,
++ _("Invalid target index '%s' in PCI controller"),
++ targetIndex);
++ goto error;
++ }
++ if (def->opts.pciopts.targetIndex < 0 ||
++ def->opts.pciopts.targetIndex > 31) {
++ virReportError(VIR_ERR_XML_ERROR,
++ _("PCI controller target index '%s' out of "
++ "range - must be 0-31"),
++ targetIndex);
++ goto error;
++ }
++ if ((def->idx == 0 && def->opts.pciopts.targetIndex != 0) ||
++ (def->idx != 0 && def->opts.pciopts.targetIndex == 0)) {
++ virReportError(VIR_ERR_XML_ERROR, "%s",
++ _("Only the PCI controller with index 0 can "
++ "have target index 0, and vice versa"));
++ goto error;
++ }
++ }
+ if (numaNode >= 0)
+ def->opts.pciopts.numaNode = numaNode;
+ break;
+@@ -9275,6 +9302,7 @@ virDomainControllerDefParseXML(xmlNodePtr node,
+ VIR_FREE(chassis);
+ VIR_FREE(port);
+ VIR_FREE(busNr);
++ VIR_FREE(targetIndex);
+ VIR_FREE(ioeventfd);
+ VIR_FREE(portsStr);
+ VIR_FREE(iothread);
+@@ -21615,6 +21643,7 @@ virDomainControllerDefFormat(virBufferPtr buf,
+ def->opts.pciopts.chassis != -1 ||
+ def->opts.pciopts.port != -1 ||
+ def->opts.pciopts.busNr != -1 ||
++ def->opts.pciopts.targetIndex != -1 ||
+ def->opts.pciopts.numaNode != -1)
+ pciTarget = true;
+ break;
+@@ -21655,6 +21684,9 @@ virDomainControllerDefFormat(virBufferPtr buf,
+ if (def->opts.pciopts.busNr != -1)
+ virBufferAsprintf(buf, " busNr='%d'",
+ def->opts.pciopts.busNr);
++ if (def->opts.pciopts.targetIndex != -1)
++ virBufferAsprintf(buf, " index='%d'",
++ def->opts.pciopts.targetIndex);
+ if (def->opts.pciopts.numaNode == -1) {
+ virBufferAddLit(buf, "/>\n");
+ } else {
+diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
+index e287e6d7f3..50fdc6e2a6 100644
+--- a/src/conf/domain_conf.h
++++ b/src/conf/domain_conf.h
+@@ -786,6 +786,7 @@ struct _virDomainPCIControllerOpts {
+ int chassis;
+ int port;
+ int busNr; /* used by pci-expander-bus, -1 == unspecified */
++ int targetIndex; /* used by spapr-pci-host-bridge, -1 == unspecified */
+ /* numaNode is a *subelement* of target (to match existing
+ * item in memory target config) -1 == unspecified
+ */
+--
+2.13.3
+
diff --git a/SOURCES/libvirt-conf-Pass-xmlopt-to-virDomainSnapshotDefFormat.patch b/SOURCES/libvirt-conf-Pass-xmlopt-to-virDomainSnapshotDefFormat.patch
new file mode 100644
index 0000000..d546c53
--- /dev/null
+++ b/SOURCES/libvirt-conf-Pass-xmlopt-to-virDomainSnapshotDefFormat.patch
@@ -0,0 +1,251 @@
+From 49f9421cddc176e39cbb062f26e80ec93341ef0d Mon Sep 17 00:00:00 2001
+Message-Id: <49f9421cddc176e39cbb062f26e80ec93341ef0d@dist-git>
+From: Jiri Denemark
+Date: Fri, 2 Jun 2017 00:27:33 +0200
+Subject: [PATCH] conf: Pass xmlopt to virDomainSnapshotDefFormat
+
+This will be used later when a save cookie will become part of the
+snapshot XML using new driver specific parser/formatter functions.
+
+Signed-off-by: Jiri Denemark
+Reviewed-by: Pavel Hrdina
+(cherry picked from commit 957cd268a98043fe061227a8e829c622a6fb4b86)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1441662
+
+Signed-off-by: Jiri Denemark
+---
+ src/conf/snapshot_conf.c | 1 +
+ src/conf/snapshot_conf.h | 1 +
+ src/esx/esx_driver.c | 2 +-
+ src/qemu/qemu_domain.c | 4 +++-
+ src/qemu/qemu_domain.h | 1 +
+ src/qemu/qemu_driver.c | 16 ++++++++++++----
+ src/test/test_driver.c | 1 +
+ src/vbox/vbox_common.c | 4 ++--
+ src/vz/vz_driver.c | 1 +
+ tests/domainsnapshotxml2xmltest.c | 1 +
+ 10 files changed, 24 insertions(+), 8 deletions(-)
+
+diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c
+index 7daa9b22ad..e3bba985d7 100644
+--- a/src/conf/snapshot_conf.c
++++ b/src/conf/snapshot_conf.c
+@@ -691,6 +691,7 @@ char *
+ virDomainSnapshotDefFormat(const char *domain_uuid,
+ virDomainSnapshotDefPtr def,
+ virCapsPtr caps,
++ virDomainXMLOptionPtr xmlopt ATTRIBUTE_UNUSED,
+ unsigned int flags,
+ int internal)
+ {
+diff --git a/src/conf/snapshot_conf.h b/src/conf/snapshot_conf.h
+index da904f9460..2ce526fa6b 100644
+--- a/src/conf/snapshot_conf.h
++++ b/src/conf/snapshot_conf.h
+@@ -114,6 +114,7 @@ void virDomainSnapshotDefFree(virDomainSnapshotDefPtr def);
+ char *virDomainSnapshotDefFormat(const char *domain_uuid,
+ virDomainSnapshotDefPtr def,
+ virCapsPtr caps,
++ virDomainXMLOptionPtr xmlopt,
+ unsigned int flags,
+ int internal);
+ int virDomainSnapshotAlignDisks(virDomainSnapshotDefPtr snapshot,
+diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c
+index 166d4bcfcc..c4e1f58a0b 100644
+--- a/src/esx/esx_driver.c
++++ b/src/esx/esx_driver.c
+@@ -4282,7 +4282,7 @@ esxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
+
+ virUUIDFormat(snapshot->domain->uuid, uuid_string);
+
+- xml = virDomainSnapshotDefFormat(uuid_string, &def, priv->caps,
++ xml = virDomainSnapshotDefFormat(uuid_string, &def, priv->caps, priv->xmlopt,
+ virDomainDefFormatConvertXMLFlags(flags),
+ 0);
+
+diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
+index 11be085801..09903bdd5f 100644
+--- a/src/qemu/qemu_domain.c
++++ b/src/qemu/qemu_domain.c
+@@ -4794,6 +4794,7 @@ int
+ qemuDomainSnapshotWriteMetadata(virDomainObjPtr vm,
+ virDomainSnapshotObjPtr snapshot,
+ virCapsPtr caps,
++ virDomainXMLOptionPtr xmlopt,
+ char *snapshotDir)
+ {
+ char *newxml = NULL;
+@@ -4804,7 +4805,7 @@ qemuDomainSnapshotWriteMetadata(virDomainObjPtr vm,
+
+ virUUIDFormat(vm->def->uuid, uuidstr);
+ newxml = virDomainSnapshotDefFormat(
+- uuidstr, snapshot->def, caps,
++ uuidstr, snapshot->def, caps, xmlopt,
+ virDomainDefFormatConvertXMLFlags(QEMU_DOMAIN_FORMAT_LIVE_FLAGS),
+ 1);
+ if (newxml == NULL)
+@@ -4965,6 +4966,7 @@ qemuDomainSnapshotDiscard(virQEMUDriverPtr driver,
+ } else {
+ parentsnap->def->current = true;
+ if (qemuDomainSnapshotWriteMetadata(vm, parentsnap, driver->caps,
++ driver->xmlopt,
+ cfg->snapshotDir) < 0) {
+ VIR_WARN("failed to set parent snapshot '%s' as current",
+ snap->def->parent);
+diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
+index 2994398a9e..4db92fac8a 100644
+--- a/src/qemu/qemu_domain.h
++++ b/src/qemu/qemu_domain.h
+@@ -557,6 +557,7 @@ const char *qemuFindQemuImgBinary(virQEMUDriverPtr driver);
+ int qemuDomainSnapshotWriteMetadata(virDomainObjPtr vm,
+ virDomainSnapshotObjPtr snapshot,
+ virCapsPtr caps,
++ virDomainXMLOptionPtr xmlopt,
+ char *snapshotDir);
+
+ int qemuDomainSnapshotForEachQcow2(virQEMUDriverPtr driver,
+diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
+index 354329fe64..2688c3eec7 100644
+--- a/src/qemu/qemu_driver.c
++++ b/src/qemu/qemu_driver.c
+@@ -14650,7 +14650,7 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
+ if (update_current) {
+ vm->current_snapshot->def->current = false;
+ if (qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
+- driver->caps,
++ driver->caps, driver->xmlopt,
+ cfg->snapshotDir) < 0)
+ goto endjob;
+ vm->current_snapshot = NULL;
+@@ -14700,6 +14700,7 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain,
+ endjob:
+ if (snapshot && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA)) {
+ if (qemuDomainSnapshotWriteMetadata(vm, snap, driver->caps,
++ driver->xmlopt,
+ cfg->snapshotDir) < 0) {
+ /* if writing of metadata fails, error out rather than trying
+ * to silently carry on without completing the snapshot */
+@@ -15037,7 +15038,8 @@ qemuDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
+
+ virUUIDFormat(snapshot->domain->uuid, uuidstr);
+
+- xml = virDomainSnapshotDefFormat(uuidstr, snap->def, driver->caps,
++ xml = virDomainSnapshotDefFormat(uuidstr, snap->def,
++ driver->caps, driver->xmlopt,
+ virDomainDefFormatConvertXMLFlags(flags),
+ 0);
+
+@@ -15219,7 +15221,8 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
+ if (vm->current_snapshot) {
+ vm->current_snapshot->def->current = false;
+ if (qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
+- driver->caps, cfg->snapshotDir) < 0)
++ driver->caps, driver->xmlopt,
++ cfg->snapshotDir) < 0)
+ goto endjob;
+ vm->current_snapshot = NULL;
+ /* XXX Should we restore vm->current_snapshot after this point
+@@ -15459,6 +15462,7 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
+ cleanup:
+ if (ret == 0) {
+ if (qemuDomainSnapshotWriteMetadata(vm, snap, driver->caps,
++ driver->xmlopt,
+ cfg->snapshotDir) < 0)
+ ret = -1;
+ else
+@@ -15495,6 +15499,7 @@ struct _virQEMUSnapReparent {
+ virDomainSnapshotObjPtr parent;
+ virDomainObjPtr vm;
+ virCapsPtr caps;
++ virDomainXMLOptionPtr xmlopt;
+ int err;
+ virDomainSnapshotObjPtr last;
+ };
+@@ -15523,7 +15528,8 @@ qemuDomainSnapshotReparentChildren(void *payload,
+ if (!snap->sibling)
+ rep->last = snap;
+
+- rep->err = qemuDomainSnapshotWriteMetadata(rep->vm, snap, rep->caps,
++ rep->err = qemuDomainSnapshotWriteMetadata(rep->vm, snap,
++ rep->caps, rep->xmlopt,
+ rep->cfg->snapshotDir);
+ return 0;
+ }
+@@ -15594,6 +15600,7 @@ qemuDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
+ if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
+ snap->def->current = true;
+ if (qemuDomainSnapshotWriteMetadata(vm, snap, driver->caps,
++ driver->xmlopt,
+ cfg->snapshotDir) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to set snapshot '%s' as current"),
+@@ -15611,6 +15618,7 @@ qemuDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
+ rep.err = 0;
+ rep.last = NULL;
+ rep.caps = driver->caps;
++ rep.xmlopt = driver->xmlopt;
+ virDomainSnapshotForEachChild(snap,
+ qemuDomainSnapshotReparentChildren,
+ &rep);
+diff --git a/src/test/test_driver.c b/src/test/test_driver.c
+index 39df646260..c8085dd797 100644
+--- a/src/test/test_driver.c
++++ b/src/test/test_driver.c
+@@ -6348,6 +6348,7 @@ testDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
+ virUUIDFormat(snapshot->domain->uuid, uuidstr);
+
+ xml = virDomainSnapshotDefFormat(uuidstr, snap->def, privconn->caps,
++ privconn->xmlopt,
+ virDomainDefFormatConvertXMLFlags(flags),
+ 0);
+
+diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c
+index dcc64b579c..c739031660 100644
+--- a/src/vbox/vbox_common.c
++++ b/src/vbox/vbox_common.c
+@@ -5115,7 +5115,7 @@ vboxSnapshotRedefine(virDomainPtr dom,
+ VIR_FREE(currentSnapshotXmlFilePath);
+ if (virAsprintf(¤tSnapshotXmlFilePath, "%s%s.xml", machineLocationPath, snapshotMachineDesc->currentSnapshot) < 0)
+ goto cleanup;
+- char *snapshotContent = virDomainSnapshotDefFormat(NULL, def, data->caps, VIR_DOMAIN_DEF_FORMAT_SECURE, 0);
++ char *snapshotContent = virDomainSnapshotDefFormat(NULL, def, data->caps, data->xmlopt, VIR_DOMAIN_DEF_FORMAT_SECURE, 0);
+ if (snapshotContent == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unable to get snapshot content"));
+@@ -6037,7 +6037,7 @@ static char *vboxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
+
+ virUUIDFormat(dom->uuid, uuidstr);
+ memcpy(def->dom->uuid, dom->uuid, VIR_UUID_BUFLEN);
+- ret = virDomainSnapshotDefFormat(uuidstr, def, data->caps,
++ ret = virDomainSnapshotDefFormat(uuidstr, def, data->caps, data->xmlopt,
+ virDomainDefFormatConvertXMLFlags(flags),
+ 0);
+
+diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c
+index 26c4f48459..f0b6722a6e 100644
+--- a/src/vz/vz_driver.c
++++ b/src/vz/vz_driver.c
+@@ -2309,6 +2309,7 @@ vzDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot, unsigned int flags)
+ virUUIDFormat(snapshot->domain->uuid, uuidstr);
+
+ xml = virDomainSnapshotDefFormat(uuidstr, snap->def, privconn->driver->caps,
++ privconn->driver->xmlopt,
+ virDomainDefFormatConvertXMLFlags(flags),
+ 0);
+
+diff --git a/tests/domainsnapshotxml2xmltest.c b/tests/domainsnapshotxml2xmltest.c
+index f5fec47520..df204f9f16 100644
+--- a/tests/domainsnapshotxml2xmltest.c
++++ b/tests/domainsnapshotxml2xmltest.c
+@@ -101,6 +101,7 @@ testCompareXMLToXMLFiles(const char *inxml,
+ goto cleanup;
+
+ if (!(actual = virDomainSnapshotDefFormat(uuid, def, driver.caps,
++ driver.xmlopt,
+ VIR_DOMAIN_DEF_FORMAT_SECURE,
+ internal)))
+ goto cleanup;
+--
+2.13.1
+
diff --git a/SOURCES/libvirt-conf-Refactor-virCPUDefParseXML.patch b/SOURCES/libvirt-conf-Refactor-virCPUDefParseXML.patch
new file mode 100644
index 0000000..eaa2ab7
--- /dev/null
+++ b/SOURCES/libvirt-conf-Refactor-virCPUDefParseXML.patch
@@ -0,0 +1,413 @@
+From 7bdac52dd6979f76f9a75a404a76e79f7da11a06 Mon Sep 17 00:00:00 2001
+Message-Id: <7bdac52dd6979f76f9a75a404a76e79f7da11a06@dist-git>
+From: Jiri Denemark
+Date: Tue, 23 May 2017 09:29:36 +0200
+Subject: [PATCH] conf: Refactor virCPUDefParseXML
+
+Signed-off-by: Jiri Denemark
+Reviewed-by: Pavel Hrdina
+(cherry picked from commit 702013f3b3ad8bd28c326058e2dd9ea8afbd1e61)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1441662
+
+Signed-off-by: Jiri Denemark
+---
+ src/conf/cpu_conf.c | 109 +++++++++++++++++++++++++++----------------------
+ src/conf/cpu_conf.h | 9 ++--
+ src/conf/domain_conf.c | 12 +-----
+ src/cpu/cpu.c | 5 +--
+ tests/cputest.c | 5 +--
+ 5 files changed, 72 insertions(+), 68 deletions(-)
+
+diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c
+index ffb2e83d67..da40e9ba97 100644
+--- a/src/conf/cpu_conf.c
++++ b/src/conf/cpu_conf.c
+@@ -245,12 +245,25 @@ virCPUDefCopy(const virCPUDef *cpu)
+ }
+
+
+-virCPUDefPtr
+-virCPUDefParseXML(xmlNodePtr node,
+- xmlXPathContextPtr ctxt,
+- virCPUType type)
++/*
++ * Parses CPU definition XML from a node pointed to by @xpath. If @xpath is
++ * NULL, the current node of @ctxt is used (i.e., it is a shortcut to ".").
++ *
++ * Missing element in the XML document is not considered an error unless
++ * @xpath is NULL in which case the function expects it was provided with a
++ * valid element already. In other words, the function returns success
++ * and sets @cpu to NULL if @xpath is not NULL and the node pointed to by
++ * @xpath is not found.
++ *
++ * Returns 0 on success, -1 on error.
++ */
++int
++virCPUDefParseXML(xmlXPathContextPtr ctxt,
++ const char *xpath,
++ virCPUType type,
++ virCPUDefPtr *cpu)
+ {
+- virCPUDefPtr def;
++ virCPUDefPtr def = NULL;
+ xmlNodePtr *nodes = NULL;
+ xmlNodePtr oldnode = ctxt->node;
+ int n;
+@@ -258,15 +271,23 @@ virCPUDefParseXML(xmlNodePtr node,
+ char *cpuMode;
+ char *fallback = NULL;
+ char *vendor_id = NULL;
++ int ret = -1;
+
+- if (!xmlStrEqual(node->name, BAD_CAST "cpu")) {
++ *cpu = NULL;
++
++ if (xpath && !(ctxt->node = virXPathNode(xpath, ctxt))) {
++ ret = 0;
++ goto cleanup;
++ }
++
++ if (!xmlStrEqual(ctxt->node->name, BAD_CAST "cpu")) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("XML does not contain expected 'cpu' element"));
+- return NULL;
++ goto cleanup;
+ }
+
+ if (VIR_ALLOC(def) < 0)
+- return NULL;
++ goto cleanup;
+
+ if (type == VIR_CPU_TYPE_AUTO) {
+ if (virXPathBoolean("boolean(./arch)", ctxt)) {
+@@ -274,7 +295,7 @@ virCPUDefParseXML(xmlNodePtr node,
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("'arch' element cannot be used inside 'cpu'"
+ " element with 'match' attribute'"));
+- goto error;
++ goto cleanup;
+ }
+ def->type = VIR_CPU_TYPE_HOST;
+ } else {
+@@ -284,12 +305,12 @@ virCPUDefParseXML(xmlNodePtr node,
+ def->type = type;
+ }
+
+- if ((cpuMode = virXMLPropString(node, "mode"))) {
++ if ((cpuMode = virXMLPropString(ctxt->node, "mode"))) {
+ if (def->type == VIR_CPU_TYPE_HOST) {
+ VIR_FREE(cpuMode);
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Attribute mode is only allowed for guest CPU"));
+- goto error;
++ goto cleanup;
+ } else {
+ def->mode = virCPUModeTypeFromString(cpuMode);
+
+@@ -298,7 +319,7 @@ virCPUDefParseXML(xmlNodePtr node,
+ _("Invalid mode attribute '%s'"),
+ cpuMode);
+ VIR_FREE(cpuMode);
+- goto error;
++ goto cleanup;
+ }
+ VIR_FREE(cpuMode);
+ }
+@@ -310,7 +331,7 @@ virCPUDefParseXML(xmlNodePtr node,
+ }
+
+ if (def->type == VIR_CPU_TYPE_GUEST) {
+- char *match = virXMLPropString(node, "match");
++ char *match = virXMLPropString(ctxt->node, "match");
+ char *check;
+
+ if (!match) {
+@@ -326,11 +347,11 @@ virCPUDefParseXML(xmlNodePtr node,
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Invalid match attribute for CPU "
+ "specification"));
+- goto error;
++ goto cleanup;
+ }
+ }
+
+- if ((check = virXMLPropString(node, "check"))) {
++ if ((check = virXMLPropString(ctxt->node, "check"))) {
+ int value = virCPUCheckTypeFromString(check);
+ VIR_FREE(check);
+
+@@ -338,7 +359,7 @@ virCPUDefParseXML(xmlNodePtr node,
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Invalid check attribute for CPU "
+ "specification"));
+- goto error;
++ goto cleanup;
+ }
+ def->check = value;
+ }
+@@ -349,13 +370,13 @@ virCPUDefParseXML(xmlNodePtr node,
+ if (!arch) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Missing CPU architecture"));
+- goto error;
++ goto cleanup;
+ }
+ if ((def->arch = virArchFromString(arch)) == VIR_ARCH_NONE) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Unknown architecture %s"), arch);
+ VIR_FREE(arch);
+- goto error;
++ goto cleanup;
+ }
+ VIR_FREE(arch);
+ }
+@@ -364,7 +385,7 @@ virCPUDefParseXML(xmlNodePtr node,
+ def->type == VIR_CPU_TYPE_HOST) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Missing CPU model name"));
+- goto error;
++ goto cleanup;
+ }
+
+ if (def->type == VIR_CPU_TYPE_GUEST &&
+@@ -374,7 +395,7 @@ virCPUDefParseXML(xmlNodePtr node,
+ if ((def->fallback = virCPUFallbackTypeFromString(fallback)) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Invalid fallback attribute"));
+- goto error;
++ goto cleanup;
+ }
+ }
+
+@@ -384,14 +405,14 @@ virCPUDefParseXML(xmlNodePtr node,
+ virReportError(VIR_ERR_XML_ERROR,
+ _("vendor_id must be exactly %d characters long"),
+ VIR_CPU_VENDOR_ID_LENGTH);
+- goto error;
++ goto cleanup;
+ }
+
+ /* ensure that the string can be passed to qemu*/
+ if (strchr(vendor_id, ',')) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("vendor id is invalid"));
+- goto error;
++ goto cleanup;
+ }
+
+ def->vendor_id = vendor_id;
+@@ -403,61 +424,54 @@ virCPUDefParseXML(xmlNodePtr node,
+ if (def->vendor && !def->model) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("CPU vendor specified without CPU model"));
+- goto error;
++ goto cleanup;
+ }
+
+ if (virXPathNode("./topology[1]", ctxt)) {
+- int ret;
+ unsigned long ul;
+
+- ret = virXPathULong("string(./topology[1]/@sockets)",
+- ctxt, &ul);
+- if (ret < 0) {
++ if (virXPathULong("string(./topology[1]/@sockets)", ctxt, &ul) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Missing 'sockets' attribute in CPU topology"));
+- goto error;
++ goto cleanup;
+ }
+ def->sockets = (unsigned int) ul;
+
+- ret = virXPathULong("string(./topology[1]/@cores)",
+- ctxt, &ul);
+- if (ret < 0) {
++ if (virXPathULong("string(./topology[1]/@cores)", ctxt, &ul) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Missing 'cores' attribute in CPU topology"));
+- goto error;
++ goto cleanup;
+ }
+ def->cores = (unsigned int) ul;
+
+- ret = virXPathULong("string(./topology[1]/@threads)",
+- ctxt, &ul);
+- if (ret < 0) {
++ if (virXPathULong("string(./topology[1]/@threads)", ctxt, &ul) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Missing 'threads' attribute in CPU topology"));
+- goto error;
++ goto cleanup;
+ }
+ def->threads = (unsigned int) ul;
+
+ if (!def->sockets || !def->cores || !def->threads) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Invalid CPU topology"));
+- goto error;
++ goto cleanup;
+ }
+ }
+
+ if ((n = virXPathNodeSet("./feature", ctxt, &nodes)) < 0)
+- goto error;
++ goto cleanup;
+
+ if (n > 0) {
+ if (!def->model && def->mode == VIR_CPU_MODE_CUSTOM) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Non-empty feature list specified without "
+ "CPU model"));
+- goto error;
++ goto cleanup;
+ }
+
+ if (VIR_RESIZE_N(def->features, def->nfeatures_max,
+ def->nfeatures, n) < 0)
+- goto error;
++ goto cleanup;
+
+ def->nfeatures = n;
+ }
+@@ -480,7 +494,7 @@ virCPUDefParseXML(xmlNodePtr node,
+ if (policy < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Invalid CPU feature policy"));
+- goto error;
++ goto cleanup;
+ }
+ } else {
+ policy = -1;
+@@ -490,7 +504,7 @@ virCPUDefParseXML(xmlNodePtr node,
+ VIR_FREE(name);
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Invalid CPU feature name"));
+- goto error;
++ goto cleanup;
+ }
+
+ for (j = 0; j < i; j++) {
+@@ -499,7 +513,7 @@ virCPUDefParseXML(xmlNodePtr node,
+ _("CPU feature '%s' specified more than once"),
+ name);
+ VIR_FREE(name);
+- goto error;
++ goto cleanup;
+ }
+ }
+
+@@ -542,17 +556,16 @@ virCPUDefParseXML(xmlNodePtr node,
+ def->cache->mode = mode;
+ }
+
++ VIR_STEAL_PTR(*cpu, def);
++ ret = 0;
++
+ cleanup:
+ ctxt->node = oldnode;
+ VIR_FREE(fallback);
+ VIR_FREE(vendor_id);
+ VIR_FREE(nodes);
+- return def;
+-
+- error:
+ virCPUDefFree(def);
+- def = NULL;
+- goto cleanup;
++ return ret;
+ }
+
+
+diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h
+index b0d891552a..b44974f47e 100644
+--- a/src/conf/cpu_conf.h
++++ b/src/conf/cpu_conf.h
+@@ -182,10 +182,11 @@ virCPUDefCopy(const virCPUDef *cpu);
+ virCPUDefPtr
+ virCPUDefCopyWithoutModel(const virCPUDef *cpu);
+
+-virCPUDefPtr
+-virCPUDefParseXML(xmlNodePtr node,
+- xmlXPathContextPtr ctxt,
+- virCPUType mode);
++int
++virCPUDefParseXML(xmlXPathContextPtr ctxt,
++ const char *xpath,
++ virCPUType mode,
++ virCPUDefPtr *cpu);
+
+ bool
+ virCPUDefIsEqual(virCPUDefPtr src,
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 2197330a22..395dcc0531 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -17418,16 +17418,8 @@ virDomainDefParseXML(xmlDocPtr xml,
+ }
+ VIR_FREE(nodes);
+
+- /* analysis of cpu handling */
+- if ((node = virXPathNode("./cpu[1]", ctxt)) != NULL) {
+- xmlNodePtr oldnode = ctxt->node;
+- ctxt->node = node;
+- def->cpu = virCPUDefParseXML(node, ctxt, VIR_CPU_TYPE_GUEST);
+- ctxt->node = oldnode;
+-
+- if (def->cpu == NULL)
+- goto error;
+- }
++ if (virCPUDefParseXML(ctxt, "./cpu[1]", VIR_CPU_TYPE_GUEST, &def->cpu) < 0)
++ goto error;
+
+ if (virDomainNumaDefCPUParseXML(def->numa, ctxt) < 0)
+ goto error;
+diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c
+index 702b14dbb7..96160901e1 100644
+--- a/src/cpu/cpu.c
++++ b/src/cpu/cpu.c
+@@ -130,7 +130,7 @@ virCPUCompareXML(virArch arch,
+ if (!(doc = virXMLParseStringCtxt(xml, _("(CPU_definition)"), &ctxt)))
+ goto cleanup;
+
+- if (!(cpu = virCPUDefParseXML(ctxt->node, ctxt, VIR_CPU_TYPE_AUTO)))
++ if (virCPUDefParseXML(ctxt, NULL, VIR_CPU_TYPE_AUTO, &cpu) < 0)
+ goto cleanup;
+
+ ret = virCPUCompare(arch, host, cpu, failIncompatible);
+@@ -562,8 +562,7 @@ cpuBaselineXML(const char **xmlCPUs,
+ if (!(doc = virXMLParseStringCtxt(xmlCPUs[i], _("(CPU_definition)"), &ctxt)))
+ goto error;
+
+- cpus[i] = virCPUDefParseXML(ctxt->node, ctxt, VIR_CPU_TYPE_HOST);
+- if (cpus[i] == NULL)
++ if (virCPUDefParseXML(ctxt, NULL, VIR_CPU_TYPE_HOST, &cpus[i]) < 0)
+ goto error;
+
+ xmlXPathFreeContext(ctxt);
+diff --git a/tests/cputest.c b/tests/cputest.c
+index efa891dc18..97b34de9ed 100644
+--- a/tests/cputest.c
++++ b/tests/cputest.c
+@@ -88,7 +88,7 @@ cpuTestLoadXML(virArch arch, const char *name)
+ if (!(doc = virXMLParseFileCtxt(xml, &ctxt)))
+ goto cleanup;
+
+- cpu = virCPUDefParseXML(ctxt->node, ctxt, VIR_CPU_TYPE_AUTO);
++ virCPUDefParseXML(ctxt, NULL, VIR_CPU_TYPE_AUTO, &cpu);
+
+ cleanup:
+ xmlXPathFreeContext(ctxt);
+@@ -126,8 +126,7 @@ cpuTestLoadMultiXML(virArch arch,
+
+ for (i = 0; i < n; i++) {
+ ctxt->node = nodes[i];
+- cpus[i] = virCPUDefParseXML(nodes[i], ctxt, VIR_CPU_TYPE_HOST);
+- if (!cpus[i])
++ if (virCPUDefParseXML(ctxt, NULL, VIR_CPU_TYPE_HOST, &cpus[i]) < 0)
+ goto cleanup_cpus;
+ }
+
+--
+2.13.1
+
diff --git a/SOURCES/libvirt-conf-Rename-mode-parameter-in-virCPUDefParseXML.patch b/SOURCES/libvirt-conf-Rename-mode-parameter-in-virCPUDefParseXML.patch
new file mode 100644
index 0000000..1c46aaf
--- /dev/null
+++ b/SOURCES/libvirt-conf-Rename-mode-parameter-in-virCPUDefParseXML.patch
@@ -0,0 +1,53 @@
+From 46761b7fdb0707036482c98eb3a80279753df484 Mon Sep 17 00:00:00 2001
+Message-Id: <46761b7fdb0707036482c98eb3a80279753df484@dist-git>
+From: Jiri Denemark
+Date: Mon, 24 Apr 2017 15:38:41 +0200
+Subject: [PATCH] conf: Rename mode parameter in virCPUDefParseXML
+
+The type of this parameter is virCPUType so calling it 'mode' is pretty
+strange, 'type' is a much better name.
+
+Signed-off-by: Jiri Denemark
+(cherry picked from commit e841a41169dd726af13f29cb57fbafe658b7011a)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1428952
+
+Signed-off-by: Jiri Denemark
+---
+ src/conf/cpu_conf.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c
+index b78531e60..623b1699f 100644
+--- a/src/conf/cpu_conf.c
++++ b/src/conf/cpu_conf.c
+@@ -230,7 +230,7 @@ virCPUDefCopy(const virCPUDef *cpu)
+ virCPUDefPtr
+ virCPUDefParseXML(xmlNodePtr node,
+ xmlXPathContextPtr ctxt,
+- virCPUType mode)
++ virCPUType type)
+ {
+ virCPUDefPtr def;
+ xmlNodePtr *nodes = NULL;
+@@ -250,7 +250,7 @@ virCPUDefParseXML(xmlNodePtr node,
+ if (VIR_ALLOC(def) < 0)
+ return NULL;
+
+- if (mode == VIR_CPU_TYPE_AUTO) {
++ if (type == VIR_CPU_TYPE_AUTO) {
+ if (virXPathBoolean("boolean(./arch)", ctxt)) {
+ if (virXPathBoolean("boolean(./@match)", ctxt)) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+@@ -263,7 +263,7 @@ virCPUDefParseXML(xmlNodePtr node,
+ def->type = VIR_CPU_TYPE_GUEST;
+ }
+ } else {
+- def->type = mode;
++ def->type = type;
+ }
+
+ if ((cpuMode = virXMLPropString(node, "mode"))) {
+--
+2.12.2
+
diff --git a/SOURCES/libvirt-conf-Resolve-corner-case-on-fc_host-deletion.patch b/SOURCES/libvirt-conf-Resolve-corner-case-on-fc_host-deletion.patch
new file mode 100644
index 0000000..b5bfc3e
--- /dev/null
+++ b/SOURCES/libvirt-conf-Resolve-corner-case-on-fc_host-deletion.patch
@@ -0,0 +1,59 @@
+From 70c60798f09324a9e4d91f787cad493a1ceca5d9 Mon Sep 17 00:00:00 2001
+Message-Id: <70c60798f09324a9e4d91f787cad493a1ceca5d9@dist-git>
+From: John Ferlan
+Date: Wed, 24 May 2017 10:27:57 -0400
+Subject: [PATCH] conf: Resolve corner case on fc_host deletion
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1420740
+
+Testing found an inventive way to cause an error at shutdown by providing the
+parent name for the fc host creation using the "same name" as the HBA. Since
+the code thus assumed the parent host name provided was the parent HBA and
+just extracted out the host number and sent that along to the vport_destroy
+this avoided checks made for equality.
+
+So just add the equality check to that path to resolve.
+
+(cherry picked from commit 2c8e30ee7e287d6490f643ccd2d7653a834e75e5)
+Signed-off-by: John Ferlan
+Signed-off-by: Jiri Denemark
+---
+ src/conf/node_device_conf.c | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
+index ac61db34c..2d0b14850 100644
+--- a/src/conf/node_device_conf.c
++++ b/src/conf/node_device_conf.c
+@@ -2300,17 +2300,25 @@ virNodeDeviceDeleteVport(virConnectPtr conn,
+ goto cleanup;
+ }
+
++ if (virAsprintf(&scsi_host_name, "scsi_%s", name) < 0)
++ goto cleanup;
++
+ /* If at startup time we provided a parent, then use that to
+ * get the parent_host value; otherwise, we have to determine
+ * the parent scsi_host which we did not save at startup time
+ */
+ if (fchost->parent) {
++ /* Someone provided a parent string at startup time that
++ * was the same as the scsi_host - meaning we have a pool
++ * backed to an HBA, so there won't be a vHBA to delete */
++ if (STREQ(scsi_host_name, fchost->parent)) {
++ ret = 0;
++ goto cleanup;
++ }
++
+ if (virSCSIHostGetNumber(fchost->parent, &parent_host) < 0)
+ goto cleanup;
+ } else {
+- if (virAsprintf(&scsi_host_name, "scsi_%s", name) < 0)
+- goto cleanup;
+-
+ if (!(vhba_parent = virNodeDeviceGetParentName(conn, scsi_host_name)))
+ goto cleanup;
+
+--
+2.13.0
+
diff --git a/SOURCES/libvirt-conf-Simplify-slot-allocation.patch b/SOURCES/libvirt-conf-Simplify-slot-allocation.patch
new file mode 100644
index 0000000..9d214e6
--- /dev/null
+++ b/SOURCES/libvirt-conf-Simplify-slot-allocation.patch
@@ -0,0 +1,136 @@
+From af91509dfc59e90262117b96a2a365d5ece29393 Mon Sep 17 00:00:00 2001
+Message-Id:
+From: Andrea Bolognani
+Date: Mon, 17 Jul 2017 12:09:03 +0200
+Subject: [PATCH] conf: Simplify slot allocation
+
+The current algorithm for slot allocation tries to be clever
+and avoid looking at buses / slots more than once unless it's
+necessary. Unfortunately that makes the code more complex,
+and it will cause problem later on in some situations unless
+even more complex code is added.
+
+Since the performance gains are going to be pretty modest
+anyway, we can just get rid of the extra complexity and use a
+completely straighforward implementation instead.
+
+Signed-off-by: Andrea Bolognani
+Reviewed-by: Laine Stump
+(cherry picked from commit 2bd0658d7cc886209a53bae23c20adbb7d4f91ac)
+
+Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1431193
+
+Signed-off-by: Andrea Bolognani
+Signed-off-by: Jiri Denemark
+---
+ src/conf/domain_addr.c | 47 +++++++++--------------------------------------
+ src/conf/domain_addr.h | 2 --
+ 2 files changed, 9 insertions(+), 40 deletions(-)
+
+diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
+index b17bb61a1d..b8e5902c07 100644
+--- a/src/conf/domain_addr.c
++++ b/src/conf/domain_addr.c
+@@ -755,46 +755,34 @@ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs,
+ virDomainPCIConnectFlags flags,
+ int function)
+ {
+- /* default to starting the search for a free slot from
+- * the first slot of domain 0 bus 0...
+- */
+ virPCIDeviceAddress a = { 0 };
+- bool found = false;
+
+ if (addrs->nbuses == 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s", _("No PCI buses available"));
+ goto error;
+ }
+
+- /* ...unless this search is for the exact same type of device as
+- * last time, then continue the search from the slot where we
+- * found the previous match (it's possible there will still be a
+- * function available on that slot).
+- */
+- if (flags == addrs->lastFlags)
+- a = addrs->lastaddr;
+- else
+- a.slot = addrs->buses[0].minSlot;
+-
+ /* if the caller asks for "any function", give them function 0 */
+ if (function == -1)
+ a.function = 0;
+ else
+ a.function = function;
+
+- while (a.bus < addrs->nbuses) {
+- if (virDomainPCIAddressFindUnusedFunctionOnBus(&addrs->buses[a.bus],
+- &a, function,
++ /* "Begin at the beginning," the King said, very gravely, "and go on
++ * till you come to the end: then stop." */
++ for (a.bus = 0; a.bus < addrs->nbuses; a.bus++) {
++ virDomainPCIAddressBusPtr bus = &addrs->buses[a.bus];
++ bool found = false;
++
++ a.slot = bus->minSlot;
++
++ if (virDomainPCIAddressFindUnusedFunctionOnBus(bus, &a, function,
+ flags, &found) < 0) {
+ goto error;
+ }
+
+ if (found)
+ goto success;
+-
+- /* nothing on this bus, go to the next bus */
+- if (++a.bus < addrs->nbuses)
+- a.slot = addrs->buses[a.bus].minSlot;
+ }
+
+ /* There were no free slots after the last used one */
+@@ -805,20 +793,6 @@ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs,
+ /* this device will use the first slot of the new bus */
+ a.slot = addrs->buses[a.bus].minSlot;
+ goto success;
+- } else if (flags == addrs->lastFlags) {
+- /* Check the buses from 0 up to the last used one */
+- for (a.bus = 0; a.bus <= addrs->lastaddr.bus; a.bus++) {
+- a.slot = addrs->buses[a.bus].minSlot;
+-
+- if (virDomainPCIAddressFindUnusedFunctionOnBus(&addrs->buses[a.bus],
+- &a, function,
+- flags, &found) < 0) {
+- goto error;
+- }
+-
+- if (found)
+- goto success;
+- }
+ }
+
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+@@ -865,9 +839,6 @@ virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs,
+ if (virDomainPCIAddressReserveAddrInternal(addrs, &addr, flags, false) < 0)
+ return -1;
+
+- addrs->lastaddr = addr;
+- addrs->lastFlags = flags;
+-
+ if (!addrs->dryRun) {
+ dev->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
+ dev->addr.pci = addr;
+diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h
+index bb10f1abf3..a5afefda95 100644
+--- a/src/conf/domain_addr.h
++++ b/src/conf/domain_addr.h
+@@ -106,8 +106,6 @@ typedef virDomainPCIAddressBus *virDomainPCIAddressBusPtr;
+ struct _virDomainPCIAddressSet {
+ virDomainPCIAddressBus *buses;
+ size_t nbuses;
+- virPCIDeviceAddress lastaddr;
+- virDomainPCIConnectFlags lastFlags;
+ bool dryRun; /* on a dry run, new buses are auto-added
+ and addresses aren't saved in device infos */
+ };
+--
+2.13.3
+
diff --git a/SOURCES/libvirt-conf-Tweak-virDomainPCIAddressGetNextAddr-signature.patch b/SOURCES/libvirt-conf-Tweak-virDomainPCIAddressGetNextAddr-signature.patch
new file mode 100644
index 0000000..ebfcb3a
--- /dev/null
+++ b/SOURCES/libvirt-conf-Tweak-virDomainPCIAddressGetNextAddr-signature.patch
@@ -0,0 +1,82 @@
+From 2d719331886e3f4ed927449ffde6a854e9deec1b Mon Sep 17 00:00:00 2001
+Message-Id: <2d719331886e3f4ed927449ffde6a854e9deec1b@dist-git>
+From: Andrea Bolognani
+Date: Mon, 17 Jul 2017 12:08:59 +0200
+Subject: [PATCH] conf: Tweak virDomainPCIAddressGetNextAddr() signature
+
+Move @function after @flags to match other functions in the
+same module like virDomainPCIAddressReserveNextAddr().
+
+Also move virDomainPCIAddressReserveNextAddr() closer to
+virDomainPCIAddressReserveAddr() in the header file.
+
+Signed-off-by: Andrea Bolognani
+Reviewed-by: Laine Stump
+(cherry picked from commit c949f6e69cbe91b9897e37e525181710f5c75b35)
+
+Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1431193
+
+Signed-off-by: Andrea Bolognani
+Signed-off-by: Jiri Denemark
+---
+ src/conf/domain_addr.c | 6 +++---
+ src/conf/domain_addr.h | 12 ++++++------
+ 2 files changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
+index 0ae1ed93af..b17bb61a1d 100644
+--- a/src/conf/domain_addr.c
++++ b/src/conf/domain_addr.c
+@@ -752,8 +752,8 @@ virDomainPCIAddressFindUnusedFunctionOnBus(virDomainPCIAddressBusPtr bus,
+ static int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
+ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs,
+ virPCIDeviceAddressPtr next_addr,
+- int function,
+- virDomainPCIConnectFlags flags)
++ virDomainPCIConnectFlags flags,
++ int function)
+ {
+ /* default to starting the search for a free slot from
+ * the first slot of domain 0 bus 0...
+@@ -859,7 +859,7 @@ virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs,
+ {
+ virPCIDeviceAddress addr;
+
+- if (virDomainPCIAddressGetNextAddr(addrs, &addr, function, flags) < 0)
++ if (virDomainPCIAddressGetNextAddr(addrs, &addr, flags, function) < 0)
+ return -1;
+
+ if (virDomainPCIAddressReserveAddrInternal(addrs, &addr, flags, false) < 0)
+diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h
+index c90a335919..bb10f1abf3 100644
+--- a/src/conf/domain_addr.h
++++ b/src/conf/domain_addr.h
+@@ -158,6 +158,12 @@ int virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs,
+ virDomainPCIConnectFlags flags)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
++int virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs,
++ virDomainDeviceInfoPtr dev,
++ virDomainPCIConnectFlags flags,
++ int function)
++ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
++
+ int virDomainPCIAddressEnsureAddr(virDomainPCIAddressSetPtr addrs,
+ virDomainDeviceInfoPtr dev,
+ virDomainPCIConnectFlags flags)
+@@ -167,12 +173,6 @@ int virDomainPCIAddressReleaseAddr(virDomainPCIAddressSetPtr addrs,
+ virPCIDeviceAddressPtr addr)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
+-int virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs,
+- virDomainDeviceInfoPtr dev,
+- virDomainPCIConnectFlags flags,
+- int function)
+- ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+-
+ void virDomainPCIAddressSetAllMulti(virDomainDefPtr def)
+ ATTRIBUTE_NONNULL(1);
+
+--
+2.13.3
+
diff --git a/SOURCES/libvirt-conf-Use-the-correct-limit-for-the-number-of-PHBs.patch b/SOURCES/libvirt-conf-Use-the-correct-limit-for-the-number-of-PHBs.patch
new file mode 100644
index 0000000..4ceca53
--- /dev/null
+++ b/SOURCES/libvirt-conf-Use-the-correct-limit-for-the-number-of-PHBs.patch
@@ -0,0 +1,62 @@
+From e2bf7a17d464c989378278c3121425e7b90442e3 Mon Sep 17 00:00:00 2001
+Message-Id:
+From: Andrea Bolognani
+Date: Mon, 21 Aug 2017 14:46:39 +0200
+Subject: [PATCH] conf: Use the correct limit for the number of PHBs
+
+I mistakenly thought pSeries guests supported 32 PHBs,
+but it turns out they only support 31. Validate the
+target index accordingly.
+
+Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1479647
+
+Signed-off-by: Andrea Bolognani
+(cherry picked from commit 64357c3f9373127aa8bdf5a829df4a9d895e1ef9)
+
+Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1479647
+
+Signed-off-by: Andrea Bolognani
+Signed-off-by: Jiri Denemark
+---
+ src/conf/domain_conf.c | 4 ++--
+ .../qemuxml2argv-pseries-phb-invalid-target-index-3.xml | 6 +++---
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 7889f5335c..3d38f668fa 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -5058,10 +5058,10 @@ virDomainControllerDefValidate(const virDomainControllerDef *controller)
+ /* Only validate the target index if it's been set */
+ if (opts->targetIndex != -1) {
+
+- if (opts->targetIndex < 0 || opts->targetIndex > 31) {
++ if (opts->targetIndex < 0 || opts->targetIndex > 30) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("PCI controller target index '%d' out of "
+- "range - must be 0-31"),
++ "range - must be 0-30"),
+ opts->targetIndex);
+ return -1;
+ }
+diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-invalid-target-index-3.xml b/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-invalid-target-index-3.xml
+index 864c5d8758..3d99da4995 100644
+--- a/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-invalid-target-index-3.xml
++++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-invalid-target-index-3.xml
+@@ -8,10 +8,10 @@
+
+
+ /usr/bin/qemu-system-ppc64
+-
++
+
+-
++
+
+
+
+--
+2.14.1
+
diff --git a/SOURCES/libvirt-conf-add-ABI-stability-checks-for-IOMMU-options.patch b/SOURCES/libvirt-conf-add-ABI-stability-checks-for-IOMMU-options.patch
new file mode 100644
index 0000000..c3c59ef
--- /dev/null
+++ b/SOURCES/libvirt-conf-add-ABI-stability-checks-for-IOMMU-options.patch
@@ -0,0 +1,64 @@
+From 4383e358e2d8a85bd46936c997071c3b776fffd0 Mon Sep 17 00:00:00 2001
+Message-Id: <4383e358e2d8a85bd46936c997071c3b776fffd0@dist-git>
+From: =?UTF-8?q?J=C3=A1n=20Tomko?=
+Date: Tue, 16 May 2017 10:44:59 +0200
+Subject: [PATCH] conf: add ABI stability checks for IOMMU options
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1427005
+(cherry picked from commit 935d927aa881753fff30f6236eedcf9680bca638)
+Signed-off-by: Ján Tomko
+Signed-off-by: Jiri Denemark
+---
+ src/conf/domain_conf.c | 26 ++++++++++++++++++++++++++
+ 1 file changed, 26 insertions(+)
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 7bf480f2a..370916396 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -19682,6 +19682,16 @@ virDomainDefFeaturesCheckABIStability(virDomainDefPtr src,
+ }
+ }
+
++ /* ioapic */
++ if (src->ioapic != dst->ioapic) {
++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
++ _("State of ioapic differs: "
++ "source: '%s', destination: '%s'"),
++ virDomainIOAPICTypeToString(src->ioapic),
++ virDomainIOAPICTypeToString(dst->ioapic));
++ return false;
++ }
++
+ return true;
+ }
+
+@@ -19821,6 +19831,22 @@ virDomainIOMMUDefCheckABIStability(virDomainIOMMUDefPtr src,
+ virDomainIOMMUModelTypeToString(src->model));
+ return false;
+ }
++ if (src->intremap != dst->intremap) {
++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
++ _("Target domain IOMMU device intremap value '%s' "
++ "does not match source '%s'"),
++ virTristateSwitchTypeToString(dst->intremap),
++ virTristateSwitchTypeToString(src->intremap));
++ return false;
++ }
++ if (src->caching_mode != dst->caching_mode) {
++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
++ _("Target domain IOMMU device caching mode '%s' "
++ "does not match source '%s'"),
++ virTristateSwitchTypeToString(dst->caching_mode),
++ virTristateSwitchTypeToString(src->caching_mode));
++ return false;
++ }
+ return true;
+ }
+
+--
+2.13.0
+
diff --git a/SOURCES/libvirt-conf-add-a-new-parse-flag-VIR_DOMAIN_DEF_PARSE_ABI_UPDATE_MIGRATION.patch b/SOURCES/libvirt-conf-add-a-new-parse-flag-VIR_DOMAIN_DEF_PARSE_ABI_UPDATE_MIGRATION.patch
new file mode 100644
index 0000000..6ce10e4
--- /dev/null
+++ b/SOURCES/libvirt-conf-add-a-new-parse-flag-VIR_DOMAIN_DEF_PARSE_ABI_UPDATE_MIGRATION.patch
@@ -0,0 +1,72 @@
+From b24b004e1196889201142d1fc7d51e2fafdbe328 Mon Sep 17 00:00:00 2001
+Message-Id:
+From: Pavel Hrdina
+Date: Thu, 20 Apr 2017 09:16:20 +0200
+Subject: [PATCH] conf: add a new parse flag
+ VIR_DOMAIN_DEF_PARSE_ABI_UPDATE_MIGRATION
+
+So far there is probably no change that is allowed to be done
+by the VIR_DOMAIN_DEF_PARSE_ABI_UPDATE flag that would break
+guest ABI but this may change in the future.
+
+This introduces new VIR_DOMAIN_DEF_PARSE_ABI_UPDATE_MIGRATION
+which should be used only for ABI updates that are "safe" for
+persistent migration.
+
+Signed-off-by: Pavel Hrdina
+(cherry picked from commit 5c7d88085a762cf4ecc9416a3b7581fa45738c2a)
+
+Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1373184
+
+Signed-off-by: Pavel Hrdina
+---
+ src/conf/domain_conf.c | 3 ++-
+ src/conf/domain_conf.h | 4 ++++
+ src/qemu/qemu_migration_cookie.c | 2 +-
+ 3 files changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 1b0a55b27..71f0c95c3 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -3805,7 +3805,8 @@ virDomainDefPostParseMemory(virDomainDefPtr def,
+ /* Attempt to infer the initial memory size from the sum NUMA memory sizes
+ * in case ABI updates are allowed or the element wasn't specified */
+ if (def->mem.total_memory == 0 ||
+- parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE)
++ parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE ||
++ parseFlags & VIR_DOMAIN_DEF_PARSE_ABI_UPDATE_MIGRATION)
+ numaMemory = virDomainNumaGetMemorySize(def->numa);
+
+ /* calculate the sizes of hotplug memory */
+diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
+index 47eaacef3..71e651975 100644
+--- a/src/conf/domain_conf.h
++++ b/src/conf/domain_conf.h
+@@ -2725,6 +2725,10 @@ typedef enum {
+ VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE = 1 << 10,
+ /* skip parsing of security labels */
+ VIR_DOMAIN_DEF_PARSE_SKIP_SECLABEL = 1 << 11,
++ /* Allows updates in post parse callback for incoming persistent migration
++ * that would break ABI otherwise. This should be used only if it's safe
++ * to do such change. */
++ VIR_DOMAIN_DEF_PARSE_ABI_UPDATE_MIGRATION = 1 << 12,
+ } virDomainDefParseFlags;
+
+ typedef enum {
+diff --git a/src/qemu/qemu_migration_cookie.c b/src/qemu/qemu_migration_cookie.c
+index bd12f1124..12887892d 100644
+--- a/src/qemu/qemu_migration_cookie.c
++++ b/src/qemu/qemu_migration_cookie.c
+@@ -1173,7 +1173,7 @@ qemuMigrationCookieXMLParse(qemuMigrationCookiePtr mig,
+ mig->persistent = virDomainDefParseNode(doc, nodes[0],
+ caps, driver->xmlopt, NULL,
+ VIR_DOMAIN_DEF_PARSE_INACTIVE |
+- VIR_DOMAIN_DEF_PARSE_ABI_UPDATE |
++ VIR_DOMAIN_DEF_PARSE_ABI_UPDATE_MIGRATION |
+ VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE);
+ if (!mig->persistent) {
+ /* virDomainDefParseNode already reported
+--
+2.12.2
+
diff --git a/SOURCES/libvirt-conf-add-caching_mode-attribute-to-iommu-device.patch b/SOURCES/libvirt-conf-add-caching_mode-attribute-to-iommu-device.patch
new file mode 100644
index 0000000..5e209b4
--- /dev/null
+++ b/SOURCES/libvirt-conf-add-caching_mode-attribute-to-iommu-device.patch
@@ -0,0 +1,196 @@
+From 3b7b827deb9eb7f43f548aabd27c300ae24c7db3 Mon Sep 17 00:00:00 2001
+Message-Id: <3b7b827deb9eb7f43f548aabd27c300ae24c7db3@dist-git>
+From: =?UTF-8?q?J=C3=A1n=20Tomko?=
+Date: Tue, 16 May 2017 10:44:56 +0200
+Subject: [PATCH] conf: add caching_mode attribute to iommu device
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add a new attribute to control the caching mode.
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1427005
+(cherry picked from commit d12781b47eb0c9f3a498d88b632c327aa08aaf8a)
+Signed-off-by: Ján Tomko
+Signed-off-by: Jiri Denemark
+---
+ docs/formatdomain.html.in | 9 ++++
+ docs/schemas/domaincommon.rng | 5 +++
+ src/conf/domain_conf.c | 24 +++++++++--
+ src/conf/domain_conf.h | 1 +
+ .../qemuxml2argv-intel-iommu-caching-mode.xml | 50 ++++++++++++++++++++++
+ .../qemuxml2xmlout-intel-iommu-caching-mode.xml | 1 +
+ tests/qemuxml2xmltest.c | 1 +
+ 7 files changed, 88 insertions(+), 3 deletions(-)
+ create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-intel-iommu-caching-mode.xml
+ create mode 120000 tests/qemuxml2xmloutdata/qemuxml2xmlout-intel-iommu-caching-mode.xml
+
+diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
+index 41b8bfb50..43a75c1ee 100644
+--- a/docs/formatdomain.html.in
++++ b/docs/formatdomain.html.in
+@@ -7424,6 +7424,15 @@ qemu-kvm -net nic,model=? /dev/null
+ Since 3.4.0 (QEMU/KVM only)
+
+
++
caching_mode
++
++
++ The caching_mode attribute with possible values
++ on and off can be used to
++ turn on the VT-d caching mode (useful for assigned devices).
++ Since 3.4.0 (QEMU/KVM only)
++
+@@ -7404,6 +7406,26 @@ qemu-kvm -net nic,model=? /dev/null
+ Currently only the intel model is supported.
+
+
++
driver
++
++
++ The driver subelement can be used to configure
++ additional options:
++
++
++
intremap
++
++
++ The intremap attribute with possible values
++ on and off can be used to
++ turn on interrupt remapping, a part of the VT-d functionality.
++ Currently this requires split I/O APIC
++ (<ioapic driver='qemu'/>).
++ Since 3.4.0 (QEMU/KVM only)
++
++ The eim attribute (with possible values
++ on and off) can be used to
++ configure Extended Interrupt Mode. A q35 domain with
++ split I/O APIC (as described in
++ hypervisor features),
++ and both interrupt remapping and EIM turned on for
++ the IOMMU, will be able to use more than 255 vCPUs.
++ Since 3.4.0 (QEMU/KVM only)
++
Tune the I/O APIC. Possible values for the
++ driver attribute are:
++ kvm (default for KVM domains)
++ and qemu which puts I/O APIC in userspace
++ which is also known as a split I/O APIC mode.
++ Since 3.4.0 (QEMU/KVM only)
++
++ The iotlb attribute with possible values
++ on and off can be used to
++ turn on the IOTLB used to cache address translation
++ requests from devices.
++ Since 3.5.0 (QEMU/KVM only)
++
++
+
+
+
+diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
+index af7824aa02..1b66362f17 100644
+--- a/docs/schemas/domaincommon.rng
++++ b/docs/schemas/domaincommon.rng
+@@ -3910,6 +3910,11 @@
+
+
+
++
++
++
++
++
+
+
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 275145b1ec..701a6d2136 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -14196,6 +14196,14 @@ virDomainIOMMUDefParseXML(xmlNodePtr node,
+ }
+ iommu->caching_mode = val;
+ }
++ VIR_FREE(tmp);
++ if ((tmp = virXPathString("string(./driver/@iotlb)", ctxt))) {
++ if ((val = virTristateSwitchTypeFromString(tmp)) < 0) {
++ virReportError(VIR_ERR_XML_ERROR, _("unknown iotlb value: %s"), tmp);
++ goto cleanup;
++ }
++ iommu->iotlb = val;
++ }
+
+ VIR_FREE(tmp);
+ if ((tmp = virXPathString("string(./driver/@eim)", ctxt))) {
+@@ -19877,6 +19885,14 @@ virDomainIOMMUDefCheckABIStability(virDomainIOMMUDefPtr src,
+ virTristateSwitchTypeToString(src->eim));
+ return false;
+ }
++ if (src->iotlb != dst->iotlb) {
++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
++ _("Target domain IOMMU device iotlb value '%s' "
++ "does not match source '%s'"),
++ virTristateSwitchTypeToString(dst->iotlb),
++ virTristateSwitchTypeToString(src->iotlb));
++ return false;
++ }
+ return true;
+ }
+
+@@ -24212,7 +24228,8 @@ virDomainIOMMUDefFormat(virBufferPtr buf,
+ virBufferAdjustIndent(&childBuf, virBufferGetIndent(buf, false) + 2);
+
+ if (iommu->intremap != VIR_TRISTATE_SWITCH_ABSENT ||
+- iommu->caching_mode != VIR_TRISTATE_SWITCH_ABSENT) {
++ iommu->caching_mode != VIR_TRISTATE_SWITCH_ABSENT ||
++ iommu->iotlb != VIR_TRISTATE_SWITCH_ABSENT) {
+ virBufferAddLit(&childBuf, "intremap != VIR_TRISTATE_SWITCH_ABSENT) {
+ virBufferAsprintf(&childBuf, " intremap='%s'",
+@@ -24226,6 +24243,10 @@ virDomainIOMMUDefFormat(virBufferPtr buf,
+ virBufferAsprintf(&childBuf, " eim='%s'",
+ virTristateSwitchTypeToString(iommu->eim));
+ }
++ if (iommu->iotlb != VIR_TRISTATE_SWITCH_ABSENT) {
++ virBufferAsprintf(&childBuf, " iotlb='%s'",
++ virTristateSwitchTypeToString(iommu->iotlb));
++ }
+ virBufferAddLit(&childBuf, "/>\n");
+ }
+
+diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
+index 706d106ad9..e6c20a9e1e 100644
+--- a/src/conf/domain_conf.h
++++ b/src/conf/domain_conf.h
+@@ -2213,6 +2213,7 @@ struct _virDomainIOMMUDef {
+ virTristateSwitch intremap;
+ virTristateSwitch caching_mode;
+ virTristateSwitch eim;
++ virTristateSwitch iotlb;
+ };
+ /*
+ * Guest VM main configuration
+diff --git a/tests/qemuxml2argvdata/qemuxml2argv-intel-iommu-device-iotlb.xml b/tests/qemuxml2argvdata/qemuxml2argv-intel-iommu-device-iotlb.xml
+new file mode 100644
+index 0000000000..3eb08ab9af
+--- /dev/null
++++ b/tests/qemuxml2argvdata/qemuxml2argv-intel-iommu-device-iotlb.xml
+@@ -0,0 +1,31 @@
++
++ QEMUGuest1
++ c7a5fdbd-edaf-9455-926a-d65c16db1809
++ 219100
++ 219100
++ 1
++
++ hvm
++
++
++
++
++
++
++ destroy
++ restart
++ destroy
++
++ /usr/bin/qemu-system-x86_64
++
++
++
++
++
++
++
++
++
++
++
++
+diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-intel-iommu-device-iotlb.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-intel-iommu-device-iotlb.xml
+new file mode 120000
+index 0000000000..3120d9f677
+--- /dev/null
++++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-intel-iommu-device-iotlb.xml
+@@ -0,0 +1 @@
++../qemuxml2argvdata/qemuxml2argv-intel-iommu-device-iotlb.xml
+\ No newline at end of file
+diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
+index 6283da4096..3f7c268e43 100644
+--- a/tests/qemuxml2xmltest.c
++++ b/tests/qemuxml2xmltest.c
+@@ -1131,6 +1131,7 @@ mymain(void)
+ DO_TEST("intel-iommu-ioapic", NONE);
+ DO_TEST("intel-iommu-caching-mode", NONE);
+ DO_TEST("intel-iommu-eim", NONE);
++ DO_TEST("intel-iommu-device-iotlb", NONE);
+
+ DO_TEST("cpu-check-none", NONE);
+ DO_TEST("cpu-check-partial", NONE);
+--
+2.13.1
+
diff --git a/SOURCES/libvirt-conf-docs-Add-support-for-coalesce-setting-s.patch b/SOURCES/libvirt-conf-docs-Add-support-for-coalesce-setting-s.patch
new file mode 100644
index 0000000..f7166fc
--- /dev/null
+++ b/SOURCES/libvirt-conf-docs-Add-support-for-coalesce-setting-s.patch
@@ -0,0 +1,557 @@
+From 705cbf8998e405b98f2d536f6d92c524755fe219 Mon Sep 17 00:00:00 2001
+Message-Id: <705cbf8998e405b98f2d536f6d92c524755fe219@dist-git>
+From: Martin Kletzander
+Date: Tue, 25 Apr 2017 13:41:16 +0200
+Subject: [PATCH] conf, docs: Add support for coalesce setting(s)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1414627
+
+We are currently parsing only rx/frames/max because that's the only
+value that makes sense for us. The tun device just added support for
+this one and the others are only supported by hardware devices which
+we don't need to worry about as the only way we'd pass those to the
+domain is using or . And in
+those cases the guest can modify the settings itself.
+
+Signed-off-by: Martin Kletzander
+(cherry picked from commit 523c9960621eaf307ae8d4ae2735fb66f89d5634)
+Signed-off-by: Martin Kletzander
+Signed-off-by: Jiri Denemark
+---
+ docs/formatdomain.html.in | 27 +++++
+ docs/schemas/domaincommon.rng | 131 +++++++++++++++++++++
+ src/conf/domain_conf.c | 80 +++++++++++++
+ src/conf/domain_conf.h | 2 +
+ src/qemu/qemu_domain.c | 31 +++++
+ .../qemuxml2argvdata/qemuxml2argv-net-coalesce.xml | 68 +++++++++++
+ .../qemuxml2xmlout-net-coalesce.xml | 71 +++++++++++
+ tests/qemuxml2xmltest.c | 1 +
+ 8 files changed, 411 insertions(+)
+ create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-net-coalesce.xml
+ create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-net-coalesce.xml
+
+diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
+index aee1e1442..7374cb243 100644
+--- a/docs/formatdomain.html.in
++++ b/docs/formatdomain.html.in
+@@ -5437,6 +5437,33 @@ qemu-kvm -net nic,model=? /dev/null
+ Since 3.1.0
+
+
++
++ This element provides means of setting coalesce settings for
++ some interface devices (currently only type network
++ and bridge. Currently there is just one attribute,
++ max, to tweak, in element frames for
++ the rx group, which accepts a non-negative integer
++ that specifies the maximum number of packets that will be
++ received before an interrupt.
++ Since 3.3.0
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 71f0c95c3..f2801ec84 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -6759,6 +6759,77 @@ virDomainNetIPInfoParseXML(const char *source,
+ return ret;
+ }
+
++
++static virNetDevCoalescePtr
++virDomainNetDefCoalesceParseXML(xmlNodePtr node,
++ xmlXPathContextPtr ctxt)
++{
++ virNetDevCoalescePtr ret = NULL;
++ xmlNodePtr save = NULL;
++ char *str = NULL;
++ unsigned long long tmp = 0;
++
++ save = ctxt->node;
++ ctxt->node = node;
++
++ str = virXPathString("string(./rx/frames/@max)", ctxt);
++ if (!str)
++ goto cleanup;
++
++ if (!ret && VIR_ALLOC(ret) < 0)
++ goto cleanup;
++
++ if (virStrToLong_ullp(str, NULL, 10, &tmp) < 0) {
++ virReportError(VIR_ERR_XML_DETAIL,
++ _("cannot parse value '%s' for coalesce parameter"),
++ str);
++ VIR_FREE(str);
++ goto error;
++ }
++ VIR_FREE(str);
++
++ if (tmp > UINT32_MAX) {
++ virReportError(VIR_ERR_OVERFLOW,
++ _("value '%llu' is too big for coalesce "
++ "parameter, maximum is '%lu'"),
++ tmp, (unsigned long) UINT32_MAX);
++ goto error;
++ }
++ ret->rx_max_coalesced_frames = tmp;
++
++ cleanup:
++ ctxt->node = save;
++ return ret;
++
++ error:
++ VIR_FREE(ret);
++ goto cleanup;
++}
++
++static void
++virDomainNetDefCoalesceFormatXML(virBufferPtr buf,
++ virNetDevCoalescePtr coalesce)
++{
++ if (!coalesce || !coalesce->rx_max_coalesced_frames)
++ return;
++
++ virBufferAddLit(buf, "\n");
++ virBufferAdjustIndent(buf, 2);
++
++ virBufferAddLit(buf, "\n");
++ virBufferAdjustIndent(buf, 2);
++
++ virBufferAsprintf(buf, "\n",
++ coalesce->rx_max_coalesced_frames);
++
++ virBufferAdjustIndent(buf, -2);
++ virBufferAddLit(buf, "\n");
++
++ virBufferAdjustIndent(buf, -2);
++ virBufferAddLit(buf, "\n");
++}
++
++
+ static int
+ virDomainHostdevDefParseXMLCaps(xmlNodePtr node ATTRIBUTE_UNUSED,
+ xmlXPathContextPtr ctxt,
+@@ -10242,6 +10313,13 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
+ goto error;
+ }
+
++ node = virXPathNode("./coalesce", ctxt);
++ if (node) {
++ def->coalesce = virDomainNetDefCoalesceParseXML(node, ctxt);
++ if (!def->coalesce)
++ goto error;
++ }
++
+ cleanup:
+ ctxt->node = oldnode;
+ VIR_FREE(macaddr);
+@@ -22135,6 +22213,8 @@ virDomainNetDefFormat(virBufferPtr buf,
+ if (def->mtu)
+ virBufferAsprintf(buf, "\n", def->mtu);
+
++ virDomainNetDefCoalesceFormatXML(buf, def->coalesce);
++
+ if (virDomainDeviceInfoFormat(buf, &def->info,
+ flags | VIR_DOMAIN_DEF_FORMAT_ALLOW_BOOT
+ | VIR_DOMAIN_DEF_FORMAT_ALLOW_ROM) < 0)
+diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
+index 71e651975..1dbbcdc51 100644
+--- a/src/conf/domain_conf.h
++++ b/src/conf/domain_conf.h
+@@ -41,6 +41,7 @@
+ # include "numa_conf.h"
+ # include "virnetdevmacvlan.h"
+ # include "virsysinfo.h"
++# include "virnetdev.h"
+ # include "virnetdevip.h"
+ # include "virnetdevvportprofile.h"
+ # include "virnetdevbandwidth.h"
+@@ -1036,6 +1037,7 @@ struct _virDomainNetDef {
+ int trustGuestRxFilters; /* enum virTristateBool */
+ int linkstate;
+ unsigned int mtu;
++ virNetDevCoalescePtr coalesce;
+ };
+
+ /* Used for prefix of ifname of any network name generated dynamically
+diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
+index d31645fd1..53586878b 100644
+--- a/src/qemu/qemu_domain.c
++++ b/src/qemu/qemu_domain.c
+@@ -3012,6 +3012,30 @@ qemuDomainDefValidate(const virDomainDef *def,
+ }
+
+
++static bool
++qemuDomainNetSupportsCoalesce(virDomainNetType type)
++{
++ switch (type) {
++ case VIR_DOMAIN_NET_TYPE_NETWORK:
++ case VIR_DOMAIN_NET_TYPE_BRIDGE:
++ return true;
++ case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
++ case VIR_DOMAIN_NET_TYPE_ETHERNET:
++ case VIR_DOMAIN_NET_TYPE_DIRECT:
++ case VIR_DOMAIN_NET_TYPE_HOSTDEV:
++ case VIR_DOMAIN_NET_TYPE_USER:
++ case VIR_DOMAIN_NET_TYPE_SERVER:
++ case VIR_DOMAIN_NET_TYPE_CLIENT:
++ case VIR_DOMAIN_NET_TYPE_MCAST:
++ case VIR_DOMAIN_NET_TYPE_INTERNAL:
++ case VIR_DOMAIN_NET_TYPE_UDP:
++ case VIR_DOMAIN_NET_TYPE_LAST:
++ break;
++ }
++ return false;
++}
++
++
+ static int
+ qemuDomainDeviceDefValidate(const virDomainDeviceDef *dev,
+ const virDomainDef *def ATTRIBUTE_UNUSED,
+@@ -3046,6 +3070,13 @@ qemuDomainDeviceDefValidate(const virDomainDeviceDef *dev,
+ virDomainNetTypeToString(net->type));
+ goto cleanup;
+ }
++
++ if (net->coalesce && !qemuDomainNetSupportsCoalesce(net->type)) {
++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
++ _("coalesce settings on interface type %s are not supported"),
++ virDomainNetTypeToString(net->type));
++ goto cleanup;
++ }
+ }
+
+ ret = 0;
+diff --git a/tests/qemuxml2argvdata/qemuxml2argv-net-coalesce.xml b/tests/qemuxml2argvdata/qemuxml2argv-net-coalesce.xml
+new file mode 100644
+index 000000000..b51032442
+--- /dev/null
++++ b/tests/qemuxml2argvdata/qemuxml2argv-net-coalesce.xml
+@@ -0,0 +1,68 @@
++
++ test
++ 15d091de-0181-456b-9554-e4382dc1f1ab
++ 1048576
++ 1048576
++ 1
++
++ hvm
++
++
++
++
++
++ destroy
++ restart
++ restart
++
++ /usr/bin/qemu-system-x86_64
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
+diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-net-coalesce.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-net-coalesce.xml
+new file mode 100644
+index 000000000..fd5fdbece
+--- /dev/null
++++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-net-coalesce.xml
+@@ -0,0 +1,71 @@
++
++ test
++ 15d091de-0181-456b-9554-e4382dc1f1ab
++ 1048576
++ 1048576
++ 1
++
++ hvm
++
++
++
++
++
++ destroy
++ restart
++ restart
++
++ /usr/bin/qemu-system-x86_64
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
+diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
+index eae999dd6..26a2259fd 100644
+--- a/tests/qemuxml2xmltest.c
++++ b/tests/qemuxml2xmltest.c
+@@ -532,6 +532,7 @@ mymain(void)
+ DO_TEST("net-bandwidth", NONE);
+ DO_TEST("net-bandwidth2", NONE);
+ DO_TEST("net-mtu", NONE);
++ DO_TEST("net-coalesce", NONE);
+
+ DO_TEST("serial-vc", NONE);
+ DO_TEST("serial-pty", NONE);
+--
+2.12.2
+
diff --git a/SOURCES/libvirt-conf-don-t-ignore-target-dev-blah-for-macvtap-interfaces.patch b/SOURCES/libvirt-conf-don-t-ignore-target-dev-blah-for-macvtap-interfaces.patch
new file mode 100644
index 0000000..4b716d6
--- /dev/null
+++ b/SOURCES/libvirt-conf-don-t-ignore-target-dev-blah-for-macvtap-interfaces.patch
@@ -0,0 +1,71 @@
+From c2e748f3d928f8030e5c12b474c427086c962ad4 Mon Sep 17 00:00:00 2001
+Message-Id:
+From: Laine Stump
+Date: Tue, 2 May 2017 12:33:11 -0400
+Subject: [PATCH] conf: don't ignore for macvtap
+ interfaces
+
+The parser had been clearing out *all* suggested device names for
+type='direct' (aka macvtap) interfaces. All of the code implementing
+macvtap allows for a user-specified device name, so we should allow
+it. In the case that an interface name starts with "macvtap" or
+"macvlan" though, we do still clear it out, just as we do with "vnet"
+(which is the prefix used for automatically generated tap device
+names), since those are the prefixes for the names we autogenerate for
+macvtap and macvlan devices.
+
+Resolves: https://bugzilla.redhat.com/1335798
+(cherry picked from commit 9cb891141c4a5a96243c61518c4e0dbcf6a86c24)
+
+Signed-off-by: Jiri Denemark
+---
+ docs/formatdomain.html.in | 6 +++---
+ src/conf/domain_conf.c | 7 ++++++-
+ 2 files changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
+index 2dc5e751a..7e55b0327 100644
+--- a/docs/formatdomain.html.in
++++ b/docs/formatdomain.html.in
+@@ -5207,9 +5207,9 @@ qemu-kvm -net nic,model=? /dev/null
+ If no target is specified, certain hypervisors will
+ automatically generate a name for the created tun device. This
+ name can be manually specified, however the name should not
+- start with either 'vnet' or 'vif', which are prefixes
+- reserved by libvirt and certain hypervisors. Manually specified
+- targets using these prefixes may be ignored.
++ start with either 'vnet', 'vif', 'macvtap', or 'macvlan',
++ which are prefixes reserved by libvirt and certain hypervisors.
++ Manually specified targets using these prefixes may be ignored.
+
+
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 7ab5e5051..84a8a94e5 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -55,6 +55,7 @@
+ #include "virtpm.h"
+ #include "virstring.h"
+ #include "virnetdev.h"
++#include "virnetdevmacvlan.h"
+ #include "virhostdev.h"
+ #include "virmdev.h"
+
+@@ -10016,8 +10017,12 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
+ def->data.direct.linkdev = dev;
+ dev = NULL;
+
+- if (flags & VIR_DOMAIN_DEF_PARSE_INACTIVE)
++ if (ifname &&
++ flags & VIR_DOMAIN_DEF_PARSE_INACTIVE &&
++ (STRPREFIX(ifname, VIR_NET_GENERATED_MACVTAP_PREFIX) ||
++ STRPREFIX(ifname, VIR_NET_GENERATED_MACVTAP_PREFIX))) {
+ VIR_FREE(ifname);
++ }
+
+ break;
+
+--
+2.12.2
+
diff --git a/SOURCES/libvirt-conf-introduce-virDomainControllerDriverFormat.patch b/SOURCES/libvirt-conf-introduce-virDomainControllerDriverFormat.patch
new file mode 100644
index 0000000..5f37f4f
--- /dev/null
+++ b/SOURCES/libvirt-conf-introduce-virDomainControllerDriverFormat.patch
@@ -0,0 +1,104 @@
+From 8874ecd393f7098376d9c46c34f43d47a697f932 Mon Sep 17 00:00:00 2001
+Message-Id: <8874ecd393f7098376d9c46c34f43d47a697f932@dist-git>
+From: =?UTF-8?q?J=C3=A1n=20Tomko?=
+Date: Fri, 9 Jun 2017 12:48:55 +0200
+Subject: [PATCH] conf: introduce virDomainControllerDriverFormat
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Split out formatting the subelement of
+to make adding new options easier.
+
+(cherry picked from commit fe262186dccfa5c5cbcfe5ab7eb95195cf3b10f5)
+Signed-off-by: Ján Tomko
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1283251
+Signed-off-by: Jiri Denemark
+---
+ src/conf/domain_conf.c | 55 +++++++++++++++++++++++++++++---------------------
+ 1 file changed, 32 insertions(+), 23 deletions(-)
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index e004559f9f..275145b1ec 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -21323,6 +21323,37 @@ virDomainDiskDefFormat(virBufferPtr buf,
+ #undef FORMAT_IOTUNE
+
+
++static void
++virDomainControllerDriverFormat(virBufferPtr buf,
++ virDomainControllerDefPtr def)
++{
++ virBuffer driverBuf = VIR_BUFFER_INITIALIZER;
++
++ if (def->queues)
++ virBufferAsprintf(&driverBuf, " queues='%u'", def->queues);
++
++ if (def->cmd_per_lun)
++ virBufferAsprintf(&driverBuf, " cmd_per_lun='%u'", def->cmd_per_lun);
++
++ if (def->max_sectors)
++ virBufferAsprintf(&driverBuf, " max_sectors='%u'", def->max_sectors);
++
++ if (def->ioeventfd) {
++ virBufferAsprintf(&driverBuf, " ioeventfd='%s'",
++ virTristateSwitchTypeToString(def->ioeventfd));
++ }
++
++ if (def->iothread)
++ virBufferAsprintf(&driverBuf, " iothread='%u'", def->iothread);
++
++ if (virBufferUse(&driverBuf)) {
++ virBufferAddLit(buf, "\n");
++ }
++}
++
++
+ static int
+ virDomainControllerDefFormat(virBufferPtr buf,
+ virDomainControllerDefPtr def,
+@@ -21332,7 +21363,6 @@ virDomainControllerDefFormat(virBufferPtr buf,
+ const char *model = NULL;
+ const char *modelName = NULL;
+ bool pcihole64 = false, pciModel = false, pciTarget = false;
+- virBuffer driverBuf = VIR_BUFFER_INITIALIZER;
+
+ if (!type) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+@@ -21437,28 +21467,7 @@ virDomainControllerDefFormat(virBufferPtr buf,
+ }
+ }
+
+- if (def->queues)
+- virBufferAsprintf(&driverBuf, " queues='%u'", def->queues);
+-
+- if (def->cmd_per_lun)
+- virBufferAsprintf(&driverBuf, " cmd_per_lun='%u'", def->cmd_per_lun);
+-
+- if (def->max_sectors)
+- virBufferAsprintf(&driverBuf, " max_sectors='%u'", def->max_sectors);
+-
+- if (def->ioeventfd) {
+- virBufferAsprintf(&driverBuf, " ioeventfd='%s'",
+- virTristateSwitchTypeToString(def->ioeventfd));
+- }
+-
+- if (def->iothread)
+- virBufferAsprintf(&driverBuf, " iothread='%u'", def->iothread);
+-
+- if (virBufferUse(&driverBuf)) {
+- virBufferAddLit(buf, "\n");
+- }
++ virDomainControllerDriverFormat(buf, def);
+
+ if (virDomainDeviceInfoNeedsFormat(&def->info, flags) &&
+ virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
+--
+2.13.1
+
diff --git a/SOURCES/libvirt-conf-nodedev-Split-virNodeDeviceDefFormat-into-more-functions.patch b/SOURCES/libvirt-conf-nodedev-Split-virNodeDeviceDefFormat-into-more-functions.patch
new file mode 100644
index 0000000..7cd3720
--- /dev/null
+++ b/SOURCES/libvirt-conf-nodedev-Split-virNodeDeviceDefFormat-into-more-functions.patch
@@ -0,0 +1,644 @@
+From f636c368f181c9f18ee135e8902490faf30186f9 Mon Sep 17 00:00:00 2001
+Message-Id:
+From: Erik Skultety
+Date: Thu, 18 May 2017 14:02:48 +0200
+Subject: [PATCH] conf: nodedev: Split virNodeDeviceDefFormat into more
+ functions
+
+Make the code look cleaner by moving the capability specific bits into
+separate functions.
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1452072
+
+Signed-off-by: Erik Skultety
+(cherry picked from commit bfaaaf108da087c38cc0f2890ed96730a3734ba8)
+Signed-off-by: Erik Skultety
+Signed-off-by: Jiri Denemark
+---
+ src/conf/node_device_conf.c | 578 ++++++++++++++++++++++++--------------------
+ 1 file changed, 322 insertions(+), 256 deletions(-)
+
+diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
+index cc3fad8b9..02215f32d 100644
+--- a/src/conf/node_device_conf.c
++++ b/src/conf/node_device_conf.c
+@@ -155,6 +155,320 @@ virPCIEDeviceInfoFormat(virBufferPtr buf,
+ }
+
+
++static void
++virNodeDeviceCapSystemDefFormat(virBufferPtr buf,
++ const virNodeDevCapData *data)
++{
++ char uuidstr[VIR_UUID_STRING_BUFLEN];
++
++ if (data->system.product_name)
++ virBufferEscapeString(buf, "%s\n",
++ data->system.product_name);
++ virBufferAddLit(buf, "\n");
++ virBufferAdjustIndent(buf, 2);
++ if (data->system.hardware.vendor_name)
++ virBufferEscapeString(buf, "%s\n",
++ data->system.hardware.vendor_name);
++ if (data->system.hardware.version)
++ virBufferEscapeString(buf, "%s\n",
++ data->system.hardware.version);
++ if (data->system.hardware.serial)
++ virBufferEscapeString(buf, "%s\n",
++ data->system.hardware.serial);
++ virUUIDFormat(data->system.hardware.uuid, uuidstr);
++ virBufferAsprintf(buf, "%s\n", uuidstr);
++ virBufferAdjustIndent(buf, -2);
++ virBufferAddLit(buf, "\n");
++
++ virBufferAddLit(buf, "\n");
++ virBufferAdjustIndent(buf, 2);
++ if (data->system.firmware.vendor_name)
++ virBufferEscapeString(buf, "%s\n",
++ data->system.firmware.vendor_name);
++ if (data->system.firmware.version)
++ virBufferEscapeString(buf, "%s\n",
++ data->system.firmware.version);
++ if (data->system.firmware.release_date)
++ virBufferEscapeString(buf, "%s\n",
++ data->system.firmware.release_date);
++ virBufferAdjustIndent(buf, -2);
++ virBufferAddLit(buf, "\n");
++}
++
++
++static void
++virNodeDeviceCapPCIDefFormat(virBufferPtr buf,
++ const virNodeDevCapData *data)
++{
++ size_t i;
++
++ virBufferAsprintf(buf, "%d\n",
++ data->pci_dev.domain);
++ virBufferAsprintf(buf, "%d\n", data->pci_dev.bus);
++ virBufferAsprintf(buf, "%d\n",
++ data->pci_dev.slot);
++ virBufferAsprintf(buf, "%d\n",
++ data->pci_dev.function);
++ virBufferAsprintf(buf, "pci_dev.product);
++ if (data->pci_dev.product_name)
++ virBufferEscapeString(buf, ">%s\n",
++ data->pci_dev.product_name);
++ else
++ virBufferAddLit(buf, " />\n");
++ virBufferAsprintf(buf, "pci_dev.vendor);
++ if (data->pci_dev.vendor_name)
++ virBufferEscapeString(buf, ">%s\n",
++ data->pci_dev.vendor_name);
++ else
++ virBufferAddLit(buf, " />\n");
++ if (data->pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION) {
++ virBufferAddLit(buf, "\n");
++ virBufferAdjustIndent(buf, 2);
++ virBufferAsprintf(buf,
++ "\n",
++ data->pci_dev.physical_function->domain,
++ data->pci_dev.physical_function->bus,
++ data->pci_dev.physical_function->slot,
++ data->pci_dev.physical_function->function);
++ virBufferAdjustIndent(buf, -2);
++ virBufferAddLit(buf, "\n");
++ }
++ if (data->pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION) {
++ virBufferAddLit(buf, "pci_dev.max_virtual_functions)
++ virBufferAsprintf(buf, " maxCount='%u'",
++ data->pci_dev.max_virtual_functions);
++ if (data->pci_dev.num_virtual_functions == 0) {
++ virBufferAddLit(buf, "/>\n");
++ } else {
++ virBufferAddLit(buf, ">\n");
++ virBufferAdjustIndent(buf, 2);
++ for (i = 0; i < data->pci_dev.num_virtual_functions; i++) {
++ virBufferAsprintf(buf,
++ "\n",
++ data->pci_dev.virtual_functions[i]->domain,
++ data->pci_dev.virtual_functions[i]->bus,
++ data->pci_dev.virtual_functions[i]->slot,
++ data->pci_dev.virtual_functions[i]->function);
++ }
++ virBufferAdjustIndent(buf, -2);
++ virBufferAddLit(buf, "\n");
++ }
++ }
++ if (data->pci_dev.hdrType) {
++ virBufferAsprintf(buf, "\n",
++ virPCIHeaderTypeToString(data->pci_dev.hdrType));
++ }
++ if (data->pci_dev.nIommuGroupDevices) {
++ virBufferAsprintf(buf, "\n",
++ data->pci_dev.iommuGroupNumber);
++ virBufferAdjustIndent(buf, 2);
++ for (i = 0; i < data->pci_dev.nIommuGroupDevices; i++) {
++ virBufferAsprintf(buf,
++ "\n",
++ data->pci_dev.iommuGroupDevices[i]->domain,
++ data->pci_dev.iommuGroupDevices[i]->bus,
++ data->pci_dev.iommuGroupDevices[i]->slot,
++ data->pci_dev.iommuGroupDevices[i]->function);
++ }
++ virBufferAdjustIndent(buf, -2);
++ virBufferAddLit(buf, "\n");
++ }
++ if (data->pci_dev.numa_node >= 0)
++ virBufferAsprintf(buf, "\n",
++ data->pci_dev.numa_node);
++
++ if (data->pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCIE)
++ virPCIEDeviceInfoFormat(buf, data->pci_dev.pci_express);
++}
++
++
++static void
++virNodeDeviceCapUSBDevDefFormat(virBufferPtr buf,
++ const virNodeDevCapData *data)
++{
++ virBufferAsprintf(buf, "%d\n", data->usb_dev.bus);
++ virBufferAsprintf(buf, "%d\n",
++ data->usb_dev.device);
++ virBufferAsprintf(buf, "usb_dev.product);
++ if (data->usb_dev.product_name)
++ virBufferEscapeString(buf, ">%s\n",
++ data->usb_dev.product_name);
++ else
++ virBufferAddLit(buf, " />\n");
++ virBufferAsprintf(buf, "usb_dev.vendor);
++ if (data->usb_dev.vendor_name)
++ virBufferEscapeString(buf, ">%s\n",
++ data->usb_dev.vendor_name);
++ else
++ virBufferAddLit(buf, " />\n");
++}
++
++
++static void
++virNodeDeviceCapUSBInterfaceDefFormat(virBufferPtr buf,
++ const virNodeDevCapData *data)
++{
++ virBufferAsprintf(buf, "%d\n",
++ data->usb_if.number);
++ virBufferAsprintf(buf, "%d\n",
++ data->usb_if._class);
++ virBufferAsprintf(buf, "%d\n",
++ data->usb_if.subclass);
++ virBufferAsprintf(buf, "%d\n",
++ data->usb_if.protocol);
++ if (data->usb_if.description)
++ virBufferEscapeString(buf,
++ "%s\n",
++ data->usb_if.description);
++}
++
++
++static void
++virNodeDeviceCapNetDefFormat(virBufferPtr buf,
++ const virNodeDevCapData *data)
++{
++ size_t i;
++
++ virBufferEscapeString(buf, "%s\n",
++ data->net.ifname);
++ if (data->net.address)
++ virBufferEscapeString(buf, "%s\n",
++ data->net.address);
++ virInterfaceLinkFormat(buf, &data->net.lnk);
++ if (data->net.features) {
++ for (i = 0; i < VIR_NET_DEV_FEAT_LAST; i++) {
++ if (virBitmapIsBitSet(data->net.features, i)) {
++ virBufferAsprintf(buf, "\n",
++ virNetDevFeatureTypeToString(i));
++ }
++ }
++ }
++ if (data->net.subtype != VIR_NODE_DEV_CAP_NET_LAST) {
++ const char *subtyp =
++ virNodeDevNetCapTypeToString(data->net.subtype);
++ virBufferEscapeString(buf, "\n",
++ subtyp);
++ }
++}
++
++
++static void
++virNodeDeviceCapSCSIHostDefFormat(virBufferPtr buf,
++ const virNodeDevCapData *data)
++{
++ virBufferAsprintf(buf, "%d\n",
++ data->scsi_host.host);
++ if (data->scsi_host.unique_id != -1)
++ virBufferAsprintf(buf, "%d\n",
++ data->scsi_host.unique_id);
++ if (data->scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) {
++ virBufferAddLit(buf, "\n");
++ virBufferAdjustIndent(buf, 2);
++ virBufferEscapeString(buf, "%s\n",
++ data->scsi_host.wwnn);
++ virBufferEscapeString(buf, "%s\n",
++ data->scsi_host.wwpn);
++ virBufferEscapeString(buf, "%s\n",
++ data->scsi_host.fabric_wwn);
++ virBufferAdjustIndent(buf, -2);
++ virBufferAddLit(buf, "\n");
++ }
++ if (data->scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS) {
++ virBufferAddLit(buf, "\n");
++ virBufferAdjustIndent(buf, 2);
++ virBufferAsprintf(buf, "%d\n",
++ data->scsi_host.max_vports);
++ virBufferAsprintf(buf, "%d\n",
++ data->scsi_host.vports);
++ virBufferAdjustIndent(buf, -2);
++ virBufferAddLit(buf, "\n");
++ }
++}
++
++
++static void
++virNodeDeviceCapSCSIDefFormat(virBufferPtr buf,
++ const virNodeDevCapData *data)
++{
++ virBufferAsprintf(buf, "%d\n", data->scsi.host);
++ virBufferAsprintf(buf, "%d\n", data->scsi.bus);
++ virBufferAsprintf(buf, "%d\n",
++ data->scsi.target);
++ virBufferAsprintf(buf, "%d\n", data->scsi.lun);
++ if (data->scsi.type)
++ virBufferEscapeString(buf, "%s\n",
++ data->scsi.type);
++}
++
++
++static void
++virNodeDeviceCapStorageDefFormat(virBufferPtr buf,
++ const virNodeDevCapData *data)
++{
++ virBufferEscapeString(buf, "%s\n",
++ data->storage.block);
++ if (data->storage.bus)
++ virBufferEscapeString(buf, "%s\n",
++ data->storage.bus);
++ if (data->storage.drive_type)
++ virBufferEscapeString(buf, "%s\n",
++ data->storage.drive_type);
++ if (data->storage.model)
++ virBufferEscapeString(buf, "%s\n",
++ data->storage.model);
++ if (data->storage.vendor)
++ virBufferEscapeString(buf, "%s\n",
++ data->storage.vendor);
++ if (data->storage.serial)
++ virBufferEscapeString(buf, "%s\n",
++ data->storage.serial);
++ if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_REMOVABLE) {
++ int avl = data->storage.flags &
++ VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE;
++ virBufferAddLit(buf, "\n");
++ virBufferAdjustIndent(buf, 2);
++ virBufferAsprintf(buf, "%d"
++ "\n", avl ? 1 : 0);
++ virBufferAsprintf(buf, "%llu\n",
++ data->storage.removable_media_size);
++ if (data->storage.media_label)
++ virBufferEscapeString(buf,
++ "%s\n",
++ data->storage.media_label);
++ if (data->storage.logical_block_size > 0)
++ virBufferAsprintf(buf, "%llu"
++ "\n",
++ data->storage.logical_block_size);
++ if (data->storage.num_blocks > 0)
++ virBufferAsprintf(buf,
++ "%llu\n",
++ data->storage.num_blocks);
++ virBufferAdjustIndent(buf, -2);
++ virBufferAddLit(buf, "\n");
++ } else {
++ virBufferAsprintf(buf, "%llu\n",
++ data->storage.size);
++ if (data->storage.logical_block_size > 0)
++ virBufferAsprintf(buf, "%llu"
++ "\n",
++ data->storage.logical_block_size);
++ if (data->storage.num_blocks > 0)
++ virBufferAsprintf(buf, "%llu\n",
++ data->storage.num_blocks);
++ }
++ if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE)
++ virBufferAddLit(buf, "\n");
++}
++
++
+ char *
+ virNodeDeviceDefFormat(const virNodeDeviceDef *def)
+ {
+@@ -185,7 +499,6 @@ virNodeDeviceDefFormat(const virNodeDeviceDef *def)
+ }
+
+ for (caps = def->caps; caps; caps = caps->next) {
+- char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virNodeDevCapDataPtr data = &caps->data;
+
+ virBufferAsprintf(&buf, "\n",
+@@ -193,279 +506,32 @@ virNodeDeviceDefFormat(const virNodeDeviceDef *def)
+ virBufferAdjustIndent(&buf, 2);
+ switch (caps->data.type) {
+ case VIR_NODE_DEV_CAP_SYSTEM:
+- if (data->system.product_name)
+- virBufferEscapeString(&buf, "%s\n",
+- data->system.product_name);
+- virBufferAddLit(&buf, "\n");
+- virBufferAdjustIndent(&buf, 2);
+- if (data->system.hardware.vendor_name)
+- virBufferEscapeString(&buf, "%s\n",
+- data->system.hardware.vendor_name);
+- if (data->system.hardware.version)
+- virBufferEscapeString(&buf, "%s\n",
+- data->system.hardware.version);
+- if (data->system.hardware.serial)
+- virBufferEscapeString(&buf, "%s\n",
+- data->system.hardware.serial);
+- virUUIDFormat(data->system.hardware.uuid, uuidstr);
+- virBufferAsprintf(&buf, "%s\n", uuidstr);
+- virBufferAdjustIndent(&buf, -2);
+- virBufferAddLit(&buf, "\n");
+-
+- virBufferAddLit(&buf, "\n");
+- virBufferAdjustIndent(&buf, 2);
+- if (data->system.firmware.vendor_name)
+- virBufferEscapeString(&buf, "%s\n",
+- data->system.firmware.vendor_name);
+- if (data->system.firmware.version)
+- virBufferEscapeString(&buf, "%s\n",
+- data->system.firmware.version);
+- if (data->system.firmware.release_date)
+- virBufferEscapeString(&buf, "%s\n",
+- data->system.firmware.release_date);
+- virBufferAdjustIndent(&buf, -2);
+- virBufferAddLit(&buf, "\n");
++ virNodeDeviceCapSystemDefFormat(&buf, data);
+ break;
+ case VIR_NODE_DEV_CAP_PCI_DEV:
+- virBufferAsprintf(&buf, "%d\n",
+- data->pci_dev.domain);
+- virBufferAsprintf(&buf, "%d\n", data->pci_dev.bus);
+- virBufferAsprintf(&buf, "%d\n",
+- data->pci_dev.slot);
+- virBufferAsprintf(&buf, "%d\n",
+- data->pci_dev.function);
+- virBufferAsprintf(&buf, "pci_dev.product);
+- if (data->pci_dev.product_name)
+- virBufferEscapeString(&buf, ">%s\n",
+- data->pci_dev.product_name);
+- else
+- virBufferAddLit(&buf, " />\n");
+- virBufferAsprintf(&buf, "pci_dev.vendor);
+- if (data->pci_dev.vendor_name)
+- virBufferEscapeString(&buf, ">%s\n",
+- data->pci_dev.vendor_name);
+- else
+- virBufferAddLit(&buf, " />\n");
+- if (data->pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_PHYSICAL_FUNCTION) {
+- virBufferAddLit(&buf, "\n");
+- virBufferAdjustIndent(&buf, 2);
+- virBufferAsprintf(&buf,
+- "\n",
+- data->pci_dev.physical_function->domain,
+- data->pci_dev.physical_function->bus,
+- data->pci_dev.physical_function->slot,
+- data->pci_dev.physical_function->function);
+- virBufferAdjustIndent(&buf, -2);
+- virBufferAddLit(&buf, "\n");
+- }
+- if (data->pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION) {
+- virBufferAddLit(&buf, "pci_dev.max_virtual_functions)
+- virBufferAsprintf(&buf, " maxCount='%u'",
+- data->pci_dev.max_virtual_functions);
+- if (data->pci_dev.num_virtual_functions == 0) {
+- virBufferAddLit(&buf, "/>\n");
+- } else {
+- virBufferAddLit(&buf, ">\n");
+- virBufferAdjustIndent(&buf, 2);
+- for (i = 0; i < data->pci_dev.num_virtual_functions; i++) {
+- virBufferAsprintf(&buf,
+- "\n",
+- data->pci_dev.virtual_functions[i]->domain,
+- data->pci_dev.virtual_functions[i]->bus,
+- data->pci_dev.virtual_functions[i]->slot,
+- data->pci_dev.virtual_functions[i]->function);
+- }
+- virBufferAdjustIndent(&buf, -2);
+- virBufferAddLit(&buf, "\n");
+- }
+- }
+- if (data->pci_dev.hdrType) {
+- virBufferAsprintf(&buf, "\n",
+- virPCIHeaderTypeToString(data->pci_dev.hdrType));
+- }
+- if (data->pci_dev.nIommuGroupDevices) {
+- virBufferAsprintf(&buf, "\n",
+- data->pci_dev.iommuGroupNumber);
+- virBufferAdjustIndent(&buf, 2);
+- for (i = 0; i < data->pci_dev.nIommuGroupDevices; i++) {
+- virBufferAsprintf(&buf,
+- "\n",
+- data->pci_dev.iommuGroupDevices[i]->domain,
+- data->pci_dev.iommuGroupDevices[i]->bus,
+- data->pci_dev.iommuGroupDevices[i]->slot,
+- data->pci_dev.iommuGroupDevices[i]->function);
+- }
+- virBufferAdjustIndent(&buf, -2);
+- virBufferAddLit(&buf, "\n");
+- }
+- if (data->pci_dev.numa_node >= 0)
+- virBufferAsprintf(&buf, "\n",
+- data->pci_dev.numa_node);
+-
+- if (data->pci_dev.flags & VIR_NODE_DEV_CAP_FLAG_PCIE)
+- virPCIEDeviceInfoFormat(&buf, data->pci_dev.pci_express);
++ virNodeDeviceCapPCIDefFormat(&buf, data);
+ break;
+ case VIR_NODE_DEV_CAP_USB_DEV:
+- virBufferAsprintf(&buf, "%d\n", data->usb_dev.bus);
+- virBufferAsprintf(&buf, "%d\n",
+- data->usb_dev.device);
+- virBufferAsprintf(&buf, "usb_dev.product);
+- if (data->usb_dev.product_name)
+- virBufferEscapeString(&buf, ">%s\n",
+- data->usb_dev.product_name);
+- else
+- virBufferAddLit(&buf, " />\n");
+- virBufferAsprintf(&buf, "usb_dev.vendor);
+- if (data->usb_dev.vendor_name)
+- virBufferEscapeString(&buf, ">%s\n",
+- data->usb_dev.vendor_name);
+- else
+- virBufferAddLit(&buf, " />\n");
++ virNodeDeviceCapUSBDevDefFormat(&buf, data);
+ break;
+ case VIR_NODE_DEV_CAP_USB_INTERFACE:
+- virBufferAsprintf(&buf, "%d\n",
+- data->usb_if.number);
+- virBufferAsprintf(&buf, "%d\n",
+- data->usb_if._class);
+- virBufferAsprintf(&buf, "%d\n",
+- data->usb_if.subclass);
+- virBufferAsprintf(&buf, "%d\n",
+- data->usb_if.protocol);
+- if (data->usb_if.description)
+- virBufferEscapeString(&buf,
+- "%s\n",
+- data->usb_if.description);
++ virNodeDeviceCapUSBInterfaceDefFormat(&buf, data);
+ break;
+ case VIR_NODE_DEV_CAP_NET:
+- virBufferEscapeString(&buf, "%s\n",
+- data->net.ifname);
+- if (data->net.address)
+- virBufferEscapeString(&buf, "%s\n",
+- data->net.address);
+- virInterfaceLinkFormat(&buf, &data->net.lnk);
+- if (data->net.features) {
+- for (i = 0; i < VIR_NET_DEV_FEAT_LAST; i++) {
+- if (virBitmapIsBitSet(data->net.features, i)) {
+- virBufferAsprintf(&buf, "\n",
+- virNetDevFeatureTypeToString(i));
+- }
+- }
+- }
+- if (data->net.subtype != VIR_NODE_DEV_CAP_NET_LAST) {
+- const char *subtyp =
+- virNodeDevNetCapTypeToString(data->net.subtype);
+- virBufferEscapeString(&buf, "\n",
+- subtyp);
+- }
++ virNodeDeviceCapNetDefFormat(&buf, data);
+ break;
+ case VIR_NODE_DEV_CAP_SCSI_HOST:
+- virBufferAsprintf(&buf, "%d\n",
+- data->scsi_host.host);
+- if (data->scsi_host.unique_id != -1)
+- virBufferAsprintf(&buf, "%d\n",
+- data->scsi_host.unique_id);
+- if (data->scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_FC_HOST) {
+- virBufferAddLit(&buf, "\n");
+- virBufferAdjustIndent(&buf, 2);
+- virBufferEscapeString(&buf, "%s\n",
+- data->scsi_host.wwnn);
+- virBufferEscapeString(&buf, "%s\n",
+- data->scsi_host.wwpn);
+- virBufferEscapeString(&buf, "%s\n",
+- data->scsi_host.fabric_wwn);
+- virBufferAdjustIndent(&buf, -2);
+- virBufferAddLit(&buf, "\n");
+- }
+- if (data->scsi_host.flags & VIR_NODE_DEV_CAP_FLAG_HBA_VPORT_OPS) {
+- virBufferAddLit(&buf, "\n");
+- virBufferAdjustIndent(&buf, 2);
+- virBufferAsprintf(&buf, "%d\n",
+- data->scsi_host.max_vports);
+- virBufferAsprintf(&buf, "%d\n",
+- data->scsi_host.vports);
+- virBufferAdjustIndent(&buf, -2);
+- virBufferAddLit(&buf, "\n");
+- }
+-
++ virNodeDeviceCapSCSIHostDefFormat(&buf, data);
+ break;
+-
+ case VIR_NODE_DEV_CAP_SCSI_TARGET:
+ virBufferEscapeString(&buf, "%s\n",
+ data->scsi_target.name);
+ break;
+-
+ case VIR_NODE_DEV_CAP_SCSI:
+- virBufferAsprintf(&buf, "%d\n", data->scsi.host);
+- virBufferAsprintf(&buf, "%d\n", data->scsi.bus);
+- virBufferAsprintf(&buf, "%d\n",
+- data->scsi.target);
+- virBufferAsprintf(&buf, "%d\n", data->scsi.lun);
+- if (data->scsi.type)
+- virBufferEscapeString(&buf, "%s\n",
+- data->scsi.type);
++ virNodeDeviceCapSCSIDefFormat(&buf, data);
+ break;
+ case VIR_NODE_DEV_CAP_STORAGE:
+- virBufferEscapeString(&buf, "%s\n",
+- data->storage.block);
+- if (data->storage.bus)
+- virBufferEscapeString(&buf, "%s\n",
+- data->storage.bus);
+- if (data->storage.drive_type)
+- virBufferEscapeString(&buf, "%s\n",
+- data->storage.drive_type);
+- if (data->storage.model)
+- virBufferEscapeString(&buf, "%s\n",
+- data->storage.model);
+- if (data->storage.vendor)
+- virBufferEscapeString(&buf, "%s\n",
+- data->storage.vendor);
+- if (data->storage.serial)
+- virBufferEscapeString(&buf, "%s\n",
+- data->storage.serial);
+- if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_REMOVABLE) {
+- int avl = data->storage.flags &
+- VIR_NODE_DEV_CAP_STORAGE_REMOVABLE_MEDIA_AVAILABLE;
+- virBufferAddLit(&buf, "\n");
+- virBufferAdjustIndent(&buf, 2);
+- virBufferAsprintf(&buf, "%d"
+- "\n", avl ? 1 : 0);
+- virBufferAsprintf(&buf, "%llu\n",
+- data->storage.removable_media_size);
+- if (data->storage.media_label)
+- virBufferEscapeString(&buf,
+- "%s\n",
+- data->storage.media_label);
+- if (data->storage.logical_block_size > 0)
+- virBufferAsprintf(&buf, "%llu"
+- "\n",
+- data->storage.logical_block_size);
+- if (data->storage.num_blocks > 0)
+- virBufferAsprintf(&buf,
+- "%llu\n",
+- data->storage.num_blocks);
+- virBufferAdjustIndent(&buf, -2);
+- virBufferAddLit(&buf, "\n");
+- } else {
+- virBufferAsprintf(&buf, "%llu\n",
+- data->storage.size);
+- if (data->storage.logical_block_size > 0)
+- virBufferAsprintf(&buf, "%llu"
+- "\n",
+- data->storage.logical_block_size);
+- if (data->storage.num_blocks > 0)
+- virBufferAsprintf(&buf, "%llu\n",
+- data->storage.num_blocks);
+- }
+- if (data->storage.flags & VIR_NODE_DEV_CAP_STORAGE_HOTPLUGGABLE)
+- virBufferAddLit(&buf, "\n");
++ virNodeDeviceCapStorageDefFormat(&buf, data);
+ break;
+ case VIR_NODE_DEV_CAP_SCSI_GENERIC:
+ virBufferEscapeString(&buf, "%s\n",
+--
+2.13.0
+
diff --git a/SOURCES/libvirt-conf-split-out-virDomainIOMMUDefCheckABIStability.patch b/SOURCES/libvirt-conf-split-out-virDomainIOMMUDefCheckABIStability.patch
new file mode 100644
index 0000000..9d33757
--- /dev/null
+++ b/SOURCES/libvirt-conf-split-out-virDomainIOMMUDefCheckABIStability.patch
@@ -0,0 +1,64 @@
+From 244b42c385fc611380bfb2532905a63ce4380254 Mon Sep 17 00:00:00 2001
+Message-Id: <244b42c385fc611380bfb2532905a63ce4380254@dist-git>
+From: =?UTF-8?q?J=C3=A1n=20Tomko?=
+Date: Tue, 16 May 2017 10:44:58 +0200
+Subject: [PATCH] conf: split out virDomainIOMMUDefCheckABIStability
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+(cherry picked from commit 3a276c6524026b661ed7bee4539fc5387b963611)
+Signed-off-by: Ján Tomko
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1427005
+Signed-off-by: Jiri Denemark
+---
+ src/conf/domain_conf.c | 24 +++++++++++++++++-------
+ 1 file changed, 17 insertions(+), 7 deletions(-)
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index e77b542f3..7bf480f2a 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -19810,6 +19810,22 @@ virDomainMemoryDefCheckABIStability(virDomainMemoryDefPtr src,
+
+
+ static bool
++virDomainIOMMUDefCheckABIStability(virDomainIOMMUDefPtr src,
++ virDomainIOMMUDefPtr dst)
++{
++ if (src->model != dst->model) {
++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
++ _("Target domain IOMMU device model '%s' "
++ "does not match source '%s'"),
++ virDomainIOMMUModelTypeToString(dst->model),
++ virDomainIOMMUModelTypeToString(src->model));
++ return false;
++ }
++ return true;
++}
++
++
++static bool
+ virDomainDefVcpuCheckAbiStability(virDomainDefPtr src,
+ virDomainDefPtr dst)
+ {
+@@ -20275,14 +20291,8 @@ virDomainDefCheckABIStabilityFlags(virDomainDefPtr src,
+ }
+
+ if (src->iommu &&
+- src->iommu->model != dst->iommu->model) {
+- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+- _("Target domain IOMMU device model '%s' "
+- "does not match source '%s'"),
+- virDomainIOMMUModelTypeToString(dst->iommu->model),
+- virDomainIOMMUModelTypeToString(src->iommu->model));
++ !virDomainIOMMUDefCheckABIStability(src->iommu, dst->iommu))
+ goto error;
+- }
+
+ /* Coverity is not very happy with this - all dead_error_condition */
+ #if !STATIC_ANALYSIS
+--
+2.13.0
+
diff --git a/SOURCES/libvirt-conf-use-a-leading-space-in-virDomainVirtioNetDriverFormat.patch b/SOURCES/libvirt-conf-use-a-leading-space-in-virDomainVirtioNetDriverFormat.patch
new file mode 100644
index 0000000..fe28da8
--- /dev/null
+++ b/SOURCES/libvirt-conf-use-a-leading-space-in-virDomainVirtioNetDriverFormat.patch
@@ -0,0 +1,77 @@
+From 5238dd8211d06fc8c7003bb608e41bb2a4653dec Mon Sep 17 00:00:00 2001
+Message-Id: <5238dd8211d06fc8c7003bb608e41bb2a4653dec@dist-git>
+From: =?UTF-8?q?J=C3=A1n=20Tomko?=
+Date: Fri, 9 Jun 2017 12:48:59 +0200
+Subject: [PATCH] conf: use a leading space in virDomainVirtioNetDriverFormat
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Instead of formatting a space after every option.
+
+Reviewed-by: Pavel Hrdina
+(cherry picked from commit d1feb4773d41b928dc1079dfc19d17b5a0e5957b)
+Signed-off-by: Ján Tomko
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1283251
+Signed-off-by: Jiri Denemark
+---
+ src/conf/domain_conf.c | 18 ++++++++----------
+ 1 file changed, 8 insertions(+), 10 deletions(-)
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 701a6d2136..4652e1c72b 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -22053,29 +22053,27 @@ virDomainVirtioNetDriverFormat(char **outstr,
+ {
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ if (def->driver.virtio.name) {
+- virBufferAsprintf(&buf, "name='%s' ",
++ virBufferAsprintf(&buf, " name='%s'",
+ virDomainNetBackendTypeToString(def->driver.virtio.name));
+ }
+ if (def->driver.virtio.txmode) {
+- virBufferAsprintf(&buf, "txmode='%s' ",
++ virBufferAsprintf(&buf, " txmode='%s'",
+ virDomainNetVirtioTxModeTypeToString(def->driver.virtio.txmode));
+ }
+ if (def->driver.virtio.ioeventfd) {
+- virBufferAsprintf(&buf, "ioeventfd='%s' ",
++ virBufferAsprintf(&buf, " ioeventfd='%s'",
+ virTristateSwitchTypeToString(def->driver.virtio.ioeventfd));
+ }
+ if (def->driver.virtio.event_idx) {
+- virBufferAsprintf(&buf, "event_idx='%s' ",
++ virBufferAsprintf(&buf, " event_idx='%s'",
+ virTristateSwitchTypeToString(def->driver.virtio.event_idx));
+ }
+ if (def->driver.virtio.queues)
+- virBufferAsprintf(&buf, "queues='%u' ", def->driver.virtio.queues);
++ virBufferAsprintf(&buf, " queues='%u'", def->driver.virtio.queues);
+ if (def->driver.virtio.rx_queue_size)
+- virBufferAsprintf(&buf, "rx_queue_size='%u' ",
++ virBufferAsprintf(&buf, " rx_queue_size='%u'",
+ def->driver.virtio.rx_queue_size);
+
+- virBufferTrim(&buf, " ", -1);
+-
+ if (virBufferCheckError(&buf) < 0)
+ return -1;
+
+@@ -22323,10 +22321,10 @@ virDomainNetDefFormat(virBufferPtr buf,
+
+ if (!gueststr && !hoststr) {
+ if (str)
+- virBufferAsprintf(buf, "\n", str);
++ virBufferAsprintf(buf, "\n", str);
+ } else {
+ if (str)
+- virBufferAsprintf(buf, "\n", str);
++ virBufferAsprintf(buf, "\n", str);
+ else
+ virBufferAddLit(buf, "\n");
+ virBufferAdjustIndent(buf, 2);
+--
+2.13.1
+
diff --git a/SOURCES/libvirt-cpu-Drop-feature-filtering-from-virCPUUpdate.patch b/SOURCES/libvirt-cpu-Drop-feature-filtering-from-virCPUUpdate.patch
new file mode 100644
index 0000000..239d248
--- /dev/null
+++ b/SOURCES/libvirt-cpu-Drop-feature-filtering-from-virCPUUpdate.patch
@@ -0,0 +1,58 @@
+From 2642333131bda397dc4b00fd945efdd34e2aa314 Mon Sep 17 00:00:00 2001
+Message-Id: <2642333131bda397dc4b00fd945efdd34e2aa314@dist-git>
+From: Jiri Denemark
+Date: Wed, 29 Mar 2017 15:00:21 +0200
+Subject: [PATCH] cpu: Drop feature filtering from virCPUUpdate
+
+Because of the changes done in the previous commit, @host is already a
+migratable CPU and there's no need to do any additional filtering.
+
+Signed-off-by: Jiri Denemark
+(cherry picked from commit 232d87c7dd081d126a079fb45178e0be096cc680)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1444421
+
+Signed-off-by: Jiri Denemark
+---
+ src/cpu/cpu_x86.c | 9 +++------
+ 1 file changed, 3 insertions(+), 6 deletions(-)
+
+diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
+index a771b251e..53359ff9b 100644
+--- a/src/cpu/cpu_x86.c
++++ b/src/cpu/cpu_x86.c
+@@ -2549,8 +2549,7 @@ x86Baseline(virCPUDefPtr *cpus,
+
+ static int
+ x86UpdateHostModel(virCPUDefPtr guest,
+- const virCPUDef *host,
+- virCPUx86MapPtr map)
++ const virCPUDef *host)
+ {
+ virCPUDefPtr updated = NULL;
+ size_t i;
+@@ -2559,11 +2558,9 @@ x86UpdateHostModel(virCPUDefPtr guest,
+ if (!(updated = virCPUDefCopyWithoutModel(host)))
+ goto cleanup;
+
+- /* Remove non-migratable features by default */
+ updated->type = VIR_CPU_TYPE_GUEST;
+ updated->mode = VIR_CPU_MODE_CUSTOM;
+- if (virCPUDefCopyModelFilter(updated, host, true,
+- x86FeatureIsMigratable, map) < 0)
++ if (virCPUDefCopyModel(updated, host, true) < 0)
+ goto cleanup;
+
+ if (guest->vendor_id) {
+@@ -2627,7 +2624,7 @@ virCPUx86Update(virCPUDefPtr guest,
+
+ if (guest->mode == VIR_CPU_MODE_HOST_MODEL ||
+ guest->match == VIR_CPU_MATCH_MINIMUM)
+- ret = x86UpdateHostModel(guest, host, map);
++ ret = x86UpdateHostModel(guest, host);
+ else
+ ret = 0;
+
+--
+2.12.2
+
diff --git a/SOURCES/libvirt-cpu-Introduce-virCPUCopyMigratable.patch b/SOURCES/libvirt-cpu-Introduce-virCPUCopyMigratable.patch
new file mode 100644
index 0000000..382224f
--- /dev/null
+++ b/SOURCES/libvirt-cpu-Introduce-virCPUCopyMigratable.patch
@@ -0,0 +1,154 @@
+From 57b2e02a1c4cf52f3ea1ec3af469dd4e44402595 Mon Sep 17 00:00:00 2001
+Message-Id: <57b2e02a1c4cf52f3ea1ec3af469dd4e44402595@dist-git>
+From: Jiri Denemark
+Date: Wed, 29 Mar 2017 14:45:44 +0200
+Subject: [PATCH] cpu: Introduce virCPUCopyMigratable
+
+This new internal API makes a copy of virCPUDef while removing all
+features which would block migration. It uses cpu_map.xml as a database
+of such features, which should only be used as a fallback when we cannot
+get the data from a hypervisor. The main goal of this API is to decouple
+this filtering from virCPUUpdate so that the hypervisor driver can
+filter the features according to the hypervisor.
+
+Signed-off-by: Jiri Denemark
+(cherry picked from commit 05e91c79f19e0be96526098d58a3498dac3f8529)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1444421
+
+Signed-off-by: Jiri Denemark
+---
+ src/cpu/cpu.c | 31 +++++++++++++++++++++++++++++++
+ src/cpu/cpu.h | 8 ++++++++
+ src/cpu/cpu_x86.c | 25 +++++++++++++++++++++++++
+ src/libvirt_private.syms | 1 +
+ 4 files changed, 65 insertions(+)
+
+diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c
+index 93647a2ed..8a407ac18 100644
+--- a/src/cpu/cpu.c
++++ b/src/cpu/cpu.c
+@@ -1130,3 +1130,34 @@ virCPUExpandFeatures(virArch arch,
+ VIR_DEBUG("nfeatures=%zu", cpu->nfeatures);
+ return 0;
+ }
++
++
++/**
++ * virCPUCopyMigratable:
++ *
++ * @arch: CPU architecture
++ * @cpu: CPU definition to be copied
++ *
++ * Makes a copy of @cpu with all features which would block migration removed.
++ * If this doesn't make sense for a given architecture, the function returns a
++ * plain copy of @cpu (i.e., a copy with no features removed).
++ *
++ * Returns the copy of the CPU or NULL on error.
++ */
++virCPUDefPtr
++virCPUCopyMigratable(virArch arch,
++ virCPUDefPtr cpu)
++{
++ struct cpuArchDriver *driver;
++
++ VIR_DEBUG("arch=%s, cpu=%p, model=%s",
++ virArchToString(arch), cpu, NULLSTR(cpu->model));
++
++ if (!(driver = cpuGetSubDriver(arch)))
++ return NULL;
++
++ if (driver->copyMigratable)
++ return driver->copyMigratable(cpu);
++ else
++ return virCPUDefCopy(cpu);
++}
+diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h
+index 8c238ad55..352445c40 100644
+--- a/src/cpu/cpu.h
++++ b/src/cpu/cpu.h
+@@ -118,6 +118,9 @@ typedef int
+ typedef int
+ (*virCPUArchExpandFeatures)(virCPUDefPtr cpu);
+
++typedef virCPUDefPtr
++(*virCPUArchCopyMigratable)(virCPUDefPtr cpu);
++
+ struct cpuArchDriver {
+ const char *name;
+ const virArch *arch;
+@@ -138,6 +141,7 @@ struct cpuArchDriver {
+ virCPUArchTranslate translate;
+ virCPUArchConvertLegacy convertLegacy;
+ virCPUArchExpandFeatures expandFeatures;
++ virCPUArchCopyMigratable copyMigratable;
+ };
+
+
+@@ -254,6 +258,10 @@ int
+ virCPUExpandFeatures(virArch arch,
+ virCPUDefPtr cpu);
+
++virCPUDefPtr
++virCPUCopyMigratable(virArch arch,
++ virCPUDefPtr cpu);
++
+ /* virCPUDataFormat and virCPUDataParse are implemented for unit tests only and
+ * have no real-life usage
+ */
+diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
+index 48648a7f4..a771b251e 100644
+--- a/src/cpu/cpu_x86.c
++++ b/src/cpu/cpu_x86.c
+@@ -2903,6 +2903,30 @@ virCPUx86ExpandFeatures(virCPUDefPtr cpu)
+ }
+
+
++static virCPUDefPtr
++virCPUx86CopyMigratable(virCPUDefPtr cpu)
++{
++ virCPUDefPtr copy;
++ virCPUx86MapPtr map;
++
++ if (!(map = virCPUx86GetMap()))
++ return NULL;
++
++ if (!(copy = virCPUDefCopyWithoutModel(cpu)))
++ return NULL;
++
++ if (virCPUDefCopyModelFilter(copy, cpu, false,
++ x86FeatureIsMigratable, map) < 0)
++ goto error;
++
++ return copy;
++
++ error:
++ virCPUDefFree(copy);
++ return NULL;
++}
++
++
+ int
+ virCPUx86DataAddCPUID(virCPUDataPtr cpuData,
+ const virCPUx86CPUID *cpuid)
+@@ -2978,4 +3002,5 @@ struct cpuArchDriver cpuDriverX86 = {
+ .getModels = virCPUx86GetModels,
+ .translate = virCPUx86Translate,
+ .expandFeatures = virCPUx86ExpandFeatures,
++ .copyMigratable = virCPUx86CopyMigratable,
+ };
+diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
+index 9a334311d..cc78c5975 100644
+--- a/src/libvirt_private.syms
++++ b/src/libvirt_private.syms
+@@ -1018,6 +1018,7 @@ virCPUCheckFeature;
+ virCPUCompare;
+ virCPUCompareXML;
+ virCPUConvertLegacy;
++virCPUCopyMigratable;
+ virCPUDataCheckFeature;
+ virCPUDataFormat;
+ virCPUDataFree;
+--
+2.12.2
+
diff --git a/SOURCES/libvirt-cpu-Introduce-virCPUGetHostIsSupported.patch b/SOURCES/libvirt-cpu-Introduce-virCPUGetHostIsSupported.patch
new file mode 100644
index 0000000..87757a9
--- /dev/null
+++ b/SOURCES/libvirt-cpu-Introduce-virCPUGetHostIsSupported.patch
@@ -0,0 +1,83 @@
+From 401cbf50f18234b0631b4b0e01b9e403137fee95 Mon Sep 17 00:00:00 2001
+Message-Id: <401cbf50f18234b0631b4b0e01b9e403137fee95@dist-git>
+From: Jiri Denemark
+Date: Tue, 11 Apr 2017 20:45:07 +0200
+Subject: [PATCH] cpu: Introduce virCPUGetHostIsSupported
+
+Sometimes we want to call virCPUGetHost only when it is implemented for
+a given architecture to avoid logging expected and possibly misleading
+errors. The new virCPUGetHostIsSupported API may be used to guard such
+calls to virCPUGetHost.
+
+Signed-off-by: Jiri Denemark
+(cherry picked from commit bf1a881715c905c67f7d38dcd5bd6c2afbff1f9b)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1444421
+
+Signed-off-by: Jiri Denemark
+---
+ src/cpu/cpu.c | 20 ++++++++++++++++++++
+ src/cpu/cpu.h | 3 +++
+ src/libvirt_private.syms | 1 +
+ 3 files changed, 24 insertions(+)
+
+diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c
+index 8a407ac18..702b14dbb 100644
+--- a/src/cpu/cpu.c
++++ b/src/cpu/cpu.c
+@@ -358,6 +358,26 @@ virCPUDataFree(virCPUDataPtr data)
+
+
+ /**
++ * virCPUGetHostIsSupported:
++ *
++ * @arch: CPU architecture
++ *
++ * Check whether virCPUGetHost is supported for @arch.
++ *
++ * Returns true if virCPUGetHost is supported, false otherwise.
++ */
++bool
++virCPUGetHostIsSupported(virArch arch)
++{
++ struct cpuArchDriver *driver;
++
++ VIR_DEBUG("arch=%s", virArchToString(arch));
++
++ return (driver = cpuGetSubDriver(arch)) && driver->getHost;
++}
++
++
++/**
+ * virCPUGetHost:
+ *
+ * @arch: CPU architecture
+diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h
+index 352445c40..c6ca111e9 100644
+--- a/src/cpu/cpu.h
++++ b/src/cpu/cpu.h
+@@ -183,6 +183,9 @@ virCPUDataNew(virArch arch);
+ void
+ virCPUDataFree(virCPUDataPtr data);
+
++bool
++virCPUGetHostIsSupported(virArch arch);
++
+ virCPUDefPtr
+ virCPUGetHost(virArch arch,
+ virCPUType type,
+diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
+index cc78c5975..d802e7598 100644
+--- a/src/libvirt_private.syms
++++ b/src/libvirt_private.syms
+@@ -1026,6 +1026,7 @@ virCPUDataNew;
+ virCPUDataParse;
+ virCPUExpandFeatures;
+ virCPUGetHost;
++virCPUGetHostIsSupported;
+ virCPUGetModels;
+ virCPUProbeHost;
+ virCPUTranslate;
+--
+2.12.2
+
diff --git a/SOURCES/libvirt-cpu_ppc64-Add-support-for-host-model-on-POWER9.patch b/SOURCES/libvirt-cpu_ppc64-Add-support-for-host-model-on-POWER9.patch
new file mode 100644
index 0000000..db7e944
--- /dev/null
+++ b/SOURCES/libvirt-cpu_ppc64-Add-support-for-host-model-on-POWER9.patch
@@ -0,0 +1,182 @@
+From 3feb7797cfe7ac9cfd05fbc5d008527b1a88c06a Mon Sep 17 00:00:00 2001
+Message-Id: <3feb7797cfe7ac9cfd05fbc5d008527b1a88c06a@dist-git>
+From: Jiri Denemark
+Date: Wed, 17 May 2017 16:39:16 +0200
+Subject: [PATCH] cpu_ppc64: Add support for host-model on POWER9
+
+Signed-off-by: Jiri Denemark
+(cherry picked from commit 5c8c2d1633f3d2500e49132296793fc267648d2b)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1450770
+
+Signed-off-by: Jiri Denemark
+---
+ src/cpu/cpu_ppc64.c | 8 ++++----
+ .../qemuxml2argv-pseries-cpu-compat-power9.args | 24 ++++++++++++++++++++++
+ .../qemuxml2argv-pseries-cpu-compat-power9.xml | 21 +++++++++++++++++++
+ tests/qemuxml2argvtest.c | 7 +++++++
+ tests/testutilsqemu.c | 13 +++++++++++-
+ tests/testutilsqemu.h | 1 +
+ 6 files changed, 69 insertions(+), 5 deletions(-)
+ create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-compat-power9.args
+ create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-compat-power9.xml
+
+diff --git a/src/cpu/cpu_ppc64.c b/src/cpu/cpu_ppc64.c
+index f64592b558..bf08599049 100644
+--- a/src/cpu/cpu_ppc64.c
++++ b/src/cpu/cpu_ppc64.c
+@@ -92,22 +92,22 @@ ppc64CheckCompatibilityMode(const char *host_model,
+ if (!compat_mode)
+ return VIR_CPU_COMPARE_IDENTICAL;
+
+- /* Valid host CPUs: POWER6, POWER7, POWER8 */
++ /* Valid host CPUs: POWER6, POWER7, POWER8, POWER9 */
+ if (!STRPREFIX(host_model, "POWER") ||
+ !(tmp = (char *) host_model + strlen("POWER")) ||
+ virStrToLong_i(tmp, NULL, 10, &host) < 0 ||
+- host < 6 || host > 8) {
++ host < 6 || host > 9) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s",
+ _("Host CPU does not support compatibility modes"));
+ goto out;
+ }
+
+- /* Valid compatibility modes: power6, power7, power8 */
++ /* Valid compatibility modes: power6, power7, power8, power9 */
+ if (!STRPREFIX(compat_mode, "power") ||
+ !(tmp = (char *) compat_mode + strlen("power")) ||
+ virStrToLong_i(tmp, NULL, 10, &compat) < 0 ||
+- compat < 6 || compat > 8) {
++ compat < 6 || compat > 9) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown compatibility mode %s"),
+ compat_mode);
+diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-compat-power9.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-compat-power9.args
+new file mode 100644
+index 0000000000..af93d63dc9
+--- /dev/null
++++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-compat-power9.args
+@@ -0,0 +1,24 @@
++LC_ALL=C \
++PATH=/bin \
++HOME=/home/test \
++USER=test \
++LOGNAME=test \
++QEMU_AUDIO_DRV=none \
++/usr/bin/qemu-system-ppc64 \
++-name QEMUGuest1 \
++-S \
++-M pseries \
++-cpu host,compat=power9 \
++-m 256 \
++-smp 4,sockets=4,cores=1,threads=1 \
++-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
++-nographic \
++-nodefconfig \
++-nodefaults \
++-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\
++server,nowait \
++-mon chardev=charmonitor,id=monitor,mode=readline \
++-boot c \
++-usb \
++-chardev pty,id=charserial0 \
++-device spapr-vty,chardev=charserial0,reg=0x30000000
+diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-compat-power9.xml b/tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-compat-power9.xml
+new file mode 100644
+index 0000000000..30ab5c2679
+--- /dev/null
++++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-cpu-compat-power9.xml
+@@ -0,0 +1,21 @@
++
++ QEMUGuest1
++ c7a5fdbd-edaf-9455-926a-d65c16db1809
++ 219100
++ 219100
++ 4
++
++ hvm
++
++
++ power9
++
++
++
++ /usr/bin/qemu-system-ppc64
++
++
++
++
++
++
+diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
+index 5ca27f105d..6ac24c9bb0 100644
+--- a/tests/qemuxml2argvtest.c
++++ b/tests/qemuxml2argvtest.c
+@@ -1688,6 +1688,13 @@ mymain(void)
+ QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG);
+ DO_TEST("pseries-cpu-le", QEMU_CAPS_KVM,
+ QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG);
++ DO_TEST_FAILURE("pseries-cpu-compat-power9", QEMU_CAPS_KVM);
++
++ qemuTestSetHostCPU(driver.caps, cpuPower9);
++ DO_TEST("pseries-cpu-compat-power9",
++ QEMU_CAPS_KVM, QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG);
++ qemuTestSetHostCPU(driver.caps, NULL);
++
+ qemuTestSetHostArch(driver.caps, VIR_ARCH_NONE);
+
+ DO_TEST("pseries-panic-missing",
+diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c
+index 4cc482dfb0..fe2941efbf 100644
+--- a/tests/testutilsqemu.c
++++ b/tests/testutilsqemu.c
+@@ -17,6 +17,7 @@
+ virCPUDefPtr cpuDefault;
+ virCPUDefPtr cpuHaswell;
+ virCPUDefPtr cpuPower8;
++virCPUDefPtr cpuPower9;
+
+ static virCPUFeatureDef cpuDefaultFeatures[] = {
+ { (char *) "ds", -1 },
+@@ -94,6 +95,15 @@ static virCPUDef cpuPower8Data = {
+ .threads = 8,
+ };
+
++static virCPUDef cpuPower9Data = {
++ .type = VIR_CPU_TYPE_HOST,
++ .arch = VIR_ARCH_PPC64,
++ .model = (char *) "POWER9",
++ .sockets = 1,
++ .cores = 16,
++ .threads = 1,
++};
++
+ static virCapsGuestMachinePtr *testQemuAllocMachines(int *nmachines)
+ {
+ virCapsGuestMachinePtr *machines;
+@@ -334,7 +344,8 @@ virCapsPtr testQemuCapsInit(void)
+
+ if (!(cpuDefault = virCPUDefCopy(&cpuDefaultData)) ||
+ !(cpuHaswell = virCPUDefCopy(&cpuHaswellData)) ||
+- !(cpuPower8 = virCPUDefCopy(&cpuPower8Data)))
++ !(cpuPower8 = virCPUDefCopy(&cpuPower8Data)) ||
++ !(cpuPower9 = virCPUDefCopy(&cpuPower9Data)))
+ goto cleanup;
+
+ qemuTestSetHostCPU(caps, NULL);
+diff --git a/tests/testutilsqemu.h b/tests/testutilsqemu.h
+index 047a64d1ac..781b435cc2 100644
+--- a/tests/testutilsqemu.h
++++ b/tests/testutilsqemu.h
+@@ -21,6 +21,7 @@ virQEMUCapsPtr qemuTestParseCapabilities(virCapsPtr caps,
+ extern virCPUDefPtr cpuDefault;
+ extern virCPUDefPtr cpuHaswell;
+ extern virCPUDefPtr cpuPower8;
++extern virCPUDefPtr cpuPower9;
+
+ void qemuTestSetHostArch(virCapsPtr caps,
+ virArch arch);
+--
+2.13.1
+
diff --git a/SOURCES/libvirt-daemon-Don-t-initialize-SASL-context-if-not-necessary.patch b/SOURCES/libvirt-daemon-Don-t-initialize-SASL-context-if-not-necessary.patch
new file mode 100644
index 0000000..159fca0
--- /dev/null
+++ b/SOURCES/libvirt-daemon-Don-t-initialize-SASL-context-if-not-necessary.patch
@@ -0,0 +1,43 @@
+From 8c9296cbe21657aadbc4bff88eabd617168349f6 Mon Sep 17 00:00:00 2001
+Message-Id: <8c9296cbe21657aadbc4bff88eabd617168349f6@dist-git>
+From: Peter Krempa
+Date: Fri, 2 Jun 2017 15:07:59 +0200
+Subject: [PATCH] daemon: Don't initialize SASL context if not necessary
+
+SASL context would be initialized even if the corresponding TCP or TLS
+sockets are not enabled.
+
+fe772f24a68 attempted to fix the symptom by commenting out the settings,
+but that did not fix the root cause. 3c647ee4bbb later reverted those
+changes so that the more secure algorithm is used.
+
+Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1450095
+(cherry picked from commit ed914284ba74afb7dd16dcb623073bb1a1d5cd21)
+
+Signed-off-by: Jiri Denemark
+---
+ daemon/libvirtd.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
+index 891238bcbe..bac4bc1b65 100644
+--- a/daemon/libvirtd.c
++++ b/daemon/libvirtd.c
+@@ -613,11 +613,11 @@ daemonSetupNetworking(virNetServerPtr srv,
+
+ #if WITH_SASL
+ if (config->auth_unix_rw == REMOTE_AUTH_SASL ||
+- config->auth_unix_ro == REMOTE_AUTH_SASL ||
++ (sock_path_ro && config->auth_unix_ro == REMOTE_AUTH_SASL) ||
+ # if WITH_GNUTLS
+- config->auth_tls == REMOTE_AUTH_SASL ||
++ (ipsock && config->listen_tls && config->auth_tls == REMOTE_AUTH_SASL) ||
+ # endif
+- config->auth_tcp == REMOTE_AUTH_SASL) {
++ (ipsock && config->listen_tcp && config->auth_tcp == REMOTE_AUTH_SASL)) {
+ saslCtxt = virNetSASLContextNewServer(
+ (const char *const*)config->sasl_allowed_username_list);
+ if (!saslCtxt)
+--
+2.13.1
+
diff --git a/SOURCES/libvirt-disk-Force-usage-of-parted-when-checking-disk-format-for-bsd.patch b/SOURCES/libvirt-disk-Force-usage-of-parted-when-checking-disk-format-for-bsd.patch
new file mode 100644
index 0000000..e867cc5
--- /dev/null
+++ b/SOURCES/libvirt-disk-Force-usage-of-parted-when-checking-disk-format-for-bsd.patch
@@ -0,0 +1,43 @@
+From 911438df6c652e377f80712c67da90aed91444b7 Mon Sep 17 00:00:00 2001
+Message-Id: <911438df6c652e377f80712c67da90aed91444b7@dist-git>
+From: John Ferlan
+Date: Wed, 26 Apr 2017 08:41:09 -0400
+Subject: [PATCH] disk: Force usage of parted when checking disk format for
+ "bsd"
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1439132
+
+Add "bsd" to the list of format types to not checked during blkid
+processing even though it supposedly knows the format - for some
+(now unknown) reason it's returning partition table not found. So
+let's just let PARTED handle "bsd" too.
+
+Signed-off-by: John Ferlan
+(cherry picked from commit 98f424d5038b362d1b62549930d0b9253106bdca)
+Signed-off-by: Jiri Denemark
+---
+ src/storage/storage_util.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/src/storage/storage_util.c b/src/storage/storage_util.c
+index 7a458b828..adec9ab6f 100644
+--- a/src/storage/storage_util.c
++++ b/src/storage/storage_util.c
+@@ -3002,10 +3002,12 @@ virStorageBackendBLKIDFindPart(blkid_probe probe,
+
+ /* A blkid_known_pttype on "dvh" and "pc98" returns a failure;
+ * however, the blkid_do_probe for "dvh" returns "sgi" and
+- * for "pc98" it returns "dos". So since those will cause problems
++ * for "pc98" it returns "dos". Although "bsd" is recognized,
++ * it seems that the parted created partition table is not being
++ * properly recogized. Since each of these will cause problems
+ * with startup comparison, let's just treat them as UNKNOWN causing
+ * the caller to fallback to using PARTED */
+- if (STREQ(format, "dvh") || STREQ(format, "pc98"))
++ if (STREQ(format, "dvh") || STREQ(format, "pc98") || STREQ(format, "bsd"))
+ return VIR_STORAGE_BLKID_PROBE_UNKNOWN;
+
+ /* Make sure we're doing a partitions probe from the start */
+--
+2.12.2
+
diff --git a/SOURCES/libvirt-disk-Resolve-issues-with-disk-partition-build-start-checks.patch b/SOURCES/libvirt-disk-Resolve-issues-with-disk-partition-build-start-checks.patch
new file mode 100644
index 0000000..77b111d
--- /dev/null
+++ b/SOURCES/libvirt-disk-Resolve-issues-with-disk-partition-build-start-checks.patch
@@ -0,0 +1,40 @@
+From 5c1a822cfa7993b1f55f90b75b66c86787a063d1 Mon Sep 17 00:00:00 2001
+Message-Id: <5c1a822cfa7993b1f55f90b75b66c86787a063d1@dist-git>
+From: John Ferlan
+Date: Wed, 26 Apr 2017 08:41:08 -0400
+Subject: [PATCH] disk: Resolve issues with disk partition build/start checks
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1439132
+
+Commit id 'a48c674fb' added a check for format types "dvh" and "pc98"
+to use the parted print processing instead of using blkid processing
+in order to validate the label on the disk was what is expected for
+disk pool startup. However, commit id 'a4cb4a74f' really messed things
+up by missing an else condition causing PARTEDFindLabel to always
+return DIFFERENT.
+
+Signed-off-by: John Ferlan
+(cherry picked from commit f2a123203105b4fe010aea866e87f8bcf5f31193)
+Signed-off-by: Jiri Denemark
+---
+ src/storage/storage_util.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/storage/storage_util.c b/src/storage/storage_util.c
+index 0ceaab6b9..7a458b828 100644
+--- a/src/storage/storage_util.c
++++ b/src/storage/storage_util.c
+@@ -3213,8 +3213,8 @@ virStorageBackendPARTEDFindLabel(const char *device,
+ /* Does the on disk match what the pool desired? */
+ if (STREQ(start, format))
+ ret = VIR_STORAGE_PARTED_MATCH;
+-
+- ret = VIR_STORAGE_PARTED_DIFFERENT;
++ else
++ ret = VIR_STORAGE_PARTED_DIFFERENT;
+
+ cleanup:
+ virCommandFree(cmd);
+--
+2.12.2
+
diff --git a/SOURCES/libvirt-disk-Use-virStorageBackendZeroPartitionTable.patch b/SOURCES/libvirt-disk-Use-virStorageBackendZeroPartitionTable.patch
new file mode 100644
index 0000000..705de4d
--- /dev/null
+++ b/SOURCES/libvirt-disk-Use-virStorageBackendZeroPartitionTable.patch
@@ -0,0 +1,56 @@
+From 9aeaadcf7d7f33cc5208bcbc788676f27691843a Mon Sep 17 00:00:00 2001
+Message-Id: <9aeaadcf7d7f33cc5208bcbc788676f27691843a@dist-git>
+From: John Ferlan
+Date: Wed, 26 Apr 2017 08:41:14 -0400
+Subject: [PATCH] disk: Use virStorageBackendZeroPartitionTable
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1439132
+
+During 'matrix' testing of all possible combinations I found that if
+device is formated with "gpt" first, then an attempt is made to format
+using "mac", a startup will fail.
+
+Deeper analysis by Peter Krempa indicates that the "mac" table fits
+into the first block on the disk. Since the GPT disklabel is stored
+at LBA address 1 it is not overwritten at all. Thus it's apparent that
+the (blkid) detection tool then prefers GPT over a older disklabel.
+
+The GPT disklabel has also a secondary copy at the last LBA of the disk.
+
+So, follow the same logic as the logical pool in clearing a 1MB swath
+at the beginning and end of the device to avoid potential issues with
+larger sector sizes for the device.
+
+Also fixed a minor formatting nit in virStorageBackendDeviceIsEmpty call.
+
+(cherry picked from commit 3c4f2e3fb725054921f855a229afc7daca7119ae)
+Signed-off-by: John Ferlan
+Signed-off-by: Jiri Denemark
+---
+ src/storage/storage_backend_disk.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/src/storage/storage_backend_disk.c b/src/storage/storage_backend_disk.c
+index 39371f2d9..e8f67bb00 100644
+--- a/src/storage/storage_backend_disk.c
++++ b/src/storage/storage_backend_disk.c
+@@ -491,11 +491,15 @@ virStorageBackendDiskBuildPool(virConnectPtr conn ATTRIBUTE_UNUSED,
+ ok_to_mklabel = true;
+ } else {
+ if (virStorageBackendDeviceIsEmpty(pool->def->source.devices[0].path,
+- fmt, true))
++ fmt, true))
+ ok_to_mklabel = true;
+ }
+
+ if (ok_to_mklabel) {
++ if (virStorageBackendZeroPartitionTable(pool->def->source.devices[0].path,
++ 1024 * 1024) < 0)
++ goto error;
++
+ /* eg parted /dev/sda mklabel --script msdos */
+ if (format == VIR_STORAGE_POOL_DISK_UNKNOWN)
+ format = pool->def->source.format = VIR_STORAGE_POOL_DISK_DOS;
+--
+2.12.2
+
diff --git a/SOURCES/libvirt-docs-Document-the-mediated-devices-within-the-nodedev-driver.patch b/SOURCES/libvirt-docs-Document-the-mediated-devices-within-the-nodedev-driver.patch
new file mode 100644
index 0000000..fa10ab2
--- /dev/null
+++ b/SOURCES/libvirt-docs-Document-the-mediated-devices-within-the-nodedev-driver.patch
@@ -0,0 +1,231 @@
+From 9a202d80f7b60fcf6caf059570bfd2d0b0cbe8a4 Mon Sep 17 00:00:00 2001
+Message-Id: <9a202d80f7b60fcf6caf059570bfd2d0b0cbe8a4@dist-git>
+From: Erik Skultety
+Date: Thu, 18 May 2017 14:02:55 +0200
+Subject: [PATCH] docs: Document the mediated devices within the nodedev driver
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1452072
+
+Signed-off-by: Erik Skultety
+(cherry picked from commit a0a0b3cf71cbee1df40dd0fdebd7bb6a84682f09)
+Signed-off-by: Erik Skultety
+Signed-off-by: Jiri Denemark
+---
+ docs/drvnodedev.html.in | 168 +++++++++++++++++++++++++++++++++++++++++++++++-
+ tools/virsh.pod | 7 +-
+ 2 files changed, 171 insertions(+), 4 deletions(-)
+
+diff --git a/docs/drvnodedev.html.in b/docs/drvnodedev.html.in
+index 0a3870343..26c52dd0d 100644
+--- a/docs/drvnodedev.html.in
++++ b/docs/drvnodedev.html.in
+@@ -9,7 +9,7 @@
+ (historically also referred to as node devices) like USB, PCI, SCSI, and
+ network devices. This also includes various virtualization capabilities
+ which the aforementioned devices provide for utilization, for example
+- SR-IOV, NPIV, DRM, etc.
++ SR-IOV, NPIV, MDEV, DRM, etc.
+
+
+
+@@ -75,6 +75,7 @@
+ storage (Since 1.0.4),
+ scsi_generic (Since 1.0.7),
+ drm (Since 3.1.0), and
++ mdev (Since 3.4.0).
+ This element can be nested in which case it further specifies a
+ device's capability. Refer to specific device types to see more values
+ for the type attribute which are exclusive.
+@@ -185,5 +186,170 @@
+ ...
+ <device>
+
++
++ A PCI device capable of creating mediated devices will include a nested
++ capability mdev_types which enumerates all supported mdev
++ types on the physical device, along with the type attributes available
++ through sysfs:
++
++
++
++
type
++
++ This element describes a mediated device type which acts as an
++ abstract template defining a resource allocation for instances of this
++ device type. The element has one attribute id which holds
++ an official vendor-supplied identifier for the type.
++ Since 3.4.0
++
++
++
name
++
++ The name element holds a vendor-supplied code name for
++ the given mediated device type. This is an optional element.
++ Since 3.4.0
++
++
++
deviceAPI
++
++ The value of this element describes how an instance of the given type
++ will be presented to the guest by the VFIO framework.
++ Since 3.4.0
++
++
++
availableInstances
++
++ This element reports the current state of resource allocation. In other
++ words, how many instances of the given type can still be successfully
++ created on the physical device.
++ Since 3.4.0
++
++
++
++
++ For a more info about mediated devices, refer to the
++ paragraph below.
++
++
++
++<device>
++...
++ <driver>
++ <name>nvidia</name>
++ </driver>
++ <capability type='pci'>
++...
++ <capability type='mdev_types'>
++ <type id='nvidia-11'>
++ <name>GRID M60-0B</name>
++ <deviceAPI>vfio-pci</deviceAPI>
++ <availableInstances>16</availableInstances>
++ </type>
++ <!-- Here would come the rest of the available mdev types -->
++ </capability>
++...
++ </capability>
++</device>
++ Mediated devices (Since 3.2.0) are software
++ devices defining resource allocation on the backing physical device which
++ in turn allows the parent physical device's resources to be divided into
++ several mediated devices, thus sharing the physical device's performance
++ among multiple guests. Unlike SR-IOV however, where a PCIe device appears
++ as multiple separate PCIe devices on the host's PCI bus, mediated devices
++ only appear on the mdev virtual bus. Therefore, no detach/reattach
++ procedure from/to the host driver procedure is involved even though
++ mediated devices are used in a direct device assignment manner.
++
++
++
++ The following sub-elements and attributes are exposed within the
++ capability element:
++
++
++
++
type
++
++ This element describes a mediated device type which acts as an
++ abstract template defining a resource allocation for instances of this
++ device type. The element has one attribute id which holds
++ an official vendor-supplied identifier for the type.
++ Since 3.4.0
++
++
++
iommuGroup
++
++ This element supports a single attribute number which holds
++ the IOMMU group number the mediated device belongs to.
++ Since 3.4.0
++
++ The support of mediated device's framework in libvirt's node device driver
++ covers the following features:
++
++
++
++
++ list available mediated devices on the host
++ (Since 3.4.0)
++
++
++ display device details
++ (Since 3.4.0)
++
++
++
++
++ Because mediated devices are instantiated from vendor specific templates,
++ simply called 'types', information describing these types is contained
++ within the parent device's capabilities
++ (see the example in PCI host devices).
++
++
++
++ To see the supported mediated device types on a specific physical device
++ use the following:
++
++
++
++$ ls /sys/class/mdev_bus/<device>/mdev_supported_types
++
++
++ To manually instantiate a mediated device, use one of the following as a
++ reference:
++