virtio: don't waste irqfds on control vqs
PATCH v2 1/1 virtio: don't waste irqfds on control vqs
Pass nvqs to set_guest_notifiers. This makes it possible to save on irqfds by not allocating one for the control vq for virtio-net.
Signed-off-by Michael S. Tsirkin <[email protected]>
---
Changes from v1:
- fix poll implementation to not use uninitialized notifiers
- verify correct API usage by checking same nvqs is passed on assign/deassign
hw/vhost.c | 10 +++++++--- hw/virtio-pci.c | 15 ++++++++++++--- hw/virtio-pci.h | 1 + hw/virtio.h | 2 +- 4 files changed, 21 insertions(+), 7 deletions(-)
hw/vhost.c +7 -3
@@ -879,7 +879,9 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev) goto fail; } - r = vdev->binding->set_guest_notifiers (vdev->binding_opaque, true); + r = vdev->binding->set_guest_notifiers (vdev->binding_opaque, + hdev->nvqs, + true);if (r <0 ) {fprintf (stderr,"Error binding guest notifier: %d\n" , -r); goto fail_notifiers;
@@ -929,7 +931,7 @@ fail_vq: } fail_mem: fail_features: - vdev->binding->set_guest_notifiers (vdev->binding_opaque, false); + vdev->binding->set_guest_notifiers (vdev->binding_opaque, hdev->nvqs, false); fail_notifiers: fail:return r;
@@ -950,7 +952,9 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)vhost_sync_dirty_bitmap (hdev, &hdev->mem_sections[i],0 , (hwaddr )~0x0ull ); } - r = vdev->binding->set_guest_notifiers (vdev->binding_opaque, false); + r = vdev->binding->set_guest_notifiers (vdev->binding_opaque, + hdev->nvqs, + false);if (r <0 ) {fprintf (stderr,"vhost guest notifier cleanup failed: %d\n" , r);fflush (stderr);
hw/virtio-pci.c +12 -3
@@ -587,7 +587,7 @@ static void kvm_virtio_pci_vector_poll(PCIDevice *dev,EventNotifier *notifier;VirtQueue *vq; -for (queue_no =0 ; queue_no <VIRTIO_PCI_QUEUE_MAX ; queue_no++) { +for (queue_no =0 ; queue_no < proxy->nvqs_with_notifiers; queue_no++) {if (!virtio_queue_get_num (vdev, queue_no)) {break ; }
@@ -631,7 +631,7 @@ static bool virtio_pci_query_guest_notifiers(DeviceState *d)return msix_enabled (&proxy->pci_dev); } -static int virtio_pci_set_guest_notifiers (DeviceState *d,bool assign) +static int virtio_pci_set_guest_notifiers (DeviceState *d,int nvqs,bool assign) {VirtIOPCIProxy *proxy =to_virtio_pci_proxy (d);VirtIODevice *vdev = proxy->vdev;
@@ -639,6 +639,13 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, bool assign)bool with_irqfd =msix_enabled (&proxy->pci_dev) &&kvm_msi_via_irqfd_enabled (); + nvqs =MIN (nvqs,VIRTIO_PCI_QUEUE_MAX ); + +/* When deassigning, pass a consistent nvqs value +* to avoid leaking notifiers. +*/ +assert (assign || nvqs == proxy->nvqs_with_notifiers); +/* Must unset vector notifier while guest notifier is still assigned */ if (with_irqfd && !assign) {msix_unset_vector_notifiers (&proxy->pci_dev);
@@ -646,7 +653,7 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, bool assign) proxy->vector_irqfd =NULL ; } -for (n =0 ; n <VIRTIO_PCI_QUEUE_MAX ; n++) { +for (n =0 ; n < nvqs; n++) {if (!virtio_queue_get_num (vdev, n)) {break ; }
@@ -672,6 +679,8 @@ static int virtio_pci_set_guest_notifiers(DeviceState *d, bool assign) } } + proxy->nvqs_with_notifiers = nvqs; +return 0 ; assign_error:
hw/virtio-pci.h +1 -0
@@ -51,6 +51,7 @@ typedef struct {bool ioeventfd_disabled;bool ioeventfd_started;VirtIOIRQFD *vector_irqfd; +int nvqs_with_notifiers; } VirtIOPCIProxy;void virtio_init_pci (VirtIOPCIProxy *proxy,VirtIODevice *vdev);
hw/virtio.h +1 -1
@@ -99,7 +99,7 @@ typedef struct {int (*load_done)(DeviceState *d,QEMUFile *f);unsigned (*get_features)(DeviceState *d);bool (*query_guest_notifiers)(DeviceState *d); -int (*set_guest_notifiers)(DeviceState *d,bool assigned); +int (*set_guest_notifiers)(DeviceState *d,int nvqs,bool assigned);int (*set_host_notifier)(DeviceState *d,int n,bool assigned);void (*vmstate_change)(DeviceState *d,bool running); } VirtIOBindings;
Signature · 1 line
MST