---
docs/formatsnapshot.html.in | 7 +++++
docs/schemas/domainsnapshot.rng | 4 +++
src/conf/snapshot_conf.c | 63 +++++++++++++++++++++++++++++++++++++++++
src/conf/snapshot_conf.h | 2 ++
src/qemu/qemu_driver.c | 21 +++++++++++---
5 files changed, 93 insertions(+), 4 deletions(-)
diff --git a/docs/formatsnapshot.html.in b/docs/formatsnapshot.html.in
index 8fcc04c..842ebab 100644
--- a/docs/formatsnapshot.html.in
+++ b/docs/formatsnapshot.html.in
@@ -167,6 +167,13 @@
snapshots, the original file name becomes the read-only
snapshot, and the new file name contains the read-write
delta of all disk changes since the snapshot.
+
+ An optional <code>features</code> element may be specified,
+ containing format-specific features. So far only for qcow3
+ driver type. See
+ <a href="formatstorage.html#StorageVolTarget">storage volume
+ target</a> for valid values. <span class="since">Since
1.0.3
+ </span>
</dd>
</dl>
</dd>
diff --git a/docs/schemas/domainsnapshot.rng b/docs/schemas/domainsnapshot.rng
index 45d55b5..7ceb582 100644
--- a/docs/schemas/domainsnapshot.rng
+++ b/docs/schemas/domainsnapshot.rng
@@ -6,6 +6,7 @@
</start>
<include href='domaincommon.rng'/>
+ <include href='storagefeatures.rng'/>
<define name='domainsnapshot'>
<element name='domainsnapshot'>
@@ -144,6 +145,9 @@
<empty/>
</element>
</optional>
+ <optional>
+ <ref name='diskFormatFeatures'/>
+ </optional>
</interleave>
</group>
</choice>
diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c
index fe77bd0..7be04f4 100644
--- a/src/conf/snapshot_conf.c
+++ b/src/conf/snapshot_conf.c
@@ -103,6 +103,35 @@ void virDomainSnapshotDefFree(virDomainSnapshotDefPtr def)
}
static int
+virDomainSnapshotDiskDefParseFeatures(xmlNodePtr node,
+ virDomainSnapshotDiskDefPtr def)
+{
+ int value;
+ xmlNodePtr cur;
+
+ def->features = virBitmapNew(VIR_STORAGE_FILE_FEAT_QCOW3_LAST);
+ if (!def->features)
+ goto no_memory;
+
+ for (cur = node->children; cur; cur = cur->next) {
+ if (cur->type != XML_ELEMENT_NODE)
+ continue;
+ value = virStorageFileFeaturesQcow3TypeFromString((const char*)
+ cur->name);
+ if (value >= 0 && virBitmapSetBit(def->features, value) < 0)
+ goto error;
+ }
+
+ return 0;
+
+no_memory:
+ virReportOOMError();
+error:
+ virBitmapFree(def->features);
+ return -1;
+}
+
+static int
virDomainSnapshotDiskDefParseXML(xmlNodePtr node,
virDomainSnapshotDiskDefPtr def)
{
@@ -146,6 +175,10 @@ virDomainSnapshotDiskDefParseXML(xmlNodePtr node,
goto cleanup;
}
VIR_FREE(driver);
+ } else if (!def->features &&
+ xmlStrEqual(cur->name, BAD_CAST "features")) {
+ if (virDomainSnapshotDiskDefParseFeatures(cur, def) < 0)
+ goto cleanup;
}
}
cur = cur->next;
@@ -551,6 +584,30 @@ cleanup:
return ret;
}
+static int
+virDomainSnapshotDefFeaturesFormat(virBufferPtr buf,
+ int format,
+ virBitmapPtr features)
+{
+ int i;
+ bool tmp;
+ if (format != VIR_STORAGE_FILE_QCOW3)
+ return 0;
+
+ virBufferAddLit(buf, "<features>\n");
+ if (features) {
+ for (i = 0; i < VIR_STORAGE_FILE_FEAT_QCOW3_LAST; i++) {
+ if (virBitmapGetBit(features, i, &tmp) == 0 && tmp) {
+ virBufferEscapeString(buf, " <%s/>\n",
+ virStorageFileFeaturesQcow3TypeToString(i));
+ }
+ }
+ }
+ virBufferAddLit(buf, "</features>\n");
+
+ return 0;
+}
+
char *virDomainSnapshotDefFormat(const char *domain_uuid,
virDomainSnapshotDefPtr def,
unsigned int flags,
@@ -602,6 +659,12 @@ char *virDomainSnapshotDefFormat(const char *domain_uuid,
virBufferEscapeString(&buf, " <driver
type='%s'/>\n",
virStorageFileFormatTypeToString(
disk->format));
+ if (disk->format == VIR_STORAGE_FILE_QCOW3) {
+ virBufferAdjustIndent(&buf, 6);
+ virDomainSnapshotDefFeaturesFormat(&buf, disk->format,
+ disk->features);
+ virBufferAdjustIndent(&buf, -6);
+ }
if (disk->file)
virBufferEscapeString(&buf, " <source
file='%s'/>\n",
disk->file);
diff --git a/src/conf/snapshot_conf.h b/src/conf/snapshot_conf.h
index f1d5995..7a8b08a 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 */
+ virBitmapPtr features; /* format-specific features.
+ currently only used for qcow3 */
};
/* Stores the complete snapshot metadata */
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 79f78fa..078d876 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -10513,6 +10513,7 @@ qemuDomainSnapshotCreateInactiveExternal(virQEMUDriverPtr driver,
virDomainDiskDefPtr defdisk;
virCommandPtr cmd = NULL;
const char *qemuImgPath;
+ const char *opts = NULL;
virBitmapPtr created;
int ret = -1;
@@ -10541,16 +10542,25 @@ qemuDomainSnapshotCreateInactiveExternal(virQEMUDriverPtr
driver,
if (!(cmd = virCommandNewArgList(qemuImgPath,
"create",
"-f",
-
virStorageFileFormatTypeToString(snapdisk->format),
+
virStorageFileFormatToStringQemu(snapdisk->format),
"-o",
NULL)))
goto cleanup;
+ if (snapdisk->format == VIR_STORAGE_FILE_QCOW3) {
+ opts = virStorageFileQemuImgQcow3Options(snapdisk->features);
+ if (!opts)
+ goto cleanup;
+ } else if (snapdisk->format == VIR_STORAGE_FILE_QCOW2) {
+ opts = strdup(",compat=0.10");
+ }
+
if (defdisk->format > 0) {
/* adds cmd line arg: backing_file=/path/to/backing/file,backing_fmd=format
*/
- virCommandAddArgFormat(cmd, "backing_file=%s,backing_fmt=%s",
+ virCommandAddArgFormat(cmd, "backing_file=%s,backing_fmt=%s%s",
defdisk->src,
-
virStorageFileFormatTypeToString(defdisk->format));
+ virStorageFileFormatToStringQemu(defdisk->format),
+ opts ? opts : "");
} else {
if (!driver->allowDiskFormatProbing) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
@@ -10561,7 +10571,8 @@ qemuDomainSnapshotCreateInactiveExternal(virQEMUDriverPtr driver,
}
/* adds cmd line arg: backing_file=/path/to/backing/file */
- virCommandAddArgFormat(cmd, "backing_file=%s", defdisk->src);
+ virCommandAddArgFormat(cmd, "backing_file=%s%s", defdisk->src,
+ opts ? opts : "");
}
/* adds cmd line args: /path/to/target/file */
@@ -10597,6 +10608,7 @@ qemuDomainSnapshotCreateInactiveExternal(virQEMUDriverPtr driver,
ret = 0;
cleanup:
+ VIR_FREE(opts);
virCommandFree(cmd);
/* unlink images if creation has failed */
@@ -10759,6 +10771,7 @@ qemuDomainSnapshotPrepare(virDomainObjPtr vm,
virDomainSnapshotDefPtr def,
if (!disk->format) {
disk->format = VIR_STORAGE_FILE_QCOW2;
} else if (disk->format != VIR_STORAGE_FILE_QCOW2 &&
+ disk->format != VIR_STORAGE_FILE_QCOW3 &&
disk->format != VIR_STORAGE_FILE_QED) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("external snapshot format for disk %s "
--
1.7.12.4