OpenVZ / Virtuozzo kernel development (devel@openvz.org)
 help / color / mirror / Atom feed
From: no-reply@sashiko.virtuozzo.com
To: Alexander Ivanov <alexander.ivanov@virtuozzo.com>,
	andrey.zhadchenko@virtuozzo.com
Cc: devel@openvz.org
Subject: Re: [Devel] [PATCH hci-8.1 v11 10/10] dm-qcow2: truncate unused tail of image on suspend
Date: Mon, 9 Nov 2026 14:18:02 +0000	[thread overview]
Message-ID: <010701a1c0ac58d9-774c6712-76a3-4839-b795-01687be81303-000000@eu-central-1.amazonses.com> (raw)
In-Reply-To: <20261109140143.1408038-11-alexander.ivanov@virtuozzo.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] dm-qcow2: unused-tail truncation on suspend trusts refcounts with no kernel-side guard
- [Medium] dm-qcow2: GFP_KERNEL md page reads in postsuspend can deadlock on reclaim
--

commit 74d743673c019d9879114318e501a9a5de73c937
Author: Alexander Ivanov <alexander.ivanov@virtuozzo.com>

dm-qcow2: truncate unused tail of image on suspend

This patch adds qcow2_calc_used_end(), which scans the refcount blocks backward from file_preallocated_area_start. It returns the end of the last cluster with a non-zero refcount. qcow2_truncate_unused_tail() now truncates the image file to that point on postsuspend. It falls back to the old behaviour on scan errors, after a metadata writeback error, and for dirty images when kernel_sets_dirty_bit is set.

> 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

[ ... ]

