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 v6 25/34] vfio/migration: don't migrate device state during CPR
Date: Mon, 2 Nov 2026 11:07:27 +0000	[thread overview]
Message-ID: <010701a19bf1590f-117044d8-f3c5-4aaa-a837-e73551d5f65c-000000@eu-central-1.amazonses.com> (raw)
In-Reply-To: <20261102-vfio_v1-v6-25-9bc7cabc850d@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 on cpr-transfer source
- [High] migration: cpr_is_in_progress() is false on the cpr-transfer source
- [Medium] vfio/migration: stop/cont ignored for whole CPR outgoing window, not just the handover
--

Commit 54a8e2428cc329d383d08292ed034898e8bf828e
Author: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>

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

This patch gates the VFIO migration handlers on cpr_is_in_progress(). With
the gates in place, device state is neither saved nor loaded during
cpr-transfer or cpr-exec, and the device state is not changed on VM
stop/start. 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 here on a cpr-transfer source?

On the source it returns cpr_state_file != NULL:

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

For cpr-transfer, qmp_migrate() only registers a HUP watch:

qmp_migrate()
    cpr_transfer_add_hup_watch(s, qmp_migrate_finish_cb, addr)

When the target closes the CPR socket, the callback runs:

qmp_migrate_finish_cb()
    qmp_migrate_finish(addr, NULL);
    cpr_state_close();

qmp_migrate_finish() ends up in socket_start_outgoing_migration(), which
only starts qio_channel_socket_connect_async(). The completion
(socket_outgoing_migration() -> migration_channel_connect()), the migration
thread, qemu_savevm_state_setup(), vm_stop() and vfio_save_state() all run
after the callback has returned, with cpr_state_file already NULL.

If so, cpr_is_in_progress() is false for the whole data migration on a
cpr-transfer source, and the gates in vfio_save_state(),
vfio_switchover_ack_needed(), vfio_vmstate_change_prepare() and
vfio_vmstate_change() are all bypassed. Wouldn't the device then still be
stopped and put into PRE_COPY or STOP_COPY, and its config and data state
still be sent, which is the failure the commit message describes for the
NVIDIA vGPU?

The same question applies to the source-side comment in
cpr_is_in_progress(), which says the state is open "from cpr_state_save()
to cpr_state_close()". For cpr-transfer that window ends before the data
migration starts, whereas for cpr-exec cpr_state_close() runs in
migration_cleanup() after qemu_savevm_state_cleanup().

I did not find a later patch in the series that changes cpr_is_in_progress()
or the cpr_state_close() call sites.

[ ... ]

> +/*
> + * cpr-transfer and cpr-exec hand the running device over to the new QEMU
> + * as is: its fds, mappings and interrupts are preserved and it never stops.
> + * Device state migration must stay out of it, else the device is stopped,
> + * its state saved and then resumed into the very same device.
> + */
> +static bool vfio_is_active(void *opaque)
> +{
> +    return !cpr_is_in_progress();
> +}
> +

[Severity: High]
On a cpr-transfer source, wouldn't vfio_is_active() return true here, given
that cpr_state_file has already been cleared by qmp_migrate_finish_cb()?

In that case save_setup, iterate and complete would all still run for the
device.

On the target, cpr_is_in_progress() is true because the incoming mode is
set, so load_setup is skipped. vfio_load_state() has no CPR gate:

hw/vfio/migration.c:vfio_load_state() {
    ...
    data = qemu_get_be64(f);
    while (data != VFIO_MIG_FLAG_END_OF_STATE) {
    ...
}

Could real DEV_CONFIG_STATE or DEV_DATA_STATE sent by the source then be
loaded into the preserved live device? That would re-program MSI-X, or
write to a data_fd that was never opened. The two sides would also disagree
about whether device state is migrated.

[ ... ]

> @@ -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;
> +    }
> +

[Severity: Medium]
Can this gate skip a user-issued stop or cont while a CPR migration has been
started but the VM has not yet been stopped for handover?

On the source, cpr_state_save() sets cpr_state_file from qmp_migrate(),
before the migration thread starts. For cpr-transfer, the source then
returns to the main loop and waits for the target's HUP, with
cpr_state_file open the whole time:

qmp_migrate()
    cpr_state_save()
    cpr_transfer_add_hup_watch(s, qmp_migrate_finish_cb, addr)

During that window, a QMP stop or cont reaches vfio_vmstate_change_prepare()
and vfio_vmstate_change(), and both return early on cpr_is_in_progress().

The commit message says that a plain stop/cont must still change the device
state when the mode is merely set. Does that hold once CPR migration has
started but has not yet stopped the VM? A stopped guest could keep a
running, DMA-capable device, and migration->device_state would not be
updated.

The final-state series still has the source-side early return in
vfio_vmstate_change().

> @@ -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;
> +    }
> +

[Severity: High]
Is this gate effective on a cpr-transfer source?

With cpr_state_file already cleared in qmp_migrate_finish_cb(), the early
return would not be taken when the migration thread calls vm_stop(). The
device would then still be moved to STOP or STOP_COPY, and the same applies
to vfio_save_state(), vfio_is_active() and vfio_vmstate_change_prepare().

In contrast, cpr-exec appears to work, because cpr_state_close() is called
from migration_cleanup() after qemu_savevm_state_cleanup():

migration/migration.c:migration_cleanup() {
    ...
    qemu_savevm_state_cleanup();
    cpr_state_close();
}

Should the early cpr_state_close() in qmp_migrate_finish_cb() be reconsidered,
or the predicate changed, so that cpr_is_in_progress() holds for the data
migration in cpr-transfer as well? The close in qmp_migrate_finish_cb()
seems to be the defect, rather than any mismatch between stop and start
values.

