block: let stream blockjob run in BDS AioContext
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 <stefanha@redhat.com> Reviewed-by: Max Reitz <mreitz@redhat.com> Message-id: 1413889440-32577-9-git-send-email-stefanha@redhat.com
This commit is contained in:
parent
761731b180
commit
f3e69beb94
@ -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)
|
||||
|
16
blockdev.c
16
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,
|
||||
|
Loading…
Reference in New Issue
Block a user