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

                                      int l1_size, int64_t *visited_l1_entries,

                                      int64_t l1_entries,

                                      BlockDriverAmendStatusCB *status_cb)

{

    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_try_blockalign(bs->file, s->cluster_size);

        if (l2_table == NULL) {

            return -ENOMEM;

        }

    }



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

        uint64_t l2_offset = l1_table[i] & L1E_OFFSET_MASK;

        bool l2_dirty = false;

        uint64_t l2_refcount;



        if (!l2_offset) {

            /* unallocated */

            (*visited_l1_entries)++;

            if (status_cb) {

                status_cb(bs, *visited_l1_entries, l1_entries);

            }

            continue;

        }



        if (offset_into_cluster(s, l2_offset)) {

            qcow2_signal_corruption(bs, true, -1, -1, "L2 table offset %#"

                                    PRIx64 " unaligned (L1 index: %#x)",

                                    l2_offset, i);

            ret = -EIO;

            goto fail;

        }



        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;

        }



        ret = qcow2_get_refcount(bs, l2_offset >> s->cluster_bits,

                                 &l2_refcount);

        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;

            int cluster_type = qcow2_get_cluster_type(l2_entry);

            bool preallocated = offset != 0;



            if (cluster_type != 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;

                }



                if (l2_refcount > 1) {

                    /* For shared L2 tables, set the refcount accordingly (it is

                     * already 1 and needs to be l2_refcount) */

                    ret = qcow2_update_cluster_refcount(bs,

                            offset >> s->cluster_bits,

                            refcount_diff(1, l2_refcount), false,

                            QCOW2_DISCARD_OTHER);

                    if (ret < 0) {

                        qcow2_free_clusters(bs, offset, s->cluster_size,

                                            QCOW2_DISCARD_OTHER);

                        goto fail;

                    }

                }

            }



            if (offset_into_cluster(s, offset)) {

                qcow2_signal_corruption(bs, true, -1, -1, "Data cluster offset "

                                        "%#" PRIx64 " unaligned (L2 offset: %#"

                                        PRIx64 ", L2 index: %#x)", offset,

                                        l2_offset, j);

                if (!preallocated) {

                    qcow2_free_clusters(bs, offset, s->cluster_size,

                                        QCOW2_DISCARD_ALWAYS);

                }

                ret = -EIO;

                goto fail;

            }



            ret = qcow2_pre_write_overlap_check(bs, 0, 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, 0);

            if (ret < 0) {

                if (!preallocated) {

                    qcow2_free_clusters(bs, offset, s->cluster_size,

                                        QCOW2_DISCARD_ALWAYS);

                }

                goto fail;

            }



            if (l2_refcount == 1) {

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

            } else {

                l2_table[j] = cpu_to_be64(offset);

            }

            l2_dirty = true;

        }



        if (is_active_l1) {

            if (l2_dirty) {

                qcow2_cache_entry_mark_dirty(bs, 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_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;

                }

            }

        }



        (*visited_l1_entries)++;

        if (status_cb) {

            status_cb(bs, *visited_l1_entries, l1_entries);

        }

    }



    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, int64_t *visited_l1_entries,

                                      int64_t l1_entries,

                                      BlockDriverAmendStatusCB *status_cb)

