9119d9
From 36873e3b85a70d8bbd6d9e259165050e93f43612 Mon Sep 17 00:00:00 2001
9119d9
Message-Id: <36873e3b85a70d8bbd6d9e259165050e93f43612@dist-git>
9119d9
From: John Ferlan <jferlan@redhat.com>
9119d9
Date: Wed, 12 Nov 2014 13:34:47 -0500
9119d9
Subject: [PATCH] storage: Ensure fc_host parent matches wwnn/wwpn
9119d9
9119d9
https://bugzilla.redhat.com/show_bug.cgi?id=1160565
9119d9
9119d9
The existing code assumed that the configuration of a 'parent' attribute
9119d9
was correct for the createVport path. As it turns out, that may not be
9119d9
the case which leads errors during the deleteVport path because the
9119d9
wwnn/wwpn isn't associated with the parent.
9119d9
9119d9
With this change the following is reported:
9119d9
9119d9
error: Failed to start pool fc_pool_host3
9119d9
error: XML error: Parent attribute 'scsi_host4' does not match parent 'scsi_host3' determined for the 'scsi_host16' wwnn/wwpn lookup.
9119d9
9119d9
for XML as follows:
9119d9
9119d9
  <pool type='scsi'>
9119d9
    <name>fc_pool</name>
9119d9
    <source>
9119d9
      <adapter type='fc_host' parent='scsi_host4' wwnn='5001a4aaf3ca174b' wwpn='5001a4a77192b864'/>
9119d9
    </source>
9119d9
9119d9
Where 'nodedev-dumpxml scsi_host16' provides:
9119d9
9119d9
  <device>
9119d9
    <name>scsi_host16</name>
9119d9
    <path>/sys/devices/pci0000:00/0000:00:04.0/0000:10:00.0/host3/vport-3:0-11/host16</path>
9119d9
    <parent>scsi_host3</parent>
9119d9
    <capability type='scsi_host'>
9119d9
      <host>16</host>
9119d9
      <unique_id>13</unique_id>
9119d9
      <capability type='fc_host'>
9119d9
        <wwnn>5001a4aaf3ca174b</wwnn>
9119d9
        <wwpn>5001a4a77192b864</wwpn>
9119d9
...
9119d9
9119d9
The patch also adjusts the description of the storage pool to describe the
9119d9
restrictions.
9119d9
9119d9
Signed-off-by: John Ferlan <jferlan@redhat.com>
9119d9
(cherry picked from commit 42a021c1204d7dcb531f5d476e65b53a8bd4f704)
9119d9
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
9119d9
---
9119d9
 docs/formatstorage.html.in         |  15 ++++-
9119d9
 src/storage/storage_backend_scsi.c | 118 +++++++++++++++++++++++++++++++++++--
9119d9
 2 files changed, 126 insertions(+), 7 deletions(-)
9119d9
9119d9
diff --git a/docs/formatstorage.html.in b/docs/formatstorage.html.in
9119d9
index e25bba7..7872112 100644
9119d9
--- a/docs/formatstorage.html.in
9119d9
+++ b/docs/formatstorage.html.in
9119d9
@@ -165,7 +165,13 @@
9119d9
             to uniquely identify the device in the Fibre Channel storage fabric
9119d9
             (the device can be either a HBA or vHBA). Both wwnn and wwpn should
9119d9
             be specified. Use the command 'virsh nodedev-dumpxml' to determine
9119d9
-            how to set the values for the wwnn/wwpn of a (v)HBA.
9119d9
+            how to set the values for the wwnn/wwpn of a (v)HBA. The wwnn and
9119d9
+            wwpn have very specific numerical format requirements based on the
9119d9
+            hypervisor being used, thus care should be taken if you decide to
9119d9
+            generate your own to follow the standards; otherwise, the pool
9119d9
+            will fail to start with an opaque error message indicating failure
9119d9
+            to write to the vport_create file during vport create/delete due
9119d9
+            to "No such file or directory".
9119d9
             Since 1.0.4
9119d9
           
9119d9
         
9119d9
@@ -175,7 +181,12 @@
9119d9
             parent scsi_host device defined in the
9119d9
             Node Device database as the
9119d9
             NPIV
9119d9
-            virtual Host Bus Adapter (vHBA).
9119d9
+            virtual Host Bus Adapter (vHBA). The value provided must be
9119d9
+            a vport capable scsi_host. The value is not the scsi_host of
9119d9
+            the vHBA created by 'virsh nodedev-create', rather it is
9119d9
+            the parent of that vHBA. If the value is not provided, libvirt
9119d9
+            will determine the parent based either finding the wwnn,wwpn
9119d9
+            defined for an existing scsi_host or by creating a vHBA.
9119d9
             Since 1.0.4
9119d9
           
9119d9
         
9119d9
diff --git a/src/storage/storage_backend_scsi.c b/src/storage/storage_backend_scsi.c
9119d9
index 88928c9..bfef219 100644
9119d9
--- a/src/storage/storage_backend_scsi.c
9119d9
+++ b/src/storage/storage_backend_scsi.c
9119d9
@@ -34,6 +34,7 @@
9119d9
 #include "virlog.h"
9119d9
 #include "virfile.h"
9119d9
 #include "vircommand.h"
9119d9
+#include "viraccessapicheck.h"
9119d9
 #include "virstring.h"
9119d9
 
9119d9
 #define VIR_FROM_THIS VIR_FROM_STORAGE
9119d9
@@ -547,8 +548,103 @@ getAdapterName(virStoragePoolSourceAdapter adapter)
9119d9
     return name;
9119d9
 }
9119d9
 
9119d9
+/*
9119d9
+ * Using the host# name found via wwnn/wwpn lookup in the fc_host
9119d9
+ * sysfs tree to get the parent 'scsi_host#'. On entry we need 'conn'
9119d9
+ * set. We won't get here from the autostart path since the caller
9119d9
+ * will return true before calling this function. For the shutdown
9119d9
+ * path we won't be able to delete the vport.
9119d9
+ */
9119d9
+static char * ATTRIBUTE_NONNULL(1)
9119d9
+getVhbaSCSIHostParent(virConnectPtr conn,
9119d9
+                      const char *name)
9119d9
+{
9119d9
+    char *nodedev_name = NULL;
9119d9
+    virNodeDevicePtr device = NULL;
9119d9
+    char *xml = NULL;
9119d9
+    virNodeDeviceDefPtr def = NULL;
9119d9
+    char *vhba_parent = NULL;
9119d9
+    virErrorPtr savedError = NULL;
9119d9
+
9119d9
+    VIR_DEBUG("conn=%p, name=%s", conn, name);
9119d9
+
9119d9
+    /* We get passed "host#" from the return from virGetFCHostNameByWWN,
9119d9
+     * so we need to adjust that to what the nodedev lookup expects
9119d9
+     */
9119d9
+    if (virAsprintf(&nodedev_name, "scsi_%s", name) < 0)
9119d9
+        goto cleanup;
9119d9
+
9119d9
+    /* Compare the scsi_host for the name with the provided parent
9119d9
+     * if not the same, then fail
9119d9
+     */
9119d9
+    if (!(device = virNodeDeviceLookupByName(conn, nodedev_name))) {
9119d9
+        virReportError(VIR_ERR_XML_ERROR,
9119d9
+                       _("Cannot find '%s' in node device database"),
9119d9
+                       nodedev_name);
9119d9
+        goto cleanup;
9119d9
+    }
9119d9
+
9119d9
+    if (!(xml = virNodeDeviceGetXMLDesc(device, 0)))
9119d9
+        goto cleanup;
9119d9
+
9119d9
+    if (!(def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL)))
9119d9
+        goto cleanup;
9119d9
+
9119d9
+    ignore_value(VIR_STRDUP(vhba_parent, def->parent));
9119d9
+
9119d9
+ cleanup:
9119d9
+    if (!vhba_parent)
9119d9
+        savedError = virSaveLastError();
9119d9
+    VIR_FREE(nodedev_name);
9119d9
+    virNodeDeviceDefFree(def);
9119d9
+    VIR_FREE(xml);
9119d9
+    virNodeDeviceFree(device);
9119d9
+    if (savedError) {
9119d9
+        virSetError(savedError);
9119d9
+        virFreeError(savedError);
9119d9
+    }
9119d9
+    return vhba_parent;
9119d9
+}
9119d9
+
9119d9
+/*
9119d9
+ * Using the host# name found via wwnn/wwpn lookup in the fc_host
9119d9
+ * sysfs tree to get the parent 'scsi_host#' to ensure it matches.
9119d9
+ */
9119d9
+static bool
9119d9
+checkVhbaSCSIHostParent(virConnectPtr conn,
9119d9
+                        const char *name,
9119d9
+                        const char *parent_name)
9119d9
+{
9119d9
+    char *vhba_parent = NULL;
9119d9
+    bool retval = false;
9119d9
+
9119d9
+    VIR_DEBUG("conn=%p, name=%s, parent_name=%s", conn, name, parent_name);
9119d9
+
9119d9
+    /* autostarted pool - assume we're OK */
9119d9
+    if (!conn)
9119d9
+        return true;
9119d9
+
9119d9
+    if (!(vhba_parent = getVhbaSCSIHostParent(conn, name)))
9119d9
+        goto cleanup;
9119d9
+
9119d9
+    if (STRNEQ(parent_name, vhba_parent)) {
9119d9
+        virReportError(VIR_ERR_XML_ERROR,
9119d9
+                       _("Parent attribute '%s' does not match parent '%s' "
9119d9
+                         "determined for the '%s' wwnn/wwpn lookup."),
9119d9
+                       parent_name, vhba_parent, name);
9119d9
+        goto cleanup;
9119d9
+    }
9119d9
+
9119d9
+    retval = true;
9119d9
+
9119d9
+ cleanup:
9119d9
+    VIR_FREE(vhba_parent);
9119d9
+    return retval;
9119d9
+}
9119d9
+
9119d9
 static int
