[libvirt] [PATCH 4/6] storage: scsi: Fix build if SCSI backend is disabled but iSCSI is enabled

Peter Krempa pkrempa at redhat.com
Wed Jan 18 11:36:28 UTC 2017


The iSCSI backend driver was using stuff from the SCSI driver without
making sure that it's compiled in. Move the common code into the
storage_util.c since it does not contain any specific code.
---
 src/storage/storage_backend_iscsi.c |   1 -
 src/storage/storage_backend_scsi.c  | 447 -----------------------------------
 src/storage/storage_backend_scsi.h  |   4 -
 src/storage/storage_util.c          | 449 ++++++++++++++++++++++++++++++++++++
 src/storage/storage_util.h          |   3 +
 5 files changed, 452 insertions(+), 452 deletions(-)

diff --git a/src/storage/storage_backend_iscsi.c b/src/storage/storage_backend_iscsi.c
index 8799349b6..281334124 100644
--- a/src/storage/storage_backend_iscsi.c
+++ b/src/storage/storage_backend_iscsi.c
@@ -32,7 +32,6 @@

 #include "datatypes.h"
 #include "driver.h"
-#include "storage_backend_scsi.h"
 #include "storage_backend_iscsi.h"
 #include "viralloc.h"
 #include "vircommand.h"
diff --git a/src/storage/storage_backend_scsi.c b/src/storage/storage_backend_scsi.c
index d294d2ac0..ecad1782c 100644
--- a/src/storage/storage_backend_scsi.c
+++ b/src/storage/storage_backend_scsi.c
@@ -25,7 +25,6 @@

 #include <unistd.h>
 #include <stdio.h>
-#include <dirent.h>
 #include <fcntl.h>

 #include "virerror.h"
@@ -48,452 +47,6 @@ struct _virStoragePoolFCRefreshInfo {
     unsigned char pool_uuid[VIR_UUID_BUFLEN];
 };

