From fcccb271e0894bc04078ababb29d3d5e06b79892 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 5 Nov 2019 15:09:46 +0100 Subject: virtio: notify virtqueue via host notifier when available Host notifiers are used in several cases: 1. Traditional ioeventfd where virtqueue notifications are handled in the main loop thread. 2. IOThreads (aio_handle_output) where virtqueue notifications are handled in an IOThread AioContext. 3. vhost where virtqueue notifications are handled by kernel vhost or a vhost-user device backend. Most virtqueue notifications from the guest use the ioeventfd mechanism, but there are corner cases where QEMU code calls virtio_queue_notify(). This currently honors the host notifier for the IOThreads aio_handle_output case, but not for the vhost case. The result is that vhost does not receive virtqueue notifications from QEMU when virtio_queue_notify() is called. This patch extends virtio_queue_notify() to set the host notifier whenever it is enabled instead of calling the vq->(aio_)handle_output() function directly. We track the host notifier state for each virtqueue separately since some devices may use it only for certain virtqueues. This fixes the vhost case although it does add a trip through the eventfd for the traditional ioeventfd case. I don't think it's worth adding a fast path for the traditional ioeventfd case because calling virtio_queue_notify() is rare when ioeventfd is enabled. Reported-by: Felipe Franciosi Signed-off-by: Stefan Hajnoczi Message-Id: <20191105140946.165584-1-stefanha@redhat.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-bus.c | 4 ++++ hw/virtio/virtio.c | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'hw') diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c index b2c8042..d6332d4 100644 --- a/hw/virtio/virtio-bus.c +++ b/hw/virtio/virtio-bus.c @@ -288,6 +288,10 @@ int virtio_bus_set_host_notifier(VirtioBusState *bus, int n, bool assign) k->ioeventfd_assign(proxy, notifier, n, false); } + if (r == 0) { + virtio_queue_set_host_notifier_enabled(vq, assign); + } + return r; } diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 762df12..04716b5 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -128,6 +128,7 @@ struct VirtQueue VirtIODevice *vdev; EventNotifier guest_notifier; EventNotifier host_notifier; + bool host_notifier_enabled; QLIST_ENTRY(VirtQueue) node; }; @@ -2271,7 +2272,7 @@ void virtio_queue_notify(VirtIODevice *vdev, int n) } trace_virtio_queue_notify(vdev, vq - vdev->vq, vq); - if (vq->handle_aio_output) { + if (vq->host_notifier_enabled) { event_notifier_set(&vq->host_notifier); } else if (vq->handle_output) { vq->handle_output(vdev, vq); @@ -3145,6 +3146,7 @@ void virtio_init(VirtIODevice *vdev, const char *name, vdev->vq[i].vector = VIRTIO_NO_VECTOR; vdev->vq[i].vdev = vdev; vdev->vq[i].queue_index = i; + vdev->vq[i].host_notifier_enabled = false; } vdev->name = name; @@ -3436,6 +3438,11 @@ EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq) return &vq->host_notifier; } +void virtio_queue_set_host_notifier_enabled(VirtQueue *vq, bool enabled) +{ + vq->host_notifier_enabled = enabled; +} + int virtio_queue_set_host_notifier_mr(VirtIODevice *vdev, int n, MemoryRegion *mr, bool assign) { -- cgit v1.1