Re: [PATCH] qemu-kvm: fix crash on reboot with vhost-net

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

 



"Michael S. Tsirkin" <mst@xxxxxxxxxx> wrote:
> When vhost-net is disabled on reboot, we set msix mask notifier
> to NULL to disable further mask/unmask notifications.
> Code currently tries to pass this NULL to notifier,
> leading to a crash.  The right thing to do is:
> - if vector is masked, we don't need to notify backend,
>   just disable future notifications
> - if vector is unmasked, invoke callback to unassign backend,
>   then disable future notifications
>
> Signed-off-by: Michael S. Tsirkin <mst@xxxxxxxxxx>

I don't fully understand this.

> diff --git a/hw/msix.c b/hw/msix.c
> index 3ec8805..43361b5 100644
> --- a/hw/msix.c
> +++ b/hw/msix.c
> @@ -613,9 +613,18 @@ int msix_set_mask_notifier(PCIDevice *dev, unsigned vector, void *opaque)

we have a msix_set_mask_notifier() function that, low and behold, we
also use it to unmask the notifier, just passing a NULL opaque.

I can live with this (althought I would preffer two functions)

>      if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector])
>          return 0;
>  
> -    if (dev->msix_mask_notifier)
> -        r = dev->msix_mask_notifier(dev, vector, opaque,
> -                                    msix_is_masked(dev, vector));
> +    if (dev->msix_mask_notifier && !msix_is_masked(dev, vector)) {

Now things got interesting.  We check if device has a mask notifier, and
if that vector is not masked (notice the _not_ part)

> +        /* Switching notifiers while vector is unmasked:
> +         * mask the old one, unmask the new one. */
> +        if (dev->msix_mask_notifier_opaque[vector]) {

ha ha ha, but it has a mask!

> +            r = dev->msix_mask_notifier(dev, vector,
> +                                        dev->msix_mask_notifier_opaque[vector],
> +                                        1);

No problem, we _mask_ it.

(from pci.h)
typedef int (*msix_mask_notifier_func)(PCIDevice *, unsigned vector,
				       void *opaque, int masked);

(notice that we called masked = 1)

There is only one user of msix_mask_notifier(), we look at it.

it is virtio_pci_mask_notifier()

    int r = kvm_set_irqfd(dev->msix_irq_entries[vector].gsi,
                          event_notifier_get_fd(notifier),
                          !masked);

Notice the interesting !masked part, kvm_set_irqfd() and
msix_mask_notifier() use inverse logic.

Go along:

    if (masked) {
        qemu_set_fd_handler(event_notifier_get_fd(notifier),
                            virtio_pci_guest_notifier_read, NULL, vq);
    } else {
        qemu_set_fd_handler(event_notifier_get_fd(notifier),
                            NULL, NULL, NULL);
    }

masked = 1, so we are assigning that event notifier with this vq
(vq is the opaque that we just passed, that is our
dev->msix_mask_notifier_opaque[vector], that is the one that we want to
get rid of.  Assigning it to one fd handler looks suspcious at least.
it seems that what we really want is the other branch of the if
(i.e. just disable that fd handler).

> +        }
> +        if (r >= 0 && opaque) {
> +            r = dev->msix_mask_notifier(dev, vector, opaque, 0);
> +        }

now, if we are _not_ unmasking the notifier, we just enabled it again.
humm, actually, we unmasked it again.  But remember the inverse logic
all around, here mask == 0, i.e. we are disabling the handler.  at this
point I would have though that we wanted to "enable" it.

> +    }
>      if (r >= 0)
>          dev->msix_mask_notifier_opaque[vector] = opaque;
>      return r;

Here, we assign the notifier opaque only if there hasn't been an error.
I am not fully sure that this is fully correct, because if 1st call to
msix_mask_notifier() success and second fails, I gess that a NULL value
is better than the old value.

But all of this is supposing that I haven't lost track at this point of
what is masked/unmasked :(

I think that at least the if(masked) branches in
virtio_pci_mask_notifier() needs to be changed.

Later, Juan.
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux