int qcow2_update_snapshot_refcount(BlockDriverState *bs,

    int64_t l1_table_offset, int l1_size, int addend)

{

    BDRVQcowState *s = bs->opaque;

    uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, l1_allocated;

    int64_t old_offset, old_l2_offset;

    int i, j, l1_modified = 0, nb_csectors, refcount;

    int ret;



    l2_table = NULL;

    l1_table = NULL;

    l1_size2 = l1_size * sizeof(uint64_t);



    /* WARNING: qcow2_snapshot_goto relies on this function not using the

     * l1_table_offset when it is the current s->l1_table_offset! Be careful

     * when changing this! */

    if (l1_table_offset != s->l1_table_offset) {

        l1_table = g_malloc0(align_offset(l1_size2, 512));

        l1_allocated = 1;



        ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2);

        if (ret < 0) {

            goto fail;

        }



        for(i = 0;i < l1_size; i++)

            be64_to_cpus(&l1_table[i]);

    } else {

        assert(l1_size == s->l1_size);

        l1_table = s->l1_table;

        l1_allocated = 0;

    }



    for(i = 0; i < l1_size; i++) {

        l2_offset = l1_table[i];

        if (l2_offset) {

            old_l2_offset = l2_offset;

            l2_offset &= L1E_OFFSET_MASK;



            ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,

                (void**) &l2_table);

            if (ret < 0) {

                goto fail;

            }



            for(j = 0; j < s->l2_size; j++) {

                offset = be64_to_cpu(l2_table[j]);

                if (offset != 0) {

                    old_offset = offset;

                    offset &= ~QCOW_OFLAG_COPIED;

                    if (offset & QCOW_OFLAG_COMPRESSED) {

                        nb_csectors = ((offset >> s->csize_shift) &

                                       s->csize_mask) + 1;

                        if (addend != 0) {

                            int ret;

                            ret = update_refcount(bs,

                                (offset & s->cluster_offset_mask) & ~511,

                                nb_csectors * 512, addend);

                            if (ret < 0) {

                                goto fail;

                            }

                        }

                        /* compressed clusters are never modified */

                        refcount = 2;

                    } else {

                        uint64_t cluster_index = (offset & L2E_OFFSET_MASK) >> s->cluster_bits;

                        if (addend != 0) {

                            refcount = update_cluster_refcount(bs, cluster_index, addend);

                        } else {

                            refcount = get_refcount(bs, cluster_index);

                        }



                        if (refcount < 0) {

                            ret = refcount;

                            goto fail;

                        }

                    }



                    if (refcount == 1) {

                        offset |= QCOW_OFLAG_COPIED;

                    }

                    if (offset != old_offset) {

                        if (addend > 0) {

                            qcow2_cache_set_dependency(bs, s->l2_table_cache,

                                s->refcount_block_cache);

                        }

                        l2_table[j] = cpu_to_be64(offset);

                        qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);

                    }

                }

            }



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

            if (ret < 0) {

                goto fail;

            }





            if (addend != 0) {

                refcount = update_cluster_refcount(bs, l2_offset >> s->cluster_bits, addend);

            } else {

                refcount = get_refcount(bs, l2_offset >> s->cluster_bits);

            }

            if (refcount < 0) {

                ret = refcount;

                goto fail;

            } else if (refcount == 1) {

                l2_offset |= QCOW_OFLAG_COPIED;

            }

            if (l2_offset != old_l2_offset) {

                l1_table[i] = l2_offset;

                l1_modified = 1;

            }

        }

    }



    ret = bdrv_flush(bs);

fail:

    if (l2_table) {

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

    }



    /* Update L1 only if it isn't deleted anyway (addend = -1) */

    if (addend >= 0 && l1_modified) {

        for(i = 0; i < l1_size; i++)

            cpu_to_be64s(&l1_table[i]);

        if (bdrv_pwrite_sync(bs->file, l1_table_offset, l1_table,

                        l1_size2) < 0)

            goto fail;

        for(i = 0; i < l1_size; i++)

            be64_to_cpus(&l1_table[i]);

    }

    if (l1_allocated)

        g_free(l1_table);

    return ret;

}

int qcow2_update_snapshot_refcount(BlockDriverState *bs,

    int64_t l1_table_offset, int l1_size, int addend)

