Example #1
0
void
virSCSIDeviceListDel(virSCSIDeviceListPtr list,
                     virSCSIDevicePtr dev)
{
    virSCSIDevicePtr ret = virSCSIDeviceListSteal(list, dev);
    virSCSIDeviceFree(ret);
}
Example #2
0
static void
virSCSIDeviceListDispose(void *obj)
{
    virSCSIDeviceListPtr list = obj;
    size_t i;

    for (i = 0; i < list->count; i++)
        virSCSIDeviceFree(list->devs[i]);

    VIR_FREE(list->devs);
}
Example #3
0
int
qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver,
                             virDomainDefPtr def)
{
    virDomainHostdevDefPtr hostdev = NULL;
    int i;
    int ret = -1;

    if (!def->nhostdevs)
        return 0;

    virObjectLock(driver->activeScsiHostdevs);
    for (i = 0; i < def->nhostdevs; i++) {
        virSCSIDevicePtr scsi = NULL;
        hostdev = def->hostdevs[i];

        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
            hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)
            continue;

        if (!(scsi = virSCSIDeviceNew(hostdev->source.subsys.u.scsi.adapter,
                                      hostdev->source.subsys.u.scsi.bus,
                                      hostdev->source.subsys.u.scsi.target,
                                      hostdev->source.subsys.u.scsi.unit,
                                      hostdev->readonly)))
            goto cleanup;

        virSCSIDeviceSetUsedBy(scsi, def->name);

        if (virSCSIDeviceListAdd(driver->activeScsiHostdevs, scsi) < 0) {
            virSCSIDeviceFree(scsi);
            goto cleanup;
        }
    }
    ret = 0;

cleanup:
    virObjectUnlock(driver->activeScsiHostdevs);
    return ret;
}
Example #4
0
void
virSCSIDeviceListDel(virSCSIDeviceListPtr list,
                     virSCSIDevicePtr dev,
                     const char *drvname,
                     const char *domname)
{
    virSCSIDevicePtr tmp = NULL;
    size_t i;

    for (i = 0; i < dev->n_used_by; i++) {
        if (STREQ_NULLABLE(dev->used_by[i]->drvname, drvname) &&
            STREQ_NULLABLE(dev->used_by[i]->domname, domname)) {
            if (dev->n_used_by > 1) {
                virSCSIDeviceUsedByInfoFree(dev->used_by[i]);
                VIR_DELETE_ELEMENT(dev->used_by, i, dev->n_used_by);
            } else {
                tmp = virSCSIDeviceListSteal(list, dev);
                virSCSIDeviceFree(tmp);
            }
            break;
        }
    }
}
Example #5
0
int
qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver,
                              const char *name,
                              virDomainHostdevDefPtr *hostdevs,
                              int nhostdevs)
{
    int i, j, count;
    virSCSIDeviceListPtr list;
    virSCSIDevicePtr tmp;

    /* Loop 1: Add the shared scsi host device to shared device
     * table.
     */
    for (i = 0; i < nhostdevs; i++) {
        virDomainDeviceDef dev;

        dev.type = VIR_DOMAIN_DEVICE_HOSTDEV;
        dev.data.hostdev = hostdevs[i];

        if (qemuAddSharedDevice(driver, &dev, name) < 0)
            return -1;

        if (qemuSetUnprivSGIO(&dev) < 0)
            return -1;
    }

    /* To prevent situation where SCSI device is assigned to two domains
     * we need to keep a list of currently assigned SCSI devices.
     * This is done in several loops which cannot be joined into one big
     * loop. See qemuPrepareHostdevPCIDevices()
     */
    if (!(list = virSCSIDeviceListNew()))
        goto cleanup;

    /* Loop 2: build temporary list */
    for (i = 0; i < nhostdevs; i++) {
        virDomainHostdevDefPtr hostdev = hostdevs[i];
        virSCSIDevicePtr scsi;

        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
            hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)
            continue;

        if (hostdev->managed) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("SCSI host device doesn't support managed mode"));
            goto cleanup;
        }

        if (!(scsi = virSCSIDeviceNew(hostdev->source.subsys.u.scsi.adapter,
                                      hostdev->source.subsys.u.scsi.bus,
                                      hostdev->source.subsys.u.scsi.target,
                                      hostdev->source.subsys.u.scsi.unit,
                                      hostdev->readonly)))
            goto cleanup;

        if (scsi && virSCSIDeviceListAdd(list, scsi) < 0) {
            virSCSIDeviceFree(scsi);
            goto cleanup;
        }
    }

    /* Loop 3: Mark devices in temporary list as used by @name
     * and add them to driver list. However, if something goes
     * wrong, perform rollback.
     */
    virObjectLock(driver->activeScsiHostdevs);
    count = virSCSIDeviceListCount(list);

    for (i = 0; i < count; i++) {
        virSCSIDevicePtr scsi = virSCSIDeviceListGet(list, i);
        if ((tmp = virSCSIDeviceListFind(driver->activeScsiHostdevs, scsi))) {
            const char *other_name = virSCSIDeviceGetUsedBy(tmp);

            if (other_name)
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("SCSI device %s is in use by domain %s"),
                               virSCSIDeviceGetName(tmp), other_name);
            else
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("SCSI device %s is already in use"),
                               virSCSIDeviceGetName(tmp));
            goto error;
        }

        virSCSIDeviceSetUsedBy(scsi, name);
        VIR_DEBUG("Adding %s to activeScsiHostdevs", virSCSIDeviceGetName(scsi));

        if (virSCSIDeviceListAdd(driver->activeScsiHostdevs, scsi) < 0)
            goto error;
    }

    virObjectUnlock(driver->activeScsiHostdevs);

    /* Loop 4: Temporary list was successfully merged with
     * driver list, so steal all items to avoid freeing them
     * when freeing temporary list.
     */
    while (virSCSIDeviceListCount(list) > 0) {
        tmp = virSCSIDeviceListGet(list, 0);
        virSCSIDeviceListSteal(list, tmp);
    }

    virObjectUnref(list);
    return 0;

