void qmp_drive_mirror(const char *device, const char *target,

                      bool has_format, const char *format,

                      bool has_node_name, const char *node_name,

                      bool has_replaces, const char *replaces,

                      enum MirrorSyncMode sync,

                      bool has_mode, enum NewImageMode mode,

                      bool has_speed, int64_t speed,

                      bool has_granularity, uint32_t granularity,

                      bool has_buf_size, int64_t buf_size,

                      bool has_on_source_error, BlockdevOnError on_source_error,

                      bool has_on_target_error, BlockdevOnError on_target_error,

                      Error **errp)

{

    BlockDriverState *bs;

    BlockDriverState *source, *target_bs;

    BlockDriver *drv = NULL;

    Error *local_err = NULL;

    QDict *options = NULL;

    int flags;

    int64_t size;

    int ret;



    if (!has_speed) {

        speed = 0;

    }

    if (!has_on_source_error) {

        on_source_error = BLOCKDEV_ON_ERROR_REPORT;

    }

    if (!has_on_target_error) {

        on_target_error = BLOCKDEV_ON_ERROR_REPORT;

    }

    if (!has_mode) {

        mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;

    }

    if (!has_granularity) {

        granularity = 0;

    }

    if (!has_buf_size) {

        buf_size = DEFAULT_MIRROR_BUF_SIZE;

    }



    if (granularity != 0 && (granularity < 512 || granularity > 1048576 * 64)) {

        error_set(errp, QERR_INVALID_PARAMETER_VALUE, "granularity",

                  "a value in range [512B, 64MB]");

        return;

    }

    if (granularity & (granularity - 1)) {

        error_set(errp, QERR_INVALID_PARAMETER_VALUE, "granularity", "power of 2");

        return;

    }



    bs = bdrv_find(device);

    if (!bs) {

        error_set(errp, QERR_DEVICE_NOT_FOUND, device);

        return;

    }



    if (!bdrv_is_inserted(bs)) {

        error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);

        return;

    }



    if (!has_format) {

        format = mode == NEW_IMAGE_MODE_EXISTING ? NULL : bs->drv->format_name;

    }

    if (format) {

        drv = bdrv_find_format(format);

        if (!drv) {

            error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);

            return;

        }

    }



    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR, errp)) {

        return;

    }



    flags = bs->open_flags | BDRV_O_RDWR;

    source = bs->backing_hd;

    if (!source && sync == MIRROR_SYNC_MODE_TOP) {

        sync = MIRROR_SYNC_MODE_FULL;

    }

    if (sync == MIRROR_SYNC_MODE_NONE) {

        source = bs;

    }



    size = bdrv_getlength(bs);

    if (size < 0) {

        error_setg_errno(errp, -size, "bdrv_getlength failed");

        return;

    }



    if (has_replaces) {

        BlockDriverState *to_replace_bs;



        if (!has_node_name) {

            error_setg(errp, "a node-name must be provided when replacing a"

                             " named node of the graph");

            return;

        }



        to_replace_bs = check_to_replace_node(replaces, &local_err);



        if (!to_replace_bs) {

            error_propagate(errp, local_err);

            return;

        }



        if (size != bdrv_getlength(to_replace_bs)) {

            error_setg(errp, "cannot replace image with a mirror image of "

                             "different size");

            return;

        }

    }



    if ((sync == MIRROR_SYNC_MODE_FULL || !source)

        && mode != NEW_IMAGE_MODE_EXISTING)

    {

        /* create new image w/o backing file */

        assert(format && drv);

        bdrv_img_create(target, format,

                        NULL, NULL, NULL, size, flags, &local_err, false);

    } else {

        switch (mode) {

        case NEW_IMAGE_MODE_EXISTING:

            break;

        case NEW_IMAGE_MODE_ABSOLUTE_PATHS:

            /* create new image with backing file */

            bdrv_img_create(target, format,

                            source->filename,

                            source->drv->format_name,

                            NULL, size, flags, &local_err, false);

            break;

        default:

            abort();

        }

    }



    if (local_err) {

        error_propagate(errp, local_err);

        return;

    }



    if (has_node_name) {

        options = qdict_new();

        qdict_put(options, "node-name", qstring_from_str(node_name));

    }



    /* Mirroring takes care of copy-on-write using the source's backing

     * file.

     */

    target_bs = NULL;

    ret = bdrv_open(&target_bs, target, NULL, options,

                    flags | BDRV_O_NO_BACKING, drv, &local_err);

    if (ret < 0) {

        error_propagate(errp, local_err);

        return;

    }



    /* pass the node name to replace to mirror start since it's loose coupling

     * and will allow to check whether the node still exist at mirror completion

     */

    mirror_start(bs, target_bs,

                 has_replaces ? replaces : NULL,

                 speed, granularity, buf_size, sync,

                 on_source_error, on_target_error,

                 block_job_cb, bs, &local_err);

    if (local_err != NULL) {

        bdrv_unref(target_bs);

        error_propagate(errp, local_err);

        return;

    }

}

