diff --git a/docs/formatstorage.html.in b/docs/formatstorage.html.in
index 1a45915cab..c1c1b15daf 100644
--- a/docs/formatstorage.html.in
+++ b/docs/formatstorage.html.in
@@ -334,6 +334,10 @@
<mode>0744</mode>
<label>virt_image_t</label>
</permissions>
+ <compat>1.1</compat>
+ <features>
+ <lazy_refcounts/>
+ </features>
</target>
@@ -362,6 +366,22 @@
contains the MAC (eg SELinux) label string.
Since 0.4.1
+ compat
+ Specify compatibility level. So far, this is only used for
+ type='qcow2'
volumes. Valid values are 0.10
+ and 1.1
so far, specifying QEMU version the images should
+ be compatible with. If the feature
element is present,
+ 1.1 is used. If omitted, qemu-img default is used.
+ Since 1.0.7
+
+ features
+ Format-specific features. Only used for qcow2
now.
+ Valid sub-elements are:
+
+ <lazy_refcounts/>
- allow delayed reference
+ counter updates. Since 1.0.7
+
+
diff --git a/docs/schemas/Makefile.am b/docs/schemas/Makefile.am
index 8da2c67d2f..47d1941a51 100644
--- a/docs/schemas/Makefile.am
+++ b/docs/schemas/Makefile.am
@@ -28,6 +28,7 @@ schema_DATA = \
nwfilter.rng \
secret.rng \
storageencryption.rng \
+ storagefilefeatures.rng \
storagepool.rng \
storagevol.rng
diff --git a/docs/schemas/storagefilefeatures.rng b/docs/schemas/storagefilefeatures.rng
new file mode 100644
index 0000000000..424b4e2318
--- /dev/null
+++ b/docs/schemas/storagefilefeatures.rng
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+ [0-9]+\.[0-9]+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/schemas/storagevol.rng b/docs/schemas/storagevol.rng
index 4649d9151f..8bc5907865 100644
--- a/docs/schemas/storagevol.rng
+++ b/docs/schemas/storagevol.rng
@@ -8,6 +8,7 @@
+
@@ -113,6 +114,12 @@
+
+
+
+
+
+
diff --git a/libvirt.spec.in b/libvirt.spec.in
index e357a3d264..a0a390eab6 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -2006,6 +2006,7 @@ fi
%{_datadir}/libvirt/schemas/nwfilter.rng
%{_datadir}/libvirt/schemas/secret.rng
%{_datadir}/libvirt/schemas/storageencryption.rng
+%{_datadir}/libvirt/schemas/storagefilefeatures.rng
%{_datadir}/libvirt/schemas/storagepool.rng
%{_datadir}/libvirt/schemas/storagevol.rng
diff --git a/mingw-libvirt.spec.in b/mingw-libvirt.spec.in
index 9208329a89..aa3923104d 100644
--- a/mingw-libvirt.spec.in
+++ b/mingw-libvirt.spec.in
@@ -213,6 +213,7 @@ rm -rf $RPM_BUILD_ROOT%{mingw64_libexecdir}/libvirt-guests.sh
%{mingw32_datadir}/libvirt/schemas/nwfilter.rng
%{mingw32_datadir}/libvirt/schemas/secret.rng
%{mingw32_datadir}/libvirt/schemas/storageencryption.rng
+%{mingw32_datadir}/libvirt/schemas/storagefilefeatures.rng
%{mingw32_datadir}/libvirt/schemas/storagepool.rng
%{mingw32_datadir}/libvirt/schemas/storagevol.rng
%dir %{mingw32_datadir}/libvirt/api/
@@ -273,6 +274,7 @@ rm -rf $RPM_BUILD_ROOT%{mingw64_libexecdir}/libvirt-guests.sh
%{mingw64_datadir}/libvirt/schemas/nwfilter.rng
%{mingw64_datadir}/libvirt/schemas/secret.rng
%{mingw64_datadir}/libvirt/schemas/storageencryption.rng
+%{mingw64_datadir}/libvirt/schemas/storagefilefeatures.rng
%{mingw64_datadir}/libvirt/schemas/storagepool.rng
%{mingw64_datadir}/libvirt/schemas/storagevol.rng
%dir %{mingw64_datadir}/libvirt/api/
diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c
index c58b728a5c..288e265e4a 100644
--- a/src/conf/storage_conf.c
+++ b/src/conf/storage_conf.c
@@ -97,6 +97,8 @@ VIR_ENUM_IMPL(virStoragePoolSourceAdapterType,
typedef const char *(*virStorageVolFormatToString)(int format);
typedef int (*virStorageVolFormatFromString)(const char *format);
+typedef const char *(*virStorageVolFeatureToString)(int feature);
+typedef int (*virStorageVolFeatureFromString)(const char *feature);
typedef const char *(*virStoragePoolFormatToString)(int format);
typedef int (*virStoragePoolFormatFromString)(const char *format);
@@ -107,6 +109,8 @@ struct _virStorageVolOptions {
int defaultFormat;
virStorageVolFormatToString formatToString;
virStorageVolFormatFromString formatFromString;
+ virStorageVolFeatureToString featureToString;
+ virStorageVolFeatureFromString featureFromString;
};
/* Flags to indicate mandatory components in the pool source */
@@ -161,6 +165,8 @@ static virStoragePoolTypeInfo poolTypeInfo[] = {
.defaultFormat = VIR_STORAGE_FILE_RAW,
.formatFromString = virStorageVolumeFormatFromString,
.formatToString = virStorageFileFormatTypeToString,
+ .featureFromString = virStorageFileFeatureTypeFromString,
+ .featureToString = virStorageFileFeatureTypeToString,
},
},
{.poolType = VIR_STORAGE_POOL_FS,
@@ -174,6 +180,8 @@ static virStoragePoolTypeInfo poolTypeInfo[] = {
.defaultFormat = VIR_STORAGE_FILE_RAW,
.formatFromString = virStorageVolumeFormatFromString,
.formatToString = virStorageFileFormatTypeToString,
+ .featureFromString = virStorageFileFeatureTypeFromString,
+ .featureToString = virStorageFileFeatureTypeToString,
},
},
{.poolType = VIR_STORAGE_POOL_NETFS,
@@ -188,6 +196,8 @@ static virStoragePoolTypeInfo poolTypeInfo[] = {
.defaultFormat = VIR_STORAGE_FILE_RAW,
.formatFromString = virStorageVolumeFormatFromString,
.formatToString = virStorageFileFormatTypeToString,
+ .featureFromString = virStorageFileFeatureTypeFromString,
+ .featureToString = virStorageFileFeatureTypeToString,
},
},
{.poolType = VIR_STORAGE_POOL_ISCSI,
@@ -299,6 +309,8 @@ virStorageVolDefFree(virStorageVolDefPtr def)
}
VIR_FREE(def->source.extents);
+ VIR_FREE(def->target.compat);
+ virBitmapFree(def->target.features);
VIR_FREE(def->target.path);
VIR_FREE(def->target.perms.label);
VIR_FREE(def->target.timestamps);
@@ -1248,6 +1260,8 @@ virStorageVolDefParseXML(virStoragePoolDefPtr pool,
char *capacity = NULL;
char *unit = NULL;
xmlNodePtr node;
+ xmlNodePtr *nodes = NULL;
+ int i, n;
options = virStorageVolOptionsForPoolType(pool->type);
if (options == NULL)
@@ -1335,17 +1349,59 @@ virStorageVolDefParseXML(virStoragePoolDefPtr pool,
VIR_FREE(format);
}
+ ret->target.compat = virXPathString("string(./target/compat)", ctxt);
+ if (ret->target.compat) {
+ char **version = virStringSplit(ret->target.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 error;
+ }
+ virStringFreeList(version);
+ }
+
+ if (options->featureFromString && virXPathNode("./target/features", ctxt)) {
+ if ((n = virXPathNodeSet("./target/features/*", ctxt, &nodes)) < 0)
+ goto error;
+
+ if (!ret->target.compat && VIR_STRDUP(ret->target.compat, "1.1") < 0)
+ goto error;
+
+ if (!(ret->target.features = virBitmapNew(VIR_STORAGE_FILE_FEATURE_LAST)))
+ goto no_memory;
+
+ for (i = 0; i < n; i++) {
+ int f = options->featureFromString((const char*)nodes[i]->name);
+
+ if (f < 0) {
+ virReportError(VIR_ERR_XML_ERROR, _("unsupported feature %s"),
+ (const char*)nodes[i]->name);
+ goto error;
+ }
+ ignore_value(virBitmapSetBit(ret->target.features, f));
+ }
+ VIR_FREE(nodes);
+ }
+
if (virStorageDefParsePerms(ctxt, &ret->backingStore.perms,
"./backingStore/permissions",
DEFAULT_VOL_PERM_MODE) < 0)
goto error;
cleanup:
+ VIR_FREE(nodes);
VIR_FREE(allocation);
VIR_FREE(capacity);
VIR_FREE(unit);
return ret;
+no_memory:
+ virReportOOMError();
error:
virStorageVolDefFree(ret);
ret = NULL;
@@ -1476,6 +1532,28 @@ virStorageVolTargetDefFormat(virStorageVolOptionsPtr options,
virBufferAdjustIndent(buf, -4);
}
+ virBufferEscapeString(buf, " %s \n", def->compat);
+
+ if (options->featureToString && def->features) {
+ int i;
+ bool b;
+ bool empty = virBitmapIsAllClear(def->features);
+
+ if (empty)
+ virBufferAddLit(buf, " \n");
+ else
+ virBufferAddLit(buf, " \n");
+
+ for (i = 0; i < VIR_STORAGE_FILE_FEATURE_LAST; i++) {
+ ignore_value(virBitmapGetBit(def->features, i, &b));
+ if (b)
+ virBufferAsprintf(buf, " <%s/>\n",
+ options->featureToString(i));
+ }
+ if (!empty)
+ virBufferAddLit(buf, " \n");
+ }
+
virBufferAsprintf(buf, " %s>\n", type);
return 0;
diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h
index 8e739ffd9e..3af59df48c 100644
--- a/src/conf/storage_conf.h
+++ b/src/conf/storage_conf.h
@@ -26,6 +26,7 @@
# include "internal.h"
# include "storage_encryption_conf.h"
+# include "virbitmap.h"
# include "virthread.h"
# include
@@ -84,9 +85,11 @@ struct _virStorageVolTarget {
virStoragePerms perms;
virStorageTimestampsPtr timestamps;
int type; /* only used by disk backend for partition type */
-
- /* only used in vol->target, not in vol->backingstore. */
+ /* The next three are currently only used in vol->target,
+ * not in vol->backingStore. */
virStorageEncryptionPtr encryption;
+ virBitmapPtr features;
+ char *compat;
};
typedef struct _virStorageVolDef virStorageVolDef;
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index b449293c11..7ac6fdc207 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1799,6 +1799,8 @@ virSocketAddrSetPort;
# util/virstoragefile.h
virStorageFileChainLookup;
+virStorageFileFeatureTypeFromString;
+virStorageFileFeatureTypeToString;
virStorageFileFormatTypeFromString;
virStorageFileFormatTypeToString;
virStorageFileFreeMetadata;
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c
index b1efa50933..3598d83876 100644
--- a/src/storage/storage_backend_fs.c
+++ b/src/storage/storage_backend_fs.c
@@ -150,6 +150,16 @@ virStorageBackendProbeTarget(virStorageVolTargetPtr target,
*/
}
+ virBitmapFree(target->features);
+ target->features = meta->features;
+ meta->features = NULL;
+
+ if (meta->compat) {
+ VIR_FREE(target->compat);
+ target->compat = meta->compat;
+ meta->compat = NULL;
+ }
+
virStorageFileFreeMetadata(meta);
return ret;
diff --git a/tests/storagevolxml2xmlin/vol-qcow2-1.1.xml b/tests/storagevolxml2xmlin/vol-qcow2-1.1.xml
new file mode 100644
index 0000000000..e8df8b3014
--- /dev/null
+++ b/tests/storagevolxml2xmlin/vol-qcow2-1.1.xml
@@ -0,0 +1,32 @@
+
+ OtherDemo.img
+ /var/lib/libvirt/images/OtherDemo.img
+
+
+ 5
+ 294912
+
+ /var/lib/libvirt/images/OtherDemo.img
+
+
+ 0644
+ 0
+ 0
+ unconfined_u:object_r:virt_image_t:s0
+
+
+
+
+
+
+
+ /var/lib/libvirt/images/BaseDemo.img
+
+
+ 0644
+ 0
+ 0
+ unconfined_u:object_r:virt_image_t:s0
+
+
+
diff --git a/tests/storagevolxml2xmlin/vol-qcow2-lazy.xml b/tests/storagevolxml2xmlin/vol-qcow2-lazy.xml
new file mode 100644
index 0000000000..336342a4f8
--- /dev/null
+++ b/tests/storagevolxml2xmlin/vol-qcow2-lazy.xml
@@ -0,0 +1,35 @@
+
+ OtherDemo.img
+ /var/lib/libvirt/images/OtherDemo.img
+
+
+ 5
+ 294912
+
+ /var/lib/libvirt/images/OtherDemo.img
+
+
+ 0644
+ 0
+ 0
+ unconfined_u:object_r:virt_image_t:s0
+
+
+
+
+ 1.1
+
+
+
+
+
+ /var/lib/libvirt/images/BaseDemo.img
+
+
+ 0644
+ 0
+ 0
+ unconfined_u:object_r:virt_image_t:s0
+
+
+
diff --git a/tests/storagevolxml2xmlout/vol-qcow2-1.1.xml b/tests/storagevolxml2xmlout/vol-qcow2-1.1.xml
new file mode 100644
index 0000000000..454ac11299
--- /dev/null
+++ b/tests/storagevolxml2xmlout/vol-qcow2-1.1.xml
@@ -0,0 +1,33 @@
+
+ OtherDemo.img
+ (null)
+
+
+ 5368709120
+ 294912
+
+ /var/lib/libvirt/images/OtherDemo.img
+
+
+ 0644
+ 0
+ 0
+ unconfined_u:object_r:virt_image_t:s0
+
+
+
+
+ 1.1
+
+
+
+ /var/lib/libvirt/images/BaseDemo.img
+
+
+ 0644
+ 0
+ 0
+ unconfined_u:object_r:virt_image_t:s0
+
+
+
diff --git a/tests/storagevolxml2xmlout/vol-qcow2-lazy.xml b/tests/storagevolxml2xmlout/vol-qcow2-lazy.xml
new file mode 100644
index 0000000000..4e30edef98
--- /dev/null
+++ b/tests/storagevolxml2xmlout/vol-qcow2-lazy.xml
@@ -0,0 +1,35 @@
+
+ OtherDemo.img
+ (null)
+
+
+ 5368709120
+ 294912
+
+ /var/lib/libvirt/images/OtherDemo.img
+
+
+ 0644
+ 0
+ 0
+ unconfined_u:object_r:virt_image_t:s0
+
+
+
+
+ 1.1
+
+
+
+
+
+ /var/lib/libvirt/images/BaseDemo.img
+
+
+ 0644
+ 0
+ 0
+ unconfined_u:object_r:virt_image_t:s0
+
+
+
diff --git a/tests/storagevolxml2xmltest.c b/tests/storagevolxml2xmltest.c
index 07c79c1cdd..e87b0163ba 100644
--- a/tests/storagevolxml2xmltest.c
+++ b/tests/storagevolxml2xmltest.c
@@ -110,6 +110,8 @@ mymain(void)
DO_TEST("pool-dir", "vol-file");
DO_TEST("pool-dir", "vol-file-backing");
DO_TEST("pool-dir", "vol-qcow2");
+ DO_TEST("pool-dir", "vol-qcow2-1.1");
+ DO_TEST("pool-dir", "vol-qcow2-lazy");
DO_TEST("pool-disk", "vol-partition");
DO_TEST("pool-logical", "vol-logical");
DO_TEST("pool-logical", "vol-logical-backing");