Virtuozzo QEMU development (svt-core@virtuozzo.com)
 help / color / mirror / Atom feed
From: no-reply@sashiko.virtuozzo.com
To: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>,
	 svt-core@virtuozzo.com
Subject: Re: [PATCH QEMU HCI-8.1 v5 36/36] VZ: migration: don't wait for stop-copy-only device state #VSTOR-150595
Date: Fri, 23 Oct 2026 17:40:18 +0000	[thread overview]
Message-ID: <010701a169d96a76-8ca71f65-df46-4590-9bd3-7d5de3967465-000000@eu-central-1.amazonses.com> (raw)
In-Reply-To: <20261023-vfio_v1-v5-36-ba0bf3c6d122@virtuozzo.com>

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [Medium] vfio: vfio_state_pending_exact() ignores vfio_query_precopy_size() failure
- [Medium] migration: irreducible-state switchover bound exceeds downtime-limit and commit message
- [Medium] migration: irreducible_pending only learned after RAM estimate drops below plain threshold
- [Medium] migration: irreducible-data switchover overrides a pending migrate-start-postcopy request
- [Low] migration: irreducible size passed via file-static global in savevm.c
--

commit f62ee5bb362c0d23b60102c51ee61dedc887ca84
Author: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>

VZ: migration: don't wait for stop-copy-only device state #VSTOR-150595

This patch lets state_pending_exact handlers report pending data that only
moves once the guest is stopped (the VFIO stop-copy size). When that data
alone exceeds the threshold, migration_iteration_run() switches over once
the rest is within the threshold plus as much again.

> diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c
> --- a/hw/vfio/migration.c
> +++ b/hw/vfio/migration.c
> @@ -569,18 +569,25 @@ static void vfio_state_pending_exact(void *opaque, uint64_t *must_precopy,
>      VFIODevice *vbasedev = opaque;
>      VFIOMigration *migration = vbasedev->migration;
>      uint64_t stop_copy_size = VFIO_MIG_STOP_COPY_SIZE;
> +    int ret;
>  
>      /*
>       * If getting pending migration size fails, VFIO_MIG_STOP_COPY_SIZE is
>       * reported so downtime limit won't be violated.
>       */
> -    vfio_query_stop_copy_size(vbasedev, &stop_copy_size);
> +    ret = vfio_query_stop_copy_size(vbasedev, &stop_copy_size);
>      *must_precopy += stop_copy_size;
>  
>      if (vfio_device_state_is_precopy(vbasedev)) {
>          vfio_query_precopy_size(migration);
>      }
>  
> +    /* Once there's nothing left to pre-copy, iterating can't shrink it */
> +    if (!ret && !migration->precopy_init_size &&
> +        !migration->precopy_dirty_size) {
> +        qemu_savevm_state_pending_add_irreducible(stop_copy_size);
> +    }

[Severity: Medium]
Can a failed precopy query be treated as "nothing left to pre-copy" here?

The return value of vfio_query_precopy_size() is dropped.  That function
zeroes both sizes before the ioctl and returns -errno on failure:

    migration->precopy_init_size = 0;
    migration->precopy_dirty_size = 0;

    if (ioctl(migration->data_fd, VFIO_MIG_GET_PRECOPY_INFO, &precopy)) {
        return -errno;
    }

So if VFIO_MIG_GET_PRECOPY_INFO fails while the device is in PRE_COPY or
PRE_COPY_P2P, the new test "!ret && !migration->precopy_init_size &&
!migration->precopy_dirty_size" still passes, since ret only comes from
vfio_query_stop_copy_size().  The whole stop-copy size is then reported
through qemu_savevm_state_pending_add_irreducible(), even though pre-copy
data may remain that iterating would drain.

The existing code fails closed when the stop-copy size query fails, but this
path fails open.  Should the return value of vfio_query_precopy_size() be
captured, and irreducible data reported only when it succeeded (or when the
device is not in a pre-copy state)?

The same logic also seems to treat a transient dirty_bytes == 0 on a
precopy-capable device as irreducible.

> diff --git a/migration/migration.c b/migration/migration.c
> --- a/migration/migration.c
> +++ b/migration/migration.c

[ ... ]

> @@ -3576,8 +3577,10 @@ static MigIterateState migration_iteration_run(MigrationState *s)
>           * postcopy started, so ESTIMATE should always match with EXACT
>           * during postcopy phase.
>           */
> -        if (pending_size < s->threshold_size) {
> -            qemu_savevm_state_pending_exact(&must_precopy, &can_postcopy);
> +        /* Allow for what the estimate lacks, see the irreducible rule below */
> +        if (pending_size < s->threshold_size + 2 * s->irreducible_pending) {
> +            s->irreducible_pending =
> +                qemu_savevm_state_pending_exact(&must_precopy, &can_postcopy);

[Severity: Medium]
Is irreducible_pending only learned after the RAM estimate has dropped
below the plain threshold_size?

irreducible_pending is set to 0 in migrate_init(), so the gate above is
the old "pending_size < s->threshold_size" until an exact query has run.
The pending_size here comes from qemu_savevm_state_pending_estimate().
vfio_state_pending_estimate() returns early when the device is not in a
precopy state, and otherwise reports only:

    *must_precopy +=
        migration->precopy_init_size + migration->precopy_dirty_size;

It never includes the stop-copy size.  So the estimate is roughly the RAM
dirty estimate from ram_state_pending_estimate():

    uint64_t remaining_size = rs->migration_dirty_pages * TARGET_PAGE_SIZE;

If RAM dirtying keeps that at or above threshold_size, the exact query is
never made and irreducible_pending stays 0.  The relaxed completion check
is guarded by "s->irreducible_pending > s->threshold_size", so it is never
evaluated.

Would a guest whose RAM remainder sits between threshold and threshold plus
the irreducible size, which is the case the commit message targets, then
keep iterating as before until the estimate happens to dip below the
threshold?

>              pending_size = must_precopy + can_postcopy;
>              trace_migrate_pending_exact(pending_size, must_precopy,
>                                          can_postcopy);

[ ... ]

>          /* Should we switch to postcopy now? */
>          if (must_precopy <= s->threshold_size &&
>              can_switchover && qatomic_read(&s->start_postcopy)) {

[Severity: Medium]
Can the new override below discard a pending migrate-start-postcopy
request?

must_precopy includes the VFIO stop-copy size, so when that size exceeds
threshold_size, the postcopy gate above is never satisfied and
postcopy_start() is skipped.

> @@ -3601,6 +3604,16 @@ static MigIterateState migration_iteration_run(MigrationState *s)
>           *     (which was calculated from expected downtime)
>           */
>          complete_ready = can_switchover && (pending_size <= s->threshold_size);
> +
> +        /*
> +         * Data which only moves once the guest is stopped can't shrink by
> +         * iterating: if it alone exceeds the threshold, switch over once
> +         * the rest is within the threshold plus as much again.
> +         */
> +        if (s->irreducible_pending > s->threshold_size) {
> +            complete_ready = can_switchover &&
> +                pending_size <= s->threshold_size + 2 * s->irreducible_pending;
> +        }

Before the patch, pending_size <= threshold_size implied must_precopy <=
threshold_size, so a requested postcopy always took precedence over precopy
completion.  The new override does not look at s->start_postcopy.  Once it
becomes true, migration_completion() runs with s->state == ACTIVE and takes
the migration_completion_precopy() branch, stopping the VM and sending the
whole device state during downtime.

Should this override be skipped when start_postcopy is set (or postcopy is
enabled)?

[Severity: Medium]
Does this bound match the commit message and the comment?

The commit message says "switch over once the rest is within the threshold
plus as much again", and the comment says the same.  But pending_size
already includes the irreducible bytes, since vfio_state_pending_exact()
does "*must_precopy += stop_copy_size" and then also calls
qemu_savevm_state_pending_add_irreducible(stop_copy_size).  So the
condition

    pending_size <= s->threshold_size + 2 * s->irreducible_pending

is equivalent to "rest <= threshold + irreducible", not roughly twice the
threshold.  For a ~2 GiB vGPU, around 2 GiB plus the threshold of RAM and
other state may still be pending at switchover, so about 6 GiB in total.

This replaces the bandwidth x downtime-limit criterion from
migration_update_counters():

    s->threshold_size = expected_bw_per_ms * migrate_downtime_limit();

with one that scales with the device-reported size.  s->expected_downtime
is not updated, there is no capability, parameter or compat property, and
the downtime-limit documentation does not mention it.  Is that intended,
and can the wording be made to match the actual bound?

> diff --git a/migration/savevm.c b/migration/savevm.c
> --- a/migration/savevm.c
> +++ b/migration/savevm.c

[ ... ]

> +/* Exact pending data which only moves once the guest is stopped */
> +static uint64_t savevm_pending_irreducible;
> +
> +void qemu_savevm_state_pending_add_irreducible(uint64_t size)
> +{
> +    savevm_pending_irreducible += size;
> +}

[Severity: Low]
This isn't a bug, but the irreducible amount is passed from device handlers
to the migration core through a file-static global.

It is reset only inside qemu_savevm_state_pending_exact().  Nothing checks
that an exact query is in progress, so a call from any other context would
be wiped by the next query or leak into it.  The state_pending_exact
documentation in include/migration/register.h was not updated to describe
the new contract either, and the global is not tied to MigrationState.

Would it be cleaner to extend the handler interface, or at least document
that the function may only be called from within a state_pending_exact
handler?

[ ... ]

-- 
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261023-vfio_v1-v5-0-ba0bf3c6d122@virtuozzo.com?part=36

      reply	other threads:[~2026-10-23 17:40 UTC|newest]

Thread overview: 73+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-23 16:53 [PATCH QEMU HCI-8.1 v5 00/36] vfio: support qemu-update with passed through GPU's and vGPU's #VSTOR-103860 Andrey Drobyshev
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 01/36] VZ: migration/cpr-exec: fix Error leak in preserve_ram() Andrey Drobyshev
2026-10-23 16:58   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 02/36] migration/cpr-exec: restore RAM write access if exec fails Andrey Drobyshev
2026-10-23 16:58   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 03/36] vfio/region: create BAR dma-bufs with O_CLOEXEC Andrey Drobyshev
2026-10-23 17:00   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 04/36] migration/cpr-exec: require a file or exec migration URI Andrey Drobyshev
2026-10-23 17:00   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 05/36] migration: close the CPR state if the outgoing channel fails to open Andrey Drobyshev
2026-10-23 17:01   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 06/36] migration/cpr-exec: close the persisted state if the " Andrey Drobyshev
2026-10-23 17:01   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 07/36] migration: don't refuse a blocker over a migration of another mode Andrey Drobyshev
2026-10-23 17:03   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 08/36] migration: Plug memory leaks after migrate_set_error() Andrey Drobyshev
2026-10-23 17:02   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 09/36] hw/vfio: Fix liveness check in vfio_connect_kvm_msi_virq() Andrey Drobyshev
2026-10-23 17:04   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 10/36] vfio/pci: Reject invalid MSI-X Table and PBA BIR values Andrey Drobyshev
2026-10-23 17:03   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 11/36] vfio/pci: Fix information leak in vfio_rom_read() Andrey Drobyshev
2026-10-23 17:04   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 12/36] vfio/pci: Initialize rom_read_failed in vfio_pci_load_rom() Andrey Drobyshev
2026-10-23 17:05   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 13/36] vfio/pci: Grow buffer in vfio_pci_host_match() Andrey Drobyshev
2026-10-23 17:05   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 14/36] q35: Fix migration of SMRAM state Andrey Drobyshev
2026-10-23 17:07   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 15/36] migration: ensure APIC is loaded prior to VFIO PCI devices Andrey Drobyshev
2026-10-23 17:06   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 16/36] migration: Fix regression of passing error_fatal into vmstate_load_state() Andrey Drobyshev
2026-10-23 17:09   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 17/36] migration: vmstate_save_state_v: fix double error_setg Andrey Drobyshev
2026-10-23 17:11   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 18/36] migration: yank: Move register instance earlier Andrey Drobyshev
2026-10-23 17:13   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 19/36] migration: Free cpr-transfer MigrationAddress along with gsource Andrey Drobyshev
2026-10-23 17:12   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 20/36] migration: Move CPR HUP watch to cpr-transfer.c Andrey Drobyshev
2026-10-23 17:12   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 21/36] migration: Fix crash on second migration when cancel early Andrey Drobyshev
2026-10-23 17:17   ` no-reply
2026-10-23 16:53 ` [PATCH QEMU HCI-8.1 v5 22/36] kvm: tolerate ioctls after kvm_close() Andrey Drobyshev
2026-10-23 17:17   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 23/36] kvm: fix coalesced MMIO flush racing with kvm_close() Andrey Drobyshev
2026-10-23 17:19   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 24/36] migration/cpr: add cpr_is_in_progress() Andrey Drobyshev
2026-10-23 17:19   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 25/36] vfio/migration: don't migrate device state during CPR Andrey Drobyshev
2026-10-23 17:26   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 26/36] vfio/migration: don't assume the device is running on CPR incoming Andrey Drobyshev
2026-10-23 17:23   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 27/36] vfio/listener: skip dirty page tracking during CPR Andrey Drobyshev
2026-10-23 17:27   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 28/36] VZ: vfio/cpr: don't close KVM on cpr-exec Andrey Drobyshev
2026-10-23 17:29   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 29/36] VZ: migration/cpr-exec: abort cpr-exec if memory can't be preserved Andrey Drobyshev
2026-10-23 17:29   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 30/36] VZ: migration/cpr-exec: take the vhost-net devices back if exec fails Andrey Drobyshev
2026-10-23 17:31   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 31/36] VZ: migration/cpr-exec: don't exec if a vhost-net device can't be released Andrey Drobyshev
2026-10-23 17:30   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 32/36] VZ: vfio/region: preserve BAR mappings across cpr-exec #VSTOR-103860 Andrey Drobyshev
2026-10-23 17:36   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 33/36] VZ: migration/cpr-exec: allow cpr-exec with VFIO devices #VSTOR-103860 Andrey Drobyshev
2026-10-23 17:32   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 34/36] VZ: vfio/container: lift the CPR blocker for mdev " Andrey Drobyshev
2026-10-23 17:34   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 35/36] VZ: migration: keep the estimate and wait over starved windows #VSTOR-150595 Andrey Drobyshev
2026-10-23 17:38   ` no-reply
2026-10-23 16:54 ` [PATCH QEMU HCI-8.1 v5 36/36] VZ: migration: don't wait for stop-copy-only device state #VSTOR-150595 Andrey Drobyshev
2026-10-23 17:40   ` no-reply [this message]

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=010701a169d96a76-8ca71f65-df46-4590-9bd3-7d5de3967465-000000@eu-central-1.amazonses.com \
    --to=no-reply@sashiko.virtuozzo.com \
    --cc=andrey.drobyshev@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