Virtuozzo QEMU development (svt-core@virtuozzo.com)
 help / color / mirror / Atom feed
From: no-reply@sashiko.virtuozzo.com
To: "Denis V. Lunev" <den@openvz.org>, svt-core@virtuozzo.com
Cc: den@virtuozzo.com, andrey.drobyshev@virtuozzo.com
Subject: Re: [PATCH hci-8.0 8/9] block/backup: pre-fill zero_bitmap for full/bitmap #VSTOR-134085
Date: Wed, 30 Sep 2026 11:33:04 +0000	[thread overview]
Message-ID: <010701a0f216edca-98549d2a-a526-44b9-8593-2fab29f4ed9d-000000@eu-central-1.amazonses.com> (raw)
In-Reply-To: <20260930111739.3866427-9-den@openvz.org>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] block: block_copy_calculate_zero_bitmap() can return count 0 forever, hanging the scan
- [Low] block/backup: commit message says full/bitmap but only sync=bitmap uses the new scan
--

commit 252a85c484652c4a95f8a77f49b08e8150b81585
Author: Denis V. Lunev <den@openvz.org>

block/backup: pre-fill zero_bitmap for full/bitmap #VSTOR-134085

This commit adds block_copy_calculate_zero_bitmap() and folds the
up-front source scan into a new backup_scan_source(). The scan now
pre-fills zero_bitmap for sync=bitmap as well as sync=top. sync=full
stays on block_copy_reset_unallocated(), and sync=none keeps the
per-task query.

> block/backup: pre-fill zero_bitmap for full/bitmap #VSTOR-134085

This isn't a code bug, but the subject line and body say that both FULL
and BITMAP get the new up-front scan. Two quoted portions of the commit
message read this way:

  "Add block_copy_calculate_zero_bitmap(), driven one query at a time
  from backup_scan_source() ..."
  "FULL and BITMAP know their complete copy_bitmap before copying
  starts"

In the code, sync=full still takes the block_copy_reset_unallocated()
path, and only sync=bitmap calls block_copy_calculate_zero_bitmap(). The
trailing paragraph of the message says so itself: "sync=full already
runs block_copy_reset_unallocated() ... so it stays on that path and only
sync=bitmap moves to block_copy_calculate_zero_bitmap()".

That leaves the message contradicting itself. It also carries the
downstream "hci-8.0:" tag. Could the subject and body be reworded to
match the code?

[Severity: Low]

> diff --git a/block/backup.c b/block/backup.c
> --- a/block/backup.c
> +++ b/block/backup.c

[ ... ]

