mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 21:55:25 +00:00
check IOMMU group devices usage when preparing device for vfio passthrough
The virsh start <domain> fails with qemu error when the hostdevices of the same iommu group are used actively by other vms. It is not clear which hostdev from the same iommu group is used by any of the running guests. User has to go through every guest xml to figure out who is using the hostdev of same iommu group. Solution: Iterate the iommu group of the hostdev and error our neatly in case a device in the same iommu group is busy. Reattach code also does the same kind of check, remove duplicate code as well. Signed-off-by: Shivaprasad G Bhat <sbhat@linux.vnet.ibm.com> Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
parent
6af9bb3560
commit
7e72de49fe
@ -54,6 +54,41 @@ static virClassPtr virHostdevManagerClass;
|
|||||||
static void virHostdevManagerDispose(void *obj);
|
static void virHostdevManagerDispose(void *obj);
|
||||||
static virHostdevManagerPtr virHostdevManagerNew(void);
|
static virHostdevManagerPtr virHostdevManagerNew(void);
|
||||||
|
|
||||||
|
static int virHostdevIsPCINodeDeviceUsed(virPCIDeviceAddressPtr devAddr, void *opaque)
|
||||||
|
{
|
||||||
|
virPCIDevicePtr other;
|
||||||
|
int ret = -1;
|
||||||
|
virPCIDevicePtr pci = NULL;
|
||||||
|
virHostdevManagerPtr hostdev_mgr = opaque;
|
||||||
|
|
||||||
|
if (!(pci = virPCIDeviceNew(devAddr->domain, devAddr->bus,
|
||||||
|
devAddr->slot, devAddr->function)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
other = virPCIDeviceListFind(hostdev_mgr->activePCIHostdevs, pci);
|
||||||
|
if (other) {
|
||||||
|
const char *other_drvname = NULL;
|
||||||
|
const char *other_domname = NULL;
|
||||||
|
virPCIDeviceGetUsedBy(other, &other_drvname, &other_domname);
|
||||||
|
|
||||||
|
if (other_drvname && other_domname)
|
||||||
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
||||||
|
_("PCI device %s is in use by "
|
||||||
|
"driver %s, domain %s"),
|
||||||
|
virPCIDeviceGetName(pci),
|
||||||
|
other_drvname, other_domname);
|
||||||
|
else
|
||||||
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
||||||
|
_("PCI device %s is in use"),
|
||||||
|
virPCIDeviceGetName(pci));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
cleanup:
|
||||||
|
virPCIDeviceFree(pci);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int virHostdevManagerOnceInit(void)
|
static int virHostdevManagerOnceInit(void)
|
||||||
{
|
{
|
||||||
if (!(virHostdevManagerClass = virClassNew(virClassForObject(),
|
if (!(virHostdevManagerClass = virClassNew(virClassForObject(),
|
||||||
@ -494,6 +529,7 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
|
|||||||
int last_processed_hostdev_vf = -1;
|
int last_processed_hostdev_vf = -1;
|
||||||
size_t i;
|
size_t i;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
virPCIDeviceAddressPtr devAddr = NULL;
|
||||||
|
|
||||||
if (!nhostdevs)
|
if (!nhostdevs)
|
||||||
return 0;
|
return 0;
|
||||||
@ -518,7 +554,6 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
|
|||||||
|
|
||||||
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
|
for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
|
||||||
virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
|
virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
|
||||||
virPCIDevicePtr other;
|
|
||||||
bool strict_acs_check = !!(flags & VIR_HOSTDEV_STRICT_ACS_CHECK);
|
bool strict_acs_check = !!(flags & VIR_HOSTDEV_STRICT_ACS_CHECK);
|
||||||
|
|
||||||
if (!virPCIDeviceIsAssignable(dev, strict_acs_check)) {
|
if (!virPCIDeviceIsAssignable(dev, strict_acs_check)) {
|
||||||
@ -527,24 +562,22 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
|
|||||||
virPCIDeviceGetName(dev));
|
virPCIDeviceGetName(dev));
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
/* The device is in use by other active domain if
|
|
||||||
* the dev is in list activePCIHostdevs.
|
|
||||||
*/
|
|
||||||
if ((other = virPCIDeviceListFind(hostdev_mgr->activePCIHostdevs, dev))) {
|
|
||||||
const char *other_drvname;
|
|
||||||
const char *other_domname;
|
|
||||||
|
|
||||||
virPCIDeviceGetUsedBy(other, &other_drvname, &other_domname);
|
VIR_FREE(devAddr);
|
||||||
if (other_drvname && other_domname)
|
if (!(devAddr = virPCIDeviceGetAddress(dev)))
|
||||||
virReportError(VIR_ERR_OPERATION_INVALID,
|
goto cleanup;
|
||||||
_("PCI device %s is in use by "
|
|
||||||
"driver %s, domain %s"),
|
/* The device is in use by other active domain if
|
||||||
virPCIDeviceGetName(dev),
|
* the dev is in list activePCIHostdevs. VFIO devices
|
||||||
other_drvname, other_domname);
|
* belonging to same iommu group cant be shared
|
||||||
else
|
* across guests.
|
||||||
virReportError(VIR_ERR_OPERATION_INVALID,
|
*/
|
||||||
_("PCI device %s is already in use"),
|
if (STREQ(virPCIDeviceGetStubDriver(dev), "vfio-pci")) {
|
||||||
virPCIDeviceGetName(dev));
|
if (virPCIDeviceAddressIOMMUGroupIterate(devAddr,
|
||||||
|
virHostdevIsPCINodeDeviceUsed,
|
||||||
|
hostdev_mgr) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
} else if (virHostdevIsPCINodeDeviceUsed(devAddr, hostdev_mgr)) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -678,6 +711,7 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
|
|||||||
virObjectUnlock(hostdev_mgr->activePCIHostdevs);
|
virObjectUnlock(hostdev_mgr->activePCIHostdevs);
|
||||||
virObjectUnlock(hostdev_mgr->inactivePCIHostdevs);
|
virObjectUnlock(hostdev_mgr->inactivePCIHostdevs);
|
||||||
virObjectUnref(pcidevs);
|
virObjectUnref(pcidevs);
|
||||||
|
VIR_FREE(devAddr);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1506,29 +1540,17 @@ int
|
|||||||
virHostdevPCINodeDeviceReAttach(virHostdevManagerPtr hostdev_mgr,
|
virHostdevPCINodeDeviceReAttach(virHostdevManagerPtr hostdev_mgr,
|
||||||
virPCIDevicePtr pci)
|
virPCIDevicePtr pci)
|
||||||
{
|
{
|
||||||
virPCIDevicePtr other;
|
virPCIDeviceAddressPtr devAddr = NULL;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
virObjectLock(hostdev_mgr->activePCIHostdevs);
|
virObjectLock(hostdev_mgr->activePCIHostdevs);
|
||||||
virObjectLock(hostdev_mgr->inactivePCIHostdevs);
|
virObjectLock(hostdev_mgr->inactivePCIHostdevs);
|
||||||
other = virPCIDeviceListFind(hostdev_mgr->activePCIHostdevs, pci);
|
|
||||||
if (other) {
|
|
||||||
const char *other_drvname = NULL;
|
|
||||||
const char *other_domname = NULL;
|
|
||||||
virPCIDeviceGetUsedBy(other, &other_drvname, &other_domname);
|
|
||||||
|
|
||||||
if (other_drvname && other_domname)
|
if (!(devAddr = virPCIDeviceGetAddress(pci)))
|
||||||
virReportError(VIR_ERR_OPERATION_INVALID,
|
goto out;
|
||||||
_("PCI device %s is still in use by "
|
|
||||||
"driver %s, domain %s"),
|
if (virHostdevIsPCINodeDeviceUsed(devAddr, hostdev_mgr))
|
||||||
virPCIDeviceGetName(pci),
|
|
||||||
other_drvname, other_domname);
|
|
||||||
else
|
|
||||||
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
||||||
_("PCI device %s is still in use"),
|
|
||||||
virPCIDeviceGetName(pci));
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
|
|
||||||
virPCIDeviceReattachInit(pci);
|
virPCIDeviceReattachInit(pci);
|
||||||
|
|
||||||
@ -1540,6 +1562,7 @@ virHostdevPCINodeDeviceReAttach(virHostdevManagerPtr hostdev_mgr,
|
|||||||
out:
|
out:
|
||||||
virObjectUnlock(hostdev_mgr->inactivePCIHostdevs);
|
virObjectUnlock(hostdev_mgr->inactivePCIHostdevs);
|
||||||
virObjectUnlock(hostdev_mgr->activePCIHostdevs);
|
virObjectUnlock(hostdev_mgr->activePCIHostdevs);
|
||||||
|
VIR_FREE(devAddr);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user