diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 8e4e52d1cae01ec9c5ab32094528ae799f512212..c5b9cee45e067a653aedf84a6baa8b4062319e17 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2667,6 +2667,7 @@ virGetDeviceID; virGetDeviceUnprivSGIO; virGetEnvAllowSUID; virGetEnvBlockSUID; +virGetFCHostNameByFabricWWN; virGetFCHostNameByWWN; virGetGroupID; virGetGroupList; diff --git a/src/util/virutil.c b/src/util/virutil.c index 701c382a5dde46812ecb187b9c71548f77d1e815..da836b46d3d5669442971d11a5f8f3170c6839b6 100644 --- a/src/util/virutil.c +++ b/src/util/virutil.c @@ -2166,6 +2166,60 @@ virManageVport(const int parent_host, return ret; } + +/* virReadCompareWWN + * @prefix: path to the wwn file + * @d_name: name of the current directory + * @f_name: file name to read + * + * Read/compare the on-disk file with the passed wwn value. + * + * Returns: + * -1 : Error + * 0 : No match + * 1 : Match + */ +static int +virReadCompareWWN(const char *prefix, + const char *d_name, + const char *f_name, + const char *wwn) +{ + char *path; + char *buf = NULL; + char *p; + int ret = -1; + + if (virAsprintf(&path, "%s/%s/%s", prefix, d_name, f_name) < 0) + return -1; + + if (!virFileExists(path)) { + ret = 0; + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((p = strchr(buf, '\n'))) + *p = '\0'; + if (STRPREFIX(buf, "0x")) + p = buf + strlen("0x"); + else + p = buf; + + if (STRNEQ(wwn, p)) + ret = 0; + else + ret = 1; + + cleanup: + VIR_FREE(path); + VIR_FREE(buf); + + return ret; +} + /* virGetFCHostNameByWWN: * * Iterate over the sysfs tree to get FC host name (e.g. host5) @@ -2182,56 +2236,77 @@ virGetFCHostNameByWWN(const char *sysfs_prefix, 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 (virDirOpen(&dir, prefix) < 0) 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 (virDirRead(dir, &entry, prefix) > 0) { - VIR_FREE(wwnn_buf); - VIR_FREE(wwnn_path); - VIR_FREE(wwpn_buf); - VIR_FREE(wwpn_path); + int rc; - if (virAsprintf(&wwnn_path, "%s/%s/node_name", prefix, - entry->d_name) < 0) + if ((rc = virReadCompareWWN(prefix, entry->d_name, + "node_name", wwnn)) < 0) goto cleanup; - if (!virFileExists(wwnn_path)) + if (rc == 0) continue; - READ_WWN(wwnn_path, wwnn_buf); + if ((rc = virReadCompareWWN(prefix, entry->d_name, + "port_name", wwpn)) < 0) + goto cleanup; - if (STRNEQ(wwnn, p)) + if (rc == 0) continue; - if (virAsprintf(&wwpn_path, "%s/%s/port_name", prefix, + ignore_value(VIR_STRDUP(ret, entry->d_name)); + break; + } + + cleanup: + VIR_DIR_CLOSE(dir); + return ret; +} + +/* virGetFCHostNameByFabricWWN: + * + * Iterate over the sysfs tree to get FC host name (e.g. host5) + * by the provided "fabric_wwn". This would find a host on a SAN. + * + * Returns the FC host name which must be freed by the caller, + * or NULL on failure. + */ +char * +virGetFCHostNameByFabricWWN(const char *sysfs_prefix, + const char *fabric_wwn) +{ + const char *prefix = sysfs_prefix ? sysfs_prefix : SYSFS_FC_HOST_PATH; + struct dirent *entry = NULL; + DIR *dir = NULL; + char *vport_create_path = NULL; + char *ret = NULL; + + if (virDirOpen(&dir, prefix) < 0) + return NULL; + + while (virDirRead(dir, &entry, prefix) > 0) { + int rc; + + VIR_FREE(vport_create_path); + + /* Existing vHBA's will have the same fabric_name, but won't + * have the vport_create file - so we check for both */ + if (virAsprintf(&vport_create_path, "%s/%s/vport_create", prefix, entry->d_name) < 0) goto cleanup; - if (!virFileExists(wwpn_path)) + if (!virFileExists(vport_create_path)) continue; - READ_WWN(wwpn_path, wwpn_buf); + if ((rc = virReadCompareWWN(prefix, entry->d_name, + "fabric_name", fabric_wwn)) < 0) + goto cleanup; - if (STRNEQ(wwpn, p)) + if (rc == 0) continue; ignore_value(VIR_STRDUP(ret, entry->d_name)); @@ -2239,12 +2314,8 @@ virGetFCHostNameByWWN(const char *sysfs_prefix, } cleanup: -# undef READ_WWN VIR_DIR_CLOSE(dir); - VIR_FREE(wwnn_path); - VIR_FREE(wwpn_path); - VIR_FREE(wwnn_buf); - VIR_FREE(wwpn_buf); + VIR_FREE(vport_create_path); return ret; } diff --git a/src/util/virutil.h b/src/util/virutil.h index 8c0d83c9a5748e9c54aa96f9149c7e671cd9beb4..3fbd7b0688a0390781dc5c32a511497df7fcefc6 100644 --- a/src/util/virutil.h +++ b/src/util/virutil.h @@ -206,6 +206,10 @@ char *virGetFCHostNameByWWN(const char *sysfs_prefix, const char *wwpn) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); +char *virGetFCHostNameByFabricWWN(const char *sysfs_prefix, + const char *fabric_wwn) + ATTRIBUTE_NONNULL(2); + char *virFindFCHostCapableVport(const char *sysfs_prefix); int virParseOwnershipIds(const char *label, uid_t *uidPtr, gid_t *gidPtr);