diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2016-10-27 12:48:50 +0200 |
---|---|---|
committer | Fam Zheng <famz@redhat.com> | 2016-10-28 21:50:18 +0800 |
commit | bae8196d9f97916de6323e70e3e374362ee16ec4 (patch) | |
tree | d733f20bed98d2ddaf2a66709fb81f20c9f31d2b /block/backup.c | |
parent | 50ab0e0908d592b8bda56c2d7495e1190d734b0b (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.c | 17 |
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); |