static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)

{

    BDRVQcow2State *s = bs->opaque;

    Qcow2COWRegion *start = &m->cow_start;

    Qcow2COWRegion *end = &m->cow_end;

    unsigned buffer_size;

    unsigned data_bytes = end->offset - (start->offset + start->nb_bytes);

    bool merge_reads;

    uint8_t *start_buffer, *end_buffer;

    QEMUIOVector qiov;

    int ret;



    assert(start->nb_bytes <= UINT_MAX - end->nb_bytes);

    assert(start->nb_bytes + end->nb_bytes <= UINT_MAX - data_bytes);

    assert(start->offset + start->nb_bytes <= end->offset);

    assert(!m->data_qiov || m->data_qiov->size == data_bytes);



    if (start->nb_bytes == 0 && end->nb_bytes == 0) {

        return 0;

    }



    /* If we have to read both the start and end COW regions and the

     * middle region is not too large then perform just one read

     * operation */

    merge_reads = start->nb_bytes && end->nb_bytes && data_bytes <= 16384;

    if (merge_reads) {

        buffer_size = start->nb_bytes + data_bytes + end->nb_bytes;

    } else {

        /* If we have to do two reads, add some padding in the middle

         * if necessary to make sure that the end region is optimally

         * aligned. */

        size_t align = bdrv_opt_mem_align(bs);

        assert(align > 0 && align <= UINT_MAX);

        assert(QEMU_ALIGN_UP(start->nb_bytes, align) <=

               UINT_MAX - end->nb_bytes);

        buffer_size = QEMU_ALIGN_UP(start->nb_bytes, align) + end->nb_bytes;

    }



    /* Reserve a buffer large enough to store all the data that we're

     * going to read */

    start_buffer = qemu_try_blockalign(bs, buffer_size);

    if (start_buffer == NULL) {

        return -ENOMEM;

    }

    /* The part of the buffer where the end region is located */

    end_buffer = start_buffer + buffer_size - end->nb_bytes;



    qemu_iovec_init(&qiov, 2 + (m->data_qiov ? m->data_qiov->niov : 0));



    qemu_co_mutex_unlock(&s->lock);

    /* First we read the existing data from both COW regions. We

     * either read the whole region in one go, or the start and end

     * regions separately. */

    if (merge_reads) {

        qemu_iovec_add(&qiov, start_buffer, buffer_size);

        ret = do_perform_cow_read(bs, m->offset, start->offset, &qiov);

    } else {

        qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);

        ret = do_perform_cow_read(bs, m->offset, start->offset, &qiov);

        if (ret < 0) {

            goto fail;

        }



        qemu_iovec_reset(&qiov);

        qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);

        ret = do_perform_cow_read(bs, m->offset, end->offset, &qiov);

    }

    if (ret < 0) {

        goto fail;

    }



    /* Encrypt the data if necessary before writing it */

    if (bs->encrypted) {

        if (!do_perform_cow_encrypt(bs, m->offset, start->offset,

                                    start_buffer, start->nb_bytes) ||

            !do_perform_cow_encrypt(bs, m->offset, end->offset,

                                    end_buffer, end->nb_bytes)) {

            ret = -EIO;

            goto fail;

        }

    }



    /* And now we can write everything. If we have the guest data we

     * can write everything in one single operation */

    if (m->data_qiov) {

        qemu_iovec_reset(&qiov);

        if (start->nb_bytes) {

            qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);

        }

        qemu_iovec_concat(&qiov, m->data_qiov, 0, data_bytes);

        if (end->nb_bytes) {

            qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);

        }

        /* NOTE: we have a write_aio blkdebug event here followed by

         * a cow_write one in do_perform_cow_write(), but there's only

         * one single I/O operation */

        BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);

        ret = do_perform_cow_write(bs, m->alloc_offset, start->offset, &qiov);

    } else {

        /* If there's no guest data then write both COW regions separately */

        qemu_iovec_reset(&qiov);

        qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);

        ret = do_perform_cow_write(bs, m->alloc_offset, start->offset, &qiov);

        if (ret < 0) {

            goto fail;

        }



        qemu_iovec_reset(&qiov);

        qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);

        ret = do_perform_cow_write(bs, m->alloc_offset, end->offset, &qiov);

    }



