The data plane thread isn't allowed to call virtio_irq() directly because that function is not thread-safe. Use the guest notifier just like virtio-net to handle IRQs.
When MSI-X is in use and the vector is unmasked, the guest notifier directly sets the IRQ inside the host kernel. If the vector is masked, then QEMU's iothread needs to take note of the IRQ. If MSI-X is not in use, then QEMU's iothread handles the IRQ and this will be slower than synchronously calling notify_irq() from the data plane thread. --- hw/virtio-blk.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index d75c187..bdff68a 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -73,6 +73,18 @@ static int get_raw_posix_fd_hack(VirtIOBlock *s) return *(int*)s->bs->file->opaque; } +/* Raise an interrupt to signal guest, if necessary */ +static void virtio_blk_notify_guest(VirtIOBlock *s) +{ + /* Always notify when queue is empty (when feature acknowledge) */ + if ((s->vring.vr.avail->flags & VRING_AVAIL_F_NO_INTERRUPT) && + (s->vring.vr.avail->idx != s->vring.last_avail_idx || + !(s->vdev.guest_features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)))) + return; + + event_notifier_set(virtio_queue_get_guest_notifier(s->vq)); +} + static void complete_request(struct iocb *iocb, ssize_t ret, void *opaque) { VirtIOBlock *s = opaque; @@ -154,7 +166,7 @@ static void process_request(IOQueue *ioq, struct iovec iov[], unsigned int out_n fdatasync(get_raw_posix_fd_hack(s)); inhdr->status = VIRTIO_BLK_S_OK; vring_push(&s->vring, head, sizeof *inhdr); - virtio_irq(s->vq); + virtio_blk_notify_guest(s); } return; @@ -222,8 +234,7 @@ static bool handle_io(EventHandler *handler) VirtIOBlock *s = container_of(handler, VirtIOBlock, io_handler); if (ioq_run_completion(&s->ioqueue, complete_request, s) > 0) { - /* TODO is this thread-safe and can it be done faster? */ - virtio_irq(s->vq); + virtio_blk_notify_guest(s); } /* If there were more requests than iovecs, the vring will not be empty yet @@ -251,11 +262,17 @@ static void data_plane_start(VirtIOBlock *s) vring_setup(&s->vring, &s->vdev, 0); + /* Set up guest notifier (irq) */ + if (s->vdev.binding->set_guest_notifier(s->vdev.binding_opaque, 0, true) != 0) { + fprintf(stderr, "virtio-blk failed to set guest notifier, ensure -enable-kvm is set\n"); + exit(1); + } + event_poll_init(&s->event_poll); /* Set up virtqueue notify */ if (s->vdev.binding->set_host_notifier(s->vdev.binding_opaque, 0, true) != 0) { - fprintf(stderr, "virtio-blk failed to set host notifier, ensure -enable-kvm is set\n"); + fprintf(stderr, "virtio-blk failed to set host notifier\n"); exit(1); } event_poll_add(&s->event_poll, &s->notify_handler, @@ -296,6 +313,9 @@ static void data_plane_stop(VirtIOBlock *s) s->vdev.binding->set_host_notifier(s->vdev.binding_opaque, 0, false); event_poll_cleanup(&s->event_poll); + + /* Clean up guest notifier (irq) */ + s->vdev.binding->set_guest_notifier(s->vdev.binding_opaque, 0, false); } static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t val) -- 1.7.10.4