-/* Function to check if the type file in the given sysfs_path is a
- * Direct-Access device (i.e. type 0).  Return -1 on failure, type of
- * the device otherwise.
- */
-static int
-getDeviceType(uint32_t host,
-              uint32_t bus,
-              uint32_t target,
-              uint32_t lun,
-              int *type)
-{
-    char *type_path = NULL;
-    char typestr[3];
-    char *gottype, *p;
-    FILE *typefile;
-    int retval = 0;
-
-    if (virAsprintf(&type_path, "/sys/bus/scsi/devices/%u:%u:%u:%u/type",
-                    host, bus, target, lun) < 0)
-        goto out;
-
-    typefile = fopen(type_path, "r");
-    if (typefile == NULL) {
-        virReportSystemError(errno,
-                             _("Could not find typefile '%s'"),
-                             type_path);
-        /* there was no type file; that doesn't seem right */
-        retval = -1;
-        goto out;
-    }
-
-    gottype = fgets(typestr, 3, typefile);
-    VIR_FORCE_FCLOSE(typefile);
-
-    if (gottype == NULL) {
-        virReportSystemError(errno,
-                             _("Could not read typefile '%s'"),
-                             type_path);
-        /* we couldn't read the type file; have to give up */
-        retval = -1;
-        goto out;
-    }
-
-    /* we don't actually care about p, but if you pass NULL and the last
-     * character is not \0, virStrToLong_i complains
-     */
-    if (virStrToLong_i(typestr, &p, 10, type) < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Device type '%s' is not an integer"),
-                       typestr);
-        /* Hm, type wasn't an integer; seems strange */
-        retval = -1;
-        goto out;
-    }
-
-    VIR_DEBUG("Device type is %d", *type);
-
- out:
-    VIR_FREE(type_path);
-    return retval;
-}
-
-static char *
-virStorageBackendSCSISerial(const char *dev)
-{
-    char *serial = NULL;
-#ifdef WITH_UDEV
-    virCommandPtr cmd = virCommandNewArgList(
-        "/lib/udev/scsi_id",
-        "--replace-whitespace",
-        "--whitelisted",
-        "--device", dev,
-        NULL
-        );
-
-    /* Run the program and capture its output */
-    virCommandSetOutputBuffer(cmd, &serial);
-    if (virCommandRun(cmd, NULL) < 0)
-        goto cleanup;
-#endif
-
-    if (serial && STRNEQ(serial, "")) {
-        char *nl = strchr(serial, '\n');
-        if (nl)
-            *nl = '\0';
-    } else {
-        VIR_FREE(serial);
-        ignore_value(VIR_STRDUP(serial, dev));
-    }
-
-#ifdef WITH_UDEV
- cleanup:
-    virCommandFree(cmd);
-#endif
-
-    return serial;
-}
-
-
-/*
- * Attempt to create a new LUN
- *
- * Returns:
- *
- *  0  => Success
- *  -1 => Failure due to some sort of OOM or other fatal issue found when
- *        attempting to get/update information about a found volume
- *  -2 => Failure to find a stable path, not fatal, caller can try another
- */
-static int
-virStorageBackendSCSINewLun(virStoragePoolObjPtr pool,
-                            uint32_t host ATTRIBUTE_UNUSED,
-                            uint32_t bus,
-                            uint32_t target,
-                            uint32_t lun,
-                            const char *dev)
-{
-    virStorageVolDefPtr vol = NULL;
-    char *devpath = NULL;
-    int retval = -1;
-
-    /* Check if the pool is using a stable target path. The call to
-     * virStorageBackendStablePath will fail if the pool target path
-     * isn't stable and just return the strdup'd 'devpath' anyway.
-     * This would be indistinguishable to failing to find the stable
-     * path to the device if the virDirRead loop to search the
-     * target pool path for our devpath had failed.
-     */
-    if (!virStorageBackendPoolPathIsStable(pool->def->target.path) &&
-        !(STREQ(pool->def->target.path, "/dev") ||
-          STREQ(pool->def->target.path, "/dev/"))) {
-        virReportError(VIR_ERR_INVALID_ARG,
-                       _("unable to use target path '%s' for dev '%s'"),
-                       NULLSTR(pool->def->target.path), dev);
-        goto cleanup;
-    }
-
-    if (VIR_ALLOC(vol) < 0)
-        goto cleanup;
-
-    vol->type = VIR_STORAGE_VOL_BLOCK;
-
-    /* '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 uniqueness per-pool, so
-     * just leave 'host' out
-     */
-    if (virAsprintf(&(vol->name), "unit:%u:%u:%u", bus, target, lun) < 0)
-        goto cleanup;
-
-    if (virAsprintf(&devpath, "/dev/%s", dev) < 0)
-        goto cleanup;
-
-    VIR_DEBUG("Trying to create volume for '%s'", devpath);
-
-    /* Now figure out the stable path
-     *
-     * XXX this method is O(N) because it scans the pool target
-     * dir every time its run. Should figure out a more efficient
-     * way of doing this...
-     */
-    if ((vol->target.path = virStorageBackendStablePath(pool,
-                                                        devpath,
-                                                        true)) == NULL)
-        goto cleanup;
-
-    if (STREQ(devpath, vol->target.path) &&
-        !(STREQ(pool->def->target.path, "/dev") ||
-          STREQ(pool->def->target.path, "/dev/"))) {
-
-        VIR_DEBUG("No stable path found for '%s' in '%s'",
-                  devpath, pool->def->target.path);
-
-        retval = -2;
-        goto cleanup;
-    }
-
-    /* Allow a volume read failure to ignore or skip this block file */
-    if ((retval = virStorageBackendUpdateVolInfo(vol, true,
-                                                 VIR_STORAGE_VOL_OPEN_DEFAULT,
-                                                 VIR_STORAGE_VOL_READ_NOERROR)) < 0)
-        goto cleanup;
-
-    if (!(vol->key = virStorageBackendSCSISerial(vol->target.path)))
-        goto cleanup;
-
-    pool->def->capacity += vol->target.capacity;
-    pool->def->allocation += vol->target.allocation;
-
-    if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0)
-        goto cleanup;
-
-    vol = NULL;
-    retval = 0;
-
- cleanup:
-    virStorageVolDefFree(vol);
-    VIR_FREE(devpath);
-    return retval;
-}
-
-
-static int
-getNewStyleBlockDevice(const char *lun_path,
-                       const char *block_name ATTRIBUTE_UNUSED,
-                       char **block_device)
-{
-    char *block_path = NULL;
-    DIR *block_dir = NULL;
-    struct dirent *block_dirent = NULL;
-    int retval = -1;
-    int direrr;
-
-    if (virAsprintf(&block_path, "%s/block", lun_path) < 0)
-        goto cleanup;
-
-    VIR_DEBUG("Looking for block device in '%s'", block_path);
-
-    if (virDirOpen(&block_dir, block_path) < 0)
-        goto cleanup;
-
-    while ((direrr = virDirRead(block_dir, &block_dirent, block_path)) > 0) {
-        if (VIR_STRDUP(*block_device, block_dirent->d_name) < 0)
-            goto cleanup;
-
-        VIR_DEBUG("Block device is '%s'", *block_device);
-
-        break;
-    }
-
-    if (direrr < 0)
-        goto cleanup;
-
-    retval = 0;
-
- cleanup:
-    VIR_DIR_CLOSE(block_dir);
-    VIR_FREE(block_path);
-    return retval;
-}
-
-
-static int
-getOldStyleBlockDevice(const char *lun_path ATTRIBUTE_UNUSED,
-                       const char *block_name,
-                       char **block_device)
-{
-    char *blockp = NULL;
-    int retval = -1;
-
-    /* old-style; just parse out the sd */
-    if (!(blockp = strrchr(block_name, ':'))) {
-        /* Hm, wasn't what we were expecting; have to give up */
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Failed to parse block name %s"),
-                       block_name);
-        goto cleanup;
-    } else {
-        blockp++;
-        if (VIR_STRDUP(*block_device, blockp) < 0)
-            goto cleanup;
-
-        VIR_DEBUG("Block device is '%s'", *block_device);
-    }
-
-    retval = 0;
- cleanup:
-    return retval;
-}
-
-
-/*
- * Search a device entry for the "block" file
- *
- * Returns
- *
- *   0 => Found it
- *   -1 => Fatal error
- *   -2 => Didn't find in lun_path directory
- */
-static int
-getBlockDevice(uint32_t host,
-               uint32_t bus,
-               uint32_t target,
-               uint32_t lun,
-               char **block_device)
-{
-    char *lun_path = NULL;
-    DIR *lun_dir = NULL;
-    struct dirent *lun_dirent = NULL;
-    int retval = -1;
-    int direrr;
-
-    *block_device = NULL;
-
-    if (virAsprintf(&lun_path, "/sys/bus/scsi/devices/%u:%u:%u:%u",
-                    host, bus, target, lun) < 0)
-        goto cleanup;
-
-    if (virDirOpen(&lun_dir, lun_path) < 0)
-        goto cleanup;
-
-    while ((direrr = virDirRead(lun_dir, &lun_dirent, lun_path)) > 0) {
-        if (STRPREFIX(lun_dirent->d_name, "block")) {
-            if (strlen(lun_dirent->d_name) == 5) {
-                if (getNewStyleBlockDevice(lun_path,
-                                           lun_dirent->d_name,
-                                           block_device) < 0)
-                    goto cleanup;
-            } else {
-                if (getOldStyleBlockDevice(lun_path,
-                                           lun_dirent->d_name,
-                                           block_device) < 0)
-                    goto cleanup;
-            }
-            break;
-        }
-    }
-    if (direrr < 0)
-        goto cleanup;
-    if (!*block_device) {
-        retval = -2;
-        goto cleanup;
-    }
-
-    retval = 0;
-
- cleanup:
-    VIR_DIR_CLOSE(lun_dir);
-    VIR_FREE(lun_path);
-    return retval;
-}
-
-
-/*
- * Process a Logical Unit entry from the scsi host device directory
- *
- * Returns:
- *
- *  0  => Found a valid entry
- *  -1 => Some sort of fatal error
- *  -2 => non-fatal error or a non-disk entry
- */
-static int
-processLU(virStoragePoolObjPtr pool,
-          uint32_t host,
-          uint32_t bus,
-          uint32_t target,
-          uint32_t lun)
-{
-    int retval = -1;
-    int device_type;
-    char *block_device = NULL;
-
-    VIR_DEBUG("Processing LU %u:%u:%u:%u",
-              host, bus, target, lun);
-
-    if (getDeviceType(host, bus, target, lun, &device_type) < 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("Failed to determine if %u:%u:%u:%u is a Direct-Access LUN"),
-                       host, bus, target, lun);
-        return -1;
-    }
-
-    /* We don't create volumes for devices other than disk and cdrom
-     * devices, but finding a device that isn't one of those types
-     * isn't an error, either. */
-    if (!(device_type == VIR_STORAGE_DEVICE_TYPE_DISK ||
-          device_type == VIR_STORAGE_DEVICE_TYPE_ROM))
-        return -2;
-
-    VIR_DEBUG("%u:%u:%u:%u is a Direct-Access LUN",
-              host, bus, target, lun);
-
-    if ((retval = getBlockDevice(host, bus, target, lun, &block_device)) < 0) {
-        VIR_DEBUG("Failed to find block device for this LUN");
-        return retval;
-    }
-
-    retval = virStorageBackendSCSINewLun(pool, host, bus, target, lun,
-                                         block_device);
-    if (retval < 0) {
-        VIR_DEBUG("Failed to create new storage volume for %u:%u:%u:%u",
-                  host, bus, target, lun);
-        goto cleanup;
-    }
-
-    VIR_DEBUG("Created new storage volume for %u:%u:%u:%u successfully",
-              host, bus, target, lun);
-
- cleanup:
-    VIR_FREE(block_device);
-    return retval;
-}
-
-
-int
-virStorageBackendSCSIFindLUs(virStoragePoolObjPtr pool,
-                              uint32_t scanhost)
-{
-    int retval = 0;
-    uint32_t bus, target, lun;
-    const char *device_path = "/sys/bus/scsi/devices";
-    DIR *devicedir = NULL;
-    struct dirent *lun_dirent = NULL;
-    char devicepattern[64];
-    int found = 0;
-
-    VIR_DEBUG("Discovering LUs on host %u", scanhost);
-
-    virFileWaitForDevices();
-
-    if (virDirOpen(&devicedir, device_path) < 0)
-        return -1;
-
-    snprintf(devicepattern, sizeof(devicepattern), "%u:%%u:%%u:%%u\n", scanhost);
-
-    while ((retval = virDirRead(devicedir, &lun_dirent, device_path)) > 0) {
-        int rc;
-
-        if (sscanf(lun_dirent->d_name, devicepattern,
-                   &bus, &target, &lun) != 3) {
-            continue;
-        }
-
-        VIR_DEBUG("Found possible LU '%s'", lun_dirent->d_name);
-
-        rc = processLU(pool, scanhost, bus, target, lun);
-        if (rc == -1) {
-            retval = -1;
-            break;
-        }
-        if (rc == 0)
-            found++;
-    }
-
-    VIR_DIR_CLOSE(devicedir);
-
-    if (retval < 0)
-        return -1;
-
-    VIR_DEBUG("Found %d LUs for pool %s", found, pool->def->name);
-
-    return found;
-}
-

 static int
 virStorageBackendSCSITriggerRescan(uint32_t host)
