The format is:
<volume>
<name>q4</name>
<source>
</source>
<capacity unit='MiB'>128</capacity>
<target>
<path>/var/lib/libvirt/images/q4</path>
<format type='qcow3'/>
<features>
<compatible>
<lazy_refcounts/>
</compatible>
</features>
</target>
</volume>
---
src/conf/storage_conf.c | 90 ++++++++++++++++++++++++++++++++++++++
src/conf/storage_conf.h | 3 +
src/libvirt_private.syms | 2 +
src/storage/storage_backend_fs.c | 7 +++
4 files changed, 102 insertions(+), 0 deletions(-)
diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c
index 7a39998..f13daa1 100644
--- a/src/conf/storage_conf.c
+++ b/src/conf/storage_conf.c
@@ -293,10 +293,15 @@ virStorageVolDefFree(virStorageVolDefPtr def) {
}
VIR_FREE(def->source.extents);
+ virBitmapFree(def->target.features.compatible);
+ virBitmapFree(def->target.features.incompatible);
VIR_FREE(def->target.path);
VIR_FREE(def->target.perms.label);
VIR_FREE(def->target.timestamps);
virStorageEncryptionFree(def->target.encryption);
+
+ virBitmapFree(def->backingStore.features.compatible);
+ virBitmapFree(def->backingStore.features.incompatible);
VIR_FREE(def->backingStore.path);
VIR_FREE(def->backingStore.perms.label);
VIR_FREE(def->backingStore.timestamps);
@@ -1105,6 +1110,60 @@ virStorageSize(const char *unit,
return 0;
}
+static int
+virStorageVolDefParseTargetFeatures(virStorageVolTargetPtr target,
+ xmlNodePtr start_node)
+{
+ int value, ret = -1;
+ xmlNodePtr cur, node;
+
+ target->features.compatible = virBitmapNew(VIR_STORAGE_FILE_QCOW3_COMP_LAST);
+ target->features.incompatible = virBitmapNew(VIR_STORAGE_FILE_QCOW3_INCOMP_LAST);
+
+ if (!target->features.compatible || !target->features.incompatible) {
+ virReportOOMError();
+ goto error;
+ }
+
+ for (cur = start_node->children; cur; cur = cur->next) {
+ if (cur->type != XML_ELEMENT_NODE)
+ continue;
+
+ if (xmlStrEqual(cur->name, BAD_CAST "compatible")) {
+ for (node = cur->children->next; node; node = node->next) {
+ if (node->type != XML_ELEMENT_NODE)
+ continue;
+ value = virStorageFileQcow3CompTypeFromString(
+ (const char*) node->name);
+
+ if (value < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("unexpected feature %s"),
+ node->name);
+ goto error;
+ }
+ if (virBitmapSetBit(target->features.compatible, value) < 0)
+ goto error;
+ }
+ } else {
+ value = virStorageFileQcow3IncompTypeFromString(
+ (const char*) cur->name);
+ if (value < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("unexpected feature %s"),
+ cur->name);
+ goto error;
+ }
+ if (virBitmapSetBit(target->features.incompatible, value) < 0)
+ goto error;
+ }
+ }
+
+ ret = 0;
+error:
+ return ret;
+}
+
static virStorageVolDefPtr
virStorageVolDefParseXML(virStoragePoolDefPtr pool,
xmlXPathContextPtr ctxt) {
@@ -1211,6 +1270,13 @@ virStorageVolDefParseXML(virStoragePoolDefPtr pool,
DEFAULT_VOL_PERM_MODE) < 0)
goto cleanup;
+ if (pool->type == VIR_STORAGE_POOL_DIR &&
+ ret->target.format == VIR_STORAGE_FILE_QCOW3 &&
+ (node = virXPathNode("./target/features", ctxt)) != NULL) {
+ if (virStorageVolDefParseTargetFeatures(&(ret->target), node) < 0)
+ goto cleanup;
+ }
+
return ret;
cleanup:
@@ -1294,6 +1360,9 @@ virStorageVolTargetDefFormat(virStorageVolOptionsPtr options,
virBufferPtr buf,
virStorageVolTargetPtr def,
const char *type) {
+ bool tmp;
+ int i;
+
virBufferAsprintf(buf, " <%s>\n", type);
if (def->path)
@@ -1341,6 +1410,27 @@ virStorageVolTargetDefFormat(virStorageVolOptionsPtr options,
virBufferAdjustIndent(buf, -4);
}
+ if (def->features.compatible || def->features.incompatible) {
+ virBufferAddLit(buf, " <features>\n");
+ for (i = 0; i < VIR_STORAGE_FILE_QCOW3_INCOMP_LAST; i++) {
+ if (virBitmapGetBit(def->features.incompatible, i, &tmp) == 0
+ && tmp) {
+ virBufferAsprintf(buf, " <%s/>\n",
+ virStorageFileQcow3IncompTypeToString(i));
+ }
+ }
+ virBufferAddLit(buf, " <compatible>\n");
+ for (i = 0; i < VIR_STORAGE_FILE_QCOW3_COMP_LAST; i++) {
+ if (virBitmapGetBit(def->features.compatible, i, &tmp) == 0
+ && tmp) {
+ virBufferAsprintf(buf, " <%s/>\n",
+ virStorageFileQcow3CompTypeToString(i));
+ }
+ }
+ virBufferAddLit(buf, " </compatible>\n");
+ virBufferAddLit(buf, " </features>\n");
+ }
+
virBufferAsprintf(buf, " </%s>\n", type);
return 0;
diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h
index ad16eca..fa60252 100644
--- a/src/conf/storage_conf.h
+++ b/src/conf/storage_conf.h
@@ -28,6 +28,7 @@
# include "virutil.h"
# include "storage_encryption_conf.h"
# include "virthread.h"
+# include "virstoragefile.h"
# include <libxml/tree.h>
@@ -93,6 +94,8 @@ struct _virStorageVolTarget {
int type; /* only used by disk backend for partition type */
/* Currently used only in virStorageVolDef.target, not in .backingstore. */
virStorageEncryptionPtr encryption;
+ /* Currently used only by Qcow3 */
+ virStorageFileFeatures features;
};
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index d079cc9..699cec6 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1177,6 +1177,8 @@ virStorageFileIsSharedFS;
virStorageFileIsSharedFSType;
virStorageFileProbeFormat;
virStorageFileProbeFormatFromFD;
+virStorageFileQcow3CompTypeToString;
+virStorageFileQcow3IncompTypeToString;
virStorageFileResize;
# sysinfo.h
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c
index 2205371..33ef129 100644
--- a/src/storage/storage_backend_fs.c
+++ b/src/storage/storage_backend_fs.c
@@ -136,6 +136,7 @@ virStorageBackendProbeTarget(virStorageVolTargetPtr target,
switch (target->format) {
case VIR_STORAGE_FILE_QCOW:
case VIR_STORAGE_FILE_QCOW2:
+ case VIR_STORAGE_FILE_QCOW3:
(*encryption)->format = VIR_STORAGE_ENCRYPTION_FORMAT_QCOW;
break;
default:
@@ -149,6 +150,12 @@ virStorageBackendProbeTarget(virStorageVolTargetPtr target,
*/
}
+ if (target->format == VIR_STORAGE_FILE_QCOW3) {
+ target->features = meta->features;
+ meta->features.compatible = NULL;
+ meta->features.incompatible = NULL;
+ }
+
virStorageFileFreeMetadata(meta);
return ret;
--
1.7.8.6