bcddb9
From 049bb8956ce077d7ea5e8ac613ebb20c7a6b8715 Mon Sep 17 00:00:00 2001
bcddb9
Message-Id: <049bb8956ce077d7ea5e8ac613ebb20c7a6b8715@dist-git>
bcddb9
From: John Ferlan <jferlan@redhat.com>
bcddb9
Date: Tue, 12 Mar 2019 13:55:58 -0400
bcddb9
Subject: [PATCH] util: Introduce virStorageFileGetNPIVKey
bcddb9
MIME-Version: 1.0
bcddb9
Content-Type: text/plain; charset=UTF-8
bcddb9
Content-Transfer-Encoding: 8bit
bcddb9
bcddb9
https://bugzilla.redhat.com/show_bug.cgi?id=1687715 (7.6.z)
bcddb9
https://bugzilla.redhat.com/show_bug.cgi?id=1657468 (7.7.0)
bcddb9
bcddb9
The vHBA/NPIV LUNs created via the udev processing of the
bcddb9
VPORT_CREATE command end up using the same serial value
bcddb9
as seen/generated by the /lib/udev/scsi_id as returned
bcddb9
during virStorageFileGetSCSIKey. Therefore, in order to
bcddb9
generate a unique enough key to be used when adding the
bcddb9
LUN as a volume during virStoragePoolObjAddVol a more
bcddb9
unique key needs to be generated for an NPIV volume.
bcddb9
bcddb9
The problem is illustrated by the following example, where
bcddb9
scsi_host5 is a vHBA used with the following LUNs:
bcddb9
bcddb9
$ lsscsi -tg
bcddb9
...
bcddb9
[5:0:4:0]    disk    fc:0x5006016844602198,0x101f00  /dev/sdh   /dev/sg23
bcddb9
[5:0:5:0]    disk    fc:0x5006016044602198,0x102000  /dev/sdi   /dev/sg24
bcddb9
...
bcddb9
bcddb9
Calling virStorageFileGetSCSIKey would return:
bcddb9
bcddb9
/lib/udev/scsi_id --device /dev/sdh --whitelisted --replace-whitespace /dev/sdh
bcddb9
350060160c460219850060160c4602198
bcddb9
/lib/udev/scsi_id --device /dev/sdh --whitelisted --replace-whitespace /dev/sdi
bcddb9
350060160c460219850060160c4602198
bcddb9
bcddb9
Note that althrough /dev/sdh and /dev/sdi are separate LUNs, they
bcddb9
end up with the same serial number used for the vol->key value.
bcddb9
When virStoragePoolFCRefreshThread calls virStoragePoolObjAddVol
bcddb9
the second LUN fails to be added with the following message
bcddb9
getting logged:
bcddb9
bcddb9
    virHashAddOrUpdateEntry:341 : internal error: Duplicate key
bcddb9
bcddb9
To resolve this, virStorageFileGetNPIVKey will use a similar call
bcddb9
sequence as virStorageFileGetSCSIKey, except that it will add the
bcddb9
"--export" option to the call. This results in more detailed output
bcddb9
which needs to be parsed in order to formulate a unique enough key
bcddb9
to be used. In order to be unique enough, the returned value will
bcddb9
concatenate the target port as returned in the "ID_TARGET_PORT"
bcddb9
field from the command to the "ID_SERIAL" value.
bcddb9
bcddb9
Signed-off-by: John Ferlan <jferlan@redhat.com>
bcddb9
ACKed-by: Michal Privoznik <mprivozn@redhat.com>
bcddb9
Reviewed-by: Ján Tomko <jtomko@redhat.com>
bcddb9
(cherry picked from commit 5f9e211c9319311fc296cb91ca8e330917ac9494)
bcddb9
bcddb9
Handled build failure of not having VIR_AUTOFREE in the next-7.6 sources,
bcddb9
by not using VIR_AUTOFREE and using VIR_FREE(outbuf) explicitly.
bcddb9
bcddb9
Signed-off-by: John Ferlan <jferlan@redhat.com>
bcddb9
Message-Id: <20190312175559.13583-4-jferlan@redhat.com>
bcddb9
Reviewed-by: Ján Tomko <jtomko@redhat.com>
bcddb9
---
bcddb9
 src/libvirt_private.syms  |  1 +
bcddb9
 src/util/virstoragefile.c | 80 +++++++++++++++++++++++++++++++++++++++
bcddb9
 src/util/virstoragefile.h |  2 +
bcddb9
 3 files changed, 83 insertions(+)
bcddb9
bcddb9
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
bcddb9
index 86846f3b08..636891eabd 100644
bcddb9
--- a/src/libvirt_private.syms
bcddb9
+++ b/src/libvirt_private.syms
bcddb9
@@ -2820,6 +2820,7 @@ virStorageFileGetMetadata;
bcddb9
 virStorageFileGetMetadataFromBuf;
bcddb9
 virStorageFileGetMetadataFromFD;
bcddb9
 virStorageFileGetMetadataInternal;
bcddb9
+virStorageFileGetNPIVKey;
bcddb9
 virStorageFileGetRelativeBackingPath;
bcddb9
 virStorageFileGetSCSIKey;
bcddb9
 virStorageFileGetUniqueIdentifier;
