Maintain a list of active PCI hostdevs and use it in pciResetDevice()

As we start/shutdown guests, or hotplug/hot-unplug devices, we can add
or delete devices as appropriate from a list of active devices.

Then, in pciReset(), we can use this to determine whether its safe to
reset a device as a side effect of resetting another device.

* src/qemu_conf.h: add activePciHostdevs to qemud_driver

* src/qemu_driver.c: maintain the activePciHostdevs list, and pass it
  to pciResetDevice()

* src/pci.[ch]: pass the activeDevs list to pciResetDevice() and use
  it to determine whether a Secondary Bus Reset is safe
This commit is contained in:
Mark McLoughlin 2009-08-17 15:05:23 +01:00
parent 78675b228b
commit e8ad339312
5 changed files with 165 additions and 68 deletions

102
src/pci.c
View File

@ -226,7 +226,7 @@ pciWrite32(pciDevice *dev, unsigned pos, uint32_t val)
pciWrite(dev, pos, &buf[0], sizeof(buf)); pciWrite(dev, pos, &buf[0], sizeof(buf));
} }
typedef int (*pciIterPredicate)(pciDevice *, pciDevice *); typedef int (*pciIterPredicate)(pciDevice *, pciDevice *, void *);
/* Iterate over available PCI devices calling @predicate /* Iterate over available PCI devices calling @predicate
* to compare each one to @dev. * to compare each one to @dev.
@ -237,7 +237,8 @@ static int
pciIterDevices(virConnectPtr conn, pciIterDevices(virConnectPtr conn,
pciIterPredicate predicate, pciIterPredicate predicate,
pciDevice *dev, pciDevice *dev,
pciDevice **matched) pciDevice **matched,
void *data)
{ {
DIR *dir; DIR *dir;
struct dirent *entry; struct dirent *entry;
@ -255,7 +256,7 @@ pciIterDevices(virConnectPtr conn,
while ((entry = readdir(dir))) { while ((entry = readdir(dir))) {
unsigned domain, bus, slot, function; unsigned domain, bus, slot, function;
pciDevice *try; pciDevice *check;
/* Ignore '.' and '..' */ /* Ignore '.' and '..' */
if (entry->d_name[0] == '.') if (entry->d_name[0] == '.')
@ -267,18 +268,18 @@ pciIterDevices(virConnectPtr conn,
continue; continue;
} }
try = pciGetDevice(conn, domain, bus, slot, function); check = pciGetDevice(conn, domain, bus, slot, function);
if (!try) { if (!check) {
ret = -1; ret = -1;
break; break;
} }
if (predicate(try, dev)) { if (predicate(dev, check, data)) {
VIR_DEBUG("%s %s: iter matched on %s", dev->id, dev->name, try->name); VIR_DEBUG("%s %s: iter matched on %s", dev->id, dev->name, check->name);
*matched = try; *matched = check;
break; break;
} }
pciFreeDevice(conn, try); pciFreeDevice(conn, check);
} }
closedir(dir); closedir(dir);
return ret; return ret;
@ -380,63 +381,70 @@ pciDetectPowerManagementReset(pciDevice *dev)
return 0; return 0;
} }
/* Any devices other than the one supplied on the same domain/bus ? */ /* Any active devices other than the one supplied on the same domain/bus ? */
static int static int
pciSharesBus(pciDevice *a, pciDevice *b) pciSharesBusWithActive(pciDevice *dev, pciDevice *check, void *data)
{ {
return pciDeviceList *activeDevs = data;
a->domain == b->domain &&
a->bus == b->bus &&
(a->slot != b->slot ||
a->function != b->function);
}
static int if (dev->domain != check->domain ||
pciBusContainsOtherDevices(virConnectPtr conn, pciDevice *dev) dev->bus != check->bus ||
{ (check->slot == check->slot &&
pciDevice *matched = NULL; check->function == check->function))
if (pciIterDevices(conn, pciSharesBus, dev, &matched) < 0)
return 1;
if (!matched)
return 0; return 0;
pciFreeDevice(conn, matched);
if (activeDevs && !pciDeviceListFind(activeDevs, check))
return 0;
return 1; return 1;
} }
/* Is @a the parent of @b ? */ static pciDevice *
pciBusContainsActiveDevices(virConnectPtr conn,
pciDevice *dev,
pciDeviceList *activeDevs)
{
pciDevice *active = NULL;
if (pciIterDevices(conn, pciSharesBusWithActive,
dev, &active, activeDevs) < 0)
return NULL;
return active;
}
/* Is @check the parent of @dev ? */
static int static int
pciIsParent(pciDevice *a, pciDevice *b) pciIsParent(pciDevice *dev, pciDevice *check, void *data ATTRIBUTE_UNUSED)
{ {
uint16_t device_class; uint16_t device_class;
uint8_t header_type, secondary, subordinate; uint8_t header_type, secondary, subordinate;
if (a->domain != b->domain) if (dev->domain != check->domain)
return 0; return 0;
/* Is it a bridge? */ /* Is it a bridge? */
device_class = pciRead16(a, PCI_CLASS_DEVICE); device_class = pciRead16(check, PCI_CLASS_DEVICE);
if (device_class != PCI_CLASS_BRIDGE_PCI) if (device_class != PCI_CLASS_BRIDGE_PCI)
return 0; return 0;
/* Is it a plane? */ /* Is it a plane? */
header_type = pciRead8(a, PCI_HEADER_TYPE); header_type = pciRead8(check, PCI_HEADER_TYPE);
if ((header_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE) if ((header_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE)
return 0; return 0;
secondary = pciRead8(a, PCI_SECONDARY_BUS); secondary = pciRead8(check, PCI_SECONDARY_BUS);
subordinate = pciRead8(a, PCI_SUBORDINATE_BUS); subordinate = pciRead8(check, PCI_SUBORDINATE_BUS);
VIR_DEBUG("%s %s: found parent device %s\n", b->id, b->name, a->name); VIR_DEBUG("%s %s: found parent device %s\n", dev->id, dev->name, check->name);
/* No, it's superman! */ /* No, it's superman! */
return (b->bus >= secondary && b->bus <= subordinate); return (dev->bus >= secondary && dev->bus <= subordinate);
} }
static pciDevice * static pciDevice *
pciGetParentDevice(virConnectPtr conn, pciDevice *dev) pciGetParentDevice(virConnectPtr conn, pciDevice *dev)
{ {
pciDevice *parent = NULL; pciDevice *parent = NULL;
pciIterDevices(conn, pciIsParent, dev, &parent); pciIterDevices(conn, pciIsParent, dev, &parent, NULL);
return parent; return parent;
} }
@ -444,9 +452,11 @@ pciGetParentDevice(virConnectPtr conn, pciDevice *dev)
* devices behind a bus. * devices behind a bus.
*/ */
static int static int
pciTrySecondaryBusReset(virConnectPtr conn, pciDevice *dev) pciTrySecondaryBusReset(virConnectPtr conn,
pciDevice *dev,
pciDeviceList *activeDevs)
{ {
pciDevice *parent; pciDevice *parent, *conflict;
uint8_t config_space[PCI_CONF_LEN]; uint8_t config_space[PCI_CONF_LEN];
uint16_t ctl; uint16_t ctl;
int ret = -1; int ret = -1;
@ -456,10 +466,10 @@ pciTrySecondaryBusReset(virConnectPtr conn, pciDevice *dev)
* In future, we could allow it so long as those devices * In future, we could allow it so long as those devices
* are not in use by the host or other guests. * are not in use by the host or other guests.
*/ */
if (pciBusContainsOtherDevices(conn, dev)) { if ((conflict = pciBusContainsActiveDevices(conn, dev, activeDevs))) {
pciReportError(conn, VIR_ERR_NO_SUPPORT, pciReportError(conn, VIR_ERR_NO_SUPPORT,
_("Other devices on bus with %s, not doing bus reset"), _("Active %s devices on bus with %s, not doing bus reset"),
dev->name); conflict->name, dev->name);
return -1; return -1;
} }
@ -573,10 +583,18 @@ pciInitDevice(virConnectPtr conn, pciDevice *dev)
} }
int int
pciResetDevice(virConnectPtr conn, pciDevice *dev) pciResetDevice(virConnectPtr conn,
pciDevice *dev,
pciDeviceList *activeDevs)
{ {
int ret = -1; int ret = -1;
if (activeDevs && pciDeviceListFind(activeDevs, dev)) {
pciReportError(conn, VIR_ERR_INTERNAL_ERROR,
_("Not resetting active device %s"), dev->name);
return -1;
}
if (!dev->initted && pciInitDevice(conn, dev) < 0) if (!dev->initted && pciInitDevice(conn, dev) < 0)
return -1; return -1;
@ -595,7 +613,7 @@ pciResetDevice(virConnectPtr conn, pciDevice *dev)
/* Bus reset is not an option with the root bus */ /* Bus reset is not an option with the root bus */
if (ret < 0 && dev->bus != 0) if (ret < 0 && dev->bus != 0)
ret = pciTrySecondaryBusReset(conn, dev); ret = pciTrySecondaryBusReset(conn, dev, activeDevs);
if (ret < 0) { if (ret < 0) {
virErrorPtr err = virGetLastError(); virErrorPtr err = virGetLastError();

View File

@ -44,7 +44,8 @@ int pciDettachDevice (virConnectPtr conn,
int pciReAttachDevice (virConnectPtr conn, int pciReAttachDevice (virConnectPtr conn,
pciDevice *dev); pciDevice *dev);
int pciResetDevice (virConnectPtr conn, int pciResetDevice (virConnectPtr conn,
pciDevice *dev); pciDevice *dev,
pciDeviceList *activeDevs);
void pciDeviceSetManaged(pciDevice *dev, void pciDeviceSetManaged(pciDevice *dev,
unsigned managed); unsigned managed);
unsigned pciDeviceGetManaged(pciDevice *dev); unsigned pciDeviceGetManaged(pciDevice *dev);

View File

@ -35,6 +35,7 @@
#include "threads.h" #include "threads.h"
#include "security.h" #include "security.h"
#include "cgroup.h" #include "cgroup.h"
#include "pci.h"
#define qemudDebug(fmt, ...) do {} while(0) #define qemudDebug(fmt, ...) do {} while(0)
@ -111,6 +112,8 @@ struct qemud_driver {
virSecurityDriverPtr securityDriver; virSecurityDriverPtr securityDriver;
char *saveImageFormat; char *saveImageFormat;
pciDeviceList *activePciHostdevs;
}; };

View File

@ -128,6 +128,9 @@ static int qemudDomainSetMemoryBalloon(virConnectPtr conn,
static int qemudDetectVcpuPIDs(virConnectPtr conn, static int qemudDetectVcpuPIDs(virConnectPtr conn,
virDomainObjPtr vm); virDomainObjPtr vm);
static int qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
virDomainDefPtr def);
static struct qemud_driver *qemu_driver = NULL; static struct qemud_driver *qemu_driver = NULL;
static int qemuCgroupControllerActive(struct qemud_driver *driver, static int qemuCgroupControllerActive(struct qemud_driver *driver,
@ -320,6 +323,10 @@ qemuReconnectDomain(struct qemud_driver *driver,
goto error; goto error;
} }
if (qemuUpdateActivePciHostdevs(driver, obj->def) < 0) {
goto error;
}
if (obj->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC && if (obj->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
driver->securityDriver && driver->securityDriver &&
driver->securityDriver->domainReserveSecurityLabel && driver->securityDriver->domainReserveSecurityLabel &&
@ -524,6 +531,9 @@ qemudStartup(int privileged) {
if ((qemu_driver->caps = qemudCapsInit(NULL)) == NULL) if ((qemu_driver->caps = qemudCapsInit(NULL)) == NULL)
goto out_of_memory; goto out_of_memory;
if ((qemu_driver->activePciHostdevs = pciDeviceListNew(NULL)) == NULL)
goto error;
if (qemudLoadDriverConfig(qemu_driver, driverConf) < 0) { if (qemudLoadDriverConfig(qemu_driver, driverConf) < 0) {
goto error; goto error;
} }
@ -648,6 +658,7 @@ qemudShutdown(void) {
return -1; return -1;
qemuDriverLock(qemu_driver); qemuDriverLock(qemu_driver);
pciDeviceListFree(NULL, qemu_driver->activePciHostdevs);
virCapabilitiesFree(qemu_driver->caps); virCapabilitiesFree(qemu_driver->caps);
virDomainObjListFree(&qemu_driver->domains); virDomainObjListFree(&qemu_driver->domains);
@ -1371,7 +1382,38 @@ qemuGetPciHostDeviceList(virConnectPtr conn,
} }
static int static int
qemuPrepareHostDevices(virConnectPtr conn, virDomainDefPtr def) qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
virDomainDefPtr def)
{
pciDeviceList *pcidevs;
int i, ret;
if (!def->nhostdevs)
return 0;
if (!(pcidevs = qemuGetPciHostDeviceList(NULL, def)))
return -1;
ret = 0;
for (i = 0; i < pcidevs->count; i++) {
if (pciDeviceListAdd(NULL,
driver->activePciHostdevs,
pcidevs->devs[i]) < 0) {
ret = -1;
break;
}
pcidevs->devs[i] = NULL;
}
pciDeviceListFree(NULL, pcidevs);
return ret;
}
static int
qemuPrepareHostDevices(virConnectPtr conn,
struct qemud_driver *driver,
virDomainDefPtr def)
{ {
pciDeviceList *pcidevs; pciDeviceList *pcidevs;
int i; int i;
@ -1382,10 +1424,11 @@ qemuPrepareHostDevices(virConnectPtr conn, virDomainDefPtr def)
if (!(pcidevs = qemuGetPciHostDeviceList(conn, def))) if (!(pcidevs = qemuGetPciHostDeviceList(conn, def)))
return -1; return -1;
/* We have to use 2 loops here. *All* devices must /* We have to use 3 loops here. *All* devices must
* be detached before we reset any of them, because * be detached before we reset any of them, because
* in some cases you have to reset the whole PCI, * in some cases you have to reset the whole PCI,
* which impacts all devices on it * which impacts all devices on it. Also, all devices
* must be reset before being marked as active.
*/ */
/* XXX validate that non-managed device isn't in use, eg /* XXX validate that non-managed device isn't in use, eg
@ -1401,9 +1444,19 @@ qemuPrepareHostDevices(virConnectPtr conn, virDomainDefPtr def)
/* Now that all the PCI hostdevs have be dettached, we can safely /* Now that all the PCI hostdevs have be dettached, we can safely
* reset them */ * reset them */
for (i = 0; i < pcidevs->count; i++) for (i = 0; i < pcidevs->count; i++)
if (pciResetDevice(conn, pcidevs->devs[i]) < 0) if (pciResetDevice(conn, pcidevs->devs[i],
driver->activePciHostdevs) < 0)
goto error; goto error;
/* Now mark all the devices as active */
for (i = 0; i < pcidevs->count; i++) {
if (pciDeviceListAdd(conn,
driver->activePciHostdevs,
pcidevs->devs[i]) < 0)
goto error;
pcidevs->devs[i] = NULL;
}
pciDeviceListFree(conn, pcidevs); pciDeviceListFree(conn, pcidevs);
return 0; return 0;
@ -1413,7 +1466,9 @@ error:
} }
static void static void
qemuDomainReAttachHostDevices(virConnectPtr conn, virDomainDefPtr def) qemuDomainReAttachHostDevices(virConnectPtr conn,
struct qemud_driver *driver,
virDomainDefPtr def)
{ {
pciDeviceList *pcidevs; pciDeviceList *pcidevs;
int i; int i;
@ -1429,10 +1484,15 @@ qemuDomainReAttachHostDevices(virConnectPtr conn, virDomainDefPtr def)
return; return;
} }
/* Again 2 loops; reset all the devices before re-attach */ /* Again 3 loops; mark all devices as inactive before reset
* them and reset all the devices before re-attach */
for (i = 0; i < pcidevs->count; i++) for (i = 0; i < pcidevs->count; i++)
if (pciResetDevice(conn, pcidevs->devs[i]) < 0) { pciDeviceListDel(conn, driver->activePciHostdevs, pcidevs->devs[i]);
for (i = 0; i < pcidevs->count; i++)
if (pciResetDevice(conn, pcidevs->devs[i],
driver->activePciHostdevs) < 0) {
virErrorPtr err = virGetLastError(); virErrorPtr err = virGetLastError();
VIR_ERROR(_("Failed to reset PCI device: %s\n"), VIR_ERROR(_("Failed to reset PCI device: %s\n"),
err ? err->message : ""); err ? err->message : "");
@ -1976,7 +2036,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
if (qemuSetupCgroup(conn, driver, vm) < 0) if (qemuSetupCgroup(conn, driver, vm) < 0)
goto cleanup; goto cleanup;
if (qemuPrepareHostDevices(conn, vm->def) < 0) if (qemuPrepareHostDevices(conn, driver, vm->def) < 0)
goto cleanup; goto cleanup;
if (VIR_ALLOC(vm->monitor_chr) < 0) { if (VIR_ALLOC(vm->monitor_chr) < 0) {
@ -2158,7 +2218,7 @@ static void qemudShutdownVMDaemon(virConnectPtr conn,
VIR_WARN("Failed to restore all device ownership for %s", VIR_WARN("Failed to restore all device ownership for %s",
vm->def->name); vm->def->name);
qemuDomainReAttachHostDevices(conn, vm->def); qemuDomainReAttachHostDevices(conn, driver, vm->def);
retry: retry:
if ((ret = qemuRemoveCgroup(conn, driver, vm)) < 0) { if ((ret = qemuRemoveCgroup(conn, driver, vm)) < 0) {
@ -5279,6 +5339,7 @@ cleanup:
} }
static int qemudDomainAttachHostPciDevice(virConnectPtr conn, static int qemudDomainAttachHostPciDevice(virConnectPtr conn,
struct qemud_driver *driver,
virDomainObjPtr vm, virDomainObjPtr vm,
virDomainDeviceDefPtr dev) virDomainDeviceDefPtr dev)
{ {
@ -5301,42 +5362,42 @@ static int qemudDomainAttachHostPciDevice(virConnectPtr conn,
return -1; return -1;
if ((hostdev->managed && pciDettachDevice(conn, pci) < 0) || if ((hostdev->managed && pciDettachDevice(conn, pci) < 0) ||
pciResetDevice(conn, pci) < 0) { pciResetDevice(conn, pci, driver->activePciHostdevs) < 0) {
pciFreeDevice(conn, pci); pciFreeDevice(conn, pci);
return -1; return -1;
} }
pciFreeDevice(conn, pci); if (pciDeviceListAdd(conn, driver->activePciHostdevs, pci) < 0) {
pciFreeDevice(conn, pci);
return -1;
}
cmd = reply = NULL;
if (virAsprintf(&cmd, "pci_add pci_addr=auto host host=%.2x:%.2x.%.1x", if (virAsprintf(&cmd, "pci_add pci_addr=auto host host=%.2x:%.2x.%.1x",
hostdev->source.subsys.u.pci.bus, hostdev->source.subsys.u.pci.bus,
hostdev->source.subsys.u.pci.slot, hostdev->source.subsys.u.pci.slot,
hostdev->source.subsys.u.pci.function) < 0) { hostdev->source.subsys.u.pci.function) < 0) {
virReportOOMError(conn); virReportOOMError(conn);
return -1; goto error;
} }
if (qemudMonitorCommand(vm, cmd, &reply) < 0) { if (qemudMonitorCommand(vm, cmd, &reply) < 0) {
qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED, qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
"%s", _("cannot attach host pci device")); "%s", _("cannot attach host pci device"));
VIR_FREE(cmd); goto error;
return -1;
} }
if (strstr(reply, "invalid type: host")) { if (strstr(reply, "invalid type: host")) {
qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT, "%s", qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT, "%s",
_("PCI device assignment is not supported by this version of qemu")); _("PCI device assignment is not supported by this version of qemu"));
VIR_FREE(cmd); goto error;
VIR_FREE(reply);
return -1;
} }
if (qemudParsePciAddReply(vm, reply, &domain, &bus, &slot) < 0) { if (qemudParsePciAddReply(vm, reply, &domain, &bus, &slot) < 0) {
qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED, qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
_("parsing pci_add reply failed: %s"), reply); _("parsing pci_add reply failed: %s"), reply);
VIR_FREE(cmd); goto error;
VIR_FREE(reply);
return -1;
} }
hostdev->source.subsys.u.pci.guest_addr.domain = domain; hostdev->source.subsys.u.pci.guest_addr.domain = domain;
@ -5349,6 +5410,14 @@ static int qemudDomainAttachHostPciDevice(virConnectPtr conn,
VIR_FREE(cmd); VIR_FREE(cmd);
return 0; return 0;
error:
pciDeviceListDel(conn, driver->activePciHostdevs, pci);
VIR_FREE(reply);
VIR_FREE(cmd);
return -1;
} }
static int qemudDomainAttachHostUsbDevice(virConnectPtr conn, static int qemudDomainAttachHostUsbDevice(virConnectPtr conn,
@ -5422,7 +5491,7 @@ static int qemudDomainAttachHostDevice(virConnectPtr conn,
switch (hostdev->source.subsys.type) { switch (hostdev->source.subsys.type) {
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
return qemudDomainAttachHostPciDevice(conn, vm, dev); return qemudDomainAttachHostPciDevice(conn, driver, vm, dev);
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
return qemudDomainAttachHostUsbDevice(conn, vm, dev); return qemudDomainAttachHostUsbDevice(conn, vm, dev);
default: default:
@ -5749,6 +5818,7 @@ cleanup:
} }
static int qemudDomainDetachHostPciDevice(virConnectPtr conn, static int qemudDomainDetachHostPciDevice(virConnectPtr conn,
struct qemud_driver *driver,
virDomainObjPtr vm, virDomainObjPtr vm,
virDomainDeviceDefPtr dev) virDomainDeviceDefPtr dev)
{ {
@ -5832,7 +5902,8 @@ static int qemudDomainDetachHostPciDevice(virConnectPtr conn,
if (!pci) if (!pci)
ret = -1; ret = -1;
else { else {
if (pciResetDevice(conn, pci) < 0) pciDeviceListDel(conn, driver->activePciHostdevs, pci);
if (pciResetDevice(conn, pci, driver->activePciHostdevs) < 0)
ret = -1; ret = -1;
if (detach->managed && pciReAttachDevice(conn, pci) < 0) if (detach->managed && pciReAttachDevice(conn, pci) < 0)
ret = -1; ret = -1;
@ -5868,7 +5939,7 @@ static int qemudDomainDetachHostDevice(virConnectPtr conn,
switch (hostdev->source.subsys.type) { switch (hostdev->source.subsys.type) {
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
ret = qemudDomainDetachHostPciDevice(conn, vm, dev); ret = qemudDomainDetachHostPciDevice(conn, driver, vm, dev);
break; break;
default: default:
qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT, qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT,
@ -7092,6 +7163,7 @@ out:
static int static int
qemudNodeDeviceReset (virNodeDevicePtr dev) qemudNodeDeviceReset (virNodeDevicePtr dev)
{ {
struct qemud_driver *driver = dev->conn->privateData;
pciDevice *pci; pciDevice *pci;
unsigned domain, bus, slot, function; unsigned domain, bus, slot, function;
int ret = -1; int ret = -1;
@ -7103,11 +7175,14 @@ qemudNodeDeviceReset (virNodeDevicePtr dev)
if (!pci) if (!pci)
return -1; return -1;
if (pciResetDevice(dev->conn, pci) < 0) qemuDriverLock(driver);
if (pciResetDevice(dev->conn, pci, driver->activePciHostdevs) < 0)
goto out; goto out;
ret = 0; ret = 0;
out: out:
qemuDriverUnlock(driver);
pciFreeDevice(dev->conn, pci); pciFreeDevice(dev->conn, pci);
return ret; return ret;
} }

View File

@ -1641,7 +1641,7 @@ xenUnifiedNodeDeviceReset (virNodeDevicePtr dev)
if (!pci) if (!pci)
return -1; return -1;
if (pciResetDevice(dev->conn, pci) < 0) if (pciResetDevice(dev->conn, pci, NULL) < 0)
goto out; goto out;
ret = 0; ret = 0;