diff options
Diffstat (limited to 'hw/block')
-rw-r--r-- | hw/block/dataplane/virtio-blk.c | 20 |
1 files changed, 19 insertions, 1 deletions
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index e88862dc50..d6ba65ca23 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -34,6 +34,7 @@ struct VirtIOBlockDataPlane { VirtIODevice *vdev; Vring vring; /* virtqueue vring */ EventNotifier *guest_notifier; /* irq */ + QEMUBH *bh; /* bh for guest notification */ /* Note that these EventNotifiers are assigned by value. This is * fine as long as you do not call event_notifier_cleanup on them @@ -61,13 +62,28 @@ static void notify_guest(VirtIOBlockDataPlane *s) event_notifier_set(s->guest_notifier); } +static void notify_guest_bh(void *opaque) +{ + VirtIOBlockDataPlane *s = opaque; + + notify_guest(s); +} + static void complete_request_vring(VirtIOBlockReq *req, unsigned char status) { + VirtIOBlockDataPlane *s = req->dev->dataplane; stb_p(&req->in->status, status); vring_push(&req->dev->dataplane->vring, &req->elem, req->qiov.size + sizeof(*req->in)); - notify_guest(req->dev->dataplane); + + /* Suppress notification to guest by BH and its scheduled + * flag because requests are completed as a batch after io + * plug & unplug is introduced, and the BH can still be + * executed in dataplane aio context even after it is + * stopped, so needn't worry about notification loss with BH. + */ + qemu_bh_schedule(s->bh); } static void handle_notify(EventNotifier *e) @@ -172,6 +188,7 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, s->iothread = &s->internal_iothread_obj; } s->ctx = iothread_get_aio_context(s->iothread); + s->bh = aio_bh_new(s->ctx, notify_guest_bh, s); error_setg(&s->blocker, "block device is in use by data plane"); bdrv_op_block_all(blk->conf.bs, s->blocker); @@ -190,6 +207,7 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s) bdrv_op_unblock_all(s->blk->conf.bs, s->blocker); error_free(s->blocker); object_unref(OBJECT(s->iothread)); + qemu_bh_delete(s->bh); g_free(s); } |