On Wed, May 14, 2025 at 05:09:14PM -0500, Eric Blake wrote:
> On Fri, May 09, 2025 at 03:40:26PM -0500, Eric Blake wrote:
> > The two callers to a mirror job (drive-mirror and blockdev-mirror) set
> > zero_target precisely when sync mode == FULL, with the one exception
> > that drive-mirror skips zeroing the target if it was newly created and
> > reads as zero.  But given the previous patch, that exception is
> > equally captured by target_is_zero.  And since we recently updated
> > things to pass the sync mode all the way through to
> > mirror_dirty_init(), we can now reconstruct the same conditionals
> > without the redundant parameter.
> > 
> > Signed-off-by: Eric Blake <ebl...@redhat.com>
> > 
> > ---
> > 
> > v4: new patch
> 
> I was about to send the pull request, and noticed that this patch
> reliably makes iotest 185 fail:
> 
>  {"return": {}}
> -{"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": 
> "BLOCK_JOB_READY", "data": {"device": "mirror", "len": 0, "offset": 0, 
> "speed": 0, "type": "mirror"}}
> ---- Writing data to the virtio-blk device ---
> ...
> -*** done
> +Timeout waiting for event BLOCK_JOB_READY on handle 5
> Failures: 185
> 
> 
> Investigating now...

Oh, that was extremely subtle.

Pre-patch, zero_target is set to false while sync == SYNC_TOP prior to
calling blockdev.c:blockdev_mirror_common().  But in that function, we
were forcefully slamming sync to MIRROR_SYNC_MODE_FULL if
bdrv_backing_chain_next(bs) == NULL.  Once zero_target is no longer
available, that means any mirror job using "sync":"top" but with no
backing image (which is effectively syncing the entire chain) now
defaults to pre-zeroing - and since 185 intentionally throttles
things, the newly-triggered pre-zeroing takes so long that the test
times out.

Fortunately, an examination of all places in mirror.c that care about
sync_mode TOP vs FULL shows that prior to this series, they were
mostly treated identically everywhere (only zero_target mattered)
thanks to the is_none_mode bool.  The lone exception was in
mirror_start, with this statement:

    base = mode == MIRROR_SYNC_MODE_TOP ? bdrv_backing_chain_next(bs) : NULL;

but we know that the caller slammed mode to MODE_FULL precisely if it
used to be TOP and bdrv_backing_chain_next(bs) == NULL.  So if the
caller doesn't slam sync to FULL, this ternary still sets base to the
same value.  And we are back to skipping the pre-zeroing pass for
"sync":"top", the way test 185 wants.

Hence, I'm squashing this in, and preparing the pull request.

diff --git i/blockdev.c w/blockdev.c
index 93d403d8210..21443b45144 100644
--- i/blockdev.c
+++ w/blockdev.c
@@ -2871,10 +2871,6 @@ static void blockdev_mirror_common(const char *job_id, 
BlockDriverState *bs,
         return;
     }

-    if (!bdrv_backing_chain_next(bs) && sync == MIRROR_SYNC_MODE_TOP) {
-        sync = MIRROR_SYNC_MODE_FULL;
-    }
-
     if (!replaces) {
         /* We want to mirror from @bs, but keep implicit filters on top */
         unfiltered_bs = bdrv_skip_implicit_filters(bs);



-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.
Virtualization:  qemu.org | libguestfs.org


Reply via email to