|
@@ -1925,6 +1925,10 @@ static int discard_in_l2_slice(BlockDriverState *bs, uint64_t offset,
|
|
|
uint64_t new_l2_bitmap = old_l2_bitmap;
|
|
|
QCow2ClusterType cluster_type =
|
|
|
qcow2_get_cluster_type(bs, old_l2_entry);
|
|
|
+ bool keep_reference = (cluster_type != QCOW2_CLUSTER_COMPRESSED) &&
|
|
|
+ !full_discard &&
|
|
|
+ (s->discard_no_unref &&
|
|
|
+ type == QCOW2_DISCARD_REQUEST);
|
|
|
|
|
|
/*
|
|
|
* If full_discard is true, the cluster should not read back as zeroes,
|
|
@@ -1943,10 +1947,22 @@ static int discard_in_l2_slice(BlockDriverState *bs, uint64_t offset,
|
|
|
new_l2_entry = new_l2_bitmap = 0;
|
|
|
} else if (bs->backing || qcow2_cluster_is_allocated(cluster_type)) {
|
|
|
if (has_subclusters(s)) {
|
|
|
- new_l2_entry = 0;
|
|
|
+ if (keep_reference) {
|
|
|
+ new_l2_entry = old_l2_entry;
|
|
|
+ } else {
|
|
|
+ new_l2_entry = 0;
|
|
|
+ }
|
|
|
new_l2_bitmap = QCOW_L2_BITMAP_ALL_ZEROES;
|
|
|
} else {
|
|
|
- new_l2_entry = s->qcow_version >= 3 ? QCOW_OFLAG_ZERO : 0;
|
|
|
+ if (s->qcow_version >= 3) {
|
|
|
+ if (keep_reference) {
|
|
|
+ new_l2_entry |= QCOW_OFLAG_ZERO;
|
|
|
+ } else {
|
|
|
+ new_l2_entry = QCOW_OFLAG_ZERO;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ new_l2_entry = 0;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1960,8 +1976,16 @@ static int discard_in_l2_slice(BlockDriverState *bs, uint64_t offset,
|
|
|
if (has_subclusters(s)) {
|
|
|
set_l2_bitmap(s, l2_slice, l2_index + i, new_l2_bitmap);
|
|
|
}
|
|
|
- /* Then decrease the refcount */
|
|
|
- qcow2_free_any_cluster(bs, old_l2_entry, type);
|
|
|
+ if (!keep_reference) {
|
|
|
+ /* Then decrease the refcount */
|
|
|
+ qcow2_free_any_cluster(bs, old_l2_entry, type);
|
|
|
+ } else if (s->discard_passthrough[type] &&
|
|
|
+ (cluster_type == QCOW2_CLUSTER_NORMAL ||
|
|
|
+ cluster_type == QCOW2_CLUSTER_ZERO_ALLOC)) {
|
|
|
+ /* If we keep the reference, pass on the discard still */
|
|
|
+ bdrv_pdiscard(s->data_file, old_l2_entry & L2E_OFFSET_MASK,
|
|
|
+ s->cluster_size);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
|