[libvirt] [PATCH v3 16/18] conf: Move/rename createVport and deleteVport
Laine Stump
laine at laine.org
Sun Mar 12 22:35:21 UTC 2017
On 03/10/2017 04:10 PM, John Ferlan wrote:
> Move the bulk of the code to the node_device_conf and rename to
> virNodeDevice{Create|Delete}Vport.
>
> Alter the create algorithm slightly in order to return the name of
> the scsi_host vHBA that was created. The existing code would fetch
> the name and if it exists would start a thread looking for the LUNs;
> however, in no way did it validate the device was created for the
> storage pool even though it would be used thereafter.
>
> This slight change allows the code that checks if the node device
> by wwnn/wwpn already exists and return that name. This fixes a
> second yet seen issue that if the nodedev was present, but the
> parent by name wasn't provided (perhaps parent by wwnn/wwpn or
> by fabric_name), then a failure would be returned. For this path
> it shouldn't be an error - we should just be happy that something
> else is managing the device and we don't have to create/delete it.
>
> The end result is that the startVport code can now just start the
> thread once it gets a non NULL name back.
>
> Signed-off-by: John Ferlan <jferlan at redhat.com>
> ---
> src/conf/node_device_conf.c | 211 +++++++++++++++++++++++++++++++++++++
> src/conf/node_device_conf.h | 9 ++
> src/libvirt_private.syms | 2 +
> src/storage/storage_backend_scsi.c | 192 +++------------------------------
> 4 files changed, 235 insertions(+), 179 deletions(-)
>
> diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
> index 3565aec..66cb78d 100644
> --- a/src/conf/node_device_conf.c
> +++ b/src/conf/node_device_conf.c
> @@ -1870,3 +1870,214 @@ virNodeDeviceGetParentName(virConnectPtr conn,
>
> return parent;
> }
> +
> +
> +/*
> + * Using the host# name found via wwnn/wwpn lookup in the fc_host
> + * sysfs tree to get the parent 'scsi_host#' to ensure it matches.
> + */
> +static bool
> +nodeDeviceCheckParent(virConnectPtr conn,
> + const char *name,
> + const char *parent_name)
> +{
> + char *scsi_host_name = NULL;
> + char *vhba_parent = NULL;
> + bool retval = false;
> +
> + VIR_DEBUG("conn=%p, name=%s, parent_name=%s", conn, name, parent_name);
> +
> + /* autostarted pool - assume we're OK */
> + if (!conn)
> + return true;
> +
> + if (virAsprintf(&scsi_host_name, "scsi_%s", name) < 0)
> + goto cleanup;
> +
> + if (!(vhba_parent = virNodeDeviceGetParentName(conn, scsi_host_name)))
> + goto cleanup;
> +
> + if (STRNEQ(parent_name, vhba_parent)) {
> + virReportError(VIR_ERR_XML_ERROR,
> + _("Parent attribute '%s' does not match parent '%s' "
> + "determined for the '%s' wwnn/wwpn lookup."),
> + parent_name, vhba_parent, name);
> + goto cleanup;
> + }
> +
> + retval = true;
> +
> + cleanup:
> + VIR_FREE(vhba_parent);
> + VIR_FREE(scsi_host_name);
> + return retval;
> +}
> +
> +
> +/**
> + * @conn: Connection pointer
> + * @fchost: Pointer to vHBA adapter
> + *
> + * Create a vHBA for Storage. This code accomplishes this via searching
> + * through the sysfs for scsi_host/fc_host in order to first ensure some
> + * vHBA doesn't already exist for the requested wwnn/wwpn (e.g. an unmanaged
> + * vHBA) and to search for the parent vport capable scsi_host by name,
> + * wwnn/wwpn, or fabric_wwn (if provided). If no parent is provided, then
> + * a vport capable scsi_host will be selected.
> + *
> + * Returns vHBA name on success, NULL on failure with an error message set
> + */
> +char *
> +virNodeDeviceCreateVport(virConnectPtr conn,
> + virStorageAdapterFCHostPtr fchost)
> +{
> + unsigned int parent_host;
> + char *name = NULL;
> + char *parent_hoststr = NULL;
> + bool skip_capable_check = false;
> +
> + VIR_DEBUG("conn=%p, parent='%s', wwnn='%s' wwpn='%s'",
> + conn, NULLSTR(fchost->parent), fchost->wwnn, fchost->wwpn);
> +
> + /* If we find an existing HBA/vHBA within the fc_host sysfs
> + * using the wwnn/wwpn, then a nodedev is already created for
> + * this pool and we don't have to create the vHBA
> + */
> + if ((name = virVHBAGetHostByWWN(NULL, fchost->wwnn, fchost->wwpn))) {
> + /* If a parent was provided, let's make sure the 'name' we've
> + * retrieved has the same parent. If not this will cause failure. */
> + if (fchost->parent && nodeDeviceCheckParent(conn, name, fchost->parent))
> + VIR_FREE(name);
> +
> + return name;
> + }
> +
> + if (fchost->parent) {
> + if (VIR_STRDUP(parent_hoststr, fchost->parent) < 0)
> + goto cleanup;
> + } else if (fchost->parent_wwnn && fchost->parent_wwpn) {
> + if (!(parent_hoststr = virVHBAGetHostByWWN(NULL, fchost->parent_wwnn,
> + fchost->parent_wwpn))) {
> + virReportError(VIR_ERR_XML_ERROR, "%s",
> + _("cannot find parent using provided wwnn/wwpn"));
> + goto cleanup;
> + }
> + } else if (fchost->parent_fabric_wwn) {
> + if (!(parent_hoststr =
> + virVHBAGetHostByFabricWWN(NULL, fchost->parent_fabric_wwn))) {
> + virReportError(VIR_ERR_XML_ERROR, "%s",
> + _("cannot find parent using provided fabric_wwn"));
> + goto cleanup;
> + }
> + } else {
> + if (!(parent_hoststr = virVHBAFindVportHost(NULL))) {
> + virReportError(VIR_ERR_XML_ERROR, "%s",
> + _("'parent' for vHBA not specified, and "
> + "cannot find one on this host"));
> + goto cleanup;
> + }
> + skip_capable_check = true;
> + }
> +
> + if (virSCSIHostGetNumber(parent_hoststr, &parent_host) < 0)
> + goto cleanup;
> +
> + /* NOTE:
> + * We do not save the parent_hoststr in fchost->parent since
> + * we could be writing out the 'def' to the saved XML config.
> + * If we wrote out the name in the XML, then future starts would
> + * always use the same parent rather than finding the "best available"
> + * parent. Besides we have a way to determine the parent based on
> + * the 'name' field.
> + */
> + if (!skip_capable_check && !virVHBAPathExists(NULL, parent_host)) {
> + virReportError(VIR_ERR_XML_ERROR,
> + _("parent '%s' specified for vHBA does not exist"),
> + parent_hoststr);
> + goto cleanup;
> + }
> +
> + if (virVHBAManageVport(parent_host, fchost->wwpn, fchost->wwnn,
> + VPORT_CREATE) < 0)
> + goto cleanup;
> +
> + /* Let's ensure the device was created */
> + virWaitForDevices();
> + if (!(name = virVHBAGetHostByWWN(NULL, fchost->wwnn, fchost->wwpn))) {
> + ignore_value(virVHBAManageVport(parent_host, fchost->wwpn, fchost->wwnn,
> + VPORT_DELETE));
> + goto cleanup;
> + }
> +
> + cleanup:
> + VIR_FREE(parent_hoststr);
> + return name;
> +}
> +
> +
> +/**
> + * @conn: Connection pointer
> + * @fchost: Pointer to vHBA adapter
> + *
> + * As long as the vHBA is being managed, search for the scsi_host via the
> + * provided wwnn/wwpn and then find the corresponding parent scsi_host in
> + * order to send the delete request.
> + *
> + * Returns 0 on success, -1 on failure
> + */
> +int
> +virNodeDeviceDeleteVport(virConnectPtr conn,
> + virStorageAdapterFCHostPtr fchost)
> +{
> + char *name = NULL;
> + char *scsi_host_name = NULL;
> + unsigned int parent_host;
> + char *vhba_parent = NULL;
> + int ret = -1;
> +
> + VIR_DEBUG("conn=%p parent='%s', managed='%d' wwnn='%s' wwpn='%s'",
> + conn, NULLSTR(fchost->parent), fchost->managed,
> + fchost->wwnn, fchost->wwpn);
> +
> + /* If we're not managing the deletion of the vHBA, then just return */
> + if (fchost->managed != VIR_TRISTATE_BOOL_YES)
> + return 0;
> +
> + /* Find our vHBA by searching the fc_host sysfs tree for our wwnn/wwpn */
> + if (!(name = virVHBAGetHostByWWN(NULL, fchost->wwnn, fchost->wwpn))) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Failed to find fc_host for wwnn='%s' and wwpn='%s'"),
> + fchost->wwnn, fchost->wwpn);
> + goto cleanup;
> + }
> +
> + /* If at startup time we provided a parent, then use that to
> + * get the parent_host value; otherwise, we have to determine
> + * the parent scsi_host which we did not save at startup time
> + */
> + if (fchost->parent) {
> + if (virSCSIHostGetNumber(fchost->parent, &parent_host) < 0)
> + goto cleanup;
> + } else {
> + if (virAsprintf(&scsi_host_name, "scsi_%s", name) < 0)
> + goto cleanup;
> +
> + if (!(vhba_parent = virNodeDeviceGetParentName(conn, scsi_host_name)))
> + goto cleanup;
> +
> + if (virSCSIHostGetNumber(vhba_parent, &parent_host) < 0)
> + goto cleanup;
> + }
> +
> + if (virVHBAManageVport(parent_host, fchost->wwpn, fchost->wwnn,
> + VPORT_DELETE) < 0)
> + goto cleanup;
> +
> + ret = 0;
> +
> + cleanup:
> + VIR_FREE(name);
> + VIR_FREE(vhba_parent);
> + VIR_FREE(scsi_host_name);
> + return ret;
> +}
> diff --git a/src/conf/node_device_conf.h b/src/conf/node_device_conf.h
> index cf51c69..15e2eac 100644
> --- a/src/conf/node_device_conf.h
> +++ b/src/conf/node_device_conf.h
> @@ -28,8 +28,11 @@
> # include "internal.h"
> # include "virbitmap.h"
> # include "virutil.h"
> +# include "virscsihost.h"
> # include "virpci.h"
> +# include "virvhba.h"
> # include "device_conf.h"
> +# include "storage_adapter_conf.h"
>
> # include <libxml/tree.h>
>
> @@ -354,4 +357,10 @@ char *
> virNodeDeviceGetParentName(virConnectPtr conn,
> const char *nodedev_name);
>
> +char *virNodeDeviceCreateVport(virConnectPtr conn,
> + virStorageAdapterFCHostPtr fchost);
> +
> +int virNodeDeviceDeleteVport(virConnectPtr conn,
> + virStorageAdapterFCHostPtr fchost);
> +
> #endif /* __VIR_NODE_DEVICE_CONF_H__ */
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index 7bdcde7..cacc7aa 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -686,11 +686,13 @@ virNetDevIPRouteParseXML;
> virNodeDevCapsDefFree;
> virNodeDevCapTypeFromString;
> virNodeDevCapTypeToString;
> +virNodeDeviceCreateVport;
> virNodeDeviceDefFormat;
> virNodeDeviceDefFree;
> virNodeDeviceDefParseFile;
> virNodeDeviceDefParseNode;
> virNodeDeviceDefParseString;
> +virNodeDeviceDeleteVport;
> virNodeDeviceGetParentName;
> virNodeDeviceGetWWNs;
>
> diff --git a/src/storage/storage_backend_scsi.c b/src/storage/storage_backend_scsi.c
> index abbd38d..666e473 100644
> --- a/src/storage/storage_backend_scsi.c
> +++ b/src/storage/storage_backend_scsi.c
> @@ -33,9 +33,7 @@
> #include "virlog.h"
> #include "virfile.h"
> #include "vircommand.h"
> -#include "virscsihost.h"
> #include "virstring.h"
> -#include "virvhba.h"
> #include "storage_util.h"
> #include "node_device_conf.h"
>
> @@ -214,57 +212,13 @@ getAdapterName(virStorageAdapterPtr adapter)
> return name;
> }
>
> -/*
> - * Using the host# name found via wwnn/wwpn lookup in the fc_host
> - * sysfs tree to get the parent 'scsi_host#' to ensure it matches.
> - */
> -static bool
> -checkParent(virConnectPtr conn,
> - const char *name,
> - const char *parent_name)
> -{
> - char *scsi_host_name = NULL;
> - char *vhba_parent = NULL;
> - bool retval = false;
> -
> - VIR_DEBUG("conn=%p, name=%s, parent_name=%s", conn, name, parent_name);
> -
> - /* autostarted pool - assume we're OK */
> - if (!conn)
> - return true;
> -
> - if (virAsprintf(&scsi_host_name, "scsi_%s", name) < 0)
> - goto cleanup;
> -
> - if (!(vhba_parent = virNodeDeviceGetParentName(conn, scsi_host_name)))
> - goto cleanup;
> -
> - if (STRNEQ(parent_name, vhba_parent)) {
> - virReportError(VIR_ERR_XML_ERROR,
> - _("Parent attribute '%s' does not match parent '%s' "
> - "determined for the '%s' wwnn/wwpn lookup."),
> - parent_name, vhba_parent, name);
> - goto cleanup;
> - }
> -
> - retval = true;
> -
> - cleanup:
> - VIR_FREE(vhba_parent);
> - VIR_FREE(scsi_host_name);
> - return retval;
> -}
> -
> static int
> createVport(virConnectPtr conn,
> virStoragePoolDefPtr def,
> const char *configFile,
> virStorageAdapterFCHostPtr fchost)
> {
> - unsigned int parent_host;
> char *name = NULL;
> - char *parent_hoststr = NULL;
> - bool skip_capable_check = false;
> virStoragePoolFCRefreshInfoPtr cbdata = NULL;
> virThread thread;
> int ret = -1;
> @@ -273,66 +227,11 @@ createVport(virConnectPtr conn,
> conn, NULLSTR(configFile), NULLSTR(fchost->parent),
> fchost->wwnn, fchost->wwpn);
>
> - /* If we find an existing HBA/vHBA within the fc_host sysfs
> - * using the wwnn/wwpn, then a nodedev is already created for
> - * this pool and we don't have to create the vHBA
> - */
> - if ((name = virVHBAGetHostByWWN(NULL, fchost->wwnn, fchost->wwpn))) {
> - /* If a parent was provided, let's make sure the 'name' we've
> - * retrieved has the same parent
> - */
> - if (fchost->parent && checkParent(conn, name, fchost->parent))
> - ret = 0;
>
> + if (!(name = virNodeDeviceCreateVport(conn, fchost)))
> goto cleanup;
> - }
>
> - if (fchost->parent) {
> - if (VIR_STRDUP(parent_hoststr, fchost->parent) < 0)
> - goto cleanup;
> - } else if (fchost->parent_wwnn && fchost->parent_wwpn) {
> - if (!(parent_hoststr = virVHBAGetHostByWWN(NULL, fchost->parent_wwnn,
> - fchost->parent_wwpn))) {
> - virReportError(VIR_ERR_XML_ERROR, "%s",
> - _("cannot find parent using provided wwnn/wwpn"));
> - goto cleanup;
> - }
> - } else if (fchost->parent_fabric_wwn) {
> - if (!(parent_hoststr =
> - virVHBAGetHostByFabricWWN(NULL, fchost->parent_fabric_wwn))) {
> - virReportError(VIR_ERR_XML_ERROR, "%s",
> - _("cannot find parent using provided fabric_wwn"));
> - goto cleanup;
> - }
> - } else {
> - if (!(parent_hoststr = virVHBAFindVportHost(NULL))) {
> - virReportError(VIR_ERR_XML_ERROR, "%s",
> - _("'parent' for vHBA not specified, and "
> - "cannot find one on this host"));
> - goto cleanup;
> - }
> - skip_capable_check = true;
> - }
> -
> - if (virSCSIHostGetNumber(parent_hoststr, &parent_host) < 0)
> - goto cleanup;
> -
> - /* NOTE:
> - * We do not save the parent_hoststr in fchost->parent since
> - * we could be writing out the 'def' to the saved XML config.
> - * If we wrote out the name in the XML, then future starts would
> - * always use the same parent rather than finding the "best available"
> - * parent. Besides we have a way to determine the parent based on
> - * the 'name' field.
> - */
> - if (!skip_capable_check && !virVHBAPathExists(NULL, parent_host)) {
> - virReportError(VIR_ERR_XML_ERROR,
> - _("parent '%s' specified for vHBA does not exist"),
> - parent_hoststr);
> - goto cleanup;
> - }
> -
> - /* Since we're creating the vHBA, then we need to manage removing it
> + /* Since we've created the vHBA, then we need to manage removing it
> * as well. Since we need this setting to "live" through a libvirtd
> * restart, we need to save the persistent configuration. So if not
> * already defined as YES, then force the issue.
> @@ -345,28 +244,20 @@ createVport(virConnectPtr conn,
Right in this space the old code would set managed = YES and call virStoragePoolSaveConfig(). That is now done *after calling virVHBAManageVport() (whatever *that* does) and a few other things from post-saveconfig that have been moed into virNodeDeviceCreateVport(). I just want a confirmation that this change in ordering won't cause a problem...
> }
> }
>
> - if (virVHBAManageVport(parent_host, fchost->wwpn, fchost->wwnn,
> - VPORT_CREATE) < 0)
> - goto cleanup;
> -
> - virWaitForDevices();
> -
> /* Creating our own VPORT didn't leave enough time to find any LUN's,
> * so, let's create a thread whose job it is to call the FindLU's with
> * retry logic set to true. If the thread isn't created, then no big
> * deal since it's still possible to refresh the pool later.
> */
> - if ((name = virVHBAGetHostByWWN(NULL, fchost->wwnn, fchost->wwpn))) {
> - if (VIR_ALLOC(cbdata) == 0) {
> - memcpy(cbdata->pool_uuid, def->uuid, VIR_UUID_BUFLEN);
> - VIR_STEAL_PTR(cbdata->fchost_name, name);
> -
> - if (virThreadCreate(&thread, false, virStoragePoolFCRefreshThread,
> - cbdata) < 0) {
> - /* Oh well - at least someone can still refresh afterwards */
> - VIR_DEBUG("Failed to create FC Pool Refresh Thread");
> - virStoragePoolFCRefreshDataFree(cbdata);
> - }
Okay, since a failure of virVHBAGetHostByWWN() in virNodeDeviceCreateVport() would have resulted in an early return, it's okay to move all of this outside the conditional (which no longer exists!)
Everything looks like a simple hatchet and stitch job to me - ACK.
> + if (VIR_ALLOC(cbdata) == 0) {
> + memcpy(cbdata->pool_uuid, def->uuid, VIR_UUID_BUFLEN);
> + VIR_STEAL_PTR(cbdata->fchost_name, name);
> +
> + if (virThreadCreate(&thread, false, virStoragePoolFCRefreshThread,
> + cbdata) < 0) {
> + /* Oh well - at least someone can still refresh afterwards */
> + VIR_DEBUG("Failed to create FC Pool Refresh Thread");
> + virStoragePoolFCRefreshDataFree(cbdata);
> }
> }
>
> @@ -374,64 +265,6 @@ createVport(virConnectPtr conn,
>
> cleanup:
> VIR_FREE(name);
> - VIR_FREE(parent_hoststr);
> - return ret;
> -}
> -
> -
> -static int
> -deleteVport(virConnectPtr conn,
> - virStorageAdapterFCHostPtr fchost)
> -{
> - unsigned int parent_host;
> - char *name = NULL;
> - char *scsi_host_name = NULL;
> - char *vhba_parent = NULL;
> - int ret = -1;
> -
> - VIR_DEBUG("conn=%p parent='%s', managed='%d' wwnn='%s' wwpn='%s'",
> - conn, NULLSTR(fchost->parent), fchost->managed,
> - fchost->wwnn, fchost->wwpn);
> -
> - /* If we're not managing the deletion of the vHBA, then just return */
> - if (fchost->managed != VIR_TRISTATE_BOOL_YES)
> - return 0;
> -
> - /* Find our vHBA by searching the fc_host sysfs tree for our wwnn/wwpn */
> - if (!(name = virVHBAGetHostByWWN(NULL, fchost->wwnn, fchost->wwpn))) {
> - virReportError(VIR_ERR_INTERNAL_ERROR,
> - _("Failed to find fc_host for wwnn='%s' and wwpn='%s'"),
> - fchost->wwnn, fchost->wwpn);
> - goto cleanup;
> - }
> -
> - /* If at startup time we provided a parent, then use that to
> - * get the parent_host value; otherwise, we have to determine
> - * the parent scsi_host which we did not save at startup time
> - */
> - if (fchost->parent) {
> - if (virSCSIHostGetNumber(fchost->parent, &parent_host) < 0)
> - goto cleanup;
> - } else {
> - if (virAsprintf(&scsi_host_name, "scsi_%s", name) < 0)
> - goto cleanup;
> -
> - if (!(vhba_parent = virNodeDeviceGetParentName(conn, scsi_host_name)))
> - goto cleanup;
> -
> - if (virSCSIHostGetNumber(vhba_parent, &parent_host) < 0)
> - goto cleanup;
> - }
> -
> - if (virVHBAManageVport(parent_host, fchost->wwpn, fchost->wwnn,
> - VPORT_DELETE) < 0)
> - goto cleanup;
> -
> - ret = 0;
> - cleanup:
> - VIR_FREE(name);
> - VIR_FREE(vhba_parent);
> - VIR_FREE(scsi_host_name);
> return ret;
> }
>
> @@ -525,7 +358,8 @@ virStorageBackendSCSIStopPool(virConnectPtr conn,
> virStoragePoolObjPtr pool)
> {
> if (pool->def->source.adapter.type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST)
> - return deleteVport(conn, &pool->def->source.adapter.data.fchost);
> + return virNodeDeviceDeleteVport(conn,
> + &pool->def->source.adapter.data.fchost);
>
> return 0;
> }
More information about the libvir-list
mailing list