Patchwork [26/32] mirror: implement completion

login
register
mail settings
Submitter Kevin Wolf
Date Oct. 24, 2012, 9:50 a.m.
Message ID <1351072256-6112-27-git-send-email-kwolf@redhat.com>
Download mbox | patch
Permalink /patch/193720/
State New
Headers show

Comments

Kevin Wolf - Oct. 24, 2012, 9:50 a.m.
From: Paolo Bonzini <pbonzini@redhat.com>

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>
---
 block/mirror.c |   45 ++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 40 insertions(+), 5 deletions(-)

Patch

diff --git a/block/mirror.c b/block/mirror.c
index b353798..6320f6a 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -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,