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;
virHostdevPCINodeDeviceReset;
virHostdevPrepareDomainDevices;
virHostdevPrepareMediatedDevices;
virHostdevPreparePCIDevices;
virHostdevPrepareSCSIDevices;
virHostdevPrepareSCSIVHostDevices;
virHostdevPrepareUSBDevices;
virHostdevReAttachDomainDevices;
virHostdevReAttachMediatedDevices;
virHostdevReAttachPCIDevices;
virHostdevReAttachSCSIDevices;
virHostdevReAttachSCSIVHostDevices;
virHostdevReAttachUSBDevices;
virHostdevUpdateActiveDomainDevices;
virHostdevUpdateActiveMediatedDevices;
virHostdevUpdateActivePCIDevices;
virHostdevUpdateActiveSCSIDevices;
virHostdevUpdateActiveUSBDevices;

View File

@ -83,6 +83,22 @@ qemuHostdevUpdateActiveSCSIDevices(virQEMUDriverPtr driver,
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
qemuHostdevUpdateActiveDomainDevices(virQEMUDriverPtr driver,
virDomainDefPtr def)
@ -99,6 +115,9 @@ qemuHostdevUpdateActiveDomainDevices(virQEMUDriverPtr driver,
if (qemuHostdevUpdateActiveSCSIDevices(driver, def) < 0)
return -1;
if (qemuHostdevUpdateActiveMediatedDevices(driver, def) < 0)
return -1;
return 0;
}
@ -304,6 +323,24 @@ qemuHostdevPrepareSCSIVHostDevices(virQEMUDriverPtr driver,
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
qemuHostdevPrepareDomainDevices(virQEMUDriverPtr driver,
virDomainDefPtr def,
@ -330,6 +367,10 @@ qemuHostdevPrepareDomainDevices(virQEMUDriverPtr driver,
def->hostdevs, def->nhostdevs) < 0)
return -1;
if (qemuHostdevPrepareMediatedDevices(driver, def->name,
def->hostdevs, def->nhostdevs) < 0)
return -1;
return 0;
}
@ -396,6 +437,18 @@ qemuHostdevReAttachSCSIVHostDevices(virQEMUDriverPtr driver,
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
qemuHostdevReAttachDomainDevices(virQEMUDriverPtr driver,
virDomainDefPtr def)
@ -414,4 +467,7 @@ qemuHostdevReAttachDomainDevices(virQEMUDriverPtr driver,
qemuHostdevReAttachSCSIVHostDevices(driver, def->name, def->hostdevs,
def->nhostdevs);
qemuHostdevReAttachMediatedDevices(driver, def->name, def->hostdevs,
def->nhostdevs);
}

View File

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

View File

@ -1,6 +1,6 @@
/* 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) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.
*
@ -147,6 +147,7 @@ virHostdevManagerDispose(void *obj)
virObjectUnref(hostdevMgr->activeUSBHostdevs);
virObjectUnref(hostdevMgr->activeSCSIHostdevs);
virObjectUnref(hostdevMgr->activeSCSIVHostHostdevs);
virObjectUnref(hostdevMgr->activeMediatedHostdevs);
VIR_FREE(hostdevMgr->stateDir);
}
@ -174,6 +175,9 @@ virHostdevManagerNew(void)
if (!(hostdevMgr->activeSCSIVHostHostdevs = virSCSIVHostDeviceListNew()))
goto error;
if (!(hostdevMgr->activeMediatedHostdevs = virMediatedDeviceListNew()))
goto error;
if (privileged) {
if (VIR_STRDUP(hostdevMgr->stateDir, HOSTDEV_STATE_DIR) < 0)
goto error;
@ -1165,6 +1169,50 @@ virHostdevUpdateActiveSCSIDevices(virHostdevManagerPtr mgr,
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
virHostdevMarkUSBDevices(virHostdevManagerPtr mgr,
const char *drv_name,
@ -1613,6 +1661,70 @@ virHostdevPrepareSCSIVHostDevices(virHostdevManagerPtr mgr,
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
virHostdevReAttachUSBDevices(virHostdevManagerPtr mgr,
const char *drv_name,
@ -1807,6 +1919,64 @@ virHostdevReAttachSCSIVHostDevices(virHostdevManagerPtr mgr,
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
virHostdevPCINodeDeviceDetach(virHostdevManagerPtr mgr,
virPCIDevicePtr pci)

View File

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