hostdev: Maintain a driver list of active mediated devices

Keep track of the assigned mediated devices the same way we do it for
the rest of hostdevs. Methods like 'Prepare', 'Update', and 'ReAttach'
are introduced by this patch.

Signed-off-by: Erik Skultety <eskultet@redhat.com>
This commit is contained in:
Erik Skultety 2017-02-03 14:04:59 +01:00
parent 9c5fdc3e18
commit a4a39d90ab
5 changed files with 263 additions and 1 deletions

View File

@ -1736,16 +1736,19 @@ virHostdevPCINodeDeviceDetach;
virHostdevPCINodeDeviceReAttach; virHostdevPCINodeDeviceReAttach;
virHostdevPCINodeDeviceReset; virHostdevPCINodeDeviceReset;
virHostdevPrepareDomainDevices; virHostdevPrepareDomainDevices;
virHostdevPrepareMediatedDevices;
virHostdevPreparePCIDevices; virHostdevPreparePCIDevices;
virHostdevPrepareSCSIDevices; virHostdevPrepareSCSIDevices;
virHostdevPrepareSCSIVHostDevices; virHostdevPrepareSCSIVHostDevices;
virHostdevPrepareUSBDevices; virHostdevPrepareUSBDevices;
virHostdevReAttachDomainDevices; virHostdevReAttachDomainDevices;
virHostdevReAttachMediatedDevices;
virHostdevReAttachPCIDevices; virHostdevReAttachPCIDevices;
virHostdevReAttachSCSIDevices; virHostdevReAttachSCSIDevices;
virHostdevReAttachSCSIVHostDevices; virHostdevReAttachSCSIVHostDevices;
virHostdevReAttachUSBDevices; virHostdevReAttachUSBDevices;
virHostdevUpdateActiveDomainDevices; virHostdevUpdateActiveDomainDevices;
virHostdevUpdateActiveMediatedDevices;
virHostdevUpdateActivePCIDevices; virHostdevUpdateActivePCIDevices;
virHostdevUpdateActiveSCSIDevices; virHostdevUpdateActiveSCSIDevices;
virHostdevUpdateActiveUSBDevices; virHostdevUpdateActiveUSBDevices;

View File

