static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,

                                      int l1_size, uint8_t **expanded_clusters,

                                      uint64_t *nb_clusters)

{

    BDRVQcowState *s = bs->opaque;

    bool is_active_l1 = (l1_table == s->l1_table);

    uint64_t *l2_table = NULL;

    int ret;

    int i, j;



    if (!is_active_l1) {

        /* inactive L2 tables require a buffer to be stored in when loading

         * them from disk */

        l2_table = qemu_blockalign(bs, s->cluster_size);

    }



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

        uint64_t l2_offset = l1_table[i] & L1E_OFFSET_MASK;

        bool l2_dirty = false;



        if (!l2_offset) {

            /* unallocated */

            continue;

        }



        if (is_active_l1) {

            /* get active L2 tables from cache */

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

                    (void **)&l2_table);

        } else {

            /* load inactive L2 tables from disk */

            ret = bdrv_read(bs->file, l2_offset / BDRV_SECTOR_SIZE,

                    (void *)l2_table, s->cluster_sectors);

        }

        if (ret < 0) {

            goto fail;

        }



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

            uint64_t l2_entry = be64_to_cpu(l2_table[j]);

            int64_t offset = l2_entry & L2E_OFFSET_MASK, cluster_index;

            int cluster_type = qcow2_get_cluster_type(l2_entry);

            bool preallocated = offset != 0;



            if (cluster_type == QCOW2_CLUSTER_NORMAL) {

                cluster_index = offset >> s->cluster_bits;

                assert((cluster_index >= 0) && (cluster_index < *nb_clusters));

                if ((*expanded_clusters)[cluster_index / 8] &

                    (1 << (cluster_index % 8))) {

                    /* Probably a shared L2 table; this cluster was a zero

                     * cluster which has been expanded, its refcount

                     * therefore most likely requires an update. */

                    ret = qcow2_update_cluster_refcount(bs, cluster_index, 1,

                                                        QCOW2_DISCARD_NEVER);

                    if (ret < 0) {

                        goto fail;

                    }

                    /* Since we just increased the refcount, the COPIED flag may

                     * no longer be set. */

                    l2_table[j] = cpu_to_be64(l2_entry & ~QCOW_OFLAG_COPIED);

                    l2_dirty = true;

                }

                continue;

            }

            else if (qcow2_get_cluster_type(l2_entry) != QCOW2_CLUSTER_ZERO) {

                continue;

            }



            if (!preallocated) {

                if (!bs->backing_hd) {

                    /* not backed; therefore we can simply deallocate the

                     * cluster */

                    l2_table[j] = 0;

                    l2_dirty = true;

                    continue;

                }



                offset = qcow2_alloc_clusters(bs, s->cluster_size);

                if (offset < 0) {

                    ret = offset;

                    goto fail;

                }

            }



            ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT,

                                                offset, s->cluster_size);

            if (ret < 0) {

                if (!preallocated) {

                    qcow2_free_clusters(bs, offset, s->cluster_size,

                                        QCOW2_DISCARD_ALWAYS);

                }

                goto fail;

            }



            ret = bdrv_write_zeroes(bs->file, offset / BDRV_SECTOR_SIZE,

                                    s->cluster_sectors);

            if (ret < 0) {

                if (!preallocated) {

                    qcow2_free_clusters(bs, offset, s->cluster_size,

                                        QCOW2_DISCARD_ALWAYS);

                }

                goto fail;

            }



            l2_table[j] = cpu_to_be64(offset | QCOW_OFLAG_COPIED);

            l2_dirty = true;



            cluster_index = offset >> s->cluster_bits;



            if (cluster_index >= *nb_clusters) {

                uint64_t old_bitmap_size = (*nb_clusters + 7) / 8;

                uint64_t new_bitmap_size;

                /* The offset may lie beyond the old end of the underlying image

                 * file for growable files only */

                assert(bs->file->growable);

                *nb_clusters = size_to_clusters(s, bs->file->total_sectors *

                                                BDRV_SECTOR_SIZE);

                new_bitmap_size = (*nb_clusters + 7) / 8;

                *expanded_clusters = g_realloc(*expanded_clusters,

                                               new_bitmap_size);

                /* clear the newly allocated space */

                memset(&(*expanded_clusters)[old_bitmap_size], 0,

                       new_bitmap_size - old_bitmap_size);

            }



            assert((cluster_index >= 0) && (cluster_index < *nb_clusters));

            (*expanded_clusters)[cluster_index / 8] |= 1 << (cluster_index % 8);

        }



        if (is_active_l1) {

            if (l2_dirty) {

                qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);

                qcow2_cache_depends_on_flush(s->l2_table_cache);

            }

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

            if (ret < 0) {

                l2_table = NULL;

                goto fail;

            }

        } else {

            if (l2_dirty) {

                ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT &

                        ~(QCOW2_OL_INACTIVE_L2 | QCOW2_OL_ACTIVE_L2), l2_offset,

                        s->cluster_size);

                if (ret < 0) {

                    goto fail;

                }



                ret = bdrv_write(bs->file, l2_offset / BDRV_SECTOR_SIZE,

                        (void *)l2_table, s->cluster_sectors);

                if (ret < 0) {

                    goto fail;

                }

            }

        }

    }



    ret = 0;



