Browse Source

ivshmem: Improve MSI irqfd error handling

Adds a rollback path to ivshmem_enable_irqfd() and fixes
ivshmem_disable_irqfd() to bail if irqfd has not been enabled.

To reproduce, run:

  ivshmem-server -n 0

and QEMU with:

  -device ivshmem-doorbell,chardev=iv
  -chardev socket,path=/tmp/ivshmem_socket,id=iv

then load, unload, and load again the Windows driver, at the time of writing
available at:

https://github.com/virtio-win/kvm-guest-drivers-windows/tree/master/ivshmem

The issue is believed to have been masked by other guest drivers, notably
Linux ones, not enabling MSI-X on the device.

Signed-off-by: Ladi Prosek <lprosek@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20171211072110.9058-4-lprosek@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
pull/66/head
Ladi Prosek 9 years ago
committed by Paolo Bonzini
parent
commit
0b88dd9420
  1. 37
      hw/misc/ivshmem.c

37
hw/misc/ivshmem.c

@ -785,6 +785,20 @@ static int ivshmem_setup_interrupts(IVShmemState *s, Error **errp)
return 0;
}
static void ivshmem_remove_kvm_msi_virq(IVShmemState *s, int vector)
{
IVSHMEM_DPRINTF("ivshmem_remove_kvm_msi_virq vector:%d\n", vector);
if (s->msi_vectors[vector].pdev == NULL) {
return;
}
/* it was cleaned when masked in the frontend. */
kvm_irqchip_release_virq(kvm_state, s->msi_vectors[vector].virq);
s->msi_vectors[vector].pdev = NULL;
}
static void ivshmem_enable_irqfd(IVShmemState *s)
{
PCIDevice *pdev = PCI_DEVICE(s);
@ -796,7 +810,7 @@ static void ivshmem_enable_irqfd(IVShmemState *s)
ivshmem_add_kvm_msi_virq(s, i, &err);
if (err) {
error_report_err(err);
/* TODO do we need to handle the error? */
goto undo;
}
}
@ -805,21 +819,14 @@ static void ivshmem_enable_irqfd(IVShmemState *s)
ivshmem_vector_mask,
ivshmem_vector_poll)) {
error_report("ivshmem: msix_set_vector_notifiers failed");
goto undo;
}
}
return;
static void ivshmem_remove_kvm_msi_virq(IVShmemState *s, int vector)
{
IVSHMEM_DPRINTF("ivshmem_remove_kvm_msi_virq vector:%d\n", vector);
if (s->msi_vectors[vector].pdev == NULL) {
return;
undo:
while (--i >= 0) {
ivshmem_remove_kvm_msi_virq(s, i);
}
/* it was cleaned when masked in the frontend. */
kvm_irqchip_release_virq(kvm_state, s->msi_vectors[vector].virq);
s->msi_vectors[vector].pdev = NULL;
}
static void ivshmem_disable_irqfd(IVShmemState *s)
@ -827,6 +834,10 @@ static void ivshmem_disable_irqfd(IVShmemState *s)
PCIDevice *pdev = PCI_DEVICE(s);
int i;
if (!pdev->msix_vector_use_notifier) {
return;
}
msix_unset_vector_notifiers(pdev);
for (i = 0; i < s->peers[s->vm_id].nb_eventfds; i++) {

Loading…
Cancel
Save