{

    BDRVQcowState *s = bs->opaque;

    uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, l1_allocated;

    int64_t old_offset, old_l2_offset;

    int i, j, l1_modified = 0, nb_csectors, refcount;

    int ret;



    l2_table = NULL;

    l1_table = NULL;

    l1_size2 = l1_size * sizeof(uint64_t);



    





    if (l1_table_offset != s->l1_table_offset) {

        l1_table = g_malloc0(align_offset(l1_size2, 512));

        l1_allocated = 1;



        ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2);

        if (ret < 0) {

            goto fail;

        }



        for(i = 0;i < l1_size; i++)

            be64_to_cpus(&l1_table[i]);

    } else {

        assert(l1_size == s->l1_size);

        l1_table = s->l1_table;

        l1_allocated = 0;

    }



    for(i = 0; i < l1_size; i++) {

        l2_offset = l1_table[i];

        if (l2_offset) {

            old_l2_offset = l2_offset;

            l2_offset &= L1E_OFFSET_MASK;



            ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,

                (void**) &l2_table);

            if (ret < 0) {

                goto fail;

            }



            for(j = 0; j < s->l2_size; j++) {

                offset = be64_to_cpu(l2_table[j]);

                if (offset != 0) {

                    old_offset = offset;

                    offset &= ~QCOW_OFLAG_COPIED;

                    if (offset & QCOW_OFLAG_COMPRESSED) {

                        nb_csectors = ((offset >> s->csize_shift) &

                                       s->csize_mask) + 1;

                        if (addend != 0) {

                            int ret;

                            ret = update_refcount(bs,

                                (offset & s->cluster_offset_mask) & ~511,

                                nb_csectors * 512, addend);

                            if (ret < 0) {

                                goto fail;

                            }

                        }

                        

                        refcount = 2;

                    } else {

                        uint64_t cluster_index = (offset & L2E_OFFSET_MASK) >> s->cluster_bits;

                        if (addend != 0) {

                            refcount = update_cluster_refcount(bs, cluster_index, addend);

                        } else {

                            refcount = get_refcount(bs, cluster_index);

                        }



                        if (refcount < 0) {

                            ret = refcount;

                            goto fail;

                        }

                    }



                    if (refcount == 1) {

                        offset |= QCOW_OFLAG_COPIED;

                    }

                    if (offset != old_offset) {

                        if (addend > 0) {

                            qcow2_cache_set_dependency(bs, s->l2_table_cache,

                                s->refcount_block_cache);

                        }

                        l2_table[j] = cpu_to_be64(offset);

                        qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);

                    }

                }

            }



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

            if (ret < 0) {

                goto fail;

            }





            if (addend != 0) {

                refcount = update_cluster_refcount(bs, l2_offset >> s->cluster_bits, addend);

            } else {

                refcount = get_refcount(bs, l2_offset >> s->cluster_bits);

            }

            if (refcount < 0) {

                ret = refcount;

                goto fail;

            } else if (refcount == 1) {

                l2_offset |= QCOW_OFLAG_COPIED;

            }

            if (l2_offset != old_l2_offset) {

                l1_table[i] = l2_offset;

                l1_modified = 1;

            }

        }

    }



    ret = bdrv_flush(bs);

