mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-11 15:27:47 +00:00
Revert changes to allow pciResetDevice() reset multiple devices
It turns out that the previous attempt at this doesn't work well in the case of hotplug. We need qemuCheckPciHostDevice() to disallow the reset affecting devices already attach to the guest, but we still need to avoid double locking the virDomainObjPtr. This is all getting messy, I've a better idea. This reverts commit6318808270
andc106c8a18c
. * src/qemu_driver.c, src/pci.[ch], src/xen_unified.c, src/libvirt_private.syms: revert a bunch of stuff.
This commit is contained in:
parent
0b973381dc
commit
4954e079c8
@ -283,7 +283,6 @@ virNodeDeviceAssignDef;
|
||||
pciGetDevice;
|
||||
pciFreeDevice;
|
||||
pciDettachDevice;
|
||||
pciDeviceEquals;
|
||||
pciReAttachDevice;
|
||||
pciResetDevice;
|
||||
|
||||
|
130
src/pci.c
130
src/pci.c
@ -225,11 +225,7 @@ pciWrite32(pciDevice *dev, unsigned pos, uint32_t val)
|
||||
pciWrite(dev, pos, &buf[0], sizeof(buf));
|
||||
}
|
||||
|
||||
typedef int (*pciIterPredicate)(virConnectPtr,
|
||||
virDomainObjPtr,
|
||||
pciDevice *,
|
||||
pciResetCheckFunc,
|
||||
pciDevice *);
|
||||
typedef int (*pciIterPredicate)(pciDevice *, pciDevice *);
|
||||
|
||||
/* Iterate over available PCI devices calling @predicate
|
||||
* to compare each one to @dev.
|
||||
@ -238,10 +234,8 @@ typedef int (*pciIterPredicate)(virConnectPtr,
|
||||
*/
|
||||
static int
|
||||
pciIterDevices(virConnectPtr conn,
|
||||
virDomainObjPtr vm,
|
||||
pciIterPredicate predicate,
|
||||
pciDevice *dev,
|
||||
pciResetCheckFunc check,
|
||||
pciDevice **matched)
|
||||
{
|
||||
DIR *dir;
|
||||
@ -260,7 +254,7 @@ pciIterDevices(virConnectPtr conn,
|
||||
|
||||
while ((entry = readdir(dir))) {
|
||||
unsigned domain, bus, slot, function;
|
||||
pciDevice *check_dev;
|
||||
pciDevice *try;
|
||||
|
||||
/* Ignore '.' and '..' */
|
||||
if (entry->d_name[0] == '.')
|
||||
@ -272,18 +266,18 @@ pciIterDevices(virConnectPtr conn,
|
||||
continue;
|
||||
}
|
||||
|
||||
check_dev = pciGetDevice(conn, domain, bus, slot, function);
|
||||
if (!check_dev) {
|
||||
try = pciGetDevice(conn, domain, bus, slot, function);
|
||||
if (!try) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (predicate(conn, vm, dev, check, check_dev)) {
|
||||
VIR_DEBUG("%s %s: iter matched on %s", dev->id, dev->name, check_dev->name);
|
||||
*matched = check_dev;
|
||||
if (predicate(try, dev)) {
|
||||
VIR_DEBUG("%s %s: iter matched on %s", dev->id, dev->name, try->name);
|
||||
*matched = try;
|
||||
break;
|
||||
}
|
||||
pciFreeDevice(conn, check_dev);
|
||||
pciFreeDevice(conn, try);
|
||||
}
|
||||
closedir(dir);
|
||||
return ret;
|
||||
@ -385,73 +379,63 @@ pciDetectPowerManagementReset(pciDevice *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check any devices other than the one supplied on the same domain/bus */
|
||||
/* Any devices other than the one supplied on the same domain/bus ? */
|
||||
static int
|
||||
pciCheckSharesBus(virConnectPtr conn,
|
||||
virDomainObjPtr vm,
|
||||
pciDevice *dev,
|
||||
pciResetCheckFunc check,
|
||||
pciDevice *check_dev)
|
||||
pciSharesBus(pciDevice *a, pciDevice *b)
|
||||
{
|
||||
if (check_dev->domain != dev->domain || check_dev->bus != dev->bus)
|
||||
return 0;
|
||||
if (check_dev->slot == dev->slot && check_dev->function == dev->function)
|
||||
return 0;
|
||||
if (check(conn, vm, check_dev))
|
||||
return
|
||||
a->domain == b->domain &&
|
||||
a->bus == b->bus &&
|
||||
(a->slot != b->slot ||
|
||||
a->function != b->function);
|
||||
}
|
||||
|
||||
static int
|
||||
pciBusContainsOtherDevices(virConnectPtr conn, pciDevice *dev)
|
||||
{
|
||||
pciDevice *matched = NULL;
|
||||
if (pciIterDevices(conn, pciSharesBus, dev, &matched) < 0)
|
||||
return 1;
|
||||
if (!matched)
|
||||
return 0;
|
||||
pciFreeDevice(conn, matched);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static pciDevice *
|
||||
pciBusCheckOtherDevices(virConnectPtr conn,
|
||||
virDomainObjPtr vm,
|
||||
pciDevice *dev,
|
||||
pciResetCheckFunc check)
|
||||
{
|
||||
pciDevice *conflict = NULL;
|
||||
pciIterDevices(conn, vm, pciCheckSharesBus, dev, check, &conflict);
|
||||
return conflict;
|
||||
}
|
||||
|
||||
/* Is @check_dev the parent of @dev ? */
|
||||
/* Is @a the parent of @b ? */
|
||||
static int
|
||||
pciIsParent(virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||
virDomainObjPtr vm ATTRIBUTE_UNUSED,
|
||||
pciDevice *dev,
|
||||
pciResetCheckFunc check ATTRIBUTE_UNUSED,
|
||||
pciDevice *check_dev)
|
||||
pciIsParent(pciDevice *a, pciDevice *b)
|
||||
{
|
||||
uint16_t device_class;
|
||||
uint8_t header_type, secondary, subordinate;
|
||||
|
||||
if (check_dev->domain != dev->domain)
|
||||
if (a->domain != b->domain)
|
||||
return 0;
|
||||
|
||||
/* Is it a bridge? */
|
||||
device_class = pciRead16(check_dev, PCI_CLASS_DEVICE);
|
||||
device_class = pciRead16(a, PCI_CLASS_DEVICE);
|
||||
if (device_class != PCI_CLASS_BRIDGE_PCI)
|
||||
return 0;
|
||||
|
||||
/* Is it a plane? */
|
||||
header_type = pciRead8(check_dev, PCI_HEADER_TYPE);
|
||||
header_type = pciRead8(a, PCI_HEADER_TYPE);
|
||||
if ((header_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE)
|
||||
return 0;
|
||||
|
||||
secondary = pciRead8(check_dev, PCI_SECONDARY_BUS);
|
||||
subordinate = pciRead8(check_dev, PCI_SUBORDINATE_BUS);
|
||||
secondary = pciRead8(a, PCI_SECONDARY_BUS);
|
||||
subordinate = pciRead8(a, PCI_SUBORDINATE_BUS);
|
||||
|
||||
VIR_DEBUG("%s %s: found parent device %s\n",
|
||||
dev->id, dev->name, check_dev->name);
|
||||
VIR_DEBUG("%s %s: found parent device %s\n", b->id, b->name, a->name);
|
||||
|
||||
/* No, it's superman! */
|
||||
return (dev->bus >= secondary && dev->bus <= subordinate);
|
||||
return (b->bus >= secondary && b->bus <= subordinate);
|
||||
}
|
||||
|
||||
static pciDevice *
|
||||
pciGetParentDevice(virConnectPtr conn, pciDevice *dev)
|
||||
{
|
||||
pciDevice *parent = NULL;
|
||||
pciIterDevices(conn, NULL, pciIsParent, dev, NULL, &parent);
|
||||
pciIterDevices(conn, pciIsParent, dev, &parent);
|
||||
return parent;
|
||||
}
|
||||
|
||||
@ -459,12 +443,9 @@ pciGetParentDevice(virConnectPtr conn, pciDevice *dev)
|
||||
* devices behind a bus.
|
||||
*/
|
||||
static int
|
||||
pciTrySecondaryBusReset(virConnectPtr conn,
|
||||
virDomainObjPtr vm,
|
||||
pciDevice *dev,
|
||||
pciResetCheckFunc check)
|
||||
pciTrySecondaryBusReset(virConnectPtr conn, pciDevice *dev)
|
||||
{
|
||||
pciDevice *parent, *conflict;
|
||||
pciDevice *parent;
|
||||
uint8_t config_space[PCI_CONF_LEN];
|
||||
uint16_t ctl;
|
||||
int ret = -1;
|
||||
@ -474,11 +455,10 @@ pciTrySecondaryBusReset(virConnectPtr conn,
|
||||
* In future, we could allow it so long as those devices
|
||||
* are not in use by the host or other guests.
|
||||
*/
|
||||
if ((conflict = pciBusCheckOtherDevices(conn, vm, dev, check))) {
|
||||
if (pciBusContainsOtherDevices(conn, dev)) {
|
||||
pciReportError(conn, VIR_ERR_NO_SUPPORT,
|
||||
_("Unable to reset %s using bus reset as this would cause %s to be reset"),
|
||||
dev->name, conflict->name);
|
||||
pciFreeDevice(conn, conflict);
|
||||
_("Other devices on bus with %s, not doing bus reset"),
|
||||
dev->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -592,24 +572,13 @@ pciInitDevice(virConnectPtr conn, pciDevice *dev)
|
||||
}
|
||||
|
||||
int
|
||||
pciResetDevice(virConnectPtr conn,
|
||||
virDomainObjPtr vm,
|
||||
pciDevice *dev,
|
||||
pciResetCheckFunc check)
|
||||
pciResetDevice(virConnectPtr conn, pciDevice *dev)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (!dev->initted && pciInitDevice(conn, dev) < 0)
|
||||
return -1;
|
||||
|
||||
/* Check that the device isn't owned by a running VM */
|
||||
if (!check(conn, vm, dev)) {
|
||||
pciReportError(conn, VIR_ERR_NO_SUPPORT,
|
||||
_("Unable to reset PCI device %s: device is in use"),
|
||||
dev->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* KVM will perform FLR when starting and stopping
|
||||
* a guest, so there is no need for us to do it here.
|
||||
*/
|
||||
@ -625,7 +594,7 @@ pciResetDevice(virConnectPtr conn,
|
||||
|
||||
/* Bus reset is not an option with the root bus */
|
||||
if (ret < 0 && dev->bus != 0)
|
||||
ret = pciTrySecondaryBusReset(conn, vm, dev, check);
|
||||
ret = pciTrySecondaryBusReset(conn, dev);
|
||||
|
||||
if (ret < 0) {
|
||||
virErrorPtr err = virGetLastError();
|
||||
@ -926,18 +895,3 @@ pciFreeDevice(virConnectPtr conn ATTRIBUTE_UNUSED, pciDevice *dev)
|
||||
close(dev->fd);
|
||||
VIR_FREE(dev);
|
||||
}
|
||||
|
||||
int
|
||||
pciDeviceEquals(virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||
pciDevice *dev,
|
||||
unsigned domain,
|
||||
unsigned bus,
|
||||
unsigned slot,
|
||||
unsigned function)
|
||||
{
|
||||
return
|
||||
dev->domain == domain &&
|
||||
dev->bus == bus &&
|
||||
dev->slot == slot &&
|
||||
dev->function == function;
|
||||
}
|
||||
|
22
src/pci.h
22
src/pci.h
@ -24,7 +24,6 @@
|
||||
|
||||
#include <config.h>
|
||||
#include "internal.h"
|
||||
#include "domain_conf.h"
|
||||
|
||||
typedef struct _pciDevice pciDevice;
|
||||
|
||||
@ -39,24 +38,7 @@ int pciDettachDevice (virConnectPtr conn,
|
||||
pciDevice *dev);
|
||||
int pciReAttachDevice (virConnectPtr conn,
|
||||
pciDevice *dev);
|
||||
|
||||
/* pciResetDevice() may cause other devices to be reset;
|
||||
* The check function is called for each other device to
|
||||
* be reset and by returning zero may cause the reset to
|
||||
* fail if it is not safe to reset the supplied device.
|
||||
*/
|
||||
typedef int (*pciResetCheckFunc)(virConnectPtr, virDomainObjPtr, pciDevice *);
|
||||
|
||||
int pciResetDevice(virConnectPtr conn,
|
||||
virDomainObjPtr vm,
|
||||
pciDevice *dev,
|
||||
pciResetCheckFunc check);
|
||||
|
||||
int pciDeviceEquals(virConnectPtr conn,
|
||||
pciDevice *dev,
|
||||
unsigned domain,
|
||||
unsigned bus,
|
||||
unsigned slot,
|
||||
unsigned function);
|
||||
int pciResetDevice (virConnectPtr conn,
|
||||
pciDevice *dev);
|
||||
|
||||
#endif /* __VIR_PCI_H__ */
|
||||
|
@ -1329,52 +1329,8 @@ static int qemudNextFreeVNCPort(struct qemud_driver *driver ATTRIBUTE_UNUSED) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
qemuCheckPciHostDevice(virConnectPtr conn,
|
||||
virDomainObjPtr owner_vm,
|
||||
pciDevice *dev)
|
||||
{
|
||||
struct qemud_driver *driver = conn->privateData;
|
||||
int ret = 1, i;
|
||||
|
||||
for (i = 0; i < driver->domains.count && ret; i++) {
|
||||
virDomainObjPtr vm = driver->domains.objs[i];
|
||||
|
||||
if (vm == owner_vm)
|
||||
continue;
|
||||
|
||||
virDomainObjLock(vm);
|
||||
|
||||
if (virDomainIsActive(vm)) {
|
||||
int j;
|
||||
|
||||
for (j = 0; j < vm->def->nhostdevs && ret; j++) {
|
||||
virDomainHostdevDefPtr hostdev = vm->def->hostdevs[j];
|
||||
|
||||
if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
|
||||
continue;
|
||||
if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
|
||||
continue;
|
||||
|
||||
if (pciDeviceEquals(conn, dev,
|
||||
hostdev->source.subsys.u.pci.domain,
|
||||
hostdev->source.subsys.u.pci.bus,
|
||||
hostdev->source.subsys.u.pci.slot,
|
||||
hostdev->source.subsys.u.pci.function))
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
virDomainObjUnlock(vm);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
qemuPrepareHostDevices(virConnectPtr conn, virDomainObjPtr vm)
|
||||
{
|
||||
virDomainDefPtr def = vm->def;
|
||||
static int qemuPrepareHostDevices(virConnectPtr conn,
|
||||
virDomainDefPtr def) {
|
||||
int i;
|
||||
|
||||
/* We have to use 2 loops here. *All* devices must
|
||||
@ -1432,7 +1388,7 @@ qemuPrepareHostDevices(virConnectPtr conn, virDomainObjPtr vm)
|
||||
if (!dev)
|
||||
goto error;
|
||||
|
||||
if (pciResetDevice(conn, vm, dev, qemuCheckPciHostDevice) < 0) {
|
||||
if (pciResetDevice(conn, dev) < 0) {
|
||||
pciFreeDevice(conn, dev);
|
||||
goto error;
|
||||
}
|
||||
@ -1447,9 +1403,8 @@ error:
|
||||
}
|
||||
|
||||
static void
|
||||
qemuDomainReAttachHostDevices(virConnectPtr conn, virDomainObjPtr vm)
|
||||
qemuDomainReAttachHostDevices(virConnectPtr conn, virDomainDefPtr def)
|
||||
{
|
||||
virDomainDefPtr def = vm->def;
|
||||
int i;
|
||||
|
||||
/* Again 2 loops; reset all the devices before re-attach */
|
||||
@ -1476,7 +1431,7 @@ qemuDomainReAttachHostDevices(virConnectPtr conn, virDomainObjPtr vm)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pciResetDevice(conn, vm, dev, qemuCheckPciHostDevice) < 0) {
|
||||
if (pciResetDevice(conn, dev) < 0) {
|
||||
virErrorPtr err = virGetLastError();
|
||||
VIR_ERROR(_("Failed to reset PCI device: %s\n"),
|
||||
err ? err->message : "");
|
||||
@ -2046,7 +2001,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
|
||||
if (qemuSetupCgroup(conn, driver, vm) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (qemuPrepareHostDevices(conn, vm) < 0)
|
||||
if (qemuPrepareHostDevices(conn, vm->def) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (VIR_ALLOC(vm->monitor_chr) < 0) {
|
||||
@ -2228,7 +2183,7 @@ static void qemudShutdownVMDaemon(virConnectPtr conn,
|
||||
VIR_WARN("Failed to restore all device ownership for %s",
|
||||
vm->def->name);
|
||||
|
||||
qemuDomainReAttachHostDevices(conn, vm);
|
||||
qemuDomainReAttachHostDevices(conn, vm->def);
|
||||
|
||||
retry:
|
||||
if ((ret = qemuRemoveCgroup(conn, driver, vm)) < 0) {
|
||||
@ -5371,7 +5326,7 @@ static int qemudDomainAttachHostPciDevice(virConnectPtr conn,
|
||||
return -1;
|
||||
|
||||
if (pciDettachDevice(conn, pci) < 0 ||
|
||||
pciResetDevice(conn, vm, pci, qemuCheckPciHostDevice) < 0) {
|
||||
pciResetDevice(conn, pci) < 0) {
|
||||
pciFreeDevice(conn, pci);
|
||||
return -1;
|
||||
}
|
||||
@ -7158,7 +7113,6 @@ out:
|
||||
static int
|
||||
qemudNodeDeviceReset (virNodeDevicePtr dev)
|
||||
{
|
||||
struct qemud_driver *driver = dev->conn->privateData;
|
||||
pciDevice *pci;
|
||||
unsigned domain, bus, slot, function;
|
||||
int ret = -1;
|
||||
@ -7170,14 +7124,11 @@ qemudNodeDeviceReset (virNodeDevicePtr dev)
|
||||
if (!pci)
|
||||
return -1;
|
||||
|
||||
qemuDriverLock(driver);
|
||||
|
||||
if (pciResetDevice(dev->conn, NULL, pci, qemuCheckPciHostDevice) < 0)
|
||||
if (pciResetDevice(dev->conn, pci) < 0)
|
||||
goto out;
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
qemuDriverUnlock(driver);
|
||||
pciFreeDevice(dev->conn, pci);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1641,7 +1641,7 @@ xenUnifiedNodeDeviceReset (virNodeDevicePtr dev)
|
||||
if (!pci)
|
||||
return -1;
|
||||
|
||||
if (pciResetDevice(dev->conn, NULL, pci, NULL) < 0)
|
||||
if (pciResetDevice(dev->conn, pci) < 0)
|
||||
goto out;
|
||||
|
||||
ret = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user