@ -83,6 +83,22 @@ qemuHostdevUpdateActiveSCSIDevices(virQEMUDriverPtr driver,
QEMU_DRIVER_NAME, def->name); QEMU_DRIVER_NAME, def->name);
} }
int
qemuHostdevUpdateActiveMediatedDevices(virQEMUDriverPtr driver,
virDomainDefPtr def)
{
virHostdevManagerPtr mgr = driver->hostdevMgr;
if (!def->nhostdevs)
return 0;
return virHostdevUpdateActiveMediatedDevices(mgr, def->hostdevs,
def->nhostdevs,
QEMU_DRIVER_NAME, def->name);
}
int int
qemuHostdevUpdateActiveDomainDevices(virQEMUDriverPtr driver, qemuHostdevUpdateActiveDomainDevices(virQEMUDriverPtr driver,
virDomainDefPtr def) virDomainDefPtr def)
@ -99,6 +115,9 @@ qemuHostdevUpdateActiveDomainDevices(virQEMUDriverPtr driver,
if (qemuHostdevUpdateActiveSCSIDevices(driver, def) < 0) if (qemuHostdevUpdateActiveSCSIDevices(driver, def) < 0)
return -1; return -1;
if (qemuHostdevUpdateActiveMediatedDevices(driver, def) < 0)
return -1;
return 0; return 0;
} }
@ -304,6 +323,24 @@ qemuHostdevPrepareSCSIVHostDevices(virQEMUDriverPtr driver,
name, hostdevs, nhostdevs); name, hostdevs, nhostdevs);
} }
int
qemuHostdevPrepareMediatedDevices(virQEMUDriverPtr driver,
const char *name,
virDomainHostdevDefPtr *hostdevs,
int nhostdevs)
{
virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
if (!qemuHostdevHostSupportsPassthroughVFIO()) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("host doesn't support VFIO PCI interface"));
return -1;
}
return virHostdevPrepareMediatedDevices(hostdev_mgr, QEMU_DRIVER_NAME,
name, hostdevs, nhostdevs);
}
int int
qemuHostdevPrepareDomainDevices(virQEMUDriverPtr driver, qemuHostdevPrepareDomainDevices(virQEMUDriverPtr driver,
virDomainDefPtr def, virDomainDefPtr def,
@ -330,6 +367,10 @@ qemuHostdevPrepareDomainDevices(virQEMUDriverPtr driver,
def->hostdevs, def->nhostdevs) < 0) def->hostdevs, def->nhostdevs) < 0)
return -1; return -1;
if (qemuHostdevPrepareMediatedDevices(driver, def->name,
def->hostdevs, def->nhostdevs) < 0)
return -1;
return 0; return 0;
} }
@ -396,6 +437,18 @@ qemuHostdevReAttachSCSIVHostDevices(virQEMUDriverPtr driver,
name, hostdevs, nhostdevs); name, hostdevs, nhostdevs);
} }
void
qemuHostdevReAttachMediatedDevices(virQEMUDriverPtr driver,
const char *name,
virDomainHostdevDefPtr *hostdevs,
int nhostdevs)
{
virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
virHostdevReAttachMediatedDevices(hostdev_mgr, QEMU_DRIVER_NAME,
name, hostdevs, nhostdevs);
}
void void
qemuHostdevReAttachDomainDevices(virQEMUDriverPtr driver, qemuHostdevReAttachDomainDevices(virQEMUDriverPtr driver,
virDomainDefPtr def) virDomainDefPtr def)
@ -414,4 +467,7 @@ qemuHostdevReAttachDomainDevices(virQEMUDriverPtr driver,
qemuHostdevReAttachSCSIVHostDevices(driver, def->name, def->hostdevs, qemuHostdevReAttachSCSIVHostDevices(driver, def->name, def->hostdevs,
def->nhostdevs); def->nhostdevs);
qemuHostdevReAttachMediatedDevices(driver, def->name, def->hostdevs,
def->nhostdevs);
} }

View File