{

    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_try_blockalign(bs->file, s->cluster_size);

        if (l2_table == NULL) {

            return -ENOMEM;

        }

    }



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

        uint64_t l2_offset = l1_table[i] & L1E_OFFSET_MASK;

        bool l2_dirty = false;

        uint64_t l2_refcount;



        if (!l2_offset) {

            

            (*visited_l1_entries)++;

            if (status_cb) {

                status_cb(bs, *visited_l1_entries, l1_entries);

            }

            continue;

        }



        if (offset_into_cluster(s, l2_offset)) {

            qcow2_signal_corruption(bs, true, -1, -1, "L2 table offset %#"

                                    PRIx64 " unaligned (L1 index: %#x)",

                                    l2_offset, i);

            ret = -EIO;

            goto fail;

        }



        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;

        }



        ret = qcow2_get_refcount(bs, l2_offset >> s->cluster_bits,

                                 &l2_refcount);

        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;

            int cluster_type = qcow2_get_cluster_type(l2_entry);

            bool preallocated = offset != 0;



            if (cluster_type != 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;

                }



                if (l2_refcount > 1) {

                    



                    ret = qcow2_update_cluster_refcount(bs,

                            offset >> s->cluster_bits,

                            refcount_diff(1, l2_refcount), false,

                            QCOW2_DISCARD_OTHER);

                    if (ret < 0) {

                        qcow2_free_clusters(bs, offset, s->cluster_size,

                                            QCOW2_DISCARD_OTHER);

                        goto fail;

                    }

                }

            }



            if (offset_into_cluster(s, offset)) {

                qcow2_signal_corruption(bs, true, -1, -1, "Data cluster offset "

                                        "%#" PRIx64 " unaligned (L2 offset: %#"

                                        PRIx64 ", L2 index: %#x)", offset,

                                        l2_offset, j);

                if (!preallocated) {

                    qcow2_free_clusters(bs, offset, s->cluster_size,

                                        QCOW2_DISCARD_ALWAYS);

                }

                ret = -EIO;

                goto fail;

            }



            ret = qcow2_pre_write_overlap_check(bs, 0, 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, 0);

            if (ret < 0) {

                if (!preallocated) {

                    qcow2_free_clusters(bs, offset, s->cluster_size,

                                        QCOW2_DISCARD_ALWAYS);

                }

                goto fail;

            }



            if (l2_refcount == 1) {

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

            } else {

                l2_table[j] = cpu_to_be64(offset);

            }

            l2_dirty = true;

        }



        if (is_active_l1) {

            if (l2_dirty) {

                qcow2_cache_entry_mark_dirty(bs, 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_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;

                }

            }

        }



        (*visited_l1_entries)++;

        if (status_cb) {

            status_cb(bs, *visited_l1_entries, l1_entries);

        }

    }



    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 FUNC_0(BlockDriverState *VAR_0, uint64_t *VAR_1,

                                      int VAR_2, int64_t *VAR_3,

                                      int64_t VAR_4,

                                      BlockDriverAmendStatusCB *VAR_5)

