static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,

    int64_t offset, int64_t length, int addend)

{

    BDRVQcowState *s = bs->opaque;

    int64_t start, last, cluster_offset;

    int64_t refcount_block_offset = 0;

    int64_t table_index = -1, old_table_index;

    int first_index = -1, last_index = -1;

    int ret;



#ifdef DEBUG_ALLOC2

    printf("update_refcount: offset=%" PRId64 " size=%" PRId64 " addend=%d\n",

           offset, length, addend);

#endif

    if (length < 0) {

        return -EINVAL;

    } else if (length == 0) {

        return 0;

    }



    start = offset & ~(s->cluster_size - 1);

    last = (offset + length - 1) & ~(s->cluster_size - 1);

    for(cluster_offset = start; cluster_offset <= last;

        cluster_offset += s->cluster_size)

    {

        int block_index, refcount;

        int64_t cluster_index = cluster_offset >> s->cluster_bits;

        int64_t new_block;



        /* Only write refcount block to disk when we are done with it */

        old_table_index = table_index;

        table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);

        if ((old_table_index >= 0) && (table_index != old_table_index)) {



            ret = write_refcount_block_entries(bs, refcount_block_offset,

                first_index, last_index);

            if (ret < 0) {

                return ret;

            }



            first_index = -1;

            last_index = -1;

        }



        /* Load the refcount block and allocate it if needed */

        new_block = alloc_refcount_block(bs, cluster_index);

        if (new_block < 0) {

            ret = new_block;

            goto fail;

        }

        refcount_block_offset = new_block;



        /* we can update the count and save it */

        block_index = cluster_index &

            ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);

        if (first_index == -1 || block_index < first_index) {

            first_index = block_index;

        }

        if (block_index > last_index) {

            last_index = block_index;

        }



        refcount = be16_to_cpu(s->refcount_block_cache[block_index]);

        refcount += addend;

        if (refcount < 0 || refcount > 0xffff) {

            ret = -EINVAL;

            goto fail;

        }

        if (refcount == 0 && cluster_index < s->free_cluster_index) {

            s->free_cluster_index = cluster_index;

        }

        s->refcount_block_cache[block_index] = cpu_to_be16(refcount);

    }



    ret = 0;

fail:



    /* Write last changed block to disk */

    if (refcount_block_offset != 0) {

        int wret;

        wret = write_refcount_block_entries(bs, refcount_block_offset,

            first_index, last_index);

        if (wret < 0) {

            return ret < 0 ? ret : wret;

        }

    }



    /*

     * Try do undo any updates if an error is returned (This may succeed in

     * some cases like ENOSPC for allocating a new refcount block)

     */

    if (ret < 0) {

        int dummy;

        dummy = update_refcount(bs, offset, cluster_offset - offset, -addend);

    }



    bdrv_flush(bs->file);



    return ret;

}

static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,

    int64_t offset, int64_t length, int addend)

{

    BDRVQcowState *s = bs->opaque;

    int64_t start, last, cluster_offset;

    int64_t refcount_block_offset = 0;

    int64_t table_index = -1, old_table_index;

    int first_index = -1, last_index = -1;

    int ret;



#ifdef DEBUG_ALLOC2

    printf("update_refcount: offset=%" PRId64 " size=%" PRId64 " addend=%d\n",

           offset, length, addend);

#endif

    if (length < 0) {

        return -EINVAL;

    } else if (length == 0) {

        return 0;

    }



    start = offset & ~(s->cluster_size - 1);

    last = (offset + length - 1) & ~(s->cluster_size - 1);

    for(cluster_offset = start; cluster_offset <= last;

        cluster_offset += s->cluster_size)

    {

        int block_index, refcount;

        int64_t cluster_index = cluster_offset >> s->cluster_bits;

        int64_t new_block;



        

        old_table_index = table_index;

        table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);

        if ((old_table_index >= 0) && (table_index != old_table_index)) {



            ret = write_refcount_block_entries(bs, refcount_block_offset,

                first_index, last_index);

            if (ret < 0) {

                return ret;

            }



            first_index = -1;

            last_index = -1;

        }



        

        new_block = alloc_refcount_block(bs, cluster_index);

        if (new_block < 0) {

            ret = new_block;

            goto fail;

        }

        refcount_block_offset = new_block;



        

        block_index = cluster_index &

            ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);

        if (first_index == -1 || block_index < first_index) {

            first_index = block_index;

        }

        if (block_index > last_index) {

            last_index = block_index;

        }



        refcount = be16_to_cpu(s->refcount_block_cache[block_index]);

        refcount += addend;

        if (refcount < 0 || refcount > 0xffff) {

            ret = -EINVAL;

            goto fail;

        }

        if (refcount == 0 && cluster_index < s->free_cluster_index) {

            s->free_cluster_index = cluster_index;

        }

        s->refcount_block_cache[block_index] = cpu_to_be16(refcount);

    }



    ret = 0;

