On Wed, 12/16 19:33, Paolo Bonzini wrote: > Ensure that the guest does not write anything to disk after cnt is > read for the final time. > > Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> > --- > Untested. > > block/mirror.c | 22 +++++++++++----------- > 1 file changed, 11 insertions(+), 11 deletions(-) > > diff --git a/block/mirror.c b/block/mirror.c > index 0e8f556..e57c246 100644 > --- a/block/mirror.c > +++ b/block/mirror.c > @@ -562,8 +562,18 @@ static void coroutine_fn mirror_run(void *opaque) > * mirror_populate runs. > */ > trace_mirror_before_drain(s, cnt); > - bdrv_drain(bs); > + bdrv_drained_begin(s->common.bs); > cnt = bdrv_get_dirty_count(s->dirty_bitmap); > + > + if (cnt == 0) { > + /* The two disks are in sync. Exit and report successful > + * completion. > + */ > + assert(QLIST_EMPTY(&bs->tracked_requests)); > + s->common.cancelled = false; > + break; > + } > + bdrv_drained_end(s->common.bs); > } > > ret = 0; > @@ -576,13 +586,6 @@ static void coroutine_fn mirror_run(void *opaque) > } else if (!should_complete) { > delay_ns = (s->in_flight == 0 && cnt == 0 ? SLICE_TIME : 0); > block_job_sleep_ns(&s->common, QEMU_CLOCK_REALTIME, delay_ns); > - } else if (cnt == 0) { > - /* The two disks are in sync. Exit and report successful > - * completion. > - */ > - assert(QLIST_EMPTY(&bs->tracked_requests)); > - s->common.cancelled = false; > - break; > } > last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); > } > @@ -608,9 +611,6 @@ immediate_exit: > > data = g_malloc(sizeof(*data)); > data->ret = ret; > - /* Before we switch to target in mirror_exit, make sure data doesn't > - * change. */ > - bdrv_drained_begin(s->common.bs); > block_job_defer_to_main_loop(&s->common, mirror_exit, data); > }
bdrv_drained_begin was unconditional to balance with the one in mirror_exit, but now it is only called if cnt == 0. Squashing this in fixes it: diff --git a/block/mirror.c b/block/mirror.c index e57c246..a814929 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -62,6 +62,7 @@ typedef struct MirrorBlockJob { int ret; bool unmap; bool waiting_for_io; + bool drained_begin; } MirrorBlockJob; typedef struct MirrorOp { @@ -355,6 +356,7 @@ static void mirror_exit(BlockJob *job, void *opaque) MirrorExitData *data = opaque; AioContext *replace_aio_context = NULL; BlockDriverState *src = s->common.bs; + bool drained_begin = s->drained_begin; /* Make sure that the source BDS doesn't go away before we called * block_job_completed(). */ @@ -388,7 +390,9 @@ static void mirror_exit(BlockJob *job, void *opaque) bdrv_unref(s->target); block_job_completed(&s->common, data->ret); g_free(data); - bdrv_drained_end(src); + if (drained_begin) { + bdrv_drained_end(src); + } bdrv_unref(src); } @@ -571,6 +575,7 @@ static void coroutine_fn mirror_run(void *opaque) */ assert(QLIST_EMPTY(&bs->tracked_requests)); s->common.cancelled = false; + s->drained_begin = true; break; } bdrv_drained_end(s->common.bs);