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: + +

Backing store elements

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, " \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 + + + + + + + + + /var/lib/libvirt/images/BaseDemo.img + + + 0644 + 0 + 0 + + + + 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 + + + + + + 1.1 + + + + + + /var/lib/libvirt/images/BaseDemo.img + + + 0644 + 0 + 0 + + + + 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 + + + + + + 1.1 + + + + /var/lib/libvirt/images/BaseDemo.img + + + 0644 + 0 + 0 + + + + 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 + + + + + + 1.1 + + + + + + /var/lib/libvirt/images/BaseDemo.img + + + 0644 + 0 + 0 + + + + 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");