From: Mark McLoughlin Date: Fri, 14 Aug 2009 07:31:11 +0000 (+0100) Subject: Check active domain hostdevs before allowing PCI reset X-Git-Tag: v0.7.1~187 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c106c8a18c63d9e4f2547724a4a563706f8f6778;p=thirdparty%2Flibvirt.git Check active domain hostdevs before allowing PCI reset If a PCI device reset causes other devices to be reset, allow it so long as those other devices are note assigned to another active domain. Note, we need to take the driver lock qemudNodeDeviceReset() because the check function will iterate over the domain list. * src/qemu_conf.c: add qemuCheckPciHostDevice() to iterate over active domains checking whether the affected device is assigned * src/pci.[ch]: add pciDeviceEquals() helper --- diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 642c2bca98..23fa01b2cf 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -283,6 +283,7 @@ virNodeDeviceAssignDef; pciGetDevice; pciFreeDevice; pciDettachDevice; +pciDeviceEquals; pciReAttachDevice; pciResetDevice; diff --git a/src/pci.c b/src/pci.c index 6a2e860007..619853b2af 100644 --- a/src/pci.c +++ b/src/pci.c @@ -926,3 +926,18 @@ 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; +} diff --git a/src/pci.h b/src/pci.h index 15da057f16..d5e680cba7 100644 --- a/src/pci.h +++ b/src/pci.h @@ -52,4 +52,11 @@ int pciResetDevice(virConnectPtr conn, pciDevice *dev, pciResetCheckFunc check); +int pciDeviceEquals(virConnectPtr conn, + pciDevice *dev, + unsigned domain, + unsigned bus, + unsigned slot, + unsigned function); + #endif /* __VIR_PCI_H__ */ diff --git a/src/qemu_driver.c b/src/qemu_driver.c index bfa06a55d0..4b1aeea4ad 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -1329,6 +1329,48 @@ 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) { @@ -1390,7 +1432,7 @@ qemuPrepareHostDevices(virConnectPtr conn, virDomainObjPtr vm) if (!dev) goto error; - if (pciResetDevice(conn, vm, dev, NULL) < 0) { + if (pciResetDevice(conn, vm, dev, qemuCheckPciHostDevice) < 0) { pciFreeDevice(conn, dev); goto error; } @@ -1434,7 +1476,7 @@ qemuDomainReAttachHostDevices(virConnectPtr conn, virDomainObjPtr vm) continue; } - if (pciResetDevice(conn, vm, dev, NULL) < 0) { + if (pciResetDevice(conn, vm, dev, qemuCheckPciHostDevice) < 0) { virErrorPtr err = virGetLastError(); VIR_ERROR(_("Failed to reset PCI device: %s\n"), err ? err->message : ""); @@ -5250,7 +5292,7 @@ static int qemudDomainAttachHostPciDevice(virConnectPtr conn, return -1; if (pciDettachDevice(conn, pci) < 0 || - pciResetDevice(conn, vm, pci, NULL) < 0) { + pciResetDevice(conn, vm, pci, qemuCheckPciHostDevice) < 0) { pciFreeDevice(conn, pci); return -1; } @@ -7041,6 +7083,7 @@ out: static int qemudNodeDeviceReset (virNodeDevicePtr dev) { + struct qemud_driver *driver = dev->conn->privateData; pciDevice *pci; unsigned domain, bus, slot, function; int ret = -1; @@ -7052,11 +7095,14 @@ qemudNodeDeviceReset (virNodeDevicePtr dev) if (!pci) return -1; - if (pciResetDevice(dev->conn, NULL, pci, NULL) < 0) + qemuDriverLock(driver); + + if (pciResetDevice(dev->conn, NULL, pci, qemuCheckPciHostDevice) < 0) goto out; ret = 0; out: + qemuDriverUnlock(driver); pciFreeDevice(dev->conn, pci); return ret; }