From: no-reply@sashiko.virtuozzo.com
To: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>,
svt-core@virtuozzo.com
Cc: andrey.drobyshev@virtuozzo.com
Subject: Re: [PATCH QEMU HCI-8.1 v2 18/24] vfio/migration: don't migrate device state during CPR
Date: Tue, 13 Oct 2026 15:53:50 +0000 [thread overview]
Message-ID: <010701a135f85947-e6462840-260c-40f1-a397-427470d6640b-000000@eu-central-1.amazonses.com> (raw)
In-Reply-To: <20261013-vfio_v1-v2-18-433455c0a294@virtuozzo.com>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [Medium] vfio: migration save/load gated on mode parameter, not CPR in progress
- [Medium] vfio/migration: load_state not gated for CPR, unpatched source still hits live device
- [Medium] vfio/migration: switchover_ack_needed not gated for CPR, hangs migration
- [Medium] vfio/migration: stale multifd_transfer lets save thread stop device during CPR
--
commit 27c407560d6e12fc61d8fd9e47b3508c1eaa3fcb
Author: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
vfio/migration: don't migrate device state during CPR
This patch skips VFIO device state migration in the cpr-transfer and
cpr-exec modes. It adds a vfio_is_active() callback and an early return in
vfio_save_state(), both gated on cpr_incoming_needed(). It also makes the
VM state change handlers return early when cpr_is_in_progress().
> diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c
> --- a/hw/vfio/migration.c
> +++ b/hw/vfio/migration.c
[ ... ]
> @@ -674,6 +675,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_incoming_needed(NULL)) {
> + qemu_put_be64(f, VFIO_MIG_FLAG_END_OF_STATE);
> + return;
> + }
> +
[Severity: Medium]
cpr_incoming_needed() only tests migrate_mode(), that is, the configured
mode parameter, and not whether a CPR operation is running.
If the mode parameter is left at cpr-transfer or cpr-exec (for example
after an earlier or failed CPR attempt) and a non-CPR save such as
snapshot-save runs, what happens?
save_snapshot()
vm_stop(RUN_STATE_SAVE_VM)
qemu_savevm_state()
vfio_save_state()
cpr_incoming_needed(NULL) is true -> only END_OF_STATE is written
In that case vfio_vmstate_change() is gated on cpr_is_in_progress(),
which requires migration_is_running() on the source, and that is false
for savevm. The device is therefore still moved to STOP, but no state is
written, so a later load restores nothing.
The commit message says the stop/cont hook uses cpr_is_in_progress()
because "the mode alone would also skip a plain stop/cont of a VM which
merely has it set". Does the same reasoning apply to vfio_save_state()
and vfio_is_active()? Should they use the same predicate as the
vmstate handlers?
[ ... ]
> @@ -824,7 +835,19 @@ static int vfio_switchover_start(void *opaque)
> return 0;
> }
>
> +static bool vfio_is_active(void *opaque)
> +{
> + return !cpr_incoming_needed(NULL);
> +}
> +
> static const SaveVMHandlers savevm_vfio_handlers = {
> + .is_active = vfio_is_active,
> .save_prepare = vfio_save_prepare,
> .save_setup = vfio_save_setup,
> .save_cleanup = vfio_save_cleanup,
[Severity: Medium]
This isn't limited to the case above: vfio_is_active() also returns false
on the mode parameter alone, so all VFIO save handlers are disabled
whenever the mode is cpr-transfer or cpr-exec, even with no CPR handover
running.
Separately, is the load side covered? .is_active only suppresses setup,
save and pending-estimate handling, while .load_state is still called on
the destination for any section the source sends.
If the source is a QEMU without this patch, vfio_load_state() would still
see these sections:
vfio_load_state()
case VFIO_MIG_FLAG_DEV_CONFIG_STATE:
return vfio_load_device_config_state(f, opaque);
That would apply the config to the preserved device and re-program MSI-X,
which is the failure the commit message describes. A DATA_STATE section
would reach vfio_load_buffer()->qemu_file_get_to_fd() with data_fd still
-1, because vfio_load_setup() is skipped, and the incoming migration
would fail.
Is a version requirement on the source intended here, and should
vfio_load_state() have its own CPR check?
[Severity: Medium]
Can this hang a CPR migration when switchover-ack is enabled?
vfio_switchover_ack_needed() still returns vfio_precopy_supported() and
is not gated by is_active. On the destination,
qemu_loadvm_state_switchover_ack_needed() does:
if (se->ops->switchover_ack_needed(se->opaque)) {
mis->switchover_ack_pending_num++;
}
without consulting is_active, so the VFIO device is counted as awaiting
an ACK. The fallback ACK on MIG_CMD_OPEN_RETURN_PATH then does not fire.
On the source, vfio_is_active() now returns false, so vfio_save_iterate()
is never called. That is the only place this is emitted:
qemu_put_be64(f, VFIO_MIG_FLAG_DEV_INIT_DATA_SENT);
The destination therefore never calls qemu_loadvm_approve_switchover().
migration_can_switchover() then keeps returning s->switchover_acked
(false) while the VM is running:
if (!runstate_is_running()) {
return true;
}
return s->switchover_acked;
migrate_caps_check() only requires return-path for switchover-ack and
does not reject it in CPR modes. Should vfio_switchover_ack_needed() also
return false in CPR mode, or should the capability be rejected there?
[ ... ]
> @@ -857,6 +880,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 +910,10 @@ static void vfio_vmstate_change(void *opaque, bool running, RunState state)
> Error *local_err = NULL;
> int ret;
>
> + if (cpr_is_in_progress()) {
> + return;
> + }
> +
[Severity: Medium]
Can the multifd save thread still move the preserved device to STOP_COPY
during CPR?
qemu_savevm_state_complete_precopy_iterable() spawns
save_complete_precopy_thread for every handler that has one, without
checking .is_active. The thread's only guard is
vfio_multifd_transfer_enabled():
hw/vfio/migration-multifd.c:vfio_multifd_save_complete_precopy_thread() {
if (!vfio_multifd_transfer_enabled(vbasedev)) {
/* Nothing to do, vfio_save_complete_precopy() does the transfer. */
return true;
}
...
if (vfio_migration_set_state(vbasedev, VFIO_DEVICE_STATE_STOP_COPY,
VFIO_DEVICE_STATE_STOP, errp)) {
migration->multifd_transfer is written only in vfio_multifd_setup(), and
vfio_multifd_cleanup() does not reset it. With this patch
vfio_save_setup() is skipped in CPR modes, so the flag is no longer
refreshed.
If an earlier non-CPR migration attempt ran vfio_save_setup() with
multifd transfer enabled and then failed or was cancelled, and a later
cpr-transfer or cpr-exec is run in the same process, would the flag still
be true and the thread stop the preserved device and stream its state?
The same flag also gates vfio_switchover_start() without an is_active
check, though that is a destination-side hook in a fresh process and is
less exposed.
--
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261013-vfio_v1-v2-0-433455c0a294@virtuozzo.com?part=18
next prev parent reply other threads:[~2026-10-13 15:53 UTC|newest]
Thread overview: 49+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-13 15:28 [PATCH QEMU HCI-8.1 v2 00/24] vfio: support qemu-update with passed through GPU's and vGPU's #VSTOR-103860 Andrey Drobyshev
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 01/24] migration: Plug memory leaks after migrate_set_error() Andrey Drobyshev
2026-10-13 15:30 ` no-reply
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 02/24] hw/vfio: Fix liveness check in vfio_connect_kvm_msi_virq() Andrey Drobyshev
2026-10-13 15:30 ` no-reply
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 03/24] vfio/pci: Reject invalid MSI-X Table and PBA BIR values Andrey Drobyshev
2026-10-13 15:31 ` no-reply
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 04/24] vfio/pci: Fix information leak in vfio_rom_read() Andrey Drobyshev
2026-10-13 15:31 ` no-reply
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 05/24] vfio/pci: Initialize rom_read_failed in vfio_pci_load_rom() Andrey Drobyshev
2026-10-13 15:33 ` no-reply
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 06/24] vfio/pci: Grow buffer in vfio_pci_host_match() Andrey Drobyshev
2026-10-13 15:32 ` no-reply
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 07/24] q35: Fix migration of SMRAM state Andrey Drobyshev
2026-10-13 15:35 ` no-reply
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 08/24] migration: ensure APIC is loaded prior to VFIO PCI devices Andrey Drobyshev
2026-10-13 15:33 ` no-reply
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 09/24] migration: Fix regression of passing error_fatal into vmstate_load_state() Andrey Drobyshev
2026-10-13 15:36 ` no-reply
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 10/24] migration: vmstate_save_state_v: fix double error_setg Andrey Drobyshev
2026-10-13 15:38 ` no-reply
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 11/24] migration: yank: Move register instance earlier Andrey Drobyshev
2026-10-13 15:41 ` no-reply
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 12/24] migration: Free cpr-transfer MigrationAddress along with gsource Andrey Drobyshev
2026-10-13 15:39 ` no-reply
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 13/24] migration: Move CPR HUP watch to cpr-transfer.c Andrey Drobyshev
2026-10-13 15:40 ` no-reply
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 14/24] migration: Fix crash on second migration when cancel early Andrey Drobyshev
2026-10-13 15:45 ` no-reply
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 15/24] kvm: tolerate ioctls after kvm_close() Andrey Drobyshev
2026-10-13 15:44 ` no-reply
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 16/24] kvm: fix coalesced MMIO flush racing with kvm_close() Andrey Drobyshev
2026-10-13 15:47 ` no-reply
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 17/24] migration/cpr: add cpr_is_in_progress() Andrey Drobyshev
2026-10-13 15:47 ` no-reply
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 18/24] vfio/migration: don't migrate device state during CPR Andrey Drobyshev
2026-10-13 15:53 ` no-reply [this message]
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 19/24] vfio/listener: skip dirty page tracking " Andrey Drobyshev
2026-10-13 15:50 ` no-reply
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 20/24] VZ: vfio/cpr: don't close KVM on cpr-exec Andrey Drobyshev
2026-10-13 15:53 ` no-reply
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 21/24] VZ: migration/cpr-exec: abort cpr-exec if memory can't be preserved Andrey Drobyshev
2026-10-13 15:55 ` no-reply
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 22/24] VZ: migration/cpr-exec: take the vhost-net devices back if exec fails Andrey Drobyshev
2026-10-13 15:55 ` no-reply
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 23/24] VZ: vfio/region: preserve BAR mappings across cpr-exec #VSTOR-103860 Andrey Drobyshev
2026-10-13 16:00 ` no-reply
2026-10-13 15:28 ` [PATCH QEMU HCI-8.1 v2 24/24] VZ: migration/cpr-exec: allow cpr-exec with VFIO devices #VSTOR-103860 Andrey Drobyshev
2026-10-13 15:57 ` 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=010701a135f85947-e6462840-260c-40f1-a397-427470d6640b-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