The SCSI volumes currently get a name like '17:0:0:1' based
on $host:$bus:$target:$lun. The names are intended to be unique
per pool and stable across pool restarts. The inclusion of the
$host component breaks this, because the $host number for iSCSI
pools is dynamically allocated by the kernel at time of login.
This changes the name to be 'unit:0:0:1', ie removes the leading
host component. THe 'unit:' prefix is just to ensure the volume
name doesn't start with a number and make it clearer when seen
out of context.

The SCSI volumes also get a 'key' field based on the fully
qualified volume path. All SCSI volumes have a unique serial
available in hardware which can be obtained by sending a
suitable SCSI command. Call out to udev's 'scsi_id' command
to fetch this value

* src/storage/storage_backend_scsi.c: Improve key and name
  field value stability and uniqness
---
 src/storage/storage_backend_scsi.c |   71 +++++++++++++++++++++++++++++++++---
 1 files changed, 65 insertions(+), 6 deletions(-)

diff --git a/src/storage/storage_backend_scsi.c 
b/src/storage/storage_backend_scsi.c
index 0d6b1ac..aeabd36 100644
--- a/src/storage/storage_backend_scsi.c
+++ b/src/storage/storage_backend_scsi.c
@@ -163,9 +163,66 @@ cleanup:
     return ret;
 }
 
+static char *
+virStorageBackendSCSISerial(const char *dev)
+{
+    const char *cmdargv[] = {
+        "/lib/udev/scsi_id",
+        "--replace-whitespace",
+        "--whitelisted",
+        "--device", dev,
+        NULL
+    };
+    int fd = -1;
+    pid_t child;
+    FILE *list = NULL;
+    char line[1024];
+    char *serial = NULL;
+    int err;
+    int exitstatus;
+
+    /* Run the program and capture its output */
+    if (virExec(cmdargv, NULL, NULL,
+                &child, -1, &fd, NULL, VIR_EXEC_NONE) < 0)
+        goto cleanup;
+
+    if ((list = fdopen(fd, "r")) == NULL) {
+        virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+                              "%s", _("cannot read fd"));
+        goto cleanup;
+    }
+
+    if (fgets(line, sizeof(line), list)) {
+        char *nl = strchr(line, '\n');
+        if (nl)
+            *nl = '\0';
+        VIR_ERROR("GOT ID %s\n", line);
+        serial = strdup(line);
+    } else {
+        VIR_ERROR("NO ID %s\n", dev);
+        serial = strdup(dev);
+    }
+
+    if (!serial) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+cleanup:
+    if (list)
+        fclose(list);
+    else
+        VIR_FORCE_CLOSE(fd);
+
+    while ((err = waitpid(child, &exitstatus, 0) == -1) && errno == EINTR);
+
+    return serial;
+}
+
+
 static int
 virStorageBackendSCSINewLun(virStoragePoolObjPtr pool,
-                            uint32_t host,
+                            uint32_t host ATTRIBUTE_UNUSED,
                             uint32_t bus,
                             uint32_t target,
                             uint32_t lun,
@@ -183,7 +240,12 @@ virStorageBackendSCSINewLun(virStoragePoolObjPtr pool,
 
     vol->type = VIR_STORAGE_VOL_BLOCK;
 
-    if (virAsprintf(&(vol->name), "%u.%u.%u.%u", host, bus, target, lun) < 0) {
+    /* 'host' is dynamically allocated by the kernel, first come,
+     * first served, per HBA. As such it isn't suitable for use
+     * in the volume name. We only need uniquness per-pool, so
+     * just leave 'host' out
+     */
+    if (virAsprintf(&(vol->name), "unit:%u:%u:%u", bus, target, lun) < 0) {
         virReportOOMError();
         retval = -1;
         goto free_vol;
@@ -231,10 +293,7 @@ virStorageBackendSCSINewLun(virStoragePoolObjPtr pool,
         goto free_vol;
     }
 
-    /* XXX should use logical unit's UUID instead */
-    vol->key = strdup(vol->target.path);
-    if (vol->key == NULL) {
-        virReportOOMError();
+    if (!(vol->key = virStorageBackendSCSISerial(vol->target.path))) {
         retval = -1;
         goto free_vol;
     }
-- 
1.7.2.3

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to