block: let backup blockjob run in BDS AioContext

The backup 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 completion code in block/backup.c must call bdrv_unref() from the
main loop.  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-8-git-send-email-stefanha@redhat.com
This commit is contained in:
Stefan Hajnoczi 2014-10-21 12:03:56 +01:00
parent 5b98db0ad3
commit 761731b180
2 changed files with 35 additions and 9 deletions

View File

@ -227,9 +227,25 @@ static BlockErrorAction backup_error_action(BackupBlockJob *job,
}
}
typedef struct {
int ret;
} BackupCompleteData;
static void backup_complete(BlockJob *job, void *opaque)
{
BackupBlockJob *s = container_of(job, BackupBlockJob, common);
BackupCompleteData *data = opaque;
bdrv_unref(s->target);
block_job_completed(job, data->ret);
g_free(data);
}
static void coroutine_fn backup_run(void *opaque)
{
BackupBlockJob *job = opaque;
BackupCompleteData *data;
BlockDriverState *bs = job->common.bs;
BlockDriverState *target = job->target;
BlockdevOnError on_target_error = job->on_target_error;
@ -344,9 +360,10 @@ static void coroutine_fn backup_run(void *opaque)
hbitmap_free(job->bitmap);
bdrv_iostatus_disable(target);
bdrv_unref(target);
block_job_completed(&job->common, ret);
data = g_malloc(sizeof(*data));
data->ret = ret;
block_job_defer_to_main_loop(&job->common, backup_complete, data);
}
void backup_start(BlockDriverState *bs, BlockDriverState *target,

View File

@ -2108,6 +2108,7 @@ void qmp_drive_backup(const char *device, const char *target,
BlockDriverState *bs;
BlockDriverState *target_bs;
BlockDriverState *source = NULL;
AioContext *aio_context;
BlockDriver *drv = NULL;
Error *local_err = NULL;
int flags;
@ -2133,9 +2134,12 @@ void qmp_drive_backup(const char *device, const char *target,
return;
}
aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
if (!bdrv_is_inserted(bs)) {
error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
return;
goto out;
}
if (!has_format) {
@ -2145,12 +2149,12 @@ void qmp_drive_backup(const char *device, const char *target,
drv = bdrv_find_format(format);
if (!drv) {
error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
return;
goto out;
}
}
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
return;
goto out;
}
flags = bs->open_flags | BDRV_O_RDWR;
@ -2170,7 +2174,7 @@ void qmp_drive_backup(const char *device, const char *target,
size = bdrv_getlength(bs);
if (size < 0) {
error_setg_errno(errp, -size, "bdrv_getlength failed");
return;
goto out;
}
if (mode != NEW_IMAGE_MODE_EXISTING) {
@ -2187,23 +2191,28 @@ void qmp_drive_backup(const char *device, const char *target,
if (local_err) {
error_propagate(errp, local_err);
return;
goto out;
}
target_bs = NULL;
ret = bdrv_open(&target_bs, target, NULL, NULL, flags, drv, &local_err);
if (ret < 0) {
error_propagate(errp, local_err);
return;
goto out;
}
bdrv_set_aio_context(target_bs, aio_context);
backup_start(bs, target_bs, speed, sync, on_source_error, on_target_error,
block_job_cb, bs, &local_err);
if (local_err != NULL) {
bdrv_unref(target_bs);
error_propagate(errp, local_err);
return;
goto out;
}
out:
aio_context_release(aio_context);
}
BlockDeviceInfoList *qmp_query_named_block_nodes(Error **errp)