@ -30,6 +30,8 @@
bool qemuHostdevHostSupportsPassthroughLegacy(void); bool qemuHostdevHostSupportsPassthroughLegacy(void);
bool qemuHostdevHostSupportsPassthroughVFIO(void); bool qemuHostdevHostSupportsPassthroughVFIO(void);
int qemuHostdevUpdateActiveMediatedDevices(virQEMUDriverPtr driver,
virDomainDefPtr def);
int qemuHostdevUpdateActivePCIDevices(virQEMUDriverPtr driver, int qemuHostdevUpdateActivePCIDevices(virQEMUDriverPtr driver,
virDomainDefPtr def); virDomainDefPtr def);
int qemuHostdevUpdateActiveUSBDevices(virQEMUDriverPtr driver, int qemuHostdevUpdateActiveUSBDevices(virQEMUDriverPtr driver,
@ -59,6 +61,10 @@ int qemuHostdevPrepareSCSIVHostDevices(virQEMUDriverPtr driver,
const char *name, const char *name,
virDomainHostdevDefPtr *hostdevs, virDomainHostdevDefPtr *hostdevs,
int nhostdevs); int nhostdevs);
int qemuHostdevPrepareMediatedDevices(virQEMUDriverPtr driver,
const char *name,
virDomainHostdevDefPtr *hostdevs,
int nhostdevs);
int qemuHostdevPrepareDomainDevices(virQEMUDriverPtr driver, int qemuHostdevPrepareDomainDevices(virQEMUDriverPtr driver,
virDomainDefPtr def, virDomainDefPtr def,
virQEMUCapsPtr qemuCaps, virQEMUCapsPtr qemuCaps,
@ -80,6 +86,10 @@ void qemuHostdevReAttachSCSIVHostDevices(virQEMUDriverPtr driver,
const char *name, const char *name,
virDomainHostdevDefPtr *hostdevs, virDomainHostdevDefPtr *hostdevs,
int nhostdevs); int nhostdevs);
void qemuHostdevReAttachMediatedDevices(virQEMUDriverPtr driver,
const char *name,
virDomainHostdevDefPtr *hostdevs,
int nhostdevs);
void qemuHostdevReAttachDomainDevices(virQEMUDriverPtr driver, void qemuHostdevReAttachDomainDevices(virQEMUDriverPtr driver,
virDomainDefPtr def); virDomainDefPtr def);

View File

@ -1,6 +1,6 @@
/* virhostdev.c: hostdev management /* virhostdev.c: hostdev management
* *
* Copyright (C) 2006-2007, 2009-2016 Red Hat, Inc. * Copyright (C) 2006-2007, 2009-2017 Red Hat, Inc.
* Copyright (C) 2006 Daniel P. Berrange * Copyright (C) 2006 Daniel P. Berrange
* Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. * Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.
* *
@ -147,6 +147,7 @@ virHostdevManagerDispose(void *obj)
virObjectUnref(hostdevMgr->activeUSBHostdevs); virObjectUnref(hostdevMgr->activeUSBHostdevs);
virObjectUnref(hostdevMgr->activeSCSIHostdevs); virObjectUnref(hostdevMgr->activeSCSIHostdevs);
virObjectUnref(hostdevMgr->activeSCSIVHostHostdevs); virObjectUnref(hostdevMgr->activeSCSIVHostHostdevs);
virObjectUnref(hostdevMgr->activeMediatedHostdevs);
VIR_FREE(hostdevMgr->stateDir); VIR_FREE(hostdevMgr->stateDir);
} }
@ -174,6 +175,9 @@ virHostdevManagerNew(void)
if (!(hostdevMgr->activeSCSIVHostHostdevs = virSCSIVHostDeviceListNew())) if (!(hostdevMgr->activeSCSIVHostHostdevs = virSCSIVHostDeviceListNew()))
goto error; goto error;
if (!(hostdevMgr->activeMediatedHostdevs = virMediatedDeviceListNew()))
goto error;
if (privileged) { if (privileged) {
if (VIR_STRDUP(hostdevMgr->stateDir, HOSTDEV_STATE_DIR) < 0) if (VIR_STRDUP(hostdevMgr->stateDir, HOSTDEV_STATE_DIR) < 0)
goto error; goto error;
@ -1165,6 +1169,50 @@ virHostdevUpdateActiveSCSIDevices(virHostdevManagerPtr mgr,
return ret; return ret;
} }
int
virHostdevUpdateActiveMediatedDevices(virHostdevManagerPtr mgr,
virDomainHostdevDefPtr *hostdevs,
int nhostdevs,
const char *drv_name,
const char *dom_name)
{
int ret = -1;
size_t i;
virMediatedDevicePtr mdev = NULL;
if (nhostdevs == 0)
return 0;
virObjectLock(mgr->activeMediatedHostdevs);
for (i = 0; i < nhostdevs; i++) {
virDomainHostdevDefPtr hostdev = hostdevs[i];
virDomainHostdevSubsysMediatedDevPtr mdevsrc;
mdevsrc = &hostdev->source.subsys.u.mdev;
if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV) {
continue;
}
if (!(mdev = virMediatedDeviceNew(mdevsrc->uuidstr, mdevsrc->model)))
goto cleanup;
virMediatedDeviceSetUsedBy(mdev, drv_name, dom_name);
if (virMediatedDeviceListAdd(mgr->activeMediatedHostdevs, mdev) < 0)
goto cleanup;
}
ret = 0;
cleanup:
virMediatedDeviceFree(mdev);
virObjectUnlock(mgr->activeMediatedHostdevs);
return ret;
}
static int static int
virHostdevMarkUSBDevices(virHostdevManagerPtr mgr, virHostdevMarkUSBDevices(virHostdevManagerPtr mgr,
const char *drv_name, const char *drv_name,
@ -1613,6 +1661,70 @@ virHostdevPrepareSCSIVHostDevices(virHostdevManagerPtr mgr,
return -1; return -1;
} }
int
virHostdevPrepareMediatedDevices(virHostdevManagerPtr mgr,
const char *drv_name,
const char *dom_name,
virDomainHostdevDefPtr *hostdevs,
int nhostdevs)
{
size_t i;
int ret = -1;
virMediatedDeviceListPtr list;
if (!nhostdevs)
return 0;
/* To prevent situation where mediated device is assigned to multiple
* domains we maintain a driver list of currently assigned mediated devices.
* A device is appended to the driver list after a series of preparations.
*/
if (!(list = virMediatedDeviceListNew()))
goto cleanup;
/* Loop 1: Build a temporary list of ALL mediated devices. */
for (i = 0; i < nhostdevs; i++) {
virDomainHostdevDefPtr hostdev = hostdevs[i];
virDomainHostdevSubsysMediatedDevPtr src = &hostdev->source.subsys.u.mdev;
virMediatedDevicePtr mdev;
if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
continue;
if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV)
continue;
if (!(mdev = virMediatedDeviceNew(src->uuidstr, src->model)))
goto cleanup;
if (virMediatedDeviceListAdd(list, mdev) < 0) {
virMediatedDeviceFree(mdev);
goto cleanup;
}
}
/* Mark the devices in the list as used by @drv_name-@dom_name and copy the
* references to the driver list
*/
if (virMediatedDeviceListMarkDevices(mgr->activeMediatedHostdevs,
list, drv_name, dom_name) < 0)
goto cleanup;
/* Loop 2: Temporary list was successfully merged with
* driver list, so steal all items to avoid freeing them
* in cleanup label.
*/
while (virMediatedDeviceListCount(list) > 0) {
virMediatedDevicePtr tmp = virMediatedDeviceListGet(list, 0);
virMediatedDeviceListSteal(list, tmp);
}
ret = 0;
cleanup:
virObjectUnref(list);
return ret;
}
void void
virHostdevReAttachUSBDevices(virHostdevManagerPtr mgr, virHostdevReAttachUSBDevices(virHostdevManagerPtr mgr,
const char *drv_name, const char *drv_name,
@ -1807,6 +1919,64 @@ virHostdevReAttachSCSIVHostDevices(virHostdevManagerPtr mgr,
virObjectUnlock(mgr->activeSCSIVHostHostdevs); virObjectUnlock(mgr->activeSCSIVHostHostdevs);
} }
/* TODO: Rename this function along with all virHostdevReAttach* functions that
* have nothing to do with an explicit re-attachment of a device back to the
* host driver (like PCI).
* Despite what the function name suggests, there's nothing to be re-attached
* for mediated devices, the function merely removes a mediated device from the
* list of active host devices.
*/
void
virHostdevReAttachMediatedDevices(virHostdevManagerPtr mgr,
const char *drv_name,
const char *dom_name,
virDomainHostdevDefPtr *hostdevs,
int nhostdevs)
{
const char *used_by_drvname = NULL;
const char *used_by_domname = NULL;
size_t i;
if (nhostdevs == 0)
return;
virObjectLock(mgr->activeMediatedHostdevs);
for (i = 0; i < nhostdevs; i++) {
virMediatedDevicePtr mdev, tmp;
virDomainHostdevSubsysMediatedDevPtr mdevsrc;
virDomainHostdevDefPtr hostdev = hostdevs[i];
mdevsrc = &hostdev->source.subsys.u.mdev;
if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV) {
continue;
}
if (!(mdev = virMediatedDeviceNew(mdevsrc->uuidstr,
mdevsrc->model)))
continue;
/* Remove from the list only mdevs assigned to @drv_name/@dom_name */
tmp = virMediatedDeviceListFind(mgr->activeMediatedHostdevs, mdev);
virMediatedDeviceFree(mdev);
/* skip inactive devices */
if (!tmp)
continue;
virMediatedDeviceGetUsedBy(tmp, &used_by_drvname, &used_by_domname);
if (STREQ_NULLABLE(drv_name, used_by_drvname) &&
STREQ_NULLABLE(dom_name, used_by_domname)) {
VIR_DEBUG("Removing %s dom=%s from activeMediatedHostdevs",
mdevsrc->uuidstr, dom_name);
virMediatedDeviceListDel(mgr->activeMediatedHostdevs, tmp);
}
}
virObjectUnlock(mgr->activeMediatedHostdevs);
}
int int
virHostdevPCINodeDeviceDetach(virHostdevManagerPtr mgr, virHostdevPCINodeDeviceDetach(virHostdevManagerPtr mgr,
virPCIDevicePtr pci) virPCIDevicePtr pci)

