--- /dev/null
+From 65d750dec286074fc48fdaa64eb3f5029626506f Mon Sep 17 00:00:00 2001
+Message-Id: <65d750dec286074fc48fdaa64eb3f5029626506f@dist-git>
+From: =?UTF-8?q?J=C3=A1n=20Tomko?= <jtomko@redhat.com>
+Date: Tue, 6 May 2014 13:55:44 +0200
+Subject: [PATCH] Add invariant TSC cpu flag
+
+Add suport for invariant TSC flag (CPUID 0x80000007, bit 8 of EDX).
+If this flag is enabled, the TSC ticks at a constant rate across
+all ACPI P-, C- and T-states.
+
+This can be enabled by adding:
+<feature name='invtsc'/>
+to the <cpu> element.
+
+Migration and saving the domain does not work with this flag.
+
+QEMU support: http://git.qemu.org/?p=qemu.git;a=commitdiff;h=303752a
+
+The feature name "invtsc" differs from the name "" used by the linux kernel:
+https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/arch/x86/kernel/cpu/powerflags.c?id=30321c7b#n18
+
+(cherry picked from commit fba6bc47cbcabbe08d42279691efb0dff3b9c997)
+https://bugzilla.redhat.com/show_bug.cgi?id=1185458
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/cpu/cpu_map.xml | 5 +++++
+ src/qemu/qemu_migration.c | 15 +++++++++++++++
+ src/qemu/qemu_process.c | 15 +++++++++++++++
+ 3 files changed, 35 insertions(+)
+
+diff --git a/src/cpu/cpu_map.xml b/src/cpu/cpu_map.xml
+index 6d51283..aa10019 100644
+--- a/src/cpu/cpu_map.xml
++++ b/src/cpu/cpu_map.xml
+@@ -327,6 +327,11 @@
+ <cpuid function='0x00000007' ebx='0x00100000'/>
+ </feature>
+
++ <!-- Advanced Power Management edx features -->
++ <feature name='invtsc'>
++ <cpuid function='0x80000007' edx='0x00000100'/>
++ </feature>
++
+ <!-- models -->
+ <model name='486'>
+ <feature name='fpu'/>
+diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
+index deacb66..d979d50 100644
+--- a/src/qemu/qemu_migration.c
++++ b/src/qemu/qemu_migration.c
+@@ -1506,6 +1506,21 @@ qemuMigrationIsAllowed(virQEMUDriverPtr driver, virDomainObjPtr vm,
+ return false;
+ }
+
++ for (i = 0; i < def->cpu->nfeatures; i++) {
++ virCPUFeatureDefPtr feature = &def->cpu->features[i];
++
++ if (feature->policy != VIR_CPU_FEATURE_REQUIRE)
++ continue;
++
++ /* QEMU blocks migration and save with invariant TSC enabled */
++ if (STREQ(feature->name, "invtsc")) {
++ virReportError(VIR_ERR_OPERATION_INVALID,
++ _("domain has CPU feature: %s"),
++ feature->name);
++ return false;
++ }
++ }
++
+ return true;
+ }
+
+diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
+index 3eda15b..8c07397 100644
+--- a/src/qemu/qemu_process.c
++++ b/src/qemu/qemu_process.c
+@@ -3520,6 +3520,7 @@ qemuProcessVerifyGuestCPU(virQEMUDriverPtr driver, virDomainObjPtr vm)
+ virCPUDataPtr guestcpu = NULL;
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ bool ret = false;
++ size_t i;
+
+ switch (arch) {
+ case VIR_ARCH_I686:
+@@ -3538,6 +3539,20 @@ qemuProcessVerifyGuestCPU(virQEMUDriverPtr driver, virDomainObjPtr vm)
+ goto cleanup;
+ }
+ }
++
++ for (i = 0; i < def->cpu->nfeatures; i++) {
++ virCPUFeatureDefPtr feature = &def->cpu->features[i];
++
++ if (feature->policy != VIR_CPU_FEATURE_REQUIRE)
++ continue;
++
++ if (STREQ(feature->name, "invtsc") &&
++ !cpuHasFeature(guestcpu, feature->name)) {
++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
++ _("host doesn't support invariant TSC"));
++ goto cleanup;
++ }
++ }
+ break;
+
+ default:
+--
+2.2.2
+
--- /dev/null
+From b2c63abced4d6e2f263125ab903917549fcd3abd Mon Sep 17 00:00:00 2001
+Message-Id: <b2c63abced4d6e2f263125ab903917549fcd3abd@dist-git>
+From: =?UTF-8?q?J=C3=A1n=20Tomko?= <jtomko@redhat.com>
+Date: Mon, 29 Sep 2014 12:44:43 +0200
+Subject: [PATCH] Also filter out non-migratable features out of
+ host-passthrough
+
+Commit de0aeaf filtered them out from the host-model features,
+to allow host-model to be migratable by default.
+
+Even though they are not passed to QEMU for host-passthrough,
+(and not enabled by default) filter them out too
+so the user does not think the domain has them.
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1147584
+(cherry picked from commit f53bb1af90737205fdbfd26dc99865c02457d8c9)
+https://bugzilla.redhat.com/show_bug.cgi?id=1185458
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+
+Conflicts:
+ src/cpu/cpu_x86.c -- context; const virCPUDefPtr vs. const
+ virCPUDef * (changed by d694ae0c)
+---
+ src/cpu/cpu_x86.c | 14 ++++++--------
+ 1 file changed, 6 insertions(+), 8 deletions(-)
+
+diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
+index 341a7f5..dffa488 100644
+--- a/src/cpu/cpu_x86.c
++++ b/src/cpu/cpu_x86.c
+@@ -1984,7 +1984,8 @@ cleanup:
+
+ static int
+ x86UpdateHostModel(virCPUDefPtr guest,
+- const virCPUDefPtr host)
++ const virCPUDefPtr host,
++ bool passthrough)
+ {
+ virCPUDefPtr oldguest = NULL;
+ const struct x86_map *map;
+@@ -1992,8 +1993,6 @@ x86UpdateHostModel(virCPUDefPtr guest,
+ size_t i;
+ int ret = -1;
+
+- guest->match = VIR_CPU_MATCH_EXACT;
+-
+ if (!(map = virCPUx86GetMap()))
+ goto cleanup;
+
+@@ -2016,8 +2015,7 @@ x86UpdateHostModel(virCPUDefPtr guest,
+ }
+ }
+ }
+-
+- for (i = 0; i < oldguest->nfeatures; i++) {
++ for (i = 0; !passthrough && i < oldguest->nfeatures; i++) {
+ if (virCPUDefUpdateFeature(guest,
+ oldguest->features[i].name,
+ oldguest->features[i].policy) < 0)
+@@ -2041,12 +2039,12 @@ x86Update(virCPUDefPtr guest,
+ return x86UpdateCustom(guest, host);
+
+ case VIR_CPU_MODE_HOST_MODEL:
+- return x86UpdateHostModel(guest, host);
++ guest->match = VIR_CPU_MATCH_EXACT;
++ return x86UpdateHostModel(guest, host, false);
+
+ case VIR_CPU_MODE_HOST_PASSTHROUGH:
+ guest->match = VIR_CPU_MATCH_MINIMUM;
+- virCPUDefFreeModel(guest);
+- return virCPUDefCopyModel(guest, host, true);
++ return x86UpdateHostModel(guest, host, true);
+
+ case VIR_CPU_MODE_LAST:
+ break;
+--
+2.2.2
+
--- /dev/null
+From 10be3da4947fc7923732e2056516a41514bd1695 Mon Sep 17 00:00:00 2001
+Message-Id: <10be3da4947fc7923732e2056516a41514bd1695@dist-git>
+From: =?UTF-8?q?J=C3=A1n=20Tomko?= <jtomko@redhat.com>
+Date: Fri, 5 Sep 2014 09:50:36 +0200
+Subject: [PATCH] Don't include non-migratable features in host-model
+
+Commit fba6bc4 introduced support for the 'invtsc' feature,
+which blocks migration. We should not include it in the
+host-model CPU by default, because it's intended to be used
+with migration.
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1138221
+(cherry picked from commit de0aeafe9ce3eb414c8b5d3aa8995d776a2952de)
+https://bugzilla.redhat.com/show_bug.cgi?id=1185458
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+
+Conflicts:
+ src/cpu/cpu_x86.c - context -- missing {} (fixed by ff78ff7c)
+---
+ src/cpu/cpu_map.xml | 2 +-
+ src/cpu/cpu_x86.c | 65 ++++++++++++++++++++++--
+ tests/cputest.c | 1 +
+ tests/cputestdata/x86-host-invtsc+host-model.xml | 22 ++++++++
+ tests/cputestdata/x86-host-invtsc.xml | 27 ++++++++++
+ 5 files changed, 111 insertions(+), 6 deletions(-)
+ create mode 100644 tests/cputestdata/x86-host-invtsc+host-model.xml
+ create mode 100644 tests/cputestdata/x86-host-invtsc.xml
+
+diff --git a/src/cpu/cpu_map.xml b/src/cpu/cpu_map.xml
+index aa10019..28bc5ec 100644
+--- a/src/cpu/cpu_map.xml
++++ b/src/cpu/cpu_map.xml
+@@ -328,7 +328,7 @@
+ </feature>
+
+ <!-- Advanced Power Management edx features -->
+- <feature name='invtsc'>
++ <feature name='invtsc' migratable='no'>
+ <cpuid function='0x80000007' edx='0x00000100'/>
+ </feature>
+
+diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
+index 4e77550..8ced69d 100644
+--- a/src/cpu/cpu_x86.c
++++ b/src/cpu/cpu_x86.c
+@@ -87,6 +87,7 @@ struct x86_map {
+ struct x86_vendor *vendors;
+ struct x86_feature *features;
+ struct x86_model *models;
++ struct x86_feature *migrate_blockers;
+ };
+
+ static struct x86_map* virCPUx86Map = NULL;
+@@ -590,6 +591,28 @@ x86FeatureFree(struct x86_feature *feature)
+
+
+ static struct x86_feature *
++x86FeatureCopy(const struct x86_feature *src)
++{
++ struct x86_feature *feature;
++
++ if (VIR_ALLOC(feature) < 0)
++ return NULL;
++
++ if (VIR_STRDUP(feature->name, src->name) < 0)
++ goto error;
++
++ if ((feature->data = x86DataCopy(src->data)) == NULL)
++ goto error;
++
++ return feature;
++
++ error:
++ x86FeatureFree(feature);
++ return NULL;
++}
++
++
++static struct x86_feature *
+ x86FeatureFind(const struct x86_map *map,
+ const char *name)
+ {
+@@ -675,6 +698,9 @@ x86FeatureLoad(xmlXPathContextPtr ctxt,
+ int ret = 0;
+ size_t i;
+ int n;
++ char *str = NULL;
++ bool migratable = true;
++ struct x86_feature *migrate_blocker = NULL;
+
+ if (!(feature = x86FeatureNew()))
+ goto error;
+@@ -692,6 +718,10 @@ x86FeatureLoad(xmlXPathContextPtr ctxt,
+ goto ignore;
+ }
+
++ str = virXPathString("string(@migratable)", ctxt);
++ if (STREQ_NULLABLE(str, "no"))
++ migratable = false;
++
+ n = virXPathNodeSet("./cpuid", ctxt, &nodes);
+ if (n < 0)
+ goto ignore;
+@@ -708,6 +738,14 @@ x86FeatureLoad(xmlXPathContextPtr ctxt,
+ goto error;
+ }
+
++ if (!migratable) {
++ if ((migrate_blocker = x86FeatureCopy(feature)) == NULL)
++ goto error;
++
++ migrate_blocker->next = map->migrate_blockers;
++ map->migrate_blockers = migrate_blocker;
++ }
++
+ if (map->features == NULL)
+ map->features = feature;
+ else {
+@@ -718,6 +756,7 @@ x86FeatureLoad(xmlXPathContextPtr ctxt,
+ out:
+ ctxt->node = ctxt_node;
+ VIR_FREE(nodes);
++ VIR_FREE(str);
+
+ return ret;
+
+@@ -726,6 +765,7 @@ error:
+
+ ignore:
+ x86FeatureFree(feature);
++ x86FeatureFree(migrate_blocker);
+ goto out;
+ }
+
+@@ -1061,6 +1101,12 @@ x86MapFree(struct x86_map *map)
+ x86VendorFree(vendor);
+ }
+
++ while (map->migrate_blockers != NULL) {
++ struct x86_feature *migrate_blocker = map->migrate_blockers;
++ map->migrate_blockers = migrate_blocker->next;
++ x86FeatureFree(migrate_blocker);
++ }
++
+ VIR_FREE(map);
+ }
+
+@@ -1941,16 +1987,15 @@ x86UpdateHostModel(virCPUDefPtr guest,
+ const virCPUDefPtr host)
+ {
+ virCPUDefPtr oldguest = NULL;
++ const struct x86_map *map;
++ const struct x86_feature *feat;
+ size_t i;
+ int ret = -1;
+
+ guest->match = VIR_CPU_MATCH_EXACT;
+
+- /* no updates are required */
+- if (guest->nfeatures == 0) {
+- virCPUDefFreeModel(guest);
+- return virCPUDefCopyModel(guest, host, true);
+- }
++ if (!(map = virCPUx86GetMap()))
++ goto cleanup;
+
+ /* update the host model according to the desired configuration */
+ if (!(oldguest = virCPUDefCopy(guest)))
+@@ -1960,6 +2005,16 @@ x86UpdateHostModel(virCPUDefPtr guest,
+ if (virCPUDefCopyModel(guest, host, true) < 0)
+ goto cleanup;
+
++ /* Remove non-migratable features by default
++ * Note: this only works as long as no CPU model contains non-migratable
++ * features directly */
++ for (i = 0; i < guest->nfeatures; i++) {
++ for (feat = map->migrate_blockers; feat; feat = feat->next) {
++ if (STREQ(feat->name, guest->features[i].name))
++ VIR_DELETE_ELEMENT_INPLACE(guest->features, i, guest->nfeatures);
++ }
++ }
++
+ for (i = 0; i < oldguest->nfeatures; i++) {
+ if (virCPUDefUpdateFeature(guest,
+ oldguest->features[i].name,
+diff --git a/tests/cputest.c b/tests/cputest.c
+index 6a1cfeb..153556a 100644
+--- a/tests/cputest.c
++++ b/tests/cputest.c
+@@ -591,6 +591,7 @@ mymain(void)
+ DO_TEST_UPDATE("x86", "host", "host-model", VIR_CPU_COMPARE_IDENTICAL);
+ DO_TEST_UPDATE("x86", "host", "host-model-nofallback", VIR_CPU_COMPARE_IDENTICAL);
+ DO_TEST_UPDATE("x86", "host", "host-passthrough", VIR_CPU_COMPARE_IDENTICAL);
++ DO_TEST_UPDATE("x86", "host-invtsc", "host-model", VIR_CPU_COMPARE_SUPERSET);
+
+ /* computing baseline CPUs */
+ DO_TEST_BASELINE("x86", "incompatible-vendors", -1);
+diff --git a/tests/cputestdata/x86-host-invtsc+host-model.xml b/tests/cputestdata/x86-host-invtsc+host-model.xml
+new file mode 100644
+index 0000000..ad1bbf8
+--- /dev/null
++++ b/tests/cputestdata/x86-host-invtsc+host-model.xml
+@@ -0,0 +1,22 @@
++<cpu mode='host-model' match='exact'>
++ <model fallback='allow'>SandyBridge</model>
++ <vendor>Intel</vendor>
++ <feature policy='require' name='osxsave'/>
++ <feature policy='require' name='pcid'/>
++ <feature policy='require' name='pdcm'/>
++ <feature policy='require' name='xtpr'/>
++ <feature policy='require' name='tm2'/>
++ <feature policy='require' name='est'/>
++ <feature policy='require' name='smx'/>
++ <feature policy='require' name='vmx'/>
++ <feature policy='require' name='ds_cpl'/>
++ <feature policy='require' name='monitor'/>
++ <feature policy='require' name='dtes64'/>
++ <feature policy='require' name='pbe'/>
++ <feature policy='require' name='tm'/>
++ <feature policy='require' name='ht'/>
++ <feature policy='require' name='ss'/>
++ <feature policy='require' name='acpi'/>
++ <feature policy='require' name='ds'/>
++ <feature policy='require' name='vme'/>
++</cpu>
+diff --git a/tests/cputestdata/x86-host-invtsc.xml b/tests/cputestdata/x86-host-invtsc.xml
+new file mode 100644
+index 0000000..f558399
+--- /dev/null
++++ b/tests/cputestdata/x86-host-invtsc.xml
+@@ -0,0 +1,27 @@
++<cpu>
++ <arch>x86_64</arch>
++ <model>SandyBridge</model>
++ <vendor>Intel</vendor>
++ <topology sockets='1' cores='2' threads='2'/>
++ <feature name='invtsc'/>
++ <feature name='osxsave'/>
++ <feature name='pcid'/>
++ <feature name='pdcm'/>
++ <feature name='xtpr'/>
++ <feature name='tm2'/>
++ <feature name='est'/>
++ <feature name='smx'/>
++ <feature name='vmx'/>
++ <feature name='ds_cpl'/>
++ <feature name='monitor'/>
++ <feature name='dtes64'/>
++ <feature name='pbe'/>
++ <feature name='tm'/>
++ <feature name='ht'/>
++ <feature name='ss'/>
++ <feature name='acpi'/>
++ <feature name='ds'/>
++ <feature name='vme'/>
++ <pages unit='KiB' size='4'/>
++ <pages unit='KiB' size='2048'/>
++</cpu>
+--
+2.2.2
+
--- /dev/null
+From 310634521378f3ae84f0f73293a591681f24648f Mon Sep 17 00:00:00 2001
+Message-Id: <310634521378f3ae84f0f73293a591681f24648f@dist-git>
+From: =?UTF-8?q?J=C3=A1n=20Tomko?= <jtomko@redhat.com>
+Date: Thu, 18 Sep 2014 11:55:52 +0200
+Subject: [PATCH] Fix leak in x86UpdateHostModel
+
+Commit de0aeaf introduced a memory leak.
+
+(cherry picked from commit 5b5631dedf59e540661bfeac774e543d8d38531b)
+https://bugzilla.redhat.com/show_bug.cgi?id=1185458
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/cpu/cpu_x86.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
+index 8ced69d..341a7f5 100644
+--- a/src/cpu/cpu_x86.c
++++ b/src/cpu/cpu_x86.c
+@@ -2010,8 +2010,10 @@ x86UpdateHostModel(virCPUDefPtr guest,
+ * features directly */
+ for (i = 0; i < guest->nfeatures; i++) {
+ for (feat = map->migrate_blockers; feat; feat = feat->next) {
+- if (STREQ(feat->name, guest->features[i].name))
++ if (STREQ(feat->name, guest->features[i].name)) {
++ VIR_FREE(guest->features[i].name);
+ VIR_DELETE_ELEMENT_INPLACE(guest->features, i, guest->nfeatures);
++ }
+ }
+ }
+
+--
+2.2.2
+
--- /dev/null
+From 04e1195be4e5e52da19050e2fadae95e9525ef3b Mon Sep 17 00:00:00 2001
+Message-Id: <04e1195be4e5e52da19050e2fadae95e9525ef3b@dist-git>
+From: Erik Skultety <eskultet@redhat.com>
+Date: Thu, 22 Jan 2015 16:25:16 +0100
+Subject: [PATCH] Fix libvirtd crash when removing metadata
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184929
+
+When trying to remove nonexistent metadata from XML, libvirt daemon
+crashes due to dereferencing NULL pointer.
+
+Resolves https://bugzilla.redhat.com/show_bug.cgi?id=1143955
+
+(cherry picked from commit 288c47406cffa7a6eb9e9c29764850b0cdeb5508)
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/util/virxml.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/util/virxml.c b/src/util/virxml.c
+index 88c1fcc..6cee8e1 100644
+--- a/src/util/virxml.c
++++ b/src/util/virxml.c
+@@ -979,6 +979,9 @@ virXMLFindChildNodeByNs(xmlNodePtr root,
+ {
+ xmlNodePtr next;
+
++ if (!root)
++ return NULL;
++
+ for (next = root->children; next; next = next->next) {
+ if (next->ns &&
+ STREQ_NULLABLE((const char *) next->ns->href, uri))
+--
+2.2.1
+
--- /dev/null
+From a26ded37a2e5d1deaa34fcc83d8cc6c4067ad040 Mon Sep 17 00:00:00 2001
+Message-Id: <a26ded37a2e5d1deaa34fcc83d8cc6c4067ad040@dist-git>
+From: Pavel Hrdina <phrdina@redhat.com>
+Date: Thu, 22 Jan 2015 15:53:56 +0100
+Subject: [PATCH] Fix possible memory leak in util/virxml.c
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184929
+
+A "xmlstr" string may not be assigned into a "doc" pointer and it
+could cause memory leak. To fix it if the "doc" pointer is NULL and
+the "xmlstr" string is not assigned we should free it.
+
+This has been found by coverity.
+
+Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
+(cherry picked from commit 67fbf129fc8727c98f7c4123c12a48938ccdf3fa)
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/util/virxml.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/src/util/virxml.c b/src/util/virxml.c
+index de1e1e0..88a1196 100644
+--- a/src/util/virxml.c
++++ b/src/util/virxml.c
+@@ -1047,6 +1047,8 @@ virXMLExtractNamespaceXML(xmlNodePtr root,
+ cleanup:
+ if (doc)
+ *doc = xmlstr;
++ else
++ VIR_FREE(xmlstr);
+ xmlFreeNode(nodeCopy);
+ return ret;
+ }
+--
+2.2.1
+
--- /dev/null
+From d0a2e30fb26302eaaa5efa0f2d1d1fbe7853934a Mon Sep 17 00:00:00 2001
+Message-Id: <d0a2e30fb26302eaaa5efa0f2d1d1fbe7853934a@dist-git>
+From: =?UTF-8?q?J=C3=A1n=20Tomko?= <jtomko@redhat.com>
+Date: Wed, 2 Jul 2014 10:35:31 +0200
+Subject: [PATCH] Fix segfault when starting a domain with no cpu definition
+
+My commit fba6bc4 iterated over the features in cpu definition
+without checking if there is one.
+
+(cherry picked from commit 1cd8f500ee133653ecb9d1b7f72b2b2e9870a1c3)
+https://bugzilla.redhat.com/show_bug.cgi?id=1185458
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/qemu/qemu_migration.c | 2 +-
+ src/qemu/qemu_process.c | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
+index d979d50..2e495a8 100644
+--- a/src/qemu/qemu_migration.c
++++ b/src/qemu/qemu_migration.c
+@@ -1506,7 +1506,7 @@ qemuMigrationIsAllowed(virQEMUDriverPtr driver, virDomainObjPtr vm,
+ return false;
+ }
+
+- for (i = 0; i < def->cpu->nfeatures; i++) {
++ for (i = 0; def->cpu && i < def->cpu->nfeatures; i++) {
+ virCPUFeatureDefPtr feature = &def->cpu->features[i];
+
+ if (feature->policy != VIR_CPU_FEATURE_REQUIRE)
+diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
+index 8c07397..11d5af5 100644
+--- a/src/qemu/qemu_process.c
++++ b/src/qemu/qemu_process.c
+@@ -3540,7 +3540,7 @@ qemuProcessVerifyGuestCPU(virQEMUDriverPtr driver, virDomainObjPtr vm)
+ }
+ }
+
+- for (i = 0; i < def->cpu->nfeatures; i++) {
++ for (i = 0; def->cpu && i < def->cpu->nfeatures; i++) {
+ virCPUFeatureDefPtr feature = &def->cpu->features[i];
+
+ if (feature->policy != VIR_CPU_FEATURE_REQUIRE)
+--
+2.2.2
+
--- /dev/null
+From 25d339a412b1a3d3436d3ff3c9ed63139c8f2428 Mon Sep 17 00:00:00 2001
+Message-Id: <25d339a412b1a3d3436d3ff3c9ed63139c8f2428@dist-git>
+From: Peter Krempa <pkrempa@redhat.com>
+Date: Thu, 22 Jan 2015 15:53:45 +0100
+Subject: [PATCH] conf: Add support for requesting of XML metadata via the API
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184929
+
+The virDomainGetMetadata function was designed to support also retrieval
+of app specific metadata from the <metadata> element. This functionality
+was never implemented originally.
+
+(cherry picked from commit ac38bff077642daa17f9a82480062ebef4c11a7b)
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/conf/domain_conf.c | 19 ++++----
+ src/libvirt_private.syms | 1 +
+ src/util/virxml.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++
+ src/util/virxml.h | 7 +++
+ 4 files changed, 140 insertions(+), 9 deletions(-)
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 6817e0e..c104218 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -18987,7 +18987,6 @@ virDomainObjGetMetadata(virDomainObjPtr vm,
+ unsigned int flags)
+ {
+ virDomainDefPtr def;
+- char *field = NULL;
+ char *ret = NULL;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+@@ -19002,17 +19001,21 @@ virDomainObjGetMetadata(virDomainObjPtr vm,
+
+ switch ((virDomainMetadataType) type) {
+ case VIR_DOMAIN_METADATA_DESCRIPTION:
+- field = def->description;
++ if (VIR_STRDUP(ret, def->description) < 0)
++ goto cleanup;
+ break;
+
+ case VIR_DOMAIN_METADATA_TITLE:
+- field = def->title;
++ if (VIR_STRDUP(ret, def->title) < 0)
++ goto cleanup;
+ break;
+
+ case VIR_DOMAIN_METADATA_ELEMENT:
+- virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+- _("<metadata> element is not yet supported"));
+- goto cleanup;
++ if (!def->metadata)
++ break;
++
++ if (virXMLExtractNamespaceXML(def->metadata, uri, &ret) < 0)
++ goto cleanup;
+ break;
+
+ default:
+@@ -19022,12 +19025,10 @@ virDomainObjGetMetadata(virDomainObjPtr vm,
+ break;
+ }
+
+- if (!field)
++ if (!ret)
+ virReportError(VIR_ERR_NO_DOMAIN_METADATA, "%s",
+ _("Requested metadata element is not present"));
+
+- ignore_value(VIR_STRDUP(ret, field));
+-
+ cleanup:
+ return ret;
+ }
+diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
+index 3df4379..1fbee18 100644
+--- a/src/libvirt_private.syms
++++ b/src/libvirt_private.syms
+@@ -2140,6 +2140,7 @@ virUUIDParse;
+
+ # util/virxml.h
+ virXMLChildElementCount;
++virXMLExtractNamespaceXML;
+ virXMLNodeToString;
+ virXMLParseHelper;
+ virXMLPickShellSafeComment;
+diff --git a/src/util/virxml.c b/src/util/virxml.c
+index 9bb8bf0..9048d78 100644
+--- a/src/util/virxml.c
++++ b/src/util/virxml.c
+@@ -928,3 +928,125 @@ cleanup:
+
+ return ret;
+ }
++
++typedef int (*virXMLForeachCallback)(xmlNodePtr node,
++ void *opaque);
++
++static int
++virXMLForeachNode(xmlNodePtr root,
++ virXMLForeachCallback cb,
++ void *opaque);
++
++static int
++virXMLForeachNode(xmlNodePtr root,
++ virXMLForeachCallback cb,
++ void *opaque)
++{
++ xmlNodePtr next;
++ int ret;
++
++ for (next = root; next; next = next->next) {
++ if ((ret = cb(next, opaque)) != 0)
++ return ret;
++
++ /* recurse into children */
++ if (next->children) {
++ if ((ret = virXMLForeachNode(next->children, cb, opaque)) != 0)
++ return ret;
++ }
++ }
++
++ return 0;
++}
++
++
++static int
++virXMLRemoveElementNamespace(xmlNodePtr node,
++ void *opaque)
++{
++ const char *uri = opaque;
++
++ if (node->ns &&
++ STREQ_NULLABLE((const char *)node->ns->href, uri))
++ xmlSetNs(node, NULL);
++ return 0;
++}
++
++
++xmlNodePtr
++virXMLFindChildNodeByNs(xmlNodePtr root,
++ const char *uri)
++{
++ xmlNodePtr next;
++
++ for (next = root->children; next; next = next->next) {
++ if (next->ns &&
++ STREQ_NULLABLE((const char *) next->ns->href, uri))
++ return next;
++ }
++
++ return NULL;
++}
++
++
++/**
++ * virXMLExtractNamespaceXML: extract a sub-namespace of XML as string
++ */
++int
++virXMLExtractNamespaceXML(xmlNodePtr root,
++ const char *uri,
++ char **doc)
++{
++ xmlNodePtr node;
++ xmlNodePtr nodeCopy = NULL;
++ xmlNsPtr actualNs;
++ xmlNsPtr prevNs = NULL;
++ char *xmlstr = NULL;
++ int ret = -1;
++
++ if (!(node = virXMLFindChildNodeByNs(root, uri))) {
++ /* node not found */
++ ret = 1;
++ goto cleanup;
++ }
++
++ /* copy the node so that we can modify the namespace */
++ if (!(nodeCopy = xmlCopyNode(node, 1))) {
++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
++ _("Failed to copy XML node"));
++ goto cleanup;
++ }
++
++ virXMLForeachNode(nodeCopy, virXMLRemoveElementNamespace,
++ (void *)uri);
++
++ /* remove the namespace declaration
++ * - it's only a single linked list ... doh */
++ for (actualNs = nodeCopy->nsDef; actualNs; actualNs = actualNs->next) {
++ if (STREQ_NULLABLE((const char *)actualNs->href, uri)) {
++
++ /* unlink */
++ if (prevNs)
++ prevNs->next = actualNs->next;
++ else
++ nodeCopy->nsDef = actualNs->next;
++
++ /* discard */
++ xmlFreeNs(actualNs);
++ break;
++ }
++
++ prevNs = actualNs;
++ }
++
++ if (!(xmlstr = virXMLNodeToString(nodeCopy->doc, nodeCopy)))
++ goto cleanup;
++
++ ret = 0;
++
++cleanup:
++ if (doc)
++ *doc = xmlstr;
++ xmlFreeNode(nodeCopy);
++ return ret;
++}
+diff --git a/src/util/virxml.h b/src/util/virxml.h
+index bb34069..7dc6c9d 100644
+--- a/src/util/virxml.h
++++ b/src/util/virxml.h
+@@ -165,4 +165,11 @@ int virXMLSaveFile(const char *path,
+
+ char *virXMLNodeToString(xmlDocPtr doc, xmlNodePtr node);
+
++xmlNodePtr virXMLFindChildNodeByNs(xmlNodePtr root,
++ const char *uri);
++
++int virXMLExtractNamespaceXML(xmlNodePtr root,
++ const char *uri,
++ char **doc);
++
+ #endif /* __VIR_XML_H__ */
+--
+2.2.1
+
--- /dev/null
+From bb5ed814786f3148d1e54e26e9be10ea332c3058 Mon Sep 17 00:00:00 2001
+Message-Id: <bb5ed814786f3148d1e54e26e9be10ea332c3058@dist-git>
+From: Peter Krempa <pkrempa@redhat.com>
+Date: Thu, 22 Jan 2015 15:53:52 +0100
+Subject: [PATCH] conf: Avoid false positive of uninitialized variable use
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184929
+
+GCC 4.8.0+ whines about variable "new" being uninitialized since
+commit 73bfac0e7182a3abd. This is a false positive as the
+xmlFreeNode(new) statement can be only reached if new was actually
+allocated successfully.
+
+ CC conf/libvirt_conf_la-domain_conf.lo
+ conf/domain_conf.c: In function 'virDomainDefSetMetadata':
+ conf/domain_conf.c:18650:24: error: 'new' may be used uninitialized in this function [-Werror=maybe-uninitialized]
+ xmlFreeNode(new);
+
+Reported independently by John Ferlan and Michal Privoznik.
+
+(cherry picked from commit 0d4f469c871fb5997bb24f192924163263445980)
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/conf/domain_conf.c | 9 +++------
+ 1 file changed, 3 insertions(+), 6 deletions(-)
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index c4829ff..a2c0d6c 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -19043,7 +19043,7 @@ virDomainDefSetMetadata(virDomainDefPtr def,
+ {
+ xmlDocPtr doc = NULL;
+ xmlNodePtr old;
+- xmlNodePtr new;
++ xmlNodePtr new = NULL;
+ char *tmp;
+ int ret = -1;
+
+@@ -19092,11 +19092,8 @@ virDomainDefSetMetadata(virDomainDefPtr def,
+ xmlFreeNode(old);
+ }
+
+- /* just delete the metadata */
+- if (!metadata)
+- break;
+-
+- if (!(xmlAddChild(def->metadata, new))) {
++ if (new &&
++ !(xmlAddChild(def->metadata, new))) {
+ xmlFreeNode(new);
+ virReportOOMError();
+ goto cleanup;
+--
+2.2.1
+
--- /dev/null
+From 550637214e4df0cd44d64e83a0e57fc37f470bdb Mon Sep 17 00:00:00 2001
+Message-Id: <550637214e4df0cd44d64e83a0e57fc37f470bdb@dist-git>
+From: Peter Krempa <pkrempa@redhat.com>
+Date: Thu, 22 Jan 2015 15:53:51 +0100
+Subject: [PATCH] conf: Don't corrupt metadata on OOM
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184929
+
+Eric Blake suggested that we could do a little better in case copying of
+the metadata to be set fails. With this patch, the old metadata is
+discarded after the new string is copied successfuly.
+
+(cherry picked from commit 7655ed0802eecc3d8486a0360d2326ecd052e477)
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/conf/domain_conf.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 4dbe3fc..c4829ff 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -19044,19 +19044,24 @@ virDomainDefSetMetadata(virDomainDefPtr def,
+ xmlDocPtr doc = NULL;
+ xmlNodePtr old;
+ xmlNodePtr new;
++ char *tmp;
+ int ret = -1;
+
+ switch ((virDomainMetadataType) type) {
+ case VIR_DOMAIN_METADATA_DESCRIPTION:
++ if (VIR_STRDUP(tmp, metadata) < 0)
++ goto cleanup;
++
+ VIR_FREE(def->description);
+- if (VIR_STRDUP(def->description, metadata) < 0)
+- goto cleanup;
++ def->description = tmp;
+ break;
+
+ case VIR_DOMAIN_METADATA_TITLE:
++ if (VIR_STRDUP(tmp, metadata) < 0)
++ goto cleanup;
++
+ VIR_FREE(def->title);
+- if (VIR_STRDUP(def->title, metadata) < 0)
+- goto cleanup;
++ def->title = tmp;
+ break;
+
+ case VIR_DOMAIN_METADATA_ELEMENT:
+--
+2.2.1
+
--- /dev/null
+From a1871d142620750d21fed3c06053fad60ca3f7c5 Mon Sep 17 00:00:00 2001
+Message-Id: <a1871d142620750d21fed3c06053fad60ca3f7c5@dist-git>
+From: Peter Krempa <pkrempa@redhat.com>
+Date: Thu, 22 Jan 2015 15:53:41 +0100
+Subject: [PATCH] conf: Factor out setting of metadata to simplify code
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184929
+
+The code to set the metadata in a domain definition is common to live
+and inactive domains. Factor it out into a common func.
+
+(cherry picked from commit e9cb66f14e19935db16938ebdf1e407103b4de1e)
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/conf/domain_conf.c | 115 +++++++++++++++++++++++--------------------------
+ 1 file changed, 54 insertions(+), 61 deletions(-)
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 7bfb602..6817e0e 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -19032,87 +19032,80 @@ cleanup:
+ return ret;
+ }
+
+-int
+-virDomainObjSetMetadata(virDomainObjPtr vm,
++
++static int
++virDomainDefSetMetadata(virDomainDefPtr def,
+ int type,
+ const char *metadata,
+ const char *key ATTRIBUTE_UNUSED,
+- const char *uri ATTRIBUTE_UNUSED,
++ const char *uri ATTRIBUTE_UNUSED)
++{
++ int ret = -1;
++
++ switch ((virDomainMetadataType) type) {
++ case VIR_DOMAIN_METADATA_DESCRIPTION:
++ VIR_FREE(def->description);
++ if (VIR_STRDUP(def->description, metadata) < 0)
++ goto cleanup;
++ break;
++
++ case VIR_DOMAIN_METADATA_TITLE:
++ VIR_FREE(def->title);
++ if (VIR_STRDUP(def->title, metadata) < 0)
++ goto cleanup;
++ break;
++
++ case VIR_DOMAIN_METADATA_ELEMENT:
++ virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
++ _("<metadata> element is not supported"));
++ goto cleanup;
++ break;
++
++ default:
++ virReportError(VIR_ERR_INVALID_ARG, "%s",
++ _("unknown metadata type"));
++ goto cleanup;
++ break;
++ }
++
++ ret = 0;
++
++cleanup:
++ return ret;
++}
++
++
++int
++virDomainObjSetMetadata(virDomainObjPtr vm,
++ int type,
++ const char *metadata,
++ const char *key,
++ const char *uri,
+ virCapsPtr caps,
+ virDomainXMLOptionPtr xmlopt,
+ const char *configDir,
+ unsigned int flags)
+ {
+ virDomainDefPtr persistentDef;
+- int ret = -1;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG, -1);
+
+ if (virDomainLiveConfigHelperMethod(caps, xmlopt, vm, &flags,
+ &persistentDef) < 0)
+- goto cleanup;
++ return -1;
+
+- if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+- switch ((virDomainMetadataType) type) {
+- case VIR_DOMAIN_METADATA_DESCRIPTION:
+- VIR_FREE(vm->def->description);
+- if (VIR_STRDUP(vm->def->description, metadata) < 0)
+- goto cleanup;
+- break;
+-
+- case VIR_DOMAIN_METADATA_TITLE:
+- VIR_FREE(vm->def->title);
+- if (VIR_STRDUP(vm->def->title, metadata) < 0)
+- goto cleanup;
+- break;
+-
+- case VIR_DOMAIN_METADATA_ELEMENT:
+- virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+- _("<metadata> element is not supported"));
+- goto cleanup;
+- break;
+-
+- default:
+- virReportError(VIR_ERR_INVALID_ARG, "%s",
+- _("unknown metadata type"));
+- goto cleanup;
+- break;
+- }
+- }
++ if (flags & VIR_DOMAIN_AFFECT_LIVE)
++ if (virDomainDefSetMetadata(vm->def, type, metadata, key, uri) < 0)
++ return -1;
+
+ if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+- switch ((virDomainMetadataType) type) {
+- case VIR_DOMAIN_METADATA_DESCRIPTION:
+- VIR_FREE(persistentDef->description);
+- if (VIR_STRDUP(persistentDef->description, metadata) < 0)
+- goto cleanup;
+- break;
+-
+- case VIR_DOMAIN_METADATA_TITLE:
+- VIR_FREE(persistentDef->title);
+- if (VIR_STRDUP(persistentDef->title, metadata) < 0)
+- goto cleanup;
+- break;
+-
+- case VIR_DOMAIN_METADATA_ELEMENT:
+- virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+- _("<metadata> element is not supported"));
+- goto cleanup;
+-
+- default:
+- virReportError(VIR_ERR_INVALID_ARG, "%s",
+- _("unknown metadata type"));
+- goto cleanup;
+- break;
+- }
++ if (virDomainDefSetMetadata(persistentDef, type, metadata, key, uri) < 0)
++ return -1;
+
+ if (virDomainSaveConfig(configDir, persistentDef) < 0)
+- goto cleanup;
++ return -1;
+ }
+
+- ret = 0;
+-
+-cleanup:
+- return ret;
++ return 0;
+ }
+--
+2.2.1
+
--- /dev/null
+From 4b31aeaaa431a2a0a85bedf205358c2499a8f35d Mon Sep 17 00:00:00 2001
+Message-Id: <4b31aeaaa431a2a0a85bedf205358c2499a8f35d@dist-git>
+From: Michal Privoznik <mprivozn@redhat.com>
+Date: Mon, 19 Jan 2015 12:43:42 +0100
+Subject: [PATCH] conf: Format interface's driver more frequently
+
+RHEL-7.0.z: https://bugzilla.redhat.com/show_bug.cgi?id=1183447
+RHEL-7.1: https://bugzilla.redhat.com/show_bug.cgi?id=1128751
+
+There's this <driver/> element under <interface/> which can have
+several attributes. However, the driver element is currently formated
+only if the driver's name or txmode has been specified. This makes
+only a little sense as we parse even partial <driver/>, for instance:
+
+ <interface type='user'>
+ <mac address='52:54:00:e5:48:58'/>
+ <model type='virtio'/>
+ <driver ioeventfd='on' event_idx='on' queues='5'/>
+ </interface>
+
+But such XML would never get formatted back.
+
+Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
+(cherry picked from commit 3085702b5461d3b0b057c37cf5fbff432244f529)
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/conf/domain_conf.c | 4 +-
+ .../qemuxml2argv-interface-driver.xml | 51 ++++++++++++++++++++++
+ tests/qemuxml2xmltest.c | 1 +
+ 3 files changed, 55 insertions(+), 1 deletion(-)
+ create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-interface-driver.xml
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index bb2e7ef..922c5e6 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -15387,7 +15387,9 @@ virDomainNetDefFormat(virBufferPtr buf,
+ virBufferEscapeString(buf, "<model type='%s'/>\n",
+ def->model);
+ if (STREQ(def->model, "virtio") &&
+- (def->driver.virtio.name || def->driver.virtio.txmode)) {
++ (def->driver.virtio.name || def->driver.virtio.txmode ||
++ def->driver.virtio.ioeventfd || def->driver.virtio.event_idx ||
++ def->driver.virtio.queues)) {
+ virBufferAddLit(buf, "<driver");
+ if (def->driver.virtio.name) {
+ virBufferAsprintf(buf, " name='%s'",
+diff --git a/tests/qemuxml2argvdata/qemuxml2argv-interface-driver.xml b/tests/qemuxml2argvdata/qemuxml2argv-interface-driver.xml
+new file mode 100644
+index 0000000..ec5ab61
+--- /dev/null
++++ b/tests/qemuxml2argvdata/qemuxml2argv-interface-driver.xml
+@@ -0,0 +1,51 @@
++<domain type='qemu'>
++ <name>test</name>
++ <uuid>15d091de-0181-456b-9554-e4382dc1f1ab</uuid>
++ <memory unit='KiB'>1048576</memory>
++ <currentMemory unit='KiB'>1048576</currentMemory>
++ <vcpu placement='static'>1</vcpu>
++ <os>
++ <type arch='x86_64' machine='pc-0.13'>hvm</type>
++ <boot dev='cdrom'/>
++ <boot dev='hd'/>
++ <bootmenu enable='yes'/>
++ </os>
++ <clock offset='utc'/>
++ <on_poweroff>destroy</on_poweroff>
++ <on_reboot>restart</on_reboot>
++ <on_crash>restart</on_crash>
++ <devices>
++ <emulator>/usr/bin/qemu</emulator>
++ <disk type='file' device='disk'>
++ <driver name='qemu' type='qcow2' event_idx='on'/>
++ <source file='/var/lib/libvirt/images/f14.img'/>
++ <target dev='vda' bus='virtio'/>
++ <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
++ </disk>
++ <disk type='file' device='cdrom'>
++ <driver name='qemu' type='raw'/>
++ <source file='/var/lib/libvirt/Fedora-14-x86_64-Live-KDE.iso'/>
++ <target dev='hdc' bus='ide'/>
++ <readonly/>
++ <address type='drive' controller='0' bus='1' target='0' unit='0'/>
++ </disk>
++ <controller type='usb' index='0'/>
++ <controller type='virtio-serial' index='0'>
++ <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
++ </controller>
++ <controller type='ide' index='0'/>
++ <controller type='pci' index='0' model='pci-root'/>
++ <interface type='user'>
++ <mac address='52:54:00:e5:48:58'/>
++ <model type='virtio'/>
++ <driver ioeventfd='on' event_idx='on' queues='5'/>
++ </interface>
++ <serial type='pty'>
++ <target port='0'/>
++ </serial>
++ <console type='pty'>
++ <target type='serial' port='0'/>
++ </console>
++ <memballoon model='virtio'/>
++ </devices>
++</domain>
+diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
+index d16fdc3..11ac108 100644
+--- a/tests/qemuxml2xmltest.c
++++ b/tests/qemuxml2xmltest.c
+@@ -255,6 +255,7 @@ mymain(void)
+ DO_TEST("lease");
+ DO_TEST("event_idx");
+ DO_TEST("vhost_queues");
++ DO_TEST("interface-driver");
+ DO_TEST("virtio-lun");
+
+ DO_TEST("usb-redir");
+--
+2.2.1
+
--- /dev/null
+From be61ac8742d24a170a83340b576dbb39635133f6 Mon Sep 17 00:00:00 2001
+Message-Id: <be61ac8742d24a170a83340b576dbb39635133f6@dist-git>
+From: Peter Krempa <pkrempa@redhat.com>
+Date: Thu, 22 Jan 2015 15:53:55 +0100
+Subject: [PATCH] conf: Improve metadata type verification
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184929
+
+Split out checking of invalid metadata type from the switch statement so
+that we can use the typecasted enum value to allow tracking addition of
+new items by the compliler.
+
+Also avoids two dead-code break statements.
+
+(cherry picked from commit 3738166603b2ab11ae30061381f378679b767758)
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/conf/domain_conf.c | 22 ++++++++++++++--------
+ 1 file changed, 14 insertions(+), 8 deletions(-)
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 36b9ba7..47942ff 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -18995,6 +18995,12 @@ virDomainObjGetMetadata(virDomainObjPtr vm,
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG, NULL);
+
++ if (type >= VIR_DOMAIN_METADATA_LAST) {
++ virReportError(VIR_ERR_INVALID_ARG,
++ _("unknown metadata type '%d'"), type);
++ goto cleanup;
++ }
++
+ if (virDomainLiveConfigHelperMethod(caps, xmlopt, vm, &flags, &def) < 0)
+ goto cleanup;
+
+@@ -19021,10 +19027,7 @@ virDomainObjGetMetadata(virDomainObjPtr vm,
+ goto cleanup;
+ break;
+
+- default:
+- virReportError(VIR_ERR_INVALID_ARG, "%s",
+- _("unknown metadata type"));
+- goto cleanup;
++ case VIR_DOMAIN_METADATA_LAST:
+ break;
+ }
+
+@@ -19050,6 +19053,12 @@ virDomainDefSetMetadata(virDomainDefPtr def,
+ char *tmp;
+ int ret = -1;
+
++ if (type >= VIR_DOMAIN_METADATA_LAST) {
++ virReportError(VIR_ERR_INVALID_ARG,
++ _("unknown metadata type '%d'"), type);
++ goto cleanup;
++ }
++
+ switch ((virDomainMetadataType) type) {
+ case VIR_DOMAIN_METADATA_DESCRIPTION:
+ if (VIR_STRDUP(tmp, metadata) < 0)
+@@ -19103,10 +19112,7 @@ virDomainDefSetMetadata(virDomainDefPtr def,
+ }
+ break;
+
+- default:
+- virReportError(VIR_ERR_INVALID_ARG, "%s",
+- _("unknown metadata type"));
+- goto cleanup;
++ case VIR_DOMAIN_METADATA_LAST:
+ break;
+ }
+
+--
+2.2.1
+
--- /dev/null
+From febb8d0b48c7a7bf7b587bc43d7e423318f49369 Mon Sep 17 00:00:00 2001
+Message-Id: <febb8d0b48c7a7bf7b587bc43d7e423318f49369@dist-git>
+From: Peter Krempa <pkrempa@redhat.com>
+Date: Thu, 22 Jan 2015 15:53:46 +0100
+Subject: [PATCH] conf: allow to add XML metadata using the
+ virDomainSetMetadata api
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184929
+
+The functionality wasn't originally implemented. This patch adds the
+ability to modify domain's XML metadata using the API.
+
+(cherry picked from commit 73bfac0e7182a3abde02304fd2f17845715a9a2e)
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/conf/domain_conf.c | 47 ++++++++++++++++++++++++++++++++++++++++++-----
+ src/util/virxml.c | 32 ++++++++++++++++++++++++++++++++
+ src/util/virxml.h | 4 ++++
+ 3 files changed, 78 insertions(+), 5 deletions(-)
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index c104218..4dbe3fc 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -19038,9 +19038,12 @@ static int
+ virDomainDefSetMetadata(virDomainDefPtr def,
+ int type,
+ const char *metadata,
+- const char *key ATTRIBUTE_UNUSED,
+- const char *uri ATTRIBUTE_UNUSED)
++ const char *key,
++ const char *uri)
+ {
++ xmlDocPtr doc = NULL;
++ xmlNodePtr old;
++ xmlNodePtr new;
+ int ret = -1;
+
+ switch ((virDomainMetadataType) type) {
+@@ -19057,9 +19060,42 @@ virDomainDefSetMetadata(virDomainDefPtr def,
+ break;
+
+ case VIR_DOMAIN_METADATA_ELEMENT:
+- virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+- _("<metadata> element is not supported"));
+- goto cleanup;
++ if (metadata) {
++ /* parse and modify the xml from the user */
++ if (!(doc = virXMLParseString(metadata, _("(metadata_xml)"))))
++ goto cleanup;
++
++ if (virXMLInjectNamespace(doc->children, uri, key) < 0)
++ goto cleanup;
++
++ /* create the root node if needed */
++ if (!def->metadata &&
++ !(def->metadata = xmlNewNode(NULL, (unsigned char *)"metadata"))) {
++ virReportOOMError();
++ goto cleanup;
++ }
++
++ if (!(new = xmlCopyNode(doc->children, 1))) {
++ virReportOOMError();
++ goto cleanup;
++ }
++ }
++
++ /* remove possible other nodes sharing the namespace */
++ while ((old = virXMLFindChildNodeByNs(def->metadata, uri))) {
++ xmlUnlinkNode(old);
++ xmlFreeNode(old);
++ }
++
++ /* just delete the metadata */
++ if (!metadata)
++ break;
++
++ if (!(xmlAddChild(def->metadata, new))) {
++ xmlFreeNode(new);
++ virReportOOMError();
++ goto cleanup;
++ }
+ break;
+
+ default:
+@@ -19072,6 +19108,7 @@ virDomainDefSetMetadata(virDomainDefPtr def,
+ ret = 0;
+
+ cleanup:
++ xmlFreeDoc(doc);
+ return ret;
+ }
+
+diff --git a/src/util/virxml.c b/src/util/virxml.c
+index 9048d78..de1e1e0 100644
+--- a/src/util/virxml.c
++++ b/src/util/virxml.c
+@@ -1050,3 +1050,35 @@ cleanup:
+ xmlFreeNode(nodeCopy);
+ return ret;
+ }
++
++
++static int
++virXMLAddElementNamespace(xmlNodePtr node,
++ void *opaque)
++{
++ xmlNsPtr ns = opaque;
++
++ if (!node->ns)
++ xmlSetNs(node, ns);
++
++ return 0;
++}
++
++
++int
++virXMLInjectNamespace(xmlNodePtr node,
++ const char *uri,
++ const char *key)
++{
++ xmlNsPtr ns;
++
++ if (!(ns = xmlNewNs(node, (const unsigned char *)uri, (const unsigned char *)key))) {
++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
++ _("failed to create a new XML namespace"));
++ return -1;
++ }
++
++ virXMLForeachNode(node, virXMLAddElementNamespace, ns);
++
++ return 0;
++}
+diff --git a/src/util/virxml.h b/src/util/virxml.h
+index 7dc6c9d..d967a2e 100644
+--- a/src/util/virxml.h
++++ b/src/util/virxml.h
+@@ -172,4 +172,8 @@ int virXMLExtractNamespaceXML(xmlNodePtr root,
+ const char *uri,
+ char **doc);
+
++int virXMLInjectNamespace(xmlNodePtr node,
++ const char *uri,
++ const char *key);
++
+ #endif /* __VIR_XML_H__ */
+--
+2.2.1
+
--- /dev/null
+From 495bf507eaf0eab638d3cf89a8854d23824b319e Mon Sep 17 00:00:00 2001
+Message-Id: <495bf507eaf0eab638d3cf89a8854d23824b319e@dist-git>
+From: John Ferlan <jferlan@redhat.com>
+Date: Wed, 27 Aug 2014 14:27:07 -0400
+Subject: [PATCH] cpu_x86: Resolve Coverity RESOURCE_LEAK
+
+Coverity determined that the copied 'oldguest' would be leaked for
+both error and success paths.
+
+(cherry picked from commit be7b82a283bc789da6cf9edc413ea399636b97b8)
+https://bugzilla.redhat.com/show_bug.cgi?id=1185458
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/cpu/cpu_x86.c | 15 ++++++++++-----
+ 1 file changed, 10 insertions(+), 5 deletions(-)
+
+diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
+index 7bd8acb..4e77550 100644
+--- a/src/cpu/cpu_x86.c
++++ b/src/cpu/cpu_x86.c
+@@ -1940,8 +1940,9 @@ static int
+ x86UpdateHostModel(virCPUDefPtr guest,
+ const virCPUDefPtr host)
+ {
+- virCPUDefPtr oldguest;
++ virCPUDefPtr oldguest = NULL;
+ size_t i;
++ int ret = -1;
+
+ guest->match = VIR_CPU_MATCH_EXACT;
+
+@@ -1953,20 +1954,24 @@ x86UpdateHostModel(virCPUDefPtr guest,
+
+ /* update the host model according to the desired configuration */
+ if (!(oldguest = virCPUDefCopy(guest)))
+- return -1;
++ goto cleanup;
+
+ virCPUDefFreeModel(guest);
+ if (virCPUDefCopyModel(guest, host, true) < 0)
+- return -1;
++ goto cleanup;
+
+ for (i = 0; i < oldguest->nfeatures; i++) {
+ if (virCPUDefUpdateFeature(guest,
+ oldguest->features[i].name,
+ oldguest->features[i].policy) < 0)
+- return -1;
++ goto cleanup;
+ }
+
+- return 0;
++ ret = 0;
++
++ cleanup:
++ virCPUDefFree(oldguest);
++ return ret;
+ }
+
+
+--
+2.2.2
+
--- /dev/null
+From b0a82f4abc9f4de3db965c84b926322846588278 Mon Sep 17 00:00:00 2001
+Message-Id: <b0a82f4abc9f4de3db965c84b926322846588278@dist-git>
+From: Peter Krempa <pkrempa@redhat.com>
+Date: Thu, 22 Jan 2015 15:53:47 +0100
+Subject: [PATCH] lib: Don't force the key argument when deleting metadata
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184929
+
+virDomainSetMetadata when operating on the metadata element was
+requesting the @key argument to be passed even if @metadata was NULL
+used to delete the corresponding metadata element. This is not needed as
+the key is only used when adding the element and matching is done via
+the XML namespace.
+
+(cherry picked from commit 3b6784d119074e3be8861cc4c30630f299bde121)
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/libvirt.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/src/libvirt.c b/src/libvirt.c
+index cbcc24b..874304f 100644
+--- a/src/libvirt.c
++++ b/src/libvirt.c
+@@ -10812,7 +10812,8 @@ virDomainSetMetadata(virDomainPtr domain,
+ break;
+ case VIR_DOMAIN_METADATA_ELEMENT:
+ virCheckNonNullArgGoto(uri, error);
+- virCheckNonNullArgGoto(key, error);
++ if (metadata)
++ virCheckNonNullArgGoto(key, error);
+ break;
+ default:
+ /* For future expansion */
+--
+2.2.1
+
--- /dev/null
+From 9c171ebceeed9cf28f0e86e0de604805e3669bdf Mon Sep 17 00:00:00 2001
+Message-Id: <9c171ebceeed9cf28f0e86e0de604805e3669bdf@dist-git>
+From: Peter Krempa <pkrempa@redhat.com>
+Date: Thu, 22 Jan 2015 15:53:48 +0100
+Subject: [PATCH] lxc: Add metadata modification APIs
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184929
+
+(cherry picked from commit f9c7b32e5de3fb0ccf2e0858716886bdb35a9913)
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/lxc/lxc_driver.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 70 insertions(+)
+
+diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
+index 1aaa6e7..e9f2f51 100644
+--- a/src/lxc/lxc_driver.c
++++ b/src/lxc/lxc_driver.c
+@@ -4702,6 +4702,74 @@ lxcNodeSuspendForDuration(virConnectPtr conn,
+ }
+
+
++static int
++lxcDomainSetMetadata(virDomainPtr dom,
++ int type,
++ const char *metadata,
++ const char *key,
++ const char *uri,
++ unsigned int flags)
++{
++ virLXCDriverPtr driver = dom->conn->privateData;
++ virDomainObjPtr vm;
++ virLXCDriverConfigPtr cfg = NULL;
++ virCapsPtr caps = NULL;
++ int ret = -1;
++
++ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
++ VIR_DOMAIN_AFFECT_CONFIG, -1);
++
++ if (!(vm = lxcDomObjFromDomain(dom)))
++ return -1;
++
++ cfg = virLXCDriverGetConfig(driver);
++
++ if (virDomainSetMetadataEnsureACL(dom->conn, vm->def, flags) < 0)
++ goto cleanup;
++
++ if (!(caps = virLXCDriverGetCapabilities(driver, false)))
++ goto cleanup;
++
++ ret = virDomainObjSetMetadata(vm, type, metadata, key, uri, caps,
++ driver->xmlopt, cfg->configDir, flags);
++
++cleanup:
++ virObjectUnlock(vm);
++ virObjectUnref(caps);
++ virObjectUnref(cfg);
++ return ret;
++}
++
++
++static char *
++lxcDomainGetMetadata(virDomainPtr dom,
++ int type,
++ const char *uri,
++ unsigned int flags)
++{
++ virLXCDriverPtr driver = dom->conn->privateData;
++ virCapsPtr caps = NULL;
++ virDomainObjPtr vm;
++ char *ret = NULL;
++
++ if (!(vm = lxcDomObjFromDomain(dom)))
++ return NULL;
++
++ if (virDomainGetMetadataEnsureACL(dom->conn, vm->def) < 0)
++ goto cleanup;
++
++ if (!(caps = virLXCDriverGetCapabilities(driver, false)))
++ goto cleanup;
++
++ ret = virDomainObjGetMetadata(vm, type, uri, caps, driver->xmlopt, flags);
++
++cleanup:
++ virObjectUnlock(vm);
++ virObjectUnref(caps);
++ return ret;
++}
++
++
+ /* Function Tables */
+ static virDriver lxcDriver = {
+ .no = VIR_DRV_LXC,
+@@ -4776,6 +4844,8 @@ static virDriver lxcDriver = {
+ .domainOpenConsole = lxcDomainOpenConsole, /* 0.8.6 */
+ .connectIsAlive = lxcConnectIsAlive, /* 0.9.8 */
+ .nodeSuspendForDuration = lxcNodeSuspendForDuration, /* 0.9.8 */
++ .domainSetMetadata = lxcDomainSetMetadata, /* 1.1.3 */
++ .domainGetMetadata = lxcDomainGetMetadata, /* 1.1.3 */
+ .nodeGetMemoryParameters = lxcNodeGetMemoryParameters, /* 0.10.2 */
+ .nodeSetMemoryParameters = lxcNodeSetMemoryParameters, /* 0.10.2 */
+ .domainSendProcessSignal = lxcDomainSendProcessSignal, /* 1.0.1 */
+--
+2.2.1
+
--- /dev/null
+From 715a29642aaedc6b19b451677cb02658d5924b7f Mon Sep 17 00:00:00 2001
+Message-Id: <715a29642aaedc6b19b451677cb02658d5924b7f@dist-git>
+From: Peter Krempa <pkrempa@redhat.com>
+Date: Wed, 28 Jan 2015 10:33:39 +0100
+Subject: [PATCH] man: virsh: Add man page for "virsh metadata"
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184929
+
+Patch adding the command forgot to add the man page entry.
+
+Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1130379
+(cherry picked from commit 992318cbee83dc381c44acfdfdecfb2607279e25)
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ tools/virsh.pod | 30 ++++++++++++++++++++++++++++++
+ 1 file changed, 30 insertions(+)
+
+diff --git a/tools/virsh.pod b/tools/virsh.pod
+index f1b09d9..c3ae204 100644
+--- a/tools/virsh.pod
++++ b/tools/virsh.pod
+@@ -1073,6 +1073,36 @@ I<--total> for only the total stats, I<start> for only the per-cpu
+ stats of the CPUs from I<start>, I<count> for only I<count> CPUs'
+ stats.
+
++=item B<metadata> I<domain> [[I<--live>] [I<--config>] | [I<--current>]]
++[I<--edit>] [I<uri>] [I<key>] [I<set>] [I<--remove>]
++
++Show or modify custom XML metadata of a domain. The metadata is a user
++defined XML that allows to store arbitrary XML data in the domain definition.
++Multiple separate custom metadata pieces can be stored in the domain XML.
++The pieces are identified by a private XML namespace provided via the
++I<uri> argument.
++
++Flags I<--live> or I<--config> select whether this command works on live
++or persistent definitions of the domain. If both I<--live> and I<--config>
++are specified, the I<--config> option takes precedence on getting the current
++description and both live configuration and config are updated while setting
++the description. I<--current> is exclusive and implied if none of these was
++specified.
++
++Flag I<--remove> specifies that the metadata element specified by the I<uri>
++argument should be removed rather than updated.
++
++Flag I<--edit> specifies that an editor with the metadata identified by the
++I<uri> argument should be opened and the contents saved back afterwards.
++Otherwise the new contents can be provided via the I<set> argument.
++
++When setting metadata via I<--edit> or I<set> the I<key> argument must be
++specified and is used to prefix the custom elements to bind them
++to the private namespace.
++
++If neither of I<--edit> and I<set> are specified the XML metadata corresponding
++to the I<uri> namespace is displayed instead of being modified.
++
+ =item B<migrate> [I<--live>] [I<--offline>] [I<--direct>] [I<--p2p> [I<--tunnelled>]]
+ [I<--persistent>] [I<--undefinesource>] [I<--suspend>] [I<--copy-storage-all>]
+ [I<--copy-storage-inc>] [I<--change-protection>] [I<--unsafe>] [I<--verbose>]
+--
+2.2.2
+
--- /dev/null
+From d60a5ab6fd5ba1ef21687eb995c7c2c2ffbd892c Mon Sep 17 00:00:00 2001
+Message-Id: <d60a5ab6fd5ba1ef21687eb995c7c2c2ffbd892c@dist-git>
+From: Eric Blake <eblake@redhat.com>
+Date: Thu, 22 Jan 2015 15:53:54 +0100
+Subject: [PATCH] metadata: track title edits across libvirtd restart
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184929
+https://bugzilla.redhat.com/show_bug.cgi?id=1122205
+
+Although the edits were changing in-memory XML, it was not flushed
+to disk; so unless some other action changes XML, a libvirtd restart
+would lose the changed information.
+
+* src/conf/domain_conf.c (virDomainObjSetMetadata): Add parameter,
+to save live status across restarts.
+(virDomainSaveXML): Allow for test driver.
+* src/conf/domain_conf.h (virDomainObjSetMetadata): Adjust
+signature.
+* src/bhyve/bhyve_driver.c (bhyveDomainSetMetadata): Adjust caller.
+* src/lxc/lxc_driver.c (lxcDomainSetMetadata): Likewise.
+* src/qemu/qemu_driver.c (qemuDomainSetMetadata): Likewise.
+* src/test/test_driver.c (testDomainSetMetadata): Likewise.
+
+Signed-off-by: Eric Blake <eblake@redhat.com>
+(cherry picked from commit 60e49440598b4aeb4a32bf23bfa5ed85672cbd6a)
+
+Conflicts:
+ src/bhyve/bhyve_driver.c - bhyve driver is missing
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/conf/domain_conf.c | 13 +++++++++++--
+ src/conf/domain_conf.h | 1 +
+ src/lxc/lxc_driver.c | 3 ++-
+ src/qemu/qemu_driver.c | 3 ++-
+ src/test/test_driver.c | 2 +-
+ 5 files changed, 17 insertions(+), 5 deletions(-)
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index a2c0d6c..36b9ba7 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -17491,6 +17491,9 @@ virDomainSaveXML(const char *configDir,
+ char *configFile = NULL;
+ int ret = -1;
+
++ if (!configDir)
++ return 0;
++
+ if ((configFile = virDomainConfigFile(configDir, def->name)) == NULL)
+ goto cleanup;
+
+@@ -19123,6 +19126,7 @@ virDomainObjSetMetadata(virDomainObjPtr vm,
+ const char *uri,
+ virCapsPtr caps,
+ virDomainXMLOptionPtr xmlopt,
++ const char *stateDir,
+ const char *configDir,
+ unsigned int flags)
+ {
+@@ -19135,12 +19139,17 @@ virDomainObjSetMetadata(virDomainObjPtr vm,
+ &persistentDef) < 0)
+ return -1;
+
+- if (flags & VIR_DOMAIN_AFFECT_LIVE)
++ if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+ if (virDomainDefSetMetadata(vm->def, type, metadata, key, uri) < 0)
+ return -1;
+
++ if (virDomainSaveStatus(xmlopt, stateDir, vm) < 0)
++ return -1;
++ }
++
+ if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+- if (virDomainDefSetMetadata(persistentDef, type, metadata, key, uri) < 0)
++ if (virDomainDefSetMetadata(persistentDef, type, metadata, key,
++ uri) < 0)
+ return -1;
+
+ if (virDomainSaveConfig(configDir, persistentDef) < 0)
+diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
+index eaeea03..ef64d88 100644
+--- a/src/conf/domain_conf.h
++++ b/src/conf/domain_conf.h
+@@ -2785,6 +2785,7 @@ int virDomainObjSetMetadata(virDomainObjPtr vm,
+ const char *uri,
+ virCapsPtr caps,
+ virDomainXMLOptionPtr xmlopt,
++ const char *stateDir,
+ const char *configDir,
+ unsigned int flags);
+
+diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
+index e9f2f51..c47a206 100644
+--- a/src/lxc/lxc_driver.c
++++ b/src/lxc/lxc_driver.c
+@@ -4731,7 +4731,8 @@ lxcDomainSetMetadata(virDomainPtr dom,
+ goto cleanup;
+
+ ret = virDomainObjSetMetadata(vm, type, metadata, key, uri, caps,
+- driver->xmlopt, cfg->configDir, flags);
++ driver->xmlopt, cfg->stateDir,
++ cfg->configDir, flags);
+
+ cleanup:
+ virObjectUnlock(vm);
+diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
+index 57583e8..2ee3582 100644
+--- a/src/qemu/qemu_driver.c
++++ b/src/qemu/qemu_driver.c
+@@ -15887,7 +15887,8 @@ qemuDomainSetMetadata(virDomainPtr dom,
+ goto cleanup;
+
+ ret = virDomainObjSetMetadata(vm, type, metadata, key, uri, caps,
+- driver->xmlopt, cfg->configDir, flags);
++ driver->xmlopt, cfg->stateDir,
++ cfg->configDir, flags);
+
+ cleanup:
+ virObjectUnlock(vm);
+diff --git a/src/test/test_driver.c b/src/test/test_driver.c
+index 4d23738..e398130 100644
+--- a/src/test/test_driver.c
++++ b/src/test/test_driver.c
+@@ -2585,7 +2585,7 @@ static int testDomainSetMetadata(virDomainPtr dom,
+
+ ret = virDomainObjSetMetadata(privdom, type, metadata, key, uri,
+ privconn->caps, privconn->xmlopt,
+- NULL, flags);
++ NULL, NULL, flags);
+
+ cleanup:
+ if (privdom)
+--
+2.2.1
+
--- /dev/null
+From 135eeb60e3d7b1cda9f48bdd38542bb3c06e2638 Mon Sep 17 00:00:00 2001
+Message-Id: <135eeb60e3d7b1cda9f48bdd38542bb3c06e2638@dist-git>
+From: Peter Krempa <pkrempa@redhat.com>
+Date: Thu, 22 Jan 2015 15:53:39 +0100
+Subject: [PATCH] qemu: Factor out body of qemuDomainGetMetadata for universal
+ use
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184929
+
+The function implemented common behavior that can be reused for other
+hypervisor drivers that use the virDomainObj data structures. Factor out
+the core into a separate helper func.
+
+(cherry picked from commit 99c51af2ee42de980c258ecb52cf20f96c69ff83)
+
+Conflicts:
+ src/conf/domain_conf.h - context
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/conf/domain_conf.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++
+ src/conf/domain_conf.h | 7 ++++++
+ src/libvirt_private.syms | 1 +
+ src/qemu/qemu_driver.c | 49 +++++-------------------------------------
+ 4 files changed, 68 insertions(+), 44 deletions(-)
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 922c5e6..b052924 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -18976,3 +18976,58 @@ virDomainDiskSourceIsBlockType(virDomainDiskDefPtr def)
+ }
+ return false;
+ }
++
++
++char *
++virDomainObjGetMetadata(virDomainObjPtr vm,
++ int type,
++ const char *uri ATTRIBUTE_UNUSED,
++ virCapsPtr caps,
++ virDomainXMLOptionPtr xmlopt,
++ unsigned int flags)
++{
++ virDomainDefPtr def;
++ char *field = NULL;
++ char *ret = NULL;
++
++ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
++ VIR_DOMAIN_AFFECT_CONFIG, NULL);
++
++ if (virDomainLiveConfigHelperMethod(caps, xmlopt, vm, &flags, &def) < 0)
++ goto cleanup;
++
++ /* use correct domain definition according to flags */
++ if (flags & VIR_DOMAIN_AFFECT_LIVE)
++ def = vm->def;
++
++ switch ((virDomainMetadataType) type) {
++ case VIR_DOMAIN_METADATA_DESCRIPTION:
++ field = def->description;
++ break;
++
++ case VIR_DOMAIN_METADATA_TITLE:
++ field = def->title;
++ break;
++
++ case VIR_DOMAIN_METADATA_ELEMENT:
++ virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
++ _("<metadata> element is not yet supported"));
++ goto cleanup;
++ break;
++
++ default:
++ virReportError(VIR_ERR_INVALID_ARG, "%s",
++ _("unknown metadata type"));
++ goto cleanup;
++ break;
++ }
++
++ if (!field)
++ virReportError(VIR_ERR_NO_DOMAIN_METADATA, "%s",
++ _("Requested metadata element is not present"));
++
++ ignore_value(VIR_STRDUP(ret, field));
++
++cleanup:
++ return ret;
++}
+diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
+index 00e66ae..08c677f 100644
+--- a/src/conf/domain_conf.h
++++ b/src/conf/domain_conf.h
+@@ -2771,4 +2771,11 @@ int virDomainDefFindDevice(virDomainDefPtr def,
+ bool virDomainDiskSourceIsBlockType(virDomainDiskDefPtr def)
+ ATTRIBUTE_NONNULL(1);
+
++char *virDomainObjGetMetadata(virDomainObjPtr vm,
++ int type,
++ const char *uri,
++ virCapsPtr caps,
++ virDomainXMLOptionPtr xmlopt,
++ unsigned int flags);
++
+ #endif /* __DOMAIN_CONF_H */
+diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
+index 5cf7039..40007e1 100644
+--- a/src/libvirt_private.syms
++++ b/src/libvirt_private.syms
+@@ -313,6 +313,7 @@ virDomainNostateReasonTypeFromString;
+ virDomainNostateReasonTypeToString;
+ virDomainObjAssignDef;
+ virDomainObjCopyPersistentDef;
++virDomainObjGetMetadata;
+ virDomainObjGetPersistentDef;
+ virDomainObjGetState;
+ virDomainObjListAdd;
+diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
+index b0d4f33..3beed9a 100644
+--- a/src/qemu/qemu_driver.c
++++ b/src/qemu/qemu_driver.c
+@@ -15958,21 +15958,16 @@ cleanup:
+ static char *
+ qemuDomainGetMetadata(virDomainPtr dom,
+ int type,
+- const char *uri ATTRIBUTE_UNUSED,
++ const char *uri,
+ unsigned int flags)
+ {
+ virQEMUDriverPtr driver = dom->conn->privateData;
++ virCapsPtr caps = NULL;
+ virDomainObjPtr vm;
+- virDomainDefPtr def;
+ char *ret = NULL;
+- char *field = NULL;
+- virCapsPtr caps = NULL;
+-
+- virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+- VIR_DOMAIN_AFFECT_CONFIG, NULL);
+
+ if (!(vm = qemuDomObjFromDomain(dom)))
+- goto cleanup;
++ return NULL;
+
+ if (virDomainGetMetadataEnsureACL(dom->conn, vm->def) < 0)
+ goto cleanup;
+@@ -15980,44 +15975,10 @@ qemuDomainGetMetadata(virDomainPtr dom,
+ if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
+ goto cleanup;
+
+- if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags, &def) < 0)
+- goto cleanup;
+-
+- /* use correct domain definition according to flags */
+- if (flags & VIR_DOMAIN_AFFECT_LIVE)
+- def = vm->def;
+-
+- switch ((virDomainMetadataType) type) {
+- case VIR_DOMAIN_METADATA_DESCRIPTION:
+- field = def->description;
+- break;
+- case VIR_DOMAIN_METADATA_TITLE:
+- field = def->title;
+- break;
+- case VIR_DOMAIN_METADATA_ELEMENT:
+- virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+- _("QEMU driver does not support "
+- "<metadata> element"));
+- goto cleanup;
+- break;
+- default:
+- virReportError(VIR_ERR_INVALID_ARG, "%s",
+- _("unknown metadata type"));
+- goto cleanup;
+- break;
+- }
+-
+- if (!field) {
+- virReportError(VIR_ERR_NO_DOMAIN_METADATA, "%s",
+- _("Requested metadata element is not present"));
+- goto cleanup;
+- }
+-
+- ignore_value(VIR_STRDUP(ret, field));
++ ret = virDomainObjGetMetadata(vm, type, uri, caps, driver->xmlopt, flags);
+
+ cleanup:
+- if (vm)
+- virObjectUnlock(vm);
++ virObjectUnlock(vm);
+ virObjectUnref(caps);
+ return ret;
+ }
+--
+2.2.1
+
--- /dev/null
+From eff5466a6e7ca4c5b324e091c2be00e8fa71a338 Mon Sep 17 00:00:00 2001
+Message-Id: <eff5466a6e7ca4c5b324e091c2be00e8fa71a338@dist-git>
+From: Peter Krempa <pkrempa@redhat.com>
+Date: Thu, 22 Jan 2015 15:53:40 +0100
+Subject: [PATCH] qemu: Factor out body of qemuDomainSetMetadata for universal
+ use
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184929
+
+The function implemented common behavior that can be reused for other
+hypervisor drivers that use the virDomainObj data structures. Factor out
+the core into a separate helper func.
+
+(cherry picked from commit f87a7c67de946f941fddde44d5959baaac6c7de4)
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/conf/domain_conf.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++
+ src/conf/domain_conf.h | 10 ++++++
+ src/libvirt_private.syms | 1 +
+ src/qemu/qemu_driver.c | 73 ++++-------------------------------------
+ 4 files changed, 103 insertions(+), 66 deletions(-)
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index b052924..7bfb602 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -19031,3 +19031,88 @@ virDomainObjGetMetadata(virDomainObjPtr vm,
+ cleanup:
+ return ret;
+ }
++
++int
++virDomainObjSetMetadata(virDomainObjPtr vm,
++ int type,
++ const char *metadata,
++ const char *key ATTRIBUTE_UNUSED,
++ const char *uri ATTRIBUTE_UNUSED,
++ virCapsPtr caps,
++ virDomainXMLOptionPtr xmlopt,
++ const char *configDir,
++ unsigned int flags)
++{
++ virDomainDefPtr persistentDef;
++ int ret = -1;
++
++ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
++ VIR_DOMAIN_AFFECT_CONFIG, -1);
++
++ if (virDomainLiveConfigHelperMethod(caps, xmlopt, vm, &flags,
++ &persistentDef) < 0)
++ goto cleanup;
++
++ if (flags & VIR_DOMAIN_AFFECT_LIVE) {
++ switch ((virDomainMetadataType) type) {
++ case VIR_DOMAIN_METADATA_DESCRIPTION:
++ VIR_FREE(vm->def->description);
++ if (VIR_STRDUP(vm->def->description, metadata) < 0)
++ goto cleanup;
++ break;
++
++ case VIR_DOMAIN_METADATA_TITLE:
++ VIR_FREE(vm->def->title);
++ if (VIR_STRDUP(vm->def->title, metadata) < 0)
++ goto cleanup;
++ break;
++
++ case VIR_DOMAIN_METADATA_ELEMENT:
++ virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
++ _("<metadata> element is not supported"));
++ goto cleanup;
++ break;
++
++ default:
++ virReportError(VIR_ERR_INVALID_ARG, "%s",
++ _("unknown metadata type"));
++ goto cleanup;
++ break;
++ }
++ }
++
++ if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
++ switch ((virDomainMetadataType) type) {
++ case VIR_DOMAIN_METADATA_DESCRIPTION:
++ VIR_FREE(persistentDef->description);
++ if (VIR_STRDUP(persistentDef->description, metadata) < 0)
++ goto cleanup;
++ break;
++
++ case VIR_DOMAIN_METADATA_TITLE:
++ VIR_FREE(persistentDef->title);
++ if (VIR_STRDUP(persistentDef->title, metadata) < 0)
++ goto cleanup;
++ break;
++
++ case VIR_DOMAIN_METADATA_ELEMENT:
++ virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
++ _("<metadata> element is not supported"));
++ goto cleanup;
++
++ default:
++ virReportError(VIR_ERR_INVALID_ARG, "%s",
++ _("unknown metadata type"));
++ goto cleanup;
++ break;
++ }
++
++ if (virDomainSaveConfig(configDir, persistentDef) < 0)
++ goto cleanup;
++ }
++
++ ret = 0;
++
++cleanup:
++ return ret;
++}
+diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
+index 08c677f..eaeea03 100644
+--- a/src/conf/domain_conf.h
++++ b/src/conf/domain_conf.h
+@@ -2778,4 +2778,14 @@ char *virDomainObjGetMetadata(virDomainObjPtr vm,
+ virDomainXMLOptionPtr xmlopt,
+ unsigned int flags);
+
++int virDomainObjSetMetadata(virDomainObjPtr vm,
++ int type,
++ const char *metadata,
++ const char *key,
++ const char *uri,
++ virCapsPtr caps,
++ virDomainXMLOptionPtr xmlopt,
++ const char *configDir,
++ unsigned int flags);
++
+ #endif /* __DOMAIN_CONF_H */
+diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
+index 40007e1..61d8d26 100644
+--- a/src/libvirt_private.syms
++++ b/src/libvirt_private.syms
+@@ -331,6 +331,7 @@ virDomainObjListRemove;
+ virDomainObjListRemoveLocked;
+ virDomainObjNew;
+ virDomainObjSetDefTransient;
++virDomainObjSetMetadata;
+ virDomainObjSetState;
+ virDomainObjTaint;
+ virDomainPausedReasonTypeFromString;
+diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
+index 3beed9a..57583e8 100644
+--- a/src/qemu/qemu_driver.c
++++ b/src/qemu/qemu_driver.c
+@@ -15862,22 +15862,21 @@ static int
+ qemuDomainSetMetadata(virDomainPtr dom,
+ int type,
+ const char *metadata,
+- const char *key ATTRIBUTE_UNUSED,
+- const char *uri ATTRIBUTE_UNUSED,
++ const char *key,
++ const char *uri,
+ unsigned int flags)
+ {
+ virQEMUDriverPtr driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+- virDomainDefPtr persistentDef;
+- int ret = -1;
+ virQEMUDriverConfigPtr cfg = NULL;
+ virCapsPtr caps = NULL;
++ int ret = -1;
+
+ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
+ VIR_DOMAIN_AFFECT_CONFIG, -1);
+
+ if (!(vm = qemuDomObjFromDomain(dom)))
+- goto cleanup;
++ return -1;
+
+ cfg = virQEMUDriverGetConfig(driver);
+
+@@ -15887,69 +15886,11 @@ qemuDomainSetMetadata(virDomainPtr dom,
+ if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
+ goto cleanup;
+
+- if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
+- &persistentDef) < 0)
+- goto cleanup;
+-
+- if (flags & VIR_DOMAIN_AFFECT_LIVE) {
+- switch ((virDomainMetadataType) type) {
+- case VIR_DOMAIN_METADATA_DESCRIPTION:
+- VIR_FREE(vm->def->description);
+- if (VIR_STRDUP(vm->def->description, metadata) < 0)
+- goto cleanup;
+- break;
+- case VIR_DOMAIN_METADATA_TITLE:
+- VIR_FREE(vm->def->title);
+- if (VIR_STRDUP(vm->def->title, metadata) < 0)
+- goto cleanup;
+- break;
+- case VIR_DOMAIN_METADATA_ELEMENT:
+- virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+- _("QEmu driver does not support modifying "
+- "<metadata> element"));
+- goto cleanup;
+- break;
+- default:
+- virReportError(VIR_ERR_INVALID_ARG, "%s",
+- _("unknown metadata type"));
+- goto cleanup;
+- break;
+- }
+- }
+-
+- if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
+- switch ((virDomainMetadataType) type) {
+- case VIR_DOMAIN_METADATA_DESCRIPTION:
+- VIR_FREE(persistentDef->description);
+- if (VIR_STRDUP(persistentDef->description, metadata) < 0)
+- goto cleanup;
+- break;
+- case VIR_DOMAIN_METADATA_TITLE:
+- VIR_FREE(persistentDef->title);
+- if (VIR_STRDUP(persistentDef->title, metadata) < 0)
+- goto cleanup;
+- break;
+- case VIR_DOMAIN_METADATA_ELEMENT:
+- virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+- _("QEMU driver does not support "
+- "<metadata> element"));
+- goto cleanup;
+- default:
+- virReportError(VIR_ERR_INVALID_ARG, "%s",
+- _("unknown metadata type"));
+- goto cleanup;
+- break;
+- }
+-
+- if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
+- goto cleanup;
+- }
+-
+- ret = 0;
++ ret = virDomainObjSetMetadata(vm, type, metadata, key, uri, caps,
++ driver->xmlopt, cfg->configDir, flags);
+
+ cleanup:
+- if (vm)
+- virObjectUnlock(vm);
++ virObjectUnlock(vm);
+ virObjectUnref(caps);
+ virObjectUnref(cfg);
+ return ret;
+--
+2.2.1
+
--- /dev/null
+From 5b8a0bcaacd16703b069ba1cf70e8259534eaf69 Mon Sep 17 00:00:00 2001
+Message-Id: <5b8a0bcaacd16703b069ba1cf70e8259534eaf69@dist-git>
+From: Peter Krempa <pkrempa@redhat.com>
+Date: Thu, 22 Jan 2015 15:53:49 +0100
+Subject: [PATCH] test: Add <metadata> support into the test driver
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184929
+
+(cherry picked from commit f616fbf2a4a31a2f944aae0b75d6e2ab3bef3573)
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/test/test_driver.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 68 insertions(+)
+
+diff --git a/src/test/test_driver.c b/src/test/test_driver.c
+index f7eaf06..4d23738 100644
+--- a/src/test/test_driver.c
++++ b/src/test/test_driver.c
+@@ -2528,6 +2528,72 @@ cleanup:
+ return ret;
+ }
+
++static char *testDomainGetMetadata(virDomainPtr dom,
++ int type,
++ const char *uri,
++ unsigned int flags)
++{
++ testConnPtr privconn = dom->conn->privateData;
++ virDomainObjPtr privdom;
++ char *ret = NULL;
++
++ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
++ VIR_DOMAIN_AFFECT_CONFIG, NULL);
++
++ testDriverLock(privconn);
++ privdom = virDomainObjListFindByName(privconn->domains,
++ dom->name);
++ testDriverUnlock(privconn);
++
++ if (privdom == NULL) {
++ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
++ goto cleanup;
++ }
++
++ ret = virDomainObjGetMetadata(privdom, type, uri, privconn->caps,
++ privconn->xmlopt, flags);
++
++cleanup:
++ if (privdom)
++ virObjectUnlock(privdom);
++ return ret;
++}
++
++static int testDomainSetMetadata(virDomainPtr dom,
++ int type,
++ const char *metadata,
++ const char *key,
++ const char *uri,
++ unsigned int flags)
++{
++ testConnPtr privconn = dom->conn->privateData;
++ virDomainObjPtr privdom;
++ int ret = -1;
++
++ virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
++ VIR_DOMAIN_AFFECT_CONFIG, -1);
++
++ testDriverLock(privconn);
++ privdom = virDomainObjListFindByName(privconn->domains,
++ dom->name);
++ testDriverUnlock(privconn);
++
++ if (privdom == NULL) {
++ virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
++ goto cleanup;
++ }
++
++ ret = virDomainObjSetMetadata(privdom, type, metadata, key, uri,
++ privconn->caps, privconn->xmlopt,
++ NULL, flags);
++
++cleanup:
++ if (privdom)
++ virObjectUnlock(privdom);
++ return ret;
++}
++
++
+ static int testNodeGetCellsFreeMemory(virConnectPtr conn,
+ unsigned long long *freemems,
+ int startCell, int maxCells) {
+@@ -5815,6 +5881,8 @@ static virDriver testDriver = {
+ .connectIsAlive = testConnectIsAlive, /* 0.9.8 */
+ .nodeGetCPUMap = testNodeGetCPUMap, /* 1.0.0 */
+ .domainScreenshot = testDomainScreenshot, /* 1.0.5 */
++ .domainGetMetadata = testDomainGetMetadata, /* 1.1.3 */
++ .domainSetMetadata = testDomainSetMetadata, /* 1.1.3 */
+ };
+
+ static virNetworkDriver testNetworkDriver = {
+--
+2.2.1
+
--- /dev/null
+From 7cef1905e04cef0996df582bf196902a410b4308 Mon Sep 17 00:00:00 2001
+Message-Id: <7cef1905e04cef0996df582bf196902a410b4308@dist-git>
+From: Peter Krempa <pkrempa@redhat.com>
+Date: Thu, 22 Jan 2015 15:53:50 +0100
+Subject: [PATCH] tests: Add metadata tests
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184929
+
+This test exercises the virDomain[Get|Set]Metadata API and tests it for
+regressions
+
+(cherry picked from commit 2e23c77b0061c5f1b2fd5eeca79e3d6e963e7a2f)
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ tests/Makefile.am | 7 ++
+ tests/metadatatest.c | 245 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 252 insertions(+)
+ create mode 100644 tests/metadatatest.c
+
+diff --git a/tests/Makefile.am b/tests/Makefile.am
+index e49eadc..ac816fe 100644
+--- a/tests/Makefile.am
++++ b/tests/Makefile.am
+@@ -225,6 +225,8 @@ test_programs += interfacexml2xmltest
+
+ test_programs += cputest
+
++test_programs += metadatatest
++
+ test_scripts = \
+ capabilityschematest \
+ interfaceschematest \
+@@ -567,6 +569,11 @@ cputest_SOURCES = \
+ testutils.c testutils.h
+ cputest_LDADD = $(LDADDS)
+
++metadatatest_SOURCES = \
++ metadatatest.c \
++ testutils.c testutils.h
++metadatatest_LDADD = $(LDADDS) $(LIBXML_LIBS)
++
+ virshtest_SOURCES = \
+ virshtest.c \
+ testutils.c testutils.h
+diff --git a/tests/metadatatest.c b/tests/metadatatest.c
+new file mode 100644
+index 0000000..6bcf335
+--- /dev/null
++++ b/tests/metadatatest.c
+@@ -0,0 +1,245 @@
++/*
++ * Copyright (C) 2013 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
++ * <http://www.gnu.org/licenses/>.
++ *
++ * Author: Peter Krempa <pkrempa@redhat.com>
++ */
++
++#include <config.h>
++
++#include "testutils.h"
++
++#include "virerror.h"
++#include "virxml.h"
++
++#define VIR_FROM_THIS VIR_FROM_NONE
++
++static const char metadata1[] =
++"<derp xmlns:foobar='http://foo.bar/'>\n"
++" <bar>foobar</bar>\n"
++" <foo fooish='blurb'>foofoo</foo>\n"
++" <foobar:baz>zomg</foobar:baz>\n"
++"</derp>";
++
++
++static const char metadata1_ns[] =
++"<herp:derp xmlns:foobar='http://foo.bar/' xmlns:herp='http://herp.derp/'>\n"
++" <herp:bar>foobar</herp:bar>\n"
++" <herp:foo fooish='blurb'>foofoo</herp:foo>\n"
++" <foobar:baz>zomg</foobar:baz>\n"
++"</herp:derp>";
++
++
++static const char metadata2[] =
++"<foo>\n"
++" <bar>baz</bar>\n"
++"</foo>";
++
++
++static const char metadata2_ns[] =
++"<blurb:foo xmlns:blurb='http://herp.derp/'>\n"
++" <blurb:bar>baz</blurb:bar>\n"
++"</blurb:foo>";
++
++
++static char *
++getMetadataFromXML(virDomainPtr dom)
++{
++ xmlDocPtr doc = NULL;
++ xmlXPathContextPtr ctxt = NULL;
++ xmlNodePtr node;
++
++ char *xml = NULL;
++ char *ret = NULL;
++
++ if (!(xml = virDomainGetXMLDesc(dom, 0)))
++ goto cleanup;
++
++ if (!(doc = virXMLParseStringCtxt(xml, "(domain_definition)", &ctxt)))
++ goto cleanup;
++
++ if (!(node = virXPathNode("//metadata/*", ctxt)))
++ goto cleanup;
++
++ ret = virXMLNodeToString(node->doc, node);
++
++cleanup:
++ VIR_FREE(xml);
++ xmlFreeDoc(doc);
++ xmlXPathFreeContext(ctxt);
++
++ return ret;
++}
++
++
++static void
++metadataXMLConvertApostrophe(char *str)
++{
++ do {
++ if (*str == '\"')
++ *str = '\'';
++ } while ((*++str) != '\0');
++}
++
++
++static bool
++verifyMetadata(virDomainPtr dom,
++ const char *expectXML,
++ const char *expectAPI,
++ const char *uri)
++{
++ bool ret = false;
++ char *metadataXML = NULL;
++ char *metadataAPI = NULL;
++
++ if (!expectAPI) {
++ if ((metadataAPI = virDomainGetMetadata(dom,
++ VIR_DOMAIN_METADATA_ELEMENT,
++ uri, 0))) {
++ virReportError(VIR_ERR_INTERNAL_ERROR,
++ "expected no metadata in API, but got:\n[%s]",
++ metadataAPI);
++ goto cleanup;
++ }
++ } else {
++ if (!(metadataAPI = virDomainGetMetadata(dom,
++ VIR_DOMAIN_METADATA_ELEMENT,
++ uri, 0)))
++ goto cleanup;
++
++ metadataXMLConvertApostrophe(metadataAPI);
++
++ if (STRNEQ(metadataAPI, expectAPI)) {
++ virReportError(VIR_ERR_INTERNAL_ERROR,
++ "XML metadata in API doesn't match expected metadata: "
++ "expected:\n[%s]\ngot:\n[%s]",
++ expectAPI, metadataAPI);
++ goto cleanup;
++ }
++
++ }
++
++ if (!expectXML) {
++ if ((metadataXML = getMetadataFromXML(dom))) {
++ virReportError(VIR_ERR_INTERNAL_ERROR,
++ "expected no metadata in XML, but got:\n[%s]",
++ metadataXML);
++ goto cleanup;
++ }
++ } else {
++ if (!(metadataXML = getMetadataFromXML(dom)))
++ goto cleanup;
++
++ metadataXMLConvertApostrophe(metadataXML);
++
++ if (STRNEQ(metadataXML, expectXML)) {
++ virReportError(VIR_ERR_INTERNAL_ERROR,
++ "XML in dump doesn't match expected metadata: "
++ "expected:\n[%s]\ngot:\n[%s]",
++ expectXML, metadataXML);
++ goto cleanup;
++ }
++ }
++
++ ret = true;
++
++cleanup:
++ VIR_FREE(metadataXML);
++ VIR_FREE(metadataAPI);
++
++ return ret;
++}
++
++
++struct metadataTest {
++ virConnectPtr conn;
++ virDomainPtr dom;
++};
++
++
++static int
++testAssignMetadata(const void *data)
++{
++ const struct metadataTest *test = data;
++
++ if (virDomainSetMetadata(test->dom, VIR_DOMAIN_METADATA_ELEMENT,
++ metadata1, "herp", "http://herp.derp/", 0) < 0)
++ return -1;
++
++ if (!verifyMetadata(test->dom, metadata1_ns, metadata1, "http://herp.derp/"))
++ return -1;
++
++ return 0;
++}
++
++static int
++testRewriteMetadata(const void *data)
++{
++ const struct metadataTest *test = data;
++
++ if (virDomainSetMetadata(test->dom, VIR_DOMAIN_METADATA_ELEMENT,
++ metadata2, "blurb", "http://herp.derp/", 0) < 0)
++ return -1;
++
++ if (!verifyMetadata(test->dom, metadata2_ns, metadata2, "http://herp.derp/"))
++ return -1;
++
++ return 0;
++}
++
++static int
++testEraseMetadata(const void *data)
++{
++ const struct metadataTest *test = data;
++
++ if (virDomainSetMetadata(test->dom, VIR_DOMAIN_METADATA_ELEMENT,
++ NULL, NULL, "http://herp.derp/", 0) < 0)
++ return -1;
++
++ if (!verifyMetadata(test->dom, NULL, NULL, "http://herp.derp/"))
++ return -1;
++
++ return 0;
++}
++
++static int
++mymain(void)
++{
++ struct metadataTest test;
++ int ret = EXIT_SUCCESS;
++
++ if (!(test.conn = virConnectOpen("test:///default")))
++ return EXIT_FAILURE;
++
++ if (!(test.dom = virDomainLookupByName(test.conn, "test"))) {
++ virConnectClose(test.conn);
++ return EXIT_FAILURE;
++ }
++
++ if (virtTestRun("Assign metadata ", 1, testAssignMetadata, &test) < 0)
++ ret = EXIT_FAILURE;
++ if (virtTestRun("Rewrite Metadata ", 1, testRewriteMetadata, &test) < 0)
++ ret = EXIT_FAILURE;
++ if (virtTestRun("Erase metadata ", 1, testEraseMetadata, &test) < 0)
++ ret = EXIT_FAILURE;
++
++ virDomainFree(test.dom);
++ virConnectClose(test.conn);
++
++ return ret;
++}
++
++VIRT_TEST_MAIN(mymain)
+--
+2.2.1
+
--- /dev/null
+From 2e65f52bf904f8ff5587dc42b7c37d94f9dab451 Mon Sep 17 00:00:00 2001
+Message-Id: <2e65f52bf904f8ff5587dc42b7c37d94f9dab451@dist-git>
+From: Peter Krempa <pkrempa@redhat.com>
+Date: Thu, 22 Jan 2015 15:53:42 +0100
+Subject: [PATCH] util: Add helper to convert libxml2 nodes to a string
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184929
+
+(cherry picked from commit be0f0c2292e3f171a031086f4d0a39b205c756a3)
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/libvirt_private.syms | 1 +
+ src/util/virxml.c | 33 +++++++++++++++++++++++++++++++++
+ src/util/virxml.h | 2 ++
+ 3 files changed, 36 insertions(+)
+
+diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
+index 61d8d26..3df4379 100644
+--- a/src/libvirt_private.syms
++++ b/src/libvirt_private.syms
+@@ -2140,6 +2140,7 @@ virUUIDParse;
+
+ # util/virxml.h
+ virXMLChildElementCount;
++virXMLNodeToString;
+ virXMLParseHelper;
+ virXMLPickShellSafeComment;
+ virXMLPropString;
+diff --git a/src/util/virxml.c b/src/util/virxml.c
+index 4769569..9bb8bf0 100644
+--- a/src/util/virxml.c
++++ b/src/util/virxml.c
+@@ -895,3 +895,36 @@ virXMLChildElementCount(xmlNodePtr node)
+ }
+ return ret;
+ }
++
++
++/**
++ * virXMLNodeToString: convert an XML node ptr to an XML string
++ *
++ * Returns the XML string of the document or NULL on error.
++ * The caller has to free the string.
++ */
++char *
++virXMLNodeToString(xmlDocPtr doc,
++ xmlNodePtr node)
++{
++ xmlBufferPtr xmlbuf = NULL;
++ char *ret = NULL;
++
++ if (!(xmlbuf = xmlBufferCreate())) {
++ virReportOOMError();
++ return NULL;
++ }
++
++ if (xmlNodeDump(xmlbuf, doc, node, 0, 1) == 0) {
++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
++ _("failed to convert the XML node tree"));
++ goto cleanup;
++ }
++
++ ignore_value(VIR_STRDUP(ret, (const char *)xmlBufferContent(xmlbuf)));
++
++cleanup:
++ xmlBufferFree(xmlbuf);
++
++ return ret;
++}
+diff --git a/src/util/virxml.h b/src/util/virxml.h
+index 364288d..bb34069 100644
+--- a/src/util/virxml.h
++++ b/src/util/virxml.h
+@@ -163,4 +163,6 @@ int virXMLSaveFile(const char *path,
+ const char *warnCommand,
+ const char *xml);
+
++char *virXMLNodeToString(xmlDocPtr doc, xmlNodePtr node);
++
+ #endif /* __VIR_XML_H__ */
+--
+2.2.1
+
--- /dev/null
+From 28894754f079527609645607bb44fb268259bf2c Mon Sep 17 00:00:00 2001
+Message-Id: <28894754f079527609645607bb44fb268259bf2c@dist-git>
+From: Erik Skultety <eskultet@redhat.com>
+Date: Thu, 22 Jan 2015 15:53:57 +0100
+Subject: [PATCH] util: check for an illegal character in a XML namespace
+ prefix
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184929
+
+When user tries to insert element metadata providing a namespace
+declaration as well, currently we insert the element without any validation
+check for XML prefix (if provided). The next VM start would then
+fail with parse error. This patch fixes this issue by adding a call to
+xmlValidateNCName function to check for illegal characters in the
+prefix.
+Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1143921
+
+(cherry picked from commit 2c22954f99a70ed654e4116a18f433afa24d41c5)
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/util/virxml.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/src/util/virxml.c b/src/util/virxml.c
+index 88a1196..88c1fcc 100644
+--- a/src/util/virxml.c
++++ b/src/util/virxml.c
+@@ -1074,6 +1074,12 @@ virXMLInjectNamespace(xmlNodePtr node,
+ {
+ xmlNsPtr ns;
+
++ if (xmlValidateNCName((const unsigned char *)key, 1) != 0) {
++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
++ _("failed to validate prefix for a new XML namespace"));
++ return -1;
++ }
++
+ if (!(ns = xmlNewNs(node, (const unsigned char *)uri, (const unsigned char *)key))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("failed to create a new XML namespace"));
+--
+2.2.1
+
--- /dev/null
+From 63f44f163b462a7dffefa927df771fcc88ab603f Mon Sep 17 00:00:00 2001
+Message-Id: <63f44f163b462a7dffefa927df771fcc88ab603f@dist-git>
+From: Peter Krempa <pkrempa@redhat.com>
+Date: Thu, 22 Jan 2015 15:53:53 +0100
+Subject: [PATCH] virsh: Don't shadow global variable "remove" in cmdMetadata
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184929
+
+Some systems apparently have a global variable/function called remove
+and thus break compilation of virsh-domain.c. Rename the variable to
+avoid this.
+
+Reported by GuanQiang.
+
+(cherry picked from commit 6bf4c779841f858872003ffe6a97df395b2940e6)
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ tools/virsh-domain.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
+index a2796e5..dd697f9 100644
+--- a/tools/virsh-domain.c
++++ b/tools/virsh-domain.c
+@@ -6894,7 +6894,7 @@ cmdMetadata(vshControl *ctl, const vshCmd *cmd)
+ bool live = vshCommandOptBool(cmd, "live");
+ bool current = vshCommandOptBool(cmd, "current");
+ bool edit = vshCommandOptBool(cmd, "edit");
+- bool remove = vshCommandOptBool(cmd, "remove");
++ bool rem = vshCommandOptBool(cmd, "remove");
+ const char *set = NULL;
+ const char *uri = NULL;
+ const char *key = NULL;
+@@ -6926,12 +6926,12 @@ cmdMetadata(vshControl *ctl, const vshCmd *cmd)
+ goto cleanup;
+ }
+
+- if (set || remove) {
++ if (set || rem) {
+ if (virDomainSetMetadata(dom, VIR_DOMAIN_METADATA_ELEMENT,
+ set, key, uri, flags))
+ goto cleanup;
+
+- if (remove)
++ if (rem)
+ vshPrint("%s\n", _("Metadata removed"));
+ else
+ vshPrint("%s\n", _("Metadata modified"));
+--
+2.2.1
+
--- /dev/null
+From 7aa95972f21eb0b39c06909360bcf8b51171b263 Mon Sep 17 00:00:00 2001
+Message-Id: <7aa95972f21eb0b39c06909360bcf8b51171b263@dist-git>
+From: Peter Krempa <pkrempa@redhat.com>
+Date: Thu, 22 Jan 2015 15:53:44 +0100
+Subject: [PATCH] virsh-domain: Add command to allow modifications of XML
+ metadata
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184929
+
+The metadata modification functions will support modification of the XML
+metadata. Add a virsh command to allow using this approach.
+
+(cherry picked from commit 01b03f59e76865feed3097cbe6dc0a809caccc14)
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ tools/virsh-domain.c | 161 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 161 insertions(+)
+
+diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
+index 6076e8d..a2796e5 100644
+--- a/tools/virsh-domain.c
++++ b/tools/virsh-domain.c
+@@ -6813,6 +6813,161 @@ cleanup:
+ return ret;
+ }
+
++
++static const vshCmdInfo info_metadata[] = {
++ {.name = "help",
++ .data = N_("show or set domain's custom XML metadata")
++ },
++ {.name = "desc",
++ .data = N_("Shows or modifies the XML metadata of a domain.")
++ },
++ {.name = NULL}
++};
++
++static const vshCmdOptDef opts_metadata[] = {
++ {.name = "domain",
++ .type = VSH_OT_DATA,
++ .flags = VSH_OFLAG_REQ,
++ .help = N_("domain name, id or uuid")
++ },
++ {.name = "live",
++ .type = VSH_OT_BOOL,
++ .help = N_("modify/get running state")
++ },
++ {.name = "config",
++ .type = VSH_OT_BOOL,
++ .help = N_("modify/get persistent configuration")
++ },
++ {.name = "current",
++ .type = VSH_OT_BOOL,
++ .help = N_("modify/get current state configuration")
++ },
++ {.name = "edit",
++ .type = VSH_OT_BOOL,
++ .help = N_("use an editor to change the metadata")
++ },
++ {.name = "uri",
++ .type = VSH_OT_DATA,
++ .flags = VSH_OFLAG_REQ,
++ .help = N_("URI of the namespace")
++ },
++ {.name = "key",
++ .type = VSH_OT_DATA,
++ .help = N_("key to be used as a namespace identifier"),
++ },
++ {.name = "set",
++ .type = VSH_OT_DATA,
++ .help = N_("new metadata to set"),
++ },
++ {.name = "remove",
++ .type = VSH_OT_BOOL,
++ .help = N_("remove the metadata corresponding to an uri")
++ },
++ {.name = NULL}
++};
++
++
++/* helper to add new metadata using the --edit option */
++static char *
++vshDomainGetEditMetadata(vshControl *ctl,
++ virDomainPtr dom,
++ const char *uri,
++ unsigned int flags)
++{
++ char *ret;
++
++ if (!(ret = virDomainGetMetadata(dom, VIR_DOMAIN_METADATA_ELEMENT,
++ uri, flags))) {
++ vshResetLibvirtError();
++ ret = vshStrdup(ctl, "\n");
++ }
++
++ return ret;
++}
++
++
++static bool
++cmdMetadata(vshControl *ctl, const vshCmd *cmd)
++{
++ virDomainPtr dom;
++ bool config = vshCommandOptBool(cmd, "config");
++ bool live = vshCommandOptBool(cmd, "live");
++ bool current = vshCommandOptBool(cmd, "current");
++ bool edit = vshCommandOptBool(cmd, "edit");
++ bool remove = vshCommandOptBool(cmd, "remove");
++ const char *set = NULL;
++ const char *uri = NULL;
++ const char *key = NULL;
++ unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
++ bool ret = false;
++
++ VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
++ VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
++ VSH_EXCLUSIVE_OPTIONS("edit", "set");
++ VSH_EXCLUSIVE_OPTIONS("remove", "set");
++ VSH_EXCLUSIVE_OPTIONS("remove", "edit");
++
++ if (config)
++ flags |= VIR_DOMAIN_AFFECT_CONFIG;
++ if (live)
++ flags |= VIR_DOMAIN_AFFECT_LIVE;
++
++ if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
++ return false;
++
++ if (vshCommandOptStringReq(ctl, cmd, "uri", &uri) < 0 ||
++ vshCommandOptStringReq(ctl, cmd, "key", &key) < 0 ||
++ vshCommandOptStringReq(ctl, cmd, "set", &set) < 0)
++ goto cleanup;
++
++ if ((set || edit) && !key) {
++ vshError(ctl, "%s",
++ _("namespace key is required when modifying metadata"));
++ goto cleanup;
++ }
++
++ if (set || remove) {
++ if (virDomainSetMetadata(dom, VIR_DOMAIN_METADATA_ELEMENT,
++ set, key, uri, flags))
++ goto cleanup;
++
++ if (remove)
++ vshPrint("%s\n", _("Metadata removed"));
++ else
++ vshPrint("%s\n", _("Metadata modified"));
++ } else if (edit) {
++#define EDIT_GET_XML \
++ vshDomainGetEditMetadata(ctl, dom, uri, flags)
++#define EDIT_NOT_CHANGED \
++ vshPrint(ctl, "%s", _("Metadata not changed")); \
++ ret = true; \
++ goto edit_cleanup;
++#define EDIT_DEFINE \
++ (virDomainSetMetadata(dom, VIR_DOMAIN_METADATA_ELEMENT, doc_edited, \
++ key, uri, flags) == 0)
++#define EDIT_FREE /* nothing */
++#include "virsh-edit.c"
++
++ vshPrint("%s\n", _("Metadata modified"));
++ } else {
++ char *data;
++ /* get */
++ if (!(data = virDomainGetMetadata(dom, VIR_DOMAIN_METADATA_ELEMENT,
++ uri, flags)))
++ goto cleanup;
++
++ vshPrint(ctl, "%s\n", data);
++ VIR_FREE(data);
++ }
++
++ ret = true;
++
++cleanup:
++ virDomainFree(dom);
++ return ret;
++}
++
++
+ /*
+ * "inject-nmi" command
+ */
+@@ -10603,6 +10758,12 @@ const vshCmdDef domManagementCmds[] = {
+ .info = info_memtune,
+ .flags = 0
+ },
++ {.name = "metadata",
++ .handler = cmdMetadata,
++ .opts = opts_metadata,
++ .info = info_metadata,
++ .flags = 0
++ },
+ {.name = "migrate",
+ .handler = cmdMigrate,
+ .opts = opts_migrate,
+--
+2.2.1
+
--- /dev/null
+From 502cf493c7832a3ea5a4cd20dea289d291c7c56b Mon Sep 17 00:00:00 2001
+Message-Id: <502cf493c7832a3ea5a4cd20dea289d291c7c56b@dist-git>
+From: Peter Krempa <pkrempa@redhat.com>
+Date: Thu, 22 Jan 2015 15:53:43 +0100
+Subject: [PATCH] virsh-domain: use virXMLNodeToString instead of xmlNodeDump
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184929
+
+(cherry picked from commit 3df33d7ad52d27bf9a41ab07e2c0ab631364ae04)
+
+Conflicts:
+ tools/virsh-domain.c - context
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ tools/virsh-domain.c | 113 +++++++++++++--------------------------------------
+ 1 file changed, 29 insertions(+), 84 deletions(-)
+
+diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
+index 03f96fb..6076e8d 100644
+--- a/tools/virsh-domain.c
++++ b/tools/virsh-domain.c
+@@ -2356,7 +2356,7 @@ cmdDomIfSetLink(vshControl *ctl, const vshCmd *cmd)
+ xmlXPathContextPtr ctxt = NULL;
+ xmlXPathObjectPtr obj = NULL;
+ xmlNodePtr cur = NULL;
+- xmlBufferPtr xml_buf = NULL;
++ char *xml_buf = NULL;
+
+ if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
+ return false;
+@@ -2461,18 +2461,13 @@ hit:
+ goto cleanup;
+ }
+
+- xml_buf = xmlBufferCreate();
+- if (!xml_buf) {
+- vshError(ctl, _("Failed to allocate memory"));
+- goto cleanup;
+- }
+-
+- if (xmlNodeDump(xml_buf, xml, obj->nodesetval->nodeTab[i], 0, 0) < 0) {
++ if (!(xml_buf = virXMLNodeToString(xml, obj->nodesetval->nodeTab[i]))) {
++ vshSaveLibvirtError();
+ vshError(ctl, _("Failed to create XML"));
+ goto cleanup;
+ }
+
+- if (virDomainUpdateDeviceFlags(dom, (char *)xmlBufferContent(xml_buf), flags) < 0) {
++ if (virDomainUpdateDeviceFlags(dom, xml_buf, flags) < 0) {
+ vshError(ctl, _("Failed to update interface link state"));
+ goto cleanup;
+ } else {
+@@ -2484,10 +2479,8 @@ cleanup:
+ xmlXPathFreeObject(obj);
+ xmlXPathFreeContext(ctxt);
+ xmlFreeDoc(xml);
+- xmlBufferFree(xml_buf);
+-
+- if (dom)
+- virDomainFree(dom);
++ VIR_FREE(xml_buf);
++ virDomainFree(dom);
+
+ return ret;
+ }
+@@ -6092,11 +6085,10 @@ cmdCPUCompare(vshControl *ctl, const vshCmd *cmd)
+ bool ret = false;
+ char *buffer;
+ int result;
+- const char *snippet;
++ char *snippet = NULL;
+
+ xmlDocPtr xml = NULL;
+ xmlXPathContextPtr ctxt = NULL;
+- xmlBufferPtr xml_buf = NULL;
+ xmlNodePtr node;
+
+ if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
+@@ -6112,17 +6104,10 @@ cmdCPUCompare(vshControl *ctl, const vshCmd *cmd)
+ if ((node = virXPathNode("/cpu|"
+ "/domain/cpu|"
+ "/capabilities/host/cpu", ctxt))) {
+- if (!(xml_buf = xmlBufferCreate())) {
+- vshError(ctl, _("Can't create XML buffer to extract CPU element."));
++ if (!(snippet = virXMLNodeToString(xml, node))) {
++ vshSaveLibvirtError();
+ goto cleanup;
+ }
+-
+- if (xmlNodeDump(xml_buf, xml, node, 0, 0) < 0) {
+- vshError(ctl, _("Failed to extract CPU element snippet from domain XML."));
+- goto cleanup;
+- }
+-
+- snippet = (const char *) xmlBufferContent(xml_buf);
+ } else {
+ vshError(ctl, _("File '%s' does not contain a <cpu> element or is not "
+ "a valid domain or capabilities XML"), from);
+@@ -6158,7 +6143,7 @@ cmdCPUCompare(vshControl *ctl, const vshCmd *cmd)
+
+ cleanup:
+ VIR_FREE(buffer);
+- xmlBufferFree(xml_buf);
++ VIR_FREE(snippet);
+ xmlXPathFreeContext(ctxt);
+ xmlFreeDoc(xml);
+
+@@ -6200,7 +6185,6 @@ cmdCPUBaseline(vshControl *ctl, const vshCmd *cmd)
+ xmlDocPtr xml = NULL;
+ xmlNodePtr *node_list = NULL;
+ xmlXPathContextPtr ctxt = NULL;
+- xmlBufferPtr xml_buf = NULL;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ size_t i;
+
+@@ -6233,18 +6217,11 @@ cmdCPUBaseline(vshControl *ctl, const vshCmd *cmd)
+
+ list = vshCalloc(ctl, count, sizeof(const char *));
+
+- if (!(xml_buf = xmlBufferCreate()))
+- goto no_memory;
+-
+ for (i = 0; i < count; i++) {
+- xmlBufferEmpty(xml_buf);
+-
+- if (xmlNodeDump(xml_buf, xml, node_list[i], 0, 0) < 0) {
+- vshError(ctl, _("Failed to extract <cpu> element"));
++ if (!(list[i] = virXMLNodeToString(xml, node_list[i]))) {
++ vshSaveLibvirtError();
+ goto cleanup;
+ }
+-
+- list[i] = vshStrdup(ctl, (const char *)xmlBufferContent(xml_buf));
+ }
+
+ result = virConnectBaselineCPU(ctl->conn, list, count, 0);
+@@ -6257,7 +6234,6 @@ cmdCPUBaseline(vshControl *ctl, const vshCmd *cmd)
+ cleanup:
+ xmlXPathFreeContext(ctxt);
+ xmlFreeDoc(xml);
+- xmlBufferFree(xml_buf);
+ VIR_FREE(result);
+ if (list != NULL && count > 0) {
+ for (i = 0; i < count; i++)
+@@ -9633,7 +9609,7 @@ cmdDetachInterface(vshControl *ctl, const vshCmd *cmd)
+ xmlXPathObjectPtr obj=NULL;
+ xmlXPathContextPtr ctxt = NULL;
+ xmlNodePtr cur = NULL, matchNode = NULL;
+- xmlBufferPtr xml_buf = NULL;
++ char *detach_xml = NULL;
+ const char *mac =NULL, *type = NULL;
+ char *doc = NULL;
+ char buf[64];
+@@ -9726,25 +9702,16 @@ cmdDetachInterface(vshControl *ctl, const vshCmd *cmd)
+ goto cleanup;
+ }
+
+- hit:
+- xml_buf = xmlBufferCreate();
+- if (!xml_buf) {
+- vshError(ctl, "%s", _("Failed to allocate memory"));
++hit:
++ if (!(detach_xml = virXMLNodeToString(xml, matchNode))) {
++ vshSaveLibvirtError();
+ goto cleanup;
+ }
+
+- if (xmlNodeDump(xml_buf, xml, matchNode, 0, 0) < 0) {
+- vshError(ctl, "%s", _("Failed to create XML"));
+- goto cleanup;
+- }
+-
+- if (flags != 0 || current) {
+- ret = virDomainDetachDeviceFlags(dom,
+- (char *)xmlBufferContent(xml_buf),
+- flags);
+- } else {
+- ret = virDomainDetachDevice(dom, (char *)xmlBufferContent(xml_buf));
+- }
++ if (flags != 0)
++ ret = virDomainDetachDeviceFlags(dom, detach_xml, flags);
++ else
++ ret = virDomainDetachDevice(dom, detach_xml);
+
+ if (ret != 0) {
+ vshError(ctl, "%s", _("Failed to detach interface"));
+@@ -9753,13 +9720,13 @@ cmdDetachInterface(vshControl *ctl, const vshCmd *cmd)
+ functionReturn = true;
+ }
+
+- cleanup:
++cleanup:
+ VIR_FREE(doc);
++ VIR_FREE(detach_xml);
+ virDomainFree(dom);
+ xmlXPathFreeObject(obj);
+ xmlXPathFreeContext(ctxt);
+ xmlFreeDoc(xml);
+- xmlBufferFree(xml_buf);
+ return functionReturn;
+ }
+
+@@ -9877,7 +9844,6 @@ vshPrepareDiskXML(xmlNodePtr disk_node,
+ int type)
+ {
+ xmlNodePtr cur = NULL;
+- xmlBufferPtr xml_buf = NULL;
+ const char *disk_type = NULL;
+ const char *device_type = NULL;
+ xmlNodePtr new_node = NULL;
+@@ -9886,12 +9852,6 @@ vshPrepareDiskXML(xmlNodePtr disk_node,
+ if (!disk_node)
+ return NULL;
+
+- xml_buf = xmlBufferCreate();
+- if (!xml_buf) {
+- vshError(NULL, "%s", _("Failed to allocate memory"));
+- return NULL;
+- }
+-
+ device_type = virXMLPropString(disk_node, "device");
+
+ if (STREQ_NULLABLE(device_type, "cdrom") ||
+@@ -9913,7 +9873,7 @@ vshPrepareDiskXML(xmlNodePtr disk_node,
+ if (type == VSH_PREPARE_DISK_XML_EJECT) {
+ vshError(NULL, _("The disk device '%s' doesn't have media"),
+ path);
+- goto error;
++ goto cleanup;
+ }
+
+ if (source) {
+@@ -9925,10 +9885,10 @@ vshPrepareDiskXML(xmlNodePtr disk_node,
+ xmlAddChild(disk_node, new_node);
+ } else if (type == VSH_PREPARE_DISK_XML_INSERT) {
+ vshError(NULL, _("No source is specified for inserting media"));
+- goto error;
++ goto cleanup;
+ } else if (type == VSH_PREPARE_DISK_XML_UPDATE) {
+ vshError(NULL, _("No source is specified for updating media"));
+- goto error;
++ goto cleanup;
+ }
+ }
+
+@@ -9936,7 +9896,7 @@ vshPrepareDiskXML(xmlNodePtr disk_node,
+ if (type == VSH_PREPARE_DISK_XML_INSERT) {
+ vshError(NULL, _("The disk device '%s' already has media"),
+ path);
+- goto error;
++ goto cleanup;
+ }
+
+ /* Remove the source if it tends to eject/update media. */
+@@ -9952,30 +9912,15 @@ vshPrepareDiskXML(xmlNodePtr disk_node,
+ }
+ }
+
+- if (xmlNodeDump(xml_buf, NULL, disk_node, 0, 0) < 0) {
+- vshError(NULL, "%s", _("Failed to create XML"));
+- goto error;
++ if (!(ret = virXMLNodeToString(NULL, disk_node))) {
++ vshSaveLibvirtError();
++ goto cleanup;
+ }
+
+- goto cleanup;
+-
+ cleanup:
+ VIR_FREE(device_type);
+ VIR_FREE(disk_type);
+- if (xml_buf) {
+- int len = xmlBufferLength(xml_buf);
+- if (VIR_ALLOC_N(ret, len + 1) < 0)
+- return NULL;
+- memcpy(ret, (char *)xmlBufferContent(xml_buf), len);
+- ret[len] = '\0';
+- xmlBufferFree(xml_buf);
+- }
+ return ret;
+-
+-error:
+- xmlBufferFree(xml_buf);
+- xml_buf = NULL;
+- goto cleanup;
+ }
+
+
+--
+2.2.1
+
--- /dev/null
+From 913b0f1385085b9a0a17f835fa56b1ccd2ad65c6 Mon Sep 17 00:00:00 2001
+Message-Id: <913b0f1385085b9a0a17f835fa56b1ccd2ad65c6@dist-git>
+From: Peter Krempa <pkrempa@redhat.com>
+Date: Wed, 28 Jan 2015 10:33:40 +0100
+Subject: [PATCH] virsh: man: Crosslink "desc" and "metadata" sections
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1184929
+
+Those two commands work with a single API so cross-link them.
+
+(cherry picked from commit c68ae7f61155891651081e523c5576e719f932eb)
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ tools/virsh.pod | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/tools/virsh.pod b/tools/virsh.pod
+index c3ae204..d0dbbca 100644
+--- a/tools/virsh.pod
++++ b/tools/virsh.pod
+@@ -581,6 +581,7 @@ effect on the next boot.
+ Show or modify description and title of a domain. These values are user
+ fields that allow to store arbitrary textual data to allow easy
+ identification of domains. Title should be short, although it's not enforced.
++(See also B<metadata> that works with XML based domain metadata.)
+
+ Flags I<--live> or I<--config> select whether this command works on live
+ or persistent definitions of the domain. If both I<--live> and I<--config>
+@@ -1080,7 +1081,8 @@ Show or modify custom XML metadata of a domain. The metadata is a user
+ defined XML that allows to store arbitrary XML data in the domain definition.
+ Multiple separate custom metadata pieces can be stored in the domain XML.
+ The pieces are identified by a private XML namespace provided via the
+-I<uri> argument.
++I<uri> argument. (See also B<desc> that works with textual metadata of
++a domain.)
+
+ Flags I<--live> or I<--config> select whether this command works on live
+ or persistent definitions of the domain. If both I<--live> and I<--config>
+--
+2.2.2
+
Summary: Library providing a simple virtualization API
Name: libvirt
Version: 1.1.1
-Release: 29%{?dist}.4%{?extra_release}
+Release: 29%{?dist}.7%{?extra_release}
License: LGPLv2+
Group: Development/Libraries
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
Patch519: libvirt-qemu-reject-rather-than-hang-on-blockcommit-of-active-layer.patch
Patch520: libvirt-CVE-2014-7823-dumpxml-security-hole-with-migratable-flag.patch
Patch521: libvirt-Fix-crash-when-saving-a-domain-with-type-none-dac-label.patch
+Patch522: libvirt-conf-Format-interface-s-driver-more-frequently.patch
+Patch523: libvirt-qemu-Factor-out-body-of-qemuDomainGetMetadata-for-universal-use.patch
+Patch524: libvirt-qemu-Factor-out-body-of-qemuDomainSetMetadata-for-universal-use.patch
+Patch525: libvirt-conf-Factor-out-setting-of-metadata-to-simplify-code.patch
+Patch526: libvirt-util-Add-helper-to-convert-libxml2-nodes-to-a-string.patch
+Patch527: libvirt-virsh-domain-use-virXMLNodeToString-instead-of-xmlNodeDump.patch
+Patch528: libvirt-virsh-domain-Add-command-to-allow-modifications-of-XML-metadata.patch
+Patch529: libvirt-conf-Add-support-for-requesting-of-XML-metadata-via-the-API.patch
+Patch530: libvirt-conf-allow-to-add-XML-metadata-using-the-virDomainSetMetadata-api.patch
+Patch531: libvirt-lib-Don-t-force-the-key-argument-when-deleting-metadata.patch
+Patch532: libvirt-lxc-Add-metadata-modification-APIs.patch
+Patch533: libvirt-test-Add-metadata-support-into-the-test-driver.patch
+Patch534: libvirt-tests-Add-metadata-tests.patch
+Patch535: libvirt-conf-Don-t-corrupt-metadata-on-OOM.patch
+Patch536: libvirt-conf-Avoid-false-positive-of-uninitialized-variable-use.patch
+Patch537: libvirt-virsh-Don-t-shadow-global-variable-remove-in-cmdMetadata.patch
+Patch538: libvirt-metadata-track-title-edits-across-libvirtd-restart.patch
+Patch539: libvirt-conf-Improve-metadata-type-verification.patch
+Patch540: libvirt-Fix-possible-memory-leak-in-util-virxml.c.patch
+Patch541: libvirt-util-check-for-an-illegal-character-in-a-XML-namespace-prefix.patch
+Patch542: libvirt-Fix-libvirtd-crash-when-removing-metadata.patch
+Patch543: libvirt-Add-invariant-TSC-cpu-flag.patch
+Patch544: libvirt-cpu_x86-Resolve-Coverity-RESOURCE_LEAK.patch
+Patch545: libvirt-Don-t-include-non-migratable-features-in-host-model.patch
+Patch546: libvirt-Fix-leak-in-x86UpdateHostModel.patch
+Patch547: libvirt-Also-filter-out-non-migratable-features-out-of-host-passthrough.patch
+Patch548: libvirt-man-virsh-Add-man-page-for-virsh-metadata.patch
+Patch549: libvirt-virsh-man-Crosslink-desc-and-metadata-sections.patch
+Patch550: libvirt-Fix-segfault-when-starting-a-domain-with-no-cpu-definition.patch
%if %{with_libvirtd}
%endif
%changelog
+* Thu Jan 29 2015 Jiri Denemark <jdenemar@redhat.com> - 1.1.1-29.el7_0.7
+- Fix segfault when starting a domain with no cpu definition (rhbz#1185458)
+
+* Wed Jan 28 2015 Jiri Denemark <jdenemar@redhat.com> - 1.1.1-29.el7_0.6
+- Add invariant TSC cpu flag (rhbz#1185458)
+- cpu_x86: Resolve Coverity RESOURCE_LEAK (rhbz#1185458)
+- Don't include non-migratable features in host-model (rhbz#1185458)
+- Fix leak in x86UpdateHostModel (rhbz#1185458)
+- Also filter out non-migratable features out of host-passthrough (rhbz#1185458)
+- man: virsh: Add man page for "virsh metadata" (rhbz#1184929)
+- virsh: man: Crosslink "desc" and "metadata" sections (rhbz#1184929)
+
+* Fri Jan 23 2015 Jiri Denemark <jdenemar@redhat.com> - 1.1.1-29.el7_0.5
+- conf: Format interface's driver more frequently (rhbz#1183447)
+- qemu: Factor out body of qemuDomainGetMetadata for universal use (rhbz#1184929)
+- qemu: Factor out body of qemuDomainSetMetadata for universal use (rhbz#1184929)
+- conf: Factor out setting of metadata to simplify code (rhbz#1184929)
+- util: Add helper to convert libxml2 nodes to a string (rhbz#1184929)
+- virsh-domain: use virXMLNodeToString instead of xmlNodeDump (rhbz#1184929)
+- virsh-domain: Add command to allow modifications of XML metadata (rhbz#1184929)
+- conf: Add support for requesting of XML metadata via the API (rhbz#1184929)
+- conf: allow to add XML metadata using the virDomainSetMetadata api (rhbz#1184929)
+- lib: Don't force the key argument when deleting metadata (rhbz#1184929)
+- lxc: Add metadata modification APIs (rhbz#1184929)
+- test: Add <metadata> support into the test driver (rhbz#1184929)
+- tests: Add metadata tests (rhbz#1184929)
+- conf: Don't corrupt metadata on OOM (rhbz#1184929)
+- conf: Avoid false positive of uninitialized variable use (rhbz#1184929)
+- virsh: Don't shadow global variable "remove" in cmdMetadata (rhbz#1184929)
+- metadata: track title edits across libvirtd restart (rhbz#1184929)
+- conf: Improve metadata type verification (rhbz#1184929)
+- Fix possible memory leak in util/virxml.c (rhbz#1184929)
+- util: check for an illegal character in a XML namespace prefix (rhbz#1184929)
+- Fix libvirtd crash when removing metadata (rhbz#1184929)
+
* Tue Dec 9 2014 Jiri Denemark <jdenemar@redhat.com> - 1.1.1-29.el7_0.4
- qemu: blockcopy: Don't remove existing disk mirror info (rhbz#1149078)
- qemu: copy: Accept 'format' parameter when copying to a non-existing img (rhbz#1149078)