|
@@ -1506,8 +1506,44 @@ static void virtio_blk_resize(void *opaque)
|
|
|
aio_bh_schedule_oneshot(qemu_get_aio_context(), virtio_resize_cb, vdev);
|
|
|
}
|
|
|
|
|
|
+/* Suspend virtqueue ioeventfd processing during drain */
|
|
|
+static void virtio_blk_drained_begin(void *opaque)
|
|
|
+{
|
|
|
+ VirtIOBlock *s = opaque;
|
|
|
+ VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
|
|
|
+ AioContext *ctx = blk_get_aio_context(s->conf.conf.blk);
|
|
|
+
|
|
|
+ if (!s->dataplane || !s->dataplane_started) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (uint16_t i = 0; i < s->conf.num_queues; i++) {
|
|
|
+ VirtQueue *vq = virtio_get_queue(vdev, i);
|
|
|
+ virtio_queue_aio_detach_host_notifier(vq, ctx);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* Resume virtqueue ioeventfd processing after drain */
|
|
|
+static void virtio_blk_drained_end(void *opaque)
|
|
|
+{
|
|
|
+ VirtIOBlock *s = opaque;
|
|
|
+ VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
|
|
|
+ AioContext *ctx = blk_get_aio_context(s->conf.conf.blk);
|
|
|
+
|
|
|
+ if (!s->dataplane || !s->dataplane_started) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (uint16_t i = 0; i < s->conf.num_queues; i++) {
|
|
|
+ VirtQueue *vq = virtio_get_queue(vdev, i);
|
|
|
+ virtio_queue_aio_attach_host_notifier(vq, ctx);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static const BlockDevOps virtio_block_ops = {
|
|
|
- .resize_cb = virtio_blk_resize,
|
|
|
+ .resize_cb = virtio_blk_resize,
|
|
|
+ .drained_begin = virtio_blk_drained_begin,
|
|
|
+ .drained_end = virtio_blk_drained_end,
|
|
|
};
|
|
|
|
|
|
static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
|