Add <features> and <compat> elements to snapshot disk XML.
<compat> is a string which for qcow2 represents the QEMU version
it should be compatible with. Valid values are 0.10 and 1.1.
1.1 is implicit if the <features> element is present, otherwise
qemu-img default is used. 0.10 can be specified to explicitly
create older images after the qemu-img default changes.
<features> contains optional features, so far
<lazy_refcounts/> is available.
---
docs/schemas/domainsnapshot.rng | 7 ++
src/conf/snapshot_conf.c | 84 ++++++++++++++++++++++++
src/conf/snapshot_conf.h | 2 +
tests/domainsnapshotxml2xmlin/disk_snapshot.xml | 5 ++
tests/domainsnapshotxml2xmlout/disk_snapshot.xml | 4 ++
5 files changed, 102 insertions(+)
diff --git a/docs/schemas/domainsnapshot.rng b/docs/schemas/domainsnapshot.rng
index 7b46df1..63c8511 100644
--- a/docs/schemas/domainsnapshot.rng
+++ b/docs/schemas/domainsnapshot.rng
@@ -6,6 +6,7 @@
</start>
<include href='domaincommon.rng'/>
+ <include href='storagefilefeatures.rng'/>
<define name='domainsnapshot'>
<element name='domainsnapshot'>
@@ -144,6 +145,12 @@
<empty/>
</element>
</optional>
+ <optional>
+ <ref name='compat'/>
+ </optional>
+ <optional>
+ <ref name='fileFormatFeatures'/>
+ </optional>
</interleave>
</group>
</choice>
diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c
index b500111..3596413 100644
--- a/src/conf/snapshot_conf.c
+++ b/src/conf/snapshot_conf.c
@@ -82,6 +82,9 @@ virDomainSnapshotDiskDefClear(virDomainSnapshotDiskDefPtr disk)
{
VIR_FREE(disk->name);
VIR_FREE(disk->file);
+ VIR_FREE(disk->compat);
+ virBitmapFree(disk->features);
+ disk->features = NULL;
}
void virDomainSnapshotDefFree(virDomainSnapshotDefPtr def)
@@ -103,6 +106,38 @@ void virDomainSnapshotDefFree(virDomainSnapshotDefPtr def)
}
static int
+virDomainSnapshotDiskFeaturesDefParse(virDomainSnapshotDiskDefPtr def,
+ xmlNodePtr node)
+{
+ xmlNodePtr cur;
+ int f, n = 0;
+
+ if (!(def->features = virBitmapNew(VIR_STORAGE_FILE_FEATURE_LAST))) {
+ virReportOOMError();
+ return -1;
+ }
+
+ for (cur = node->children; cur; cur = cur->next) {
+ if (cur->type != XML_ELEMENT_NODE)
+ continue;
+
+ f = virStorageFileFeatureTypeFromString((const char*) cur->name);
+
+ if (f < 0) {
+ virReportError(VIR_ERR_XML_ERROR, _("unsupported feature %s"),
+ (const char*) cur->name);
+ return -1;
+ }
+ ignore_value(virBitmapSetBit(def->features, f));
+ n++;
+
+ }
+ if (n > 0 && !def->compat && VIR_STRDUP(def->compat,
"1.1") < 0)
+ return -1;
+ return 0;
+}
+
+static int
virDomainSnapshotDiskDefParseXML(xmlNodePtr node,
virDomainSnapshotDiskDefPtr def)
{
@@ -146,6 +181,27 @@ virDomainSnapshotDiskDefParseXML(xmlNodePtr node,
goto cleanup;
}
VIR_FREE(driver);
+ } else if (xmlStrEqual(cur->name, BAD_CAST "compat")) {
+ if (VIR_STRDUP(def->compat, (const char*)cur->content) < 0)
+ goto cleanup;
+ if (def->compat) {
+ char **version = virStringSplit(def->compat, ".", 2);
+ unsigned int result;
+
+ if (!version || !version[1] ||
+ virStrToLong_ui(version[0], NULL, 10, &result) < 0 ||
+ virStrToLong_ui(version[1], NULL, 10, &result) < 0) {
+ virStringFreeList(version);
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("forbidden characters in
'compat'"
+ " attribute"));
+ goto cleanup;
+ }
+ virStringFreeList(version);
+ }
+ } else if (xmlStrEqual(cur->name, BAD_CAST "features")) {
+ if (virDomainSnapshotDiskFeaturesDefParse(def, cur) < 0)
+ goto cleanup;
}
}
cur = cur->next;
@@ -549,6 +605,29 @@ cleanup:
}
static void
+virDomainSnapshotDiskFeaturesDefFormat(virBufferPtr buf,
+ virBitmapPtr features)
+{
+ int i;
+
+ if (virBitmapIsAllClear(features)) {
+ virBufferAddLit(buf, "<features/>\n");
+ return;
+ }
+
+ virBufferAddLit(buf, "<features>\n");
+ for (i = 0; i < VIR_STORAGE_FILE_FEATURE_LAST; i++) {
+ bool b;
+
+ ignore_value(virBitmapGetBit(features, i, &b));
+ if (b)
+ virBufferAsprintf(buf, " <%s/>\n",
+ virStorageFileFeatureTypeToString(i));
+ }
+ virBufferAddLit(buf, "</features>\n");
+}
+
+static void
virDomainSnapshotDiskDefFormat(virBufferPtr buf,
virDomainSnapshotDiskDefPtr disk)
{
@@ -571,6 +650,11 @@ virDomainSnapshotDiskDefFormat(virBufferPtr buf,
virBufferEscapeString(buf, "<driver type='%s'/>\n",
virStorageFileFormatTypeToString(disk->format));
virBufferEscapeString(buf, "<source file='%s'/>\n",
disk->file);
+ virBufferEscapeString(buf, "<compat>%s</compat>\n",
disk->compat);
+
+ if (disk->features)
+ virDomainSnapshotDiskFeaturesDefFormat(buf, disk->features);
+
virBufferAdjustIndent(buf, -6);
virBufferAddLit(buf, " </disk>\n");
}
diff --git a/src/conf/snapshot_conf.h b/src/conf/snapshot_conf.h
index 6d625a7..2be5319 100644
--- a/src/conf/snapshot_conf.h
+++ b/src/conf/snapshot_conf.h
@@ -53,6 +53,8 @@ struct _virDomainSnapshotDiskDef {
int snapshot; /* enum virDomainSnapshotLocation */
char *file; /* new source file when snapshot is external */
int format; /* enum virStorageFileFormat */
+ char *compat;
+ virBitmapPtr features;
};
/* Stores the complete snapshot metadata */
diff --git a/tests/domainsnapshotxml2xmlin/disk_snapshot.xml
b/tests/domainsnapshotxml2xmlin/disk_snapshot.xml
index ee6b46a..79895d7 100644
--- a/tests/domainsnapshotxml2xmlin/disk_snapshot.xml
+++ b/tests/domainsnapshotxml2xmlin/disk_snapshot.xml
@@ -11,6 +11,11 @@
</disk>
<disk name='hde' snapshot='external'>
<source file='/path/to/new'/>
+ <driver type='qcow2'/>
+ <compat>1.1</compat>
+ <features>
+ <lazy_refcounts/>
+ </features>
</disk>
</disks>
</domainsnapshot>
diff --git a/tests/domainsnapshotxml2xmlout/disk_snapshot.xml
b/tests/domainsnapshotxml2xmlout/disk_snapshot.xml
index 5f42bf5..4c3f8ad 100644
--- a/tests/domainsnapshotxml2xmlout/disk_snapshot.xml
+++ b/tests/domainsnapshotxml2xmlout/disk_snapshot.xml
@@ -18,6 +18,10 @@
<disk name='hde' snapshot='external'>
<driver type='qcow2'/>
<source file='/path/to/new'/>
+ <compat>1.1</compat>
+ <features>
+ <lazy_refcounts/>
+ </features>
</disk>
<disk name='hdf' snapshot='external'>
<driver type='qcow2'/>
--
1.8.1.5