void qmp_drive_mirror(const char *device, const char *target,

                      bool has_format, const char *format,

                      bool has_node_name, const char *node_name,

                      bool has_replaces, const char *replaces,

                      enum MirrorSyncMode sync,

                      bool has_mode, enum NewImageMode mode,

                      bool has_speed, int64_t speed,

                      bool has_granularity, uint32_t granularity,

                      bool has_buf_size, int64_t buf_size,

                      bool has_on_source_error, BlockdevOnError on_source_error,

                      bool has_on_target_error, BlockdevOnError on_target_error,

                      Error **errp)

{

    BlockDriverState *bs;

    BlockDriverState *source, *target_bs;

    BlockDriver *drv = NULL;

    Error *local_err = NULL;

    QDict *options = NULL;

    int flags;

    int64_t size;

    int ret;



    if (!has_speed) {

        speed = 0;

    }

    if (!has_on_source_error) {

        on_source_error = BLOCKDEV_ON_ERROR_REPORT;

    }

    if (!has_on_target_error) {

        on_target_error = BLOCKDEV_ON_ERROR_REPORT;

    }

    if (!has_mode) {

        mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;

    }

    if (!has_granularity) {

        granularity = 0;

    }

    if (!has_buf_size) {

        buf_size = DEFAULT_MIRROR_BUF_SIZE;

    }



    if (granularity != 0 && (granularity < 512 || granularity > 1048576 * 64)) {

        error_set(errp, QERR_INVALID_PARAMETER_VALUE, "granularity",

                  "a value in range [512B, 64MB]");

        return;

    }

    if (granularity & (granularity - 1)) {

        error_set(errp, QERR_INVALID_PARAMETER_VALUE, "granularity", "power of 2");

        return;

    }



    bs = bdrv_find(device);

    if (!bs) {

        error_set(errp, QERR_DEVICE_NOT_FOUND, device);

        return;

    }



    if (!bdrv_is_inserted(bs)) {

        error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);

        return;

    }



    if (!has_format) {

        format = mode == NEW_IMAGE_MODE_EXISTING ? NULL : bs->drv->format_name;

    }

    if (format) {

        drv = bdrv_find_format(format);

        if (!drv) {

            error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);

            return;

        }

    }



    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR, errp)) {

        return;

    }



    flags = bs->open_flags | BDRV_O_RDWR;

    source = bs->backing_hd;

    if (!source && sync == MIRROR_SYNC_MODE_TOP) {

        sync = MIRROR_SYNC_MODE_FULL;

    }

    if (sync == MIRROR_SYNC_MODE_NONE) {

        source = bs;

    }



    size = bdrv_getlength(bs);

    if (size < 0) {

        error_setg_errno(errp, -size, "bdrv_getlength failed");

        return;

    }



    if (has_replaces) {

        BlockDriverState *to_replace_bs;



        if (!has_node_name) {

            error_setg(errp, "a node-name must be provided when replacing a"

                             " named node of the graph");

            return;

        }



        to_replace_bs = check_to_replace_node(replaces, &local_err);



        if (!to_replace_bs) {

            error_propagate(errp, local_err);

            return;

        }



        if (size != bdrv_getlength(to_replace_bs)) {

            error_setg(errp, "cannot replace image with a mirror image of "

                             "different size");

            return;

        }

    }



    if ((sync == MIRROR_SYNC_MODE_FULL || !source)

        && mode != NEW_IMAGE_MODE_EXISTING)

    {

        

        assert(format && drv);

        bdrv_img_create(target, format,

                        NULL, NULL, NULL, size, flags, &local_err, false);

    } else {

        switch (mode) {

        case NEW_IMAGE_MODE_EXISTING:

            break;

        case NEW_IMAGE_MODE_ABSOLUTE_PATHS:

            

            bdrv_img_create(target, format,

                            source->filename,

                            source->drv->format_name,

                            NULL, size, flags, &local_err, false);

            break;

        default:

            abort();

        }

    }



    if (local_err) {

        error_propagate(errp, local_err);

        return;

    }



    if (has_node_name) {

        options = qdict_new();

        qdict_put(options, "node-name", qstring_from_str(node_name));

    }



    





    target_bs = NULL;

    ret = bdrv_open(&target_bs, target, NULL, options,

                    flags | BDRV_O_NO_BACKING, drv, &local_err);

    if (ret < 0) {

        error_propagate(errp, local_err);

        return;

    }



    





    mirror_start(bs, target_bs,

                 has_replaces ? replaces : NULL,

                 speed, granularity, buf_size, sync,

                 on_source_error, on_target_error,

                 block_job_cb, bs, &local_err);

    if (local_err != NULL) {

        bdrv_unref(target_bs);

        error_propagate(errp, local_err);

        return;

    }

}

void FUNC_0(const char *VAR_0, const char *VAR_1,

                      bool VAR_2, const char *VAR_3,

                      bool VAR_4, const char *VAR_5,

                      bool VAR_6, const char *VAR_7,

                      enum MirrorSyncMode VAR_8,

                      bool VAR_9, enum NewImageMode VAR_10,

                      bool VAR_11, int64_t VAR_12,

                      bool VAR_13, uint32_t VAR_14,

                      bool VAR_15, int64_t VAR_16,

                      bool VAR_17, BlockdevOnError VAR_18,

                      bool VAR_19, BlockdevOnError VAR_20,

                      Error **VAR_21)

{

    BlockDriverState *bs;

    BlockDriverState *source, *target_bs;

    BlockDriver *drv = NULL;

    Error *local_err = NULL;

    QDict *options = NULL;

    int VAR_22;

    int64_t size;

    int VAR_23;



    if (!VAR_11) {

        VAR_12 = 0;

    }

    if (!VAR_17) {

        VAR_18 = BLOCKDEV_ON_ERROR_REPORT;

    }

    if (!VAR_19) {

        VAR_20 = BLOCKDEV_ON_ERROR_REPORT;

    }

    if (!VAR_9) {

        VAR_10 = NEW_IMAGE_MODE_ABSOLUTE_PATHS;

    }

    if (!VAR_13) {

        VAR_14 = 0;

    }

    if (!VAR_15) {

        VAR_16 = DEFAULT_MIRROR_BUF_SIZE;

    }



    if (VAR_14 != 0 && (VAR_14 < 512 || VAR_14 > 1048576 * 64)) {

        error_set(VAR_21, QERR_INVALID_PARAMETER_VALUE, "VAR_14",

                  "a value in range [512B, 64MB]");

        return;

    }

    if (VAR_14 & (VAR_14 - 1)) {

        error_set(VAR_21, QERR_INVALID_PARAMETER_VALUE, "VAR_14", "power of 2");

        return;

    }



    bs = bdrv_find(VAR_0);

    if (!bs) {

        error_set(VAR_21, QERR_DEVICE_NOT_FOUND, VAR_0);

        return;

    }



    if (!bdrv_is_inserted(bs)) {

        error_set(VAR_21, QERR_DEVICE_HAS_NO_MEDIUM, VAR_0);

        return;

    }



    if (!VAR_2) {

        VAR_3 = VAR_10 == NEW_IMAGE_MODE_EXISTING ? NULL : bs->drv->format_name;

    }

    if (VAR_3) {

        drv = bdrv_find_format(VAR_3);

        if (!drv) {

            error_set(VAR_21, QERR_INVALID_BLOCK_FORMAT, VAR_3);

            return;

        }

    }



    if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR, VAR_21)) {

        return;

    }



    VAR_22 = bs->open_flags | BDRV_O_RDWR;

    source = bs->backing_hd;

    if (!source && VAR_8 == MIRROR_SYNC_MODE_TOP) {

        VAR_8 = MIRROR_SYNC_MODE_FULL;

    }

    if (VAR_8 == MIRROR_SYNC_MODE_NONE) {

        source = bs;

    }



    size = bdrv_getlength(bs);

    if (size < 0) {

        error_setg_errno(VAR_21, -size, "bdrv_getlength failed");

        return;

    }



    if (VAR_6) {

        BlockDriverState *to_replace_bs;



        if (!VAR_4) {

            error_setg(VAR_21, "a node-name must be provided when replacing a"

                             " named node of the graph");

            return;

        }



        to_replace_bs = check_to_replace_node(VAR_7, &local_err);



        if (!to_replace_bs) {

            error_propagate(VAR_21, local_err);

            return;

        }



        if (size != bdrv_getlength(to_replace_bs)) {

            error_setg(VAR_21, "cannot replace image with a mirror image of "

                             "different size");

            return;

        }

    }



    if ((VAR_8 == MIRROR_SYNC_MODE_FULL || !source)

        && VAR_10 != NEW_IMAGE_MODE_EXISTING)

    {

        

        assert(VAR_3 && drv);

        bdrv_img_create(VAR_1, VAR_3,

                        NULL, NULL, NULL, size, VAR_22, &local_err, false);

    } else {

        switch (VAR_10) {

        case NEW_IMAGE_MODE_EXISTING:

            break;

        case NEW_IMAGE_MODE_ABSOLUTE_PATHS:

            

            bdrv_img_create(VAR_1, VAR_3,

                            source->filename,

                            source->drv->format_name,

                            NULL, size, VAR_22, &local_err, false);

            break;

        default:

            abort();

        }

    }



    if (local_err) {

        error_propagate(VAR_21, local_err);

        return;

    }



    if (VAR_4) {

        options = qdict_new();

        qdict_put(options, "node-name", qstring_from_str(VAR_5));

    }



    





    target_bs = NULL;

    VAR_23 = bdrv_open(&target_bs, VAR_1, NULL, options,

                    VAR_22 | BDRV_O_NO_BACKING, drv, &local_err);

    if (VAR_23 < 0) {

        error_propagate(VAR_21, local_err);

        return;

    }



    





    mirror_start(bs, target_bs,

                 VAR_6 ? VAR_7 : NULL,

                 VAR_12, VAR_14, VAR_16, VAR_8,

                 VAR_18, VAR_20,

                 block_job_cb, bs, &local_err);

    if (local_err != NULL) {

        bdrv_unref(target_bs);

        error_propagate(VAR_21, local_err);

        return;

    }

}

