aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2014-10-21 12:03:56 +0100
committerStefan Hajnoczi <stefanha@redhat.com>2014-11-03 11:41:49 +0000
commit761731b1805f6ef64eb615e5b82a0801db3cde78 (patch)
tree47ee44cc4f529564ab876b6e5038bdeb6b5fedff
parent5b98db0ad3ad2919c71572085d104765bad6c658 (diff)
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
-rw-r--r--block/backup.c21
-rw-r--r--blockdev.c23
2 files changed, 35 insertions, 9 deletions
diff --git a/block/backup.c b/block/backup.c
index e334740161..792e65514b 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -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,
diff --git a/blockdev.c b/blockdev.c
index 774051b44a..9c6898833b 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -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)