|
|
9119d9 |
From b7945d7e44a533d7a9cc26d493f7abb9ebccaae4 Mon Sep 17 00:00:00 2001
|
|
|
9119d9 |
Message-Id: <b7945d7e44a533d7a9cc26d493f7abb9ebccaae4@dist-git>
|
|
|
9119d9 |
From: Peter Krempa <pkrempa@redhat.com>
|
|
|
9119d9 |
Date: Fri, 21 Nov 2014 15:04:11 +0100
|
|
|
9119d9 |
Subject: [PATCH] storage: rbd: qemu: Add support for specifying internal RBD
|
|
|
9119d9 |
snapshots
|
|
|
9119d9 |
|
|
|
9119d9 |
https://bugzilla.redhat.com/show_bug.cgi?id=1164528
|
|
|
9119d9 |
|
|
|
9119d9 |
Some storage systems have internal support for snapshots. Libvirt should
|
|
|
9119d9 |
be able to select a correct snapshot when starting a VM.
|
|
|
9119d9 |
|
|
|
9119d9 |
This patch adds a XML element to select a storage source snapshot for
|
|
|
9119d9 |
the RBD protocol which supports this feature.
|
|
|
9119d9 |
|
|
|
9119d9 |
(cherry picked from commit 02556606584ef6c065eae6e36c311250fa7a24f4)
|
|
|
9119d9 |
|
|
|
9119d9 |
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
|
|
9119d9 |
---
|
|
|
9119d9 |
docs/formatdomain.html.in | 16 +++++++--
|
|
|
9119d9 |
docs/schemas/domaincommon.rng | 8 +++++
|
|
|
9119d9 |
src/conf/domain_conf.c | 38 +++++++++++++++++++---
|
|
|
9119d9 |
src/conf/domain_conf.h | 1 +
|
|
|
9119d9 |
src/conf/snapshot_conf.c | 6 ++--
|
|
|
9119d9 |
src/qemu/qemu_command.c | 3 ++
|
|
|
9119d9 |
src/util/virstoragefile.c | 8 +++++
|
|
|
9119d9 |
src/util/virstoragefile.h | 1 +
|
|
|
9119d9 |
.../qemuxml2argv-disk-drive-network-rbd.args | 4 +++
|
|
|
9119d9 |
.../qemuxml2argv-disk-drive-network-rbd.xml | 17 ++++++++++
|
|
|
9119d9 |
10 files changed, 93 insertions(+), 9 deletions(-)
|
|
|
9119d9 |
|
|
|
9119d9 |
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
|
|
|
9119d9 |
index a458067..789f6ee 100644
|
|
|
9119d9 |
--- a/docs/formatdomain.html.in
|
|
|
9119d9 |
+++ b/docs/formatdomain.html.in
|
|
|
9119d9 |
@@ -1661,6 +1661,7 @@
|
|
|
9119d9 |
<driver name="qemu" type="raw"/>
|
|
|
9119d9 |
<source protocol="rbd" name="image_name2">
|
|
|
9119d9 |
<host name="hostname" port="7000"/>
|
|
|
9119d9 |
+ <snapshot name="snapname"/>
|
|
|
9119d9 |
</source>
|
|
|
9119d9 |
<target dev="hdc" bus="ide"/>
|
|
|
9119d9 |
<auth username='myuser'>
|
|
|
9119d9 |
@@ -1934,15 +1935,17 @@
|
|
|
9119d9 |
is only valid when the specified storage volume is of 'file' or
|
|
|
9119d9 |
'block' type).
|
|
|
9119d9 |
|
|
|
9119d9 |
- When the disk type is "network", the source
|
|
|
9119d9 |
- may have zero or more host sub-elements used to
|
|
|
9119d9 |
- specify the hosts to connect.
|
|
|
9119d9 |
+ The source element may contain the following sub elements:
|
|
|
9119d9 |
|
|
|
9119d9 |
|
|
|
9119d9 |
|
|
|
9119d9 |
host
|
|
|
9119d9 |
|
|
|
9119d9 |
|
|
|
9119d9 |
+ When the disk type is "network", the source
|
|
|
9119d9 |
+ may have zero or more host sub-elements used to
|
|
|
9119d9 |
+ specify the hosts to connect.
|
|
|
9119d9 |
+
|
|
|
9119d9 |
The host element supports 4 attributes, viz. "name",
|
|
|
9119d9 |
"port", "transport" and "socket", which specify the hostname,
|
|
|
9119d9 |
the port number, transport type and path to socket, respectively.
|
|
|
9119d9 |
@@ -1995,6 +1998,13 @@
|
|
|
9119d9 |
AF_UNIX socket.
|
|
|
9119d9 |
|
|
|
9119d9 |
|
|
|
9119d9 |
+ snapshot
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ The name attribute of snapshot element can
|
|
|
9119d9 |
+ optionally specify an internal snapshot name to be used as the
|
|
|
9119d9 |
+ source for storage protocols.
|
|
|
9119d9 |
+ Supported for 'rbd' since 1.2.11 (QEMU only).
|
|
|
9119d9 |
+
|
|
|
9119d9 |
|
|
|
9119d9 |
|
|
|
9119d9 |
|
|
|
9119d9 |
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
|
|
|
9119d9 |
index c010c45..fa17494 100644
|
|
|
9119d9 |
--- a/docs/schemas/domaincommon.rng
|
|
|
9119d9 |
+++ b/docs/schemas/domaincommon.rng
|
|
|
9119d9 |
@@ -1447,6 +1447,14 @@
|
|
|
9119d9 |
</choice>
|
|
|
9119d9 |
</element>
|
|
|
9119d9 |
</zeroOrMore>
|
|
|
9119d9 |
+ <optional>
|
|
|
9119d9 |
+ <element name="snapshot">
|
|
|
9119d9 |
+ <attribute name="name">
|
|
|
9119d9 |
+ <ref name="genericName"/>
|
|
|
9119d9 |
+ </attribute>
|
|
|
9119d9 |
+ <empty/>
|
|
|
9119d9 |
+ </element>
|
|
|
9119d9 |
+ </optional>
|
|
|
9119d9 |
<empty/>
|
|
|
9119d9 |
</element>
|
|
|
9119d9 |
</interleave>
|
|
|
9119d9 |
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
|
|
|
9119d9 |
index 0e977fc..82d321a 100644
|
|
|
9119d9 |
--- a/src/conf/domain_conf.c
|
|
|
9119d9 |
+++ b/src/conf/domain_conf.c
|
|
|
9119d9 |
@@ -3157,6 +3157,22 @@ virDomainDeviceDefPostParseInternal(virDomainDeviceDefPtr dev,
|
|
|
9119d9 |
return -1;
|
|
|
9119d9 |
}
|
|
|
9119d9 |
|
|
|
9119d9 |
+ /* verify disk source */
|
|
|
9119d9 |
+ if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
|
|
|
9119d9 |
+ virDomainDiskDefPtr disk = dev->data.disk;
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ /* internal snapshots are currently supported only with rbd: */
|
|
|
9119d9 |
+ if (virStorageSourceGetActualType(disk->src) != VIR_STORAGE_TYPE_NETWORK &&
|
|
|
9119d9 |
+ disk->src->protocol != VIR_STORAGE_NET_PROTOCOL_RBD) {
|
|
|
9119d9 |
+ if (disk->src->snapshot) {
|
|
|
9119d9 |
+ virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
9119d9 |
+ _("<snapshot> element is currently supported "
|
|
|
9119d9 |
+ "only with 'rbd' disks"));
|
|
|
9119d9 |
+ return -1;
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+
|
|
|
9119d9 |
return 0;
|
|
|
9119d9 |
}
|
|
|
9119d9 |
|
|
|
9119d9 |
@@ -5301,10 +5317,14 @@ virDomainDiskSourcePoolDefParse(xmlNodePtr node,
|
|
|
9119d9 |
|
|
|
9119d9 |
int
|
|
|
9119d9 |
virDomainDiskSourceParse(xmlNodePtr node,
|
|
|
9119d9 |
+ xmlXPathContextPtr ctxt,
|
|
|
9119d9 |
virStorageSourcePtr src)
|
|
|
9119d9 |
{
|
|
|
9119d9 |
int ret = -1;
|
|
|
9119d9 |
char *protocol = NULL;
|
|
|
9119d9 |
+ xmlNodePtr saveNode = ctxt->node;
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ ctxt->node = node;
|
|
|
9119d9 |
|
|
|
9119d9 |
switch ((virStorageType)src->type) {
|
|
|
9119d9 |
case VIR_STORAGE_TYPE_FILE:
|
|
|
9119d9 |
@@ -5357,6 +5377,9 @@ virDomainDiskSourceParse(xmlNodePtr node,
|
|
|
9119d9 |
tmp[0] = '\0';
|
|
|
9119d9 |
}
|
|
|
9119d9 |
|
|
|
9119d9 |
+ /* snapshot currently works only for remote disks */
|
|
|
9119d9 |
+ src->snapshot = virXPathString("string(./snapshot/@name)", ctxt);
|
|
|
9119d9 |
+
|
|
|
9119d9 |
if (virDomainStorageHostParse(node, &src->hosts, &src->nhosts) < 0)
|
|
|
9119d9 |
goto cleanup;
|
|
|
9119d9 |
break;
|
|
|
9119d9 |
@@ -5382,6 +5405,7 @@ virDomainDiskSourceParse(xmlNodePtr node,
|
|
|
9119d9 |
|
|
|
9119d9 |
cleanup:
|
|
|
9119d9 |
VIR_FREE(protocol);
|
|
|
9119d9 |
+ ctxt->node = saveNode;
|
|
|
9119d9 |
return ret;
|
|
|
9119d9 |
}
|
|
|
9119d9 |
|
|
|
9119d9 |
@@ -5437,7 +5461,7 @@ virDomainDiskBackingStoreParse(xmlXPathContextPtr ctxt,
|
|
|
9119d9 |
goto cleanup;
|
|
|
9119d9 |
}
|
|
|
9119d9 |
|
|
|
9119d9 |
- if (virDomainDiskSourceParse(source, backingStore) < 0 ||
|
|
|
9119d9 |
+ if (virDomainDiskSourceParse(source, ctxt, backingStore) < 0 ||
|
|
|
9119d9 |
virDomainDiskBackingStoreParse(ctxt, backingStore) < 0)
|
|
|
9119d9 |
goto cleanup;
|
|
|
9119d9 |
|
|
|
9119d9 |
@@ -5547,7 +5571,7 @@ virDomainDiskDefParseXML(virDomainXMLOptionPtr xmlopt,
|
|
|
9119d9 |
xmlStrEqual(cur->name, BAD_CAST "source")) {
|
|
|
9119d9 |
sourceNode = cur;
|
|
|
9119d9 |
|
|
|
9119d9 |
- if (virDomainDiskSourceParse(cur, def->src) < 0)
|
|
|
9119d9 |
+ if (virDomainDiskSourceParse(cur, ctxt, def->src) < 0)
|
|
|
9119d9 |
goto error;
|
|
|
9119d9 |
source = def->src->path;
|
|
|
9119d9 |
|
|
|
9119d9 |
@@ -5713,7 +5737,8 @@ virDomainDiskDefParseXML(virDomainXMLOptionPtr xmlopt,
|
|
|
9119d9 |
_("mirror requires source element"));
|
|
|
9119d9 |
goto error;
|
|
|
9119d9 |
}
|
|
|
9119d9 |
- if (virDomainDiskSourceParse(mirrorNode, def->mirror) < 0)
|
|
|
9119d9 |
+ if (virDomainDiskSourceParse(mirrorNode, ctxt,
|
|
|
9119d9 |
+ def->mirror) < 0)
|
|
|
9119d9 |
goto error;
|
|
|
9119d9 |
}
|
|
|
9119d9 |
ready = virXMLPropString(cur, "ready");
|
|
|
9119d9 |
@@ -15898,11 +15923,12 @@ virDomainDiskSourceFormatInternal(virBufferPtr buf,
|
|
|
9119d9 |
|
|
|
9119d9 |
VIR_FREE(path);
|
|
|
9119d9 |
|
|
|
9119d9 |
- if (src->nhosts == 0) {
|
|
|
9119d9 |
+ if (src->nhosts == 0 && !src->snapshot) {
|
|
|
9119d9 |
virBufferAddLit(buf, "/>\n");
|
|
|
9119d9 |
} else {
|
|
|
9119d9 |
virBufferAddLit(buf, ">\n");
|
|
|
9119d9 |
virBufferAdjustIndent(buf, 2);
|
|
|
9119d9 |
+
|
|
|
9119d9 |
for (n = 0; n < src->nhosts; n++) {
|
|
|
9119d9 |
virBufferAddLit(buf, "
|
|
|
9119d9 |
virBufferEscapeString(buf, " name='%s'",
|
|
|
9119d9 |
@@ -15919,6 +15945,10 @@ virDomainDiskSourceFormatInternal(virBufferPtr buf,
|
|
|
9119d9 |
|
|
|
9119d9 |
virBufferAddLit(buf, "/>\n");
|
|
|
9119d9 |
}
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ virBufferEscapeString(buf, "<snapshot name='%s'/>\n",
|
|
|
9119d9 |
+ src->snapshot);
|
|
|
9119d9 |
+
|
|
|
9119d9 |
virBufferAdjustIndent(buf, -2);
|
|
|
9119d9 |
virBufferAddLit(buf, "</source>\n");
|
|
|
9119d9 |
}
|
|
|
9119d9 |
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
|
|
|
9119d9 |
index 21d19cf..6768089 100644
|
|
|
9119d9 |
--- a/src/conf/domain_conf.h
|
|
|
9119d9 |
+++ b/src/conf/domain_conf.h
|
|
|
9119d9 |
@@ -2445,6 +2445,7 @@ virDomainDiskRemove(virDomainDefPtr def, size_t i);
|
|
|
9119d9 |
virDomainDiskDefPtr
|
|
|
9119d9 |
virDomainDiskRemoveByName(virDomainDefPtr def, const char *name);
|
|
|
9119d9 |
int virDomainDiskSourceParse(xmlNodePtr node,
|
|
|
9119d9 |
+ xmlXPathContextPtr ctxt,
|
|
|
9119d9 |
virStorageSourcePtr src);
|
|
|
9119d9 |
|
|
|
9119d9 |
bool virDomainHasDiskMirror(virDomainObjPtr vm);
|
|
|
9119d9 |
diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c
|
|
|
9119d9 |
index c53a66b..27882b8 100644
|
|
|
9119d9 |
--- a/src/conf/snapshot_conf.c
|
|
|
9119d9 |
+++ b/src/conf/snapshot_conf.c
|
|
|
9119d9 |
@@ -107,6 +107,7 @@ void virDomainSnapshotDefFree(virDomainSnapshotDefPtr def)
|
|
|
9119d9 |
|
|
|
9119d9 |
static int
|
|
|
9119d9 |
virDomainSnapshotDiskDefParseXML(xmlNodePtr node,
|
|
|
9119d9 |
+ xmlXPathContextPtr ctxt,
|
|
|
9119d9 |
virDomainSnapshotDiskDefPtr def)
|
|
|
9119d9 |
{
|
|
|
9119d9 |
int ret = -1;
|
|
|
9119d9 |
@@ -154,7 +155,7 @@ virDomainSnapshotDiskDefParseXML(xmlNodePtr node,
|
|
|
9119d9 |
if (!def->src->path &&
|
|
|
9119d9 |
xmlStrEqual(cur->name, BAD_CAST "source")) {
|
|
|
9119d9 |
|
|
|
9119d9 |
- if (virDomainDiskSourceParse(cur, def->src) < 0)
|
|
|
9119d9 |
+ if (virDomainDiskSourceParse(cur, ctxt, def->src) < 0)
|
|
|
9119d9 |
goto cleanup;
|
|
|
9119d9 |
|
|
|
9119d9 |
} else if (!def->src->format &&
|
|
|
9119d9 |
@@ -352,7 +353,8 @@ virDomainSnapshotDefParse(xmlXPathContextPtr ctxt,
|
|
|
9119d9 |
goto cleanup;
|
|
|
9119d9 |
def->ndisks = n;
|
|
|
9119d9 |
for (i = 0; i < def->ndisks; i++) {
|
|
|
9119d9 |
- if (virDomainSnapshotDiskDefParseXML(nodes[i], &def->disks[i]) < 0)
|
|
|
9119d9 |
+ if (virDomainSnapshotDiskDefParseXML(nodes[i], ctxt,
|
|
|
9119d9 |
+ &def->disks[i]) < 0)
|
|
|
9119d9 |
goto cleanup;
|
|
|
9119d9 |
}
|
|
|
9119d9 |
VIR_FREE(nodes);
|
|
|
9119d9 |
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
|
|
|
9119d9 |
index 93f02a9..5d34ba3 100644
|
|
|
9119d9 |
--- a/src/qemu/qemu_command.c
|
|
|
9119d9 |
+++ b/src/qemu/qemu_command.c
|
|
|
9119d9 |
@@ -2986,6 +2986,9 @@ qemuBuildNetworkDriveURI(virStorageSourcePtr src,
|
|
|
9119d9 |
|
|
|
9119d9 |
virBufferStrcat(&buf, "rbd:", src->path, NULL);
|
|
|
9119d9 |
|
|
|
9119d9 |
+ if (src->snapshot)
|
|
|
9119d9 |
+ virBufferEscape(&buf, '\\', ":", "@%s", src->snapshot);
|
|
|
9119d9 |
+
|
|
|
9119d9 |
if (username) {
|
|
|
9119d9 |
virBufferEscape(&buf, '\\', ":", ":id=%s", username);
|
|
|
9119d9 |
virBufferEscape(&buf, '\\', ":",
|
|
|
9119d9 |
diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c
|
|
|
9119d9 |
index ba4d830..6cdc5be 100644
|
|
|
9119d9 |
--- a/src/util/virstoragefile.c
|
|
|
9119d9 |
+++ b/src/util/virstoragefile.c
|
|
|
9119d9 |
@@ -1842,6 +1842,7 @@ virStorageSourceCopy(const virStorageSource *src,
|
|
|
9119d9 |
VIR_STRDUP(ret->driverName, src->driverName) < 0 ||
|
|
|
9119d9 |
VIR_STRDUP(ret->relPath, src->relPath) < 0 ||
|
|
|
9119d9 |
VIR_STRDUP(ret->backingStoreRaw, src->backingStoreRaw) < 0 ||
|
|
|
9119d9 |
+ VIR_STRDUP(ret->snapshot, src->snapshot) < 0 ||
|
|
|
9119d9 |
VIR_STRDUP(ret->compat, src->compat) < 0)
|
|
|
9119d9 |
goto error;
|
|
|
9119d9 |
|
|
|
9119d9 |
@@ -2259,6 +2260,13 @@ virStorageSourceParseRBDColonString(const char *rbdstr,
|
|
|
9119d9 |
*p = '\0';
|
|
|
9119d9 |
}
|
|
|
9119d9 |
|
|
|
9119d9 |
+ /* snapshot name */
|
|
|
9119d9 |
+ if ((p = strchr(src->path, '@'))) {
|
|
|
9119d9 |
+ if (VIR_STRDUP(src->snapshot, p + 1) < 0)
|
|
|
9119d9 |
+ goto error;
|
|
|
9119d9 |
+ *p = '\0';
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+
|
|
|
9119d9 |
/* options */
|
|
|
9119d9 |
if (!options)
|
|
|
9119d9 |
return 0; /* all done */
|
|
|
9119d9 |
diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h
|
|
|
9119d9 |
index 3573ccd..74aa1a3 100644
|
|
|
9119d9 |
--- a/src/util/virstoragefile.h
|
|
|
9119d9 |
+++ b/src/util/virstoragefile.h
|
|
|
9119d9 |
@@ -236,6 +236,7 @@ struct _virStorageSource {
|
|
|
9119d9 |
char *path;
|
|
|
9119d9 |
int protocol; /* virStorageNetProtocol */
|
|
|
9119d9 |
char *volume; /* volume name for remote storage */
|
|
|
9119d9 |
+ char *snapshot; /* for storage systems supporting internal snapshots */
|
|
|
9119d9 |
size_t nhosts;
|
|
|
9119d9 |
virStorageNetHostDefPtr hosts;
|
|
|
9119d9 |
virStorageSourcePoolDefPtr srcpool;
|
|
|
9119d9 |
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd.args b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd.args
|
|
|
9119d9 |
index 21d7b64..e4f1389 100644
|
|
|
9119d9 |
--- a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd.args
|
|
|
9119d9 |
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd.args
|
|
|
9119d9 |
@@ -5,4 +5,8 @@ unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -usb \
|
|
|
9119d9 |
-drive 'file=rbd:pool/image:auth_supported=none:\
|
|
|
9119d9 |
mon_host=mon1.example.org\:6321\;mon2.example.org\:6322\;\
|
|
|
9119d9 |
mon3.example.org\:6322,if=virtio,format=raw' \
|
|
|
9119d9 |
+-drive file=rbd:pool/image@asdf:auth_supported=none,if=virtio,format=raw \
|
|
|
9119d9 |
+-drive 'file=rbd:pool/image@foo:auth_supported=none:\
|
|
|
9119d9 |
+mon_host=mon1.example.org\:6321\;mon2.example.org\:6322\;\
|
|
|
9119d9 |
+mon3.example.org\:6322,if=virtio,format=raw' \
|
|
|
9119d9 |
-net none -serial none -parallel none
|
|
|
9119d9 |
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd.xml b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd.xml
|
|
|
9119d9 |
index 37e9db5..f6accd8 100644
|
|
|
9119d9 |
--- a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd.xml
|
|
|
9119d9 |
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-network-rbd.xml
|
|
|
9119d9 |
@@ -29,6 +29,23 @@
|
|
|
9119d9 |
</source>
|
|
|
9119d9 |
<target dev='vda' bus='virtio'/>
|
|
|
9119d9 |
</disk>
|
|
|
9119d9 |
+ <disk type='network' device='disk'>
|
|
|
9119d9 |
+ <driver name='qemu' type='raw'/>
|
|
|
9119d9 |
+ <source protocol='rbd' name='pool/image'>
|
|
|
9119d9 |
+ <snapshot name='asdf'/>
|
|
|
9119d9 |
+ </source>
|
|
|
9119d9 |
+ <target dev='vdb' bus='virtio'/>
|
|
|
9119d9 |
+ </disk>
|
|
|
9119d9 |
+ <disk type='network' device='disk'>
|
|
|
9119d9 |
+ <driver name='qemu' type='raw'/>
|
|
|
9119d9 |
+ <source protocol='rbd' name='pool/image'>
|
|
|
9119d9 |
+ <host name='mon1.example.org' port='6321'/>
|
|
|
9119d9 |
+ <host name='mon2.example.org' port='6322'/>
|
|
|
9119d9 |
+ <host name='mon3.example.org' port='6322'/>
|
|
|
9119d9 |
+ <snapshot name='foo'/>
|
|
|
9119d9 |
+ </source>
|
|
|
9119d9 |
+ <target dev='vdc' bus='virtio'/>
|
|
|
9119d9 |
+ </disk>
|
|
|
9119d9 |
<controller type='usb' index='0'/>
|
|
|
9119d9 |
<controller type='ide' index='0'/>
|
|
|
9119d9 |
<controller type='pci' index='0' model='pci-root'/>
|
|
|
9119d9 |
--
|
|
|
9119d9 |
2.1.3
|
|
|
9119d9 |
|