int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,

    int n_start, int n_end, int *num, QCowL2Meta *m)

{

    BDRVQcowState *s = bs->opaque;

    int l2_index, ret, sectors;

    uint64_t *l2_table;

    unsigned int nb_clusters, keep_clusters;

    uint64_t cluster_offset;



    trace_qcow2_alloc_clusters_offset(qemu_coroutine_self(), offset,

                                      n_start, n_end);



    /* Find L2 entry for the first involved cluster */

again:

    ret = get_cluster_table(bs, offset, &l2_table, &l2_index);

    if (ret < 0) {

        return ret;

    }



    /*

     * Calculate the number of clusters to look for. We stop at L2 table

     * boundaries to keep things simple.

     */

    nb_clusters = MIN(size_to_clusters(s, n_end << BDRV_SECTOR_BITS),

                      s->l2_size - l2_index);



    cluster_offset = be64_to_cpu(l2_table[l2_index]);



    /*

     * Check how many clusters are already allocated and don't need COW, and how

     * many need a new allocation.

     */

    if (qcow2_get_cluster_type(cluster_offset) == QCOW2_CLUSTER_NORMAL

        && (cluster_offset & QCOW_OFLAG_COPIED))

    {

        /* We keep all QCOW_OFLAG_COPIED clusters */

        keep_clusters =

            count_contiguous_clusters(nb_clusters, s->cluster_size,

                                      &l2_table[l2_index], 0,

                                      QCOW_OFLAG_COPIED | QCOW_OFLAG_ZERO);

        assert(keep_clusters <= nb_clusters);

        nb_clusters -= keep_clusters;

    } else {

        /* For the moment, overwrite compressed clusters one by one */

        if (cluster_offset & QCOW_OFLAG_COMPRESSED) {

            nb_clusters = 1;

        } else {

            nb_clusters = count_cow_clusters(s, nb_clusters, l2_table, l2_index);

        }



        keep_clusters = 0;

        cluster_offset = 0;

    }



    cluster_offset &= L2E_OFFSET_MASK;



    /*

     * The L2 table isn't used any more after this. As long as the cache works

     * synchronously, it's important to release it before calling

     * do_alloc_cluster_offset, which may yield if we need to wait for another

     * request to complete. If we still had the reference, we could use up the

     * whole cache with sleeping requests.

     */

    ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);

    if (ret < 0) {

        return ret;

    }



    /* If there is something left to allocate, do that now */

    *m = (QCowL2Meta) {

        .cluster_offset     = cluster_offset,

        .nb_clusters        = 0,

    };

    qemu_co_queue_init(&m->dependent_requests);



    if (nb_clusters > 0) {

        uint64_t alloc_offset;

        uint64_t alloc_cluster_offset;

        uint64_t keep_bytes = keep_clusters * s->cluster_size;



        /* Calculate start and size of allocation */

        alloc_offset = offset + keep_bytes;



        if (keep_clusters == 0) {

            alloc_cluster_offset = 0;

        } else {

            alloc_cluster_offset = cluster_offset + keep_bytes;

        }



        /* Allocate, if necessary at a given offset in the image file */

        ret = do_alloc_cluster_offset(bs, alloc_offset, &alloc_cluster_offset,

                                      &nb_clusters);

        if (ret == -EAGAIN) {

            goto again;

        } else if (ret < 0) {

            goto fail;

        }



        /* save info needed for meta data update */

        if (nb_clusters > 0) {

            int requested_sectors = n_end - keep_clusters * s->cluster_sectors;

            int avail_sectors = (keep_clusters + nb_clusters)

                                << (s->cluster_bits - BDRV_SECTOR_BITS);



            *m = (QCowL2Meta) {

                .cluster_offset = keep_clusters == 0 ?

                                  alloc_cluster_offset : cluster_offset,

                .alloc_offset   = alloc_cluster_offset,

                .offset         = alloc_offset,

                .n_start        = keep_clusters == 0 ? n_start : 0,

                .nb_clusters    = nb_clusters,

                .nb_available   = MIN(requested_sectors, avail_sectors),

            };

            qemu_co_queue_init(&m->dependent_requests);

            QLIST_INSERT_HEAD(&s->cluster_allocs, m, next_in_flight);

        }

    }



    /* Some cleanup work */

    sectors = (keep_clusters + nb_clusters) << (s->cluster_bits - 9);

    if (sectors > n_end) {

        sectors = n_end;

    }



    assert(sectors > n_start);

    *num = sectors - n_start;



    return 0;



