[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