[libvirt] [REPOST 7/8] scsi_host: Introduce virFindSCSIHostByPCI

John Ferlan jferlan at redhat.com
Tue Jul 8 11:54:20 UTC 2014


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 at 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




More information about the libvir-list mailing list