diff options
author | Jean-Louis Dupond <jean-louis@dupond.be> | 2023-10-03 14:52:37 +0200 |
---|---|---|
committer | Hanna Czenczek <hreitz@redhat.com> | 2023-11-06 16:15:07 +0100 |
commit | b2b109041ecd1095384f5be5bb9badd13c1cf286 (patch) | |
tree | 3c6cc355936a8c74e356a86bc3b3526d0def0bc4 /block/qcow2-cluster.c | |
parent | 3e01f1147a16ca566694b97eafc941d62fa1e8d8 (diff) |
qcow2: keep reference on zeroize with discard-no-unref enabled
When the discard-no-unref flag is enabled, we keep the reference for
normal discard requests.
But when a discard is executed on a snapshot/qcow2 image with backing,
the discards are saved as zero clusters in the snapshot image.
When committing the snapshot to the backing file, not
discard_in_l2_slice is called but zero_in_l2_slice. Which did not had
any logic to keep the reference when discard-no-unref is enabled.
Therefor we add logic in the zero_in_l2_slice call to keep the reference
on commit.
Fixes: https://gitlab.com/qemu-project/qemu/-/issues/1621
Signed-off-by: Jean-Louis Dupond <jean-louis@dupond.be>
Message-Id: <20231003125236.216473-2-jean-louis@dupond.be>
[hreitz: Made the documentation change more verbose, as discussed
on-list]
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
Diffstat (limited to 'block/qcow2-cluster.c')
-rw-r--r-- | block/qcow2-cluster.c | 22 |
1 files changed, 18 insertions, 4 deletions
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 904f00d1b3..5af439bd11 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -1983,7 +1983,7 @@ discard_in_l2_slice(BlockDriverState *bs, uint64_t offset, uint64_t nb_clusters, /* 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); @@ -2061,9 +2061,15 @@ zero_in_l2_slice(BlockDriverState *bs, uint64_t offset, 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; + bool keep_reference = + (s->discard_no_unref && type != QCOW2_CLUSTER_COMPRESSED); + uint64_t new_l2_entry = old_l2_entry; uint64_t new_l2_bitmap = old_l2_bitmap; + if (unmap && !keep_reference) { + new_l2_entry = 0; + } + if (has_subclusters(s)) { new_l2_bitmap = QCOW_L2_BITMAP_ALL_ZEROES; } else { @@ -2081,9 +2087,17 @@ zero_in_l2_slice(BlockDriverState *bs, uint64_t offset, set_l2_bitmap(s, l2_slice, l2_index + i, new_l2_bitmap); } - /* Then decrease the refcount */ if (unmap) { - qcow2_free_any_cluster(bs, old_l2_entry, QCOW2_DISCARD_REQUEST); + if (!keep_reference) { + /* Then decrease the refcount */ + qcow2_free_any_cluster(bs, old_l2_entry, QCOW2_DISCARD_REQUEST); + } else if (s->discard_passthrough[QCOW2_DISCARD_REQUEST] && + (type == QCOW2_CLUSTER_NORMAL || + 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); + } } } |