fail:

    if (l2_table) {

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

    }



    

    if (addend >= 0 && l1_modified) {

        for(i = 0; i < l1_size; i++)

            cpu_to_be64s(&l1_table[i]);

        if (bdrv_pwrite_sync(bs->file, l1_table_offset, l1_table,

                        l1_size2) < 0)

            goto fail;

        for(i = 0; i < l1_size; i++)

            be64_to_cpus(&l1_table[i]);

    }

    if (l1_allocated)

        g_free(l1_table);

    return ret;

}

    if (addend >= 0 && l1_modified) {         for(i = 0; i < l1_size; i++)         if (bdrv_pwrite_sync(bs->file, l1_table_offset, l1_table,                         l1_size2) < 0)             goto fail;         for(i = 0; i < l1_size; i++)
int FUNC_0(BlockDriverState *VAR_0,

    int64_t VAR_1, int VAR_2, int VAR_3)

{

    BDRVQcowState *s = VAR_0->opaque;

    uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, l1_allocated;

    int64_t old_offset, old_l2_offset;

    int VAR_4, VAR_5, VAR_6 = 0, VAR_7, VAR_8;

    int VAR_9;



    l2_table = NULL;

    l1_table = NULL;

    l1_size2 = VAR_2 * sizeof(uint64_t);



    





    if (VAR_1 != s->VAR_1) {

        l1_table = g_malloc0(align_offset(l1_size2, 512));

        l1_allocated = 1;



        VAR_9 = bdrv_pread(VAR_0->file, VAR_1, l1_table, l1_size2);

        if (VAR_9 < 0) {

            goto fail;

        }



        for(VAR_4 = 0;VAR_4 < VAR_2; VAR_4++)

            be64_to_cpus(&l1_table[VAR_4]);

    } else {

        assert(VAR_2 == s->VAR_2);

        l1_table = s->l1_table;

        l1_allocated = 0;

    }



    for(VAR_4 = 0; VAR_4 < VAR_2; VAR_4++) {

        l2_offset = l1_table[VAR_4];

        if (l2_offset) {

            old_l2_offset = l2_offset;

            l2_offset &= L1E_OFFSET_MASK;



            VAR_9 = qcow2_cache_get(VAR_0, s->l2_table_cache, l2_offset,

                (void**) &l2_table);

            if (VAR_9 < 0) {

                goto fail;

            }



            for(VAR_5 = 0; VAR_5 < s->l2_size; VAR_5++) {

                offset = be64_to_cpu(l2_table[VAR_5]);

                if (offset != 0) {

                    old_offset = offset;

                    offset &= ~QCOW_OFLAG_COPIED;

                    if (offset & QCOW_OFLAG_COMPRESSED) {

                        VAR_7 = ((offset >> s->csize_shift) &

                                       s->csize_mask) + 1;

                        if (VAR_3 != 0) {

                            int VAR_9;

                            VAR_9 = update_refcount(VAR_0,

                                (offset & s->cluster_offset_mask) & ~511,

                                VAR_7 * 512, VAR_3);

                            if (VAR_9 < 0) {

                                goto fail;

                            }

                        }

                        

                        VAR_8 = 2;

                    } else {

                        uint64_t cluster_index = (offset & L2E_OFFSET_MASK) >> s->cluster_bits;

                        if (VAR_3 != 0) {

                            VAR_8 = update_cluster_refcount(VAR_0, cluster_index, VAR_3);

                        } else {

                            VAR_8 = get_refcount(VAR_0, cluster_index);

                        }



                        if (VAR_8 < 0) {

                            VAR_9 = VAR_8;

                            goto fail;

                        }

                    }



                    if (VAR_8 == 1) {

                        offset |= QCOW_OFLAG_COPIED;

                    }

                    if (offset != old_offset) {

                        if (VAR_3 > 0) {

                            qcow2_cache_set_dependency(VAR_0, s->l2_table_cache,

                                s->refcount_block_cache);

                        }

                        l2_table[VAR_5] = cpu_to_be64(offset);

                        qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);

                    }

                }

            }



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

            if (VAR_9 < 0) {

                goto fail;

            }





            if (VAR_3 != 0) {

                VAR_8 = update_cluster_refcount(VAR_0, l2_offset >> s->cluster_bits, VAR_3);

            } else {

                VAR_8 = get_refcount(VAR_0, l2_offset >> s->cluster_bits);

            }

            if (VAR_8 < 0) {

                VAR_9 = VAR_8;

                goto fail;

            } else if (VAR_8 == 1) {

                l2_offset |= QCOW_OFLAG_COPIED;

            }

            if (l2_offset != old_l2_offset) {

                l1_table[VAR_4] = l2_offset;

                VAR_6 = 1;

            }

        }

    }



    VAR_9 = bdrv_flush(VAR_0);

fail:

    if (l2_table) {

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

    }



    

    if (VAR_3 >= 0 && VAR_6) {

        for(VAR_4 = 0; VAR_4 < VAR_2; VAR_4++)

            cpu_to_be64s(&l1_table[VAR_4]);

        if (bdrv_pwrite_sync(VAR_0->file, VAR_1, l1_table,

                        l1_size2) < 0)

            goto fail;

        for(VAR_4 = 0; VAR_4 < VAR_2; VAR_4++)

            be64_to_cpus(&l1_table[VAR_4]);

    }

    if (l1_allocated)

        g_free(l1_table);

    return VAR_9;

}

