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(a)redhat.com>
---
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