diff --git a/src/storage/storage_backend_scsi.h b/src/storage/storage_backend_scsi.h
index 0984fd503..691b8cbf1 100644
--- a/src/storage/storage_backend_scsi.h
+++ b/src/storage/storage_backend_scsi.h
@@ -32,8 +32,4 @@

 extern virStorageBackend virStorageBackendSCSI;

-int
-virStorageBackendSCSIFindLUs(virStoragePoolObjPtr pool,
-                             uint32_t scanhost);
-
 #endif /* __VIR_STORAGE_BACKEND_SCSI_H__ */
diff --git a/src/storage/storage_util.c b/src/storage/storage_util.c
index 353dec4a8..7e69276a6 100644
--- a/src/storage/storage_util.c
+++ b/src/storage/storage_util.c
@@ -2913,3 +2913,452 @@ virStorageBackendDeviceIsEmpty(const char *devpath,

     return ret == 0;
 }
+
+
+static char *
+virStorageBackendSCSISerial(const char *dev)
+{
+    char *serial = NULL;
+#ifdef WITH_UDEV
+    virCommandPtr cmd = virCommandNewArgList(
+        "/lib/udev/scsi_id",
+        "--replace-whitespace",
+        "--whitelisted",
+        "--device", dev,
+        NULL
+        );
+
+    /* Run the program and capture its output */
+    virCommandSetOutputBuffer(cmd, &serial);
+    if (virCommandRun(cmd, NULL) < 0)
+        goto cleanup;
+#endif
+
+    if (serial && STRNEQ(serial, "")) {
+        char *nl = strchr(serial, '\n');
+        if (nl)
+            *nl = '\0';
+    } else {
+        VIR_FREE(serial);
+        ignore_value(VIR_STRDUP(serial, dev));
+    }
+
+#ifdef WITH_UDEV
+ cleanup:
+    virCommandFree(cmd);
+#endif
+
+    return serial;
+}
+
+
+/*
+ * Attempt to create a new LUN
+ *
+ * Returns:
+ *
+ *  0  => Success
+ *  -1 => Failure due to some sort of OOM or other fatal issue found when
+ *        attempting to get/update information about a found volume
+ *  -2 => Failure to find a stable path, not fatal, caller can try another
+ */
+static int
+virStorageBackendSCSINewLun(virStoragePoolObjPtr pool,
+                            uint32_t host ATTRIBUTE_UNUSED,
+                            uint32_t bus,
+                            uint32_t target,
+                            uint32_t lun,
+                            const char *dev)
+{
+    virStorageVolDefPtr vol = NULL;
+    char *devpath = NULL;
+    int retval = -1;
+
+    /* Check if the pool is using a stable target path. The call to
+     * virStorageBackendStablePath will fail if the pool target path
+     * isn't stable and just return the strdup'd 'devpath' anyway.
+     * This would be indistinguishable to failing to find the stable
+     * path to the device if the virDirRead loop to search the
+     * target pool path for our devpath had failed.
+     */
+    if (!virStorageBackendPoolPathIsStable(pool->def->target.path) &&
+        !(STREQ(pool->def->target.path, "/dev") ||
+          STREQ(pool->def->target.path, "/dev/"))) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       _("unable to use target path '%s' for dev '%s'"),
+                       NULLSTR(pool->def->target.path), dev);
+        goto cleanup;
+    }
+
+    if (VIR_ALLOC(vol) < 0)
+        goto cleanup;
+
+    vol->type = VIR_STORAGE_VOL_BLOCK;
+
+    /* '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 uniqueness per-pool, so
+     * just leave 'host' out
+     */
+    if (virAsprintf(&(vol->name), "unit:%u:%u:%u", bus, target, lun) < 0)
+        goto cleanup;
+
+    if (virAsprintf(&devpath, "/dev/%s", dev) < 0)
+        goto cleanup;
+
+    VIR_DEBUG("Trying to create volume for '%s'", devpath);
+
+    /* Now figure out the stable path
+     *
+     * XXX this method is O(N) because it scans the pool target
+     * dir every time its run. Should figure out a more efficient
+     * way of doing this...
+     */
+    if ((vol->target.path = virStorageBackendStablePath(pool,
+                                                        devpath,
+                                                        true)) == NULL)
+        goto cleanup;
+
+    if (STREQ(devpath, vol->target.path) &&
+        !(STREQ(pool->def->target.path, "/dev") ||
+          STREQ(pool->def->target.path, "/dev/"))) {
+
+        VIR_DEBUG("No stable path found for '%s' in '%s'",
+                  devpath, pool->def->target.path);
+
+        retval = -2;
+        goto cleanup;
+    }
+
+    /* Allow a volume read failure to ignore or skip this block file */
+    if ((retval = virStorageBackendUpdateVolInfo(vol, true,
+                                                 VIR_STORAGE_VOL_OPEN_DEFAULT,
+                                                 VIR_STORAGE_VOL_READ_NOERROR)) < 0)
+        goto cleanup;
+
+    if (!(vol->key = virStorageBackendSCSISerial(vol->target.path)))
+        goto cleanup;
+
+    pool->def->capacity += vol->target.capacity;
+    pool->def->allocation += vol->target.allocation;
+
+    if (VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0)
+        goto cleanup;
+
+    vol = NULL;
+    retval = 0;
+
+ cleanup:
+    virStorageVolDefFree(vol);
+    VIR_FREE(devpath);
+    return retval;
+}
+
+
+
+static int
+getNewStyleBlockDevice(const char *lun_path,
+                       const char *block_name ATTRIBUTE_UNUSED,
+                       char **block_device)
+{
+    char *block_path = NULL;
+    DIR *block_dir = NULL;
+    struct dirent *block_dirent = NULL;
+    int retval = -1;
+    int direrr;
+
+    if (virAsprintf(&block_path, "%s/block", lun_path) < 0)
+        goto cleanup;
+
+    VIR_DEBUG("Looking for block device in '%s'", block_path);
+
+    if (virDirOpen(&block_dir, block_path) < 0)
+        goto cleanup;
+
+    while ((direrr = virDirRead(block_dir, &block_dirent, block_path)) > 0) {
+        if (VIR_STRDUP(*block_device, block_dirent->d_name) < 0)
+            goto cleanup;
+
+        VIR_DEBUG("Block device is '%s'", *block_device);
+
+        break;
+    }
+
+    if (direrr < 0)
+        goto cleanup;
+
+    retval = 0;
+
+ cleanup:
+    VIR_DIR_CLOSE(block_dir);
+    VIR_FREE(block_path);
+    return retval;
+}
+
+
+static int
+getOldStyleBlockDevice(const char *lun_path ATTRIBUTE_UNUSED,
+                       const char *block_name,
+                       char **block_device)
+{
+    char *blockp = NULL;
+    int retval = -1;
+
+    /* old-style; just parse out the sd */
+    if (!(blockp = strrchr(block_name, ':'))) {
+        /* Hm, wasn't what we were expecting; have to give up */
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Failed to parse block name %s"),
+                       block_name);
+        goto cleanup;
+    } else {
+        blockp++;
+        if (VIR_STRDUP(*block_device, blockp) < 0)
+            goto cleanup;
+
+        VIR_DEBUG("Block device is '%s'", *block_device);
+    }
+
+    retval = 0;
+ cleanup:
+    return retval;
+}
+
+
+/*
+ * Search a device entry for the "block" file
+ *
+ * Returns
+ *
+ *   0 => Found it
+ *   -1 => Fatal error
+ *   -2 => Didn't find in lun_path directory
+ */
+static int
+getBlockDevice(uint32_t host,
+               uint32_t bus,
+               uint32_t target,
+               uint32_t lun,
+               char **block_device)
+{
+    char *lun_path = NULL;
+    DIR *lun_dir = NULL;
+    struct dirent *lun_dirent = NULL;
+    int retval = -1;
+    int direrr;
+
+    *block_device = NULL;
+
+    if (virAsprintf(&lun_path, "/sys/bus/scsi/devices/%u:%u:%u:%u",
+                    host, bus, target, lun) < 0)
+        goto cleanup;
+
+    if (virDirOpen(&lun_dir, lun_path) < 0)
+        goto cleanup;
+
+    while ((direrr = virDirRead(lun_dir, &lun_dirent, lun_path)) > 0) {
+        if (STRPREFIX(lun_dirent->d_name, "block")) {
+            if (strlen(lun_dirent->d_name) == 5) {
+                if (getNewStyleBlockDevice(lun_path,
+                                           lun_dirent->d_name,
+                                           block_device) < 0)
+                    goto cleanup;
+            } else {
+                if (getOldStyleBlockDevice(lun_path,
+                                           lun_dirent->d_name,
+                                           block_device) < 0)
+                    goto cleanup;
+            }
+            break;
+        }
+    }
+    if (direrr < 0)
+        goto cleanup;
+    if (!*block_device) {
+        retval = -2;
+        goto cleanup;
+    }
+
+    retval = 0;
+
+ cleanup:
+    VIR_DIR_CLOSE(lun_dir);
+    VIR_FREE(lun_path);
+    return retval;
+}
+
+
+/* Function to check if the type file in the given sysfs_path is a
+ * Direct-Access device (i.e. type 0).  Return -1 on failure, type of
+ * the device otherwise.
+ */
+static int
+getDeviceType(uint32_t host,
+              uint32_t bus,
+              uint32_t target,
+              uint32_t lun,
+              int *type)
+{
+    char *type_path = NULL;
+    char typestr[3];
+    char *gottype, *p;
+    FILE *typefile;
+    int retval = 0;
+
+    if (virAsprintf(&type_path, "/sys/bus/scsi/devices/%u:%u:%u:%u/type",
+                    host, bus, target, lun) < 0)
+        goto out;
+
+    typefile = fopen(type_path, "r");
+    if (typefile == NULL) {
+        virReportSystemError(errno,
+                             _("Could not find typefile '%s'"),
+                             type_path);
+        /* there was no type file; that doesn't seem right */
+        retval = -1;
+        goto out;
+    }
+
+    gottype = fgets(typestr, 3, typefile);
+    VIR_FORCE_FCLOSE(typefile);
+
+    if (gottype == NULL) {
+        virReportSystemError(errno,
+                             _("Could not read typefile '%s'"),
+                             type_path);
+        /* we couldn't read the type file; have to give up */
+        retval = -1;
+        goto out;
+    }
+
+    /* we don't actually care about p, but if you pass NULL and the last
+     * character is not \0, virStrToLong_i complains
+     */
+    if (virStrToLong_i(typestr, &p, 10, type) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Device type '%s' is not an integer"),
+                       typestr);
+        /* Hm, type wasn't an integer; seems strange */
+        retval = -1;
+        goto out;
+    }
+
+    VIR_DEBUG("Device type is %d", *type);
+
+ out:
+    VIR_FREE(type_path);
+    return retval;
+}
+
+
+/*
+ * Process a Logical Unit entry from the scsi host device directory
+ *
+ * Returns:
+ *
+ *  0  => Found a valid entry
+ *  -1 => Some sort of fatal error
+ *  -2 => non-fatal error or a non-disk entry
+ */
+static int
+processLU(virStoragePoolObjPtr pool,
+          uint32_t host,
+          uint32_t bus,
+          uint32_t target,
+          uint32_t lun)
+{
+    int retval = -1;
+    int device_type;
+    char *block_device = NULL;
+
+    VIR_DEBUG("Processing LU %u:%u:%u:%u",
+              host, bus, target, lun);
+
+    if (getDeviceType(host, bus, target, lun, &device_type) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Failed to determine if %u:%u:%u:%u is a Direct-Access LUN"),
+                       host, bus, target, lun);
+        return -1;
+    }
+
+    /* We don't create volumes for devices other than disk and cdrom
+     * devices, but finding a device that isn't one of those types
+     * isn't an error, either. */
+    if (!(device_type == VIR_STORAGE_DEVICE_TYPE_DISK ||
+          device_type == VIR_STORAGE_DEVICE_TYPE_ROM))
+        return -2;
+
+    VIR_DEBUG("%u:%u:%u:%u is a Direct-Access LUN",
+              host, bus, target, lun);
+
+    if ((retval = getBlockDevice(host, bus, target, lun, &block_device)) < 0) {
+        VIR_DEBUG("Failed to find block device for this LUN");
+        return retval;
+    }
+
+    retval = virStorageBackendSCSINewLun(pool, host, bus, target, lun,
+                                         block_device);
+    if (retval < 0) {
+        VIR_DEBUG("Failed to create new storage volume for %u:%u:%u:%u",
+                  host, bus, target, lun);
+        goto cleanup;
+    }
+
+    VIR_DEBUG("Created new storage volume for %u:%u:%u:%u successfully",
+              host, bus, target, lun);
+
+ cleanup:
+    VIR_FREE(block_device);
+    return retval;
+}
+
+
+int
+virStorageBackendSCSIFindLUs(virStoragePoolObjPtr pool,
+                              uint32_t scanhost)
+{
+    int retval = 0;
+    uint32_t bus, target, lun;
+    const char *device_path = "/sys/bus/scsi/devices";
+    DIR *devicedir = NULL;
+    struct dirent *lun_dirent = NULL;
+    char devicepattern[64];
+    int found = 0;
+
+    VIR_DEBUG("Discovering LUs on host %u", scanhost);
+
+    virFileWaitForDevices();
+
+    if (virDirOpen(&devicedir, device_path) < 0)
+        return -1;
+
+    snprintf(devicepattern, sizeof(devicepattern), "%u:%%u:%%u:%%u\n", scanhost);
+
+    while ((retval = virDirRead(devicedir, &lun_dirent, device_path)) > 0) {
+        int rc;
+
+        if (sscanf(lun_dirent->d_name, devicepattern,
+                   &bus, &target, &lun) != 3) {
+            continue;
+        }
+
+        VIR_DEBUG("Found possible LU '%s'", lun_dirent->d_name);
+
+        rc = processLU(pool, scanhost, bus, target, lun);
+        if (rc == -1) {
+            retval = -1;
+            break;
+        }
+        if (rc == 0)
+            found++;
+    }
+
+    VIR_DIR_CLOSE(devicedir);
+
+    if (retval < 0)
+        return -1;
+
+    VIR_DEBUG("Found %d LUs for pool %s", found, pool->def->name);
+
+    return found;
+}
diff --git a/src/storage/storage_util.h b/src/storage/storage_util.h
index 0555ae1e8..8bf0f42df 100644
--- a/src/storage/storage_util.h
+++ b/src/storage/storage_util.h
@@ -145,4 +145,7 @@ virStorageBackendCreateQemuImgCmdFromVol(virConnectPtr conn,
                                          int imgformat,
                                          const char *secretPath);

+int virStorageBackendSCSIFindLUs(virStoragePoolObjPtr pool,
+                                 uint32_t scanhost);
+
 #endif /* __VIR_STORAGE_UTIL_H__ */
-- 
2.11.0




More information about the libvir-list mailing list