int FUNC_0(BlockDriverState *VAR_0,
int64_t VAR_1, int VAR_2, int VAR_3)
{ BDRVQcowState *s = VAR_0->opaque; uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, l1_allocated; int64_t old_offset, old_l2_offset; int VAR_4, VAR_5, VAR_6 = 0, VAR_7, VAR_8; int VAR_9; l2_table = NULL; l1_table = NULL; l1_size2 = VAR_2 * sizeof(uint64_t); if (VAR_1 != s->VAR_1) { l1_table = g_malloc0(align_offset(l1_size2, 512)); l1_allocated = 1; VAR_9 = bdrv_pread(VAR_0->file, VAR_1, l1_table, l1_size2); if (VAR_9 < 0) { goto fail; } for(VAR_4 = 0;VAR_4 < VAR_2; VAR_4++) be64_to_cpus(&l1_table[VAR_4]); } else { assert(VAR_2 == s->VAR_2); l1_table = s->l1_table; l1_allocated = 0; } for(VAR_4 = 0; VAR_4 < VAR_2; VAR_4++) { l2_offset = l1_table[VAR_4]; if (l2_offset) { old_l2_offset = l2_offset; l2_offset &= L1E_OFFSET_MASK; VAR_9 = qcow2_cache_get(VAR_0, s->l2_table_cache, l2_offset,
(void**) &l2_table); if (VAR_9 < 0) { goto fail; } for(VAR_5 = 0; VAR_5 < s->l2_size; VAR_5++) { offset = be64_to_cpu(l2_table[VAR_5]); if (offset != 0) { old_offset = offset; offset &= ~QCOW_OFLAG_COPIED; if (offset & QCOW_OFLAG_COMPRESSED) { VAR_7 = ((offset >> s->csize_shift) &
s->csize_mask) + 1; if (VAR_3 != 0) { int VAR_9; VAR_9 = update_refcount(VAR_0,
(offset & s->cluster_offset_mask) & ~511,
VAR_7 * 512, VAR_3); if (VAR_9 < 0) { goto fail; } } VAR_8 = 2; } else { uint64_t cluster_index = (offset & L2E_OFFSET_MASK) >> s->cluster_bits; if (VAR_3 != 0) { VAR_8 = update_cluster_refcount(VAR_0, cluster_index, VAR_3); } else { VAR_8 = get_refcount(VAR_0, cluster_index); } if (VAR_8 < 0) { VAR_9 = VAR_8; goto fail; } } if (VAR_8 == 1) { offset |= QCOW_OFLAG_COPIED; } if (offset != old_offset) { if (VAR_3 > 0) { qcow2_cache_set_dependency(VAR_0, s->l2_table_cache,
s->refcount_block_cache); } l2_table[VAR_5] = cpu_to_be64(offset); qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table); } } } VAR_9 = qcow2_cache_put(VAR_0, s->l2_table_cache, (void**) &l2_table); if (VAR_9 < 0) { goto fail; } if (VAR_3 != 0) { VAR_8 = update_cluster_refcount(VAR_0, l2_offset >> s->cluster_bits, VAR_3); } else { VAR_8 = get_refcount(VAR_0, l2_offset >> s->cluster_bits); } if (VAR_8 < 0) { VAR_9 = VAR_8; goto fail; } else if (VAR_8 == 1) { l2_offset |= QCOW_OFLAG_COPIED; } if (l2_offset != old_l2_offset) { l1_table[VAR_4] = l2_offset; VAR_6 = 1; } } } VAR_9 = bdrv_flush(VAR_0); fail:
if (l2_table) { qcow2_cache_put(VAR_0, s->l2_table_cache, (void**) &l2_table); } if (VAR_3 >= 0 && VAR_6) { for(VAR_4 = 0; VAR_4 < VAR_2; VAR_4++) cpu_to_be64s(&l1_table[VAR_4]); if (bdrv_pwrite_sync(VAR_0->file, VAR_1, l1_table,
l1_size2) < 0)
goto fail; for(VAR_4 = 0; VAR_4 < VAR_2; VAR_4++) be64_to_cpus(&l1_table[VAR_4]); } if (l1_allocated)
g_free(l1_table); return VAR_9; }