[libvirt] [PATCH 1/7] hostdev: Add reattachPCIDevices()

Daniel P. Berrange berrange at redhat.com
Fri Jan 22 15:00:33 UTC 2016


On Tue, Jan 19, 2016 at 04:36:03PM +0100, Andrea Bolognani wrote:
> This function replaces virHostdevReattachPCIDevice() and handles several
> PCI devices instead of requiring to be called once for every device.
> 
> The handling of active and inactive devices is updated and made more
> explicit, which means virHostdevReAttachPCIDevices() has to be updated
> as well.
> ---
>  src/util/virhostdev.c | 170 ++++++++++++++++++++++++++++++--------------------
>  1 file changed, 103 insertions(+), 67 deletions(-)
> 
> diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c
> index f31ad41..0f258a5 100644
> --- a/src/util/virhostdev.c
> +++ b/src/util/virhostdev.c
> @@ -526,6 +526,73 @@ virHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev,
>      return ret;
>  }
>  
> +/**
> + * reattachPCIDevices:
> + * @mgr: hostdev manager
> + * @pcidevs: PCI devices to be reattached
> + * @skipUnmanaged: whether to skip unmanaged devices
> + *
> + * Reattach PCI devices to the host.
> + *
> + * All devices in @pcidevs must have already been marked as inactive, and
> + * the PCI related parts of @mgr (inactivePCIHostdevs, activePCIHostdevs)
> + * must have been locked beforehand using virObjectLock().
> + *
> + * Returns: 0 on success, <0 on failure
> + */
> +static int
> +reattachPCIDevices(virHostdevManagerPtr mgr,
> +                   virPCIDeviceListPtr pcidevs,
> +                   bool skipUnmanaged)
> +{
> +    size_t i;
> +    int ret = -1;
> +
> +    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
> +        virPCIDevicePtr tmp = virPCIDeviceListGet(pcidevs, i);
> +        virPCIDevicePtr dev;
> +
> +        /* Retrieve the actual device from the inactive list */
> +        if (!(dev = virPCIDeviceListFind(mgr->inactivePCIHostdevs, tmp))) {
> +            VIR_DEBUG("PCI device %s is not marked as inactive",
> +                      virPCIDeviceGetName(tmp));
> +            goto out;
> +        }
> +
> +        /* Skip unmanaged devices if asked to do so */
> +        if (!virPCIDeviceGetManaged(dev) && skipUnmanaged) {
> +            VIR_DEBUG("Not reattaching unmanaged PCI device %s",
> +                      virPCIDeviceGetName(dev));
> +            continue;
> +        }
> +
> +        /* Wait for device cleanup if it is qemu/kvm */
> +        if (virPCIDeviceGetStubDriver(dev) == VIR_PCI_STUB_DRIVER_KVM) {
> +            int retries = 100;
> +            while (virPCIDeviceWaitForCleanup(dev, "kvm_assigned_device")
> +                   && retries) {
> +                usleep(100*1000);
> +                retries--;
> +            }
> +        }
> +
> +        VIR_DEBUG("Reattaching PCI device %s", virPCIDeviceGetName(dev));
> +        if (virPCIDeviceReattach(dev, mgr->activePCIHostdevs,
> +                                 mgr->inactivePCIHostdevs) < 0) {
> +            virErrorPtr err = virGetLastError();
> +            VIR_ERROR(_("Failed to reattach PCI device: %s"),
> +                      err ? err->message : _("unknown error"));
> +            virResetError(err);
> +            goto out;
> +        }
> +    }
> +
> +    ret = 0;
> +
> + out:
> +    return ret;
> +}

IMHO you should leave virHostdevReattachPCIDevice alone, and just make
this new method call that one. In later patches you are calling this
reattachPCIDevices() method with a single device, forcing you to put
it into a temporary virPCIDeviceListPtr before calling it. If you keep
virHostdevReattachPCIDevice then you can call it directly and avoid
creating temporary lists.

