[libvirt] [PATCH 1/1] Add SCSI pool support.

Daniel P. Berrange berrange at redhat.com
Fri Mar 27 12:59:19 UTC 2009


On Thu, Mar 26, 2009 at 05:55:48PM -0400, David Allan wrote:
> It does not attempt to add a volume if it cannot find a stable 
> path for a particular LU, for example, if the user specifies a 
> target path by-id and the LU is one path of a multipath device.

This will cause  a regression in current behaviour - if a device
does not have a stable path, the semantics are that we just expose
the raw path /dev/sdXX.

> diff --git a/src/storage_backend_scsi.c b/src/storage_backend_scsi.c
> new file mode 100644
> index 0000000..62c05ae
> +static int
> +processLU(virConnectPtr conn,
> +          virStoragePoolObjPtr pool,
> +          uint32_t host,
> +          uint32_t bus,
> +          uint32_t target,
> +          uint32_t lun)
> +{
> +    char *type_path = NULL;
> +    int retval = 0;
> +    int device_type;
> +    char *block_device = NULL;
> +
> +    VIR_DEBUG(_("Processing LU %u:%u:%u:%u"),
> +              host, bus, target, lun);
> +
> +    if (getDeviceType(conn, host, bus, target, lun, &device_type) < 0) {
> +        virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
> +                              _("Failed to determine if %u:%u:%u:%u is a Direct-Access LUN"),
> +                              host, bus, target, lun);
> +        retval = -1;
> +        goto out;
> +    }
> +
> +    /* We don't use anything except Direct-Access devices, but finding
> +     * one isn't an error, either. */
> +    if (device_type != 0) {
> +        retval = 0;
> +        goto out;
> +    }

This is not quite right - it is valid for LUNs to have a non-zero device
type. For example, defining a SCSI pool for the IDE controller associated
with the CDROM device causes it not to expose the CDROM device LUN. This
is because it has a device type of 0x5 instead of 0x0

These values in sysfs come from these constants

#define TYPE_DISK           0x00
#define TYPE_TAPE           0x01
#define TYPE_PRINTER        0x02
#define TYPE_PROCESSOR      0x03    /* HP scanners use this */
#define TYPE_WORM           0x04    /* Treated as ROM by our system */
#define TYPE_ROM            0x05
#define TYPE_SCANNER        0x06
#define TYPE_MOD            0x07    /* Magneto-optical disk - 
                                     * - treated as TYPE_DISK */
#define TYPE_MEDIUM_CHANGER 0x08
#define TYPE_COMM           0x09    /* Communications device */
#define TYPE_RAID           0x0c
#define TYPE_ENCLOSURE      0x0d    /* Enclosure Services Device */
#define TYPE_RBC            0x0e
#define TYPE_NO_LUN         0x7f

So we probably want to allow TYPE_DISK, TYPE_TAPE, TYPE_WORM, TYPE_ROM,
TYPE_MOD.

The Linux iSCSI target exposes one special 'controller' device as LUN-0
For some reason they have given this TYPE_RAID, so we need to skip this
one.

