static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,

                                                   int64_t offset,

                                                   int64_t length,

                                                   uint64_t addend,

                                                   bool decrease,

                                                   enum qcow2_discard_type type)

{

    BDRVQcowState *s = bs->opaque;

    int64_t start, last, cluster_offset;

    void *refcount_block = NULL;

    int64_t old_table_index = -1;

    int ret;



#ifdef DEBUG_ALLOC2

    fprintf(stderr, "update_refcount: offset=%" PRId64 " size=%" PRId64

            " addend=%s%" PRIu64 "\n", offset, length, decrease ? "-" : "",

            addend);

#endif

    if (length < 0) {

        return -EINVAL;

    } else if (length == 0) {

        return 0;

    }



    if (decrease) {

        qcow2_cache_set_dependency(bs, s->refcount_block_cache,

            s->l2_table_cache);

    }



    start = start_of_cluster(s, offset);

    last = start_of_cluster(s, offset + length - 1);

    for(cluster_offset = start; cluster_offset <= last;

        cluster_offset += s->cluster_size)

    {

        int block_index;

        uint64_t refcount;

        int64_t cluster_index = cluster_offset >> s->cluster_bits;

        int64_t table_index = cluster_index >> s->refcount_block_bits;



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

        if (table_index != old_table_index) {

            if (refcount_block) {

                ret = qcow2_cache_put(bs, s->refcount_block_cache,

                                      &refcount_block);

                if (ret < 0) {

                    goto fail;

                }

            }



            ret = alloc_refcount_block(bs, cluster_index, &refcount_block);

            if (ret < 0) {

                goto fail;

            }

        }

        old_table_index = table_index;



        qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache,

                                     refcount_block);



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

        block_index = cluster_index & (s->refcount_block_size - 1);



        refcount = s->get_refcount(refcount_block, block_index);

        if (decrease ? (refcount - addend > refcount)

                     : (refcount + addend < refcount ||

                        refcount + addend > s->refcount_max))

        {

            ret = -EINVAL;

            goto fail;

        }

        if (decrease) {

            refcount -= addend;

        } else {

            refcount += addend;

        }

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

            s->free_cluster_index = cluster_index;

        }

        s->set_refcount(refcount_block, block_index, refcount);



        if (refcount == 0 && s->discard_passthrough[type]) {

            update_refcount_discard(bs, cluster_offset, s->cluster_size);

        }

    }



    ret = 0;

fail:

    if (!s->cache_discards) {

        qcow2_process_discards(bs, ret);

    }



    /* Write last changed block to disk */

    if (refcount_block) {

        int wret;

        wret = qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);

        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,

                                !decrease, QCOW2_DISCARD_NEVER);

        (void)dummy;

    }



    return ret;

}

static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,

                                                   int64_t offset,

                                                   int64_t length,

                                                   uint64_t addend,

                                                   bool decrease,

                                                   enum qcow2_discard_type type)

{

    BDRVQcowState *s = bs->opaque;

    int64_t start, last, cluster_offset;

    void *refcount_block = NULL;

    int64_t old_table_index = -1;

    int ret;



#ifdef DEBUG_ALLOC2

    fprintf(stderr, "update_refcount: offset=%" PRId64 " size=%" PRId64

            " addend=%s%" PRIu64 "\n", offset, length, decrease ? "-" : "",

            addend);

#endif

    if (length < 0) {

        return -EINVAL;

    } else if (length == 0) {

        return 0;

    }



    if (decrease) {

        qcow2_cache_set_dependency(bs, s->refcount_block_cache,

            s->l2_table_cache);

    }



    start = start_of_cluster(s, offset);

    last = start_of_cluster(s, offset + length - 1);

    for(cluster_offset = start; cluster_offset <= last;

        cluster_offset += s->cluster_size)

    {

        int block_index;

        uint64_t refcount;

        int64_t cluster_index = cluster_offset >> s->cluster_bits;

        int64_t table_index = cluster_index >> s->refcount_block_bits;



        

        if (table_index != old_table_index) {

            if (refcount_block) {

                ret = qcow2_cache_put(bs, s->refcount_block_cache,

                                      &refcount_block);

                if (ret < 0) {

                    goto fail;

                }

            }



            ret = alloc_refcount_block(bs, cluster_index, &refcount_block);

            if (ret < 0) {

                goto fail;

            }

        }

        old_table_index = table_index;



        qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache,

                                     refcount_block);



        

        block_index = cluster_index & (s->refcount_block_size - 1);



        refcount = s->get_refcount(refcount_block, block_index);

        if (decrease ? (refcount - addend > refcount)

                     : (refcount + addend < refcount ||

                        refcount + addend > s->refcount_max))

        {

            ret = -EINVAL;

            goto fail;

        }

        if (decrease) {

            refcount -= addend;

        } else {

            refcount += addend;

        }

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

            s->free_cluster_index = cluster_index;

        }

        s->set_refcount(refcount_block, block_index, refcount);



        if (refcount == 0 && s->discard_passthrough[type]) {

            update_refcount_discard(bs, cluster_offset, s->cluster_size);

        }

    }



    ret = 0;

fail:

    if (!s->cache_discards) {

        qcow2_process_discards(bs, ret);

    }



    

    if (refcount_block) {

        int wret;

        wret = qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);

        if (wret < 0) {

            return ret < 0 ? ret : wret;

        }

    }



    







    if (ret < 0) {

        int dummy;

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

                                !decrease, QCOW2_DISCARD_NEVER);

        (void)dummy;

    }



    return ret;

}