> +loff_t qcow2_calc_used_end(struct qcow2 *qcow2)
> +{

[ ... ]

> +		if (!r1_md || r1_md->id != r1.page_id) {
> +			ret = qcow2_md_page_read_sync(qcow2, r1.page_id, &r1_md);
> +			if (ret)
> +				return ret;
> +		}

[ ... ]

> +		ret = qcow2_md_page_read_sync(qcow2, r2.page_id, &r2.md);
> +		if (ret)
> +			return ret;
> +
> +		for (i = r2.index_in_page; i >= 0; i--, pos -= clu_size) {
> +			if (get_r2_entry(qcow2, r2.md, i))
> +				return min_t(loff_t, pos + clu_size,
> +					     qcow2->file_preallocated_area_start);
> +		}

[Severity: Medium]
Can this scan allocate memory in a way that deadlocks under reclaim? qcow2_calc_used_end() is called from the postsuspend hook:

qcow2_postsuspend()
  qcow2_truncate_unused_tail()
    qcow2_calc_used_end()
      qcow2_md_page_read_sync()
        qcow2_alloc_and_insert_md_page()
          kmalloc(sizeof(**md), GFP_KERNEL)
          alloc_page(GFP_KERNEL)

Every R1 or R2 page that is not already in the md cache is read this way, and then read from the image file. Neither the dm core nor the driver sets a memalloc_noio or memalloc_nofs scope around postsuspend.

Direct reclaim from these GFP_KERNEL allocations could issue writeback to a filesystem or swap on this same suspended device, or on a device stacked on it. That I/O cannot complete until resume, and resume waits for postsuspend.

Before this patch, postsuspend only used the already cached page 0 through qcow2_set_image_file_features(). The other allocations in the I/O and metadata paths use GFP_NOIO or run under PF_MEMALLOC_NOIO.

Should the scan run under a memalloc_noio_save()/memalloc_noio_restore() scope, or use GFP_NOIO allocations?

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

[ ... ]

> +	if (tgt->md_writeback_error) {
> +		QC_INFO(ti, "Skip shrinking to used end after md writeback error");
> +	} else if (kernel_sets_dirty_bit && qcow2->opened_dirty) {
> +		QC_INFO(ti, "Skip shrinking to used end of dirty image");
> +	} else {
> +		used_end = qcow2_calc_used_end(qcow2);

[Severity: Medium]
Can this truncation cut off live guest data? The used end is derived from refcounts alone, with no cross-check against L2. If a cluster has refcount zero but is still referenced by L2, the cut point moves below live data and qcow2_truncate_safe() discards it permanently.

The commit message says refcounts may be below real usage after a crash, since both QEMU with lazy_refcounts and this driver write L2 before refcounts. The only guards here are md_writeback_error and kernel_sets_dirty_bit && opened_dirty.

A v2 image has no dirty bit. qcow2_check_convert_hdr() returns early for version 2, so opened_dirty stays false.

In the default mode kernel_sets_dirty_bit is false, so the opened_dirty guard is skipped.

The ctr-time check in qcow2_check_convert_hdr() is commented out:

//	if (!is_ro && kernel_sets_dirty_bit !=
//	    !(hdr->incompatible_features & INCOMPATIBLE_FEATURES_DIRTY_BIT))
//		return kernel_sets_dirty_bit ? -EUCLEAN : -ENOLCK;

qcow2_wants_check() covers only md_writeback_error and truncate_error, which are errors from the current session. Nothing in the driver detects an on-disk inconsistency left by an earlier crash.

The commit message says the scan is safe "only because userspace checks the image before an RW open". Can the driver verify that assumption?

Would it be possible to refuse the truncation when the cut range is still referenced by L2, or to make the shrink opt-in?

-- 
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261109140143.1408038-2-alexander.ivanov@virtuozzo.com?part=10

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

  reply	other threads:[~2026-11-09 14:19 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-09 14:01 [Devel] [PATCH hci-8.1 v11 00/10] " Alexander Ivanov
2026-11-09 14:01 ` [Devel] [PATCH hci-8.1 v11 01/10] dm-qcow2: add qcow2_md_page_read_sync() helper Alexander Ivanov
2026-11-09 14:06   ` no-reply
2026-11-09 14:01 ` [Devel] [PATCH hci-8.1 v11 02/10] dm-qcow2: drop duplicate prefix from QC_ERR/QC_INFO messages Alexander Ivanov
2026-11-09 14:05   ` no-reply
2026-11-09 14:01 ` [Devel] [PATCH hci-8.1 v11 03/10] dm-qcow2: extend the file for a new refblock in allocate_cluster() Alexander Ivanov
2026-11-09 14:06   ` no-reply
2026-11-09 14:01 ` [Devel] [PATCH hci-8.1 v11 04/10] dm-qcow2: complete wbd before ending the data qio Alexander Ivanov
2026-11-09 14:09   ` no-reply
2026-11-09 14:01 ` [Devel] [PATCH hci-8.1 v11 05/10] dm-qcow2: flush lower md before clearing dirty bit on merge failure Alexander Ivanov
2026-11-09 14:08   ` no-reply
2026-11-09 14:01 ` [Devel] [PATCH hci-8.1 v11 06/10] dm-qcow2: keep the dirty bit of an image that needs check Alexander Ivanov
2026-11-09 14:11   ` no-reply
2026-11-09 14:01 ` [Devel] [PATCH hci-8.1 v11 07/10] dm-qcow2: flag the image for check if reftable relocation fails late Alexander Ivanov
2026-11-09 14:11   ` no-reply
2026-11-09 15:42   ` Konstantin Khorenko
2026-11-09 14:01 ` [Devel] [PATCH hci-8.1 v11 08/10] dm-qcow2: leak clusters allocated for a failed L1/L2 writeback Alexander Ivanov
2026-11-09 14:14   ` no-reply
2026-11-09 14:36     ` Alexander Ivanov
2026-11-09 15:42   ` Konstantin Khorenko
2026-11-09 14:01 ` [Devel] [PATCH hci-8.1 v11 09/10] dm-qcow2: retry R1/R2 writeback that failed with ENOSPC Alexander Ivanov
2026-11-09 14:16   ` no-reply
2026-11-09 14:39     ` Alexander Ivanov
2026-11-09 15:42   ` Konstantin Khorenko
2026-11-09 14:01 ` [Devel] [PATCH hci-8.1 v11 10/10] dm-qcow2: truncate unused tail of image on suspend Alexander Ivanov
2026-11-09 14:18   ` no-reply [this message]
2026-11-09 14:47     ` Alexander Ivanov
2026-11-09 15:42   ` Konstantin Khorenko
2026-11-09 15:42 ` [Devel] [PATCH hci-8.1 v11 00/10] " Konstantin Khorenko
2026-11-09 15:54 ` 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=010701a1c0ac58d9-774c6712-76a3-4839-b795-01687be81303-000000@eu-central-1.amazonses.com \
    --to=no-reply@sashiko.virtuozzo.com \
    --cc=alexander.ivanov@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox