[libvirt] [PATCH] hostdev: fix net config restore error

John Ferlan jferlan at redhat.com
Wed Apr 22 12:02:34 UTC 2015



On 04/15/2015 01:29 PM, Huanle Han wrote:
> Fix for such a case:
> 1. Domain A and B xml contain the same SRIOV net hostdev(<interface
> type='hostdev' /> with same pci address).
> 2. virsh start A (Successfully, and configure the SRIOV net with
> custom mac)
> 3. virsh start B (Fail because of the hostdev used by domain A or other
> reason.)
> In step 3, 'virHostdevNetConfigRestore' is called for the hostdev
> which is still used by domain A. It makes the mac/vlan of the SRIOV net
> change.
> 
> Code Change in this fix:
> 1. As the pci used by other domain have been removed from
> 'pcidevs' in previous loop, we only restore the nic config for
> the hostdev still in 'pcidevs'(used by this domain)
> 2. wrap a function 'virHostdevIsPCINetDevice', which detect whether the
> hostdev is a pci net device or not.
> 3. update the comments to make it more clear
> 
> Signed-off-by: Huanle Han <hanxueluo at gmail.com>
> ---
>  src/util/virhostdev.c | 70 ++++++++++++++++++++++++++++++++++-----------------
>  1 file changed, 47 insertions(+), 23 deletions(-)
> 

This seems reasonable - although it should have been two patches - the
first just to create virHostdevIsPCINetDevice and the second to fix the
issue and update the comments...  Something I can take care of for you
before pushing...

Hopefully Laine can also take a quick look at it and verify the actions
since he's most familiar with the SRIOV code path...

John
> diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c
> index f583e54..a2719d3 100644
> --- a/src/util/virhostdev.c
> +++ b/src/util/virhostdev.c
> @@ -350,6 +350,14 @@ virHostdevNetDevice(virDomainHostdevDefPtr hostdev, char **linkdev,
>      return ret;
>  }
>  
> +static int
> +virHostdevIsPCINetDevice(virDomainHostdevDefPtr hostdev)
> +{
> +    return hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
> +        hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
> +        hostdev->parent.type == VIR_DOMAIN_DEVICE_NET &&
> +        hostdev->parent.data.net;
> +}
>  
>  static int
>  virHostdevNetConfigVirtPortProfile(const char *linkdev, int vf,
> @@ -481,10 +489,7 @@ virHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev,
>      /* This is only needed for PCI devices that have been defined
>       * using <interface type='hostdev'>. For all others, it is a NOP.
>       */
> -    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
> -        hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI ||
> -        hostdev->parent.type != VIR_DOMAIN_DEVICE_NET ||
> -        !hostdev->parent.data.net)
> +    if (!virHostdevIsPCINetDevice(hostdev))
>         return 0;
>  
>      isvf = virHostdevIsVirtualFunction(hostdev);
> @@ -604,16 +609,11 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
>       * the network device, set the netdev config */
>      for (i = 0; i < nhostdevs; i++) {
>           virDomainHostdevDefPtr hostdev = hostdevs[i];
> -         if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
> +         if (!virHostdevIsPCINetDevice(hostdev))
>               continue;
> -         if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
> -             continue;
> -         if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET &&
> -             hostdev->parent.data.net) {
> -             if (virHostdevNetConfigReplace(hostdev, uuid,
> -                                            hostdev_mgr->stateDir) < 0) {
> -                 goto resetvfnetconfig;
> -             }
> +         if (virHostdevNetConfigReplace(hostdev, uuid,
> +                                        hostdev_mgr->stateDir) < 0) {
> +             goto resetvfnetconfig;
>           }
>           last_processed_hostdev_vf = i;
>      }
> @@ -781,19 +781,20 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
>          goto cleanup;
>      }
>  
> -    /* Again 4 loops; mark all devices as inactive before reset
> +    /* Here are 4 loops; mark all devices as inactive before reset
>       * them and reset all the devices before re-attach.
>       * Attach mac and port profile parameters to devices
>       */
> +
> +    /* Loop 1: delete the copy of the dev from pcidevs if it's used by
> +     * other domain. Or delete it from activePCIHostDevs if it had
> +     * been used by this domain.
> +     */
>      i = 0;
>      while (i < virPCIDeviceListCount(pcidevs)) {
>          virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
>          virPCIDevicePtr activeDev = NULL;
>  
> -        /* delete the copy of the dev from pcidevs if it's used by
> -         * other domain. Or delete it from activePCIHostDevs if it had
> -         * been used by this domain.
> -         */
>          activeDev = virPCIDeviceListFind(hostdev_mgr->activePCIHostdevs, dev);
>          if (activeDev) {
>              const char *usedby_drvname;
> @@ -815,13 +816,33 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
>       */
>  
>      /*
> -     * For SRIOV net host devices, unset mac and port profile before
> -     * reset and reattach device
> +     * Loop 2: For SRIOV net host devices used by this domain, unset mac and port profile before
> +     * resetting and reattaching device
>       */
> -    for (i = 0; i < nhostdevs; i++)
> -        virHostdevNetConfigRestore(hostdevs[i], hostdev_mgr->stateDir,
> -                                   oldStateDir);
> +    for (i = 0; i < nhostdevs; i++) {
> +        virDomainHostdevDefPtr hostdev = hostdevs[i];
>  
> +        if (virHostdevIsPCINetDevice(hostdev)) {
> +            virDomainHostdevSubsysPCIPtr pcisrc = &hostdev->source.subsys.u.pci;
> +            virPCIDevicePtr dev = NULL;
> +            dev = virPCIDeviceNew(pcisrc->addr.domain, pcisrc->addr.bus,
> +                                  pcisrc->addr.slot, pcisrc->addr.function);
> +            if (dev) {
> +                if (virPCIDeviceListFind(pcidevs, dev)) {
> +                    virHostdevNetConfigRestore(hostdev, hostdev_mgr->stateDir,
> +                                               oldStateDir);
> +                }
> +            } else {
> +                virErrorPtr err = virGetLastError();
> +                VIR_ERROR(_("Failed to new PCI device: %s"),
> +                          err ? err->message : _("unknown error"));
> +                virResetError(err);
> +            }
> +            virPCIDeviceFree(dev);
> +        }
> +    }
> +
> +    /* Loop 3: reset pci device used by this domain */
>      for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
>          virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
>  
> @@ -834,6 +855,9 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
>          }
>      }
>  
> +    /* Loop 4: reattach pci devices used by this domain
> +     * and steal all the devices from pcidevs
> +     */
>      while (virPCIDeviceListCount(pcidevs) > 0) {
>          virPCIDevicePtr dev = virPCIDeviceListStealIndex(pcidevs, 0);
>          virHostdevReattachPCIDevice(dev, hostdev_mgr);
> 




More information about the libvir-list mailing list