mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 13:45:38 +00:00
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:
parent
f12b283897
commit
bb8ccb050d
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
10
tests/storagepoolxml2xmlin/pool-dir-cow.xml
Normal file
10
tests/storagepoolxml2xmlin/pool-dir-cow.xml
Normal 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>
|
15
tests/storagepoolxml2xmlout/pool-dir-cow.xml
Normal file
15
tests/storagepoolxml2xmlout/pool-dir-cow.xml
Normal 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>
|
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user