[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PULL 50/53] block: let stream blockjob run in BDS AioConte
From: |
Stefan Hajnoczi |
Subject: |
[Qemu-devel] [PULL 50/53] block: let stream blockjob run in BDS AioContext |
Date: |
Mon, 3 Nov 2014 11:50:53 +0000 |
The stream block job must run in the BlockDriverState AioContext so that
it works with dataplane.
The basics of acquiring the AioContext are easy in blockdev.c.
The tricky part is the completion code which drops part of the backing
file chain. This must be done in the main loop where bdrv_unref() and
bdrv_close() are safe to call. Use block_job_defer_to_main_loop() to
achieve that.
Signed-off-by: Stefan Hajnoczi <address@hidden>
Reviewed-by: Max Reitz <address@hidden>
Message-id: address@hidden
---
block/stream.c | 50 ++++++++++++++++++++++++++++++++++++--------------
blockdev.c | 16 ++++++++++++----
2 files changed, 48 insertions(+), 18 deletions(-)
diff --git a/block/stream.c b/block/stream.c
index a1dc8da..a628901 100644
--- a/block/stream.c
+++ b/block/stream.c
@@ -79,9 +79,39 @@ static void close_unused_images(BlockDriverState *top,
BlockDriverState *base,
bdrv_refresh_limits(top, NULL);
}
+typedef struct {
+ int ret;
+ bool reached_end;
+} StreamCompleteData;
+
+static void stream_complete(BlockJob *job, void *opaque)
+{
+ StreamBlockJob *s = container_of(job, StreamBlockJob, common);
+ StreamCompleteData *data = opaque;
+ BlockDriverState *base = s->base;
+
+ if (!block_job_is_cancelled(&s->common) && data->reached_end &&
+ data->ret == 0) {
+ const char *base_id = NULL, *base_fmt = NULL;
+ if (base) {
+ base_id = s->backing_file_str;
+ if (base->drv) {
+ base_fmt = base->drv->format_name;
+ }
+ }
+ data->ret = bdrv_change_backing_file(job->bs, base_id, base_fmt);
+ close_unused_images(job->bs, base, base_id);
+ }
+
+ g_free(s->backing_file_str);
+ block_job_completed(&s->common, data->ret);
+ g_free(data);
+}
+
static void coroutine_fn stream_run(void *opaque)
{
StreamBlockJob *s = opaque;
+ StreamCompleteData *data;
BlockDriverState *bs = s->common.bs;
BlockDriverState *base = s->base;
int64_t sector_num, end;
@@ -183,21 +213,13 @@ wait:
/* Do not remove the backing file if an error was there but ignored. */
ret = error;
- if (!block_job_is_cancelled(&s->common) && sector_num == end && ret == 0) {
- const char *base_id = NULL, *base_fmt = NULL;
- if (base) {
- base_id = s->backing_file_str;
- if (base->drv) {
- base_fmt = base->drv->format_name;
- }
- }
- ret = bdrv_change_backing_file(bs, base_id, base_fmt);
- close_unused_images(bs, base, base_id);
- }
-
qemu_vfree(buf);
- g_free(s->backing_file_str);
- block_job_completed(&s->common, ret);
+
+ /* Modify backing chain and close BDSes in main loop */
+ data = g_malloc(sizeof(*data));
+ data->ret = ret;
+ data->reached_end = sector_num == end;
+ block_job_defer_to_main_loop(&s->common, stream_complete, data);
}
static void stream_set_speed(BlockJob *job, int64_t speed, Error **errp)
diff --git a/blockdev.c b/blockdev.c
index 9c68988..6e43d2e 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1963,6 +1963,7 @@ void qmp_block_stream(const char *device,
{
BlockDriverState *bs;
BlockDriverState *base_bs = NULL;
+ AioContext *aio_context;
Error *local_err = NULL;
const char *base_name = NULL;
@@ -1976,16 +1977,20 @@ void qmp_block_stream(const char *device,
return;
}
+ aio_context = bdrv_get_aio_context(bs);
+ aio_context_acquire(aio_context);
+
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_STREAM, errp)) {
- return;
+ goto out;
}
if (has_base) {
base_bs = bdrv_find_backing_image(bs, base);
if (base_bs == NULL) {
error_set(errp, QERR_BASE_NOT_FOUND, base);
- return;
+ goto out;
}
+ assert(bdrv_get_aio_context(base_bs) == aio_context);
base_name = base;
}
@@ -1994,7 +1999,7 @@ void qmp_block_stream(const char *device,
if (base_bs == NULL && has_backing_file) {
error_setg(errp, "backing file specified, but streaming the "
"entire chain");
- return;
+ goto out;
}
/* backing_file string overrides base bs filename */
@@ -2004,10 +2009,13 @@ void qmp_block_stream(const char *device,
on_error, block_job_cb, bs, &local_err);
if (local_err) {
error_propagate(errp, local_err);
- return;
+ goto out;
}
trace_qmp_block_stream(bs, bs->job);
+
+out:
+ aio_context_release(aio_context);
}
void qmp_block_commit(const char *device,
--
1.9.3
- [Qemu-devel] [PULL 40/53] block/qcow2: Make get_refcount() global, (continued)
- [Qemu-devel] [PULL 40/53] block/qcow2: Make get_refcount() global, Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 41/53] block/qcow2: Simplify shared L2 handling in amend, Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 42/53] iotests: Expand test 061, Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 43/53] block: acquire AioContext in generic blockjob QMP commands, Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 44/53] blockdev: acquire AioContext in do_qmp_query_block_jobs_one(), Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 45/53] blockdev: acquire AioContext in blockdev_mark_auto_del(), Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 46/53] blockdev: add note that block_job_cb() must be thread-safe, Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 47/53] blockjob: add block_job_defer_to_main_loop(), Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 48/53] block: add bdrv_drain(), Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 49/53] block: let backup blockjob run in BDS AioContext, Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 50/53] block: let stream blockjob run in BDS AioContext,
Stefan Hajnoczi <=
- [Qemu-devel] [PULL 52/53] block: let commit blockjob run in BDS AioContext, Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 53/53] block: declare blockjobs and dataplane friends!, Stefan Hajnoczi, 2014/11/03
- [Qemu-devel] [PULL 51/53] block: let mirror blockjob run in BDS AioContext, Stefan Hajnoczi, 2014/11/03
- Re: [Qemu-devel] [PULL 00/53] Block patches, Peter Maydell, 2014/11/03