View File

@ -32,6 +32,7 @@
# include "virscsi.h" # include "virscsi.h"
# include "virscsivhost.h" # include "virscsivhost.h"
# include "conf/domain_conf.h" # include "conf/domain_conf.h"
# include "virmdev.h"
typedef enum { typedef enum {
VIR_HOSTDEV_STRICT_ACS_CHECK = (1 << 0), /* strict acs check */ VIR_HOSTDEV_STRICT_ACS_CHECK = (1 << 0), /* strict acs check */
@ -55,6 +56,7 @@ struct _virHostdevManager {
virUSBDeviceListPtr activeUSBHostdevs; virUSBDeviceListPtr activeUSBHostdevs;
virSCSIDeviceListPtr activeSCSIHostdevs; virSCSIDeviceListPtr activeSCSIHostdevs;
virSCSIVHostDeviceListPtr activeSCSIVHostHostdevs; virSCSIVHostDeviceListPtr activeSCSIVHostHostdevs;
virMediatedDeviceListPtr activeMediatedHostdevs;
}; };
virHostdevManagerPtr virHostdevManagerGetDefault(void); virHostdevManagerPtr virHostdevManagerGetDefault(void);
@ -96,6 +98,13 @@ virHostdevPrepareSCSIVHostDevices(virHostdevManagerPtr hostdev_mgr,
virDomainHostdevDefPtr *hostdevs, virDomainHostdevDefPtr *hostdevs,
int nhostdevs) int nhostdevs)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
int
virHostdevPrepareMediatedDevices(virHostdevManagerPtr hostdev_mgr,
const char *drv_name,
const char *dom_name,
virDomainHostdevDefPtr *hostdevs,
int nhostdevs)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
void void
virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr, virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
const char *drv_name, const char *drv_name,
@ -125,6 +134,13 @@ virHostdevReAttachSCSIVHostDevices(virHostdevManagerPtr hostdev_mgr,
virDomainHostdevDefPtr *hostdevs, virDomainHostdevDefPtr *hostdevs,
int nhostdevs) int nhostdevs)
ATTRIBUTE_NONNULL(1); ATTRIBUTE_NONNULL(1);
void
virHostdevReAttachMediatedDevices(virHostdevManagerPtr hostdev_mgr,
const char *drv_name,
const char *dom_name,
virDomainHostdevDefPtr *hostdevs,
int nhostdevs)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
int int
virHostdevUpdateActivePCIDevices(virHostdevManagerPtr mgr, virHostdevUpdateActivePCIDevices(virHostdevManagerPtr mgr,
virDomainHostdevDefPtr *hostdevs, virDomainHostdevDefPtr *hostdevs,
@ -147,6 +163,13 @@ virHostdevUpdateActiveSCSIDevices(virHostdevManagerPtr mgr,
const char *dom_name) const char *dom_name)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5); ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5);
int int
virHostdevUpdateActiveMediatedDevices(virHostdevManagerPtr mgr,
virDomainHostdevDefPtr *hostdevs,
int nhostdevs,
const char *drv_name,
const char *dom_name)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5);
int
virHostdevUpdateActiveDomainDevices(virHostdevManagerPtr mgr, virHostdevUpdateActiveDomainDevices(virHostdevManagerPtr mgr,
const char *driver, const char *driver,
virDomainDefPtr def, virDomainDefPtr def,