Commit cdf3bc93 authored by Max Reitz's avatar Max Reitz
Browse files

mirror: Fix bdrv_has_zero_init() use



bdrv_has_zero_init() only has meaning for newly created images or image
areas.  If the mirror job itself did not create the image, it cannot
rely on bdrv_has_zero_init()'s result to carry any meaning.

This is the case for drive-mirror with mode=existing and always for
blockdev-mirror.

Note that we only have to zero-initialize the target with sync=full,
because other modes actually do not promise that the target will contain
the same data as the source after the job -- sync=top only promises to
copy anything allocated in the top layer, and sync=none will only copy
new I/O.  (Which is how mirror has always handled it.)

Signed-off-by: default avatarMax Reitz <mreitz@redhat.com>
Message-id: 20190724171239.8764-3-mreitz@redhat.com
Reviewed-by: default avatarMaxim Levitsky <mlevitsk@redhat.com>
Signed-off-by: default avatarMax Reitz <mreitz@redhat.com>
parent 4d7c487e
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -51,6 +51,8 @@ typedef struct MirrorBlockJob {
    Error *replace_blocker;
    bool is_none_mode;
    BlockMirrorBackingMode backing_mode;
    /* Whether the target image requires explicit zero-initialization */
    bool zero_target;
    MirrorCopyMode copy_mode;
    BlockdevOnError on_source_error, on_target_error;
    bool synced;
@@ -767,7 +769,7 @@ static int coroutine_fn mirror_dirty_init(MirrorBlockJob *s)
    int ret;
    int64_t count;

    if (base == NULL && !bdrv_has_zero_init(target_bs)) {
    if (s->zero_target) {
        if (!bdrv_can_write_zeroes_with_unmap(target_bs)) {
            bdrv_set_dirty_bitmap(s->dirty_bitmap, 0, s->bdev_length);
            return 0;
@@ -1515,6 +1517,7 @@ static BlockJob *mirror_start_job(
                             const char *replaces, int64_t speed,
                             uint32_t granularity, int64_t buf_size,
                             BlockMirrorBackingMode backing_mode,
                             bool zero_target,
                             BlockdevOnError on_source_error,
                             BlockdevOnError on_target_error,
                             bool unmap,
@@ -1643,6 +1646,7 @@ static BlockJob *mirror_start_job(
    s->on_target_error = on_target_error;
    s->is_none_mode = is_none_mode;
    s->backing_mode = backing_mode;
    s->zero_target = zero_target;
    s->copy_mode = copy_mode;
    s->base = base;
    s->granularity = granularity;
@@ -1747,6 +1751,7 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
                  int creation_flags, int64_t speed,
                  uint32_t granularity, int64_t buf_size,
                  MirrorSyncMode mode, BlockMirrorBackingMode backing_mode,
                  bool zero_target,
                  BlockdevOnError on_source_error,
                  BlockdevOnError on_target_error,
                  bool unmap, const char *filter_node_name,
@@ -1764,7 +1769,7 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
    is_none_mode = mode == MIRROR_SYNC_MODE_NONE;
    base = mode == MIRROR_SYNC_MODE_TOP ? backing_bs(bs) : NULL;
    mirror_start_job(job_id, bs, creation_flags, target, replaces,
                     speed, granularity, buf_size, backing_mode,
                     speed, granularity, buf_size, backing_mode, zero_target,
                     on_source_error, on_target_error, unmap, NULL, NULL,
                     &mirror_job_driver, is_none_mode, base, false,
                     filter_node_name, true, copy_mode, errp);
@@ -1791,7 +1796,7 @@ BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs,

    ret = mirror_start_job(
                     job_id, bs, creation_flags, base, NULL, speed, 0, 0,
                     MIRROR_LEAVE_BACKING_CHAIN,
                     MIRROR_LEAVE_BACKING_CHAIN, false,
                     on_error, on_error, true, cb, opaque,
                     &commit_active_job_driver, false, base, auto_complete,
                     filter_node_name, false, MIRROR_COPY_MODE_BACKGROUND,
+13 −3
Original line number Diff line number Diff line
@@ -3782,6 +3782,7 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
                                   bool has_replaces, const char *replaces,
                                   enum MirrorSyncMode sync,
                                   BlockMirrorBackingMode backing_mode,
                                   bool zero_target,
                                   bool has_speed, int64_t speed,
                                   bool has_granularity, uint32_t granularity,
                                   bool has_buf_size, int64_t buf_size,
@@ -3890,7 +3891,7 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
     */
    mirror_start(job_id, bs, target,
                 has_replaces ? replaces : NULL, job_flags,
                 speed, granularity, buf_size, sync, backing_mode,
                 speed, granularity, buf_size, sync, backing_mode, zero_target,
                 on_source_error, on_target_error, unmap, filter_node_name,
                 copy_mode, errp);
}
@@ -3906,6 +3907,7 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
    int flags;
    int64_t size;
    const char *format = arg->format;
    bool zero_target;
    int ret;

    bs = qmp_get_root_bs(arg->device, errp);
@@ -4007,6 +4009,10 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)
        goto out;
    }

    zero_target = (arg->sync == MIRROR_SYNC_MODE_FULL &&
                   (arg->mode == NEW_IMAGE_MODE_EXISTING ||
                    !bdrv_has_zero_init(target_bs)));

    ret = bdrv_try_set_aio_context(target_bs, aio_context, errp);
    if (ret < 0) {
        bdrv_unref(target_bs);
@@ -4015,7 +4021,8 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp)

    blockdev_mirror_common(arg->has_job_id ? arg->job_id : NULL, bs, target_bs,
                           arg->has_replaces, arg->replaces, arg->sync,
                           backing_mode, arg->has_speed, arg->speed,
                           backing_mode, zero_target,
                           arg->has_speed, arg->speed,
                           arg->has_granularity, arg->granularity,
                           arg->has_buf_size, arg->buf_size,
                           arg->has_on_source_error, arg->on_source_error,
@@ -4055,6 +4062,7 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,
    AioContext *aio_context;
    BlockMirrorBackingMode backing_mode = MIRROR_LEAVE_BACKING_CHAIN;
    Error *local_err = NULL;
    bool zero_target;
    int ret;

    bs = qmp_get_root_bs(device, errp);
@@ -4067,6 +4075,8 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,
        return;
    }

    zero_target = (sync == MIRROR_SYNC_MODE_FULL);

    aio_context = bdrv_get_aio_context(bs);
    aio_context_acquire(aio_context);

@@ -4077,7 +4087,7 @@ void qmp_blockdev_mirror(bool has_job_id, const char *job_id,

    blockdev_mirror_common(has_job_id ? job_id : NULL, bs, target_bs,
                           has_replaces, replaces, sync, backing_mode,
                           has_speed, speed,
                           zero_target, has_speed, speed,
                           has_granularity, granularity,
                           has_buf_size, buf_size,
                           has_on_source_error, on_source_error,
+2 −0
Original line number Diff line number Diff line
@@ -1115,6 +1115,7 @@ BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs,
 * @buf_size: The amount of data that can be in flight at one time.
 * @mode: Whether to collapse all images in the chain to the target.
 * @backing_mode: How to establish the target's backing chain after completion.
 * @zero_target: Whether the target should be explicitly zero-initialized
 * @on_source_error: The action to take upon error reading from the source.
 * @on_target_error: The action to take upon error writing to the target.
 * @unmap: Whether to unmap target where source sectors only contain zeroes.
@@ -1134,6 +1135,7 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
                  int creation_flags, int64_t speed,
                  uint32_t granularity, int64_t buf_size,
                  MirrorSyncMode mode, BlockMirrorBackingMode backing_mode,
                  bool zero_target,
                  BlockdevOnError on_source_error,
                  BlockdevOnError on_target_error,
                  bool unmap, const char *filter_node_name,
+1 −1
Original line number Diff line number Diff line
@@ -612,7 +612,7 @@ static void test_propagate_mirror(void)

    /* Start a mirror job */
    mirror_start("job0", src, target, NULL, JOB_DEFAULT, 0, 0, 0,
                 MIRROR_SYNC_MODE_NONE, MIRROR_OPEN_BACKING_CHAIN,
                 MIRROR_SYNC_MODE_NONE, MIRROR_OPEN_BACKING_CHAIN, false,
                 BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT,
                 false, "filter_node", MIRROR_COPY_MODE_BACKGROUND,
                 &error_abort);