conf: add control over COW for storage pool directories

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.

Reviewed-by: Neal Gompa <ngompa13@gmail.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrangé 2020-07-17 19:32:18 +01:00
parent f12b283897
commit bb8ccb050d
8 changed files with 139 additions and 1 deletions

View File

@ -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>
...
&lt;features&gt;
&lt;cow state='no'&gt;
&lt;/features&gt;
...</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>

View File

@ -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>

View File

@ -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, "<features>\n");
virBufferAdjustIndent(buf, 2);
if (def->features.cow != VIR_TRISTATE_BOOL_ABSENT)
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;

View File

@ -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;

View File

@ -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;

View File

@ -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>

View File

@ -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>

View File

@ -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");