fail:

    if (m->nb_clusters > 0) {

        QLIST_REMOVE(m, next_in_flight);

    }

    return ret;

}

int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,

    int n_start, int n_end, int *num, QCowL2Meta *m)

{

    BDRVQcowState *s = bs->opaque;

    int l2_index, ret, sectors;

    uint64_t *l2_table;

    unsigned int nb_clusters, keep_clusters;

    uint64_t cluster_offset;



    trace_qcow2_alloc_clusters_offset(qemu_coroutine_self(), offset,

                                      n_start, n_end);



    

again:

    ret = get_cluster_table(bs, offset, &l2_table, &l2_index);

    if (ret < 0) {

        return ret;

    }



    







    nb_clusters = MIN(size_to_clusters(s, n_end << BDRV_SECTOR_BITS),

                      s->l2_size - l2_index);



    cluster_offset = be64_to_cpu(l2_table[l2_index]);



    







    if (qcow2_get_cluster_type(cluster_offset) == QCOW2_CLUSTER_NORMAL

        && (cluster_offset & QCOW_OFLAG_COPIED))

    {

        

        keep_clusters =

            count_contiguous_clusters(nb_clusters, s->cluster_size,

                                      &l2_table[l2_index], 0,

                                      QCOW_OFLAG_COPIED | QCOW_OFLAG_ZERO);

        assert(keep_clusters <= nb_clusters);

        nb_clusters -= keep_clusters;

    } else {

        

        if (cluster_offset & QCOW_OFLAG_COMPRESSED) {

            nb_clusters = 1;

        } else {

            nb_clusters = count_cow_clusters(s, nb_clusters, l2_table, l2_index);

        }



        keep_clusters = 0;

        cluster_offset = 0;

    }



    cluster_offset &= L2E_OFFSET_MASK;



    













    ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);

    if (ret < 0) {

        return ret;

    }



    

    *m = (QCowL2Meta) {

        .cluster_offset     = cluster_offset,

        .nb_clusters        = 0,

    };

    qemu_co_queue_init(&m->dependent_requests);



    if (nb_clusters > 0) {

        uint64_t alloc_offset;

        uint64_t alloc_cluster_offset;

        uint64_t keep_bytes = keep_clusters * s->cluster_size;



        

        alloc_offset = offset + keep_bytes;



        if (keep_clusters == 0) {

            alloc_cluster_offset = 0;

        } else {

            alloc_cluster_offset = cluster_offset + keep_bytes;

        }



        

        ret = do_alloc_cluster_offset(bs, alloc_offset, &alloc_cluster_offset,

                                      &nb_clusters);

        if (ret == -EAGAIN) {

            goto again;

        } else if (ret < 0) {

            goto fail;

        }



        

        if (nb_clusters > 0) {

            int requested_sectors = n_end - keep_clusters * s->cluster_sectors;

            int avail_sectors = (keep_clusters + nb_clusters)

                                << (s->cluster_bits - BDRV_SECTOR_BITS);



            *m = (QCowL2Meta) {

                .cluster_offset = keep_clusters == 0 ?

                                  alloc_cluster_offset : cluster_offset,

                .alloc_offset   = alloc_cluster_offset,

                .offset         = alloc_offset,

                .n_start        = keep_clusters == 0 ? n_start : 0,

                .nb_clusters    = nb_clusters,

                .nb_available   = MIN(requested_sectors, avail_sectors),

            };

            qemu_co_queue_init(&m->dependent_requests);

            QLIST_INSERT_HEAD(&s->cluster_allocs, m, next_in_flight);

        }

    }



    

    sectors = (keep_clusters + nb_clusters) << (s->cluster_bits - 9);

    if (sectors > n_end) {

        sectors = n_end;

    }



    assert(sectors > n_start);

    *num = sectors - n_start;



    return 0;



