From b52fbad1504260fe75e2123fbfdea7db6784470b Mon Sep 17 00:00:00 2001 From: Osier Yang Date: Tue, 26 Mar 2013 00:43:40 +0800 Subject: [PATCH] util: Add helper to get the scsi host name by iterating over sysfs The helper iterates over sysfs, to find out the matched scsi host name by comparing the wwnn,wwpn pair. It will be used by checkPool and refreshPool of storage scsi backend. New helper getAdapterName is introduced in storage_backend_scsi.c, which uses the new util helper virGetFCHostNameByWWN to get the fc_host adapter name. --- src/libvirt_private.syms | 1 + src/storage/storage_backend_scsi.c | 48 +++++++++++-- src/util/virutil.c | 109 +++++++++++++++++++++++++++++ src/util/virutil.h | 9 ++- 4 files changed, 158 insertions(+), 9 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 4850fad8bc..cd4eb927e2 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1856,6 +1856,7 @@ virFindFileInPath; virFormatIntDecimal; virGetDeviceID; virGetDeviceUnprivSGIO; +virGetFCHostNameByWWN; virGetGroupID; virGetGroupName; virGetHostname; diff --git a/src/storage/storage_backend_scsi.c b/src/storage/storage_backend_scsi.c index 67cb01dd8c..275458b32f 100644 --- a/src/storage/storage_backend_scsi.c +++ b/src/storage/storage_backend_scsi.c @@ -603,6 +603,8 @@ getHostNumber(const char *adapter_name, */ if (STRPREFIX(host, "scsi_host")) { host += strlen("scsi_host"); + } else if (STRPREFIX(host, "fc_host")) { + host += strlen("fc_host"); } else if (STRPREFIX(host, "host")) { host += strlen("host"); } else { @@ -622,42 +624,73 @@ getHostNumber(const char *adapter_name, return 0; } +static char * +getAdapterName(virStoragePoolSourceAdapter adapter) +{ + char *name = NULL; + + if (adapter.type != VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) + return strdup(adapter.data.name); + + if (!(name = virGetFCHostNameByWWN(NULL, + adapter.data.fchost.wwnn, + adapter.data.fchost.wwpn))) { + virReportError(VIR_ERR_XML_ERROR, + _("Failed to find SCSI host with wwnn='%s', " + "wwpn='%s'"), adapter.data.fchost.wwnn, + adapter.data.fchost.wwpn); + } + + return name; +} + static int virStorageBackendSCSICheckPool(virConnectPtr conn ATTRIBUTE_UNUSED, virStoragePoolObjPtr pool, bool *isActive) { - char *path; + char *path = NULL; + char *name = NULL; unsigned int host; + int ret = -1; *isActive = false; - if (getHostNumber(pool->def->source.adapter.data.name, &host) < 0) + if (!(name = getAdapterName(pool->def->source.adapter))) return -1; + if (getHostNumber(name, &host) < 0) + goto cleanup; + if (virAsprintf(&path, "/sys/class/scsi_host/host%d", host) < 0) { virReportOOMError(); - return -1; + goto cleanup; } if (access(path, F_OK) == 0) *isActive = true; + ret = 0; +cleanup: VIR_FREE(path); - - return 0; + VIR_FREE(name); + return ret; } static int virStorageBackendSCSIRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED, virStoragePoolObjPtr pool) { - int ret = -1; + char *name = NULL; unsigned int host; + int ret = -1; pool->def->allocation = pool->def->capacity = pool->def->available = 0; - if (getHostNumber(pool->def->source.adapter.data.name, &host) < 0) + if (!(name = getAdapterName(pool->def->source.adapter))) + return -1; + + if (getHostNumber(name, &host) < 0) goto out; VIR_DEBUG("Scanning host%u", host); @@ -669,6 +702,7 @@ virStorageBackendSCSIRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED, ret = 0; out: + VIR_FREE(name); return ret; } diff --git a/src/util/virutil.c b/src/util/virutil.c index 87a97c9a0a..46f17456b2 100644 --- a/src/util/virutil.c +++ b/src/util/virutil.c @@ -26,6 +26,7 @@ #include +#include #include #include #include @@ -3570,6 +3571,105 @@ cleanup: VIR_FREE(operation_path); return ret; } + +/* virGetHostNameByWWN: + * + * Iterate over the sysfs tree to get SCSI host name (e.g. scsi_host5) + * by wwnn,wwpn pair. + */ +char * +virGetFCHostNameByWWN(const char *sysfs_prefix, + const char *wwnn, + const char *wwpn) +{ + const char *prefix = sysfs_prefix ? sysfs_prefix : SYSFS_FC_HOST_PATH; + struct dirent *entry = NULL; + DIR *dir = NULL; + char *wwnn_path = NULL; + char *wwpn_path = NULL; + char *wwnn_buf = NULL; + char *wwpn_buf = NULL; + char *p; + char *ret = NULL; + + if (!(dir = opendir(prefix))) { + virReportSystemError(errno, + _("Failed to opendir path '%s'"), + prefix); + return NULL; + } + +# define READ_WWN(wwn_path, buf) \ + do { \ + if (virFileReadAll(wwn_path, 1024, &buf) < 0) \ + goto cleanup; \ + if ((p = strchr(buf, '\n'))) \ + *p = '\0'; \ + if (STRPREFIX(buf, "0x")) \ + p = buf + strlen("0x"); \ + else \ + p = buf; \ + } while (0) + + while ((entry = readdir(dir))) { + if (entry->d_name[0] == '.') + continue; + + if (virAsprintf(&wwnn_path, "%s%s/node_name", prefix, + entry->d_name) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (!virFileExists(wwnn_path)) { + VIR_FREE(wwnn_path); + continue; + } + + READ_WWN(wwnn_path, wwnn_buf); + + if (STRNEQ(wwnn, p)) { + VIR_FREE(wwnn_buf); + VIR_FREE(wwnn_path); + continue; + } + + if (virAsprintf(&wwpn_path, "%s%s/port_name", prefix, + entry->d_name) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (!virFileExists(wwpn_path)) { + VIR_FREE(wwnn_buf); + VIR_FREE(wwnn_path); + VIR_FREE(wwpn_path); + continue; + } + + READ_WWN(wwpn_path, wwpn_buf); + + if (STRNEQ(wwpn, p)) { + VIR_FREE(wwnn_path); + VIR_FREE(wwpn_path); + VIR_FREE(wwnn_buf); + VIR_FREE(wwpn_buf); + continue; + } + + ret = strdup(entry->d_name); + break; + } + +cleanup: +# undef READ_WWN + closedir(dir); + VIR_FREE(wwnn_path); + VIR_FREE(wwpn_path); + VIR_FREE(wwnn_buf); + VIR_FREE(wwpn_buf); + return ret; +} #else int virReadFCHost(const char *sysfs_prefix ATTRIBUTE_UNUSED, @@ -3607,4 +3707,13 @@ virManageVport(const int parent_host ATTRIBUTE_UNUSED, return -1; } +char * +virGetFCHostNameByWWN(const char *sysfs_prefix ATTRIBUTE_UNUSED, + const char *wwnn ATTRIBUTE_UNUSED, + const char *wwpn 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 2a797cb28e..2aa4f2c7a5 100644 --- a/src/util/virutil.h +++ b/src/util/virutil.h @@ -295,8 +295,8 @@ int virSetDeviceUnprivSGIO(const char *path, int virGetDeviceUnprivSGIO(const char *path, const char *sysfs_dir, int *unpriv_sgio); -char * virGetUnprivSGIOSysfsPath(const char *path, - const char *sysfs_dir); +char *virGetUnprivSGIOSysfsPath(const char *path, + const char *sysfs_dir); int virReadFCHost(const char *sysfs_prefix, int host, const char *entry, @@ -317,4 +317,9 @@ int virManageVport(const int parent_host, int operation) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); +char *virGetFCHostNameByWWN(const char *sysfs_prefix, + const char *wwnn, + const char *wwpn) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); + #endif /* __VIR_UTIL_H__ */