All Virtuozzo development lists (kernel + QEMU)
 help / color / mirror / Atom feed
From: no-reply@sashiko.virtuozzo.com
To: andrey.zhadchenko@virtuozzo.com, "Denis V. Lunev" <den@openvz.org>
Cc: devel@openvz.org
Subject: Re: [Devel] [PATCH hci-8.1 v2 1/3] dm-qcow2: fix a failed refcount table relocation leaking md pages
Date: Tue, 3 Nov 2026 09:13:41 +0000	[thread overview]
Message-ID: <010701a1a0af8baa-a0ca15fb-0759-4d53-a0b5-0db02a731ff8-000000@eu-central-1.amazonses.com> (raw)
In-Reply-To: <20261103090813.166986-2-den@openvz.org>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] dm-qcow2: err_free_r2_pages frees dirty md pages still on writeback lists
--

commit 774fe387096c63a6d4048c14687fd00ee87e6e1a
Author: Denis V. Lunev <den@openvz.org>

dm-qcow2: fix a failed refcount table relocation leaking md pages

This patch changes the error path of relocate_refcount_table() so that it
frees exactly the md pages the allocation loop inserted. Before, it freed
only one page per cluster starting from end. The patch tracks the range with
new_md_start and new_md_end and frees every page in that range.

Link: https://virtuozzo.atlassian.net/browse/VSTOR-153051

> diff --git a/drivers/md/dm-qcow2-map.c b/drivers/md/dm-qcow2-map.c
> --- a/drivers/md/dm-qcow2-map.c
> +++ b/drivers/md/dm-qcow2-map.c

[ ... ]

> @@ -2342,8 +2343,9 @@ static int relocate_refcount_table(struct qcow2 *qcow2, struct qio **qio)
>  		return ret;
>  
>  	/* Alloc R1/R2 pages covering clusters of new R1 and new R2 */
> -	for (i = pos + (u64)old_clus * clu_size; i < r2_end; i += PAGE_SIZE) {
> -		ret = qcow2_alloc_and_insert_md_page(qcow2, i >> PAGE_SHIFT, &md);
> +	new_md_start = pos + (u64)old_clus * clu_size;
> +	for (new_md_end = new_md_start; new_md_end < r2_end; new_md_end += PAGE_SIZE) {
> +		ret = qcow2_alloc_and_insert_md_page(qcow2, new_md_end >> PAGE_SHIFT, &md);
>  		if (ret < 0)
>  			goto err_free_r2_pages;

[ ... ]

> @@ -2419,7 +2421,7 @@ static int relocate_refcount_table(struct qcow2 *qcow2, struct qio **qio)
>  	return 1;
>  
>  err_free_r2_pages:
> -	for (i = end; i < r2_end; i += clu_size) {
> +	for (i = new_md_start; i < new_md_end; i += PAGE_SIZE) {
>  		ret = handle_md_page(qcow2, i >> PAGE_SHIFT, NULL, &md);
>  		if (ret <= 0)
>  			break;
>  		spin_lock_irq(&qcow2->md_pages_lock);
>  		qcow2_md_page_erase(qcow2, md);
>  		spin_unlock_irq(&qcow2->md_pages_lock);
>  		qcow2_free_md_page(md);
>  	}

[Severity: Medium]
Can this cleanup free md pages that are still linked on a writeback list?

The loop now erases and frees every page in [new_md_start, new_md_end).
It does not unlink md->wb_link, and it does not check MD_DIRTY or
MD_WRITEBACK.

Several gotos to err_free_r2_pages come after the header write, once pages
in this range may already be dirty:

  - the renumber loop, when qcow2_md_page_renumber() returns NULL
    (md_page_try_insert() failure, or error injection through
    ALLOW_ERROR_INJECTION)
  - the "Connect new R2 to new R1" loop, on calc_refcounters_map() or
    handle_md_page() failure
  - the mark_cluster_used() and mark_cluster_unused() loops, on
    qcow2_handle_r1r2_maps() failure. This includes the non-WARN -EIO
    from the "refblock=%llu, while no snapshots" sanity check.

By then qcow2_md_make_dirty() may have run on pages in the range:

qcow2_md_make_dirty() {
    if (!(md->status & MD_DIRTY)) {
        md->status |= MD_DIRTY;
        list_add_tail(&md->wb_link, head);
        ...
        mod_timer(&qcow2->slow_wb_timer, jiffies + WB_TIMEOUT_JI);

qcow2_md_page_erase() is only an rb_erase(). qcow2_free_md_page() is only
put_page() plus kfree(). Neither touches wb_link.

A freed struct md_page could then stay on wb_batch_list or
slow_wb_batch_list. A later writeback pass or slow_wb_timer would touch
freed memory.

The commit message says this is safe because "the gotos after it are
WARN_ON_ONCE() branches" that "want the image switched to read-only".
Is that accurate?

There is still no switch to read-only here, only the "TODO: switch to RO"
comment followed by return -EIO.

Some of the late branches are not WARN_ON_ONCE() branches. One example is
the -EIO from the "while no snapshots" check in qcow2_handle_r1r2_maps().

R2 pages could already be dirtied by mark_cluster_used() before this patch.
The R1 tail page and the additional pages of each R2 cluster are newly
exposed to this cleanup.

Would it make sense to unlink wb_link for dirty pages in this loop, or to
skip freeing the pages once the header write has succeeded?

-- 
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261103090813.166986-1-den@openvz.org?part=1

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

  reply	other threads:[~2026-11-03  9:15 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-03  9:08 [Devel] [PATCH hci-8.1 v2 0/3] dm-qcow2: fix merges not stopping the users of the images they change Denis V. Lunev
2026-11-03  9:08 ` [Devel] [PATCH hci-8.1 v2 1/3] dm-qcow2: fix a failed refcount table relocation leaking md pages Denis V. Lunev
2026-11-03  9:13   ` no-reply [this message]
2026-11-03  9:27     ` Denis V. Lunev
2026-11-04 16:59   ` Konstantin Khorenko
2026-11-03  9:08 ` [Devel] [PATCH hci-8.1 v2 2/3] dm-qcow2: fix backward merge of an inner image racing its reads Denis V. Lunev
2026-11-03  9:13   ` no-reply
2026-11-04 16:59   ` Konstantin Khorenko
2026-11-03  9:08 ` [Devel] [PATCH hci-8.1 v2 3/3] dm-qcow2: fix SEEK_HOLE/SEEK_DATA using an image freed by a merge Denis V. Lunev
2026-11-03  9:15   ` no-reply
2026-11-04 16:59   ` Konstantin Khorenko
2026-11-04 13:15 ` [Devel] [PATCH hci-8.1 v2 0/3] dm-qcow2: fix merges not stopping the users of the images they change Andrey Zhadchenko
2026-11-04 16:59 ` 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=010701a1a0af8baa-a0ca15fb-0759-4d53-a0b5-0db02a731ff8-000000@eu-central-1.amazonses.com \
    --to=no-reply@sashiko.virtuozzo.com \
    --cc=andrey.zhadchenko@virtuozzo.com \
    --cc=den@openvz.org \
    --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.