Re: [PATCH 1/4] qemu: prevent unnecessarily failing live interface update

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 9/18/24 17:26, Laine Stump wrote:
> Attempts to use update-device to modify just the link state of a guest
> interface were failing due to a supposed attempt to modify something
> in the interface that can't be modified live (even though the only
> thing that was changing was the link state, which *can* be modified
> live).
> 
> It turned out that this failure happened because the guest interface
> in question was type='network', and the network in question was a
> 'direct' network that provides each guest interface with one device
> from a pool of network devices. As a part of qemuDomainChangeNet() we
> would always allocate a new port from the network driver for the
> updated interface definition (by way of calling
> virDomainNetAllocateActualDevice(newdev)), and this new port (ie the
> ActualNetDef in newdev) would of course be allocated a new host device
> from the pool (which would of course be different from the one
> currently in use by the guest interface (in olddev)). Because direct
> interfaces don't support changing the host device in a live update,
> this would cause the update to fail.
> 
> The solution to this is to realize that as long as the interface
> doesn't get switched to a different network as a part of the update,
> the network port information (ie the ActualNetDef) will not change as
> a part of updating the guest interface itself. So for sake of
> comparison we can just point the newdev at the ActualNetDef of olddev,
> and then clear out one or the other when we're done (to avoid a double
> free or, more likely, attempt to reference freed memory).
> 
> (If, on the other hand, the name of the network has changed, or if the
> interface type has changed to type='network' from something else, then
> we *do* need to allocate a new port (actual device) from the network
> driver (as we used to do in all cases when the new type was
> 'network'), and also indicate that we'll need to replace olddev in the
> domain with newdev (because either of these changes is major enough
> that we shouldn't just try to fix up olddev)
> 
> Resolves: https://issues.redhat.com/browse/RHEL-7036
> Signed-off-by: Laine Stump <laine@xxxxxxxxxx>
> ---
>  src/qemu/qemu_hotplug.c | 92 +++++++++++++++++++++++++++++++++++------
>  1 file changed, 80 insertions(+), 12 deletions(-)
> 
> diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
> index 75b97cf736..a187466c5b 100644
> --- a/src/qemu/qemu_hotplug.c
> +++ b/src/qemu/qemu_hotplug.c
> @@ -3675,6 +3675,7 @@ qemuDomainChangeNet(virQEMUDriver *driver,
>      virDomainNetDef **devslot = NULL;
>      virDomainNetDef *olddev;
>      virDomainNetType oldType, newType;
> +    bool actualSame = false;
>      bool needReconnect = false;
>      bool needBridgeChange = false;
>      bool needFilterChange = false;
> @@ -3895,15 +3896,49 @@ qemuDomainChangeNet(virQEMUDriver *driver,
>       * free it if we fail for any reason
>       */
>      if (newdev->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
> -        if (!(conn = virGetConnectNetwork()))
> -            goto cleanup;
> -        if (virDomainNetAllocateActualDevice(conn, vm->def, newdev) < 0)
> -            goto cleanup;
> -    }
> +        if (olddev->type == VIR_DOMAIN_NET_TYPE_NETWORK
> +            && STREQ(olddev->data.network.name, newdev->data.network.name)) {
> +            /* old and new are type='network', and the network name
> +             * hasn't changed. In this case we *don't* want to get a
> +             * new port ("actual device") from the network because we
> +             * can use the old one (since it hasn't changed).
> +             *
> +             * So instead we just duplicate *the pointer to* the
> +             * actualNetDef from olddev to newdev so that comparisons
> +             * of actualNetDef will show no change. If the update is
> +             * successful, we will clear the actualNetDef pointer from
> +             * olddev before destroying it (or if the update fails,
> +             * then we need to clear the pointer from newdev before
> +             * destroying it)
> +             */
> +            newdev->data.network.actual = olddev->data.network.actual;
> +            memcpy(newdev->data.network.portid, olddev->data.network.portid,
> +                   sizeof(newdev->data.network.portid));

I thought we had a function that copies over .actual, but apparently I
remembered it wrong.

> +            actualSame = true; /* old and new actual are pointing to same object */
> +        } else {
> +            /* either the olddev wasn't type='network', or else the
> +             * name of the network changed. In this case we *do* want
> +             * to get a new port from the new network (because we know
> +             * that it *will* change), and then if the update is
> +             * successful, we will release the port ("actual device")
> +             * in olddev. Or if the update is a failure, we will
> +             * release this new port
> +             */
> +            if (!(conn = virGetConnectNetwork())
> +                || virDomainNetAllocateActualDevice(conn, vm->def, newdev) < 0) {

nitpick, The or operator should go onto the previous line.

> +                goto cleanup;
> +            }
>  

Michal



[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]

  Powered by Linux