On 06/18/2013 04:36 AM, Osier Yang wrote:
The difference with already supported pool types (dir, fs, block)
is: there are two modes for iscsi pool (or network pools in future),
one can specify it either to use the volume target path (the path
showed up on host) with mode='host', or to use the remote URI qemu
supports (e.g. file=iscsi://example.org:6000/iqn.1992-01.com.example/1)
with mode='uri'.
For 'host' mode, it copies the volume target path into disk->src. For
'uri' mode, the conresponded info in the *one* pool source host def
s/conresponded/corresponding/ ??
Not sure I understand the "*one* pool" reference.
are copied to disk->hosts[0].
* src/conf/domain_conf.[ch]: (Introduce a new helper to check if
the disk source is of block type:
virDomainDiskSourceIsBlockType;
Introduce "pooltype" for disk->srcpool,
to indicate the pool type)
src/libvirt_private.syms: (Expose the new helper's symbol)
* src/qemu/qemu_conf.c: (Use the helper to ease the checking in
"shared disk", "sgio" related helpers;
Translate the iscsi pool/volume disk source)
* src/qemu/qemu_command.c (Use the helper to ease the checking in
qemuBuildDriveDevStr; Build qemu command
line for iscsi pool/volume disk source)
---
src/conf/domain_conf.c | 42 +++++++++++++++++
src/conf/domain_conf.h | 3 ++
src/libvirt_private.syms | 1 +
src/qemu/qemu_command.c | 20 ++++++--
src/qemu/qemu_conf.c | 117 ++++++++++++++++++++++++++++++++++++++---------
5 files changed, 158 insertions(+), 25 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 009a8aa..04b14dc 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -41,6 +41,7 @@
#include "virbuffer.h"
#include "virlog.h"
#include "nwfilter_conf.h"
+#include "storage_conf.h"
#include "virstoragefile.h"
#include "virfile.h"
#include "virbitmap.h"
@@ -17950,3 +17951,44 @@ virDomainDiskDefGenSecurityLabelDef(const char *model)
return seclabel;
}
+
+/**
+ * virDomainDiskSourceIsBlockType:
+ *
+ * Check if the disk *source* is of block type. This just tries
+ * to check from the type of disk def, not to probe the underlying
+ * storage.
+ *
+ * Return true if its source is block type, or false otherwise.
+ */
+bool
+virDomainDiskSourceIsBlockType(virDomainDiskDefPtr def)
+{
+ if (!def)
+ return false;
+
+ /* No reason to think the disk source is block type if
+ * the source is empty
+ */
+ if (!def->src && !def->srcpool)
+ return false;
Logic changed slightly over the previous code, but I think it's OK. I'm
reading this as a block source will be always part of some block pool.
And that we only care to check the srcpool if we're a volume.
I guess the question is - will srcpool be set? We previously only cared
about srcpool if we had a src that was a volume. Now we're always
checking. It's a slight change, but could be important.
+
+ if (def->type == VIR_DOMAIN_DISK_TYPE_BLOCK)
+ return true;
+
+ if (def->type == VIR_DOMAIN_DISK_TYPE_VOLUME) {
+ if (def->srcpool->voltype == VIR_STORAGE_VOL_BLOCK) {
NIT: Two "ifs" that could be combined - that is we have a source of
volume type backed by a pool of volume block devices)
+ /* We don't think the volume accessed by remote URI
is
+ * block type source, since we can't/shoudn't manage it
s/shoudn't/shouldn't/
+ * (e.g. set sgio=filtered|unfilered for it) in libvirt.
s/unfilered/unfiltered/
+ */
+ if (def->srcpool->pooltype == VIR_STORAGE_POOL_ISCSI &&
+ def->srcpool->mode == VIR_DOMAIN_DISK_SOURCE_POOL_MODE_URI)
+ return false;
+
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index d57b7c3..3c60293 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -671,6 +671,7 @@ struct _virDomainDiskSourcePoolDef {
char *pool; /* pool name */
char *volume; /* volume name */
int voltype; /* enum virStorageVolType, internal only */
+ int pooltype; /* enum virStoragePoolType, internal only */
This is being made generic to all disk source pool types, but only ever
defined when/if it's a VIR_DOMAIN_DISK_TYPE_VOLUME and
VIR_STORAGE_VOL_BLOCK (I assume that's a volume back by a pool of volume
block devices).
int mode; /* enum virDomainDiskSourcePoolMode */
};
typedef virDomainDiskSourcePoolDef *virDomainDiskSourcePoolDefPtr;
@@ -2652,4 +2653,6 @@ virDomainDefMaybeAddController(virDomainDefPtr def,
char *virDomainDefGetDefaultEmulator(virDomainDefPtr def, virCapsPtr caps);
+bool virDomainDiskSourceIsBlockType(virDomainDiskDefPtr def);
+
#endif /* __DOMAIN_CONF_H */
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 1ea7467..fa9f079 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -161,6 +161,7 @@ virDomainDiskProtocolTransportTypeToString;
virDomainDiskProtocolTypeToString;
virDomainDiskRemove;
virDomainDiskRemoveByName;
+virDomainDiskSourceIsBlockType;
virDomainDiskTypeFromString;
virDomainDiskTypeToString;
virDomainEmulatorPinAdd;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 486682e..ae5f7dd 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -42,6 +42,7 @@
#include "domain_audit.h"
#include "domain_conf.h"
#include "snapshot_conf.h"
+#include "storage_conf.h"
#include "network/bridge_driver.h"
#include "virnetdevtap.h"
#include "base64.h"
@@ -3163,7 +3164,20 @@ qemuBuildDriveStr(virConnectPtr conn ATTRIBUTE_UNUSED,
"block type volume"));
goto error;
}
- virBufferEscape(&opt, ',', ",",
"file=%s,", disk->src);
+
+ if (disk->srcpool->pooltype == VIR_STORAGE_POOL_ISCSI) {
+ if (disk->srcpool->mode ==
+ VIR_DOMAIN_DISK_SOURCE_POOL_MODE_URI) {
+ if (qemuBuildISCSIString(conn, disk, &opt) < 0)
+ goto error;
+ virBufferAddChar(&opt, ',');
+ } else if (disk->srcpool->mode ==
+ VIR_DOMAIN_DISK_SOURCE_POOL_MODE_HOST) {
+ virBufferEscape(&opt, ',', ",",
"file=%s,", disk->src);
+ }
+ } else {
+ virBufferEscape(&opt, ',', ",",
"file=%s,", disk->src);
+ }
break;
case VIR_STORAGE_VOL_FILE:
virBufferEscape(&opt, ',', ",",
"file=%s,", disk->src);
@@ -3450,9 +3464,7 @@ qemuBuildDriveDevStr(virDomainDefPtr def,
virDomainDiskProtocolTypeToString(disk->protocol));
goto error;
}
- } else if (disk->type != VIR_DOMAIN_DISK_TYPE_BLOCK &&
- !(disk->type == VIR_DOMAIN_DISK_TYPE_VOLUME &&
- disk->srcpool->voltype == VIR_STORAGE_VOL_BLOCK)) {
+ } else if (!virDomainDiskSourceIsBlockType(disk)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("disk device='lun' is only valid for block
type disk source"));
goto error;
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 094f9f7..b67f182 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -52,6 +52,7 @@
#include "virfile.h"
#include "virstring.h"
#include "viratomic.h"
+#include "storage_conf.h"
#include "configmake.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -1180,12 +1181,7 @@ qemuAddSharedDevice(virQEMUDriverPtr driver,
if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
disk = dev->data.disk;
- if (!disk->shared ||
- !disk->src ||
- (disk->type != VIR_DOMAIN_DISK_TYPE_BLOCK &&
- !(disk->type == VIR_DOMAIN_DISK_TYPE_VOLUME &&
- disk->srcpool &&
- disk->srcpool->voltype == VIR_STORAGE_VOL_BLOCK)))
+ if (!disk->shared || !virDomainDiskSourceIsBlockType(disk))
return 0;
} else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
hostdev = dev->data.hostdev;
@@ -1295,12 +1291,7 @@ qemuRemoveSharedDevice(virQEMUDriverPtr driver,
if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
disk = dev->data.disk;
- if (!disk->shared ||
- !disk->src ||
- (disk->type != VIR_DOMAIN_DISK_TYPE_BLOCK &&
- !(disk->type == VIR_DOMAIN_DISK_TYPE_VOLUME &&
- disk->srcpool &&
- disk->srcpool->voltype == VIR_STORAGE_VOL_BLOCK)))
+ if (!disk->shared || !virDomainDiskSourceIsBlockType(disk))
return 0;
} else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
hostdev = dev->data.hostdev;
@@ -1392,12 +1383,8 @@ qemuSetUnprivSGIO(virDomainDeviceDefPtr dev)
if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
disk = dev->data.disk;
- if (!disk->src ||
- disk->device != VIR_DOMAIN_DISK_DEVICE_LUN ||
- (disk->type != VIR_DOMAIN_DISK_TYPE_BLOCK &&
- !(disk->type == VIR_DOMAIN_DISK_TYPE_VOLUME &&
- disk->srcpool &&
- disk->srcpool->voltype == VIR_STORAGE_VOL_BLOCK)))
+ if (disk->device != VIR_DOMAIN_DISK_DEVICE_LUN ||
+ virDomainDiskSourceIsBlockType(disk))
return 0;
path = disk->src;
@@ -1463,9 +1450,12 @@ int
qemuTranslateDiskSourcePool(virConnectPtr conn,
virDomainDiskDefPtr def)
{
+ virStoragePoolDefPtr pooldef = NULL;
virStoragePoolPtr pool = NULL;
virStorageVolPtr vol = NULL;
+ char *poolxml = NULL;
virStorageVolInfo info;
+ char **tokens = NULL;
int ret = -1;
if (def->type != VIR_DOMAIN_DISK_TYPE_VOLUME)
Remainder only ever run for a source of volume type...
@@ -1492,11 +1482,91 @@ qemuTranslateDiskSourcePool(virConnectPtr
conn,
switch (info.type) {
case VIR_STORAGE_VOL_FILE:
- case VIR_STORAGE_VOL_BLOCK:
case VIR_STORAGE_VOL_DIR:
if (!(def->src = virStorageVolGetPath(vol)))
goto cleanup;
So no need to check/set pooltype here?
break;
+ case VIR_STORAGE_VOL_BLOCK:
+ if (!(poolxml = virStoragePoolGetXMLDesc(pool, 0)))
+ goto cleanup;
+
+ if (!(pooldef = virStoragePoolDefParseString(poolxml)))
+ goto cleanup;
+
+ if (pooldef->type != VIR_STORAGE_POOL_ISCSI &&
+ def->srcpool->mode) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("disk source mode is only valid when "
+ "storage pool is of iscsi type"));
+ goto cleanup;
+ }
+
+ if (pooldef->type == VIR_STORAGE_POOL_ISCSI) {
+ /* Default to use the LUN's path on host */
+ if (!def->srcpool->mode)
+ def->srcpool->mode = VIR_DOMAIN_DISK_SOURCE_POOL_MODE_HOST;
+
+ if (def->srcpool->mode ==
+ VIR_DOMAIN_DISK_SOURCE_POOL_MODE_URI) {
+ /* iscsi pool only supports one host */
+ def->nhosts = 1;
+
+ if (VIR_ALLOC_N(def->hosts, def->nhosts) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (VIR_STRDUP(def->hosts[0].name,
+ pooldef->source.hosts[0].name) < 0)
+ goto cleanup;
+
+ if (virAsprintf(&def->hosts[0].port, "%d",
+ pooldef->source.hosts[0].port ?
+ pooldef->source.hosts[0].port :
+ 3260) < 0) {
From 1/6 in storage_backend_iscsi:
#define ISCSI_DEFAULT_TARGET_PORT 3260
Maybe that needs to be put in a more common include file?
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ /* iscsi volume has name like "unit:0:0:1" */
+ if (!(tokens = virStringSplit(def->srcpool->volume,
+ ":", 0)))
s/0/4/ ?? Although if you do 5 or more, then the proceeding check 4 is
"more valid" (in the even someone has "unit:1:2:3:4")
+ goto cleanup;
+
+ if (virStringListLength(tokens) != 4) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unexpected iscsi volume name
'%s'"),
+ def->srcpool->volume);
+ goto cleanup;
+ }
+
+ /* iscsi pool has only one source device path */
So using the '4th' value makes the name unique enough? I'm not familiar
with the naming scheme, but it would seem that "unit:0:0:1" and
"unit:1:1:1" would result in the same name, correct? Or am I missing
something. Don't want to assume anything.
+ if (virAsprintf(&def->src,
"%s/%s",
+ pooldef->source.devices[0].path,
+ tokens[3]) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ /* Storage pool have not supportted these 2 attributes yet,
+ * use the defaults.
s/supportted/supported
+ */
+ def->hosts[0].transport = VIR_DOMAIN_DISK_PROTO_TRANS_TCP;
+ def->hosts[0].socket = NULL;
+
+ def->protocol = VIR_DOMAIN_DISK_PROTOCOL_ISCSI;
+ } else if (def->srcpool->mode ==
+ VIR_DOMAIN_DISK_SOURCE_POOL_MODE_HOST) {
+ if (!(def->src = virStorageVolGetPath(vol)))
+ goto cleanup;
+ }
+ } else {
+ if (!(def->src = virStorageVolGetPath(vol)))
+ goto cleanup;
+ }
+
+ def->srcpool->pooltype = pooldef->type;
+ break;
case VIR_STORAGE_VOL_NETWORK:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Using network volume as disk source is not
supported"));
Again, no need to set "pooltype" then, right?
@@ -1506,7 +1576,12 @@ qemuTranslateDiskSourcePool(virConnectPtr
conn,
def->srcpool->voltype = info.type;
ret = 0;
cleanup:
- virStoragePoolFree(pool);
- virStorageVolFree(vol);
+ if (pool)
+ virStoragePoolFree(pool);
+ if (vol)
+ virStorageVolFree(vol);
Don't think either is necessary -
virStoragePoolFree -> VIR_IS_CONNECTED_STORAGE_POOL(pool) ->
VIR_IS_STORAGE_POOL(obj) -> VIR_IS_STORAGE_POOL(obj) ->
virObjectIsClass(obj) -> if (!obj) return false
virStorageVolFree -> !VIR_IS_STORAGE_VOL(vol) -> virObjectIsClass(obj)
-> if (!obj) return false
+ VIR_FREE(poolxml);
+ virStoragePoolDefFree(pooldef);
+ virStringFreeList(tokens);
return ret;
}