]> xenbits.xensource.com Git - libvirt.git/commitdiff
scsi_host: Introduce virFindSCSIHostByPCI
authorJohn Ferlan <jferlan@redhat.com>
Tue, 10 Jun 2014 11:47:12 +0000 (07:47 -0400)
committerJohn Ferlan <jferlan@redhat.com>
Mon, 21 Jul 2014 16:55:11 +0000 (12:55 -0400)
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

docs/formatstorage.html.in
src/libvirt_private.syms
src/util/virutil.c
src/util/virutil.h
tests/scsihosttest.c

index 6bbd61a95379ec76ad212bfaa6ded1915c949d26..e26498543a94deb3102ec7539403edc801ec925b 100644 (file)
                 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>
index 97999758b667ed65629e35d58db0a3f009968d53..6ac563c091f1149470bde7b493c95f617d413449 100644 (file)
@@ -2113,6 +2113,7 @@ virDoubleToStr;
 virEnumFromString;
 virEnumToString;
 virFindFCHostCapableVport;
+virFindSCSIHostByPCI;
 virFormatIntDecimal;
 virGetDeviceID;
 virGetDeviceUnprivSGIO;
index bb1d7ea5b2cae0bdd688d792fb0f259cf475f5e9..1c6d261fbbd7efca789611569421a0d68aa7121c 100644 (file)
@@ -1729,6 +1729,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"
@@ -2090,6 +2182,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,
index 1407dfd9aaab41675901c3787b2ad93a4f2b1ab2..e8c1d7c7d02cd06239b8395eb8397fcebadacdae 100644 (file)
@@ -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,
index 990fe8012973a69da4517b307d28882d5b845da9..eecb1c3ad1a7deebb860c9cccee2ea1fdf87195e 100644 (file)
@@ -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: