static int alloc_refcount_block(BlockDriverState *bs,
    int64_t cluster_index, uint16_t **refcount_block)
{
    BDRVQcowState *s = bs->opaque;
    unsigned int refcount_table_index;
    int ret;
    BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC);
    /* Find the refcount block for the given cluster */
    refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
    if (refcount_table_index < s->refcount_table_size) {
        uint64_t refcount_block_offset =
            s->refcount_table[refcount_table_index] & REFT_OFFSET_MASK;
        /* If it's already there, we're done */
        if (refcount_block_offset) {
             return load_refcount_block(bs, refcount_block_offset,
                 (void**) refcount_block);
    /*
     * If we came here, we need to allocate something. Something is at least
     * a cluster for the new refcount block. It may also include a new refcount
     * table if the old refcount table is too small.
     *
     * Note that allocating clusters here needs some special care:
     *
     * - We can't use the normal qcow2_alloc_clusters(), it would try to
     *   increase the refcount and very likely we would end up with an endless
     *   recursion. Instead we must place the refcount blocks in a way that
     *   they can describe them themselves.
     *
     * - We need to consider that at this point we are inside update_refcounts
     *   and potentially doing an initial refcount increase. This means that
     *   some clusters have already been allocated by the caller, but their
     *   refcount isn't accurate yet. If we allocate clusters for metadata, we
     *   need to return -EAGAIN to signal the caller that it needs to restart
     *   the search for free clusters.
     *
     * - alloc_clusters_noref and qcow2_free_clusters may load a different
     *   refcount block into the cache
     */
    *refcount_block = NULL;
    /* We write to the refcount table, so we might depend on L2 tables */
    ret = qcow2_cache_flush(bs, s->l2_table_cache);
    if (ret < 0) {
        return ret;
    /* Allocate the refcount block itself and mark it as used */
    int64_t new_block = alloc_clusters_noref(bs, s->cluster_size);
    if (new_block < 0) {
        return new_block;
#ifdef DEBUG_ALLOC2
    fprintf(stderr, "qcow2: Allocate refcount block %d for %" PRIx64
        " at %" PRIx64 "\n",
        refcount_table_index, cluster_index << s->cluster_bits, new_block);
#endif
    if (in_same_refcount_block(s, new_block, cluster_index << s->cluster_bits)) {
        /* Zero the new refcount block before updating it */
        ret = qcow2_cache_get_empty(bs, s->refcount_block_cache, new_block,
            (void**) refcount_block);
        if (ret < 0) {
            goto fail_block;
        memset(*refcount_block, 0, s->cluster_size);
        /* The block describes itself, need to update the cache */
        int block_index = (new_block >> s->cluster_bits) &
            ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
        (*refcount_block)[block_index] = cpu_to_be16(1);
    } else {
        /* Described somewhere else. This can recurse at most twice before we
         * arrive at a block that describes itself. */
        ret = update_refcount(bs, new_block, s->cluster_size, 1,
                              QCOW2_DISCARD_NEVER);
        if (ret < 0) {
            goto fail_block;
        ret = qcow2_cache_flush(bs, s->refcount_block_cache);
        if (ret < 0) {
            goto fail_block;
        /* Initialize the new refcount block only after updating its refcount,
         * update_refcount uses the refcount cache itself */
        ret = qcow2_cache_get_empty(bs, s->refcount_block_cache, new_block,
            (void**) refcount_block);
        if (ret < 0) {
            goto fail_block;
        memset(*refcount_block, 0, s->cluster_size);
    /* Now the new refcount block needs to be written to disk */
    BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE);
    qcow2_cache_entry_mark_dirty(s->refcount_block_cache, *refcount_block);
    ret = qcow2_cache_flush(bs, s->refcount_block_cache);
    if (ret < 0) {
        goto fail_block;
    /* If the refcount table is big enough, just hook the block up there */
    if (refcount_table_index < s->refcount_table_size) {
        uint64_t data64 = cpu_to_be64(new_block);
        BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_HOOKUP);
        ret = bdrv_pwrite_sync(bs->file,
            s->refcount_table_offset + refcount_table_index * sizeof(uint64_t),
            &data64, sizeof(data64));
        if (ret < 0) {
            goto fail_block;
        s->refcount_table[refcount_table_index] = new_block;
        /* The new refcount block may be where the caller intended to put its
         * data, so let it restart the search. */
        return -EAGAIN;
    ret = qcow2_cache_put(bs, s->refcount_block_cache, (void**) refcount_block);
    if (ret < 0) {
        goto fail_block;
    /*
     * If we come here, we need to grow the refcount table. Again, a new
     * refcount table needs some space and we can't simply allocate to avoid
     * endless recursion.
     *
     * Therefore let's grab new refcount blocks at the end of the image, which
     * will describe themselves and the new refcount table. This way we can
     * reference them only in the new table and do the switch to the new
     * refcount table at once without producing an inconsistent state in
     * between.
     */
    BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_GROW);
    /* Calculate the number of refcount blocks needed so far */
    uint64_t refcount_block_clusters = 1 << (s->cluster_bits - REFCOUNT_SHIFT);
    uint64_t blocks_used = DIV_ROUND_UP(cluster_index, refcount_block_clusters);
    /* And now we need at least one block more for the new metadata */
    uint64_t table_size = next_refcount_table_size(s, blocks_used + 1);
    uint64_t last_table_size;
    uint64_t blocks_clusters;
    do {
        uint64_t table_clusters =
            size_to_clusters(s, table_size * sizeof(uint64_t));
        blocks_clusters = 1 +
            ((table_clusters + refcount_block_clusters - 1)
            / refcount_block_clusters);
        uint64_t meta_clusters = table_clusters + blocks_clusters;
        last_table_size = table_size;
        table_size = next_refcount_table_size(s, blocks_used +
            ((meta_clusters + refcount_block_clusters - 1)
            / refcount_block_clusters));
    } while (last_table_size != table_size);
#ifdef DEBUG_ALLOC2
    fprintf(stderr, "qcow2: Grow refcount table %" PRId32 " => %" PRId64 "\n",
        s->refcount_table_size, table_size);
#endif
    /* Create the new refcount table and blocks */
    uint64_t meta_offset = (blocks_used * refcount_block_clusters) *
        s->cluster_size;
    uint64_t table_offset = meta_offset + blocks_clusters * s->cluster_size;
    uint16_t *new_blocks = g_malloc0(blocks_clusters * s->cluster_size);
    uint64_t *new_table = g_malloc0(table_size * sizeof(uint64_t));
    /* Fill the new refcount table */
    memcpy(new_table, s->refcount_table,
        s->refcount_table_size * sizeof(uint64_t));
    new_table[refcount_table_index] = new_block;
    int i;
    for (i = 0; i < blocks_clusters; i++) {
        new_table[blocks_used + i] = meta_offset + (i * s->cluster_size);
    /* Fill the refcount blocks */
    uint64_t table_clusters = size_to_clusters(s, table_size * sizeof(uint64_t));
    int block = 0;
    for (i = 0; i < table_clusters + blocks_clusters; i++) {
        new_blocks[block++] = cpu_to_be16(1);
    /* Write refcount blocks to disk */
    BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS);
    ret = bdrv_pwrite_sync(bs->file, meta_offset, new_blocks,
        blocks_clusters * s->cluster_size);
    g_free(new_blocks);
    if (ret < 0) {
        goto fail_table;
    /* Write refcount table to disk */
    for(i = 0; i < table_size; i++) {
        cpu_to_be64s(&new_table[i]);
    BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE);
    ret = bdrv_pwrite_sync(bs->file, table_offset, new_table,
        table_size * sizeof(uint64_t));
    if (ret < 0) {
        goto fail_table;
    for(i = 0; i < table_size; i++) {
        be64_to_cpus(&new_table[i]);
    /* Hook up the new refcount table in the qcow2 header */
    uint8_t data[12];
    cpu_to_be64w((uint64_t*)data, table_offset);
    cpu_to_be32w((uint32_t*)(data + 8), table_clusters);
    BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE);
    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, refcount_table_offset),
        data, sizeof(data));
    if (ret < 0) {
        goto fail_table;
    /* And switch it in memory */
    uint64_t old_table_offset = s->refcount_table_offset;
    uint64_t old_table_size = s->refcount_table_size;
    g_free(s->refcount_table);
    s->refcount_table = new_table;
    s->refcount_table_size = table_size;
    s->refcount_table_offset = table_offset;
    /* Free old table. */
    qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t),
                        QCOW2_DISCARD_OTHER);
    ret = load_refcount_block(bs, new_block, (void**) refcount_block);
    if (ret < 0) {
        return ret;
    /* If we were trying to do the initial refcount update for some cluster
     * allocation, we might have used the same clusters to store newly
     * allocated metadata. Make the caller search some new space. */
    return -EAGAIN;
fail_table:
    g_free(new_table);
fail_block:
    if (*refcount_block != NULL) {
        qcow2_cache_put(bs, s->refcount_block_cache, (void**) refcount_block);
    return ret;
static int alloc_refcount_block(BlockDriverState *bs,
    int64_t cluster_index, uint16_t **refcount_block)
{
    BDRVQcowState *s = bs->opaque;
    unsigned int refcount_table_index;
    int ret;
    BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC);
    
    refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);
    if (refcount_table_index < s->refcount_table_size) {
        uint64_t refcount_block_offset =
            s->refcount_table[refcount_table_index] & REFT_OFFSET_MASK;
        
        if (refcount_block_offset) {
             return load_refcount_block(bs, refcount_block_offset,
                 (void**) refcount_block);
    





















    *refcount_block = NULL;
    
    ret = qcow2_cache_flush(bs, s->l2_table_cache);
    if (ret < 0) {
        return ret;
    
    int64_t new_block = alloc_clusters_noref(bs, s->cluster_size);
    if (new_block < 0) {
        return new_block;
#ifdef DEBUG_ALLOC2
    fprintf(stderr, "qcow2: Allocate refcount block %d for %" PRIx64
        " at %" PRIx64 "\n",
        refcount_table_index, cluster_index << s->cluster_bits, new_block);
#endif
    if (in_same_refcount_block(s, new_block, cluster_index << s->cluster_bits)) {
        
        ret = qcow2_cache_get_empty(bs, s->refcount_block_cache, new_block,
            (void**) refcount_block);
        if (ret < 0) {
            goto fail_block;
        memset(*refcount_block, 0, s->cluster_size);
        
        int block_index = (new_block >> s->cluster_bits) &
            ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
        (*refcount_block)[block_index] = cpu_to_be16(1);
    } else {
        

        ret = update_refcount(bs, new_block, s->cluster_size, 1,
                              QCOW2_DISCARD_NEVER);
        if (ret < 0) {
            goto fail_block;
        ret = qcow2_cache_flush(bs, s->refcount_block_cache);
        if (ret < 0) {
            goto fail_block;
        

        ret = qcow2_cache_get_empty(bs, s->refcount_block_cache, new_block,
            (void**) refcount_block);
        if (ret < 0) {
            goto fail_block;
        memset(*refcount_block, 0, s->cluster_size);
    
    BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE);
    qcow2_cache_entry_mark_dirty(s->refcount_block_cache, *refcount_block);
    ret = qcow2_cache_flush(bs, s->refcount_block_cache);
    if (ret < 0) {
        goto fail_block;
    
    if (refcount_table_index < s->refcount_table_size) {
        uint64_t data64 = cpu_to_be64(new_block);
        BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_HOOKUP);
        ret = bdrv_pwrite_sync(bs->file,
            s->refcount_table_offset + refcount_table_index * sizeof(uint64_t),
            &data64, sizeof(data64));
        if (ret < 0) {
            goto fail_block;
        s->refcount_table[refcount_table_index] = new_block;
        

        return -EAGAIN;
    ret = qcow2_cache_put(bs, s->refcount_block_cache, (void**) refcount_block);
    if (ret < 0) {
        goto fail_block;
    










    BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_GROW);
    
    uint64_t refcount_block_clusters = 1 << (s->cluster_bits - REFCOUNT_SHIFT);
    uint64_t blocks_used = DIV_ROUND_UP(cluster_index, refcount_block_clusters);
    
    uint64_t table_size = next_refcount_table_size(s, blocks_used + 1);
    uint64_t last_table_size;
    uint64_t blocks_clusters;
    do {
        uint64_t table_clusters =
            size_to_clusters(s, table_size * sizeof(uint64_t));
        blocks_clusters = 1 +
            ((table_clusters + refcount_block_clusters - 1)
            / refcount_block_clusters);
        uint64_t meta_clusters = table_clusters + blocks_clusters;
        last_table_size = table_size;
        table_size = next_refcount_table_size(s, blocks_used +
            ((meta_clusters + refcount_block_clusters - 1)
            / refcount_block_clusters));
    } while (last_table_size != table_size);
#ifdef DEBUG_ALLOC2
    fprintf(stderr, "qcow2: Grow refcount table %" PRId32 " => %" PRId64 "\n",
        s->refcount_table_size, table_size);
#endif
    
    uint64_t meta_offset = (blocks_used * refcount_block_clusters) *
        s->cluster_size;
    uint64_t table_offset = meta_offset + blocks_clusters * s->cluster_size;
    uint16_t *new_blocks = g_malloc0(blocks_clusters * s->cluster_size);
    uint64_t *new_table = g_malloc0(table_size * sizeof(uint64_t));
    
    memcpy(new_table, s->refcount_table,
        s->refcount_table_size * sizeof(uint64_t));
    new_table[refcount_table_index] = new_block;
    int i;
    for (i = 0; i < blocks_clusters; i++) {
        new_table[blocks_used + i] = meta_offset + (i * s->cluster_size);
    
    uint64_t table_clusters = size_to_clusters(s, table_size * sizeof(uint64_t));
    int block = 0;
    for (i = 0; i < table_clusters + blocks_clusters; i++) {
        new_blocks[block++] = cpu_to_be16(1);
    
    BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS);
    ret = bdrv_pwrite_sync(bs->file, meta_offset, new_blocks,
        blocks_clusters * s->cluster_size);
    g_free(new_blocks);
    if (ret < 0) {
        goto fail_table;
    
    for(i = 0; i < table_size; i++) {
        cpu_to_be64s(&new_table[i]);
    BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE);
    ret = bdrv_pwrite_sync(bs->file, table_offset, new_table,
        table_size * sizeof(uint64_t));
    if (ret < 0) {
        goto fail_table;
    for(i = 0; i < table_size; i++) {
        be64_to_cpus(&new_table[i]);
    
    uint8_t data[12];
    cpu_to_be64w((uint64_t*)data, table_offset);
    cpu_to_be32w((uint32_t*)(data + 8), table_clusters);
    BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE);
    ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, refcount_table_offset),
        data, sizeof(data));
    if (ret < 0) {
        goto fail_table;
    
    uint64_t old_table_offset = s->refcount_table_offset;
    uint64_t old_table_size = s->refcount_table_size;
    g_free(s->refcount_table);
    s->refcount_table = new_table;
    s->refcount_table_size = table_size;
    s->refcount_table_offset = table_offset;
    
    qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t),
                        QCOW2_DISCARD_OTHER);
    ret = load_refcount_block(bs, new_block, (void**) refcount_block);
    if (ret < 0) {
        return ret;
    


    return -EAGAIN;
fail_table:
    g_free(new_table);
fail_block:
    if (*refcount_block != NULL) {
        qcow2_cache_put(bs, s->refcount_block_cache, (void**) refcount_block);
    return ret;
static int FUNC_0(BlockDriverState *VAR_0,
    int64_t VAR_1, uint16_t **VAR_2)
{
    BDRVQcowState *s = VAR_0->opaque;
    unsigned int VAR_3;
    int VAR_4;
    BLKDBG_EVENT(VAR_0->file, BLKDBG_REFBLOCK_ALLOC);
    
    VAR_3 = VAR_1 >> (s->cluster_bits - REFCOUNT_SHIFT);
    if (VAR_3 < s->refcount_table_size) {
        uint64_t refcount_block_offset =
            s->refcount_table[VAR_3] & REFT_OFFSET_MASK;
        
        if (refcount_block_offset) {
             return load_refcount_block(VAR_0, refcount_block_offset,
                 (void**) VAR_2);
    





















    *VAR_2 = NULL;
    
    VAR_4 = qcow2_cache_flush(VAR_0, s->l2_table_cache);
    if (VAR_4 < 0) {
        return VAR_4;
    
    int64_t new_block = alloc_clusters_noref(VAR_0, s->cluster_size);
    if (new_block < 0) {
        return new_block;
#ifdef DEBUG_ALLOC2
    fprintf(stderr, "qcow2: Allocate refcount block %d for %" PRIx64
        " at %" PRIx64 "\n",
        VAR_3, VAR_1 << s->cluster_bits, new_block);
#endif
    if (in_same_refcount_block(s, new_block, VAR_1 << s->cluster_bits)) {
        
        VAR_4 = qcow2_cache_get_empty(VAR_0, s->refcount_block_cache, new_block,
            (void**) VAR_2);
        if (VAR_4 < 0) {
            goto fail_block;
        memset(*VAR_2, 0, s->cluster_size);
        
        int VAR_5 = (new_block >> s->cluster_bits) &
            ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
        (*VAR_2)[VAR_5] = cpu_to_be16(1);
    } else {
        

        VAR_4 = update_refcount(VAR_0, new_block, s->cluster_size, 1,
                              QCOW2_DISCARD_NEVER);
        if (VAR_4 < 0) {
            goto fail_block;
        VAR_4 = qcow2_cache_flush(VAR_0, s->refcount_block_cache);
        if (VAR_4 < 0) {
            goto fail_block;
        

        VAR_4 = qcow2_cache_get_empty(VAR_0, s->refcount_block_cache, new_block,
            (void**) VAR_2);
        if (VAR_4 < 0) {
            goto fail_block;
        memset(*VAR_2, 0, s->cluster_size);
    
    BLKDBG_EVENT(VAR_0->file, BLKDBG_REFBLOCK_ALLOC_WRITE);
    qcow2_cache_entry_mark_dirty(s->refcount_block_cache, *VAR_2);
    VAR_4 = qcow2_cache_flush(VAR_0, s->refcount_block_cache);
    if (VAR_4 < 0) {
        goto fail_block;
    
    if (VAR_3 < s->refcount_table_size) {
        uint64_t data64 = cpu_to_be64(new_block);
        BLKDBG_EVENT(VAR_0->file, BLKDBG_REFBLOCK_ALLOC_HOOKUP);
        VAR_4 = bdrv_pwrite_sync(VAR_0->file,
            s->refcount_table_offset + VAR_3 * sizeof(uint64_t),
            &data64, sizeof(data64));
        if (VAR_4 < 0) {
            goto fail_block;
        s->refcount_table[VAR_3] = new_block;
        

        return -EAGAIN;
    VAR_4 = qcow2_cache_put(VAR_0, s->refcount_block_cache, (void**) VAR_2);
    if (VAR_4 < 0) {
        goto fail_block;
    










    BLKDBG_EVENT(VAR_0->file, BLKDBG_REFTABLE_GROW);
    
    uint64_t refcount_block_clusters = 1 << (s->cluster_bits - REFCOUNT_SHIFT);
    uint64_t blocks_used = DIV_ROUND_UP(VAR_1, refcount_block_clusters);
    
    uint64_t table_size = next_refcount_table_size(s, blocks_used + 1);
    uint64_t last_table_size;
    uint64_t blocks_clusters;
    do {
        uint64_t table_clusters =
            size_to_clusters(s, table_size * sizeof(uint64_t));
        blocks_clusters = 1 +
            ((table_clusters + refcount_block_clusters - 1)
            / refcount_block_clusters);
        uint64_t meta_clusters = table_clusters + blocks_clusters;
        last_table_size = table_size;
        table_size = next_refcount_table_size(s, blocks_used +
            ((meta_clusters + refcount_block_clusters - 1)
            / refcount_block_clusters));
    } while (last_table_size != table_size);
#ifdef DEBUG_ALLOC2
    fprintf(stderr, "qcow2: Grow refcount table %" PRId32 " => %" PRId64 "\n",
        s->refcount_table_size, table_size);
#endif
    
    uint64_t meta_offset = (blocks_used * refcount_block_clusters) *
        s->cluster_size;
    uint64_t table_offset = meta_offset + blocks_clusters * s->cluster_size;
    uint16_t *new_blocks = g_malloc0(blocks_clusters * s->cluster_size);
    uint64_t *new_table = g_malloc0(table_size * sizeof(uint64_t));
    
    memcpy(new_table, s->refcount_table,
        s->refcount_table_size * sizeof(uint64_t));
    new_table[VAR_3] = new_block;
    int VAR_6;
    for (VAR_6 = 0; VAR_6 < blocks_clusters; VAR_6++) {
        new_table[blocks_used + VAR_6] = meta_offset + (VAR_6 * s->cluster_size);
    
    uint64_t table_clusters = size_to_clusters(s, table_size * sizeof(uint64_t));
    int block = 0;
    for (VAR_6 = 0; VAR_6 < table_clusters + blocks_clusters; VAR_6++) {
        new_blocks[block++] = cpu_to_be16(1);
    
    BLKDBG_EVENT(VAR_0->file, BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS);
    VAR_4 = bdrv_pwrite_sync(VAR_0->file, meta_offset, new_blocks,
        blocks_clusters * s->cluster_size);
    g_free(new_blocks);
    if (VAR_4 < 0) {
        goto fail_table;
    
    for(VAR_6 = 0; VAR_6 < table_size; VAR_6++) {
        cpu_to_be64s(&new_table[VAR_6]);
    BLKDBG_EVENT(VAR_0->file, BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE);
    VAR_4 = bdrv_pwrite_sync(VAR_0->file, table_offset, new_table,
        table_size * sizeof(uint64_t));
    if (VAR_4 < 0) {
        goto fail_table;
    for(VAR_6 = 0; VAR_6 < table_size; VAR_6++) {
        be64_to_cpus(&new_table[VAR_6]);
    
    uint8_t data[12];
    cpu_to_be64w((uint64_t*)data, table_offset);
    cpu_to_be32w((uint32_t*)(data + 8), table_clusters);
    BLKDBG_EVENT(VAR_0->file, BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE);
    VAR_4 = bdrv_pwrite_sync(VAR_0->file, offsetof(QCowHeader, refcount_table_offset),
        data, sizeof(data));
    if (VAR_4 < 0) {
        goto fail_table;
    
    uint64_t old_table_offset = s->refcount_table_offset;
    uint64_t old_table_size = s->refcount_table_size;
    g_free(s->refcount_table);
    s->refcount_table = new_table;
    s->refcount_table_size = table_size;
    s->refcount_table_offset = table_offset;
    
    qcow2_free_clusters(VAR_0, old_table_offset, old_table_size * sizeof(uint64_t),
                        QCOW2_DISCARD_OTHER);
    VAR_4 = load_refcount_block(VAR_0, new_block, (void**) VAR_2);
    if (VAR_4 < 0) {
        return VAR_4;
    


    return -EAGAIN;
fail_table:
    g_free(new_table);
fail_block:
    if (*VAR_2 != NULL) {
        qcow2_cache_put(VAR_0, s->refcount_block_cache, (void**) VAR_2);
    return VAR_4;
static int FUNC_0(BlockDriverState *VAR_0,
int64_t VAR_1, uint16_t **VAR_2)
{ BDRVQcowState *s = VAR_0->opaque; unsigned int VAR_3; int VAR_4; BLKDBG_EVENT(VAR_0->file, BLKDBG_REFBLOCK_ALLOC); VAR_3 = VAR_1 >> (s->cluster_bits - REFCOUNT_SHIFT); if (VAR_3 < s->refcount_table_size) { uint64_t refcount_block_offset =
s->refcount_table[VAR_3] & REFT_OFFSET_MASK; if (refcount_block_offset) { return load_refcount_block(VAR_0, refcount_block_offset,
(void**) VAR_2); *VAR_2 = NULL; VAR_4 = qcow2_cache_flush(VAR_0, s->l2_table_cache); if (VAR_4 < 0) { return VAR_4; int64_t new_block = alloc_clusters_noref(VAR_0, s->cluster_size); if (new_block < 0) { return new_block; #ifdef DEBUG_ALLOC2
fprintf(stderr, "qcow2: Allocate refcount block %d for %" PRIx64
" at %" PRIx64 "\n",
VAR_3, VAR_1 << s->cluster_bits, new_block); #endif
if (in_same_refcount_block(s, new_block, VAR_1 << s->cluster_bits)) { VAR_4 = qcow2_cache_get_empty(VAR_0, s->refcount_block_cache, new_block,
(void**) VAR_2); if (VAR_4 < 0) { goto fail_block; memset(*VAR_2, 0, s->cluster_size); int VAR_5 = (new_block >> s->cluster_bits) &
((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1); (*VAR_2)[VAR_5] = cpu_to_be16(1); } else { VAR_4 = update_refcount(VAR_0, new_block, s->cluster_size, 1,
QCOW2_DISCARD_NEVER); if (VAR_4 < 0) { goto fail_block; VAR_4 = qcow2_cache_flush(VAR_0, s->refcount_block_cache); if (VAR_4 < 0) { goto fail_block; VAR_4 = qcow2_cache_get_empty(VAR_0, s->refcount_block_cache, new_block,
(void**) VAR_2); if (VAR_4 < 0) { goto fail_block; memset(*VAR_2, 0, s->cluster_size); BLKDBG_EVENT(VAR_0->file, BLKDBG_REFBLOCK_ALLOC_WRITE); qcow2_cache_entry_mark_dirty(s->refcount_block_cache, *VAR_2); VAR_4 = qcow2_cache_flush(VAR_0, s->refcount_block_cache); if (VAR_4 < 0) { goto fail_block; if (VAR_3 < s->refcount_table_size) { uint64_t data64 = cpu_to_be64(new_block); BLKDBG_EVENT(VAR_0->file, BLKDBG_REFBLOCK_ALLOC_HOOKUP); VAR_4 = bdrv_pwrite_sync(VAR_0->file,
s->refcount_table_offset + VAR_3 * sizeof(uint64_t),
&data64, sizeof(data64)); if (VAR_4 < 0) { goto fail_block; s->refcount_table[VAR_3] = new_block; return -EAGAIN; VAR_4 = qcow2_cache_put(VAR_0, s->refcount_block_cache, (void**) VAR_2); if (VAR_4 < 0) { goto fail_block; BLKDBG_EVENT(VAR_0->file, BLKDBG_REFTABLE_GROW); uint64_t refcount_block_clusters = 1 << (s->cluster_bits - REFCOUNT_SHIFT); uint64_t blocks_used = DIV_ROUND_UP(VAR_1, refcount_block_clusters); uint64_t table_size = next_refcount_table_size(s, blocks_used + 1); uint64_t last_table_size; uint64_t blocks_clusters; do { uint64_t table_clusters =
size_to_clusters(s, table_size * sizeof(uint64_t)); blocks_clusters = 1 +
((table_clusters + refcount_block_clusters - 1)
/ refcount_block_clusters); uint64_t meta_clusters = table_clusters + blocks_clusters; last_table_size = table_size; table_size = next_refcount_table_size(s, blocks_used +
((meta_clusters + refcount_block_clusters - 1)
/ refcount_block_clusters)); } while (last_table_size != table_size); #ifdef DEBUG_ALLOC2
fprintf(stderr, "qcow2: Grow refcount table %" PRId32 " => %" PRId64 "\n",
s->refcount_table_size, table_size); #endif
uint64_t meta_offset = (blocks_used * refcount_block_clusters) *
s->cluster_size; uint64_t table_offset = meta_offset + blocks_clusters * s->cluster_size; uint16_t *new_blocks = g_malloc0(blocks_clusters * s->cluster_size); uint64_t *new_table = g_malloc0(table_size * sizeof(uint64_t)); memcpy(new_table, s->refcount_table,
s->refcount_table_size * sizeof(uint64_t)); new_table[VAR_3] = new_block; int VAR_6; for (VAR_6 = 0; VAR_6 < blocks_clusters; VAR_6++) { new_table[blocks_used + VAR_6] = meta_offset + (VAR_6 * s->cluster_size); uint64_t table_clusters = size_to_clusters(s, table_size * sizeof(uint64_t)); int block = 0; for (VAR_6 = 0; VAR_6 < table_clusters + blocks_clusters; VAR_6++) { new_blocks[block++] = cpu_to_be16(1); BLKDBG_EVENT(VAR_0->file, BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS); VAR_4 = bdrv_pwrite_sync(VAR_0->file, meta_offset, new_blocks,
blocks_clusters * s->cluster_size); g_free(new_blocks); if (VAR_4 < 0) { goto fail_table; for(VAR_6 = 0; VAR_6 < table_size; VAR_6++) { cpu_to_be64s(&new_table[VAR_6]); BLKDBG_EVENT(VAR_0->file, BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE); VAR_4 = bdrv_pwrite_sync(VAR_0->file, table_offset, new_table,
table_size * sizeof(uint64_t)); if (VAR_4 < 0) { goto fail_table; for(VAR_6 = 0; VAR_6 < table_size; VAR_6++) { be64_to_cpus(&new_table[VAR_6]); uint8_t data[12]; cpu_to_be64w((uint64_t*)data, table_offset); cpu_to_be32w((uint32_t*)(data + 8), table_clusters); BLKDBG_EVENT(VAR_0->file, BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE); VAR_4 = bdrv_pwrite_sync(VAR_0->file, offsetof(QCowHeader, refcount_table_offset),
data, sizeof(data)); if (VAR_4 < 0) { goto fail_table; uint64_t old_table_offset = s->refcount_table_offset; uint64_t old_table_size = s->refcount_table_size; g_free(s->refcount_table); s->refcount_table = new_table; s->refcount_table_size = table_size; s->refcount_table_offset = table_offset; qcow2_free_clusters(VAR_0, old_table_offset, old_table_size * sizeof(uint64_t),
QCOW2_DISCARD_OTHER); VAR_4 = load_refcount_block(VAR_0, new_block, (void**) VAR_2); if (VAR_4 < 0) { return VAR_4; return -EAGAIN; fail_table:
g_free(new_table); fail_block:
if (*VAR_2 != NULL) { qcow2_cache_put(VAR_0, s->refcount_block_cache, (void**) VAR_2); return VAR_4;