fail:



    

    if (refcount_block_offset != 0) {

        int wret;

        wret = write_refcount_block_entries(bs, refcount_block_offset,

            first_index, last_index);

        if (wret < 0) {

            return ret < 0 ? ret : wret;

        }

    }



    







    if (ret < 0) {

        int dummy;

        dummy = update_refcount(bs, offset, cluster_offset - offset, -addend);

    }



    bdrv_flush(bs->file);



    return ret;

}

    bdrv_flush(bs->file);
static int VAR_0 update_refcount(BlockDriverState *bs,

    int64_t offset, int64_t length, int addend)

{

    BDRVQcowState *s = bs->opaque;

    int64_t start, last, cluster_offset;

    int64_t refcount_block_offset = 0;

    int64_t table_index = -1, old_table_index;

    int first_index = -1, last_index = -1;

    int ret;



#ifdef DEBUG_ALLOC2

    printf("update_refcount: offset=%" PRId64 " size=%" PRId64 " addend=%d\n",

           offset, length, addend);

#endif

    if (length < 0) {

        return -EINVAL;

    } else if (length == 0) {

        return 0;

    }



    start = offset & ~(s->cluster_size - 1);

    last = (offset + length - 1) & ~(s->cluster_size - 1);

    for(cluster_offset = start; cluster_offset <= last;

        cluster_offset += s->cluster_size)

    {

        int block_index, refcount;

        int64_t cluster_index = cluster_offset >> s->cluster_bits;

        int64_t new_block;



        

        old_table_index = table_index;

        table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT);

        if ((old_table_index >= 0) && (table_index != old_table_index)) {



            ret = write_refcount_block_entries(bs, refcount_block_offset,

                first_index, last_index);

            if (ret < 0) {

                return ret;

            }



            first_index = -1;

            last_index = -1;

        }



        

        new_block = alloc_refcount_block(bs, cluster_index);

        if (new_block < 0) {

            ret = new_block;

            goto fail;

        }

        refcount_block_offset = new_block;



        

        block_index = cluster_index &

            ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);

        if (first_index == -1 || block_index < first_index) {

            first_index = block_index;

        }

        if (block_index > last_index) {

            last_index = block_index;

        }



        refcount = be16_to_cpu(s->refcount_block_cache[block_index]);

        refcount += addend;

        if (refcount < 0 || refcount > 0xffff) {

            ret = -EINVAL;

            goto fail;

        }

        if (refcount == 0 && cluster_index < s->free_cluster_index) {

            s->free_cluster_index = cluster_index;

        }

        s->refcount_block_cache[block_index] = cpu_to_be16(refcount);

    }



    ret = 0;

fail:



    

    if (refcount_block_offset != 0) {

        int wret;

        wret = write_refcount_block_entries(bs, refcount_block_offset,

            first_index, last_index);

        if (wret < 0) {

            return ret < 0 ? ret : wret;

        }

    }



    







    if (ret < 0) {

        int dummy;

        dummy = update_refcount(bs, offset, cluster_offset - offset, -addend);

    }



    bdrv_flush(bs->file);



    return ret;

}

static int VAR_0 update_refcount(BlockDriverState *bs,
int64_t offset, int64_t length, int addend)
{ BDRVQcowState *s = bs->opaque; int64_t start, last, cluster_offset; int64_t refcount_block_offset = 0; int64_t table_index = -1, old_table_index; int first_index = -1, last_index = -1; int ret; #ifdef DEBUG_ALLOC2
printf("update_refcount: offset=%" PRId64 " size=%" PRId64 " addend=%d\n",
offset, length, addend); #endif
if (length < 0) { return -EINVAL; } else if (length == 0) { return 0; } start = offset & ~(s->cluster_size - 1); last = (offset + length - 1) & ~(s->cluster_size - 1); for(cluster_offset = start; cluster_offset <= last; cluster_offset += s->cluster_size)
{ int block_index, refcount; int64_t cluster_index = cluster_offset >> s->cluster_bits; int64_t new_block; old_table_index = table_index; table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT); if ((old_table_index >= 0) && (table_index != old_table_index)) { ret = write_refcount_block_entries(bs, refcount_block_offset,
first_index, last_index); if (ret < 0) { return ret; } first_index = -1; last_index = -1; } new_block = alloc_refcount_block(bs, cluster_index); if (new_block < 0) { ret = new_block; goto fail; } refcount_block_offset = new_block; block_index = cluster_index &
((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1); if (first_index == -1 || block_index < first_index) { first_index = block_index; } if (block_index > last_index) { last_index = block_index; } refcount = be16_to_cpu(s->refcount_block_cache[block_index]); refcount += addend; if (refcount < 0 || refcount > 0xffff) { ret = -EINVAL; goto fail; } if (refcount == 0 && cluster_index < s->free_cluster_index) { s->free_cluster_index = cluster_index; } s->refcount_block_cache[block_index] = cpu_to_be16(refcount); } ret = 0; fail:
if (refcount_block_offset != 0) { int wret; wret = write_refcount_block_entries(bs, refcount_block_offset,
first_index, last_index); if (wret < 0) { return ret < 0 ? ret : wret; } } if (ret < 0) { int dummy; dummy = update_refcount(bs, offset, cluster_offset - offset, -addend); } bdrv_flush(bs->file); return ret; }