This finds the parent for vHBA by iterating over all the HBA which supports vport_ops capability on the host, and return the first one which is online, not saturated (vports in use is less than max_vports). --- docs/formatstorage.html.in | 3 +- src/libvirt_private.syms | 1 + src/storage/storage_backend_scsi.c | 10 +++-- src/util/virutil.c | 83 ++++++++++++++++++++++++++++++++++++ src/util/virutil.h | 2 + 5 files changed, 93 insertions(+), 6 deletions(-) diff --git a/docs/formatstorage.html.in b/docs/formatstorage.html.in index af42fed..7315865 100644 --- a/docs/formatstorage.html.in +++ b/docs/formatstorage.html.in @@ -99,8 +99,7 @@ <code>wwpn</code> (<span class="since">1.0.2</span>) indicates the (v)HBA. The optional attribute <code>parent</code> (<span class="since">1.0.2</span>) specifies the parent device of - the (v)HBA. It's optional for HBA, but required for vHBA. - <span class="since">Since 0.6.2</span></dd> + the (v)HBA. <span class="since">Since 0.6.2</span></dd> <dt><code>host</code></dt> <dd>Provides the source for pools backed by storage from a remote server. Will be used in combination with a <code>directory</code> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 7334e15..759d630 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1841,6 +1841,7 @@ virFileStripSuffix; virFileUnlock; virFileWaitForDevices; virFileWriteStr; +virFindFCHostCapableVport; virFindFileInPath; virFormatIntDecimal; virGetDeviceID; diff --git a/src/storage/storage_backend_scsi.c b/src/storage/storage_backend_scsi.c index a9b96a3..59abeb0 100644 --- a/src/storage/storage_backend_scsi.c +++ b/src/storage/storage_backend_scsi.c @@ -646,10 +646,12 @@ createVport(virStoragePoolSourceAdapter adapter) adapter.data.fchost.wwpn)) return 0; - if (!adapter.data.fchost.parent) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("'parent' for vHBA must be specified")); - return -1; + if (!adapter.data.fchost.parent && + !(adapter.data.fchost.parent = virFindFCHostCapableVport(NULL))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("'parent' for vHBA not specified, and " + "cannot find one on this host")); + return -1; } if ((parent_host = getHostNumber(adapter.data.fchost.parent)) < 0) diff --git a/src/util/virutil.c b/src/util/virutil.c index 3073337..b9a6166 100644 --- a/src/util/virutil.c +++ b/src/util/virutil.c @@ -3555,6 +3555,82 @@ cleanup: VIR_FREE(wwpn_buf); return ret; } + +# define PORT_STATE_ONLINE "Online" + +/* virFindFCHostCapableVport: + * + * Iterate over the sysfs and find out the first online HBA which + * supports vport, and not saturated,. + */ +char * +virFindFCHostCapableVport(const char *sysfs_prefix) +{ + const char *prefix = sysfs_prefix ? sysfs_prefix : SYSFS_FC_HOST_PATH; + DIR *dir = NULL; + struct dirent *entry = NULL; + char *max_vports = NULL; + char *vports = NULL; + char *state = NULL; + char *ret = NULL; + + if (!(dir = opendir(prefix))) { + virReportSystemError(errno, + _("Failed to opendir path '%s'"), + prefix); + return NULL; + } + + while ((entry = readdir(dir))) { + if (STREQ(entry->d_name, ".") || STREQ(entry->d_name, "..")) + continue; + + int host; + + ignore_value(sscanf(entry->d_name, "host%d", &host)); + if (!virIsCapableVport(NULL, host)) + continue; + + if (virReadFCHost(NULL, host, "port_state", &state) < 0) { + VIR_DEBUG("Failed to read port_state for host%d", host); + continue; + } + + /* Skip the not online FC host */ + if (!STREQ(state, PORT_STATE_ONLINE)) { + VIR_FREE(state); + continue; + } + VIR_FREE(state); + + if (virReadFCHost(NULL, host, "max_npiv_vports", &max_vports) < 0) { + VIR_DEBUG("Failed to read max_npiv_vports for host%d", host); + continue; + } + + if (virReadFCHost(NULL, host, "npiv_vports_inuse", &vports) < 0) { + VIR_DEBUG("Failed to read npiv_vports_inuse for host%d", host); + VIR_FREE(max_vports); + continue; + } + + if ((strlen(max_vports) > strlen(vports)) || + ((strlen(max_vports) == strlen(vports)) && + strcmp(max_vports, vports) > 0)) { + ret = strdup(entry->d_name); + goto cleanup; + } + + VIR_FREE(max_vports); + VIR_FREE(vports); + } + +cleanup: + closedir(dir); + VIR_FREE(max_vports); + VIR_FREE(vports); + return ret; +} #else int virReadFCHost(const char *sysfs_prefix ATTRIBUTE_UNUSED, @@ -3600,4 +3676,11 @@ virGetFCHostNameByWWN(const char *sysfs_prefix ATTRIBUTE_UNUSED, return NULL; } +char * +virFindFCHostCapableVport(const char *sysfs_prefix ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", _("Not supported on this platform")); + return NULL; +} + #endif /* __linux__ */ diff --git a/src/util/virutil.h b/src/util/virutil.h index 78b50a8..3a68134 100644 --- a/src/util/virutil.h +++ b/src/util/virutil.h @@ -320,4 +320,6 @@ char * virGetFCHostNameByWWN(const char *sysfs_prefix, const char *wwpn) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); +char * virFindFCHostCapableVport(const char *sysfs_prefix ); + #endif /* __VIR_UTIL_H__ */ -- 1.7.7.6 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list