]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/libvirt.git/commitdiff
util: Add helper to get the scsi host name by iterating over sysfs
authorOsier Yang <jyang@redhat.com>
Mon, 25 Mar 2013 16:43:40 +0000 (00:43 +0800)
committerOsier Yang <jyang@redhat.com>
Mon, 8 Apr 2013 10:41:06 +0000 (18:41 +0800)
The helper iterates over sysfs, to find out the matched scsi host
name by comparing the wwnn,wwpn pair. It will be used by checkPool
and refreshPool of storage scsi backend. New helper getAdapterName
is introduced in storage_backend_scsi.c, which uses the new util
helper virGetFCHostNameByWWN to get the fc_host adapter name.

src/libvirt_private.syms
src/storage/storage_backend_scsi.c
src/util/virutil.c
src/util/virutil.h

index 4850fad8bc3b8ef9938f429a8e4a12b6c912fb54..cd4eb927e229965749c6e94c33ba1bb2b9287e32 100644 (file)
@@ -1856,6 +1856,7 @@ virFindFileInPath;
 virFormatIntDecimal;
 virGetDeviceID;
 virGetDeviceUnprivSGIO;
+virGetFCHostNameByWWN;
 virGetGroupID;
 virGetGroupName;
 virGetHostname;
index 67cb01dd8cad01337979d986c98833cbc2fb53fb..275458b32f5c0a7b6b4a6ef95b725c4517379275 100644 (file)
@@ -603,6 +603,8 @@ getHostNumber(const char *adapter_name,
      */
     if (STRPREFIX(host, "scsi_host")) {
         host += strlen("scsi_host");
+    } else if (STRPREFIX(host, "fc_host")) {
+        host += strlen("fc_host");
     } else if (STRPREFIX(host, "host")) {
         host += strlen("host");
     } else {
@@ -622,42 +624,73 @@ getHostNumber(const char *adapter_name,
     return 0;
 }
 
+static char *
+getAdapterName(virStoragePoolSourceAdapter adapter)
+{
+    char *name = NULL;
+
+    if (adapter.type != VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST)
+        return strdup(adapter.data.name);
+
+    if (!(name = virGetFCHostNameByWWN(NULL,
+                                       adapter.data.fchost.wwnn,
+                                       adapter.data.fchost.wwpn))) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("Failed to find SCSI host with wwnn='%s', "
+                         "wwpn='%s'"), adapter.data.fchost.wwnn,
+                       adapter.data.fchost.wwpn);
+    }
+
+    return name;
+}
+
 static int
 virStorageBackendSCSICheckPool(virConnectPtr conn ATTRIBUTE_UNUSED,
                                virStoragePoolObjPtr pool,
                                bool *isActive)
 {
-    char *path;
+    char *path = NULL;
+    char *name = NULL;
     unsigned int host;
+    int ret = -1;
 
     *isActive = false;
 
-    if (getHostNumber(pool->def->source.adapter.data.name, &host) < 0)
+    if (!(name = getAdapterName(pool->def->source.adapter)))
         return -1;
 
+    if (getHostNumber(name, &host) < 0)
+        goto cleanup;
+
     if (virAsprintf(&path, "/sys/class/scsi_host/host%d", host) < 0) {
         virReportOOMError();
-        return -1;
+        goto cleanup;
     }
 
     if (access(path, F_OK) == 0)
         *isActive = true;
 
+    ret = 0;
+cleanup:
     VIR_FREE(path);
-
-    return 0;
+    VIR_FREE(name);
+    return ret;
 }
 
 static int
 virStorageBackendSCSIRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
                                  virStoragePoolObjPtr pool)
 {
-    int ret = -1;
+    char *name = NULL;
     unsigned int host;
+    int ret = -1;
 
     pool->def->allocation = pool->def->capacity = pool->def->available = 0;
 
-    if (getHostNumber(pool->def->source.adapter.data.name, &host) < 0)
+    if (!(name = getAdapterName(pool->def->source.adapter)))
+        return -1;
+
+    if (getHostNumber(name, &host) < 0)
         goto out;
 
     VIR_DEBUG("Scanning host%u", host);
@@ -669,6 +702,7 @@ virStorageBackendSCSIRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
 
     ret = 0;
 out:
+    VIR_FREE(name);
     return ret;
 }
 
