mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-22 19:32:19 +00:00
qemu: Introduce activeScsiHostdevs list for scsi host devices
Although virtio-scsi supports SCSI PR (Persistent Reservations), the device on host may do not support it. To avoid losing data, Just like PCI and USB pass through devices, only one live guest is allowed per SCSI host pass through device." Signed-off-by: Han Cheng <hanc.fnst@cn.fujitsu.com>
This commit is contained in:
parent
31532cabe8
commit
ea74c07636
@ -36,6 +36,7 @@
|
|||||||
# include "security/security_manager.h"
|
# include "security/security_manager.h"
|
||||||
# include "virpci.h"
|
# include "virpci.h"
|
||||||
# include "virusb.h"
|
# include "virusb.h"
|
||||||
|
# include "virscsi.h"
|
||||||
# include "cpu_conf.h"
|
# include "cpu_conf.h"
|
||||||
# include "driver.h"
|
# include "driver.h"
|
||||||
# include "virportallocator.h"
|
# include "virportallocator.h"
|
||||||
@ -203,6 +204,7 @@ struct _virQEMUDriver {
|
|||||||
virPCIDeviceListPtr activePciHostdevs;
|
virPCIDeviceListPtr activePciHostdevs;
|
||||||
virPCIDeviceListPtr inactivePciHostdevs;
|
virPCIDeviceListPtr inactivePciHostdevs;
|
||||||
virUSBDeviceListPtr activeUsbHostdevs;
|
virUSBDeviceListPtr activeUsbHostdevs;
|
||||||
|
virSCSIDeviceListPtr activeScsiHostdevs;
|
||||||
|
|
||||||
/* Immutable pointer. Unsafe APIs. XXX */
|
/* Immutable pointer. Unsafe APIs. XXX */
|
||||||
virHashTablePtr sharedDisks;
|
virHashTablePtr sharedDisks;
|
||||||
|
@ -675,6 +675,9 @@ qemuStateInitialize(bool privileged,
|
|||||||
if ((qemu_driver->inactivePciHostdevs = virPCIDeviceListNew()) == NULL)
|
if ((qemu_driver->inactivePciHostdevs = virPCIDeviceListNew()) == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
if ((qemu_driver->activeScsiHostdevs = virSCSIDeviceListNew()) == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
if (!(qemu_driver->sharedDisks = virHashCreate(30, qemuSharedDiskEntryFree)))
|
if (!(qemu_driver->sharedDisks = virHashCreate(30, qemuSharedDiskEntryFree)))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "viralloc.h"
|
#include "viralloc.h"
|
||||||
#include "virpci.h"
|
#include "virpci.h"
|
||||||
#include "virusb.h"
|
#include "virusb.h"
|
||||||
|
#include "virscsi.h"
|
||||||
#include "virnetdev.h"
|
#include "virnetdev.h"
|
||||||
|
|
||||||
#define VIR_FROM_THIS VIR_FROM_QEMU
|
#define VIR_FROM_THIS VIR_FROM_QEMU
|
||||||
@ -226,6 +227,47 @@ cleanup:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
qemuDomainHostdevPciSysfsPath(virDomainHostdevDefPtr hostdev, char **sysfs_path)
|
qemuDomainHostdevPciSysfsPath(virDomainHostdevDefPtr hostdev, char **sysfs_path)
|
||||||
{
|
{
|
||||||
@ -827,6 +869,107 @@ cleanup:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver,
|
||||||
|
const char *name,
|
||||||
|
virDomainHostdevDefPtr *hostdevs,
|
||||||
|
int nhostdevs)
|
||||||
|
{
|
||||||
|
int i, j, 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 qemuPrepareHostdevPCIDevices()
|
||||||
|
*/
|
||||||
|
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(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 2: 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 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(driver->activeScsiHostdevs, tmp);
|
||||||
|
}
|
||||||
|
virObjectUnlock(driver->activeScsiHostdevs);
|
||||||
|
cleanup:
|
||||||
|
virObjectUnref(list);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int qemuPrepareHostDevices(virQEMUDriverPtr driver,
|
int qemuPrepareHostDevices(virQEMUDriverPtr driver,
|
||||||
virDomainDefPtr def,
|
virDomainDefPtr def,
|
||||||
bool coldBoot)
|
bool coldBoot)
|
||||||
@ -841,6 +984,10 @@ int qemuPrepareHostDevices(virQEMUDriverPtr driver,
|
|||||||
if (qemuPrepareHostUSBDevices(driver, def, coldBoot) < 0)
|
if (qemuPrepareHostUSBDevices(driver, def, coldBoot) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (qemuPrepareHostdevSCSIDevices(driver, def->name,
|
||||||
|
def->hostdevs, def->nhostdevs) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1025,6 +1172,69 @@ qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver,
|
|||||||
virObjectUnlock(driver->activeUsbHostdevs);
|
virObjectUnlock(driver->activeUsbHostdevs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
void qemuDomainReAttachHostDevices(virQEMUDriverPtr driver,
|
void qemuDomainReAttachHostDevices(virQEMUDriverPtr driver,
|
||||||
virDomainDefPtr def)
|
virDomainDefPtr def)
|
||||||
{
|
{
|
||||||
@ -1036,4 +1246,7 @@ void qemuDomainReAttachHostDevices(virQEMUDriverPtr driver,
|
|||||||
|
|
||||||
qemuDomainReAttachHostUsbDevices(driver, def->name, def->hostdevs,
|
qemuDomainReAttachHostUsbDevices(driver, def->name, def->hostdevs,
|
||||||
def->nhostdevs);
|
def->nhostdevs);
|
||||||
|
|
||||||
|
qemuDomainReAttachHostScsiDevices(driver, def->name, def->hostdevs,
|
||||||
|
def->nhostdevs);
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,8 @@ int qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver,
|
|||||||
virDomainDefPtr def);
|
virDomainDefPtr def);
|
||||||
int qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver,
|
int qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver,
|
||||||
virDomainDefPtr def);
|
virDomainDefPtr def);
|
||||||
|
int qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver,
|
||||||
|
virDomainDefPtr def);
|
||||||
int qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
|
int qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
|
||||||
const char *name,
|
const char *name,
|
||||||
const unsigned char *uuid,
|
const unsigned char *uuid,
|
||||||
@ -42,9 +44,17 @@ int qemuFindHostdevUSBDevice(virDomainHostdevDefPtr hostdev,
|
|||||||
int qemuPrepareHostdevUSBDevices(virQEMUDriverPtr driver,
|
int qemuPrepareHostdevUSBDevices(virQEMUDriverPtr driver,
|
||||||
const char *name,
|
const char *name,
|
||||||
virUSBDeviceListPtr list);
|
virUSBDeviceListPtr list);
|
||||||
|
int qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver,
|
||||||
|
const char *name,
|
||||||
|
virDomainHostdevDefPtr *hostdevs,
|
||||||
|
int nhostdevs);
|
||||||
int qemuPrepareHostDevices(virQEMUDriverPtr driver,
|
int qemuPrepareHostDevices(virQEMUDriverPtr driver,
|
||||||
virDomainDefPtr def,
|
virDomainDefPtr def,
|
||||||
bool coldBoot);
|
bool coldBoot);
|
||||||
|
void qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver,
|
||||||
|
const char *name,
|
||||||
|
virDomainHostdevDefPtr *hostdevs,
|
||||||
|
int nhostdevs);
|
||||||
void qemuReattachPciDevice(virPCIDevicePtr dev, virQEMUDriverPtr driver);
|
void qemuReattachPciDevice(virPCIDevicePtr dev, virQEMUDriverPtr driver);
|
||||||
void qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver,
|
void qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver,
|
||||||
const char *name,
|
const char *name,
|
||||||
|
@ -2972,6 +2972,9 @@ qemuProcessReconnect(void *opaque)
|
|||||||
if (qemuUpdateActiveUsbHostdevs(driver, obj->def) < 0)
|
if (qemuUpdateActiveUsbHostdevs(driver, obj->def) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
if (qemuUpdateActiveScsiHostdevs(driver, obj->def) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
if (qemuInitCgroup(driver, obj, false) < 0)
|
if (qemuInitCgroup(driver, obj, false) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user