From 14e9559f4624e704a53d0789124b6f9ea9ebb5ca Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Sat, 8 Apr 2017 11:34:45 +0800 Subject: block: Make bdrv_parent_drained_begin/end public Signed-off-by: Fam Zheng Reviewed-by: Stefan Hajnoczi Acked-by: Stefan Hajnoczi Reviewed-by: Kevin Wolf --- block/io.c | 4 ++-- include/block/block.h | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/block/io.c b/block/io.c index 7321ddab3d..959864678f 100644 --- a/block/io.c +++ b/block/io.c @@ -44,7 +44,7 @@ static void coroutine_fn bdrv_co_do_rw(void *opaque); static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int count, BdrvRequestFlags flags); -static void bdrv_parent_drained_begin(BlockDriverState *bs) +void bdrv_parent_drained_begin(BlockDriverState *bs) { BdrvChild *c; @@ -55,7 +55,7 @@ static void bdrv_parent_drained_begin(BlockDriverState *bs) } } -static void bdrv_parent_drained_end(BlockDriverState *bs) +void bdrv_parent_drained_end(BlockDriverState *bs) { BdrvChild *c; diff --git a/include/block/block.h b/include/block/block.h index 3e09222f5f..488a07ed67 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -572,6 +572,22 @@ int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo); void bdrv_io_plug(BlockDriverState *bs); void bdrv_io_unplug(BlockDriverState *bs); +/** + * bdrv_parent_drained_begin: + * + * Begin a quiesced section of all users of @bs. This is part of + * bdrv_drained_begin. + */ +void bdrv_parent_drained_begin(BlockDriverState *bs); + +/** + * bdrv_parent_drained_end: + * + * End a quiesced section of all users of @bs. This is part of + * bdrv_drained_end. + */ +void bdrv_parent_drained_end(BlockDriverState *bs); + /** * bdrv_drained_begin: * -- cgit v1.2.1 From aabf591007a83dc6520329bce929570115849286 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Wed, 5 Apr 2017 14:44:24 +0800 Subject: block: Quiesce old aio context during bdrv_set_aio_context The fact that the bs->aio_context is changing can confuse the dataplane iothread, because of the now fine granularity aio context lock. bdrv_drain should rather be a bdrv_drained_begin/end pair, but since bs->aio_context is changing, we can just use aio_disable_external and bdrv_parent_drained_begin. Reported-by: Ed Swierk Signed-off-by: Fam Zheng Acked-by: Stefan Hajnoczi Reviewed-by: Stefan Hajnoczi Reviewed-by: Kevin Wolf --- block.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/block.c b/block.c index b8a30115e1..a995a8ec00 100644 --- a/block.c +++ b/block.c @@ -4396,11 +4396,12 @@ void bdrv_attach_aio_context(BlockDriverState *bs, void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context) { - AioContext *ctx; + AioContext *ctx = bdrv_get_aio_context(bs); + aio_disable_external(ctx); + bdrv_parent_drained_begin(bs); bdrv_drain(bs); /* ensure there are no in-flight requests */ - ctx = bdrv_get_aio_context(bs); while (aio_poll(ctx, false)) { /* wait for all bottom halves to execute */ } @@ -4412,6 +4413,8 @@ void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context) */ aio_context_acquire(new_context); bdrv_attach_aio_context(bs, new_context); + bdrv_parent_drained_end(bs); + aio_enable_external(ctx); aio_context_release(new_context); } -- cgit v1.2.1 From d90fce944647f8b2759f016b0f86bf36dffe34c8 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Fri, 7 Apr 2017 08:55:13 +0800 Subject: tests/block-job-txn: Don't start block job before adding to txn Previously, before test_block_job_start returns, the job can already complete, as a result, the transactional state of other jobs added to the same txn later cannot be handled correctly. Move the block_job_start() calls to callers after block_job_txn_add_job() calls. Signed-off-by: Fam Zheng Acked-by: Stefan Hajnoczi Reviewed-by: Kevin Wolf --- tests/test-blockjob-txn.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c index 4ccbda14af..0f80194e85 100644 --- a/tests/test-blockjob-txn.c +++ b/tests/test-blockjob-txn.c @@ -110,7 +110,6 @@ static BlockJob *test_block_job_start(unsigned int iterations, s->result = result; data->job = s; data->result = result; - block_job_start(&s->common); return &s->common; } @@ -123,6 +122,7 @@ static void test_single_job(int expected) txn = block_job_txn_new(); job = test_block_job_start(1, true, expected, &result); block_job_txn_add_job(txn, job); + block_job_start(job); if (expected == -ECANCELED) { block_job_cancel(job); @@ -164,6 +164,8 @@ static void test_pair_jobs(int expected1, int expected2) block_job_txn_add_job(txn, job1); job2 = test_block_job_start(2, true, expected2, &result2); block_job_txn_add_job(txn, job2); + block_job_start(job1); + block_job_start(job2); if (expected1 == -ECANCELED) { block_job_cancel(job1); @@ -223,6 +225,8 @@ static void test_pair_jobs_fail_cancel_race(void) block_job_txn_add_job(txn, job1); job2 = test_block_job_start(2, false, 0, &result2); block_job_txn_add_job(txn, job2); + block_job_start(job1); + block_job_start(job2); block_job_cancel(job1); -- cgit v1.2.1 From ba9e75ceef93000e624ae55faf2e498f96be2ec7 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Mon, 10 Apr 2017 20:06:12 +0800 Subject: coroutine: Extract qemu_aio_coroutine_enter It's a variant of qemu_coroutine_enter with an explicit AioContext parameter. Signed-off-by: Fam Zheng Acked-by: Stefan Hajnoczi Reviewed-by: Kevin Wolf --- include/qemu/coroutine.h | 5 +++++ util/qemu-coroutine.c | 11 ++++++++--- util/trace-events | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/include/qemu/coroutine.h b/include/qemu/coroutine.h index e60beaff81..a4509bd977 100644 --- a/include/qemu/coroutine.h +++ b/include/qemu/coroutine.h @@ -76,6 +76,11 @@ void qemu_coroutine_enter(Coroutine *coroutine); */ void qemu_coroutine_enter_if_inactive(Coroutine *co); +/** + * Transfer control to a coroutine and associate it with ctx + */ +void qemu_aio_coroutine_enter(AioContext *ctx, Coroutine *co); + /** * Transfer control back to a coroutine's caller * diff --git a/util/qemu-coroutine.c b/util/qemu-coroutine.c index 72412e5649..486af9a622 100644 --- a/util/qemu-coroutine.c +++ b/util/qemu-coroutine.c @@ -102,12 +102,12 @@ static void coroutine_delete(Coroutine *co) qemu_coroutine_delete(co); } -void qemu_coroutine_enter(Coroutine *co) +void qemu_aio_coroutine_enter(AioContext *ctx, Coroutine *co) { Coroutine *self = qemu_coroutine_self(); CoroutineAction ret; - trace_qemu_coroutine_enter(self, co, co->entry_arg); + trace_qemu_aio_coroutine_enter(ctx, self, co, co->entry_arg); if (co->caller) { fprintf(stderr, "Co-routine re-entered recursively\n"); @@ -115,7 +115,7 @@ void qemu_coroutine_enter(Coroutine *co) } co->caller = self; - co->ctx = qemu_get_current_aio_context(); + co->ctx = ctx; /* Store co->ctx before anything that stores co. Matches * barrier in aio_co_wake and qemu_co_mutex_wake. @@ -139,6 +139,11 @@ void qemu_coroutine_enter(Coroutine *co) } } +void qemu_coroutine_enter(Coroutine *co) +{ + qemu_aio_coroutine_enter(qemu_get_current_aio_context(), co); +} + void qemu_coroutine_enter_if_inactive(Coroutine *co) { if (!qemu_coroutine_entered(co)) { diff --git a/util/trace-events b/util/trace-events index ac27d94a97..b44ef4f895 100644 --- a/util/trace-events +++ b/util/trace-events @@ -22,7 +22,7 @@ buffer_move(const char *buf, size_t len, const char *from) "%s: %zd bytes from % buffer_free(const char *buf, size_t len) "%s: capacity %zd" # util/qemu-coroutine.c -qemu_coroutine_enter(void *from, void *to, void *opaque) "from %p to %p opaque %p" +qemu_aio_coroutine_enter(void *ctx, void *from, void *to, void *opaque) "ctx %p from %p to %p opaque %p" qemu_coroutine_yield(void *from, void *to) "from %p to %p" qemu_coroutine_terminate(void *co) "self %p" -- cgit v1.2.1 From 8865852e00557925f60eb6e26d797833422ee86d Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Mon, 10 Apr 2017 20:07:35 +0800 Subject: async: Introduce aio_co_enter They start the coroutine on the specified context. Signed-off-by: Fam Zheng Acked-by: Stefan Hajnoczi Reviewed-by: Kevin Wolf --- include/block/aio.h | 9 +++++++++ util/async.c | 7 ++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/block/aio.h b/include/block/aio.h index 677b6ffc25..406e32305a 100644 --- a/include/block/aio.h +++ b/include/block/aio.h @@ -510,6 +510,15 @@ void aio_co_schedule(AioContext *ctx, struct Coroutine *co); */ void aio_co_wake(struct Coroutine *co); +/** + * aio_co_enter: + * @ctx: the context to run the coroutine + * @co: the coroutine to run + * + * Enter a coroutine in the specified AioContext. + */ +void aio_co_enter(AioContext *ctx, struct Coroutine *co); + /** * Return the AioContext whose event loop runs in the current thread. * diff --git a/util/async.c b/util/async.c index 663e297e1f..355af73ee7 100644 --- a/util/async.c +++ b/util/async.c @@ -453,6 +453,11 @@ void aio_co_wake(struct Coroutine *co) smp_read_barrier_depends(); ctx = atomic_read(&co->ctx); + aio_co_enter(ctx, co); +} + +void aio_co_enter(AioContext *ctx, struct Coroutine *co) +{ if (ctx != qemu_get_current_aio_context()) { aio_co_schedule(ctx, co); return; @@ -464,7 +469,7 @@ void aio_co_wake(struct Coroutine *co) QSIMPLEQ_INSERT_TAIL(&self->co_queue_wakeup, co, co_queue_next); } else { aio_context_acquire(ctx); - qemu_coroutine_enter(co); + qemu_aio_coroutine_enter(ctx, co); aio_context_release(ctx); } } -- cgit v1.2.1 From 052a75721fb38b9aa0e71ea6420b462c0e356e74 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Mon, 10 Apr 2017 20:09:25 +0800 Subject: block: Introduce bdrv_coroutine_enter Signed-off-by: Fam Zheng Acked-by: Stefan Hajnoczi Reviewed-by: Kevin Wolf --- block.c | 5 +++++ include/block/block.h | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/block.c b/block.c index a995a8ec00..086a12df97 100644 --- a/block.c +++ b/block.c @@ -4324,6 +4324,11 @@ AioContext *bdrv_get_aio_context(BlockDriverState *bs) return bs->aio_context; } +void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co) +{ + aio_co_enter(bdrv_get_aio_context(bs), co); +} + static void bdrv_do_remove_aio_context_notifier(BdrvAioNotifier *ban) { QLIST_REMOVE(ban, list); diff --git a/include/block/block.h b/include/block/block.h index 488a07ed67..97d4330292 100644 --- a/include/block/block.h +++ b/include/block/block.h @@ -557,6 +557,11 @@ bool bdrv_debug_is_suspended(BlockDriverState *bs, const char *tag); */ AioContext *bdrv_get_aio_context(BlockDriverState *bs); +/** + * Transfer control to @co in the aio context of @bs + */ +void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co); + /** * bdrv_set_aio_context: * -- cgit v1.2.1 From aef4278c5a835c555ffe065f9e480190fd076675 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Mon, 10 Apr 2017 20:12:05 +0800 Subject: blockjob: Use bdrv_coroutine_enter to start coroutine Resuming and especially starting of the block job coroutine, could be issued in the main thread. However the coroutine's "home" ctx should be set to the same context as job->blk. Use bdrv_coroutine_enter to ensure that. Signed-off-by: Fam Zheng Acked-by: Stefan Hajnoczi Reviewed-by: Kevin Wolf --- blockjob.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/blockjob.c b/blockjob.c index 9b619f385a..6e489327ff 100644 --- a/blockjob.c +++ b/blockjob.c @@ -290,7 +290,7 @@ void block_job_start(BlockJob *job) job->pause_count--; job->busy = true; job->paused = false; - qemu_coroutine_enter(job->co); + bdrv_coroutine_enter(blk_bs(job->blk), job->co); } void block_job_ref(BlockJob *job) @@ -532,7 +532,7 @@ void block_job_user_resume(BlockJob *job) void block_job_enter(BlockJob *job) { if (job->co && !job->busy) { - qemu_coroutine_enter(job->co); + bdrv_coroutine_enter(blk_bs(job->blk), job->co); } } -- cgit v1.2.1 From 324ec3e4f26e0a2a422478db4b9992f8aad3bde4 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Mon, 10 Apr 2017 20:16:18 +0800 Subject: qemu-io-cmds: Use bdrv_coroutine_enter qemu_coroutine_create associates @co to qemu_aio_context but we poll blk's context below. If the coroutine yields, it may never get resumed again. Use bdrv_coroutine_enter to make sure we are starting the I/O on the right context. Signed-off-by: Fam Zheng Acked-by: Stefan Hajnoczi Reviewed-by: Kevin Wolf --- qemu-io-cmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c index 883f53b64d..312fc6d157 100644 --- a/qemu-io-cmds.c +++ b/qemu-io-cmds.c @@ -521,7 +521,7 @@ static int do_co_pwrite_zeroes(BlockBackend *blk, int64_t offset, } co = qemu_coroutine_create(co_pwrite_zeroes_entry, &data); - qemu_coroutine_enter(co); + bdrv_coroutine_enter(blk_bs(blk), co); while (!data.done) { aio_poll(blk_get_aio_context(blk), true); } -- cgit v1.2.1 From e92f0e1910f0655a0edd8d87c5a7262d36517a89 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Mon, 10 Apr 2017 20:20:17 +0800 Subject: block: Use bdrv_coroutine_enter to start I/O coroutines BDRV_POLL_WHILE waits for the started I/O by releasing bs's ctx then polling the main context, which relies on the yielded coroutine continuing on bs->ctx before notifying qemu_aio_context with bdrv_wakeup(). Thus, using qemu_coroutine_enter to start I/O is wrong because if the coroutine is entered from main loop, co->ctx will be qemu_aio_context, as a result of the "release, poll, acquire" loop of BDRV_POLL_WHILE, race conditions happen when both main thread and the iothread access the same BDS: main loop iothread ----------------------------------------------------------------------- blockdev_snapshot aio_context_acquire(bs->ctx) virtio_scsi_data_plane_handle_cmd bdrv_drained_begin(bs->ctx) bdrv_flush(bs) bdrv_co_flush(bs) aio_context_acquire(bs->ctx).enter ... qemu_coroutine_yield(co) BDRV_POLL_WHILE() aio_context_release(bs->ctx) aio_context_acquire(bs->ctx).return ... aio_co_wake(co) aio_poll(qemu_aio_context) ... co_schedule_bh_cb() ... qemu_coroutine_enter(co) ... /* (A) bdrv_co_flush(bs) /* (B) I/O on bs */ continues... */ aio_context_release(bs->ctx) aio_context_acquire(bs->ctx) Note that in above case, bdrv_drained_begin() doesn't do the "release, poll, acquire" in BDRV_POLL_WHILE, because bs->in_flight == 0. Fix this by using bdrv_coroutine_enter and enter coroutine in the right context. iotests 109 output is updated because the coroutine reenter flow during mirror job complete is different (now through co_queue_wakeup, instead of the unconditional qemu_coroutine_switch before), making the end job len different. Signed-off-by: Fam Zheng Acked-by: Stefan Hajnoczi Reviewed-by: Kevin Wolf --- block/block-backend.c | 4 ++-- block/io.c | 14 +++++++------- tests/qemu-iotests/109.out | 10 +++++----- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/block/block-backend.c b/block/block-backend.c index 18ece99c6e..a8f2b3440f 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1045,7 +1045,7 @@ static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf, co_entry(&rwco); } else { Coroutine *co = qemu_coroutine_create(co_entry, &rwco); - qemu_coroutine_enter(co); + bdrv_coroutine_enter(blk_bs(blk), co); BDRV_POLL_WHILE(blk_bs(blk), rwco.ret == NOT_DONE); } @@ -1152,7 +1152,7 @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, int bytes, acb->has_returned = false; co = qemu_coroutine_create(co_entry, acb); - qemu_coroutine_enter(co); + bdrv_coroutine_enter(blk_bs(blk), co); acb->has_returned = true; if (acb->rwco.ret != NOT_DONE) { diff --git a/block/io.c b/block/io.c index 959864678f..00e45ca219 100644 --- a/block/io.c +++ b/block/io.c @@ -616,7 +616,7 @@ static int bdrv_prwv_co(BdrvChild *child, int64_t offset, bdrv_rw_co_entry(&rwco); } else { co = qemu_coroutine_create(bdrv_rw_co_entry, &rwco); - qemu_coroutine_enter(co); + bdrv_coroutine_enter(child->bs, co); BDRV_POLL_WHILE(child->bs, rwco.ret == NOT_DONE); } return rwco.ret; @@ -1880,7 +1880,7 @@ int64_t bdrv_get_block_status_above(BlockDriverState *bs, } else { co = qemu_coroutine_create(bdrv_get_block_status_above_co_entry, &data); - qemu_coroutine_enter(co); + bdrv_coroutine_enter(bs, co); BDRV_POLL_WHILE(bs, !data.done); } return data.ret; @@ -2006,7 +2006,7 @@ bdrv_rw_vmstate(BlockDriverState *bs, QEMUIOVector *qiov, int64_t pos, }; Coroutine *co = qemu_coroutine_create(bdrv_co_rw_vmstate_entry, &data); - qemu_coroutine_enter(co); + bdrv_coroutine_enter(bs, co); while (data.ret == -EINPROGRESS) { aio_poll(bdrv_get_aio_context(bs), true); } @@ -2223,7 +2223,7 @@ static BlockAIOCB *bdrv_co_aio_prw_vector(BdrvChild *child, acb->is_write = is_write; co = qemu_coroutine_create(bdrv_co_do_rw, acb); - qemu_coroutine_enter(co); + bdrv_coroutine_enter(child->bs, co); bdrv_co_maybe_schedule_bh(acb); return &acb->common; @@ -2254,7 +2254,7 @@ BlockAIOCB *bdrv_aio_flush(BlockDriverState *bs, acb->req.error = -EINPROGRESS; co = qemu_coroutine_create(bdrv_aio_flush_co_entry, acb); - qemu_coroutine_enter(co); + bdrv_coroutine_enter(bs, co); bdrv_co_maybe_schedule_bh(acb); return &acb->common; @@ -2387,7 +2387,7 @@ int bdrv_flush(BlockDriverState *bs) bdrv_flush_co_entry(&flush_co); } else { co = qemu_coroutine_create(bdrv_flush_co_entry, &flush_co); - qemu_coroutine_enter(co); + bdrv_coroutine_enter(bs, co); BDRV_POLL_WHILE(bs, flush_co.ret == NOT_DONE); } @@ -2534,7 +2534,7 @@ int bdrv_pdiscard(BlockDriverState *bs, int64_t offset, int count) bdrv_pdiscard_co_entry(&rwco); } else { co = qemu_coroutine_create(bdrv_pdiscard_co_entry, &rwco); - qemu_coroutine_enter(co); + bdrv_coroutine_enter(bs, co); BDRV_POLL_WHILE(bs, rwco.ret == NOT_DONE); } diff --git a/tests/qemu-iotests/109.out b/tests/qemu-iotests/109.out index e5d70d75f1..55fe536d56 100644 --- a/tests/qemu-iotests/109.out +++ b/tests/qemu-iotests/109.out @@ -10,7 +10,7 @@ Automatically detecting the format is dangerous for raw images, write operations Specify the 'raw' format explicitly to remove the restrictions. {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 1024, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} {"return": []} read 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -73,7 +73,7 @@ Automatically detecting the format is dangerous for raw images, write operations Specify the 'raw' format explicitly to remove the restrictions. {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 1024, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} {"return": []} read 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -115,7 +115,7 @@ Automatically detecting the format is dangerous for raw images, write operations Specify the 'raw' format explicitly to remove the restrictions. {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2560, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} {"return": []} read 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -135,7 +135,7 @@ Automatically detecting the format is dangerous for raw images, write operations Specify the 'raw' format explicitly to remove the restrictions. {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2560, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} {"return": []} read 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) @@ -195,7 +195,7 @@ Automatically detecting the format is dangerous for raw images, write operations Specify the 'raw' format explicitly to remove the restrictions. {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}} -{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 2048, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}} {"return": []} read 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -- cgit v1.2.1 From 49ca6259131c6b0555845fcac3e34467c8ac37eb Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Mon, 10 Apr 2017 21:00:50 +0800 Subject: block: Fix bdrv_co_flush early return bdrv_inc_in_flight and bdrv_dec_in_flight are mandatory for BDRV_POLL_WHILE to work, even for the shortcut case where flush is unnecessary. Move the if block to below bdrv_dec_in_flight, and BTW fix the variable declaration position. Signed-off-by: Fam Zheng Acked-by: Stefan Hajnoczi Reviewed-by: Kevin Wolf Reviewed-by: Paolo Bonzini --- block/io.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/block/io.c b/block/io.c index 00e45ca219..bae6947032 100644 --- a/block/io.c +++ b/block/io.c @@ -2278,16 +2278,17 @@ static void coroutine_fn bdrv_flush_co_entry(void *opaque) int coroutine_fn bdrv_co_flush(BlockDriverState *bs) { - int ret; + int current_gen; + int ret = 0; + + bdrv_inc_in_flight(bs); if (!bs || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs) || bdrv_is_sg(bs)) { - return 0; + goto early_exit; } - bdrv_inc_in_flight(bs); - - int current_gen = bs->write_gen; + current_gen = bs->write_gen; /* Wait until any previous flushes are completed */ while (bs->active_flush_req) { @@ -2370,6 +2371,7 @@ out: /* Return value is ignored - it's ok if wait queue is empty */ qemu_co_queue_next(&bs->flush_queue); +early_exit: bdrv_dec_in_flight(bs); return ret; } -- cgit v1.2.1 From 76296dff97864ebb15fa65cc56a6f890ee0c5a28 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Tue, 11 Apr 2017 19:43:52 +0800 Subject: sheepdog: Use bdrv_coroutine_enter before BDRV_POLL_WHILE When called from main thread, the coroutine should run in the context of bs. Use bdrv_coroutine_enter to ensure that. Signed-off-by: Fam Zheng --- block/sheepdog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/sheepdog.c b/block/sheepdog.c index 1b71fc81ec..14d6327209 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -736,7 +736,7 @@ static int do_req(int sockfd, BlockDriverState *bs, SheepdogReq *hdr, } else { co = qemu_coroutine_create(do_co_req, &srco); if (bs) { - qemu_coroutine_enter(co); + bdrv_coroutine_enter(bs, co); BDRV_POLL_WHILE(bs, !srco.finished); } else { qemu_coroutine_enter(co); -- cgit v1.2.1