fail:

    qemu_co_mutex_lock(&s->lock);



    /*

     * Before we update the L2 table to actually point to the new cluster, we

     * need to be sure that the refcounts have been increased and COW was

     * handled.

     */

    if (ret == 0) {

        qcow2_cache_depends_on_flush(s->l2_table_cache);

    }



    qemu_vfree(start_buffer);

    qemu_iovec_destroy(&qiov);

    return ret;

}

static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)

{

    BDRVQcow2State *s = bs->opaque;

    Qcow2COWRegion *start = &m->cow_start;

    Qcow2COWRegion *end = &m->cow_end;

    unsigned buffer_size;

    unsigned data_bytes = end->offset - (start->offset + start->nb_bytes);

    bool merge_reads;

    uint8_t *start_buffer, *end_buffer;

    QEMUIOVector qiov;

    int ret;



    assert(start->nb_bytes <= UINT_MAX - end->nb_bytes);

    assert(start->nb_bytes + end->nb_bytes <= UINT_MAX - data_bytes);

    assert(start->offset + start->nb_bytes <= end->offset);

    assert(!m->data_qiov || m->data_qiov->size == data_bytes);



    if (start->nb_bytes == 0 && end->nb_bytes == 0) {

        return 0;

    }



    





    merge_reads = start->nb_bytes && end->nb_bytes && data_bytes <= 16384;

    if (merge_reads) {

        buffer_size = start->nb_bytes + data_bytes + end->nb_bytes;

    } else {

        





        size_t align = bdrv_opt_mem_align(bs);

        assert(align > 0 && align <= UINT_MAX);

        assert(QEMU_ALIGN_UP(start->nb_bytes, align) <=

               UINT_MAX - end->nb_bytes);

        buffer_size = QEMU_ALIGN_UP(start->nb_bytes, align) + end->nb_bytes;

    }



    



    start_buffer = qemu_try_blockalign(bs, buffer_size);

    if (start_buffer == NULL) {

        return -ENOMEM;

    }

    

    end_buffer = start_buffer + buffer_size - end->nb_bytes;



    qemu_iovec_init(&qiov, 2 + (m->data_qiov ? m->data_qiov->niov : 0));



    qemu_co_mutex_unlock(&s->lock);

    





    if (merge_reads) {

        qemu_iovec_add(&qiov, start_buffer, buffer_size);

        ret = do_perform_cow_read(bs, m->offset, start->offset, &qiov);

    } else {

        qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);

        ret = do_perform_cow_read(bs, m->offset, start->offset, &qiov);

        if (ret < 0) {

            goto fail;

        }



        qemu_iovec_reset(&qiov);

        qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);

        ret = do_perform_cow_read(bs, m->offset, end->offset, &qiov);

    }

    if (ret < 0) {

        goto fail;

    }



    

    if (bs->encrypted) {

        if (!do_perform_cow_encrypt(bs, m->offset, start->offset,

                                    start_buffer, start->nb_bytes) ||

            !do_perform_cow_encrypt(bs, m->offset, end->offset,

                                    end_buffer, end->nb_bytes)) {

            ret = -EIO;

            goto fail;

        }

    }



    



    if (m->data_qiov) {

        qemu_iovec_reset(&qiov);

        if (start->nb_bytes) {

            qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);

        }

        qemu_iovec_concat(&qiov, m->data_qiov, 0, data_bytes);

        if (end->nb_bytes) {

            qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);

        }

        





        BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);

        ret = do_perform_cow_write(bs, m->alloc_offset, start->offset, &qiov);

    } else {

        

        qemu_iovec_reset(&qiov);

        qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);

        ret = do_perform_cow_write(bs, m->alloc_offset, start->offset, &qiov);

        if (ret < 0) {

            goto fail;

        }



        qemu_iovec_reset(&qiov);

        qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);

        ret = do_perform_cow_write(bs, m->alloc_offset, end->offset, &qiov);

    }