fail:

    if (l2_table) {

        if (!is_active_l1) {

            qemu_vfree(l2_table);

        } else {

            if (ret < 0) {

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

            } else {

                ret = qcow2_cache_put(bs, s->l2_table_cache,

                        (void **)&l2_table);

            }

        }

    }

    return ret;

}

static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,

                                      int l1_size, uint8_t **expanded_clusters,

                                      uint64_t *nb_clusters)

{

    BDRVQcowState *s = bs->opaque;

    bool is_active_l1 = (l1_table == s->l1_table);

    uint64_t *l2_table = NULL;

    int ret;

    int i, j;



    if (!is_active_l1) {

        



        l2_table = qemu_blockalign(bs, s->cluster_size);

    }



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

        uint64_t l2_offset = l1_table[i] & L1E_OFFSET_MASK;

        bool l2_dirty = false;



        if (!l2_offset) {

            

            continue;

        }



        if (is_active_l1) {

            

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

                    (void **)&l2_table);

        } else {

            

            ret = bdrv_read(bs->file, l2_offset / BDRV_SECTOR_SIZE,

                    (void *)l2_table, s->cluster_sectors);

        }

        if (ret < 0) {

            goto fail;

        }



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

            uint64_t l2_entry = be64_to_cpu(l2_table[j]);

            int64_t offset = l2_entry & L2E_OFFSET_MASK, cluster_index;

            int cluster_type = qcow2_get_cluster_type(l2_entry);

            bool preallocated = offset != 0;



            if (cluster_type == QCOW2_CLUSTER_NORMAL) {

                cluster_index = offset >> s->cluster_bits;

                assert((cluster_index >= 0) && (cluster_index < *nb_clusters));

                if ((*expanded_clusters)[cluster_index / 8] &

                    (1 << (cluster_index % 8))) {

                    





                    ret = qcow2_update_cluster_refcount(bs, cluster_index, 1,

                                                        QCOW2_DISCARD_NEVER);

                    if (ret < 0) {

                        goto fail;

                    }

                    



                    l2_table[j] = cpu_to_be64(l2_entry & ~QCOW_OFLAG_COPIED);

                    l2_dirty = true;

                }

                continue;

            }

            else if (qcow2_get_cluster_type(l2_entry) != QCOW2_CLUSTER_ZERO) {

                continue;

            }



            if (!preallocated) {

                if (!bs->backing_hd) {

                    



                    l2_table[j] = 0;

                    l2_dirty = true;

                    continue;

                }



                offset = qcow2_alloc_clusters(bs, s->cluster_size);

                if (offset < 0) {

                    ret = offset;

                    goto fail;

                }

            }



            ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT,

                                                offset, s->cluster_size);

            if (ret < 0) {

                if (!preallocated) {

                    qcow2_free_clusters(bs, offset, s->cluster_size,

                                        QCOW2_DISCARD_ALWAYS);

                }

                goto fail;

            }



            ret = bdrv_write_zeroes(bs->file, offset / BDRV_SECTOR_SIZE,

                                    s->cluster_sectors);

            if (ret < 0) {

                if (!preallocated) {

                    qcow2_free_clusters(bs, offset, s->cluster_size,

                                        QCOW2_DISCARD_ALWAYS);

                }

                goto fail;

            }



            l2_table[j] = cpu_to_be64(offset | QCOW_OFLAG_COPIED);

            l2_dirty = true;



            cluster_index = offset >> s->cluster_bits;



            if (cluster_index >= *nb_clusters) {

                uint64_t old_bitmap_size = (*nb_clusters + 7) / 8;

                uint64_t new_bitmap_size;

                



                assert(bs->file->growable);

                *nb_clusters = size_to_clusters(s, bs->file->total_sectors *

                                                BDRV_SECTOR_SIZE);

                new_bitmap_size = (*nb_clusters + 7) / 8;

                *expanded_clusters = g_realloc(*expanded_clusters,

                                               new_bitmap_size);

                

                memset(&(*expanded_clusters)[old_bitmap_size], 0,

                       new_bitmap_size - old_bitmap_size);

            }



            assert((cluster_index >= 0) && (cluster_index < *nb_clusters));

            (*expanded_clusters)[cluster_index / 8] |= 1 << (cluster_index % 8);

        }



        if (is_active_l1) {

            if (l2_dirty) {

                qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);

                qcow2_cache_depends_on_flush(s->l2_table_cache);

            }

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

            if (ret < 0) {

                l2_table = NULL;

                goto fail;

            }

        } else {

            if (l2_dirty) {

                ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT &

                        ~(QCOW2_OL_INACTIVE_L2 | QCOW2_OL_ACTIVE_L2), l2_offset,

                        s->cluster_size);

                if (ret < 0) {

                    goto fail;

                }



                ret = bdrv_write(bs->file, l2_offset / BDRV_SECTOR_SIZE,

                        (void *)l2_table, s->cluster_sectors);

                if (ret < 0) {

                    goto fail;

                }

            }

        }

    }



    ret = 0;



