[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v2 08/11] block: let stream blockjob run in BDS AioC
From: |
Stefan Hajnoczi |
Subject: |
[Qemu-devel] [PATCH v2 08/11] block: let stream blockjob run in BDS AioContext |
Date: |
Tue, 21 Oct 2014 12:03:57 +0100 |
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>
---
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 cdea3e8..21bce12 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 f2ee6e9..5d905ce 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1987,6 +1987,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;
@@ -2000,16 +2001,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;
}
@@ -2018,7 +2023,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 */
@@ -2028,10 +2033,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] [PATCH v2 02/11] blockdev: acquire AioContext in do_qmp_query_block_jobs_one(), (continued)
- [Qemu-devel] [PATCH v2 02/11] blockdev: acquire AioContext in do_qmp_query_block_jobs_one(), Stefan Hajnoczi, 2014/10/21
- [Qemu-devel] [PATCH v2 03/11] blockdev: acquire AioContext in blockdev_mark_auto_del(), Stefan Hajnoczi, 2014/10/21
- [Qemu-devel] [PATCH v2 04/11] blockdev: add note that block_job_cb() must be thread-safe, Stefan Hajnoczi, 2014/10/21
- [Qemu-devel] [PATCH v2 05/11] blockjob: add block_job_defer_to_main_loop(), Stefan Hajnoczi, 2014/10/21
- [Qemu-devel] [PATCH v2 06/11] block: add bdrv_drain(), Stefan Hajnoczi, 2014/10/21
- [Qemu-devel] [PATCH v2 07/11] block: let backup blockjob run in BDS AioContext, Stefan Hajnoczi, 2014/10/21
- [Qemu-devel] [PATCH v2 09/11] block: let mirror blockjob run in BDS AioContext, Stefan Hajnoczi, 2014/10/21
- [Qemu-devel] [PATCH v2 08/11] block: let stream blockjob run in BDS AioContext,
Stefan Hajnoczi <=
- [Qemu-devel] [PATCH v2 10/11] block: let commit blockjob run in BDS AioContext, Stefan Hajnoczi, 2014/10/21
- [Qemu-devel] [PATCH v2 11/11] block: declare blockjobs and dataplane friends!, Stefan Hajnoczi, 2014/10/21
- Re: [Qemu-devel] [PATCH v2 00/11] block: allow blockjobs to coexist with dataplane, Stefan Hajnoczi, 2014/10/29