From mboxrd@z Thu Jan 1 00:00:00 1970 From: Andrey Zhadchenko Date: Tue, 25 Aug 2026 15:24:30 +0300 Subject: [Devel] [PATCH VZ10 v3 11/11] drivers/md/dm-qcow2: respect zeroes during merge In-Reply-To: <20260825122430.252094-1-andrey.zhadchenko@virtuozzo.com> References: <20260825122430.252094-1-andrey.zhadchenko@virtuozzo.com> Message-ID: <20260825122430.252094-12-andrey.zhadchenko@virtuozzo.com> List-Id: The merge machinery used to skip unallocated clusters, therefore breaking all clusters with zero bits and non-zero backing. Technically this bug was present even before discard changes, as qcow2 image could have 'reads as zero' bits before being inserted into dm-qcow2. Properly commit all zero clusters (albeit with data for now). https://virtuozzo.atlassian.net/browse/VSTOR-138288 Feature: dm-qcow2: block device over QCOW2 files driver Signed-off-by: Andrey Zhadchenko --- drivers/md/dm-qcow2-map.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/md/dm-qcow2-map.c b/drivers/md/dm-qcow2-map.c index 41a504c65b722..e909548530d27 100644 --- a/drivers/md/dm-qcow2-map.c +++ b/drivers/md/dm-qcow2-map.c @@ -2744,6 +2744,13 @@ static void requeue_if_ok(struct qcow2_target *tgt, struct qio *unused, qcow2_dispatch_qios(qio->qcow2, qio, NULL); } +static bool clu_zeroes_present(struct qcow2 *qcow2, struct qcow2_map *map) +{ + if (qcow2->ext_l2) + return (map->ext_l2 >> 32) != 0; + return map->all_zeroes; +} + static int prepare_backward_merge(struct qcow2 *qcow2, struct qio **qio, struct qcow2_map *map, bool write) { @@ -2761,7 +2768,7 @@ static int prepare_backward_merge(struct qcow2 *qcow2, struct qio **qio, } } - if (!map->data_clu_alloced) { + if (!map->data_clu_alloced && !clu_zeroes_present(qcow2, map)) { /* Strange COW at L1, except the merge from RO image */ WARN_ON_ONCE(map->clu_is_cow && qio_may_modify_image(qcow2, *qio)); if (fake_merge_qio(*qio)) { @@ -2808,7 +2815,7 @@ static int prepare_backward_merge(struct qcow2 *qcow2, struct qio **qio, goto endio; } - if (!map->clu_is_cow) { + if (!map->clu_is_cow && map->data_clu_alloced) { /* Forced set these to unuse them after discard */ (*qio)->ext->unuse_clu_pos = map->data_clu_pos; (*qio)->ext->unuse_clu_end = map->data_clu_pos + qcow2->clu_size; -- 2.43.5