9119d9
-createVport(virStoragePoolSourceAdapter adapter)
9119d9
+createVport(virConnectPtr conn,
9119d9
+            virStoragePoolSourceAdapter adapter)
9119d9
 {
9119d9
     unsigned int parent_host;
9119d9
     char *name = NULL;
9119d9
@@ -570,11 +666,23 @@ createVport(virStoragePoolSourceAdapter adapter)
9119d9
         }
9119d9
     }
9119d9
 
9119d9
-    /* This filters either HBA or already created vHBA */
9119d9
+    /* If we find an existing HBA/vHBA within the fc_host sysfs
9119d9
+     * using the wwnn/wwpn, then a nodedev is already created for
9119d9
+     * this pool and we don't have to create the vHBA
9119d9
+     */
9119d9
     if ((name = virGetFCHostNameByWWN(NULL, adapter.data.fchost.wwnn,
9119d9
                                       adapter.data.fchost.wwpn))) {
9119d9
+        int retval = 0;
9119d9
+
9119d9
+        /* If a parent was provided, let's make sure the 'name' we've
9119d9
+         * retrieved has the same parent
9119d9
+         */
9119d9
+        if (adapter.data.fchost.parent &&
9119d9
+            !checkVhbaSCSIHostParent(conn, name, adapter.data.fchost.parent))
9119d9
+            retval = -1;
9119d9
+
9119d9
         VIR_FREE(name);
9119d9
-        return 0;
9119d9
+        return retval;
9119d9
     }
9119d9
 
9119d9
     if (!adapter.data.fchost.parent) {
9119d9
@@ -705,11 +813,11 @@ virStorageBackendSCSIRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
9119d9
 }
9119d9
 
9119d9
 static int
9119d9
-virStorageBackendSCSIStartPool(virConnectPtr conn ATTRIBUTE_UNUSED,
9119d9
+virStorageBackendSCSIStartPool(virConnectPtr conn,
9119d9
                                virStoragePoolObjPtr pool)
9119d9
 {
9119d9
     virStoragePoolSourceAdapter adapter = pool->def->source.adapter;
9119d9
-    return createVport(adapter);
9119d9
+    return createVport(conn, adapter);
9119d9
 }
9119d9
 
9119d9
 static int
9119d9
-- 
9119d9
2.1.3
9119d9