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. Since 0.4.1
+
+
+
+ Some pools support optional features:
+
+
+
+...
+<features>
+ <cow state='no'>
+</features>
+...
+
+
+ Valid features are:
+
+
+ cow
+ 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 btrfs
filesystem. If not set then libvirt
+ will attempt to disable COW on any btrfs filesystems.
+ Since 6.6.0 .
+
+
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 @@
+
@@ -49,6 +50,7 @@
+
@@ -64,6 +66,7 @@
+
@@ -79,6 +82,7 @@
+
@@ -91,6 +95,7 @@
+
@@ -103,6 +108,7 @@
+
@@ -117,6 +123,7 @@
+
@@ -128,6 +135,7 @@
+
@@ -140,6 +148,7 @@
+
@@ -154,6 +163,7 @@
+
@@ -169,6 +179,7 @@
+
@@ -180,6 +191,7 @@
+
@@ -191,6 +203,7 @@
+
@@ -205,6 +218,7 @@
+
@@ -277,6 +291,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c
index 65d9b33049..fac5ff7b86 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 == VIR_TRISTATE_BOOL_ABSENT)
+ return;
+
+ virBufferAddLit(buf, "\n");
+ virBufferAdjustIndent(buf, 2);
+ if (def->features.cow != VIR_TRISTATE_BOOL_ABSENT)
+ virBufferAsprintf(buf, " \n",
+ virTristateBoolTypeToString(def->features.cow));
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, " \n");
+}
+
+
static int
virStoragePoolDefFormatBuf(virBufferPtr buf,
virStoragePoolDefPtr def)
@@ -1166,6 +1213,8 @@ virStoragePoolDefFormatBuf(virBufferPtr buf,
virBufferAsprintf(buf, "%llu \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 @@
+
+ vms
+ 751f8e7e-d2e9-463d-8ffe-d38f5e13a19b
+
+
+
+
+ /i/cant/believe/its/not/btrfs
+
+
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 @@
+
+ vms
+ 751f8e7e-d2e9-463d-8ffe-d38f5e13a19b
+ 0
+ 0
+ 0
+
+
+
+
+
+
+ /i/cant/believe/its/not/btrfs
+
+
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");