Commit 320c7066 authored by Max Reitz's avatar Max Reitz Committed by Kevin Wolf
Browse files

qcow2: Free only newly allocated clusters on error



In expand_zero_clusters_in_l1, a new cluster is only allocated if it was
not already preallocated. On error, such preallocated clusters should
not be freed, but only the newly allocated ones.

Signed-off-by: default avatarMax Reitz <mreitz@redhat.com>
Signed-off-by: default avatarKevin Wolf <kwolf@redhat.com>
parent be0b742e
Loading
Loading
Loading
Loading
+10 −6
Original line number Diff line number Diff line
@@ -1554,6 +1554,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
            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;
@@ -1579,8 +1580,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
                continue;
            }

            if (!offset) {
                /* not preallocated */
            if (!preallocated) {
                if (!bs->backing_hd) {
                    /* not backed; therefore we can simply deallocate the
                     * cluster */
@@ -1599,16 +1599,20 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
            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;
            }