bcddb9
diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c
bcddb9
index 56d38b467e..52c9dc0e1a 100644
bcddb9
--- a/src/util/virstoragefile.c
bcddb9
+++ b/src/util/virstoragefile.c
bcddb9
@@ -1503,6 +1503,86 @@ int virStorageFileGetSCSIKey(const char *path,
bcddb9
 #endif
bcddb9
 
bcddb9
 
bcddb9
+#ifdef WITH_UDEV
bcddb9
+/* virStorageFileGetNPIVKey
bcddb9
+ * @path: Path to the NPIV device
bcddb9
+ * @key: Unique key to be returned
bcddb9
+ *
bcddb9
+ * Using a udev specific function, query the @path to get and return a
bcddb9
+ * unique @key for the caller to use. Unlike the GetSCSIKey method, an
bcddb9
+ * NPIV LUN is uniquely identified by its ID_TARGET_PORT value.
bcddb9
+ *
bcddb9
+ * Returns:
bcddb9
+ *     0 On success, with the @key filled in or @key=NULL if the
bcddb9
+ *       returned output string didn't have the data we need to
bcddb9
+ *       formulate a unique key value
bcddb9
+ *    -1 When WITH_UDEV is undefined and a system error is reported
bcddb9
+ *    -2 When WITH_UDEV is defined, but calling virCommandRun fails
bcddb9
+ */
bcddb9
+# define ID_SERIAL "ID_SERIAL="
bcddb9
+# define ID_TARGET_PORT "ID_TARGET_PORT="
bcddb9
+int
bcddb9
+virStorageFileGetNPIVKey(const char *path,
bcddb9
+                         char **key)
bcddb9
+{
bcddb9
+    int status;
bcddb9
+    char *outbuf = NULL;
bcddb9
+    const char *serial;
bcddb9
+    const char *port;
bcddb9
+    virCommandPtr cmd = virCommandNewArgList("/lib/udev/scsi_id",
bcddb9
+                                             "--replace-whitespace",
bcddb9
+                                             "--whitelisted",
bcddb9
+                                             "--export",
bcddb9
+                                             "--device", path,
bcddb9
+                                             NULL
bcddb9
+                                             );
bcddb9
+    int ret = -2;
bcddb9
+
bcddb9
+    *key = NULL;
bcddb9
+
bcddb9
+    /* Run the program and capture its output */
bcddb9
+    virCommandSetOutputBuffer(cmd, &outbuf);
bcddb9
+    if (virCommandRun(cmd, &status) < 0)
bcddb9
+        goto cleanup;
bcddb9
+
bcddb9
+    /* Explicitly check status == 0, rather than passing NULL
bcddb9
+     * to virCommandRun because we don't want to raise an actual
bcddb9
+     * error in this scenario, just return a NULL key.
bcddb9
+     */
bcddb9
+    if (status == 0 && *outbuf &&
bcddb9
+        (serial = strstr(outbuf, ID_SERIAL)) &&
bcddb9
+        (port = strstr(outbuf, ID_TARGET_PORT))) {
bcddb9
+        char *tmp;
bcddb9
+
bcddb9
+        serial += strlen(ID_SERIAL);
bcddb9
+        port += strlen(ID_TARGET_PORT);
bcddb9
+
bcddb9
+        if ((tmp = strchr(serial, '\n')))
bcddb9
+            *tmp = '\0';
bcddb9
+
bcddb9
+        if ((tmp = strchr(port, '\n')))
bcddb9
+            *tmp = '\0';
bcddb9
+
bcddb9
+        if (*serial != '\0' && *port != '\0')
bcddb9
+            ignore_value(virAsprintf(key, "%s_PORT%s", serial, port));
bcddb9
+    }
bcddb9
+
bcddb9
+    ret = 0;
bcddb9
+
bcddb9
+ cleanup:
bcddb9
+    virCommandFree(cmd);
bcddb9
+    VIR_FREE(outbuf);
bcddb9
+
bcddb9
+    return ret;
bcddb9
+}
bcddb9
+#else
bcddb9
+int virStorageFileGetNPIVKey(const char *path,
bcddb9
+                             char **key ATTRIBUTE_UNUSED)
bcddb9
+{
bcddb9
+    return -1;
bcddb9
+}
bcddb9
+#endif
bcddb9
+
bcddb9
 /**
bcddb9
  * virStorageFileParseBackingStoreStr:
bcddb9
  * @str: backing store specifier string to parse
bcddb9
diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h
bcddb9
index bbb0b8b3c1..7d28dcfe65 100644
bcddb9
--- a/src/util/virstoragefile.h
bcddb9
+++ b/src/util/virstoragefile.h
bcddb9
@@ -386,6 +386,8 @@ int virStorageFileGetLVMKey(const char *path,
bcddb9
 int virStorageFileGetSCSIKey(const char *path,
bcddb9
                              char **key,
bcddb9
                              bool ignoreError);
bcddb9
+int virStorageFileGetNPIVKey(const char *path,
bcddb9
+                             char **key);
bcddb9
 
bcddb9
 void virStorageAuthDefFree(virStorageAuthDefPtr def);
bcddb9
 virStorageAuthDefPtr virStorageAuthDefCopy(const virStorageAuthDef *src);
bcddb9
-- 
bcddb9
2.21.0
bcddb9