fail:

    qemu_co_mutex_lock(&s->lock);



    









    if (ret == 0) {

        qcow2_cache_depends_on_flush(s->l2_table_cache);

    }



    qemu_vfree(start_buffer);

    qemu_iovec_destroy(&qiov);

    return ret;

}

        if (!do_perform_cow_encrypt(bs, m->offset, start->offset,                                     start_buffer, start->nb_bytes) ||             !do_perform_cow_encrypt(bs, m->offset, end->offset,                                     end_buffer, end->nb_bytes)) {         goto fail;
static int FUNC_0(BlockDriverState *VAR_0, QCowL2Meta *VAR_1)

{

    BDRVQcow2State *s = VAR_0->opaque;

    Qcow2COWRegion *start = &VAR_1->cow_start;

    Qcow2COWRegion *end = &VAR_1->cow_end;

    unsigned VAR_2;

    unsigned VAR_3 = end->offset - (start->offset + start->nb_bytes);

    bool merge_reads;

    uint8_t *start_buffer, *end_buffer;

    QEMUIOVector qiov;

    int VAR_4;



    assert(start->nb_bytes <= UINT_MAX - end->nb_bytes);

    assert(start->nb_bytes + end->nb_bytes <= UINT_MAX - VAR_3);

    assert(start->offset + start->nb_bytes <= end->offset);

    assert(!VAR_1->data_qiov || VAR_1->data_qiov->size == VAR_3);



    if (start->nb_bytes == 0 && end->nb_bytes == 0) {

        return 0;

    }



    





    merge_reads = start->nb_bytes && end->nb_bytes && VAR_3 <= 16384;

    if (merge_reads) {

        VAR_2 = start->nb_bytes + VAR_3 + end->nb_bytes;

    } else {

        





        size_t align = bdrv_opt_mem_align(VAR_0);

        assert(align > 0 && align <= UINT_MAX);

        assert(QEMU_ALIGN_UP(start->nb_bytes, align) <=

               UINT_MAX - end->nb_bytes);

        VAR_2 = QEMU_ALIGN_UP(start->nb_bytes, align) + end->nb_bytes;

    }



    



    start_buffer = qemu_try_blockalign(VAR_0, VAR_2);

    if (start_buffer == NULL) {

        return -ENOMEM;

    }

    

    end_buffer = start_buffer + VAR_2 - end->nb_bytes;



    qemu_iovec_init(&qiov, 2 + (VAR_1->data_qiov ? VAR_1->data_qiov->niov : 0));



    qemu_co_mutex_unlock(&s->lock);

    





    if (merge_reads) {

        qemu_iovec_add(&qiov, start_buffer, VAR_2);

        VAR_4 = do_perform_cow_read(VAR_0, VAR_1->offset, start->offset, &qiov);

    } else {

        qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);

        VAR_4 = do_perform_cow_read(VAR_0, VAR_1->offset, start->offset, &qiov);

        if (VAR_4 < 0) {

            goto fail;

        }



        qemu_iovec_reset(&qiov);

        qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);

        VAR_4 = do_perform_cow_read(VAR_0, VAR_1->offset, end->offset, &qiov);

    }

    if (VAR_4 < 0) {

        goto fail;

    }



    

    if (VAR_0->encrypted) {

        if (!do_perform_cow_encrypt(VAR_0, VAR_1->offset, start->offset,

                                    start_buffer, start->nb_bytes) ||

            !do_perform_cow_encrypt(VAR_0, VAR_1->offset, end->offset,

                                    end_buffer, end->nb_bytes)) {

            VAR_4 = -EIO;

            goto fail;

        }

    }



    



    if (VAR_1->data_qiov) {

        qemu_iovec_reset(&qiov);

        if (start->nb_bytes) {

            qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);

        }

        qemu_iovec_concat(&qiov, VAR_1->data_qiov, 0, VAR_3);

        if (end->nb_bytes) {

            qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);

        }

        





        BLKDBG_EVENT(VAR_0->file, BLKDBG_WRITE_AIO);

        VAR_4 = do_perform_cow_write(VAR_0, VAR_1->alloc_offset, start->offset, &qiov);

    } else {

        

        qemu_iovec_reset(&qiov);

        qemu_iovec_add(&qiov, start_buffer, start->nb_bytes);

        VAR_4 = do_perform_cow_write(VAR_0, VAR_1->alloc_offset, start->offset, &qiov);

        if (VAR_4 < 0) {

            goto fail;

        }



        qemu_iovec_reset(&qiov);

        qemu_iovec_add(&qiov, end_buffer, end->nb_bytes);

        VAR_4 = do_perform_cow_write(VAR_0, VAR_1->alloc_offset, end->offset, &qiov);

    }



fail:

    qemu_co_mutex_lock(&s->lock);



    









    if (VAR_4 == 0) {

        qcow2_cache_depends_on_flush(s->l2_table_cache);

    }



    qemu_vfree(start_buffer);

    qemu_iovec_destroy(&qiov);

    return VAR_4;

}

