From: Andrey Zhadchenko <andrey.zhadchenko@virtuozzo.com>
To: ptikhomirov@virtuozzo.com, vasileios.almpanis@virtuozzo.com
Cc: devel@openvz.org
Subject: [Devel] [PATCH VZ10 v4 06/11] drivers/md/dm-qcow2: set L2_READS_ALL_ZEROES after some discards
Date: Thu, 27 Aug 2026 19:06:14 +0300 [thread overview]
Message-ID: <20260827160619.303398-7-andrey.zhadchenko@virtuozzo.com> (raw)
In-Reply-To: <20260827160619.303398-1-andrey.zhadchenko@virtuozzo.com>
Discard does not guarantee zero data. Therefore, to safely erase
data, users may write zeroes and then discard. Imagine we have
a backing file. If we write zeroes and do the discard, next read
will give the stale data from backing image.
Probably this is rather an edge case, but to be sure let's just
set L2 entry to L2_READS_ALL_ZEROES so the device looks more
consistent to users.
Feature: dm-qcow2: block device over QCOW2 files driver
https://virtuozzo.atlassian.net/browse/VSTOR-139406
Signed-off-by: Andrey Zhadchenko <andrey.zhadchenko@virtuozzo.com>
---
v2:
- expand qio_discard_updates_metadata() condition to return true
when backing file is present and fully covered sublcu zero bit isn't
already set
v4:
- set new_ext_l2 value as 0. If we clear a full cluster, we also need
to clear all ext_l2, except the case with backing (handled separately)
drivers/md/dm-qcow2-map.c | 24 +++++++++++++++++++++---
drivers/md/dm-qcow2.h | 1 +
2 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/drivers/md/dm-qcow2-map.c b/drivers/md/dm-qcow2-map.c
index a2e5c37adb7b9..52a630685518b 100644
--- a/drivers/md/dm-qcow2-map.c
+++ b/drivers/md/dm-qcow2-map.c
@@ -1309,6 +1309,7 @@ static void revert_l_entries_update(struct qcow2 *qcow2, struct wb_desc *wbd)
struct page *pe_page;
bool skip_odd;
u64 pos, old;
+ bool cleared;
int i, ret;
skip_odd = qcow2->ext_l2 && wbd->lx_level == L2_LEVEL;
@@ -1317,6 +1318,8 @@ static void revert_l_entries_update(struct qcow2 *qcow2, struct wb_desc *wbd)
for_each_set_bit(i, wbd->changed_indexes, LX_INDEXES_PER_PAGE) {
pos = get_u64_from_be_page(wbd->md->page, i);
+ cleared = !(pos & ~(u64)L2_READS_ALL_ZEROES);
+
/* Here we restore prealloced and compressed clu mappings */
pe_page = wbd->pe_page;
if (pe_page) { /* Only L2 has this. */
@@ -1330,7 +1333,7 @@ static void revert_l_entries_update(struct qcow2 *qcow2, struct wb_desc *wbd)
set_u64_to_be_page(wbd->md->page, i, 0);
if (skip_odd && (i & 1))
continue; /* pos contains ext_l2 part of L2 entry */
- if (!pos)
+ if (cleared)
continue; /* no cluster was allocated */
spin_unlock(&qcow2->md_pages_lock);
@@ -3368,14 +3371,18 @@ static bool qio_discard_updates_metadata(struct qcow2 *qcow2, struct qio *qio,
*
* Discard covering the whole cluster replaces the entry and unuses
* the discarded (or COW source) cluster.
+ * If the backing is present, set 'reads as zeroes' to avoid exposing
+ * stale data.
*/
static int prepare_cluster_discard(struct qcow2 *qcow2, struct qio **qio,
struct qcow2_map *map)
{
+ bool zeroes = maybe_mapped_in_lower_delta(qcow2, *qio);
u32 index_in_page = map->l2.index_in_page;
struct md_page *md = map->l2.md;
loff_t unuse_pos, unuse_end;
struct qio_ext *ext;
+ u64 new_ext_l2 = 0;
int ret;
WARN_ON_ONCE(!(map->level & L2_LEVEL) || !map->data_clu_alloced);
@@ -3399,6 +3406,8 @@ static int prepare_cluster_discard(struct qcow2 *qcow2, struct qio **qio,
unuse_pos = map->data_clu_pos;
unuse_end = map->data_clu_pos + qcow2->clu_size;
}
+ if (zeroes && qcow2->ext_l2)
+ new_ext_l2 = (u64)U32_MAX << 32;
ret = prepare_l_entry_replace(qcow2, map, *qio, md, index_in_page,
unuse_pos, unuse_end, L2_LEVEL);
@@ -3408,6 +3417,10 @@ static int prepare_cluster_discard(struct qcow2 *qcow2, struct qio **qio,
ext = (*qio)->ext;
ext->lx_md = md;
+ ext->new_ext_l2 = new_ext_l2;
+ if (zeroes && !qcow2->ext_l2)
+ ext->set_all_zeroes = true;
+
(*qio)->flags |= QIO_IS_DISCARD_FL;
return 1;
}
@@ -4053,6 +4066,7 @@ static void process_indexes_write(struct qcow2 *qcow2,
struct qio *qio;
bool discard;
u32 arg_mask;
+ u64 entry;
int ret;
while (1) {
@@ -4076,11 +4090,15 @@ static void process_indexes_write(struct qcow2 *qcow2,
goto set_ext_l2;
}
+ entry = ext->allocated_clu_pos;
+ if (unlikely(ext->set_all_zeroes))
+ entry = L2_READS_ALL_ZEROES;
+
/* XXX: check prealloced_pos ==> revert */
ret = prepare_l_entry_update(qcow2, qio, lx_md,
ext->lx_index_in_page,
- &ext->allocated_clu_pos,
- arg_mask, ext->lx_level);
+ &entry, arg_mask,
+ ext->lx_level);
if (ret < 0) {
qio->bi_status = errno_to_blk_status(ret);
qio_endio(qio);
diff --git a/drivers/md/dm-qcow2.h b/drivers/md/dm-qcow2.h
index 8a24e04130e4d..0f006f1ae48cc 100644
--- a/drivers/md/dm-qcow2.h
+++ b/drivers/md/dm-qcow2.h
@@ -312,6 +312,7 @@ struct qio_ext {
u64 new_ext_l2;
u32 cow_mask;
bool only_set_ext_l2:1;
+ bool set_all_zeroes:1;
u8 lx_level;
--
2.43.5
_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel
next prev parent reply other threads:[~2026-08-27 16:10 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-27 16:06 [Devel] [PATCH VZ10 v4 00/11] dm-qcow2: improve discard and read-only merge handling Andrey Zhadchenko
2026-08-27 16:06 ` [Devel] [PATCH VZ10 v4 01/11] drivers/md/dm-qcow2: do not attach a bvec to discard qios Andrey Zhadchenko
2026-08-28 17:03 ` [Devel] [PATCH RHEL10 COMMIT] " Konstantin Khorenko
2026-08-27 16:06 ` [Devel] [PATCH VZ10 v4 02/11] drivers/md/dm-qcow2: fix revert_cluster_alloc() for ext_l2 case Andrey Zhadchenko
2026-08-28 17:03 ` [Devel] [PATCH RHEL10 COMMIT] " Konstantin Khorenko
2026-08-27 16:06 ` [Devel] [PATCH VZ10 v4 03/11] drivers/md/dm-qcow2: generalize COW index update machinery Andrey Zhadchenko
2026-08-28 17:03 ` [Devel] [PATCH RHEL10 COMMIT] " Konstantin Khorenko
2026-08-27 16:06 ` [Devel] [PATCH VZ10 v4 04/11] drivers/md/dm-qcow2: update metadata on whole cluster discard Andrey Zhadchenko
2026-08-28 17:03 ` [Devel] [PATCH RHEL10 COMMIT] " Konstantin Khorenko
2026-08-27 16:06 ` [Devel] [PATCH VZ10 v4 05/11] drivers/md/dm-qcow2: never trigger COW or allocation on discard Andrey Zhadchenko
2026-08-28 17:03 ` [Devel] [PATCH RHEL10 COMMIT] " Konstantin Khorenko
2026-08-27 16:06 ` Andrey Zhadchenko [this message]
2026-08-28 17:03 ` [Devel] [PATCH RHEL10 COMMIT] drivers/md/dm-qcow2: set L2_READS_ALL_ZEROES after some discards Konstantin Khorenko
2026-08-27 16:06 ` [Devel] [PATCH VZ10 v4 07/11] drivers/md/dm-qcow2: update metadata on subclusters discard Andrey Zhadchenko
2026-08-28 17:03 ` [Devel] [PATCH RHEL10 COMMIT] " Konstantin Khorenko
2026-08-27 16:06 ` [Devel] [PATCH VZ10 v4 08/11] drivers/md/dm-qcow2: unmap cluster when discard clears last allocated subclusters Andrey Zhadchenko
2026-08-28 17:03 ` [Devel] [PATCH RHEL10 COMMIT] " Konstantin Khorenko
2026-08-27 16:06 ` [Devel] [PATCH VZ10 v4 09/11] drivers/md/dm-qcow2: allow shared L1 entries during merge from RO image Andrey Zhadchenko
2026-08-28 17:03 ` [Devel] [PATCH RHEL10 COMMIT] " Konstantin Khorenko
2026-08-27 16:06 ` [Devel] [PATCH VZ10 v4 10/11] drivers/md/dm-qcow2: do discards during backward merge only for writable image Andrey Zhadchenko
2026-08-28 17:03 ` [Devel] [PATCH RHEL10 COMMIT] " Konstantin Khorenko
2026-08-27 16:06 ` [Devel] [PATCH VZ10 v4 11/11] drivers/md/dm-qcow2: respect zeroes during merge Andrey Zhadchenko
2026-08-28 17:03 ` [Devel] [PATCH RHEL10 COMMIT] " Konstantin Khorenko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260827160619.303398-7-andrey.zhadchenko@virtuozzo.com \
--to=andrey.zhadchenko@virtuozzo.com \
--cc=devel@openvz.org \
--cc=ptikhomirov@virtuozzo.com \
--cc=vasileios.almpanis@virtuozzo.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox