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 :| -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list