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