fail:

    if (l2_table) {

        if (!is_active_l1) {

            qemu_vfree(l2_table);

        } else {

            if (ret < 0) {

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

            } else {

                ret = qcow2_cache_put(bs, s->l2_table_cache,

                        (void **)&l2_table);

            }

        }

    }

    return ret;

}

            ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT,                                                 offset, s->cluster_size);                 ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT &                         ~(QCOW2_OL_INACTIVE_L2 | QCOW2_OL_ACTIVE_L2), l2_offset,
static int FUNC_0(BlockDriverState *VAR_0, uint64_t *VAR_1,

                                      int VAR_2, uint8_t **VAR_3,

                                      uint64_t *VAR_4)

{

    BDRVQcowState *s = VAR_0->opaque;

    bool is_active_l1 = (VAR_1 == s->VAR_1);

    uint64_t *l2_table = NULL;

    int VAR_5;

    int VAR_6, VAR_7;



    if (!is_active_l1) {

        



        l2_table = qemu_blockalign(VAR_0, s->cluster_size);

    }



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

        uint64_t l2_offset = VAR_1[VAR_6] & L1E_OFFSET_MASK;

        bool l2_dirty = false;



        if (!l2_offset) {

            

            continue;

        }



        if (is_active_l1) {

            

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

                    (void **)&l2_table);

        } else {

            

            VAR_5 = bdrv_read(VAR_0->file, l2_offset / BDRV_SECTOR_SIZE,

                    (void *)l2_table, s->cluster_sectors);

        }

        if (VAR_5 < 0) {

            goto fail;

        }



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

            uint64_t l2_entry = be64_to_cpu(l2_table[VAR_7]);

            int64_t offset = l2_entry & L2E_OFFSET_MASK, cluster_index;

            int cluster_type = qcow2_get_cluster_type(l2_entry);

            bool preallocated = offset != 0;



            if (cluster_type == QCOW2_CLUSTER_NORMAL) {

                cluster_index = offset >> s->cluster_bits;

                assert((cluster_index >= 0) && (cluster_index < *VAR_4));

                if ((*VAR_3)[cluster_index / 8] &

                    (1 << (cluster_index % 8))) {

                    





                    VAR_5 = qcow2_update_cluster_refcount(VAR_0, cluster_index, 1,

                                                        QCOW2_DISCARD_NEVER);

                    if (VAR_5 < 0) {

                        goto fail;

                    }

                    



                    l2_table[VAR_7] = cpu_to_be64(l2_entry & ~QCOW_OFLAG_COPIED);

                    l2_dirty = true;

                }

                continue;

            }

            else if (qcow2_get_cluster_type(l2_entry) != QCOW2_CLUSTER_ZERO) {

                continue;

            }



            if (!preallocated) {

                if (!VAR_0->backing_hd) {

                    



                    l2_table[VAR_7] = 0;

                    l2_dirty = true;

                    continue;

                }



                offset = qcow2_alloc_clusters(VAR_0, s->cluster_size);

                if (offset < 0) {

                    VAR_5 = offset;

                    goto fail;

                }

            }



            VAR_5 = qcow2_pre_write_overlap_check(VAR_0, QCOW2_OL_DEFAULT,

                                                offset, s->cluster_size);

            if (VAR_5 < 0) {

                if (!preallocated) {

                    qcow2_free_clusters(VAR_0, offset, s->cluster_size,

                                        QCOW2_DISCARD_ALWAYS);

                }

                goto fail;

            }



            VAR_5 = bdrv_write_zeroes(VAR_0->file, offset / BDRV_SECTOR_SIZE,

                                    s->cluster_sectors);

            if (VAR_5 < 0) {

                if (!preallocated) {

                    qcow2_free_clusters(VAR_0, offset, s->cluster_size,

                                        QCOW2_DISCARD_ALWAYS);

                }

                goto fail;

            }



            l2_table[VAR_7] = cpu_to_be64(offset | QCOW_OFLAG_COPIED);

            l2_dirty = true;



            cluster_index = offset >> s->cluster_bits;



            if (cluster_index >= *VAR_4) {

                uint64_t old_bitmap_size = (*VAR_4 + 7) / 8;

                uint64_t new_bitmap_size;

                



                assert(VAR_0->file->growable);

                *VAR_4 = size_to_clusters(s, VAR_0->file->total_sectors *

                                                BDRV_SECTOR_SIZE);

                new_bitmap_size = (*VAR_4 + 7) / 8;

                *VAR_3 = g_realloc(*VAR_3,

                                               new_bitmap_size);

                

                memset(&(*VAR_3)[old_bitmap_size], 0,

                       new_bitmap_size - old_bitmap_size);

            }



            assert((cluster_index >= 0) && (cluster_index < *VAR_4));

            (*VAR_3)[cluster_index / 8] |= 1 << (cluster_index % 8);

        }



        if (is_active_l1) {

            if (l2_dirty) {

                qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);

                qcow2_cache_depends_on_flush(s->l2_table_cache);

            }

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

            if (VAR_5 < 0) {

                l2_table = NULL;

                goto fail;

            }

        } else {

            if (l2_dirty) {

                VAR_5 = qcow2_pre_write_overlap_check(VAR_0, QCOW2_OL_DEFAULT &

                        ~(QCOW2_OL_INACTIVE_L2 | QCOW2_OL_ACTIVE_L2), l2_offset,

                        s->cluster_size);

                if (VAR_5 < 0) {

                    goto fail;

                }



                VAR_5 = bdrv_write(VAR_0->file, l2_offset / BDRV_SECTOR_SIZE,

                        (void *)l2_table, s->cluster_sectors);

                if (VAR_5 < 0) {

                    goto fail;

                }

            }

        }

    }



    VAR_5 = 0;



