From c9d1a56174339b0afdef63b7d151b38f4bb6dae5 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 27 Oct 2016 12:49:05 +0200 Subject: block: only call aio_poll on the current thread's AioContext aio_poll is not thread safe; for example bdrv_drain can hang if the last in-flight I/O operation is completed in the I/O thread after the main thread has checked bs->in_flight. The bug remains latent as long as all of it is called within aio_context_acquire/aio_context_release, but this will change soon. To fix this, if bdrv_drain is called from outside the I/O thread, signal the main AioContext through a dummy bottom half. The event loop then only runs in the I/O thread. Reviewed-by: Fam Zheng Signed-off-by: Paolo Bonzini Message-Id: <1477565348-5458-18-git-send-email-pbonzini@redhat.com> Signed-off-by: Fam Zheng --- block/io.c | 12 ++++++++++++ block/nfs.c | 1 + block/sheepdog.c | 3 +++ 3 files changed, 16 insertions(+) (limited to 'block') diff --git a/block/io.c b/block/io.c index 6fc0145864..be0d862ca6 100644 --- a/block/io.c +++ b/block/io.c @@ -474,9 +474,21 @@ void bdrv_inc_in_flight(BlockDriverState *bs) atomic_inc(&bs->in_flight); } +static void dummy_bh_cb(void *opaque) +{ +} + +void bdrv_wakeup(BlockDriverState *bs) +{ + if (bs->wakeup) { + aio_bh_schedule_oneshot(qemu_get_aio_context(), dummy_bh_cb, NULL); + } +} + void bdrv_dec_in_flight(BlockDriverState *bs) { atomic_dec(&bs->in_flight); + bdrv_wakeup(bs); } static bool coroutine_fn wait_serialising_requests(BdrvTrackedRequest *self) diff --git a/block/nfs.c b/block/nfs.c index 7474fbc7cc..88c60a9118 100644 --- a/block/nfs.c +++ b/block/nfs.c @@ -505,6 +505,7 @@ nfs_get_allocated_file_size_cb(int ret, struct nfs_context *nfs, void *data, error_report("NFS Error: %s", nfs_get_error(nfs)); } task->complete = 1; + bdrv_wakeup(task->bs); } static int64_t nfs_get_allocated_file_size(BlockDriverState *bs) diff --git a/block/sheepdog.c b/block/sheepdog.c index 16a5c1c28d..1fb917343a 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -702,6 +702,9 @@ out: srco->ret = ret; srco->finished = true; + if (srco->bs) { + bdrv_wakeup(srco->bs); + } } /* -- cgit v1.2.3