[libvirt] [PATCH 3/6] qemu: Translate the iscsi pool/volume disk source

John Ferlan jferlan at redhat.com
Fri Jun 21 16:06:58 UTC 2013


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




More information about the libvir-list mailing list