void FUNC_0(const char *VAR_0, const char *VAR_1,
bool VAR_2, const char *VAR_3,
bool VAR_4, const char *VAR_5,
bool VAR_6, const char *VAR_7,
enum MirrorSyncMode VAR_8,
bool VAR_9, enum NewImageMode VAR_10,
bool VAR_11, int64_t VAR_12,
bool VAR_13, uint32_t VAR_14,
bool VAR_15, int64_t VAR_16,
bool VAR_17, BlockdevOnError VAR_18,
bool VAR_19, BlockdevOnError VAR_20,
Error **VAR_21)
{ BlockDriverState *bs; BlockDriverState *source, *target_bs; BlockDriver *drv = NULL; Error *local_err = NULL; QDict *options = NULL; int VAR_22; int64_t size; int VAR_23; if (!VAR_11) { VAR_12 = 0; } if (!VAR_17) { VAR_18 = BLOCKDEV_ON_ERROR_REPORT; } if (!VAR_19) { VAR_20 = BLOCKDEV_ON_ERROR_REPORT; } if (!VAR_9) { VAR_10 = NEW_IMAGE_MODE_ABSOLUTE_PATHS; } if (!VAR_13) { VAR_14 = 0; } if (!VAR_15) { VAR_16 = DEFAULT_MIRROR_BUF_SIZE; } if (VAR_14 != 0 && (VAR_14 < 512 || VAR_14 > 1048576 * 64)) { error_set(VAR_21, QERR_INVALID_PARAMETER_VALUE, "VAR_14",
"a value in range [512B, 64MB]"); return; } if (VAR_14 & (VAR_14 - 1)) { error_set(VAR_21, QERR_INVALID_PARAMETER_VALUE, "VAR_14", "power of 2"); return; } bs = bdrv_find(VAR_0); if (!bs) { error_set(VAR_21, QERR_DEVICE_NOT_FOUND, VAR_0); return; } if (!bdrv_is_inserted(bs)) { error_set(VAR_21, QERR_DEVICE_HAS_NO_MEDIUM, VAR_0); return; } if (!VAR_2) { VAR_3 = VAR_10 == NEW_IMAGE_MODE_EXISTING ? NULL : bs->drv->format_name; } if (VAR_3) { drv = bdrv_find_format(VAR_3); if (!drv) { error_set(VAR_21, QERR_INVALID_BLOCK_FORMAT, VAR_3); return; } } if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR, VAR_21)) { return; } VAR_22 = bs->open_flags | BDRV_O_RDWR; source = bs->backing_hd; if (!source && VAR_8 == MIRROR_SYNC_MODE_TOP) { VAR_8 = MIRROR_SYNC_MODE_FULL; } if (VAR_8 == MIRROR_SYNC_MODE_NONE) { source = bs; } size = bdrv_getlength(bs); if (size < 0) { error_setg_errno(VAR_21, -size, "bdrv_getlength failed"); return; } if (VAR_6) { BlockDriverState *to_replace_bs; if (!VAR_4) { error_setg(VAR_21, "a node-name must be provided when replacing a"
" named node of the graph"); return; } to_replace_bs = check_to_replace_node(VAR_7, &local_err); if (!to_replace_bs) { error_propagate(VAR_21, local_err); return; } if (size != bdrv_getlength(to_replace_bs)) { error_setg(VAR_21, "cannot replace image with a mirror image of "
"different size"); return; } } if ((VAR_8 == MIRROR_SYNC_MODE_FULL || !source)
&& VAR_10 != NEW_IMAGE_MODE_EXISTING)
{ assert(VAR_3 && drv); bdrv_img_create(VAR_1, VAR_3,
NULL, NULL, NULL, size, VAR_22, &local_err, false); } else { switch (VAR_10) { case NEW_IMAGE_MODE_EXISTING:
break; case NEW_IMAGE_MODE_ABSOLUTE_PATHS:
bdrv_img_create(VAR_1, VAR_3,
source->filename,
source->drv->format_name,
NULL, size, VAR_22, &local_err, false); break; default:
abort(); } } if (local_err) { error_propagate(VAR_21, local_err); return; } if (VAR_4) { options = qdict_new(); qdict_put(options, "node-name", qstring_from_str(VAR_5)); } target_bs = NULL; VAR_23 = bdrv_open(&target_bs, VAR_1, NULL, options,
VAR_22 | BDRV_O_NO_BACKING, drv, &local_err); if (VAR_23 < 0) { error_propagate(VAR_21, local_err); return; } mirror_start(bs, target_bs,
VAR_6 ? VAR_7 : NULL,
VAR_12, VAR_14, VAR_16, VAR_8,
VAR_18, VAR_20,
block_job_cb, bs, &local_err); if (local_err != NULL) { bdrv_unref(target_bs); error_propagate(VAR_21, local_err); return; } }