index 87a97c9a0af656f7d8157824aa73845f9bf23e10..46f17456b2c4487458005e312a752f6fbabb0931 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <config.h>
 
+#include <dirent.h>
 #include <stdio.h>
 #include <stdarg.h>
 #include <stdlib.h>
@@ -3570,6 +3571,105 @@ cleanup:
     VIR_FREE(operation_path);
     return ret;
 }
+
+/* virGetHostNameByWWN:
+ *
+ * Iterate over the sysfs tree to get SCSI host name (e.g. scsi_host5)
+ * by wwnn,wwpn pair.
+ */
+char *
+virGetFCHostNameByWWN(const char *sysfs_prefix,
+                      const char *wwnn,
+                      const char *wwpn)
+{
+    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 (!(dir = opendir(prefix))) {
+        virReportSystemError(errno,
+                             _("Failed to opendir path '%s'"),
+                             prefix);
+        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 ((entry = readdir(dir))) {
+        if (entry->d_name[0] == '.')
+            continue;
+
+        if (virAsprintf(&wwnn_path, "%s%s/node_name", prefix,
+                        entry->d_name) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        if (!virFileExists(wwnn_path)) {
+            VIR_FREE(wwnn_path);
+            continue;
+        }
+
+        READ_WWN(wwnn_path, wwnn_buf);
+
+        if (STRNEQ(wwnn, p)) {
+            VIR_FREE(wwnn_buf);
+            VIR_FREE(wwnn_path);
+            continue;
+        }
+
+        if (virAsprintf(&wwpn_path, "%s%s/port_name", prefix,
+                        entry->d_name) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+        if (!virFileExists(wwpn_path)) {
+            VIR_FREE(wwnn_buf);
+            VIR_FREE(wwnn_path);
+            VIR_FREE(wwpn_path);
+            continue;
+        }
+
+        READ_WWN(wwpn_path, wwpn_buf);
+
+        if (STRNEQ(wwpn, p)) {
+            VIR_FREE(wwnn_path);
+            VIR_FREE(wwpn_path);
+            VIR_FREE(wwnn_buf);
+            VIR_FREE(wwpn_buf);
+            continue;
+        }
+
+        ret = strdup(entry->d_name);
+        break;
+    }
+
+cleanup:
+# undef READ_WWN
+    closedir(dir);
+    VIR_FREE(wwnn_path);
+    VIR_FREE(wwpn_path);
+    VIR_FREE(wwnn_buf);
+    VIR_FREE(wwpn_buf);
+    return ret;
+}
 #else
 int
 virReadFCHost(const char *sysfs_prefix ATTRIBUTE_UNUSED,
@@ -3607,4 +3707,13 @@ virManageVport(const int parent_host ATTRIBUTE_UNUSED,
     return -1;
 }
 
+char *
+virGetFCHostNameByWWN(const char *sysfs_prefix ATTRIBUTE_UNUSED,
+                      const char *wwnn ATTRIBUTE_UNUSED,
+                      const char *wwpn ATTRIBUTE_UNUSED)
+{
+    virReportSystemError(ENOSYS, "%s", _("Not supported on this platform"));
+    return NULL;
+}
+
 #endif /* __linux__ */
index 2a797cb28e061c6d06a5506cdd22b13e9d925357..2aa4f2c7a5c296cc3e0f5d97646aaa84ddee6e35 100644 (file)
@@ -295,8 +295,8 @@ int virSetDeviceUnprivSGIO(const char *path,
 int virGetDeviceUnprivSGIO(const char *path,
                            const char *sysfs_dir,
                            int *unpriv_sgio);
-char * virGetUnprivSGIOSysfsPath(const char *path,
-                                 const char *sysfs_dir);
+char *virGetUnprivSGIOSysfsPath(const char *path,
+                                const char *sysfs_dir);
 int virReadFCHost(const char *sysfs_prefix,
                   int host,
                   const char *entry,
@@ -317,4 +317,9 @@ int virManageVport(const int parent_host,
                    int operation)
     ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
 
+char *virGetFCHostNameByWWN(const char *sysfs_prefix,
+                            const char *wwnn,
+                            const char *wwpn)
+    ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+
 #endif /* __VIR_UTIL_H__ */