mirror: implement completion
Switching to the target of the migration is done mostly asynchronously, and reported to management via the BLOCK_JOB_COMPLETED event; the only synchronous phase is opening the backing files. bdrv_open_backing_file can always be done, even for migration of the full image (aka sync: 'full'). In this case, qmp_drive_mirror will create the target disk with no backing file at all, and bdrv_open_backing_file will be a no-op. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
d9b902db3f
commit
d63ffd87ac
@ -32,6 +32,8 @@ typedef struct MirrorBlockJob {
|
||||
RateLimit limit;
|
||||
BlockDriverState *target;
|
||||
MirrorSyncMode mode;
|
||||
bool synced;
|
||||
bool should_complete;
|
||||
int64_t sector_num;
|
||||
uint8_t *buf;
|
||||
} MirrorBlockJob;
|
||||
@ -70,7 +72,6 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
int64_t sector_num, end;
|
||||
int ret = 0;
|
||||
int n;
|
||||
bool synced = false;
|
||||
|
||||
if (block_job_is_cancelled(&s->common)) {
|
||||
goto immediate_exit;
|
||||
@ -136,9 +137,14 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
* report completion. This way, block-job-cancel will leave
|
||||
* the target in a consistent state.
|
||||
*/
|
||||
synced = true;
|
||||
s->common.offset = end * BDRV_SECTOR_SIZE;
|
||||
should_complete = block_job_is_cancelled(&s->common);
|
||||
if (!s->synced) {
|
||||
block_job_ready(&s->common);
|
||||
s->synced = true;
|
||||
}
|
||||
|
||||
should_complete = s->should_complete ||
|
||||
block_job_is_cancelled(&s->common);
|
||||
cnt = bdrv_get_dirty_count(bs);
|
||||
}
|
||||
|
||||
@ -157,8 +163,8 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
trace_mirror_before_sleep(s, cnt, synced);
|
||||
if (!synced) {
|
||||
trace_mirror_before_sleep(s, cnt, s->synced);
|
||||
if (!s->synced) {
|
||||
/* Publish progress */
|
||||
s->common.offset = end * BDRV_SECTOR_SIZE - cnt * BLOCK_SIZE;
|
||||
|
||||
@ -191,6 +197,12 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
immediate_exit:
|
||||
g_free(s->buf);
|
||||
bdrv_set_dirty_tracking(bs, false);
|
||||
if (s->should_complete && ret == 0) {
|
||||
if (bdrv_get_flags(s->target) != bdrv_get_flags(s->common.bs)) {
|
||||
bdrv_reopen(s->target, bdrv_get_flags(s->common.bs), NULL);
|
||||
}
|
||||
bdrv_swap(s->target, s->common.bs);
|
||||
}
|
||||
bdrv_close(s->target);
|
||||
bdrv_delete(s->target);
|
||||
block_job_completed(&s->common, ret);
|
||||
@ -207,10 +219,33 @@ static void mirror_set_speed(BlockJob *job, int64_t speed, Error **errp)
|
||||
ratelimit_set_speed(&s->limit, speed / BDRV_SECTOR_SIZE, SLICE_TIME);
|
||||
}
|
||||
|
||||
static void mirror_complete(BlockJob *job, Error **errp)
|
||||
{
|
||||
MirrorBlockJob *s = container_of(job, MirrorBlockJob, common);
|
||||
int ret;
|
||||
|
||||
ret = bdrv_open_backing_file(s->target);
|
||||
if (ret < 0) {
|
||||
char backing_filename[PATH_MAX];
|
||||
bdrv_get_full_backing_filename(s->target, backing_filename,
|
||||
sizeof(backing_filename));
|
||||
error_set(errp, QERR_OPEN_FILE_FAILED, backing_filename);
|
||||
return;
|
||||
}
|
||||
if (!s->synced) {
|
||||
error_set(errp, QERR_BLOCK_JOB_NOT_READY, job->bs->device_name);
|
||||
return;
|
||||
}
|
||||
|
||||
s->should_complete = true;
|
||||
block_job_resume(job);
|
||||
}
|
||||
|
||||
static BlockJobType mirror_job_type = {
|
||||
.instance_size = sizeof(MirrorBlockJob),
|
||||
.job_type = "mirror",
|
||||
.set_speed = mirror_set_speed,
|
||||
.complete = mirror_complete,
|
||||
};
|
||||
|
||||
void mirror_start(BlockDriverState *bs, BlockDriverState *target,
|
||||
|
Loading…
Reference in New Issue
Block a user