static int VAR_0 update_refcount(BlockDriverState *bs,

                                                   int64_t offset,

                                                   int64_t length,

                                                   uint64_t addend,

                                                   bool decrease,

                                                   enum qcow2_discard_type type)

{

    BDRVQcowState *s = bs->opaque;

    int64_t start, last, cluster_offset;

    void *refcount_block = NULL;

    int64_t old_table_index = -1;

    int ret;



#ifdef DEBUG_ALLOC2

    fprintf(stderr, "update_refcount: offset=%" PRId64 " size=%" PRId64

            " addend=%s%" PRIu64 "\n", offset, length, decrease ? "-" : "",

            addend);

#endif

    if (length < 0) {

        return -EINVAL;

    } else if (length == 0) {

        return 0;

    }



    if (decrease) {

        qcow2_cache_set_dependency(bs, s->refcount_block_cache,

            s->l2_table_cache);

    }



    start = start_of_cluster(s, offset);

    last = start_of_cluster(s, offset + length - 1);

    for(cluster_offset = start; cluster_offset <= last;

        cluster_offset += s->cluster_size)

    {

        int block_index;

        uint64_t refcount;

        int64_t cluster_index = cluster_offset >> s->cluster_bits;

        int64_t table_index = cluster_index >> s->refcount_block_bits;



        

        if (table_index != old_table_index) {

            if (refcount_block) {

                ret = qcow2_cache_put(bs, s->refcount_block_cache,

                                      &refcount_block);

                if (ret < 0) {

                    goto fail;

                }

            }



            ret = alloc_refcount_block(bs, cluster_index, &refcount_block);

            if (ret < 0) {

                goto fail;

            }

        }

        old_table_index = table_index;



        qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache,

                                     refcount_block);



        

        block_index = cluster_index & (s->refcount_block_size - 1);



        refcount = s->get_refcount(refcount_block, block_index);

        if (decrease ? (refcount - addend > refcount)

                     : (refcount + addend < refcount ||

                        refcount + addend > s->refcount_max))

        {

            ret = -EINVAL;

            goto fail;

        }

        if (decrease) {

            refcount -= addend;

        } else {

            refcount += addend;

        }

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

            s->free_cluster_index = cluster_index;

        }

        s->set_refcount(refcount_block, block_index, refcount);



        if (refcount == 0 && s->discard_passthrough[type]) {

            update_refcount_discard(bs, cluster_offset, s->cluster_size);

        }

    }



    ret = 0;

fail:

    if (!s->cache_discards) {

        qcow2_process_discards(bs, ret);

    }



    

    if (refcount_block) {

        int wret;

        wret = qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);

        if (wret < 0) {

            return ret < 0 ? ret : wret;

        }

    }



    







    if (ret < 0) {

        int dummy;

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

                                !decrease, QCOW2_DISCARD_NEVER);

        (void)dummy;

    }



    return ret;

}

static int VAR_0 update_refcount(BlockDriverState *bs,
int64_t offset,
int64_t length,
uint64_t addend,
bool decrease,
enum qcow2_discard_type type)
{ BDRVQcowState *s = bs->opaque; int64_t start, last, cluster_offset; void *refcount_block = NULL; int64_t old_table_index = -1; int ret; #ifdef DEBUG_ALLOC2
fprintf(stderr, "update_refcount: offset=%" PRId64 " size=%" PRId64
" addend=%s%" PRIu64 "\n", offset, length, decrease ? "-" : "",
addend); #endif
if (length < 0) { return -EINVAL; } else if (length == 0) { return 0; } if (decrease) { qcow2_cache_set_dependency(bs, s->refcount_block_cache,
s->l2_table_cache); } start = start_of_cluster(s, offset); last = start_of_cluster(s, offset + length - 1); for(cluster_offset = start; cluster_offset <= last; cluster_offset += s->cluster_size)
{ int block_index; uint64_t refcount; int64_t cluster_index = cluster_offset >> s->cluster_bits; int64_t table_index = cluster_index >> s->refcount_block_bits; if (table_index != old_table_index) { if (refcount_block) { ret = qcow2_cache_put(bs, s->refcount_block_cache,
&refcount_block); if (ret < 0) { goto fail; } } ret = alloc_refcount_block(bs, cluster_index, &refcount_block); if (ret < 0) { goto fail; } } old_table_index = table_index; qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache,
refcount_block); block_index = cluster_index & (s->refcount_block_size - 1); refcount = s->get_refcount(refcount_block, block_index); if (decrease ? (refcount - addend > refcount)
: (refcount + addend < refcount ||
refcount + addend > s->refcount_max))
{ ret = -EINVAL; goto fail; } if (decrease) { refcount -= addend; } else { refcount += addend; } if (refcount == 0 && cluster_index < s->free_cluster_index) { s->free_cluster_index = cluster_index; } s->set_refcount(refcount_block, block_index, refcount); if (refcount == 0 && s->discard_passthrough[type]) { update_refcount_discard(bs, cluster_offset, s->cluster_size); } } ret = 0; fail:
if (!s->cache_discards) { qcow2_process_discards(bs, ret); } if (refcount_block) { int wret; wret = qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block); if (wret < 0) { return ret < 0 ? ret : wret; } } if (ret < 0) { int dummy; dummy = update_refcount(bs, offset, cluster_offset - offset, addend,
!decrease, QCOW2_DISCARD_NEVER); (void)dummy; } return ret; }