[libvirt] [PATCH 5/7] util: Add helper to get the scsi host name by iterating over sysfs
Osier Yang
jyang at redhat.com
Mon Apr 8 10:03:10 UTC 2013
On 06/04/13 03:11, John Ferlan wrote:
> On 03/25/2013 12:43 PM, Osier Yang wrote:
>> 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 | 49 ++++++++++++++---
>> src/util/virutil.c | 109 +++++++++++++++++++++++++++++++++++++
>> src/util/virutil.h | 9 ++-
>> 4 files changed, 159 insertions(+), 9 deletions(-)
>>
>> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
>> index 39c02ad..3df7632 100644
>> --- a/src/libvirt_private.syms
>> +++ b/src/libvirt_private.syms
>> @@ -1854,6 +1854,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 1bf6c0b..258c82e 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");
> How is this related? Or even possible? The number is associated (at
> least so far) with the SCSI "name" parameter which isn't used for FC.
> Both callers below still only call here iff it's SCSI_HOST.
I use getHostNumber after getAdapterName, which suits for
both scsi_host and fc_host. :-)
>
>> } else if (STRPREFIX(host, "host")) {
>> host += strlen("host");
>> } else {
>> @@ -622,42 +624,74 @@ 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 NULL;
> superfluous since name = NULL... :-)
Cleaned.
>
>> + }
>> +
>> + 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 +703,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 557225c..a8b9962 100644
>> --- a/src/util/virutil.c
>> +++ b/src/util/virutil.c
>> @@ -26,6 +26,7 @@
>>
>> #include <config.h>
>>
>> +#include <dirent.h>
>> #include <stdio.h>
>> #include <stdarg.h>
>> #include <stdlib.h>
>> @@ -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; \
> suggestions:
> 1. Add another parameter to take wwnn or wwpn (ww_name?)
> 2. VIR_FREE(wwn_path) here
> 3. VIR_FREE(buf) here too
> 4. You could probably put the virFileExists check in this macro too -
> appropriately placed of course. It'd only need to free the _path
> generated from virAsprintf().
>
> VIR_FREE(wwn_path); \
> if (STRNEQ(ww_name, p)) { \
> VIR_FREE(buf); \
> continue; \
This will just jump out this "do...while" loop, perhaps there is
a way to work around. If it is, let's do in a later patch.
> } \
> VIR_FREE(buf); \
>
> I think this works - you can double check my eyesight though. After you
> exit the macro, neither the virAsprintf buffer nor the virFileReadAll
> buffers will still be allocated. Thus reducing the need for keeping
> track...
>
>> + } 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(wwpn_buf);
> In any case:
>
> s/wwpn_buf/wwnn_buf
>
> right?
Right, cleaned.
>
>> + 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);
>> + goto cleanup;
> s/goto cleanup/break
>
> Same difference...
Cleaned.
>> + }
>> +
>> +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,
>> @@ -3606,4 +3706,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 47357fa..d134034 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__ */
>>
> ACK - with a bit of cleanup. Depending on responses and path chosen, a
> followup could be done.
>
> John
>
> --
> libvir-list mailing list
> libvir-list at redhat.com
> https://www.redhat.com/mailman/listinfo/libvir-list
More information about the libvir-list
mailing list