> +
>  int
>  virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
>                              const char *drv_name,
> @@ -753,45 +820,6 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
>      return ret;
>  }
>  
> -/*
> - * Pre-condition: inactivePCIHostdevs & activePCIHostdevs
> - * are locked
> - */
> -static void
> -virHostdevReattachPCIDevice(virPCIDevicePtr dev, virHostdevManagerPtr mgr)
> -{
> -    /* If the device is not managed and was attached to guest
> -     * successfully, it must have been inactive.
> -     */
> -    if (!virPCIDeviceGetManaged(dev)) {
> -        VIR_DEBUG("Adding unmanaged PCI device %s to inactive list",
> -                  virPCIDeviceGetName(dev));
> -        if (virPCIDeviceListAdd(mgr->inactivePCIHostdevs, dev) < 0)
> -            virPCIDeviceFree(dev);
> -        return;
> -    }
> -
> -    /* Wait for device cleanup if it is qemu/kvm */
> -    if (virPCIDeviceGetStubDriver(dev) == VIR_PCI_STUB_DRIVER_KVM) {
> -        int retries = 100;
> -        while (virPCIDeviceWaitForCleanup(dev, "kvm_assigned_device")
> -               && retries) {
> -            usleep(100*1000);
> -            retries--;
> -        }
> -    }
> -
> -    VIR_DEBUG("Reattaching PCI device %s", virPCIDeviceGetName(dev));
> -    if (virPCIDeviceReattach(dev, mgr->activePCIHostdevs,
> -                             mgr->inactivePCIHostdevs) < 0) {
> -        virErrorPtr err = virGetLastError();
> -        VIR_ERROR(_("Failed to re-attach PCI device: %s"),
> -                  err ? err->message : _("unknown error"));
> -        virResetError(err);
> -    }
> -    virPCIDeviceFree(dev);
> -}
> -
>  /* @oldStateDir:
>   * For upgrade purpose: see virHostdevNetConfigRestore
>   */
> @@ -803,7 +831,7 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
>                               int nhostdevs,
>                               const char *oldStateDir)
>  {
> -    virPCIDeviceListPtr pcidevs;
> +    virPCIDeviceListPtr pcidevs = NULL;
>      size_t i;
>  
>      if (!nhostdevs)
> @@ -822,16 +850,11 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
>          goto cleanup;
>      }
>  
> -    /* Loop through the assigned devices 4 times: 1) delete them all from
> -     * activePCIHostdevs, 2) restore network config of SRIOV netdevs, 3) Do a
> -     * PCI reset on each device, 4) reattach the devices to their host drivers
> -     * (managed) or add them to inactivePCIHostdevs (!managed).
> -     */
> +    /* Reattaching devices to the host involves several steps; each of them
> +     * is described at length below */
>  
> -    /*
> -     * Loop 1: verify that each device in the hostdevs list really was in use
> -     * by this domain, and remove them all from the activePCIHostdevs list.
> -     */
> +    /* Step 1: verify that each device in the hostdevs list really was in use
> +     *         by this domain */
>      i = 0;
>      while (i < virPCIDeviceListCount(pcidevs)) {
>          virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
> @@ -848,21 +871,32 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
>                      continue;
>                  }
>          }
> +        i++;
> +    }
> +
> +    /* Step 2: move all devices from the active list to the inactive list */
> +    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
> +        virPCIDevicePtr tmp = virPCIDeviceListGet(pcidevs, i);
> +        virPCIDevicePtr dev;
>  
>          VIR_DEBUG("Removing PCI device %s from active list",
> +                  virPCIDeviceGetName(tmp));
> +        if (!(dev = virPCIDeviceListSteal(hostdev_mgr->activePCIHostdevs,
> +                                          tmp)))
> +            goto cleanup;
> +
> +        VIR_DEBUG("Adding PCI device %s to inactive list",
>                    virPCIDeviceGetName(dev));
> -        virPCIDeviceListDel(hostdev_mgr->activePCIHostdevs, dev);
> -        i++;
> +        if (virPCIDeviceListAdd(hostdev_mgr->inactivePCIHostdevs,
> +                                dev) < 0)
> +            goto cleanup;
>      }
>  
> -    /* At this point, any device that had been used by the guest is in
> -     * pcidevs, but has been removed from activePCIHostdevs.
> -     */
> +    /* At this point, devices are no longer marked as active and have been
> +     * marked as inactive instead */
>  
> -    /*
> -     * Loop 2: restore original network config of hostdevs that used
> -     * <interface type='hostdev'>
> -     */
> +    /* Step 3: restore original network config of hostdevs that used
> +     *         <interface type='hostdev'> */
>      for (i = 0; i < nhostdevs; i++) {
>          virDomainHostdevDefPtr hostdev = hostdevs[i];
>  
> @@ -883,7 +917,7 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
>          }
>      }
>  
> -    /* Loop 3: perform a PCI Reset on all devices */
> +    /* Step 4: perform a PCI Reset on all devices */
>      for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
>          virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
>


I'm inclined to say that all the changes above this point should
have been a separate commit from the commit that introduces the
reattachPCIDevices method, as this is really mixing 2 sets of
unrelated changes in one commit.

> @@ -897,16 +931,18 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
>          }
>      }
>  
> -    /* Loop 4: reattach devices to their host drivers (if managed) or place
> -     * them on the inactive list (if not managed)
> -     */
> -    while (virPCIDeviceListCount(pcidevs) > 0) {
> -        virPCIDevicePtr dev = virPCIDeviceListStealIndex(pcidevs, 0);
> -        virHostdevReattachPCIDevice(dev, hostdev_mgr);
> -    }
> +    /* Step 5: reattach managed devices to their host drivers; unmanaged
> +     *         devices need no further processing. reattachPCIDevices() will
> +     *         remove devices from the inactive list as they are reattached
> +     *         to the host */
> +    ignore_value(reattachPCIDevices(hostdev_mgr, pcidevs, true));
> +
> +    /* At this point, all devices are either marked as inactive (if they
> +     * were unmanaged), or have been reattached to the host driver (if they
> +     * were managed) and are no longer tracked by any of our device lists */
>  
> -    virObjectUnref(pcidevs);
>   cleanup:
> +    virObjectUnref(pcidevs);
>      virObjectUnlock(hostdev_mgr->activePCIHostdevs);
>      virObjectUnlock(hostdev_mgr->inactivePCIHostdevs);
>  }

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|




More information about the libvir-list mailing list