diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 08ecb4ca0c..5afcd72f5a 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -1957,7 +1957,6 @@ static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset, int l2_index; int ret; int i; - bool unmap = !!(flags & BDRV_REQ_MAY_UNMAP); ret = get_cluster_table(bs, offset, &l2_slice, &l2_index); if (ret < 0) { @@ -1969,28 +1968,31 @@ static int zero_in_l2_slice(BlockDriverState *bs, uint64_t offset, assert(nb_clusters <= INT_MAX); for (i = 0; i < nb_clusters; i++) { - uint64_t old_offset; - QCow2ClusterType cluster_type; + uint64_t old_l2_entry = get_l2_entry(s, l2_slice, l2_index + i); + uint64_t old_l2_bitmap = get_l2_bitmap(s, l2_slice, l2_index + i); + QCow2ClusterType type = qcow2_get_cluster_type(bs, old_l2_entry); + bool unmap = (type == QCOW2_CLUSTER_COMPRESSED) || + ((flags & BDRV_REQ_MAY_UNMAP) && qcow2_cluster_is_allocated(type)); + uint64_t new_l2_entry = unmap ? 0 : old_l2_entry; + uint64_t new_l2_bitmap = old_l2_bitmap; - old_offset = get_l2_entry(s, l2_slice, l2_index + i); + if (has_subclusters(s)) { + new_l2_bitmap = QCOW_L2_BITMAP_ALL_ZEROES; + } else { + new_l2_entry |= QCOW_OFLAG_ZERO; + } - /* - * Minimize L2 changes if the cluster already reads back as - * zeroes with correct allocation. - */ - cluster_type = qcow2_get_cluster_type(bs, old_offset); - if (cluster_type == QCOW2_CLUSTER_ZERO_PLAIN || - (cluster_type == QCOW2_CLUSTER_ZERO_ALLOC && !unmap)) { + if (old_l2_entry == new_l2_entry && old_l2_bitmap == new_l2_bitmap) { continue; } qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice); - if (cluster_type == QCOW2_CLUSTER_COMPRESSED || unmap) { - set_l2_entry(s, l2_slice, l2_index + i, QCOW_OFLAG_ZERO); - qcow2_free_any_clusters(bs, old_offset, 1, QCOW2_DISCARD_REQUEST); - } else { - uint64_t entry = get_l2_entry(s, l2_slice, l2_index + i); - set_l2_entry(s, l2_slice, l2_index + i, entry | QCOW_OFLAG_ZERO); + if (unmap) { + qcow2_free_any_clusters(bs, old_l2_entry, 1, QCOW2_DISCARD_REQUEST); + } + set_l2_entry(s, l2_slice, l2_index + i, new_l2_entry); + if (has_subclusters(s)) { + set_l2_bitmap(s, l2_slice, l2_index + i, new_l2_bitmap); } }