[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Libvir] [PATCH]: Make the iscsi backend work with updated iscsiadm tools



All,
     Updated versions of the iscsi-initiator-utils changed the output structure
from the "iscsiadm -m session -P 3" command, which is being used in
storage_backend_iscsi.c to gather the scsi devices available in a pool and
present them as volumes.  Consequently, when starting an iSCSI pool on a machine
with a newer version of the iscsi tools, you can successfully define the pool,
but will fail to find any LUNs on it.

The attached patch lessens our dependency on this command by groping around
sysfs for the information, instead of parsing it from the iscsiadm command.  We
still parse the command to get target, channel, id, and lun numbers, but then we
cruise through sysfs looking for the corresponding /dev/sd? devices ourselves.
This makes the libvirt iSCSI backend work for both older iscsiadm and newer
iscsiadm.

After much wrangling with iscsiadm and friends, I came to the conclusion that
this is the best we can do with the current state of the iscsi tools; from what
I can tell, there is no (simple) way to get away from parsing the iscsiadm output.

This is a repost of a patch I had originally posted on 2/21; this patch
incorporates Jim's comments at that time, and also adds better error checking
and error strings.  Please review and commit as appropriate.

Signed-off-by: Chris Lalancette <clalance redhat com>
--- a/src/storage_backend_iscsi.c	4 Mar 2008 20:02:34 -0000	1.3
+++ b/src/storage_backend_iscsi.c	26 Mar 2008 22:07:05 -0000
@@ -170,20 +170,91 @@
 virStorageBackendISCSIMakeLUN(virConnectPtr conn,
                               virStoragePoolObjPtr pool,
                               char **const groups,
-                              void *data ATTRIBUTE_UNUSED)
+                              void *data)
 {
     virStorageVolDefPtr vol;
     int fd = -1;
+    unsigned int target, channel, id, lun;
     char lunid[100];
-    char *dev = groups[4];
     int opentries = 0;
     char *devpath = NULL;
+    char *session = data;
+    char sysfs_path[PATH_MAX];
+    char *dev = NULL;
+    DIR *sysdir;
+    struct dirent *block_dirent;
+    struct stat sbuf;
+    int len;
+
+    if ((virStrToLong_ui(groups[0], NULL, 10, &target) < 0) ||
+        (virStrToLong_ui(groups[1], NULL, 10, &channel) < 0) ||
+        (virStrToLong_ui(groups[2], NULL, 10, &id) < 0) ||
+        (virStrToLong_ui(groups[3], NULL, 10, &lun) < 0)) {
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
+                              _("Failed parsing iscsiadm commands"));
+        return -1;
+    }
+
+    if (lun == 0) {
+        /* the 0'th LUN isn't a real LUN, it's just a control LUN; skip it */
+        return 0;
+    }
+
+    snprintf(sysfs_path, PATH_MAX,
+             "/sys/class/iscsi_session/session%s/device/"
+             "target%d:%d:%d/%d:%d:%d:%d/block",
+             session, target, channel, id, target, channel, id, lun);
+
+    if (stat(sysfs_path, &sbuf) < 0) {
+        /* block path in subdir didn't exist; this is unexpected, so fail */
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                              _("Failed to find the sysfs path for %d:%d:%d:%d: %s"),
+                              target, channel, id, lun, strerror(errno));
+        return -1;
+    }
+
+    sysdir = opendir(sysfs_path);
+    if (sysdir == NULL) {
+        /* we failed for some reason; return an error */
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                              _("Failed to opendir sysfs path %s: %s"),
+                              sysfs_path, strerror(errno));
+        return -1;
+    }
+
+    while ((block_dirent = readdir(sysdir)) != NULL) {
+        len = strlen(block_dirent->d_name);
+        if ((len == 1 && block_dirent->d_name[0] == '.') ||
+            (len == 2 && block_dirent->d_name[0] == '.' && block_dirent->d_name[1] == '.')) {
+            /* the . and .. directories; just skip them */
+            continue;
+        }
+
+        /* OK, not . or ..; let's see if it is a SCSI device */
+        if (len > 2 &&
+            block_dirent->d_name[0] == 's' &&
+            block_dirent->d_name[1] == 'd') {
+            /* looks like a scsi device, smells like scsi device; it must be
+               a scsi device */
+            dev = strdup(block_dirent->d_name);
+            break;
+        }
+    }
+    closedir(sysdir);
+
+    if (dev == NULL) {
+        /* we didn't find the sd? device we were looking for; fail */
+        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                              _("Failed to find SCSI device for %d:%d:%d:%d: %s"),
+                              target, channel, id, lun, strerror(errno));
+        return -1;
+    }
 
     snprintf(lunid, sizeof(lunid)-1, "lun-%s", groups[3]);
 
     if ((vol = calloc(1, sizeof(virStorageVolDef))) == NULL) {
         virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s", _("volume"));
-        return -1;
+        goto cleanup;
     }
 
     if ((vol->name = strdup(lunid)) == NULL) {
@@ -197,6 +268,8 @@
     }
     strcpy(devpath, "/dev/");
     strcat(devpath, dev);
+    free(dev);
+    dev = NULL;
     /* It can take a little while between logging into the ISCSI
      * server and udev creating the /dev nodes, so if we get ENOENT
      * we must retry a few times - they should eventually appear.
@@ -258,6 +331,7 @@
     if (fd != -1) close(fd);
     free(devpath);
     virStorageVolDefFree(vol);
+    free(dev);
     return -1;
 }
 
@@ -281,14 +355,13 @@
      *           scsi1 Channel 00 Id 0 Lun: 5
      *                   Attached scsi disk sdg          State: running
      *
-     * Need 2 regex to match alternating lines
+     * Need a regex to match the Channel:Id:Lun lines
      */
     const char *regexes[] = {
-        "^\\s*scsi(\\S+)\\s+Channel\\s+(\\S+)\\s+Id\\s+(\\S+)\\s+Lun:\\s+(\\S+)\\s*$",
-        "^\\s*Attached\\s+scsi\\s+disk\\s+(\\S+)\\s+State:\\s+running\\s*$"
+        "^\\s*scsi(\\S+)\\s+Channel\\s+(\\S+)\\s+Id\\s+(\\S+)\\s+Lun:\\s+(\\S+)\\s*$"
     };
     int vars[] = {
-        4, 1
+        4
     };
     const char *prog[] = {
         ISCSIADM, "--mode", "session", "-r", session, "-P", "3", NULL,
@@ -296,11 +369,11 @@
 
     return virStorageBackendRunProgRegex(conn, pool,
                                          prog,
-                                         2,
+                                         1,
                                          regexes,
                                          vars,
                                          virStorageBackendISCSIMakeLUN,
-                                         NULL);
+                                         (void *)session);
 }
 
 

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]