> +static int coroutine_fn backup_scan_source(BackupBlockJob *s)
>  {
[ ... ]
> +    for (offset = 0; offset < s->len; offset += count) {
> +        if (job_is_cancelled(job)) {
> +            return -ECANCELED;
> +        }
> +
> +        job_pause_point(job);
[ ... ]
> +        bdrv_graph_co_rdlock();
> +        if (skip) {
> +            ret = block_copy_reset_unallocated(s->bcs, offset, &count);
> +        } else {
> +            block_copy_calculate_zero_bitmap(s->bcs, offset, &cached_end,
> +                                             &count);
> +        }
> +        bdrv_graph_co_rdunlock();

> diff --git a/block/block-copy.c b/block/block-copy.c
> --- a/block/block-copy.c
> +++ b/block/block-copy.c

[ ... ]

> +    if (*cached_end < dirty_end) {
> +        int64_t clusters;
> +        int64_t query_offset = MAX(dirty_offset, *cached_end);
> +        int ret = block_copy_is_cluster_allocated(s, query_offset, &clusters);
> +
> +        if (ret >= 0) {
> +            *cached_end = query_offset + clusters * s->cluster_size;
> +        } else {
> +            /* Best-effort: leave this area unmarked; it copies as data. */
> +            *cached_end = dirty_end;
> +        }
> +    }
> +
> +    /* 0 if the query above didn't yet reach dirty_end: try again next call. */
> +    *count = *cached_end >= dirty_end ? dirty_end - offset : 0;
> +}

Can block_copy_calculate_zero_bitmap() return *count == 0 forever for
sync=bitmap?

block_copy_is_cluster_allocated() sets *pnum = DIV_ROUND_UP(total_count,
cluster_size). That is 0 when bdrv_co_block_status_above() returns
count == 0, for example at or beyond the source EOF. The function still
returns ret >= 0 in that case, since it has an explicit "count == 0"
branch.

If that happens, the ret >= 0 branch above sets
  *cached_end = query_offset + 0 * s->cluster_size;
which is still below dirty_end. *count then stays 0.

In backup_scan_source(), "offset += count" does not advance, so the next
iteration repeats the identical query. job_pause_point() and
job_is_cancelled() do not yield unless the job is paused or cancelled.
That would leave the scan spinning without yielding in the job's
AioContext.

I could not confirm that s->len can exceed the real source length, for
example if the source shrinks during the job, so this may be hard to
reach.

The same "offset += count" shape already exists in
block_copy_reset_unallocated() for top/full. However, the sync=bitmap
path through block_copy_calculate_zero_bitmap() is new with this patch.
The later patch "block/block-copy: coalesce write-zeroes tasks" does not
touch this scan.

Would it make sense to force progress, for example by treating
clusters == 0 like the error path (cached_end = dirty_end), or by
clamping clusters to at least 1?

[Severity: Medium]

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

  reply	other threads:[~2026-09-30 11:33 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-30 11:17 [PATCH hci-8.0 0/9] block: cheaper zero handling in backup and commit #VSTOR-134085 Denis V. Lunev
2026-09-30 11:17 ` [PATCH hci-8.0 1/9] block/commit: pass BDRV_WANT_PRECISE to block-status #VSTOR-134085 Denis V. Lunev
2026-09-30 11:20   ` no-reply
2026-09-30 11:17 ` [PATCH hci-8.0 2/9] iotests/040: cover large and fragmented commit runs #VSTOR-134085 Denis V. Lunev
2026-09-30 11:19   ` no-reply
2026-09-30 11:17 ` [PATCH hci-8.0 3/9] block/commit: batch block-status queries #VSTOR-134085 Denis V. Lunev
2026-09-30 11:21   ` no-reply
2026-09-30 11:17 ` [PATCH hci-8.0 4/9] iotests/124: cover backup of zero clusters and holes #VSTOR-134085 Denis V. Lunev
2026-09-30 11:31   ` no-reply
2026-09-30 11:17 ` [PATCH hci-8.0 5/9] block/block-copy: don't reserve memory for zero tasks #VSTOR-134085 Denis V. Lunev
2026-09-30 11:22   ` no-reply
2026-09-30 11:17 ` [PATCH hci-8.0 6/9] block/block-copy: extract block_copy_set_task_method() #VSTOR-134085 Denis V. Lunev
2026-09-30 11:22   ` no-reply
2026-09-30 11:17 ` [PATCH hci-8.0 7/9] block/block-copy: track known-zero source clusters #VSTOR-134085 Denis V. Lunev
2026-09-30 11:30   ` no-reply
2026-09-30 11:17 ` [PATCH hci-8.0 8/9] block/backup: pre-fill zero_bitmap for full/bitmap #VSTOR-134085 Denis V. Lunev
2026-09-30 11:33   ` no-reply [this message]
2026-09-30 11:17 ` [PATCH hci-8.0 9/9] block/block-copy: coalesce write-zeroes tasks #VSTOR-134085 Denis V. Lunev
2026-09-30 11:34   ` no-reply
2026-09-30 12:49 ` [PATCH hci-8.0 0/9] block: cheaper zero handling in backup and commit #VSTOR-134085 Andrey Drobyshev

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=010701a0f216edca-98549d2a-a526-44b9-8593-2fab29f4ed9d-000000@eu-central-1.amazonses.com \
    --to=no-reply@sashiko.virtuozzo.com \
    --cc=andrey.drobyshev@virtuozzo.com \
    --cc=den@openvz.org \
    --cc=den@virtuozzo.com \
    --cc=svt-core@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