aboutsummaryrefslogtreecommitdiff
path: root/block/backup.c
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2016-10-27 12:48:50 +0200
committerFam Zheng <famz@redhat.com>2016-10-28 21:50:18 +0800
commitbae8196d9f97916de6323e70e3e374362ee16ec4 (patch)
treed733f20bed98d2ddaf2a66709fb81f20c9f31d2b /block/backup.c
parent50ab0e0908d592b8bda56c2d7495e1190d734b0b (diff)
blockjob: introduce .drain callback for jobs
This is required to decouple block jobs from running in an AioContext. With multiqueue block devices, a BlockDriverState does not really belong to a single AioContext. The solution is to first wait until all I/O operations are complete; then loop in the main thread for the block job to complete entirely. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Reviewed-by: Fam Zheng <famz@redhat.com> Message-Id: <1477565348-5458-3-git-send-email-pbonzini@redhat.com> Signed-off-by: Fam Zheng <famz@redhat.com>
Diffstat (limited to 'block/backup.c')
-rw-r--r--block/backup.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/block/backup.c b/block/backup.c
index 02dbe48035..81d4042ae8 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -300,6 +300,21 @@ void backup_cow_request_end(CowRequest *req)
cow_request_end(req);
}
+static void backup_drain(BlockJob *job)
+{
+ BackupBlockJob *s = container_of(job, BackupBlockJob, common);
+
+ /* Need to keep a reference in case blk_drain triggers execution
+ * of backup_complete...
+ */
+ if (s->target) {
+ BlockBackend *target = s->target;
+ blk_ref(target);
+ blk_drain(target);
+ blk_unref(target);
+ }
+}
+
static const BlockJobDriver backup_job_driver = {
.instance_size = sizeof(BackupBlockJob),
.job_type = BLOCK_JOB_TYPE_BACKUP,
@@ -307,6 +322,7 @@ static const BlockJobDriver backup_job_driver = {
.commit = backup_commit,
.abort = backup_abort,
.attached_aio_context = backup_attached_aio_context,
+ .drain = backup_drain,
};
static BlockErrorAction backup_error_action(BackupBlockJob *job,
@@ -331,6 +347,7 @@ static void backup_complete(BlockJob *job, void *opaque)
BackupCompleteData *data = opaque;
blk_unref(s->target);
+ s->target = NULL;
block_job_completed(job, data->ret);
g_free(data);