--- 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); }