static int FUNC_0(BlockDriverState *VAR_0, QCowL2Meta *VAR_1)
{ BDRVQcow2State *s = VAR_0->opaque; Qcow2COWRegion *start = &VAR_1->cow_start; Qcow2COWRegion *end = &VAR_1->cow_end; unsigned VAR_2; unsigned VAR_3 = end->offset - (start->offset + start->nb_bytes); bool merge_reads; uint8_t *start_buffer, *end_buffer; QEMUIOVector qiov; int VAR_4; assert(start->nb_bytes <= UINT_MAX - end->nb_bytes); assert(start->nb_bytes + end->nb_bytes <= UINT_MAX - VAR_3); assert(start->offset + start->nb_bytes <= end->offset); assert(!VAR_1->data_qiov || VAR_1->data_qiov->size == VAR_3); if (start->nb_bytes == 0 && end->nb_bytes == 0) { return 0; } merge_reads = start->nb_bytes && end->nb_bytes && VAR_3 <= 16384; if (merge_reads) { VAR_2 = start->nb_bytes + VAR_3 + end->nb_bytes; } else { size_t align = bdrv_opt_mem_align(VAR_0); assert(align > 0 && align <= UINT_MAX); assert(QEMU_ALIGN_UP(start->nb_bytes, align) <=
UINT_MAX - end->nb_bytes); VAR_2 = QEMU_ALIGN_UP(start->nb_bytes, align) + end->nb_bytes; } start_buffer = qemu_try_blockalign(VAR_0, VAR_2); if (start_buffer == NULL) { return -ENOMEM; } end_buffer = start_buffer + VAR_2 - end->nb_bytes; qemu_iovec_init(&qiov, 2 + (VAR_1->data_qiov ? VAR_1->data_qiov->niov : 0)); qemu_co_mutex_unlock(&s->lock); if (merge_reads) { qemu_iovec_add(&qiov, start_buffer, VAR_2); VAR_4 = do_perform_cow_read(VAR_0, VAR_1->offset, start->offset, &qiov); } else { qemu_iovec_add(&qiov, start_buffer, start->nb_bytes); VAR_4 = do_perform_cow_read(VAR_0, VAR_1->offset, start->offset, &qiov); if (VAR_4 < 0) { goto fail; } qemu_iovec_reset(&qiov); qemu_iovec_add(&qiov, end_buffer, end->nb_bytes); VAR_4 = do_perform_cow_read(VAR_0, VAR_1->offset, end->offset, &qiov); } if (VAR_4 < 0) { goto fail; } if (VAR_0->encrypted) { if (!do_perform_cow_encrypt(VAR_0, VAR_1->offset, start->offset,
start_buffer, start->nb_bytes) ||
!do_perform_cow_encrypt(VAR_0, VAR_1->offset, end->offset,
end_buffer, end->nb_bytes)) { VAR_4 = -EIO; goto fail; } } if (VAR_1->data_qiov) { qemu_iovec_reset(&qiov); if (start->nb_bytes) { qemu_iovec_add(&qiov, start_buffer, start->nb_bytes); } qemu_iovec_concat(&qiov, VAR_1->data_qiov, 0, VAR_3); if (end->nb_bytes) { qemu_iovec_add(&qiov, end_buffer, end->nb_bytes); } BLKDBG_EVENT(VAR_0->file, BLKDBG_WRITE_AIO); VAR_4 = do_perform_cow_write(VAR_0, VAR_1->alloc_offset, start->offset, &qiov); } else { qemu_iovec_reset(&qiov); qemu_iovec_add(&qiov, start_buffer, start->nb_bytes); VAR_4 = do_perform_cow_write(VAR_0, VAR_1->alloc_offset, start->offset, &qiov); if (VAR_4 < 0) { goto fail; } qemu_iovec_reset(&qiov); qemu_iovec_add(&qiov, end_buffer, end->nb_bytes); VAR_4 = do_perform_cow_write(VAR_0, VAR_1->alloc_offset, end->offset, &qiov); } fail:
qemu_co_mutex_lock(&s->lock); if (VAR_4 == 0) { qcow2_cache_depends_on_flush(s->l2_table_cache); } qemu_vfree(start_buffer); qemu_iovec_destroy(&qiov); return VAR_4; }