[libvirt] [PATCH 8/8] Check active domain hostdevs before allowing PCI reset
Daniel P. Berrange
berrange at redhat.com
Thu Aug 13 18:46:15 UTC 2009
On Thu, Aug 13, 2009 at 05:44:37PM +0100, Mark McLoughlin wrote:
> 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
> ---
> src/libvirt_private.syms | 1 +
> src/pci.c | 15 ++++++++++++
> src/pci.h | 7 ++++++
> src/qemu_driver.c | 54 ++++++++++++++++++++++++++++++++++++++++++---
> 4 files changed, 73 insertions(+), 4 deletions(-)
>
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index 642c2bc..23fa01b 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 6a2e860..619853b 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 15da057..d5e680c 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 bfa06a5..4b1aeea 100644
> --- a/src/qemu_driver.c
> +++ b/src/qemu_driver.c
> @@ -1330,6 +1330,48 @@ static int qemudNextFreeVNCPort(struct qemud_driver *driver ATTRIBUTE_UNUSED) {
> }
>
> 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;
> @@ -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;
> }
ACK
Daniel
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
More information about the libvir-list
mailing list