diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index fbe7bd70150d88502b7e82c297adbc65221cffbc..23168e5ddabaeca0fca48e8e8fd7f1742a9daaec 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1300,6 +1300,7 @@ virHookPresent; #util/virhostdev.h virHostdevManagerGetDefault; virHostdevPreparePCIDevices; +virHostdevPrepareSCSIDevices; virHostdevPrepareUSBDevices; virHostdevReAttachPCIDevices; virHostdevUpdateActivePciHostdevs; diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 41ee32f9a80889274514a15bb75347d80e07fd1b..32825a4e221ffde55502f40afaed3c484a1e3b79 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -245,117 +245,6 @@ qemuPrepareHostUSBDevices(virQEMUDriverPtr driver, hostdevs, nhostdevs, flags); } -static int -virHostdevPrepareSCSIDevices(virHostdevManagerPtr hostdev_mgr, - const char *drv_name, - const char *name, - virDomainHostdevDefPtr *hostdevs, - int nhostdevs) -{ - size_t i, j; - int count; - virSCSIDeviceListPtr list; - virSCSIDevicePtr tmp; - - /* 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 virHostdevPreparePCIDevices() - */ - if (!(list = virSCSIDeviceListNew())) - goto cleanup; - - /* Loop 1: 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(NULL, - 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, - hostdev->shareable))) - goto cleanup; - - if (scsi && virSCSIDeviceListAdd(list, scsi) < 0) { - virSCSIDeviceFree(scsi); - goto cleanup; - } - } - - /* Loop 2: Mark devices in temporary list as used by @name - * and add them to driver list. However, if something goes - * wrong, perform rollback. - */ - virObjectLock(hostdev_mgr->activeScsiHostdevs); - count = virSCSIDeviceListCount(list); - - for (i = 0; i < count; i++) { - virSCSIDevicePtr scsi = virSCSIDeviceListGet(list, i); - if ((tmp = virSCSIDeviceListFind(hostdev_mgr->activeScsiHostdevs, - scsi))) { - bool scsi_shareable = virSCSIDeviceGetShareable(scsi); - bool tmp_shareable = virSCSIDeviceGetShareable(tmp); - - if (!(scsi_shareable && tmp_shareable)) { - virReportError(VIR_ERR_OPERATION_INVALID, - _("SCSI device %s is already in use by " - "other domain(s) as '%s'"), - virSCSIDeviceGetName(tmp), - tmp_shareable ? "shareable" : "non-shareable"); - goto error; - } - - if (virSCSIDeviceSetUsedBy(tmp, drv_name, name) < 0) - goto error; - } else { - if (virSCSIDeviceSetUsedBy(scsi, drv_name, name) < 0) - goto error; - - VIR_DEBUG("Adding %s to activeScsiHostdevs", virSCSIDeviceGetName(scsi)); - - if (virSCSIDeviceListAdd(hostdev_mgr->activeScsiHostdevs, scsi) < 0) - goto error; - } - } - - virObjectUnlock(hostdev_mgr->activeScsiHostdevs); - - /* Loop 3: 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(hostdev_mgr->activeScsiHostdevs, tmp); - } - virObjectUnlock(hostdev_mgr->activeScsiHostdevs); -cleanup: - virObjectUnref(list); - return -1; -} - int qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver, const char *name, diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c index 8d832a9cebcac07cb70632eb59e16a20c6923635..8bebb66a4acb6bf9be47c867b1226b02984f9a0b 100644 --- a/src/util/virhostdev.c +++ b/src/util/virhostdev.c @@ -1140,3 +1140,114 @@ cleanup: virObjectUnref(list); return ret; } + +int +virHostdevPrepareSCSIDevices(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs) +{ + size_t i, j; + int count; + virSCSIDeviceListPtr list; + virSCSIDevicePtr tmp; + + /* 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 virHostdevPreparePCIDevices() + */ + if (!(list = virSCSIDeviceListNew())) + goto cleanup; + + /* Loop 1: 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(NULL, + 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, + hostdev->shareable))) + goto cleanup; + + if (scsi && virSCSIDeviceListAdd(list, scsi) < 0) { + virSCSIDeviceFree(scsi); + goto cleanup; + } + } + + /* Loop 2: Mark devices in temporary list as used by @name + * and add them to driver list. However, if something goes + * wrong, perform rollback. + */ + virObjectLock(hostdev_mgr->activeScsiHostdevs); + count = virSCSIDeviceListCount(list); + + for (i = 0; i < count; i++) { + virSCSIDevicePtr scsi = virSCSIDeviceListGet(list, i); + if ((tmp = virSCSIDeviceListFind(hostdev_mgr->activeScsiHostdevs, + scsi))) { + bool scsi_shareable = virSCSIDeviceGetShareable(scsi); + bool tmp_shareable = virSCSIDeviceGetShareable(tmp); + + if (!(scsi_shareable && tmp_shareable)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("SCSI device %s is already in use by " + "other domain(s) as '%s'"), + virSCSIDeviceGetName(tmp), + tmp_shareable ? "shareable" : "non-shareable"); + goto error; + } + + if (virSCSIDeviceSetUsedBy(tmp, drv_name, name) < 0) + goto error; + } else { + if (virSCSIDeviceSetUsedBy(scsi, drv_name, name) < 0) + goto error; + + VIR_DEBUG("Adding %s to activeScsiHostdevs", virSCSIDeviceGetName(scsi)); + + if (virSCSIDeviceListAdd(hostdev_mgr->activeScsiHostdevs, scsi) < 0) + goto error; + } + } + + virObjectUnlock(hostdev_mgr->activeScsiHostdevs); + + /* Loop 3: 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(hostdev_mgr->activeScsiHostdevs, tmp); + } + virObjectUnlock(hostdev_mgr->activeScsiHostdevs); +cleanup: + virObjectUnref(list); + return -1; +} diff --git a/src/util/virhostdev.h b/src/util/virhostdev.h index 83ebefcc194bc0b7893cce11754c5cfbb06208e3..c14960384b084b07610b5b5c04ca8b35ce3d308d 100644 --- a/src/util/virhostdev.h +++ b/src/util/virhostdev.h @@ -65,6 +65,12 @@ virHostdevPrepareUSBDevices(virHostdevManagerPtr hostdev_mgr, virDomainHostdevDefPtr *hostdevs, int nhostdevs, unsigned int flags); +int +virHostdevPrepareSCSIDevices(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs); void virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr, const char *drv_name,