From 17c42b1f6bc22c64e36b7172990ac65f00be173b Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 21 Jun 2016 11:02:11 +0100 Subject: [PATCH 1/9] Revert "virtio: sync the dataplane vring state to the virtqueue before virtio_save" This reverts commit 10a06fd65f667a972848ebbbcac11bdba931b544. Dataplane has used the same virtqueue code as non-dataplane since commits e24a47c5b73e04f94030e2daa356c7582aebfca2 ("virtio-scsi: do not use vring in dataplane") and 03de2f527499ae0c6d16a379665d072345254f2c ("virtio-blk: do not use vring in dataplane"). It is no longer necessary to stop dataplane in order to sync state since there is no duplicated virtqueue state. Signed-off-by: Stefan Hajnoczi Reviewed-by: Cornelia Huck Reviewed-by: Pavel Butsykin Message-id: 1466503331-9831-1-git-send-email-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/block/virtio-blk.c | 5 ----- hw/scsi/virtio-scsi.c | 5 ----- 2 files changed, 10 deletions(-) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 284e64667c..beb4e12049 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -795,11 +795,6 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status) static void virtio_blk_save(QEMUFile *f, void *opaque) { VirtIODevice *vdev = VIRTIO_DEVICE(opaque); - VirtIOBlock *s = VIRTIO_BLK(vdev); - - if (s->dataplane) { - virtio_blk_data_plane_stop(s->dataplane); - } virtio_save(vdev, f); } diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 71d09d3ef3..e8179d6616 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -666,11 +666,6 @@ static void virtio_scsi_reset(VirtIODevice *vdev) static void virtio_scsi_save(QEMUFile *f, void *opaque) { VirtIODevice *vdev = VIRTIO_DEVICE(opaque); - VirtIOSCSI *s = VIRTIO_SCSI(vdev); - - if (s->dataplane_started) { - virtio_scsi_dataplane_stop(s); - } virtio_save(vdev, f); } From 5fa78b2a1ca228255cb4a492ebf16cbb8d80c111 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 20 Jun 2016 20:36:57 +0100 Subject: [PATCH 2/9] dma-helpers: dma_blk_io() cancel support Attempting to cancel a dma_blk_io() request causes an abort(3): void bdrv_aio_cancel(BlockAIOCB *acb) { ... while (acb->refcnt > 1) { if (acb->aiocb_info->get_aio_context) { aio_poll(acb->aiocb_info->get_aio_context(acb), true); } else if (acb->bs) { aio_poll(bdrv_get_aio_context(acb->bs), true); } else { abort(); } } ... } This happens because DMAAIOCB->bs is NULL and dma_aiocb_info.get_aio_context() is also NULL. This patch trivially implements dma_aiocb_info.get_aio_context() by fetching the DMAAIOCB->ctx field. Signed-off-by: Stefan Hajnoczi Reviewed-by: Fam Zheng Message-id: 1466451417-27988-1-git-send-email-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- dma-helpers.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dma-helpers.c b/dma-helpers.c index b521d84ebd..9defc101b7 100644 --- a/dma-helpers.c +++ b/dma-helpers.c @@ -185,10 +185,17 @@ static void dma_aio_cancel(BlockAIOCB *acb) } } +static AioContext *dma_get_aio_context(BlockAIOCB *acb) +{ + DMAAIOCB *dbs = container_of(acb, DMAAIOCB, common); + + return dbs->ctx; +} static const AIOCBInfo dma_aiocb_info = { .aiocb_size = sizeof(DMAAIOCB), .cancel_async = dma_aio_cancel, + .get_aio_context = dma_get_aio_context, }; BlockAIOCB *dma_blk_io(AioContext *ctx, From 84419863f72f6b9ae1b4513fa73e28690f2d5458 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 21 Jun 2016 13:13:10 +0100 Subject: [PATCH 3/9] virtio-blk: add VirtIOBlockConf->num_queues The num_queues field is always 1 for the time being. A later patch will make it a configurable device property so that multiqueue can be enabled. Signed-off-by: Stefan Hajnoczi Reviewed-by: Fam Zheng Message-id: 1466511196-12612-2-git-send-email-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/block/virtio-blk.c | 1 + include/hw/virtio/virtio-blk.h | 1 + 2 files changed, 2 insertions(+) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index beb4e12049..4a3781a5f7 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -883,6 +883,7 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) s->rq = NULL; s->sector_mask = (s->conf.conf.logical_block_size / BDRV_SECTOR_SIZE) - 1; + conf->num_queues = 1; s->vq = virtio_add_queue(vdev, 128, virtio_blk_handle_output); virtio_blk_data_plane_create(vdev, conf, &s->dataplane, &err); if (err != NULL) { diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index 8f2b056515..9b03b6af2c 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -38,6 +38,7 @@ struct VirtIOBlkConf uint32_t scsi; uint32_t config_wce; uint32_t request_merging; + uint16_t num_queues; }; struct VirtIOBlockDataPlane; From e21737ab150c2742dd94089017db96c472dd4b87 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 21 Jun 2016 13:13:11 +0100 Subject: [PATCH 4/9] virtio-blk: multiqueue batch notify 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 Reviewed-by: Fam Zheng Message-id: 1466511196-12612-3-git-send-email-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- 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 2041b0400b..c20a195eb5 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; /* Note that these EventNotifiers are assigned by value. This is * fine as long as you do not call event_notifier_cleanup on them @@ -49,18 +49,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); } /* Context: QEMU global mutex held */ @@ -104,6 +120,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); *dataplane = s; } @@ -116,6 +133,7 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s) } virtio_blk_data_plane_stop(s); + g_free(s->batch_notify_vqs); qemu_bh_delete(s->bh); object_unref(OBJECT(s->iothread)); g_free(s); @@ -154,7 +172,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 = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), 0, true); From b234cdda958b329dbbec840702c65432f4907623 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 21 Jun 2016 13:13:12 +0100 Subject: [PATCH 5/9] virtio-blk: tell dataplane which vq to notify Let the virtio_blk_data_plane_notify() caller decide which virtqueue to notify. This will allow the function to be used with multiqueue. Signed-off-by: Stefan Hajnoczi Reviewed-by: Fam Zheng Message-id: 1466511196-12612-4-git-send-email-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/block/dataplane/virtio-blk.c | 4 ++-- hw/block/dataplane/virtio-blk.h | 2 +- hw/block/virtio-blk.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index c20a195eb5..835021b235 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -47,9 +47,9 @@ struct VirtIOBlockDataPlane { }; /* Raise an interrupt to signal guest, if necessary */ -void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s) +void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s, VirtQueue *vq) { - set_bit(0, s->batch_notify_vqs); + set_bit(virtio_get_queue_index(vq), s->batch_notify_vqs); qemu_bh_schedule(s->bh); } diff --git a/hw/block/dataplane/virtio-blk.h b/hw/block/dataplane/virtio-blk.h index 0714c11a2b..b1f0b95b32 100644 --- a/hw/block/dataplane/virtio-blk.h +++ b/hw/block/dataplane/virtio-blk.h @@ -26,6 +26,6 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s); void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s); void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s); void virtio_blk_data_plane_drain(VirtIOBlockDataPlane *s); -void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s); +void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s, VirtQueue *vq); #endif /* HW_DATAPLANE_VIRTIO_BLK_H */ diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 4a3781a5f7..bcce3df22d 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -55,7 +55,7 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status) stb_p(&req->in->status, status); virtqueue_push(s->vq, &req->elem, req->in_len); if (s->dataplane_started && !s->dataplane_disabled) { - virtio_blk_data_plane_notify(s->dataplane); + virtio_blk_data_plane_notify(s->dataplane, s->vq); } else { virtio_notify(vdev, s->vq); } From edaffd9f0baa32c9524ac8bc80370a7257aa322e Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 21 Jun 2016 13:13:13 +0100 Subject: [PATCH 6/9] virtio-blk: associate request with a virtqueue Multiqueue requires that each request knows to which virtqueue it belongs. Signed-off-by: Stefan Hajnoczi Reviewed-by: Fam Zheng Message-id: 1466511196-12612-5-git-send-email-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/block/virtio-blk.c | 20 +++++++++++--------- include/hw/virtio/virtio-blk.h | 4 +++- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index bcce3df22d..3c6a1fa4dd 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -29,9 +29,11 @@ #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-access.h" -void virtio_blk_init_request(VirtIOBlock *s, VirtIOBlockReq *req) +void virtio_blk_init_request(VirtIOBlock *s, VirtQueue *vq, + VirtIOBlockReq *req) { req->dev = s; + req->vq = vq; req->qiov.size = 0; req->in_len = 0; req->next = NULL; @@ -53,11 +55,11 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status) trace_virtio_blk_req_complete(req, status); stb_p(&req->in->status, status); - virtqueue_push(s->vq, &req->elem, req->in_len); + virtqueue_push(req->vq, &req->elem, req->in_len); if (s->dataplane_started && !s->dataplane_disabled) { - virtio_blk_data_plane_notify(s->dataplane, s->vq); + virtio_blk_data_plane_notify(s->dataplane, req->vq); } else { - virtio_notify(vdev, s->vq); + virtio_notify(vdev, req->vq); } } @@ -187,12 +189,12 @@ out: #endif -static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s) +static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s, VirtQueue *vq) { - VirtIOBlockReq *req = virtqueue_pop(s->vq, sizeof(VirtIOBlockReq)); + VirtIOBlockReq *req = virtqueue_pop(vq, sizeof(VirtIOBlockReq)); if (req) { - virtio_blk_init_request(s, req); + virtio_blk_init_request(s, vq, req); } return req; } @@ -583,7 +585,7 @@ void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq) blk_io_plug(s->blk); - while ((req = virtio_blk_get_request(s))) { + while ((req = virtio_blk_get_request(s, vq))) { virtio_blk_handle_request(req, &mrb); } @@ -831,7 +833,7 @@ static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f, while (qemu_get_sbyte(f)) { VirtIOBlockReq *req; req = qemu_get_virtqueue_element(f, sizeof(VirtIOBlockReq)); - virtio_blk_init_request(s, req); + virtio_blk_init_request(s, s->vq, req); req->next = s->rq; s->rq = req; } diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index 9b03b6af2c..a25b3447d7 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -63,6 +63,7 @@ typedef struct VirtIOBlockReq { VirtQueueElement elem; int64_t sector_num; VirtIOBlock *dev; + VirtQueue *vq; struct virtio_blk_inhdr *in; struct virtio_blk_outhdr out; QEMUIOVector qiov; @@ -80,7 +81,8 @@ typedef struct MultiReqBuffer { bool is_write; } MultiReqBuffer; -void virtio_blk_init_request(VirtIOBlock *s, VirtIOBlockReq *req); +void virtio_blk_init_request(VirtIOBlock *s, VirtQueue *vq, + VirtIOBlockReq *req); void virtio_blk_free_request(VirtIOBlockReq *req); void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb); From 30d8bf6d171b02e90ac8c0b5cda868282c11d1d7 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 21 Jun 2016 13:13:14 +0100 Subject: [PATCH 7/9] virtio-blk: live migrate s->rq with multiqueue Add a field for the virtqueue index when migrating the s->rq request list. The new field is only needed when num_queues > 1. Existing QEMUs are unaffected by this change and therefore virtio-blk migration stays compatible. Suggested-by: Paolo Bonzini Signed-off-by: Stefan Hajnoczi Reviewed-by: Fam Zheng Message-id: 1466511196-12612-6-git-send-email-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/block/virtio-blk.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 3c6a1fa4dd..0353f389d7 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -808,6 +808,11 @@ static void virtio_blk_save_device(VirtIODevice *vdev, QEMUFile *f) while (req) { qemu_put_sbyte(f, 1); + + if (s->conf.num_queues > 1) { + qemu_put_be32(f, virtio_get_queue_index(req->vq)); + } + qemu_put_virtqueue_element(f, &req->elem); req = req->next; } @@ -831,9 +836,22 @@ static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f, VirtIOBlock *s = VIRTIO_BLK(vdev); while (qemu_get_sbyte(f)) { + unsigned nvqs = s->conf.num_queues; + unsigned vq_idx = 0; VirtIOBlockReq *req; + + if (nvqs > 1) { + vq_idx = qemu_get_be32(f); + + if (vq_idx >= nvqs) { + error_report("Invalid virtqueue index in request list: %#x", + vq_idx); + return -EINVAL; + } + } + req = qemu_get_virtqueue_element(f, sizeof(VirtIOBlockReq)); - virtio_blk_init_request(s, s->vq, req); + virtio_blk_init_request(s, virtio_get_queue(vdev, vq_idx), req); req->next = s->rq; s->rq = req; } From 51b04ac5c6a63cc8cd477c15a7e0998e0af24bcc Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 21 Jun 2016 13:13:15 +0100 Subject: [PATCH 8/9] virtio-blk: dataplane multiqueue support Monitor ioeventfds for all virtqueues in the device's AioContext. This is not true multiqueue because requests from all virtqueues are processed in a single IOThread. In the future it will be possible to use multiple IOThreads when the QEMU block layer supports multiqueue. Signed-off-by: Stefan Hajnoczi Reviewed-by: Fam Zheng Message-id: 1466511196-12612-7-git-send-email-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/block/dataplane/virtio-blk.c | 50 ++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index 835021b235..54b9ac1da6 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -31,9 +31,7 @@ struct VirtIOBlockDataPlane { bool stopping; VirtIOBlkConf *conf; - VirtIODevice *vdev; - VirtQueue *vq; /* virtqueue vring */ QEMUBH *bh; /* bh for guest notification */ unsigned long *batch_notify_vqs; @@ -156,6 +154,8 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev))); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); VirtIOBlock *vblk = VIRTIO_BLK(s->vdev); + unsigned i; + unsigned nvqs = s->conf->num_queues; int r; if (vblk->dataplane_started || s->starting) { @@ -163,10 +163,9 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) } s->starting = true; - s->vq = virtio_get_queue(s->vdev, 0); /* Set up guest notifier (irq) */ - r = k->set_guest_notifiers(qbus->parent, 1, true); + r = k->set_guest_notifiers(qbus->parent, nvqs, true); if (r != 0) { fprintf(stderr, "virtio-blk failed to set guest notifier (%d), " "ensure -enable-kvm is set\n", r); @@ -174,10 +173,15 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) } /* Set up virtqueue notify */ - r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), 0, true); - if (r != 0) { - fprintf(stderr, "virtio-blk failed to set host notifier (%d)\n", r); - goto fail_host_notifier; + for (i = 0; i < nvqs; i++) { + r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, true); + if (r != 0) { + fprintf(stderr, "virtio-blk failed to set host notifier (%d)\n", r); + while (i--) { + virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); + } + goto fail_guest_notifiers; + } } s->starting = false; @@ -187,17 +191,23 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) blk_set_aio_context(s->conf->conf.blk, s->ctx); /* Kick right away to begin processing requests already in vring */ - event_notifier_set(virtio_queue_get_host_notifier(s->vq)); + for (i = 0; i < nvqs; i++) { + VirtQueue *vq = virtio_get_queue(s->vdev, i); + + event_notifier_set(virtio_queue_get_host_notifier(vq)); + } /* Get this show started by hooking up our callbacks */ aio_context_acquire(s->ctx); - virtio_queue_aio_set_host_notifier_handler(s->vq, s->ctx, - virtio_blk_data_plane_handle_output); + for (i = 0; i < nvqs; i++) { + VirtQueue *vq = virtio_get_queue(s->vdev, i); + + virtio_queue_aio_set_host_notifier_handler(vq, s->ctx, + virtio_blk_data_plane_handle_output); + } aio_context_release(s->ctx); return; - fail_host_notifier: - k->set_guest_notifiers(qbus->parent, 1, false); fail_guest_notifiers: vblk->dataplane_disabled = true; s->starting = false; @@ -210,6 +220,8 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s) BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev))); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); VirtIOBlock *vblk = VIRTIO_BLK(s->vdev); + unsigned i; + unsigned nvqs = s->conf->num_queues; if (!vblk->dataplane_started || s->stopping) { return; @@ -227,17 +239,23 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s) aio_context_acquire(s->ctx); /* Stop notifications for new requests from guest */ - virtio_queue_aio_set_host_notifier_handler(s->vq, s->ctx, NULL); + for (i = 0; i < nvqs; i++) { + VirtQueue *vq = virtio_get_queue(s->vdev, i); + + virtio_queue_aio_set_host_notifier_handler(vq, s->ctx, NULL); + } /* Drain and switch bs back to the QEMU main loop */ blk_set_aio_context(s->conf->conf.blk, qemu_get_aio_context()); aio_context_release(s->ctx); - virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), 0, false); + for (i = 0; i < nvqs; i++) { + virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false); + } /* Clean up guest notifier (irq) */ - k->set_guest_notifiers(qbus->parent, 1, false); + k->set_guest_notifiers(qbus->parent, nvqs, false); vblk->dataplane_started = false; s->stopping = false; From 2f2705908fc4b7be868d45b7b02159fb243a8457 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 21 Jun 2016 13:13:16 +0100 Subject: [PATCH 9/9] virtio-blk: add num-queues device property Multiqueue virtio-blk can be enabled as follows: qemu -device virtio-blk-pci,num-queues=8 Signed-off-by: Stefan Hajnoczi Reviewed-by: Fam Zheng Message-id: 1466511196-12612-8-git-send-email-stefanha@redhat.com Signed-off-by: Stefan Hajnoczi --- hw/block/virtio-blk.c | 15 +++++++++++++-- include/hw/virtio/virtio-blk.h | 1 - 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 0353f389d7..fb43bbaa46 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -710,6 +710,7 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) blkcfg.physical_block_exp = get_physical_block_exp(conf); blkcfg.alignment_offset = 0; blkcfg.wce = blk_enable_write_cache(s->blk); + virtio_stw_p(vdev, &blkcfg.num_queues, s->conf.num_queues); memcpy(config, &blkcfg, sizeof(struct virtio_blk_config)); } @@ -753,6 +754,9 @@ static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features, if (blk_is_read_only(s->blk)) { virtio_add_feature(&features, VIRTIO_BLK_F_RO); } + if (s->conf.num_queues > 1) { + virtio_add_feature(&features, VIRTIO_BLK_F_MQ); + } return features; } @@ -877,6 +881,7 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) VirtIOBlkConf *conf = &s->conf; Error *err = NULL; static int virtio_blk_id; + unsigned i; if (!conf->conf.blk) { error_setg(errp, "drive property not set"); @@ -886,6 +891,10 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) error_setg(errp, "Device needs media, but drive is empty"); return; } + if (!conf->num_queues) { + error_setg(errp, "num-queues property must be larger than 0"); + return; + } blkconf_serial(&conf->conf, &conf->serial); s->original_wce = blk_enable_write_cache(conf->conf.blk); @@ -903,8 +912,9 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) s->rq = NULL; s->sector_mask = (s->conf.conf.logical_block_size / BDRV_SECTOR_SIZE) - 1; - conf->num_queues = 1; - s->vq = virtio_add_queue(vdev, 128, virtio_blk_handle_output); + for (i = 0; i < conf->num_queues; i++) { + virtio_add_queue(vdev, 128, virtio_blk_handle_output); + } virtio_blk_data_plane_create(vdev, conf, &s->dataplane, &err); if (err != NULL) { error_propagate(errp, err); @@ -957,6 +967,7 @@ static Property virtio_blk_properties[] = { #endif DEFINE_PROP_BIT("request-merging", VirtIOBlock, conf.request_merging, 0, true), + DEFINE_PROP_UINT16("num-queues", VirtIOBlock, conf.num_queues, 1), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index a25b3447d7..e9bf463f53 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -47,7 +47,6 @@ struct VirtIOBlockReq; typedef struct VirtIOBlock { VirtIODevice parent_obj; BlockBackend *blk; - VirtQueue *vq; void *rq; QEMUBH *bh; VirtIOBlkConf conf;