@@ -1956,7 +1956,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) {
@@ -1968,28 +1967,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);
}
}