fail:

    if (l2_table) {

        if (!is_active_l1) {

            qemu_vfree(l2_table);

        } else {

            if (VAR_5 < 0) {

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

            } else {

                VAR_5 = qcow2_cache_put(VAR_0, s->l2_table_cache,

                        (void **)&l2_table);

            }

        }

    }

    return VAR_5;

}

static int FUNC_0(BlockDriverState *VAR_0, uint64_t *VAR_1,
int VAR_2, uint8_t **VAR_3,
uint64_t *VAR_4)
{ BDRVQcowState *s = VAR_0->opaque; bool is_active_l1 = (VAR_1 == s->VAR_1); uint64_t *l2_table = NULL; int VAR_5; int VAR_6, VAR_7; if (!is_active_l1) { l2_table = qemu_blockalign(VAR_0, s->cluster_size); } for (VAR_6 = 0; VAR_6 < VAR_2; VAR_6++) { uint64_t l2_offset = VAR_1[VAR_6] & L1E_OFFSET_MASK; bool l2_dirty = false; if (!l2_offset) { continue; } if (is_active_l1) { VAR_5 = qcow2_cache_get(VAR_0, s->l2_table_cache, l2_offset,
(void **)&l2_table); } else { VAR_5 = bdrv_read(VAR_0->file, l2_offset / BDRV_SECTOR_SIZE,
(void *)l2_table, s->cluster_sectors); } if (VAR_5 < 0) { goto fail; } for (VAR_7 = 0; VAR_7 < s->l2_size; VAR_7++) { uint64_t l2_entry = be64_to_cpu(l2_table[VAR_7]); int64_t offset = l2_entry & L2E_OFFSET_MASK, cluster_index; int cluster_type = qcow2_get_cluster_type(l2_entry); bool preallocated = offset != 0; if (cluster_type == QCOW2_CLUSTER_NORMAL) { cluster_index = offset >> s->cluster_bits; assert((cluster_index >= 0) && (cluster_index < *VAR_4)); if ((*VAR_3)[cluster_index / 8] &
(1 << (cluster_index % 8))) { VAR_5 = qcow2_update_cluster_refcount(VAR_0, cluster_index, 1,
QCOW2_DISCARD_NEVER); if (VAR_5 < 0) { goto fail; } l2_table[VAR_7] = cpu_to_be64(l2_entry & ~QCOW_OFLAG_COPIED); l2_dirty = true; } continue; } else if (qcow2_get_cluster_type(l2_entry) != QCOW2_CLUSTER_ZERO) { continue; } if (!preallocated) { if (!VAR_0->backing_hd) { l2_table[VAR_7] = 0; l2_dirty = true; continue; } offset = qcow2_alloc_clusters(VAR_0, s->cluster_size); if (offset < 0) { VAR_5 = offset; goto fail; } } VAR_5 = qcow2_pre_write_overlap_check(VAR_0, QCOW2_OL_DEFAULT,
offset, s->cluster_size); if (VAR_5 < 0) { if (!preallocated) { qcow2_free_clusters(VAR_0, offset, s->cluster_size,
QCOW2_DISCARD_ALWAYS); } goto fail; } VAR_5 = bdrv_write_zeroes(VAR_0->file, offset / BDRV_SECTOR_SIZE,
s->cluster_sectors); if (VAR_5 < 0) { if (!preallocated) { qcow2_free_clusters(VAR_0, offset, s->cluster_size,
QCOW2_DISCARD_ALWAYS); } goto fail; } l2_table[VAR_7] = cpu_to_be64(offset | QCOW_OFLAG_COPIED); l2_dirty = true; cluster_index = offset >> s->cluster_bits; if (cluster_index >= *VAR_4) { uint64_t old_bitmap_size = (*VAR_4 + 7) / 8; uint64_t new_bitmap_size; assert(VAR_0->file->growable); *VAR_4 = size_to_clusters(s, VAR_0->file->total_sectors *
BDRV_SECTOR_SIZE); new_bitmap_size = (*VAR_4 + 7) / 8; *VAR_3 = g_realloc(*VAR_3,
new_bitmap_size); memset(&(*VAR_3)[old_bitmap_size], 0,
new_bitmap_size - old_bitmap_size); } assert((cluster_index >= 0) && (cluster_index < *VAR_4)); (*VAR_3)[cluster_index / 8] |= 1 << (cluster_index % 8); } if (is_active_l1) { if (l2_dirty) { qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table); qcow2_cache_depends_on_flush(s->l2_table_cache); } VAR_5 = qcow2_cache_put(VAR_0, s->l2_table_cache, (void **)&l2_table); if (VAR_5 < 0) { l2_table = NULL; goto fail; } } else { if (l2_dirty) { VAR_5 = qcow2_pre_write_overlap_check(VAR_0, QCOW2_OL_DEFAULT &
~(QCOW2_OL_INACTIVE_L2 | QCOW2_OL_ACTIVE_L2), l2_offset,
s->cluster_size); if (VAR_5 < 0) { goto fail; } VAR_5 = bdrv_write(VAR_0->file, l2_offset / BDRV_SECTOR_SIZE,
(void *)l2_table, s->cluster_sectors); if (VAR_5 < 0) { goto fail; } } } } VAR_5 = 0; fail:
if (l2_table) { if (!is_active_l1) { qemu_vfree(l2_table); } else { if (VAR_5 < 0) { qcow2_cache_put(VAR_0, s->l2_table_cache, (void **)&l2_table); } else { VAR_5 = qcow2_cache_put(VAR_0, s->l2_table_cache,
(void **)&l2_table); } } } return VAR_5; }