[Devel] [PATCH hci-8.1 v3 5/5] dm-qcow2: fix a refcount table relocation failing on a valid image
Denis V. Lunev
den at openvz.org
Wed Nov 4 21:01:05 MSK 2026
From: Denis V. Lunev <den at openvz.org>
relocate_refcount_table() puts the new reftable at pos, the start of
the first refcount group the old table does not cover, and the new
refblocks right after it. It then gives each new refblock to the group
the refblock itself sits in. When the new reftable fills the group of
pos by itself, the refblocks all land in the next group, and the group
of pos gets none. Marking the reftable clusters used then fails with a
WARN, and every allocating write past the old refcount coverage fails
with EIO.
A valid image gets there: with 4K clusters and refcount_bits=64 a
refcount group is 512 clusters, and the reftable reaches 512 clusters
when the image file grows to about 511G; with refcount_bits=32, at
about 2T.
Give the new refblocks to the groups the new reftable and refblocks
span, one each, in order. pos is group-aligned, and r2_clus is computed
for the refblocks to count both themselves and the new table, so there
is a refblock for each of these groups.
Fixes: 222b6f1291c1 ("dm-qcow2: Introduce driver to create block devices over QCOW2 files")
Reported-by: Konstantin Khorenko <khorenko at virtuozzo.com>
https://virtuozzo.atlassian.net/browse/VSTOR-153421
Feature: dm-qcow2: block device over QCOW2 files driver
Signed-off-by: Denis V. Lunev <den at openvz.org>
---
drivers/md/dm-qcow2-map.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/md/dm-qcow2-map.c b/drivers/md/dm-qcow2-map.c
index eee865989ef7..34d9d9810f60 100644
--- a/drivers/md/dm-qcow2-map.c
+++ b/drivers/md/dm-qcow2-map.c
@@ -2277,7 +2277,7 @@ static void set_reftable_in_raw_hdr(struct page *page0, loff_t pos, loff_t clus)
static int relocate_refcount_table(struct qcow2 *qcow2, struct qio **qio)
{
loff_t i, old_pos, old_end, pos, end, r2_end, delta;
- loff_t new_md_start, new_md_end;
+ loff_t new_md_start, new_md_end, group_size, r2_pos;
u32 old_clus, clus, clu_size = qcow2->clu_size;
u32 r2_clus, bits = qcow2->refblock_bits;
unsigned long nr_pages, index;
@@ -2385,8 +2385,11 @@ static int relocate_refcount_table(struct qcow2 *qcow2, struct qio **qio)
if (i != nr_pages)
goto err_eio;
- /* Connect new R2 to new R1 */
- for (i = end; i < r2_end; i += clu_size) {
+ /* Connect new R2 to new R1: one for each group new R1 and R2 span */
+ group_size = (u64)qcow2->refblock_entries * clu_size;
+ for (i = pos, r2_pos = end; i < r2_end; i += group_size, r2_pos += clu_size) {
+ if (WARN_ON_ONCE(r2_pos >= r2_end))
+ goto err_eio;
if (calc_refcounters_map(qcow2, i, &r1, &r2) < 0) {
WARN_ON_ONCE(1);
goto err_eio;
@@ -2395,7 +2398,7 @@ static int relocate_refcount_table(struct qcow2 *qcow2, struct qio **qio)
if (WARN_ON_ONCE(ret <= 0))
goto err_eio;
spin_lock_irq(&qcow2->md_pages_lock);
- set_u64_to_be_page(md->page, r1.index_in_page, i);
+ set_u64_to_be_page(md->page, r1.index_in_page, r2_pos);
qcow2_md_make_dirty(qcow2, md, true);
spin_unlock_irq(&qcow2->md_pages_lock);
}
--
2.53.0
More information about the Devel
mailing list