virtio-blk: implement BlockDevOps->drained_begin()
Detach ioeventfds during drained sections to stop I/O submission from the guest. virtio-blk is no longer reliant on aio_disable_external() after this patch. This will allow us to remove the aio_disable_external() API once all other code that relies on it is converted. Take extra care to avoid attaching/detaching ioeventfds if the data plane is started/stopped during a drained section. This should be rare, but maybe the mirror block job can trigger it. Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Message-Id: <20230516190238.8401-18-stefanha@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
		
				
					committed by
					
						 Kevin Wolf
						Kevin Wolf
					
				
			
			
				
	
			
			
			
						parent
						
							bd58ab40c3
						
					
				
				
					commit
					1665d9326f
				
			| @@ -246,13 +246,15 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev) | ||||
|     } | ||||
|  | ||||
|     /* Get this show started by hooking up our callbacks */ | ||||
|     aio_context_acquire(s->ctx); | ||||
|     for (i = 0; i < nvqs; i++) { | ||||
|         VirtQueue *vq = virtio_get_queue(s->vdev, i); | ||||
|     if (!blk_in_drain(s->conf->conf.blk)) { | ||||
|         aio_context_acquire(s->ctx); | ||||
|         for (i = 0; i < nvqs; i++) { | ||||
|             VirtQueue *vq = virtio_get_queue(s->vdev, i); | ||||
|  | ||||
|         virtio_queue_aio_attach_host_notifier(vq, s->ctx); | ||||
|             virtio_queue_aio_attach_host_notifier(vq, s->ctx); | ||||
|         } | ||||
|         aio_context_release(s->ctx); | ||||
|     } | ||||
|     aio_context_release(s->ctx); | ||||
|     return 0; | ||||
|  | ||||
|   fail_aio_context: | ||||
| @@ -322,7 +324,9 @@ void virtio_blk_data_plane_stop(VirtIODevice *vdev) | ||||
|     s->stopping = true; | ||||
|     trace_virtio_blk_data_plane_stop(s); | ||||
|  | ||||
|     aio_wait_bh_oneshot(s->ctx, virtio_blk_data_plane_stop_bh, s); | ||||
|     if (!blk_in_drain(s->conf->conf.blk)) { | ||||
|         aio_wait_bh_oneshot(s->ctx, virtio_blk_data_plane_stop_bh, s); | ||||
|     } | ||||
|  | ||||
|     aio_context_acquire(s->ctx); | ||||
|  | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user