Introduce a new function to parse the provided scsi_host parent address and unique_id value in order to find the /sys/class/scsi_host directory which will allow a stable SCSI host address Add a test to scsihosttest to lookup the host# name by using the PCI address and unique_id value Signed-off-by: John Ferlan <jferlan@xxxxxxxxxx> --- docs/formatstorage.html.in | 5 ++- src/libvirt_private.syms | 1 + src/util/virutil.c | 101 +++++++++++++++++++++++++++++++++++++++++++++ src/util/virutil.h | 4 ++ tests/scsihosttest.c | 54 ++++++++++++++++++++++++ 5 files changed, 164 insertions(+), 1 deletion(-) diff --git a/docs/formatstorage.html.in b/docs/formatstorage.html.in index d0c111e..295c27f 100644 --- a/docs/formatstorage.html.in +++ b/docs/formatstorage.html.in @@ -226,7 +226,10 @@ For a PCI address of "0000:00:1f:2", the unique identifer files can be found using the command <code>find -H /sys/class/scsi_host/host*/unique_id | - xargs grep '[0-9]'</code>. + xargs grep '[0-9]'</code>. Optionally, the + <code>virsh nodedev-dumpxml scsi_hostN</code>' of a + specific scsi_hostN list entry will list the + <code>unique_id</code> value. </dd> </dl> </dd> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index bf365ac..4aa41bf 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2088,6 +2088,7 @@ virDoubleToStr; virEnumFromString; virEnumToString; virFindFCHostCapableVport; +virFindSCSIHostByPCI; virFormatIntDecimal; virGetDeviceID; virGetDeviceUnprivSGIO; diff --git a/src/util/virutil.c b/src/util/virutil.c index c73ce06..350b6fe 100644 --- a/src/util/virutil.c +++ b/src/util/virutil.c @@ -1725,6 +1725,98 @@ virReadSCSIUniqueId(const char *sysfs_prefix, return ret; } +/* virFindSCSIHostByPCI: + * @sysfs_prefix: "scsi_host" sysfs path, defaults to SYSFS_SCSI_HOST_PATH + * @parentaddr: string of the PCI address "scsi_host" device to be found + * @unique_id: unique_id value of the to be found "scsi_host" device + * @result: Return the host# of the matching "scsi_host" device + * + * Iterate over the SYSFS_SCSI_HOST_PATH entries looking for a matching + * PCI Address in the expected format (dddd:bb:ss.f, where 'dddd' is the + * 'domain' value, 'bb' is the 'bus' value, 'ss' is the 'slot' value, and + * 'f' is the 'function' value from the PCI address) with a unique_id file + * entry having the value expected. Unlike virReadSCSIUniqueId() we don't + * have a host number yet and that's what we're looking for. + * + * Returns the host name of the "scsi_host" which must be freed by the caller, + * or NULL on failure + */ +char * +virFindSCSIHostByPCI(const char *sysfs_prefix, + const char *parentaddr, + unsigned int unique_id) +{ + const char *prefix = sysfs_prefix ? sysfs_prefix : SYSFS_SCSI_HOST_PATH; + struct dirent *entry = NULL; + DIR *dir = NULL; + char *host_link = NULL; + char *host_path = NULL; + char *p = NULL; + char *ret = NULL; + char *buf = NULL; + char *unique_path = NULL; + unsigned int read_unique_id; + + if (!(dir = opendir(prefix))) { + virReportSystemError(errno, + _("Failed to opendir path '%s'"), + prefix); + goto cleanup; + } + + while (virDirRead(dir, &entry, prefix) > 0) { + if (entry->d_name[0] == '.' || !virFileIsLink(entry->d_name)) + continue; + + if (virAsprintf(&host_link, "%s/%s", prefix, entry->d_name) < 0) + goto cleanup; + + if (virFileResolveLink(host_link, &host_path) < 0) + goto cleanup; + + if (!strstr(host_path, parentaddr)) { + VIR_FREE(host_link); + VIR_FREE(host_path); + continue; + } + VIR_FREE(host_link); + VIR_FREE(host_path); + + if (virAsprintf(&unique_path, "%s/%s/unique_id", prefix, + entry->d_name) < 0) + goto cleanup; + + if (!virFileExists(unique_path)) { + VIR_FREE(unique_path); + continue; + } + + if (virFileReadAll(unique_path, 1024, &buf) < 0) + goto cleanup; + + if ((p = strchr(buf, '\n'))) + *p = '\0'; + + if (virStrToLong_ui(buf, NULL, 10, &read_unique_id) < 0) + goto cleanup; + + if (read_unique_id != unique_id) { + VIR_FREE(unique_path); + continue; + } + + ignore_value(VIR_STRDUP(ret, entry->d_name)); + break; + } + + cleanup: + closedir(dir); + VIR_FREE(unique_path); + VIR_FREE(host_link); + VIR_FREE(host_path); + return ret; +} + /* virReadFCHost: * @sysfs_prefix: "fc_host" sysfs path, defaults to SYSFS_FC_HOST_PATH * @host: Host number, E.g. 5 of "fc_host/host5" @@ -2086,6 +2178,15 @@ virReadSCSIUniqueId(const char *sysfs_prefix ATTRIBUTE_UNUSED, return -1; } +char * +virFindSCSIHostByPCI(const char *sysfs_prefix ATTRIBUTE_UNUSED, + const char *parentaddr ATTRIBUTE_UNUSED, + unsigned int unique_id ATTRIBUTE_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", _("Not supported on this platform")); + return -1; +} + int virReadFCHost(const char *sysfs_prefix ATTRIBUTE_UNUSED, int host ATTRIBUTE_UNUSED, diff --git a/src/util/virutil.h b/src/util/virutil.h index 1407dfd..e8c1d7c 100644 --- a/src/util/virutil.h +++ b/src/util/virutil.h @@ -168,6 +168,10 @@ int virReadSCSIUniqueId(const char *sysfs_prefix, int host, int *result) ATTRIBUTE_NONNULL(3); +char * +virFindSCSIHostByPCI(const char *sysfs_prefix, + const char *parentaddr, + unsigned int unique_id); int virReadFCHost(const char *sysfs_prefix, int host, const char *entry, diff --git a/tests/scsihosttest.c b/tests/scsihosttest.c index 990fe80..eecb1c3 100644 --- a/tests/scsihosttest.c +++ b/tests/scsihosttest.c @@ -196,6 +196,54 @@ testVirReadSCSIUniqueId(const void *data ATTRIBUTE_UNUSED) return 0; } +/* Test virFindSCSIHostByPCI */ +static int +testVirFindSCSIHostByPCI(const void *data ATTRIBUTE_UNUSED) +{ + unsigned int unique_id1 = 1; + unsigned int unique_id2 = 2; + const char *pci_addr1 = "0000:00:1f.1"; + const char *pci_addr2 = "0000:00:1f.2"; + char *path_addr = NULL; + char *ret_host = NULL; + int ret = -1; + + if (virAsprintf(&path_addr, "%s/%s", abs_srcdir, + "sysfs/class/scsi_host") < 0) + goto cleanup; + + if (!(ret_host = virFindSCSIHostByPCI(TEST_SCSIHOST_CLASS_PATH, + pci_addr1, unique_id1)) || + STRNEQ(ret_host, "host0")) + goto cleanup; + VIR_FREE(ret_host); + + if (!(ret_host = virFindSCSIHostByPCI(TEST_SCSIHOST_CLASS_PATH, + pci_addr1, unique_id2)) || + STRNEQ(ret_host, "host1")) + goto cleanup; + VIR_FREE(ret_host); + + if (!(ret_host = virFindSCSIHostByPCI(TEST_SCSIHOST_CLASS_PATH, + pci_addr2, unique_id1)) || + STRNEQ(ret_host, "host2")) + goto cleanup; + VIR_FREE(ret_host); + + if (!(ret_host = virFindSCSIHostByPCI(TEST_SCSIHOST_CLASS_PATH, + pci_addr2, unique_id2)) || + STRNEQ(ret_host, "host3")) + goto cleanup; + VIR_FREE(ret_host); + + ret = 0; + + cleanup: + VIR_FREE(ret_host); + VIR_FREE(path_addr); + return ret; +} + # define FAKESYSFSDIRTEMPLATE abs_builddir "/fakesysfsdir-XXXXXX" static int @@ -234,6 +282,12 @@ mymain(void) goto cleanup; } + if (virtTestRun("testVirFindSCSIHostByPCI", + testVirFindSCSIHostByPCI, NULL) < 0) { + ret = -1; + goto cleanup; + } + ret = 0; cleanup: -- 1.9.3 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list