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;
 | 
					    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)
 | 
					static void ivshmem_remove_kvm_msi_virq(IVShmemState *s, int vector)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    IVSHMEM_DPRINTF("ivshmem_remove_kvm_msi_virq vector:%d\n", 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;
 | 
					    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)
 | 
					static void ivshmem_disable_irqfd(IVShmemState *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    PCIDevice *pdev = PCI_DEVICE(s);
 | 
					    PCIDevice *pdev = PCI_DEVICE(s);
 | 
				
			||||||
    int i;
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!pdev->msix_vector_use_notifier) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    msix_unset_vector_notifiers(pdev);
 | 
					    msix_unset_vector_notifiers(pdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < s->peers[s->vm_id].nb_eventfds; i++) {
 | 
					    for (i = 0; i < s->peers[s->vm_id].nb_eventfds; i++) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue