Virtuozzo QEMU development (svt-core@virtuozzo.com)
 help / color / mirror / Atom feed
From: no-reply@sashiko.virtuozzo.com
To: svt-core@virtuozzo.com,
	 Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
Subject: Re: [PATCH QEMU HCI-8.1 v5 25/36] vfio/migration: don't migrate device state during CPR
Date: Fri, 23 Oct 2026 17:26:42 +0000	[thread overview]
Message-ID: <010701a169ccf478-07c899c0-1d21-4c38-8528-4db80d6786ef-000000@eu-central-1.amazonses.com> (raw)
In-Reply-To: <20261023-vfio_v1-v5-25-ba0bf3c6d122@virtuozzo.com>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] vfio/migration: cpr_is_in_progress() is false for cpr-transfer source after HUP, so the gating is bypassed
- [Medium] vfio/cpr: cpr_is_in_progress() is false on the cpr-transfer source during stream
- [Medium] vfio/migration: vfio_load_state() lacks a CPR guard, so a non-empty stream re-programs MSI-X
--

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

vfio/migration: don't migrate device state during CPR

This patch makes the VFIO migration handlers do nothing while a CPR
migration (cpr-transfer or cpr-exec) is in progress. It gates the save,
load and VM stop/start paths on cpr_is_in_progress(). It also resets
multifd_transfer in vfio_multifd_cleanup().

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

[ ... ]

> @@ -674,6 +674,16 @@ static void vfio_save_state(QEMUFile *f, void *opaque)
>      Error *local_err = NULL;
>      int ret;
>  
> +    /*
> +     * .is_active doesn't cover the non-iterable stage, so the section is
> +     * still sent: leave it empty, or new QEMU would load the config into
> +     * the preserved device and re-program its MSI-X.
> +     */
> +    if (cpr_is_in_progress()) {
> +        qemu_put_be64(f, VFIO_MIG_FLAG_END_OF_STATE);
> +        return;
> +    }
> +

[Severity: High]
Is cpr_is_in_progress() still true on the cpr-transfer source when this
runs?

On the source the predicate reduces to cpr_state_file != NULL:

migration/cpr.c:cpr_is_in_progress() {
    ...
    return cpr_state_file != NULL;
}

For cpr-transfer, qmp_migrate() calls cpr_state_save() and only arms
cpr_transfer_add_hup_watch().  When the target closes the CPR socket:

qmp_migrate_finish_cb()
    qmp_migrate_finish(addr, NULL);   /* only starts an async connect */
    cpr_state_close();                /* cpr_state_file = NULL */

The migration thread (vm_stop, the vmstate change notifiers,
qemu_savevm_state_setup(), vfio_save_state(), save_complete) runs only
after the connect completes.  By then cpr_is_in_progress() returns false
on the source.

Would that make vfio_is_active(), vfio_save_state(),
vfio_switchover_ack_needed(), vfio_vmstate_change_prepare() and
vfio_vmstate_change() all take the normal migration path on a cpr-transfer
source?  The old QEMU would then stop the live device and save its config
and state.

The target has cpr_is_incoming() true, so it skips load_setup but still
parses the stream.  That looks like the vGPU breakage this patch is meant
to fix, together with a source/target mismatch.

The comment in cpr_is_in_progress() says "An outgoing CPR migration has
the CPR state open, from cpr_state_save() to cpr_state_close()", and the
commit message relies on this.  Does that hold for cpr-transfer?

cpr-exec looks fine, since qmp_migrate_finish() is called directly there
and cpr_state_close() runs only on error or in migration_cleanup().

Nothing later in the series appears to change cpr_is_in_progress(),
cpr_state_save(), cpr_state_close() or qmp_migrate_finish_cb().  The later
patch "VZ: vfio/region: preserve BAR mappings across cpr-exec" adds an
mmap_blocker in vfio_device_attach() that blocks cpr-transfer for VFIO
devices.  That makes the path unreachable at series end, but it doesn't
change the predicate.

[Severity: High]
Is the source-side predicate also an unlatched sample of mutable globals?

qmp_migrate_set_parameters() does not reject changing "mode" while a
migration is running.  Could migrate_mode(), which cpr_is_in_progress()
reads, change between the VM stop and the later vm start or
vfio_save_state() call?  The gates in vfio_vmstate_change_prepare(),
vfio_vmstate_change() and vfio_save_state() would then disagree with each
other.

[ ... ]

> @@ -810,6 +820,11 @@ static bool vfio_switchover_ack_needed(void *opaque)
>  {
>      VFIODevice *vbasedev = opaque;
>  
> +    /* No device state is sent during CPR, so no ACK to wait for */
> +    if (cpr_is_in_progress()) {
> +        return false;
> +    }
> +
>      return vfio_precopy_supported(vbasedev);
>  }

[ ... ]

> +static bool vfio_is_active(void *opaque)
> +{
> +    return !cpr_is_in_progress();
> +}
> +
>  static const SaveVMHandlers savevm_vfio_handlers = {
> +    .is_active = vfio_is_active,
>      .save_prepare = vfio_save_prepare,

[Severity: Medium]
Should vfio_load_state() have a matching cpr_is_in_progress() guard?

The patch gates only the save side and load_setup (through is_active).
vfio_load_state() has no check:

hw/vfio/migration.c:vfio_load_state() {
    ...
    case VFIO_MIG_FLAG_DEV_CONFIG_STATE:
        ...
        return vfio_load_device_config_state(f, opaque);
}

Nothing in the loadvm section path consults is_active before calling
load_state.  If the target receives a non-empty VFIO section during CPR,
it reaches vfio_pci_load_config() on the preserved device even though
vfio_load_setup() never ran.  That would re-program MSI-X and disable
vector 0.

A DEV_DATA_STATE section would reach vfio_load_buffer() with data_fd == -1
and fail with EBADF, aborting the migration.

A non-empty section is reachable when the source predicate returns false,
as described above for the cpr-transfer source.  The later patch "vfio/migration: don't assume
the device is running on CPR incoming" only adds cpr_is_incoming()
handling in vfio_vmstate_change() and migration init, and adds no
load-side guard.

[ ... ]

> @@ -857,6 +884,11 @@ static void vfio_vmstate_change_prepare(void *opaque, bool running,
>      Error *local_err = NULL;
>      int ret;
>  
> +    /* The device is preserved, not a plain stop/cont: keep its state */
> +    if (cpr_is_in_progress()) {
> +        return;
> +    }
> +

[ ... ]

> @@ -882,6 +914,10 @@ static void vfio_vmstate_change(void *opaque, bool running, RunState state)
>      Error *local_err = NULL;
>      int ret;
>  
> +    if (cpr_is_in_progress()) {
> +        return;
> +    }
> +

The same cpr_is_in_progress() question applies to both of these gates on
the cpr-transfer source, since cpr_state_close() has already cleared
cpr_state_file when the VM is stopped.

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

  reply	other threads:[~2026-10-23 17:26 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 [this message]
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

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=010701a169ccf478-07c899c0-1d21-4c38-8528-4db80d6786ef-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