{

    BDRVQcowState *s = VAR_0->opaque;

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

    uint64_t *l2_table = NULL;

    int VAR_6;

    int VAR_7, VAR_8;



    if (!is_active_l1) {

        



        l2_table = qemu_try_blockalign(VAR_0->file, s->cluster_size);

        if (l2_table == NULL) {

            return -ENOMEM;

        }

    }



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

        uint64_t l2_offset = VAR_1[VAR_7] & L1E_OFFSET_MASK;

        bool l2_dirty = false;

        uint64_t l2_refcount;



        if (!l2_offset) {

            

            (*VAR_3)++;

            if (VAR_5) {

                VAR_5(VAR_0, *VAR_3, VAR_4);

            }

            continue;

        }



        if (offset_into_cluster(s, l2_offset)) {

            qcow2_signal_corruption(VAR_0, true, -1, -1, "L2 table offset %#"

                                    PRIx64 " unaligned (L1 index: %#x)",

                                    l2_offset, VAR_7);

            VAR_6 = -EIO;

            goto fail;

        }



        if (is_active_l1) {

            

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

                    (void **)&l2_table);

        } else {

            

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

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

        }

        if (VAR_6 < 0) {

            goto fail;

        }



        VAR_6 = qcow2_get_refcount(VAR_0, l2_offset >> s->cluster_bits,

                                 &l2_refcount);

        if (VAR_6 < 0) {

            goto fail;

        }



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

            uint64_t l2_entry = be64_to_cpu(l2_table[VAR_8]);

            int64_t offset = l2_entry & L2E_OFFSET_MASK;

            int cluster_type = qcow2_get_cluster_type(l2_entry);

            bool preallocated = offset != 0;



            if (cluster_type != QCOW2_CLUSTER_ZERO) {

                continue;

            }



            if (!preallocated) {

                if (!VAR_0->backing_hd) {

                    



                    l2_table[VAR_8] = 0;

                    l2_dirty = true;

                    continue;

                }



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

                if (offset < 0) {

                    VAR_6 = offset;

                    goto fail;

                }



                if (l2_refcount > 1) {

                    



                    VAR_6 = qcow2_update_cluster_refcount(VAR_0,

                            offset >> s->cluster_bits,

                            refcount_diff(1, l2_refcount), false,

                            QCOW2_DISCARD_OTHER);

                    if (VAR_6 < 0) {

                        qcow2_free_clusters(VAR_0, offset, s->cluster_size,

                                            QCOW2_DISCARD_OTHER);

                        goto fail;

                    }

                }

            }



            if (offset_into_cluster(s, offset)) {

                qcow2_signal_corruption(VAR_0, true, -1, -1, "Data cluster offset "

                                        "%#" PRIx64 " unaligned (L2 offset: %#"

                                        PRIx64 ", L2 index: %#x)", offset,

                                        l2_offset, VAR_8);

                if (!preallocated) {

                    qcow2_free_clusters(VAR_0, offset, s->cluster_size,

                                        QCOW2_DISCARD_ALWAYS);

                }

                VAR_6 = -EIO;

                goto fail;

            }



            VAR_6 = qcow2_pre_write_overlap_check(VAR_0, 0, offset, s->cluster_size);

            if (VAR_6 < 0) {

                if (!preallocated) {

                    qcow2_free_clusters(VAR_0, offset, s->cluster_size,

                                        QCOW2_DISCARD_ALWAYS);

                }

                goto fail;

            }



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

                                    s->cluster_sectors, 0);

            if (VAR_6 < 0) {

                if (!preallocated) {

                    qcow2_free_clusters(VAR_0, offset, s->cluster_size,

                                        QCOW2_DISCARD_ALWAYS);

                }

                goto fail;

            }



            if (l2_refcount == 1) {

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

            } else {

                l2_table[VAR_8] = cpu_to_be64(offset);

            }

            l2_dirty = true;

        }



        if (is_active_l1) {

            if (l2_dirty) {

                qcow2_cache_entry_mark_dirty(VAR_0, s->l2_table_cache, l2_table);

                qcow2_cache_depends_on_flush(s->l2_table_cache);

            }

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

            if (VAR_6 < 0) {

                l2_table = NULL;

                goto fail;

            }

        } else {

            if (l2_dirty) {

                VAR_6 = qcow2_pre_write_overlap_check(VAR_0,

                        QCOW2_OL_INACTIVE_L2 | QCOW2_OL_ACTIVE_L2, l2_offset,

                        s->cluster_size);

                if (VAR_6 < 0) {

                    goto fail;

                }



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

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

                if (VAR_6 < 0) {

                    goto fail;

                }

            }

        }



        (*VAR_3)++;

        if (VAR_5) {

            VAR_5(VAR_0, *VAR_3, VAR_4);

        }

    }



    VAR_6 = 0;



fail:

    if (l2_table) {

        if (!is_active_l1) {

            qemu_vfree(l2_table);

        } else {

            if (VAR_6 < 0) {

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

            } else {

                VAR_6 = qcow2_cache_put(VAR_0, s->l2_table_cache,

                        (void **)&l2_table);

            }

        }

    }

    return VAR_6;

}