> +
> +    VIR_DEBUG(_("%u:%u:%u:%u is a Direct-Access LUN"),
> +              host, bus, target, lun);
> +
> +    if (getBlockDevice(conn, host, bus, target, lun, &block_device) < 0) {
> +        goto out;
> +    }
> +
> +    if (virStorageBackendSCSINewLun(conn, pool,
> +                                    host, bus, target, lun,
> +                                    block_device) < 0) {
> +        VIR_DEBUG(_("Failed to create new storage volume for %u:%u:%u:%u"),
> +                  host, bus, target, lun);
> +        retval = -1;
> +        goto out;
> +    }
> +
> +    VIR_DEBUG(_("Created new storage volume for %u:%u:%u:%u successfully"),
> +              host, bus, target, lun);
> +
> +    VIR_FREE(type_path);
> +
> +out:
> +    return retval;
> +}
> +
> +
> +static int
> +virStorageBackendSCSIFindLUs(virConnectPtr conn,
> +                             virStoragePoolObjPtr pool,
> +                             uint32_t scanhost,
> +                             uint32_t scanbus,
> +                             uint32_t scantarget)
> +{
> +    int retval = 0;
> +    uint32_t host, bus, target, lun;
> +    char *target_path = NULL;
> +    DIR *targetdir = NULL;
> +    struct dirent *lun_dirent = NULL;
> +
> +    VIR_DEBUG(_("Discovering LUs on host %u bus %u target %u"),
> +              scanhost, scanbus, scantarget);
> +
> +    if (virAsprintf(&target_path, "/sys/bus/scsi/devices/target%u:%u:%u",
> +             scanhost, scanbus, scantarget) < 0) {
> +        virReportOOMError(conn);
> +        goto out;
> +    }

This unfortauntely does not work on RHEL5, because there are no targetX.X.X
links here. Only the LUNs appear in this directory.

The location which appears to be present on both old and new kernels is
under:

   /sys/class/scsi_host/host0/device/targetX.X.X

This appears to be present for both SCSI and iSCSI hosts.

> +
> +    targetdir = opendir(target_path);
> +
> +    if (targetdir == NULL) {
> +        virReportSystemError(conn, errno,
> +                             _("Failed to opendir path '%s'"), target_path);
> +        retval = -1;
> +        goto out;
> +    }
> +
> +    while ((lun_dirent = readdir(targetdir))) {
> +        if (sscanf(lun_dirent->d_name, "%u:%u:%u:%u\n",
> +                   &host, &bus, &target, &lun) != 4) {
> +            continue;
> +        }
> +
> +        VIR_DEBUG(_("Found LU '%s'"), lun_dirent->d_name);
> +
> +        processLU(conn, pool, host, bus, target, lun);
> +    }
> +
> +    closedir(targetdir);
> +
> +out:
> +    VIR_FREE(target_path);
> +    return retval;
> +}
> +
> +
> +int
> +virStorageBackendSCSIFindTargets(virConnectPtr conn,
> +                                 virStoragePoolObjPtr pool,
> +                                 const char *sysfs_path,
> +                                 const char *pattern)
> +{
> +    int retval = 0;
> +    uint32_t host, bus, target;
> +    DIR *sysdir = NULL;
> +    struct dirent *dirent = NULL;
> +
> +    VIR_DEBUG(_("Discovering targets in '%s'"), sysfs_path);
> +
> +    sysdir = opendir(sysfs_path);
> +
> +    if (sysdir == NULL) {
> +        virReportSystemError(conn, errno,
> +                             _("Failed to opendir path '%s'"), sysfs_path);
> +        retval = -1;
> +        goto out;
> +    }
> +
> +    while ((dirent = readdir(sysdir))) {
> +        if (STREQLEN(dirent->d_name, pattern, strlen(pattern))) {
> +            if (sscanf(dirent->d_name,
> +                       "target%u:%u:%u", &host, &bus, &target) != 3) {
> +                VIR_DEBUG(_("Failed to parse target '%s'"), dirent->d_name);
> +                retval = -1;
> +                break;
> +            }
> +            virStorageBackendSCSIFindLUs(conn, pool, host, bus, target);
> +        }
> +    }
> +
> +    closedir(sysdir);
> +out:
> +    return retval;
> +}
> +
> +
> +static int
> +virStorageBackendSCSIRefreshPool(virConnectPtr conn,
> +                                 virStoragePoolObjPtr pool)
> +{
> +    char targetN[64];
> +    int retval = 0;
> +    uint32_t host;
> +
> +    pool->def->allocation = pool->def->capacity = pool->def->available = 0;
> +
> +    virStorageBackendWaitForDevices(conn);
> +
> +    if (sscanf(pool->def->source.adapter, "host%u", &host) != 1) {
> +        VIR_DEBUG(_("Failed to get host number from '%s'"), pool->def->source.adapter);
> +        retval = -1;
> +        goto out;
> +    }
> +
> +    VIR_DEBUG(_("Scanning host%u"), host);
> +
> +    snprintf(targetN, sizeof(targetN), "target%u", host);
> +
> +    virStorageBackendSCSIFindTargets(conn, pool, "/sys/bus/scsi/devices", targetN);


This path doesn't work for same reason as earlier comment - targetX.X.X does
not exist under this location in RHEL-5 vintage kernels.

Since you already have the 'hostX' name, you can just go straight to

    /sys/class/scsi_host/host0/device

to find the target.X.X.X  name.


Daniel
-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




More information about the libvir-list mailing list