fail:

    if (m->nb_clusters > 0) {

        QLIST_REMOVE(m, next_in_flight);

    }

    return ret;

}

        if (cluster_offset & QCOW_OFLAG_COMPRESSED) {             nb_clusters = count_cow_clusters(s, nb_clusters, l2_table, l2_index);         keep_clusters = 0;         cluster_offset = 0;
int FUNC_0(BlockDriverState *VAR_0, uint64_t VAR_1,

    int VAR_2, int VAR_3, int *VAR_4, QCowL2Meta *VAR_5)

{

    BDRVQcowState *s = VAR_0->opaque;

    int VAR_6, VAR_7, VAR_8;

    uint64_t *l2_table;

    unsigned int VAR_9, VAR_10;

    uint64_t cluster_offset;



    trace_qcow2_alloc_clusters_offset(qemu_coroutine_self(), VAR_1,

                                      VAR_2, VAR_3);



    

again:

    VAR_7 = get_cluster_table(VAR_0, VAR_1, &l2_table, &VAR_6);

    if (VAR_7 < 0) {

        return VAR_7;

    }



    







    VAR_9 = MIN(size_to_clusters(s, VAR_3 << BDRV_SECTOR_BITS),

                      s->l2_size - VAR_6);



    cluster_offset = be64_to_cpu(l2_table[VAR_6]);



    







    if (qcow2_get_cluster_type(cluster_offset) == QCOW2_CLUSTER_NORMAL

        && (cluster_offset & QCOW_OFLAG_COPIED))

    {

        

        VAR_10 =

            count_contiguous_clusters(VAR_9, s->cluster_size,

                                      &l2_table[VAR_6], 0,

                                      QCOW_OFLAG_COPIED | QCOW_OFLAG_ZERO);

        assert(VAR_10 <= VAR_9);

        VAR_9 -= VAR_10;

    } else {

        

        if (cluster_offset & QCOW_OFLAG_COMPRESSED) {

            VAR_9 = 1;

        } else {

            VAR_9 = count_cow_clusters(s, VAR_9, l2_table, VAR_6);

        }



        VAR_10 = 0;

        cluster_offset = 0;

    }



    cluster_offset &= L2E_OFFSET_MASK;



    













    VAR_7 = qcow2_cache_put(VAR_0, s->l2_table_cache, (void**) &l2_table);

    if (VAR_7 < 0) {

        return VAR_7;

    }



    

    *VAR_5 = (QCowL2Meta) {

        .cluster_offset     = cluster_offset,

        .VAR_9        = 0,

    };

    qemu_co_queue_init(&VAR_5->dependent_requests);



    if (VAR_9 > 0) {

        uint64_t alloc_offset;

        uint64_t alloc_cluster_offset;

        uint64_t keep_bytes = VAR_10 * s->cluster_size;



        

        alloc_offset = VAR_1 + keep_bytes;



        if (VAR_10 == 0) {

            alloc_cluster_offset = 0;

        } else {

            alloc_cluster_offset = cluster_offset + keep_bytes;

        }



        

        VAR_7 = do_alloc_cluster_offset(VAR_0, alloc_offset, &alloc_cluster_offset,

                                      &VAR_9);

        if (VAR_7 == -EAGAIN) {

            goto again;

        } else if (VAR_7 < 0) {

            goto fail;

        }



        

        if (VAR_9 > 0) {

            int VAR_11 = VAR_3 - VAR_10 * s->cluster_sectors;

            int VAR_12 = (VAR_10 + VAR_9)

                                << (s->cluster_bits - BDRV_SECTOR_BITS);



            *VAR_5 = (QCowL2Meta) {

                .cluster_offset = VAR_10 == 0 ?

                                  alloc_cluster_offset : cluster_offset,

                .alloc_offset   = alloc_cluster_offset,

                .VAR_1         = alloc_offset,

                .VAR_2        = VAR_10 == 0 ? VAR_2 : 0,

                .VAR_9    = VAR_9,

                .nb_available   = MIN(VAR_11, VAR_12),

            };

            qemu_co_queue_init(&VAR_5->dependent_requests);

            QLIST_INSERT_HEAD(&s->cluster_allocs, VAR_5, next_in_flight);

        }

    }



    

    VAR_8 = (VAR_10 + VAR_9) << (s->cluster_bits - 9);

    if (VAR_8 > VAR_3) {

        VAR_8 = VAR_3;

    }



    assert(VAR_8 > VAR_2);

    *VAR_4 = VAR_8 - VAR_2;



    return 0;



fail:

    if (VAR_5->VAR_9 > 0) {

        QLIST_REMOVE(VAR_5, next_in_flight);

    }

    return VAR_7;

}

int FUNC_0(BlockDriverState *VAR_0, uint64_t VAR_1,
int VAR_2, int VAR_3, int *VAR_4, QCowL2Meta *VAR_5)
{ BDRVQcowState *s = VAR_0->opaque; int VAR_6, VAR_7, VAR_8; uint64_t *l2_table; unsigned int VAR_9, VAR_10; uint64_t cluster_offset; trace_qcow2_alloc_clusters_offset(qemu_coroutine_self(), VAR_1,
VAR_2, VAR_3); again:
VAR_7 = get_cluster_table(VAR_0, VAR_1, &l2_table, &VAR_6); if (VAR_7 < 0) { return VAR_7; } VAR_9 = MIN(size_to_clusters(s, VAR_3 << BDRV_SECTOR_BITS),
s->l2_size - VAR_6); cluster_offset = be64_to_cpu(l2_table[VAR_6]); if (qcow2_get_cluster_type(cluster_offset) == QCOW2_CLUSTER_NORMAL
&& (cluster_offset & QCOW_OFLAG_COPIED))
{ VAR_10 =
count_contiguous_clusters(VAR_9, s->cluster_size,
&l2_table[VAR_6], 0,
QCOW_OFLAG_COPIED | QCOW_OFLAG_ZERO); assert(VAR_10 <= VAR_9); VAR_9 -= VAR_10; } else { if (cluster_offset & QCOW_OFLAG_COMPRESSED) { VAR_9 = 1; } else { VAR_9 = count_cow_clusters(s, VAR_9, l2_table, VAR_6); } VAR_10 = 0; cluster_offset = 0; } cluster_offset &= L2E_OFFSET_MASK; VAR_7 = qcow2_cache_put(VAR_0, s->l2_table_cache, (void**) &l2_table); if (VAR_7 < 0) { return VAR_7; } *VAR_5 = (QCowL2Meta) { .cluster_offset     = cluster_offset,
.VAR_9        = 0,
}; qemu_co_queue_init(&VAR_5->dependent_requests); if (VAR_9 > 0) { uint64_t alloc_offset; uint64_t alloc_cluster_offset; uint64_t keep_bytes = VAR_10 * s->cluster_size; alloc_offset = VAR_1 + keep_bytes; if (VAR_10 == 0) { alloc_cluster_offset = 0; } else { alloc_cluster_offset = cluster_offset + keep_bytes; } VAR_7 = do_alloc_cluster_offset(VAR_0, alloc_offset, &alloc_cluster_offset,
&VAR_9); if (VAR_7 == -EAGAIN) { goto again; } else if (VAR_7 < 0) { goto fail; } if (VAR_9 > 0) { int VAR_11 = VAR_3 - VAR_10 * s->cluster_sectors; int VAR_12 = (VAR_10 + VAR_9)
<< (s->cluster_bits - BDRV_SECTOR_BITS); *VAR_5 = (QCowL2Meta) { .cluster_offset = VAR_10 == 0 ?
alloc_cluster_offset : cluster_offset,
.alloc_offset   = alloc_cluster_offset,
.VAR_1         = alloc_offset,
.VAR_2        = VAR_10 == 0 ? VAR_2 : 0,
.VAR_9    = VAR_9,
.nb_available   = MIN(VAR_11, VAR_12),
}; qemu_co_queue_init(&VAR_5->dependent_requests); QLIST_INSERT_HEAD(&s->cluster_allocs, VAR_5, next_in_flight); } } VAR_8 = (VAR_10 + VAR_9) << (s->cluster_bits - 9); if (VAR_8 > VAR_3) { VAR_8 = VAR_3; } assert(VAR_8 > VAR_2); *VAR_4 = VAR_8 - VAR_2; return 0; fail:
if (VAR_5->VAR_9 > 0) { QLIST_REMOVE(VAR_5, next_in_flight); } return VAR_7; }