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>
This commit is contained in:
parent
089fd80376
commit
0b88dd9420
@ -785,29 +785,6 @@ static int ivshmem_setup_interrupts(IVShmemState *s, Error **errp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ivshmem_enable_irqfd(IVShmemState *s)
|
||||
{
|
||||
PCIDevice *pdev = PCI_DEVICE(s);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->peers[s->vm_id].nb_eventfds; i++) {
|
||||
Error *err = NULL;
|
||||
|
||||
ivshmem_add_kvm_msi_virq(s, i, &err);
|
||||
if (err) {
|
||||
error_report_err(err);
|
||||
/* TODO do we need to handle the error? */
|
||||
}
|
||||
}
|
||||
|
||||
if (msix_set_vector_notifiers(pdev,
|
||||
ivshmem_vector_unmask,
|
||||
ivshmem_vector_mask,
|
||||
ivshmem_vector_poll)) {
|
||||
error_report("ivshmem: msix_set_vector_notifiers failed");
|
||||
}
|
||||
}
|
||||
|
||||
static void ivshmem_remove_kvm_msi_virq(IVShmemState *s, int vector)
|
||||
{
|
||||
IVSHMEM_DPRINTF("ivshmem_remove_kvm_msi_virq vector:%d\n", vector);
|
||||
@ -822,11 +799,45 @@ static void ivshmem_remove_kvm_msi_virq(IVShmemState *s, int vector)
|
||||
s->msi_vectors[vector].pdev = NULL;
|
||||
}
|
||||
|
||||
static void ivshmem_enable_irqfd(IVShmemState *s)
|
||||
{
|
||||
PCIDevice *pdev = PCI_DEVICE(s);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->peers[s->vm_id].nb_eventfds; i++) {
|
||||
Error *err = NULL;
|
||||
|
||||
ivshmem_add_kvm_msi_virq(s, i, &err);
|
||||
if (err) {
|
||||
error_report_err(err);
|
||||
goto undo;
|
||||
}
|
||||
}
|
||||
|
||||
if (msix_set_vector_notifiers(pdev,
|
||||
ivshmem_vector_unmask,
|
||||
ivshmem_vector_mask,
|
||||
ivshmem_vector_poll)) {
|
||||
error_report("ivshmem: msix_set_vector_notifiers failed");
|
||||
goto undo;
|
||||
}
|
||||
return;
|
||||
|
||||
undo:
|
||||
while (--i >= 0) {
|
||||
ivshmem_remove_kvm_msi_virq(s, i);
|
||||
}
|
||||
}
|
||||
|
||||
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…
Reference in New Issue
Block a user