From: Konstantin Khorenko <khorenko@virtuozzo.com>
To: Andrey Zhadchenko <andrey.zhadchenko@virtuozzo.com>
Cc: OpenVZ devel <devel@openvz.org>
Subject: Re: [Devel] [PATCH RHEL10 COMMIT] drivers/md/dm-qcow2: fix revert_cluster_alloc() for ext_l2 case
Date: Fri, 28 Aug 2026 19:03:55 +0200 [thread overview]
Message-ID: <202608281703.67SH3tt81064173@f0.sw.ru> (raw)
In-Reply-To: <20260827160619.303398-3-andrey.zhadchenko@virtuozzo.com>
The commit is pushed to "branch-rh10-6.12.0-211.39.1.16.x.vz10-ovz" and will appear at git@bitbucket.org:openvz/vzkernel.git
after rh10-6.12.0-211.39.1.16.11.vz10
------>
commit 96e80433d537c82f2cfb27a3e2c335882d4e15a3
Author: Andrey Zhadchenko <andrey.zhadchenko@virtuozzo.com>
Date: Thu Aug 27 19:06:10 2026 +0300
drivers/md/dm-qcow2: fix revert_cluster_alloc() for ext_l2 case
This function walks over all changed u64 values in md. With ext_l2
half of them holds subcluster description. Firstly it reverts these
values to saved pe_page, which is fine, but then it tries to revert
r1r2 changes. It makes no sense when the value is a subcluster
description.
Teach the function to skip subcluster descriptions: do it based on
a new lx_level in struct wb_desc. Add new argument to
prepare_l_entry_update() and set it there.
The warning also could have tripped for ext_l2 entries, so drop
it entirely.
The function effectively reverts not only cluster alloc, so rename
it to revert_l_entries_update() to mimic prepare_l_entry_update().
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>
Reviewed-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
Reviewed-by: Vasileios Almpanis <vasileios.almpanis@virtuozzo.com>
Reviewed-by: Konstantin Khorenko <khorenko@virtuozzo.com>
---
drivers/md/dm-qcow2-map.c | 28 ++++++++++++++++++----------
drivers/md/dm-qcow2-target.c | 2 +-
drivers/md/dm-qcow2.h | 1 +
3 files changed, 20 insertions(+), 11 deletions(-)
diff --git a/drivers/md/dm-qcow2-map.c b/drivers/md/dm-qcow2-map.c
index 6ead06ef7b3f9..52dc68baa49be 100644
--- a/drivers/md/dm-qcow2-map.c
+++ b/drivers/md/dm-qcow2-map.c
@@ -1297,18 +1297,19 @@ static void do_md_page_read_complete(int ret, struct qcow2 *qcow2,
}
/* Be careful with dirty_or_writeback()/etc! Check races. */
-static void revert_clusters_alloc(struct qcow2 *qcow2, struct wb_desc *wbd)
+static void revert_l_entries_update(struct qcow2 *qcow2, struct wb_desc *wbd)
{
struct qcow2_map_item r1, r2;
struct page *pe_page;
+ bool skip_odd;
u64 pos, old;
int i, ret;
+ skip_odd = qcow2->ext_l2 && wbd->lx_level == L2_LEVEL;
+
lockdep_assert_held(&qcow2->md_pages_lock);
for_each_set_bit(i, wbd->changed_indexes, LX_INDEXES_PER_PAGE) {
pos = get_u64_from_be_page(wbd->md->page, i);
- WARN_ON_ONCE(!(pos & ~LX_REFCOUNT_EXACTLY_ONE) ||
- !(pos & LX_REFCOUNT_EXACTLY_ONE));
/* Here we restore prealloced and compressed clu mappings */
pe_page = wbd->pe_page;
@@ -1321,6 +1322,9 @@ static void revert_clusters_alloc(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 */
+
spin_unlock(&qcow2->md_pages_lock);
pos &= ~LX_REFCOUNT_EXACTLY_ONE;
@@ -1369,7 +1373,7 @@ static void complete_wbd(struct qcow2 *qcow2, struct wb_desc *wbd)
unsigned long flags;
spin_lock_irqsave(&qcow2->md_pages_lock, flags);
- revert_clusters_alloc(qcow2, wbd);
+ revert_l_entries_update(qcow2, wbd);
clear_writeback_status(qcow2, wbd->md, wbd->ret,
&wait_list, &end_list);
spin_unlock_irqrestore(&qcow2->md_pages_lock, flags);
@@ -2433,7 +2437,7 @@ static loff_t allocate_cluster(struct qcow2 *qcow2, struct qio *qio,
#define LU_IGN_CHANGED_IND (1 << 3)
static int prepare_l_entry_update(struct qcow2 *qcow2, struct qio *qio,
struct md_page *md, u32 index_in_page,
- u64 *pval, u32 arg_mask)
+ u64 *pval, u32 arg_mask, u8 lx_level)
{
bool wants_pe_page = (arg_mask & LU_WANTS_PE_PAGE);
struct wb_desc *new_wbd = NULL;
@@ -2453,6 +2457,7 @@ static int prepare_l_entry_update(struct qcow2 *qcow2, struct qio *qio,
if (!new_wbd)
return -ENOMEM;
new_wbd->md = md;
+ new_wbd->lx_level = lx_level;
} else if (wants_pe_page && !md->wbd->pe_page) {
pe_page = alloc_page(GFP_NOIO|__GFP_ZERO);
if (!pe_page)
@@ -2515,7 +2520,8 @@ static int prepare_l1l2_allocation(struct qcow2 *qcow2, struct qio *qio,
/* Allocate cluster for L2 entries, and prepare L1 update */
ret = prepare_l_entry_update(qcow2, qio, map->l1.md,
map->l1.index_in_page, &val,
- LU_SET_ONE_MASK|LU_WANTS_ALLOC);
+ LU_SET_ONE_MASK | LU_WANTS_ALLOC,
+ L1_LEVEL);
if (ret <= 0)
return ret;
@@ -2541,7 +2547,8 @@ static int prepare_l1l2_allocation(struct qcow2 *qcow2, struct qio *qio,
ret = prepare_l_entry_update(qcow2, qio, map->l2.md,
map->l2.index_in_page,
- &map->data_clu_pos, arg_mask);
+ &map->data_clu_pos, arg_mask,
+ L2_LEVEL);
if (ret <= 0)
return ret;
@@ -2562,7 +2569,7 @@ static int prepare_l1l2_allocation(struct qcow2 *qcow2, struct qio *qio,
return prepare_l_entry_update(qcow2, qio, map->l2.md,
map->l2.index_in_page + 1,
- &val, arg_mask);
+ &val, arg_mask, L2_LEVEL);
}
/*
@@ -3979,7 +3986,7 @@ static void process_cow_indexes_write(struct qcow2 *qcow2,
ret = prepare_l_entry_update(qcow2, qio, lx_md,
ext->lx_index_in_page,
&ext->allocated_clu_pos,
- arg_mask);
+ arg_mask, ext->cow_level);
if (ret < 0) {
qio->bi_status = errno_to_blk_status(ret);
qio_endio(qio);
@@ -3990,7 +3997,8 @@ static void process_cow_indexes_write(struct qcow2 *qcow2,
arg_mask &= ~LU_SET_ONE_MASK;
ret = prepare_l_entry_update(qcow2, qio, lx_md,
ext->lx_index_in_page + 1,
- &ext->new_ext_l2, arg_mask);
+ &ext->new_ext_l2, arg_mask,
+ L2_LEVEL);
WARN_ON_ONCE(ret < 0);
}
diff --git a/drivers/md/dm-qcow2-target.c b/drivers/md/dm-qcow2-target.c
index 2877de6f11c12..be09615eb8e2e 100644
--- a/drivers/md/dm-qcow2-target.c
+++ b/drivers/md/dm-qcow2-target.c
@@ -174,7 +174,7 @@ void qcow2_flush_deferred_activity(struct qcow2_target *tgt, struct qcow2 *qcow2
int i;
/*
- * We need second iteration, since revert_clusters_alloc()
+ * We need second iteration, since revert_l_entries_update()
* may start timer again after failed wb.
*/
for (i = 0; i < 2; i++) {
diff --git a/drivers/md/dm-qcow2.h b/drivers/md/dm-qcow2.h
index 86f0688e7345a..aa3487007523f 100644
--- a/drivers/md/dm-qcow2.h
+++ b/drivers/md/dm-qcow2.h
@@ -118,6 +118,7 @@ struct wb_desc {
struct list_head dependent_list;
int nr_submitted;
bool completed;
+ u8 lx_level;
int ret;
};
_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel
next prev parent reply other threads:[~2026-08-28 17:05 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 ` Konstantin Khorenko [this message]
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 ` [Devel] [PATCH VZ10 v4 06/11] drivers/md/dm-qcow2: set L2_READS_ALL_ZEROES after some discards Andrey Zhadchenko
2026-08-28 17:03 ` [Devel] [PATCH RHEL10 COMMIT] " 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=202608281703.67SH3tt81064173@f0.sw.ru \
--to=khorenko@virtuozzo.com \
--cc=andrey.zhadchenko@virtuozzo.com \
--cc=devel@openvz.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.