static void mirror_start_job(const char *job_id, BlockDriverState *bs,

                             int creation_flags, BlockDriverState *target,

                             const char *replaces, int64_t speed,

                             uint32_t granularity, int64_t buf_size,

                             BlockMirrorBackingMode backing_mode,

                             BlockdevOnError on_source_error,

                             BlockdevOnError on_target_error,

                             bool unmap,

                             BlockCompletionFunc *cb,

                             void *opaque,

                             const BlockJobDriver *driver,

                             bool is_none_mode, BlockDriverState *base,

                             bool auto_complete, const char *filter_node_name,

                             Error **errp)

{

    MirrorBlockJob *s;

    BlockDriverState *mirror_top_bs;

    bool target_graph_mod;

    bool target_is_backing;

    Error *local_err = NULL;

    int ret;



    if (granularity == 0) {

        granularity = bdrv_get_default_bitmap_granularity(target);




    assert ((granularity & (granularity - 1)) == 0);

    /* Granularity must be large enough for sector-based dirty bitmap */

    assert(granularity >= BDRV_SECTOR_SIZE);



    if (buf_size < 0) {

        error_setg(errp, "Invalid parameter 'buf-size'");

        return;




    if (buf_size == 0) {

        buf_size = DEFAULT_MIRROR_BUF_SIZE;




    /* In the case of active commit, add dummy driver to provide consistent

     * reads on the top, while disabling it in the intermediate nodes, and make

     * the backing chain writable. */

    mirror_top_bs = bdrv_new_open_driver(&bdrv_mirror_top, filter_node_name,

                                         BDRV_O_RDWR, errp);

    if (mirror_top_bs == NULL) {

        return;





    mirror_top_bs->total_sectors = bs->total_sectors;

    bdrv_set_aio_context(mirror_top_bs, bdrv_get_aio_context(bs));



    /* bdrv_append takes ownership of the mirror_top_bs reference, need to keep

     * it alive until block_job_create() succeeds even if bs has no parent. */

    bdrv_ref(mirror_top_bs);

    bdrv_drained_begin(bs);

    bdrv_append(mirror_top_bs, bs, &local_err);

    bdrv_drained_end(bs);



    if (local_err) {

        bdrv_unref(mirror_top_bs);

        error_propagate(errp, local_err);

        return;




    /* Make sure that the source is not resized while the job is running */

    s = block_job_create(job_id, driver, mirror_top_bs,

                         BLK_PERM_CONSISTENT_READ,

                         BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |

                         BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD, speed,

                         creation_flags, cb, opaque, errp);

    if (!s) {

        goto fail;


    /* The block job now has a reference to this node */

    bdrv_unref(mirror_top_bs);



    s->source = bs;

    s->mirror_top_bs = mirror_top_bs;



    /* No resize for the target either; while the mirror is still running, a

     * consistent read isn't necessarily possible. We could possibly allow

     * writes and graph modifications, though it would likely defeat the

     * purpose of a mirror, so leave them blocked for now.

     *

     * In the case of active commit, things look a bit different, though,

     * because the target is an already populated backing file in active use.

     * We can allow anything except resize there.*/

    target_is_backing = bdrv_chain_contains(bs, target);

    target_graph_mod = (backing_mode != MIRROR_LEAVE_BACKING_CHAIN);

    s->target = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE |

                        (target_graph_mod ? BLK_PERM_GRAPH_MOD : 0),

                        BLK_PERM_WRITE_UNCHANGED |

                        (target_is_backing ? BLK_PERM_CONSISTENT_READ |

                                             BLK_PERM_WRITE |

                                             BLK_PERM_GRAPH_MOD : 0));

    ret = blk_insert_bs(s->target, target, errp);

    if (ret < 0) {

        goto fail;




    s->replaces = g_strdup(replaces);

    s->on_source_error = on_source_error;

    s->on_target_error = on_target_error;

    s->is_none_mode = is_none_mode;

    s->backing_mode = backing_mode;

    s->base = base;

    s->granularity = granularity;

    s->buf_size = ROUND_UP(buf_size, granularity);

    s->unmap = unmap;

    if (auto_complete) {

        s->should_complete = true;




    s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);

    if (!s->dirty_bitmap) {

        goto fail;




    /* Required permissions are already taken with blk_new() */

    block_job_add_bdrv(&s->common, "target", target, 0, BLK_PERM_ALL,

                       &error_abort);



    /* In commit_active_start() all intermediate nodes disappear, so

     * any jobs in them must be blocked */

    if (target_is_backing) {

        BlockDriverState *iter;

        for (iter = backing_bs(bs); iter != target; iter = backing_bs(iter)) {

            /* XXX BLK_PERM_WRITE needs to be allowed so we don't block

             * ourselves at s->base (if writes are blocked for a node, they are

             * also blocked for its backing file). The other options would be a

             * second filter driver above s->base (== target). */

            ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,

                                     BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE,

                                     errp);

            if (ret < 0) {

                goto fail;






    trace_mirror_start(bs, s, opaque);

    block_job_start(&s->common);

    return;



fail:

    if (s) {

        /* Make sure this BDS does not go away until we have completed the graph

         * changes below */

        bdrv_ref(mirror_top_bs);



        g_free(s->replaces);

        blk_unref(s->target);

        block_job_early_fail(&s->common);




    bdrv_child_try_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL,

                            &error_abort);

    bdrv_replace_node(mirror_top_bs, backing_bs(mirror_top_bs), &error_abort);



    bdrv_unref(mirror_top_bs);

static void mirror_start_job(const char *job_id, BlockDriverState *bs,

                             int creation_flags, BlockDriverState *target,

                             const char *replaces, int64_t speed,

                             uint32_t granularity, int64_t buf_size,

                             BlockMirrorBackingMode backing_mode,

                             BlockdevOnError on_source_error,

                             BlockdevOnError on_target_error,

                             bool unmap,

                             BlockCompletionFunc *cb,

                             void *opaque,

                             const BlockJobDriver *driver,

                             bool is_none_mode, BlockDriverState *base,

                             bool auto_complete, const char *filter_node_name,

                             Error **errp)

{

    MirrorBlockJob *s;

    BlockDriverState *mirror_top_bs;

    bool target_graph_mod;

    bool target_is_backing;

    Error *local_err = NULL;

    int ret;



    if (granularity == 0) {

        granularity = bdrv_get_default_bitmap_granularity(target);




    assert ((granularity & (granularity - 1)) == 0);

    

    assert(granularity >= BDRV_SECTOR_SIZE);



    if (buf_size < 0) {

        error_setg(errp, "Invalid parameter 'buf-size'");

        return;




    if (buf_size == 0) {

        buf_size = DEFAULT_MIRROR_BUF_SIZE;




    





    mirror_top_bs = bdrv_new_open_driver(&bdrv_mirror_top, filter_node_name,

                                         BDRV_O_RDWR, errp);

    if (mirror_top_bs == NULL) {

        return;





    mirror_top_bs->total_sectors = bs->total_sectors;

    bdrv_set_aio_context(mirror_top_bs, bdrv_get_aio_context(bs));



    



    bdrv_ref(mirror_top_bs);

    bdrv_drained_begin(bs);

    bdrv_append(mirror_top_bs, bs, &local_err);

    bdrv_drained_end(bs);



    if (local_err) {

        bdrv_unref(mirror_top_bs);

        error_propagate(errp, local_err);

        return;




    

    s = block_job_create(job_id, driver, mirror_top_bs,

                         BLK_PERM_CONSISTENT_READ,

                         BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |

                         BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD, speed,

                         creation_flags, cb, opaque, errp);

    if (!s) {

        goto fail;


    

    bdrv_unref(mirror_top_bs);



    s->source = bs;

    s->mirror_top_bs = mirror_top_bs;



    















    target_is_backing = bdrv_chain_contains(bs, target);

    target_graph_mod = (backing_mode != MIRROR_LEAVE_BACKING_CHAIN);

    s->target = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE |

                        (target_graph_mod ? BLK_PERM_GRAPH_MOD : 0),

                        BLK_PERM_WRITE_UNCHANGED |

                        (target_is_backing ? BLK_PERM_CONSISTENT_READ |

                                             BLK_PERM_WRITE |

                                             BLK_PERM_GRAPH_MOD : 0));

    ret = blk_insert_bs(s->target, target, errp);

    if (ret < 0) {

        goto fail;




    s->replaces = g_strdup(replaces);

    s->on_source_error = on_source_error;

    s->on_target_error = on_target_error;

    s->is_none_mode = is_none_mode;

    s->backing_mode = backing_mode;

    s->base = base;

    s->granularity = granularity;

    s->buf_size = ROUND_UP(buf_size, granularity);

    s->unmap = unmap;

    if (auto_complete) {

        s->should_complete = true;




    s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);

    if (!s->dirty_bitmap) {

        goto fail;




    

    block_job_add_bdrv(&s->common, "target", target, 0, BLK_PERM_ALL,

                       &error_abort);



    



    if (target_is_backing) {

        BlockDriverState *iter;

        for (iter = backing_bs(bs); iter != target; iter = backing_bs(iter)) {

            







            ret = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,

                                     BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE,

                                     errp);

            if (ret < 0) {

                goto fail;






    trace_mirror_start(bs, s, opaque);

    block_job_start(&s->common);

    return;



fail:

    if (s) {

        



        bdrv_ref(mirror_top_bs);



        g_free(s->replaces);

        blk_unref(s->target);

        block_job_early_fail(&s->common);




    bdrv_child_try_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL,

                            &error_abort);

    bdrv_replace_node(mirror_top_bs, backing_bs(mirror_top_bs), &error_abort);



    bdrv_unref(mirror_top_bs);

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

                             int VAR_2, BlockDriverState *VAR_3,

                             const char *VAR_4, int64_t VAR_5,

                             uint32_t VAR_6, int64_t VAR_7,

                             BlockMirrorBackingMode VAR_8,

                             BlockdevOnError VAR_9,

                             BlockdevOnError VAR_10,

                             bool VAR_11,

                             BlockCompletionFunc *VAR_12,

                             void *VAR_13,

                             const BlockJobDriver *VAR_14,

                             bool VAR_15, BlockDriverState *VAR_16,

                             bool VAR_17, const char *VAR_18,

                             Error **VAR_19)

{

    MirrorBlockJob *s;

    BlockDriverState *mirror_top_bs;

    bool target_graph_mod;

    bool target_is_backing;

    Error *local_err = NULL;

    int VAR_20;



    if (VAR_6 == 0) {

        VAR_6 = bdrv_get_default_bitmap_granularity(VAR_3);




    assert ((VAR_6 & (VAR_6 - 1)) == 0);

    

    assert(VAR_6 >= BDRV_SECTOR_SIZE);



    if (VAR_7 < 0) {

        error_setg(VAR_19, "Invalid parameter 'buf-size'");

        return;




    if (VAR_7 == 0) {

        VAR_7 = DEFAULT_MIRROR_BUF_SIZE;




    





    mirror_top_bs = bdrv_new_open_driver(&bdrv_mirror_top, VAR_18,

                                         BDRV_O_RDWR, VAR_19);

    if (mirror_top_bs == NULL) {

        return;





    mirror_top_bs->total_sectors = VAR_1->total_sectors;

    bdrv_set_aio_context(mirror_top_bs, bdrv_get_aio_context(VAR_1));



    



    bdrv_ref(mirror_top_bs);

    bdrv_drained_begin(VAR_1);

    bdrv_append(mirror_top_bs, VAR_1, &local_err);

    bdrv_drained_end(VAR_1);



    if (local_err) {

        bdrv_unref(mirror_top_bs);

        error_propagate(VAR_19, local_err);

        return;




    

    s = block_job_create(VAR_0, VAR_14, mirror_top_bs,

                         BLK_PERM_CONSISTENT_READ,

                         BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |

                         BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD, VAR_5,

                         VAR_2, VAR_12, VAR_13, VAR_19);

    if (!s) {

        goto fail;


    

    bdrv_unref(mirror_top_bs);



    s->source = VAR_1;

    s->mirror_top_bs = mirror_top_bs;



    















    target_is_backing = bdrv_chain_contains(VAR_1, VAR_3);

    target_graph_mod = (VAR_8 != MIRROR_LEAVE_BACKING_CHAIN);

    s->VAR_3 = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE |

                        (target_graph_mod ? BLK_PERM_GRAPH_MOD : 0),

                        BLK_PERM_WRITE_UNCHANGED |

                        (target_is_backing ? BLK_PERM_CONSISTENT_READ |

                                             BLK_PERM_WRITE |

                                             BLK_PERM_GRAPH_MOD : 0));

    VAR_20 = blk_insert_bs(s->VAR_3, VAR_3, VAR_19);

    if (VAR_20 < 0) {

        goto fail;




    s->VAR_4 = g_strdup(VAR_4);

    s->VAR_9 = VAR_9;

    s->VAR_10 = VAR_10;

    s->VAR_15 = VAR_15;

    s->VAR_8 = VAR_8;

    s->VAR_16 = VAR_16;

    s->VAR_6 = VAR_6;

    s->VAR_7 = ROUND_UP(VAR_7, VAR_6);

    s->VAR_11 = VAR_11;

    if (VAR_17) {

        s->should_complete = true;




    s->dirty_bitmap = bdrv_create_dirty_bitmap(VAR_1, VAR_6, NULL, VAR_19);

    if (!s->dirty_bitmap) {

        goto fail;




    

    block_job_add_bdrv(&s->common, "VAR_3", VAR_3, 0, BLK_PERM_ALL,

                       &error_abort);



    



    if (target_is_backing) {

        BlockDriverState *iter;

        for (iter = backing_bs(VAR_1); iter != VAR_3; iter = backing_bs(iter)) {

            







            VAR_20 = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,

                                     BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE,

                                     VAR_19);

            if (VAR_20 < 0) {

                goto fail;






    trace_mirror_start(VAR_1, s, VAR_13);

    block_job_start(&s->common);

    return;



fail:

    if (s) {

        



        bdrv_ref(mirror_top_bs);



        g_free(s->VAR_4);

        blk_unref(s->VAR_3);

        block_job_early_fail(&s->common);




    bdrv_child_try_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL,

                            &error_abort);

    bdrv_replace_node(mirror_top_bs, backing_bs(mirror_top_bs), &error_abort);



    bdrv_unref(mirror_top_bs);

static void FUNC_0(const char *VAR_0, BlockDriverState *VAR_1,
int VAR_2, BlockDriverState *VAR_3,
const char *VAR_4, int64_t VAR_5,
uint32_t VAR_6, int64_t VAR_7,
BlockMirrorBackingMode VAR_8,
BlockdevOnError VAR_9,
BlockdevOnError VAR_10,
bool VAR_11,
BlockCompletionFunc *VAR_12,
void *VAR_13,
const BlockJobDriver *VAR_14,
bool VAR_15, BlockDriverState *VAR_16,
bool VAR_17, const char *VAR_18,
Error **VAR_19)
{ MirrorBlockJob *s; BlockDriverState *mirror_top_bs; bool target_graph_mod; bool target_is_backing; Error *local_err = NULL; int VAR_20; if (VAR_6 == 0) { VAR_6 = bdrv_get_default_bitmap_granularity(VAR_3); assert ((VAR_6 & (VAR_6 - 1)) == 0); assert(VAR_6 >= BDRV_SECTOR_SIZE); if (VAR_7 < 0) { error_setg(VAR_19, "Invalid parameter 'buf-size'"); return; if (VAR_7 == 0) { VAR_7 = DEFAULT_MIRROR_BUF_SIZE; mirror_top_bs = bdrv_new_open_driver(&bdrv_mirror_top, VAR_18,
BDRV_O_RDWR, VAR_19); if (mirror_top_bs == NULL) { return; mirror_top_bs->total_sectors = VAR_1->total_sectors; bdrv_set_aio_context(mirror_top_bs, bdrv_get_aio_context(VAR_1)); bdrv_ref(mirror_top_bs); bdrv_drained_begin(VAR_1); bdrv_append(mirror_top_bs, VAR_1, &local_err); bdrv_drained_end(VAR_1); if (local_err) { bdrv_unref(mirror_top_bs); error_propagate(VAR_19, local_err); return; s = block_job_create(VAR_0, VAR_14, mirror_top_bs,
BLK_PERM_CONSISTENT_READ,
BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED |
BLK_PERM_WRITE | BLK_PERM_GRAPH_MOD, VAR_5,
VAR_2, VAR_12, VAR_13, VAR_19); if (!s) { goto fail; bdrv_unref(mirror_top_bs); s->source = VAR_1; s->mirror_top_bs = mirror_top_bs; target_is_backing = bdrv_chain_contains(VAR_1, VAR_3); target_graph_mod = (VAR_8 != MIRROR_LEAVE_BACKING_CHAIN); s->VAR_3 = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE |
(target_graph_mod ? BLK_PERM_GRAPH_MOD : 0),
BLK_PERM_WRITE_UNCHANGED |
(target_is_backing ? BLK_PERM_CONSISTENT_READ |
BLK_PERM_WRITE |
BLK_PERM_GRAPH_MOD : 0)); VAR_20 = blk_insert_bs(s->VAR_3, VAR_3, VAR_19); if (VAR_20 < 0) { goto fail; s->VAR_4 = g_strdup(VAR_4); s->VAR_9 = VAR_9; s->VAR_10 = VAR_10; s->VAR_15 = VAR_15; s->VAR_8 = VAR_8; s->VAR_16 = VAR_16; s->VAR_6 = VAR_6; s->VAR_7 = ROUND_UP(VAR_7, VAR_6); s->VAR_11 = VAR_11; if (VAR_17) { s->should_complete = true; s->dirty_bitmap = bdrv_create_dirty_bitmap(VAR_1, VAR_6, NULL, VAR_19); if (!s->dirty_bitmap) { goto fail; block_job_add_bdrv(&s->common, "VAR_3", VAR_3, 0, BLK_PERM_ALL,
&error_abort); if (target_is_backing) { BlockDriverState *iter; for (iter = backing_bs(VAR_1); iter != VAR_3; iter = backing_bs(iter)) { VAR_20 = block_job_add_bdrv(&s->common, "intermediate node", iter, 0,
BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE,
VAR_19); if (VAR_20 < 0) { goto fail; trace_mirror_start(VAR_1, s, VAR_13); block_job_start(&s->common); return; fail:
if (s) { bdrv_ref(mirror_top_bs); g_free(s->VAR_4); blk_unref(s->VAR_3); block_job_early_fail(&s->common); bdrv_child_try_set_perm(mirror_top_bs->backing, 0, BLK_PERM_ALL,
&error_abort); bdrv_replace_node(mirror_top_bs, backing_bs(mirror_top_bs), &error_abort); bdrv_unref(mirror_top_bs);