The storage pool code now attempts to disable COW by default on btrfs, but management applications may wish to override this behaviour. Thus we introduce a concept of storage pool features: <features> <cow state='yes|no'/> </features> If the <cow> feature policy is set, it will be enforced. It will always return an hard error if COW cannot be explicitly set or unset. Signed-off-by: Daniel P. Berrangé <berrange@xxxxxxxxxx> --- docs/formatstorage.html.in | 25 ++++++++++ docs/schemas/storagepool.rng | 30 ++++++++++++ src/conf/storage_conf.c | 49 ++++++++++++++++++++ src/conf/storage_conf.h | 8 ++++ src/storage/storage_util.c | 2 +- tests/storagepoolxml2xmlin/pool-dir-cow.xml | 10 ++++ tests/storagepoolxml2xmlout/pool-dir-cow.xml | 15 ++++++ tests/storagepoolxml2xmltest.c | 1 + 8 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 tests/storagepoolxml2xmlin/pool-dir-cow.xml create mode 100644 tests/storagepoolxml2xmlout/pool-dir-cow.xml diff --git a/docs/formatstorage.html.in b/docs/formatstorage.html.in index 2a7604d136..7493714c5c 100644 --- a/docs/formatstorage.html.in +++ b/docs/formatstorage.html.in @@ -67,6 +67,31 @@ pool. <span class="since">Since 0.4.1</span></dd> </dl> + <h3><a id="StoragePoolFeatures">Features</a></h3> + + <p> + Some pools support optional features: + </p> + + <pre> +... +<features> + <cow state='no'> +</features> +...</pre> + + <p> + Valid features are: + </p> + <ul> + <dd><code>cow</code></dd> + <dt>Controls whether the filesystem performs copy-on-write (COW) for + images in the pool. This may only be set for directory / filesystem + pools on the <code>btrfs</code> filesystem. If not set then libvirt + will attempt to disable COW on any btrfs filesystems. + <span class="since">Since 6.6.0</span>.</dt> + </ul> + <h3><a id="StoragePoolSource">Source elements</a></h3> <p> diff --git a/docs/schemas/storagepool.rng b/docs/schemas/storagepool.rng index ff0d3c836c..f5cf6769c8 100644 --- a/docs/schemas/storagepool.rng +++ b/docs/schemas/storagepool.rng @@ -37,6 +37,7 @@ <interleave> <ref name='commonmetadata'/> <ref name='sizing'/> + <ref name='features'/> <ref name='sourcedir'/> <ref name='target'/> </interleave> @@ -49,6 +50,7 @@ <interleave> <ref name='commonmetadata'/> <ref name='sizing'/> + <ref name='features'/> <ref name='sourcefs'/> <ref name='target'/> </interleave> @@ -64,6 +66,7 @@ <interleave> <ref name='commonmetadata'/> <ref name='sizing'/> + <ref name='features'/> <ref name='sourcenetfs'/> <ref name='target'/> </interleave> @@ -79,6 +82,7 @@ <interleave> <ref name='commonMetadataNameOptional'/> <ref name='sizing'/> + <ref name='features'/> <ref name='sourcelogical'/> <ref name='targetlogical'/> </interleave> @@ -91,6 +95,7 @@ <interleave> <ref name='commonmetadata'/> <ref name='sizing'/> + <ref name='features'/> <ref name='sourcedisk'/> <ref name='target'/> </interleave> @@ -103,6 +108,7 @@ <interleave> <ref name='commonmetadata'/> <ref name='sizing'/> + <ref name='features'/> <ref name='sourceiscsi'/> <ref name='target'/> </interleave> @@ -117,6 +123,7 @@ <optional> <ref name='sizing'/> </optional> + <ref name='features'/> <ref name='sourceiscsidirect'/> </interleave> </define> @@ -128,6 +135,7 @@ <interleave> <ref name='commonmetadata'/> <ref name='sizing'/> + <ref name='features'/> <ref name='sourcescsi'/> <ref name='target'/> </interleave> @@ -140,6 +148,7 @@ <interleave> <ref name='commonmetadata'/> <ref name='sizing'/> + <ref name='features'/> <optional> <ref name='sourcempath'/> </optional> @@ -154,6 +163,7 @@ <interleave> <ref name='commonMetadataNameOptional'/> <ref name='sizing'/> + <ref name='features'/> <ref name='sourcerbd'/> <ref name='refresh'/> </interleave> @@ -169,6 +179,7 @@ <interleave> <ref name='commonMetadataNameOptional'/> <ref name='sizing'/> + <ref name='features'/> <ref name='sourcesheepdog'/> </interleave> </define> @@ -180,6 +191,7 @@ <interleave> <ref name='commonMetadataNameOptional'/> <ref name='sizing'/> + <ref name='features'/> <ref name='sourcegluster'/> </interleave> </define> @@ -191,6 +203,7 @@ <interleave> <ref name='commonMetadataNameOptional'/> <ref name='sizing'/> + <ref name='features'/> <ref name='sourcezfs'/> <optional> <ref name='target'/> @@ -205,6 +218,7 @@ <interleave> <ref name='commonMetadataNameOptional'/> <ref name='sizing'/> + <ref name='features'/> <ref name='sourcevstorage'/> <ref name='target'/> </interleave> @@ -277,6 +291,22 @@ </interleave> </define> + <define name='features'> + <optional> + <element name='features'> + <interleave> + <optional> + <element name='cow'> + <attribute name="state"> + <ref name='virYesNo'/> + </attribute> + </element> + </optional> + </interleave> + </element> + </optional> + </define> + <define name='target'> <element name='target'> <interleave> diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index 65d9b33049..4e63865b39 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -839,6 +839,33 @@ virStoragePoolDefRefreshFormat(virBufferPtr buf, } +static int +virStoragePoolDefParseFeatures(virStoragePoolDefPtr def, + xmlXPathContextPtr ctxt) +{ + g_autofree char *cow = virXPathString("string(./features/cow/@state)", ctxt); + + if (cow) { + int val; + if (def->type != VIR_STORAGE_POOL_FS && + def->type != VIR_STORAGE_POOL_DIR) { + virReportError(VIR_ERR_NO_SUPPORT, "%s", + _("cow feature may only be used for 'fs' and 'dir' pools")); + return -1; + } + if ((val = virTristateBoolTypeFromString(cow)) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("invalid storage pool cow feature state '%s'"), + cow); + return -1; + } + def->features.cow = val; + } + + return 0; +} + + virStoragePoolDefPtr virStoragePoolDefParseXML(xmlXPathContextPtr ctxt) { @@ -910,6 +937,9 @@ virStoragePoolDefParseXML(xmlXPathContextPtr ctxt) } } + if (virStoragePoolDefParseFeatures(def, ctxt) < 0) + return NULL; + if (options->flags & VIR_STORAGE_POOL_SOURCE_HOST) { if (!def->source.nhost) { virReportError(VIR_ERR_XML_ERROR, "%s", @@ -1131,6 +1161,23 @@ virStoragePoolSourceFormat(virBufferPtr buf, } +static void +virStoragePoolDefFormatFeatures(virBufferPtr buf, + virStoragePoolDefPtr def) +{ + if (!def->features.cow) + return; + + virBufferAddLit(buf, "<features>\n"); + virBufferAdjustIndent(buf, 2); + if (def->features.cow) + virBufferAsprintf(buf, "<cow state='%s'/>\n", + virTristateBoolTypeToString(def->features.cow)); + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</features>\n"); +} + + static int virStoragePoolDefFormatBuf(virBufferPtr buf, virStoragePoolDefPtr def) @@ -1166,6 +1213,8 @@ virStoragePoolDefFormatBuf(virBufferPtr buf, virBufferAsprintf(buf, "<available unit='bytes'>%llu</available>\n", def->available); + virStoragePoolDefFormatFeatures(buf, def); + if (virStoragePoolSourceFormat(buf, options, &def->source) < 0) return -1; diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h index daa21a127b..ffd406e093 100644 --- a/src/conf/storage_conf.h +++ b/src/conf/storage_conf.h @@ -180,6 +180,13 @@ struct _virStoragePoolSourceDevice { } geometry; }; +typedef struct _virStoragePoolFeatures virStoragePoolFeatures; +typedef virStoragePoolFeatures *virStoragePoolFeaturesPtr; +struct _virStoragePoolFeatures { + virTristateBool cow; +}; + + typedef struct _virStoragePoolSource virStoragePoolSource; typedef virStoragePoolSource *virStoragePoolSourcePtr; struct _virStoragePoolSource { @@ -256,6 +263,7 @@ struct _virStoragePoolDef { unsigned long long capacity; /* bytes */ unsigned long long available; /* bytes */ + virStoragePoolFeatures features; virStoragePoolSource source; virStoragePoolTarget target; diff --git a/src/storage/storage_util.c b/src/storage/storage_util.c index 80b49bd1cf..f7c09e3375 100644 --- a/src/storage/storage_util.c +++ b/src/storage/storage_util.c @@ -2755,7 +2755,7 @@ virStorageBackendBuildLocal(virStoragePoolObjPtr pool) return -1; if (virFileSetCOW(def->target.path, - VIR_TRISTATE_BOOL_ABSENT) < 0) + def->features.cow) < 0) return -1; return 0; diff --git a/tests/storagepoolxml2xmlin/pool-dir-cow.xml b/tests/storagepoolxml2xmlin/pool-dir-cow.xml new file mode 100644 index 0000000000..2217f2b8e3 --- /dev/null +++ b/tests/storagepoolxml2xmlin/pool-dir-cow.xml @@ -0,0 +1,10 @@ +<pool type='dir'> + <name>vms</name> + <uuid>751f8e7e-d2e9-463d-8ffe-d38f5e13a19b</uuid> + <features> + <cow state="yes"/> + </features> + <target> + <path>/i/cant/believe/its/not/btrfs</path> + </target> +</pool> diff --git a/tests/storagepoolxml2xmlout/pool-dir-cow.xml b/tests/storagepoolxml2xmlout/pool-dir-cow.xml new file mode 100644 index 0000000000..2f3fe1f909 --- /dev/null +++ b/tests/storagepoolxml2xmlout/pool-dir-cow.xml @@ -0,0 +1,15 @@ +<pool type='dir'> + <name>vms</name> + <uuid>751f8e7e-d2e9-463d-8ffe-d38f5e13a19b</uuid> + <capacity unit='bytes'>0</capacity> + <allocation unit='bytes'>0</allocation> + <available unit='bytes'>0</available> + <features> + <cow state='yes'/> + </features> + <source> + </source> + <target> + <path>/i/cant/believe/its/not/btrfs</path> + </target> +</pool> diff --git a/tests/storagepoolxml2xmltest.c b/tests/storagepoolxml2xmltest.c index 382a7c659f..f21f20357a 100644 --- a/tests/storagepoolxml2xmltest.c +++ b/tests/storagepoolxml2xmltest.c @@ -62,6 +62,7 @@ mymain(void) DO_TEST("pool-dir"); DO_TEST("pool-dir-naming"); + DO_TEST("pool-dir-cow"); DO_TEST("pool-fs"); DO_TEST("pool-logical"); DO_TEST("pool-logical-nopath"); -- 2.26.2