error:
    for (j = 0; j < i; j++) {
        tmp = virSCSIDeviceListGet(list, i);
        virSCSIDeviceListSteal(driver->activeScsiHostdevs, tmp);
    }
    virObjectUnlock(driver->activeScsiHostdevs);
cleanup:
    virObjectUnref(list);
    return -1;
}
Example #6
0
void
qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver,
                                  const char *name,
                                  virDomainHostdevDefPtr *hostdevs,
                                  int nhostdevs)
{
    int i;

    virObjectLock(driver->activeScsiHostdevs);
    for (i = 0; i < nhostdevs; i++) {
        virDomainHostdevDefPtr hostdev = hostdevs[i];
        virSCSIDevicePtr scsi, tmp;
        const char *used_by = NULL;
        virDomainDeviceDef dev;

        dev.type = VIR_DOMAIN_DEVICE_HOSTDEV;
        dev.data.hostdev = hostdev;

        ignore_value(qemuRemoveSharedDevice(driver, &dev, name));

        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
            hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)
            continue;

        if (!(scsi = virSCSIDeviceNew(hostdev->source.subsys.u.scsi.adapter,
                                      hostdev->source.subsys.u.scsi.bus,
                                      hostdev->source.subsys.u.scsi.target,
                                      hostdev->source.subsys.u.scsi.unit,
                                      hostdev->readonly))) {
            VIR_WARN("Unable to reattach SCSI device %s:%d:%d:%d on domain %s",
                     hostdev->source.subsys.u.scsi.adapter,
                     hostdev->source.subsys.u.scsi.bus,
                     hostdev->source.subsys.u.scsi.target,
                     hostdev->source.subsys.u.scsi.unit,
                     name);
            continue;
        }

        /* Only delete the devices which are marked as being used by @name,
         * because qemuProcessStart could fail on the half way. */

        tmp = virSCSIDeviceListFind(driver->activeScsiHostdevs, scsi);
        virSCSIDeviceFree(scsi);

        if (!tmp) {
            VIR_WARN("Unable to find device %s:%d:%d:%d "
                     "in list of active SCSI devices",
                     hostdev->source.subsys.u.scsi.adapter,
                     hostdev->source.subsys.u.scsi.bus,
                     hostdev->source.subsys.u.scsi.target,
                     hostdev->source.subsys.u.scsi.unit);
            continue;
        }

        used_by = virSCSIDeviceGetUsedBy(tmp);
        if (STREQ_NULLABLE(used_by, name)) {
            VIR_DEBUG("Removing %s:%d:%d:%d dom=%s from activeScsiHostdevs",
                      hostdev->source.subsys.u.scsi.adapter,
                      hostdev->source.subsys.u.scsi.bus,
                      hostdev->source.subsys.u.scsi.target,
                      hostdev->source.subsys.u.scsi.unit,
                      name);

            virSCSIDeviceListDel(driver->activeScsiHostdevs, tmp);
        }
    }
    virObjectUnlock(driver->activeScsiHostdevs);
}
Example #7
0
int
qemuSetupHostdevCGroup(virDomainObjPtr vm,
                       virDomainHostdevDefPtr dev)
{
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainHostdevSubsysUSBPtr usbsrc = &dev->source.subsys.u.usb;
    virDomainHostdevSubsysPCIPtr pcisrc = &dev->source.subsys.u.pci;
    virDomainHostdevSubsysSCSIPtr scsisrc = &dev->source.subsys.u.scsi;
    virPCIDevicePtr pci = NULL;
    virUSBDevicePtr usb = NULL;
    virSCSIDevicePtr scsi = NULL;
    char *path = NULL;

    /* currently this only does something for PCI devices using vfio
     * for device assignment, but it is called for *all* hostdev
     * devices.
     */

    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES))
        return 0;

    if (dev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {

        switch (dev->source.subsys.type) {
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
            if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
                int rv;

                pci = virPCIDeviceNew(pcisrc->addr.domain,
                                      pcisrc->addr.bus,
                                      pcisrc->addr.slot,
                                      pcisrc->addr.function);
                if (!pci)
                    goto cleanup;

                if (!(path = virPCIDeviceGetIOMMUGroupDev(pci)))
                    goto cleanup;

                VIR_DEBUG("Cgroup allow %s for PCI device assignment", path);
                rv = virCgroupAllowDevicePath(priv->cgroup, path,
                                              VIR_CGROUP_DEVICE_RW);
                virDomainAuditCgroupPath(vm, priv->cgroup,
                                         "allow", path, "rw", rv == 0);
                if (rv < 0)
                    goto cleanup;
            }
            break;

        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
            /* NB: hostdev->missing wasn't previously checked in the
             * case of hotplug, only when starting a domain. Now it is
             * always checked, and the cgroup setup skipped if true.
             */
            if (dev->missing)
                break;
            if ((usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device,
                                       NULL)) == NULL) {
                goto cleanup;
            }

            /* oddly, qemuSetupHostUSBDeviceCgroup doesn't ever
             * reference the usb object we just created
             */
            if (virUSBDeviceFileIterate(usb, qemuSetupHostUSBDeviceCgroup,
                                        vm) < 0) {
                goto cleanup;
            }
            break;

        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
            if (scsisrc->protocol ==
                VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) {
                virDomainHostdevSubsysSCSIiSCSIPtr iscsisrc = &scsisrc->u.iscsi;
                /* Follow qemuSetupDiskCgroup() and qemuSetImageCgroupInternal()
                 * which does nothing for non local storage
                 */
                VIR_DEBUG("Not updating cgroups for hostdev iSCSI path '%s'",
                          iscsisrc->path);
            } else {
                virDomainHostdevSubsysSCSIHostPtr scsihostsrc =
                    &scsisrc->u.host;
                if ((scsi = virSCSIDeviceNew(NULL,
                                             scsihostsrc->adapter,
                                             scsihostsrc->bus,
                                             scsihostsrc->target,
                                             scsihostsrc->unit,
                                             dev->readonly,
                                             dev->shareable)) == NULL)
                    goto cleanup;

                if (virSCSIDeviceFileIterate(scsi,
                                             qemuSetupHostSCSIDeviceCgroup,
                                             vm) < 0)
                    goto cleanup;
            }
            break;
        }

        default:
            break;
        }
    }

    ret = 0;
 cleanup:
    virPCIDeviceFree(pci);
    virUSBDeviceFree(usb);
    virSCSIDeviceFree(scsi);
    VIR_FREE(path);
    return ret;
}
Example #8
0
int
qemuSetupHostdevCGroup(virDomainObjPtr vm,
                       virDomainHostdevDefPtr dev)
{
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virPCIDevicePtr pci = NULL;
    virUSBDevicePtr usb = NULL;
    virSCSIDevicePtr scsi = NULL;
    char *path = NULL;

    /* currently this only does something for PCI devices using vfio
     * for device assignment, but it is called for *all* hostdev
     * devices.
     */

    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_DEVICES))
        return 0;

    if (dev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {

        switch (dev->source.subsys.type) {
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
            if (dev->source.subsys.u.pci.backend
                == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
                int rv;

                pci = virPCIDeviceNew(dev->source.subsys.u.pci.addr.domain,
                                      dev->source.subsys.u.pci.addr.bus,
                                      dev->source.subsys.u.pci.addr.slot,
                                      dev->source.subsys.u.pci.addr.function);
                if (!pci)
                    goto cleanup;

                if (!(path = virPCIDeviceGetIOMMUGroupDev(pci)))
                    goto cleanup;

                VIR_DEBUG("Cgroup allow %s for PCI device assignment", path);
                rv = virCgroupAllowDevicePath(priv->cgroup, path,
                                              VIR_CGROUP_DEVICE_RW);
                virDomainAuditCgroupPath(vm, priv->cgroup,
                                         "allow", path, "rw", rv == 0);
                if (rv < 0)
                    goto cleanup;
            }
            break;

        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
            /* NB: hostdev->missing wasn't previously checked in the
             * case of hotplug, only when starting a domain. Now it is
             * always checked, and the cgroup setup skipped if true.
             */
            if (dev->missing)
                break;
            if ((usb = virUSBDeviceNew(dev->source.subsys.u.usb.bus,
                                       dev->source.subsys.u.usb.device,
                                       NULL)) == NULL) {
                goto cleanup;
            }

            /* oddly, qemuSetupHostUSBDeviceCgroup doesn't ever
             * reference the usb object we just created
             */
            if (virUSBDeviceFileIterate(usb, qemuSetupHostUSBDeviceCgroup,
                                        vm) < 0) {
                goto cleanup;
            }
            break;

        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
            if ((scsi = virSCSIDeviceNew(NULL,
                                         dev->source.subsys.u.scsi.adapter,
                                         dev->source.subsys.u.scsi.bus,
                                         dev->source.subsys.u.scsi.target,
                                         dev->source.subsys.u.scsi.unit,
                                         dev->readonly,
                                         dev->shareable)) == NULL)
                goto cleanup;

            if (virSCSIDeviceFileIterate(scsi,
                                         qemuSetupHostSCSIDeviceCgroup,
                                         vm) < 0)
                goto cleanup;

        default:
            break;
        }
    }

    ret = 0;
 cleanup:
    virPCIDeviceFree(pci);
    virUSBDeviceFree(usb);
    virSCSIDeviceFree(scsi);
    VIR_FREE(path);
    return ret;
}
Example #9
0
virSCSIDevicePtr
virSCSIDeviceNew(const char *adapter,
                 unsigned int bus,
                 unsigned int target,
                 unsigned int unit,
                 bool readonly)
{
    virSCSIDevicePtr dev, ret = NULL;
    char *sg = NULL;
    char *vendor_path = NULL;
    char *model_path = NULL;
    char *vendor = NULL;
    char *model = NULL;

    if (VIR_ALLOC(dev) < 0)
        return NULL;

    dev->bus = bus;
    dev->target = target;
    dev->unit = unit;
    dev->readonly = readonly;

    if (!(sg = virSCSIDeviceGetSgName(adapter, bus, target, unit)))
        goto cleanup;

    if (virSCSIDeviceGetAdapterId(adapter, &dev->adapter) < 0)
        goto cleanup;

    if (virAsprintf(&dev->name, "%d:%d:%d:%d", dev->adapter,
                    dev->bus, dev->target, dev->unit) < 0 ||
        virAsprintf(&dev->sg_path, "/dev/%s", sg) < 0)
        goto cleanup;

    if (access(dev->sg_path, F_OK) != 0) {
        virReportSystemError(errno,
                             _("SCSI device '%s': could not access %s"),
                             dev->name, dev->sg_path);
        goto cleanup;
    }

    if (virAsprintf(&vendor_path,
                    SYSFS_SCSI_DEVICES "/%s/vendor", dev->name) < 0 ||
        virAsprintf(&model_path,
                    SYSFS_SCSI_DEVICES "/%s/model", dev->name) < 0)
        goto cleanup;

    if (virFileReadAll(vendor_path, 1024, &vendor) < 0)
        goto cleanup;

    if (virFileReadAll(model_path, 1024, &model) < 0)
        goto cleanup;

    virTrimSpaces(vendor, NULL);
    virTrimSpaces(model, NULL);

    if (virAsprintf(&dev->id, "%s:%s", vendor, model) < 0)
        goto cleanup;

    ret = dev;
cleanup:
    VIR_FREE(sg);
    VIR_FREE(vendor);
    VIR_FREE(model);
    VIR_FREE(vendor_path);
    VIR_FREE(model_path);
    if (!ret)
        virSCSIDeviceFree(dev);
    return ret;
}
Example #10
0
virSCSIDevicePtr
virSCSIDeviceNew(const char *sysfs_prefix,
                 const char *adapter,
                 unsigned int bus,
                 unsigned int target,
                 unsigned long long unit,
                 bool readonly,
                 bool shareable)
{
    virSCSIDevicePtr dev, ret = NULL;
    char *sg = NULL;
    char *vendor_path = NULL;
    char *model_path = NULL;
    char *vendor = NULL;
    char *model = NULL;
    const char *prefix = sysfs_prefix ? sysfs_prefix : SYSFS_SCSI_DEVICES;

    if (VIR_ALLOC(dev) < 0)
        return NULL;

    dev->bus = bus;
    dev->target = target;
    dev->unit = unit;
    dev->readonly = readonly;
    dev->shareable = shareable;

    if (!(sg = virSCSIDeviceGetSgName(prefix, adapter, bus, target, unit)))
        goto cleanup;

    if (virSCSIDeviceGetAdapterId(adapter, &dev->adapter) < 0)
        goto cleanup;

    if (virAsprintf(&dev->name, "%d:%u:%u:%llu", dev->adapter,
                    dev->bus, dev->target, dev->unit) < 0 ||
        virAsprintf(&dev->sg_path, "%s/%s",
                    sysfs_prefix ? sysfs_prefix : "/dev", sg) < 0)
        goto cleanup;

    if (!virFileExists(dev->sg_path)) {
        virReportSystemError(errno,
                             _("SCSI device '%s': could not access %s"),
                             dev->name, dev->sg_path);
        goto cleanup;
    }

    if (virAsprintf(&vendor_path,
                    "%s/%s/vendor", prefix, dev->name) < 0 ||
        virAsprintf(&model_path,
                    "%s/%s/model", prefix, dev->name) < 0)
        goto cleanup;

    if (virFileReadAll(vendor_path, 1024, &vendor) < 0)
        goto cleanup;

    if (virFileReadAll(model_path, 1024, &model) < 0)
        goto cleanup;

    virTrimSpaces(vendor, NULL);
    virTrimSpaces(model, NULL);

    if (virAsprintf(&dev->id, "%s:%s", vendor, model) < 0)
        goto cleanup;

    ret = dev;
 cleanup:
    VIR_FREE(sg);
    VIR_FREE(vendor);
    VIR_FREE(model);
    VIR_FREE(vendor_path);
    VIR_FREE(model_path);
    if (!ret)
        virSCSIDeviceFree(dev);
    return ret;
}