static int FUNC_0(BlockDriverState *VAR_0, uint64_t *VAR_1,
int VAR_2, int64_t *VAR_3,
int64_t VAR_4,
BlockDriverAmendStatusCB *VAR_5)
{ BDRVQcowState *s = VAR_0->opaque; bool is_active_l1 = (VAR_1 == s->VAR_1); uint64_t *l2_table = NULL; int VAR_6; int VAR_7, VAR_8; if (!is_active_l1) { l2_table = qemu_try_blockalign(VAR_0->file, s->cluster_size); if (l2_table == NULL) { return -ENOMEM; } } for (VAR_7 = 0; VAR_7 < VAR_2; VAR_7++) { uint64_t l2_offset = VAR_1[VAR_7] & L1E_OFFSET_MASK; bool l2_dirty = false; uint64_t l2_refcount; if (!l2_offset) { (*VAR_3)++; if (VAR_5) { VAR_5(VAR_0, *VAR_3, VAR_4); } continue; } if (offset_into_cluster(s, l2_offset)) { qcow2_signal_corruption(VAR_0, true, -1, -1, "L2 table offset %#"
PRIx64 " unaligned (L1 index: %#x)",
l2_offset, VAR_7); VAR_6 = -EIO; goto fail; } if (is_active_l1) { VAR_6 = qcow2_cache_get(VAR_0, s->l2_table_cache, l2_offset,
(void **)&l2_table); } else { VAR_6 = bdrv_read(VAR_0->file, l2_offset / BDRV_SECTOR_SIZE,
(void *)l2_table, s->cluster_sectors); } if (VAR_6 < 0) { goto fail; } VAR_6 = qcow2_get_refcount(VAR_0, l2_offset >> s->cluster_bits,
&l2_refcount); if (VAR_6 < 0) { goto fail; } for (VAR_8 = 0; VAR_8 < s->l2_size; VAR_8++) { uint64_t l2_entry = be64_to_cpu(l2_table[VAR_8]); int64_t offset = l2_entry & L2E_OFFSET_MASK; int cluster_type = qcow2_get_cluster_type(l2_entry); bool preallocated = offset != 0; if (cluster_type != QCOW2_CLUSTER_ZERO) { continue; } if (!preallocated) { if (!VAR_0->backing_hd) { l2_table[VAR_8] = 0; l2_dirty = true; continue; } offset = qcow2_alloc_clusters(VAR_0, s->cluster_size); if (offset < 0) { VAR_6 = offset; goto fail; } if (l2_refcount > 1) { VAR_6 = qcow2_update_cluster_refcount(VAR_0,
offset >> s->cluster_bits,
refcount_diff(1, l2_refcount), false,
QCOW2_DISCARD_OTHER); if (VAR_6 < 0) { qcow2_free_clusters(VAR_0, offset, s->cluster_size,
QCOW2_DISCARD_OTHER); goto fail; } } } if (offset_into_cluster(s, offset)) { qcow2_signal_corruption(VAR_0, true, -1, -1, "Data cluster offset "
"%#" PRIx64 " unaligned (L2 offset: %#"
PRIx64 ", L2 index: %#x)", offset,
l2_offset, VAR_8); if (!preallocated) { qcow2_free_clusters(VAR_0, offset, s->cluster_size,
QCOW2_DISCARD_ALWAYS); } VAR_6 = -EIO; goto fail; } VAR_6 = qcow2_pre_write_overlap_check(VAR_0, 0, offset, s->cluster_size); if (VAR_6 < 0) { if (!preallocated) { qcow2_free_clusters(VAR_0, offset, s->cluster_size,
QCOW2_DISCARD_ALWAYS); } goto fail; } VAR_6 = bdrv_write_zeroes(VAR_0->file, offset / BDRV_SECTOR_SIZE,
s->cluster_sectors, 0); if (VAR_6 < 0) { if (!preallocated) { qcow2_free_clusters(VAR_0, offset, s->cluster_size,
QCOW2_DISCARD_ALWAYS); } goto fail; } if (l2_refcount == 1) { l2_table[VAR_8] = cpu_to_be64(offset | QCOW_OFLAG_COPIED); } else { l2_table[VAR_8] = cpu_to_be64(offset); } l2_dirty = true; } if (is_active_l1) { if (l2_dirty) { qcow2_cache_entry_mark_dirty(VAR_0, s->l2_table_cache, l2_table); qcow2_cache_depends_on_flush(s->l2_table_cache); } VAR_6 = qcow2_cache_put(VAR_0, s->l2_table_cache, (void **)&l2_table); if (VAR_6 < 0) { l2_table = NULL; goto fail; } } else { if (l2_dirty) { VAR_6 = qcow2_pre_write_overlap_check(VAR_0,
QCOW2_OL_INACTIVE_L2 | QCOW2_OL_ACTIVE_L2, l2_offset,
s->cluster_size); if (VAR_6 < 0) { goto fail; } VAR_6 = bdrv_write(VAR_0->file, l2_offset / BDRV_SECTOR_SIZE,
(void *)l2_table, s->cluster_sectors); if (VAR_6 < 0) { goto fail; } } } (*VAR_3)++; if (VAR_5) { VAR_5(VAR_0, *VAR_3, VAR_4); } } VAR_6 = 0; fail:
if (l2_table) { if (!is_active_l1) { qemu_vfree(l2_table); } else { if (VAR_6 < 0) { qcow2_cache_put(VAR_0, s->l2_table_cache, (void **)&l2_table); } else { VAR_6 = qcow2_cache_put(VAR_0, s->l2_table_cache,
(void **)&l2_table); } } } return VAR_6; }