The batch notification BH needs to know which virtqueues to notify when multiqueue is enabled. Use a bitmap to track the virtqueues with pending notifications.
At this point there is only one virtqueue so hard-code virtqueue index 0. A later patch will switch to real virtqueue indices. Signed-off-by: Stefan Hajnoczi <stefa...@redhat.com> --- hw/block/dataplane/virtio-blk.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index 3cb97c9..4439c7b 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -34,8 +34,8 @@ struct VirtIOBlockDataPlane { VirtIODevice *vdev; VirtQueue *vq; /* virtqueue vring */ - EventNotifier *guest_notifier; /* irq */ QEMUBH *bh; /* bh for guest notification */ + unsigned long *batch_notify_vqs; Notifier insert_notifier, remove_notifier; @@ -54,18 +54,34 @@ struct VirtIOBlockDataPlane { /* Raise an interrupt to signal guest, if necessary */ void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s) { + set_bit(0, s->batch_notify_vqs); qemu_bh_schedule(s->bh); } static void notify_guest_bh(void *opaque) { VirtIOBlockDataPlane *s = opaque; + unsigned nvqs = s->conf->num_queues; + unsigned long bitmap[BITS_TO_LONGS(nvqs)]; + unsigned j; - if (!virtio_should_notify(s->vdev, s->vq)) { - return; + memcpy(bitmap, s->batch_notify_vqs, sizeof(bitmap)); + memset(s->batch_notify_vqs, 0, sizeof(bitmap)); + + for (j = 0; j < nvqs; j += BITS_PER_LONG) { + unsigned long bits = bitmap[j]; + + while (bits != 0) { + unsigned i = j + ctzl(bits); + VirtQueue *vq = virtio_get_queue(s->vdev, i); + + if (virtio_should_notify(s->vdev, vq)) { + event_notifier_set(virtio_queue_get_guest_notifier(vq)); + } + + bits &= bits - 1; /* clear right-most bit */ + } } - - event_notifier_set(s->guest_notifier); } static void data_plane_set_up_op_blockers(VirtIOBlockDataPlane *s) @@ -157,6 +173,7 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf, } s->ctx = iothread_get_aio_context(s->iothread); s->bh = aio_bh_new(s->ctx, notify_guest_bh, s); + s->batch_notify_vqs = bitmap_new(conf->num_queues); s->insert_notifier.notify = data_plane_blk_insert_notifier; s->remove_notifier.notify = data_plane_blk_remove_notifier; @@ -179,6 +196,7 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s) data_plane_remove_op_blockers(s); notifier_remove(&s->insert_notifier); notifier_remove(&s->remove_notifier); + g_free(s->batch_notify_vqs); qemu_bh_delete(s->bh); object_unref(OBJECT(s->iothread)); g_free(s); @@ -217,7 +235,6 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) "ensure -enable-kvm is set\n", r); goto fail_guest_notifiers; } - s->guest_notifier = virtio_queue_get_guest_notifier(s->vq); /* Set up virtqueue notify */ r = k->set_host_notifier(qbus->parent, 0, true); -- 2.5.5