Commit c9d1a561 authored by Paolo Bonzini's avatar Paolo Bonzini Committed by Fam Zheng
Browse files

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: default avatarFam Zheng <famz@redhat.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
Message-Id: <1477565348-5458-18-git-send-email-pbonzini@redhat.com>
Signed-off-by: default avatarFam Zheng <famz@redhat.com>
parent 9e944cb4
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ void aio_bh_schedule_oneshot(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
    smp_wmb();
    ctx->first_bh = bh;
    qemu_mutex_unlock(&ctx->bh_lock);
    aio_notify(ctx);
}

QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
+2 −0
Original line number Diff line number Diff line
@@ -2090,7 +2090,9 @@ int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **er

    assert(bs_queue != NULL);

    aio_context_release(ctx);
    bdrv_drain_all();
    aio_context_acquire(ctx);

    QSIMPLEQ_FOREACH(bs_entry, bs_queue, entry) {
        if (bdrv_reopen_prepare(&bs_entry->state, bs_queue, &local_err)) {
+12 −0
Original line number Diff line number Diff line
@@ -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)
+1 −0
Original line number Diff line number Diff line
@@ -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)
+3 −0
Original line number Diff line number Diff line
@@ -702,6 +702,9 @@ out:

    srco->ret = ret;
    srco->finished = true;
    if (srco->bs) {
        bdrv_wakeup(srco->bs);
    }
}

/*
Loading