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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list