-- 
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261102-vfio_v1-v6-0-9bc7cabc850d@virtuozzo.com?part=25

  reply	other threads:[~2026-11-02 11:07 UTC|newest]

Thread overview: 70+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-02 10:36 [PATCH QEMU HCI-8.1 v6 00/34] vfio: support qemu-update with passed through GPU's and vGPU's #VSTOR-103860 Andrey Drobyshev
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 01/34] VZ: migration/cpr-exec: fix Error leak in preserve_ram() Andrey Drobyshev
2026-11-02 10:39   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 02/34] migration/cpr-exec: restore RAM write access if exec fails Andrey Drobyshev
2026-11-02 10:40   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 03/34] vfio/region: create BAR dma-bufs with O_CLOEXEC Andrey Drobyshev
2026-11-02 10:40   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 04/34] migration/cpr-exec: require a file or exec migration URI Andrey Drobyshev
2026-11-02 10:42   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 05/34] migration: close the CPR state if the outgoing channel fails to open Andrey Drobyshev
2026-11-02 10:42   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 06/34] migration/cpr-exec: close the persisted state if the " Andrey Drobyshev
2026-11-02 10:44   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 07/34] migration: don't refuse a blocker over a migration of another mode Andrey Drobyshev
2026-11-02 10:44   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 08/34] migration: Plug memory leaks after migrate_set_error() Andrey Drobyshev
2026-11-02 10:44   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 09/34] hw/vfio: Fix liveness check in vfio_connect_kvm_msi_virq() Andrey Drobyshev
2026-11-02 10:45   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 10/34] vfio/pci: Reject invalid MSI-X Table and PBA BIR values Andrey Drobyshev
2026-11-02 10:45   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 11/34] vfio/pci: Fix information leak in vfio_rom_read() Andrey Drobyshev
2026-11-02 10:45   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 12/34] vfio/pci: Initialize rom_read_failed in vfio_pci_load_rom() Andrey Drobyshev
2026-11-02 10:46   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 13/34] vfio/pci: Grow buffer in vfio_pci_host_match() Andrey Drobyshev
2026-11-02 10:46   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 14/34] q35: Fix migration of SMRAM state Andrey Drobyshev
2026-11-02 10:48   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 15/34] migration: ensure APIC is loaded prior to VFIO PCI devices Andrey Drobyshev
2026-11-02 10:47   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 16/34] migration: Fix regression of passing error_fatal into vmstate_load_state() Andrey Drobyshev
2026-11-02 10:51   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 17/34] migration: vmstate_save_state_v: fix double error_setg Andrey Drobyshev
2026-11-02 10:51   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 18/34] migration: yank: Move register instance earlier Andrey Drobyshev
2026-11-02 10:55   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 19/34] migration: Free cpr-transfer MigrationAddress along with gsource Andrey Drobyshev
2026-11-02 10:53   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 20/34] migration: Move CPR HUP watch to cpr-transfer.c Andrey Drobyshev
2026-11-02 10:54   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 21/34] migration: Fix crash on second migration when cancel early Andrey Drobyshev
2026-11-02 10:57   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 22/34] kvm: tolerate ioctls after kvm_close() Andrey Drobyshev
2026-11-02 11:01   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 23/34] kvm: fix coalesced MMIO flush racing with kvm_close() Andrey Drobyshev
2026-11-02 11:00   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 24/34] migration/cpr: add cpr_is_in_progress() Andrey Drobyshev
2026-11-02 11:01   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 25/34] vfio/migration: don't migrate device state during CPR Andrey Drobyshev
2026-11-02 11:07   ` no-reply [this message]
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 26/34] vfio/migration: don't assume the device is running on CPR incoming Andrey Drobyshev
2026-11-02 11:06   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 27/34] migration/ram: don't start dirty logging in CPR modes Andrey Drobyshev
2026-11-02 11:07   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 28/34] VZ: vfio/cpr: don't close KVM on cpr-exec Andrey Drobyshev
2026-11-02 11:09   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 29/34] VZ: migration/cpr-exec: abort cpr-exec if memory can't be preserved Andrey Drobyshev
2026-11-02 11:09   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 30/34] VZ: migration/cpr-exec: take the vhost-net devices back if exec fails Andrey Drobyshev
2026-11-02 11:11   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 31/34] VZ: migration/cpr-exec: don't exec if a vhost-net device can't be released Andrey Drobyshev
2026-11-02 11:10   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 32/34] VZ: vfio/region: preserve BAR mappings across cpr-exec #VSTOR-103860 Andrey Drobyshev
2026-11-02 11:16   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 33/34] VZ: migration/cpr-exec: allow cpr-exec with VFIO devices #VSTOR-103860 Andrey Drobyshev
2026-11-02 11:12   ` no-reply
2026-11-02 10:36 ` [PATCH QEMU HCI-8.1 v6 34/34] VZ: vfio/migration: don't wait for stop-copy-only device state #VSTOR-141821 Andrey Drobyshev
2026-11-02 11:15   ` no-reply
  -- strict thread matches above, loose matches on Subject: below --
2026-10-30 14:45 [PATCH QEMU HCI-8.1 v6 00/34] vfio: support qemu-update with passed through GPU's and vGPU's #VSTOR-103860 Andrey Drobyshev
2026-10-30 14:45 ` [PATCH QEMU HCI-8.1 v6 25/34] vfio/migration: don't migrate device state during CPR 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=010701a19bf1590f-117044d8-f3c5-4aaa-a837-e73551d5f65c-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