mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 17:34:18 +03:00
snapshot: Add support for specifying snapshot disk backing type
Add support for specifying various types when doing snapshots. This will later allow to do snapshots on network backed volumes. Disks of type 'volume' are not supported by snapshots (yet). Also amend the test suite to check parsing of the various new disk types that can now be specified.
This commit is contained in:
parent
37564b471d
commit
7076b4b72c
@ -170,6 +170,21 @@
|
|||||||
snapshots, the original file name becomes the read-only
|
snapshots, the original file name becomes the read-only
|
||||||
snapshot, and the new file name contains the read-write
|
snapshot, and the new file name contains the read-write
|
||||||
delta of all disk changes since the snapshot.
|
delta of all disk changes since the snapshot.
|
||||||
|
|
||||||
|
<span class="since">Since 1.2.2</span> the <code>disk</code> element
|
||||||
|
supports an optional attribute <code>type</code> if the
|
||||||
|
<code>snapshot</code> attribute is set to <code>external</code>.
|
||||||
|
This attribute specifies the snapshot target storage type and allows
|
||||||
|
to overwrite the default <code>file</code> type. The <code>type</code>
|
||||||
|
attribute along with the format of the <code>source</code>
|
||||||
|
sub-element is identical to the <code>source</code> element used in
|
||||||
|
domain disk definitions. See the
|
||||||
|
<a href="formatdomain.html#elementsDisks">disk devices</a> section
|
||||||
|
documentation for further information.
|
||||||
|
|
||||||
|
Libvirt currently supports the <code>type</code> element in the qemu
|
||||||
|
driver and supported values are <code>file</code> and
|
||||||
|
<code>block</code> <span class="since">(since 1.2.2)</span>.
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</dd>
|
</dd>
|
||||||
|
@ -123,19 +123,57 @@
|
|||||||
<value>external</value>
|
<value>external</value>
|
||||||
</attribute>
|
</attribute>
|
||||||
</optional>
|
</optional>
|
||||||
<interleave>
|
<choice>
|
||||||
<ref name='disksnapshotdriver'/>
|
<group>
|
||||||
<optional>
|
<optional>
|
||||||
<element name='source'>
|
<attribute name='type'>
|
||||||
|
<value>file</value>
|
||||||
|
</attribute>
|
||||||
|
</optional>
|
||||||
|
<interleave>
|
||||||
<optional>
|
<optional>
|
||||||
<attribute name='file'>
|
<element name='source'>
|
||||||
<ref name='absFilePath'/>
|
<optional>
|
||||||
</attribute>
|
<attribute name='file'>
|
||||||
|
<ref name='absFilePath'/>
|
||||||
|
</attribute>
|
||||||
|
</optional>
|
||||||
|
<empty/>
|
||||||
|
</element>
|
||||||
</optional>
|
</optional>
|
||||||
<empty/>
|
<ref name='disksnapshotdriver'/>
|
||||||
</element>
|
</interleave>
|
||||||
</optional>
|
</group>
|
||||||
</interleave>
|
<group>
|
||||||
|
<attribute name='type'>
|
||||||
|
<value>block</value>
|
||||||
|
</attribute>
|
||||||
|
<interleave>
|
||||||
|
<optional>
|
||||||
|
<element name="source">
|
||||||
|
<attribute name="dev">
|
||||||
|
<ref name="absFilePath"/>
|
||||||
|
</attribute>
|
||||||
|
<empty/>
|
||||||
|
</element>
|
||||||
|
</optional>
|
||||||
|
<ref name='disksnapshotdriver'/>
|
||||||
|
</interleave>
|
||||||
|
</group>
|
||||||
|
<group>
|
||||||
|
<attribute name="type">
|
||||||
|
<value>network</value>
|
||||||
|
</attribute>
|
||||||
|
<interleave>
|
||||||
|
<optional>
|
||||||
|
<element name="source">
|
||||||
|
<ref name='diskSourceNetwork'/>
|
||||||
|
</element>
|
||||||
|
</optional>
|
||||||
|
<ref name='disksnapshotdriver'/>
|
||||||
|
</interleave>
|
||||||
|
</group>
|
||||||
|
</choice>
|
||||||
</group>
|
</group>
|
||||||
</choice>
|
</choice>
|
||||||
</element>
|
</element>
|
||||||
|
@ -108,6 +108,7 @@ virDomainSnapshotDiskDefParseXML(xmlNodePtr node,
|
|||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
char *snapshot = NULL;
|
char *snapshot = NULL;
|
||||||
|
char *type = NULL;
|
||||||
xmlNodePtr cur;
|
xmlNodePtr cur;
|
||||||
|
|
||||||
def->name = virXMLPropString(node, "name");
|
def->name = virXMLPropString(node, "name");
|
||||||
@ -128,7 +129,17 @@ virDomainSnapshotDiskDefParseXML(xmlNodePtr node,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def->type = -1;
|
if ((type = virXMLPropString(node, "type"))) {
|
||||||
|
if ((def->type = virDomainDiskTypeFromString(type)) < 0 ||
|
||||||
|
def->type == VIR_DOMAIN_DISK_TYPE_VOLUME ||
|
||||||
|
def->type == VIR_DOMAIN_DISK_TYPE_DIR) {
|
||||||
|
virReportError(VIR_ERR_XML_ERROR,
|
||||||
|
_("unknown disk snapshot type '%s'"), type);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
def->type = VIR_DOMAIN_DISK_TYPE_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
for (cur = node->children; cur; cur = cur->next) {
|
for (cur = node->children; cur; cur = cur->next) {
|
||||||
if (cur->type != XML_ELEMENT_NODE)
|
if (cur->type != XML_ELEMENT_NODE)
|
||||||
@ -137,17 +148,12 @@ virDomainSnapshotDiskDefParseXML(xmlNodePtr node,
|
|||||||
if (!def->file &&
|
if (!def->file &&
|
||||||
xmlStrEqual(cur->name, BAD_CAST "source")) {
|
xmlStrEqual(cur->name, BAD_CAST "source")) {
|
||||||
|
|
||||||
int backingtype = def->type;
|
|
||||||
|
|
||||||
if (backingtype < 0)
|
|
||||||
backingtype = VIR_DOMAIN_DISK_TYPE_FILE;
|
|
||||||
|
|
||||||
if (virDomainDiskSourceDefParse(cur,
|
if (virDomainDiskSourceDefParse(cur,
|
||||||
backingtype,
|
def->type,
|
||||||
&def->file,
|
&def->file,
|
||||||
NULL,
|
&def->protocol,
|
||||||
NULL,
|
&def->nhosts,
|
||||||
NULL,
|
&def->hosts,
|
||||||
NULL) < 0)
|
NULL) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
@ -174,6 +180,7 @@ virDomainSnapshotDiskDefParseXML(xmlNodePtr node,
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
cleanup:
|
cleanup:
|
||||||
VIR_FREE(snapshot);
|
VIR_FREE(snapshot);
|
||||||
|
VIR_FREE(type);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
virDomainSnapshotDiskDefClear(def);
|
virDomainSnapshotDiskDefClear(def);
|
||||||
return ret;
|
return ret;
|
||||||
@ -532,7 +539,7 @@ virDomainSnapshotAlignDisks(virDomainSnapshotDefPtr def,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
disk->index = i;
|
disk->index = i;
|
||||||
disk->snapshot = def->dom->disks[i]->snapshot;
|
disk->snapshot = def->dom->disks[i]->snapshot;
|
||||||
disk->type = -1;
|
disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
|
||||||
if (!disk->snapshot)
|
if (!disk->snapshot)
|
||||||
disk->snapshot = default_snapshot;
|
disk->snapshot = default_snapshot;
|
||||||
}
|
}
|
||||||
@ -550,8 +557,7 @@ virDomainSnapshotAlignDisks(virDomainSnapshotDefPtr def,
|
|||||||
const char *tmp;
|
const char *tmp;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
|
|
||||||
if (disk->type != VIR_DOMAIN_DISK_TYPE_FILE &&
|
if (disk->type != VIR_DOMAIN_DISK_TYPE_FILE) {
|
||||||
disk->type != -1) {
|
|
||||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||||
_("cannot generate external snapshot name "
|
_("cannot generate external snapshot name "
|
||||||
"for disk '%s' on a '%s' device"),
|
"for disk '%s' on a '%s' device"),
|
||||||
@ -614,15 +620,12 @@ virDomainSnapshotDiskDefFormat(virBufferPtr buf,
|
|||||||
virBufferAsprintf(buf, " snapshot='%s'",
|
virBufferAsprintf(buf, " snapshot='%s'",
|
||||||
virDomainSnapshotLocationTypeToString(disk->snapshot));
|
virDomainSnapshotLocationTypeToString(disk->snapshot));
|
||||||
|
|
||||||
if (type < 0)
|
|
||||||
type = VIR_DOMAIN_DISK_TYPE_FILE;
|
|
||||||
|
|
||||||
if (!disk->file && disk->format == 0) {
|
if (!disk->file && disk->format == 0) {
|
||||||
virBufferAddLit(buf, "/>\n");
|
virBufferAddLit(buf, "/>\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
virBufferAddLit(buf, ">\n");
|
virBufferAsprintf(buf, " type='%s'>\n", virDomainDiskTypeToString(type));
|
||||||
|
|
||||||
if (disk->format > 0)
|
if (disk->format > 0)
|
||||||
virBufferEscapeString(buf, " <driver type='%s'/>\n",
|
virBufferEscapeString(buf, " <driver type='%s'/>\n",
|
||||||
@ -630,7 +633,11 @@ virDomainSnapshotDiskDefFormat(virBufferPtr buf,
|
|||||||
virDomainDiskSourceDefFormatInternal(buf,
|
virDomainDiskSourceDefFormatInternal(buf,
|
||||||
type,
|
type,
|
||||||
disk->file,
|
disk->file,
|
||||||
0, 0, 0, NULL, 0, NULL, NULL, 0);
|
0,
|
||||||
|
disk->protocol,
|
||||||
|
disk->nhosts,
|
||||||
|
disk->hosts,
|
||||||
|
0, NULL, NULL, 0);
|
||||||
|
|
||||||
virBufferAddLit(buf, " </disk>\n");
|
virBufferAddLit(buf, " </disk>\n");
|
||||||
}
|
}
|
||||||
|
@ -48,12 +48,15 @@ enum virDomainSnapshotState {
|
|||||||
typedef struct _virDomainSnapshotDiskDef virDomainSnapshotDiskDef;
|
typedef struct _virDomainSnapshotDiskDef virDomainSnapshotDiskDef;
|
||||||
typedef virDomainSnapshotDiskDef *virDomainSnapshotDiskDefPtr;
|
typedef virDomainSnapshotDiskDef *virDomainSnapshotDiskDefPtr;
|
||||||
struct _virDomainSnapshotDiskDef {
|
struct _virDomainSnapshotDiskDef {
|
||||||
char *name; /* name matching the <target dev='...' of the domain */
|
char *name; /* name matching the <target dev='...' of the domain */
|
||||||
int index; /* index within snapshot->dom->disks that matches name */
|
int index; /* index within snapshot->dom->disks that matches name */
|
||||||
int snapshot; /* enum virDomainSnapshotLocation */
|
int snapshot; /* enum virDomainSnapshotLocation */
|
||||||
int type; /* enum virDomainDiskType */
|
int type; /* enum virDomainDiskType */
|
||||||
char *file; /* new source file when snapshot is external */
|
char *file; /* new source file when snapshot is external */
|
||||||
int format; /* enum virStorageFileFormat */
|
int format; /* enum virStorageFileFormat */
|
||||||
|
int protocol; /* network source protocol */
|
||||||
|
size_t nhosts; /* network source hosts count */
|
||||||
|
virDomainDiskHostDefPtr hosts; /* network source hosts */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Stores the complete snapshot metadata */
|
/* Stores the complete snapshot metadata */
|
||||||
|
@ -1473,9 +1473,6 @@ cleanup:
|
|||||||
int
|
int
|
||||||
qemuSnapshotDiskGetActualType(virDomainSnapshotDiskDefPtr def)
|
qemuSnapshotDiskGetActualType(virDomainSnapshotDiskDefPtr def)
|
||||||
{
|
{
|
||||||
if (def->type == -1)
|
|
||||||
return VIR_DOMAIN_DISK_TYPE_FILE;
|
|
||||||
|
|
||||||
return def->type;
|
return def->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12623,33 +12623,47 @@ qemuDomainSnapshotCreateSingleDiskActive(virQEMUDriverPtr driver,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (virAsprintf(&device, "drive-%s", disk->info.alias) < 0 ||
|
if (virAsprintf(&device, "drive-%s", disk->info.alias) < 0 ||
|
||||||
VIR_STRDUP(source, snap->file) < 0 ||
|
|
||||||
(persistDisk && VIR_STRDUP(persistSource, source) < 0))
|
(persistDisk && VIR_STRDUP(persistSource, source) < 0))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
/* create the stub file and set selinux labels; manipulate disk in
|
|
||||||
* place, in a way that can be reverted on failure. */
|
|
||||||
if (!reuse) {
|
|
||||||
fd = qemuOpenFile(driver, vm, source, O_WRONLY | O_TRUNC | O_CREAT,
|
|
||||||
&need_unlink, NULL);
|
|
||||||
if (fd < 0)
|
|
||||||
goto cleanup;
|
|
||||||
VIR_FORCE_CLOSE(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* XXX Here, we know we are about to alter disk->backingChain if
|
/* XXX Here, we know we are about to alter disk->backingChain if
|
||||||
* successful, so we nuke the existing chain so that future
|
* successful, so we nuke the existing chain so that future commands will
|
||||||
* commands will recompute it. Better would be storing the chain
|
* recompute it. Better would be storing the chain ourselves rather than
|
||||||
* ourselves rather than reprobing, but this requires modifying
|
* reprobing, but this requires modifying domain_conf and our XML to fully
|
||||||
* domain_conf and our XML to fully track the chain across
|
* track the chain across libvirtd restarts. */
|
||||||
* libvirtd restarts. */
|
|
||||||
virStorageFileFreeMetadata(disk->backingChain);
|
virStorageFileFreeMetadata(disk->backingChain);
|
||||||
disk->backingChain = NULL;
|
disk->backingChain = NULL;
|
||||||
|
|
||||||
if (qemuDomainPrepareDiskChainElement(driver, vm, disk, source,
|
switch (snap->type) {
|
||||||
VIR_DISK_CHAIN_READ_WRITE) < 0) {
|
case VIR_DOMAIN_DISK_TYPE_BLOCK:
|
||||||
qemuDomainPrepareDiskChainElement(driver, vm, disk, source,
|
reuse = true;
|
||||||
VIR_DISK_CHAIN_NO_ACCESS);
|
/* fallthrough */
|
||||||
|
case VIR_DOMAIN_DISK_TYPE_FILE:
|
||||||
|
if (VIR_STRDUP(source, snap->file) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
/* create the stub file and set selinux labels; manipulate disk in
|
||||||
|
* place, in a way that can be reverted on failure. */
|
||||||
|
if (!reuse) {
|
||||||
|
fd = qemuOpenFile(driver, vm, source, O_WRONLY | O_TRUNC | O_CREAT,
|
||||||
|
&need_unlink, NULL);
|
||||||
|
if (fd < 0)
|
||||||
|
goto cleanup;
|
||||||
|
VIR_FORCE_CLOSE(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qemuDomainPrepareDiskChainElement(driver, vm, disk, source,
|
||||||
|
VIR_DISK_CHAIN_READ_WRITE) < 0) {
|
||||||
|
qemuDomainPrepareDiskChainElement(driver, vm, disk, source,
|
||||||
|
VIR_DISK_CHAIN_NO_ACCESS);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
|
||||||
|
_("snapshots are not supported on '%s' volumes"),
|
||||||
|
virDomainDiskTypeToString(snap->type));
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12685,11 +12699,13 @@ qemuDomainSnapshotCreateSingleDiskActive(virQEMUDriverPtr driver,
|
|||||||
disk->src = source;
|
disk->src = source;
|
||||||
source = NULL;
|
source = NULL;
|
||||||
disk->format = format;
|
disk->format = format;
|
||||||
|
disk->type = snap->type;
|
||||||
if (persistDisk) {
|
if (persistDisk) {
|
||||||
VIR_FREE(persistDisk->src);
|
VIR_FREE(persistDisk->src);
|
||||||
persistDisk->src = persistSource;
|
persistDisk->src = persistSource;
|
||||||
persistSource = NULL;
|
persistSource = NULL;
|
||||||
persistDisk->format = format;
|
persistDisk->format = format;
|
||||||
|
persistDisk->type = snap->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
@ -12731,11 +12747,13 @@ qemuDomainSnapshotUndoSingleDiskActive(virQEMUDriverPtr driver,
|
|||||||
disk->src = source;
|
disk->src = source;
|
||||||
source = NULL;
|
source = NULL;
|
||||||
disk->format = origdisk->format;
|
disk->format = origdisk->format;
|
||||||
|
disk->type = origdisk->type;
|
||||||
if (persistDisk) {
|
if (persistDisk) {
|
||||||
VIR_FREE(persistDisk->src);
|
VIR_FREE(persistDisk->src);
|
||||||
persistDisk->src = persistSource;
|
persistDisk->src = persistSource;
|
||||||
persistSource = NULL;
|
persistSource = NULL;
|
||||||
persistDisk->format = origdisk->format;
|
persistDisk->format = origdisk->format;
|
||||||
|
persistDisk->type = origdisk->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
@ -12,5 +12,23 @@
|
|||||||
<disk name='hde' snapshot='external'>
|
<disk name='hde' snapshot='external'>
|
||||||
<source file='/path/to/new'/>
|
<source file='/path/to/new'/>
|
||||||
</disk>
|
</disk>
|
||||||
|
<disk name='hde' snapshot='external' type='file'>
|
||||||
|
<source file='/path/to/new2'/>
|
||||||
|
</disk>
|
||||||
|
<disk name='hdf' snapshot='external' type='block'>
|
||||||
|
<source dev='/path/to/new3'/>
|
||||||
|
</disk>
|
||||||
|
<disk name='hdg' snapshot='external' type='network'>
|
||||||
|
<source protocol='gluster' name='volume/path'>
|
||||||
|
<host name='host' port='1234'/>
|
||||||
|
</source>
|
||||||
|
</disk>
|
||||||
|
<disk name='hdh' snapshot='external' type='network'>
|
||||||
|
<source protocol='rbd' name='name'>
|
||||||
|
<host name='host' port='1234'/>
|
||||||
|
<host name='host2' port='1234' transport='rdma'/>
|
||||||
|
<host name='host3' port='1234'/>
|
||||||
|
</source>
|
||||||
|
</disk>
|
||||||
</disks>
|
</disks>
|
||||||
</domainsnapshot>
|
</domainsnapshot>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<name>asdf</name>
|
<name>asdf</name>
|
||||||
<description>adsf</description>
|
<description>adsf</description>
|
||||||
<disks>
|
<disks>
|
||||||
<disk name='vda' snapshot='external'>
|
<disk name='vda' snapshot='external' type='file'>
|
||||||
<source file='/tmp/foo'/>
|
<source file='/tmp/foo'/>
|
||||||
</disk>
|
</disk>
|
||||||
</disks>
|
</disks>
|
||||||
|
@ -5,11 +5,29 @@
|
|||||||
<disk name='/dev/HostVG/QEMUGuest1'/>
|
<disk name='/dev/HostVG/QEMUGuest1'/>
|
||||||
<disk name='hdb' snapshot='no'/>
|
<disk name='hdb' snapshot='no'/>
|
||||||
<disk name='hdc' snapshot='internal'/>
|
<disk name='hdc' snapshot='internal'/>
|
||||||
<disk name='hdd' snapshot='external'>
|
<disk name='hdd' snapshot='external' type='file'>
|
||||||
<driver type='qed'/>
|
<driver type='qed'/>
|
||||||
</disk>
|
</disk>
|
||||||
<disk name='hde' snapshot='external'>
|
<disk name='hde' snapshot='external' type='file'>
|
||||||
<source file='/path/to/new'/>
|
<source file='/path/to/new'/>
|
||||||
</disk>
|
</disk>
|
||||||
|
<disk name='hde' snapshot='external' type='file'>
|
||||||
|
<source file='/path/to/new2'/>
|
||||||
|
</disk>
|
||||||
|
<disk name='hdf' snapshot='external' type='block'>
|
||||||
|
<source dev='/path/to/new3'/>
|
||||||
|
</disk>
|
||||||
|
<disk name='hdg' snapshot='external' type='network'>
|
||||||
|
<source protocol='gluster' name='volume/path'>
|
||||||
|
<host name='host' port='1234'/>
|
||||||
|
</source>
|
||||||
|
</disk>
|
||||||
|
<disk name='hdh' snapshot='external' type='network'>
|
||||||
|
<source protocol='rbd' name='name'>
|
||||||
|
<host name='host' port='1234'/>
|
||||||
|
<host name='host2' port='1234' transport='rdma'/>
|
||||||
|
<host name='host3' port='1234'/>
|
||||||
|
</source>
|
||||||
|
</disk>
|
||||||
</disks>
|
</disks>
|
||||||
</domainsnapshot>
|
</domainsnapshot>
|
||||||
|
@ -11,15 +11,15 @@
|
|||||||
<disk name='hda' snapshot='no'/>
|
<disk name='hda' snapshot='no'/>
|
||||||
<disk name='hdb' snapshot='no'/>
|
<disk name='hdb' snapshot='no'/>
|
||||||
<disk name='hdc' snapshot='internal'/>
|
<disk name='hdc' snapshot='internal'/>
|
||||||
<disk name='hdd' snapshot='external'>
|
<disk name='hdd' snapshot='external' type='file'>
|
||||||
<driver type='qed'/>
|
<driver type='qed'/>
|
||||||
<source file='/path/to/generated4'/>
|
<source file='/path/to/generated4'/>
|
||||||
</disk>
|
</disk>
|
||||||
<disk name='hde' snapshot='external'>
|
<disk name='hde' snapshot='external' type='file'>
|
||||||
<driver type='qcow2'/>
|
<driver type='qcow2'/>
|
||||||
<source file='/path/to/new'/>
|
<source file='/path/to/new'/>
|
||||||
</disk>
|
</disk>
|
||||||
<disk name='hdf' snapshot='external'>
|
<disk name='hdf' snapshot='external' type='file'>
|
||||||
<driver type='qcow2'/>
|
<driver type='qcow2'/>
|
||||||
<source file='/path/to/generated5'/>
|
<source file='/path/to/generated5'/>
|
||||||
</disk>
|
</disk>
|
||||||
|
Loading…
Reference in New Issue
Block a user