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
Cc: andrey.drobyshev@virtuozzo.com
Subject: Re: [PATCH QEMU HCI-8.1 v7 33/35] VZ: vfio/region: preserve BAR mappings across cpr-exec #VSTOR-103860
Date: Tue, 3 Nov 2026 14:38:03 +0000	[thread overview]
Message-ID: <010701a1a1d88344-56f27a4c-ab30-4a82-8740-c48017502bb1-000000@eu-central-1.amazonses.com> (raw)
In-Reply-To: <20261103-vfio_v1-v7-33-4467fdccbbe6@virtuozzo.com>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [Medium] vfio: cpr-transfer blocked for every VFIO device, not only those with saved BAR mmaps
- [Medium] vfio: cpr-transfer blocker skipped for vfio-user, stale BAR mappings reused
- [Low] vfio/region: BAR mappings enter CPR ramblock list walked by cpr-ram-rdonly mprotect
- [Low] vfio: unclaimed BAR mappings preserved by cpr-exec are never cleaned up
--

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

VZ: vfio/region: preserve BAR mappings across cpr-exec #VSTOR-103860

This patch saves each VFIO BAR mapping in the CPR ramblock list so that
cpr-exec preserves it with MADV_DOEXEC, and the new QEMU reuses it instead
of calling mmap() again. It also blocks cpr-transfer for all VFIO devices
and updates CPR.rst to say so.

> diff --git a/docs/devel/migration/CPR.rst b/docs/devel/migration/CPR.rst
> --- a/docs/devel/migration/CPR.rst
> +++ b/docs/devel/migration/CPR.rst

[ ... ]

> -RAM in place, albeit with new virtual addresses in new QEMU.  Devices
> -and their pinned memory pages are also preserved for VFIO and IOMMUFD.
> +RAM in place, albeit with new virtual addresses in new QEMU.  VFIO and
> +IOMMUFD devices are not supported in this mode: use cpr-exec for them.

This documents the new policy, but only this paragraph was changed. Are
the other cpr-transfer and VFIO descriptions in CPR.rst still accurate?

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

[ ... ]

> @@ -464,12 +464,32 @@ bool vfio_device_attach(char *name, VFIODevice *vbasedev,
> +    error_setg(&vbasedev->cpr.mmap_blocker,
> +               "cpr-transfer is not supported with VFIO devices; "
> +               "use the cpr-exec mode");
> +    if (migrate_add_blocker_modes(&vbasedev->cpr.mmap_blocker, errp,
> +                                  MIG_MODE_CPR_TRANSFER, -1)) {
> +        return false;
> +    }

[Severity: Medium]
Is it intended that this blocker is installed in vfio_device_attach() for
every VFIO device?

The blocker is added before any backend-specific work and without checking
device type, no_mmap, or whether any region will ever be saved through
vfio_region_cpr_save(). Devices such as vfio-ap, vfio-ccw, x-no-mmap
devices, devices with no mmap-able BARs, and PCI devices whose drivers
allow re-mapping would also lose cpr-transfer.

The commit message gives the NVIDIA vGPU re-map restriction as the
rationale. Would it be narrower to block only when
vfio_region_cpr_save() actually saves a mapping, or only on the PCI path?

The series does not appear to narrow this blocker later. The final state
still has the same unconditional mmap_blocker in vfio_device_attach().

Also, the cpr-transfer specific VFIO code now looks unreachable for
cpr-transfer, but it is left in place: the id_blocker with
MIG_MODE_CPR_TRANSFER in device.c, the blockers in cpr-legacy.c and
cpr-iommufd.c, and the ones in cpr.c. Should that code be cleaned up?

[Severity: Medium]
Does this blocker cover vfio-user devices? vfio_user_pci_realize() in
hw/vfio-user/pci.c calls vfio_device_attach_by_iommu_type() directly:

    if (!vfio_device_attach_by_iommu_type(TYPE_VFIO_IOMMU_USER,
                                          vbasedev->name, vbasedev,
                                          as, errp)) {

That bypasses vfio_device_attach(), so vbasedev->cpr.mmap_blocker is never
installed for vfio-user. hw/vfio-user/ has no other CPR blocker.

vfio-user regions can be mmapped through server-supplied region fds, and
vfio_bar_register() in hw/vfio/pci.c calls vfio_region_mmap(). That now
reaches vfio_region_cpr_save(), which puts the mapping in
cpr_state.ramblocks. That list is serialized for both cpr-exec and
cpr-transfer.

On a cpr-transfer target, vfio_region_cpr_find() looks up
"<vbasedev->name> region N mmaps[i]". For vfio-user, vbasedev->name is
"vfio-user:<sock>", so the name matches the saved entry.

> +static void *vfio_region_cpr_find(VFIORegion *region, int index)
> +{
> +    g_autofree char *name = vfio_region_cpr_name(region, index);
> +    cpr_ramblock_t ram = cpr_find_ramblock(name);
> +
> +    if (ram.addr && ram.length != region->mmaps[index].size) {
[ ... ]
> +    return (void *)(uintptr_t)ram.addr;
> +}

Nothing checks that the incoming mode is cpr-exec here. Can a cpr-transfer
target take the old process's address from this function and pass it to
memory_region_init_ram_device_ptr() in vfio_region_mmap() as if it were a
local mapping? If so, the first guest access to that BAR would touch an
invalid or unrelated address.

Should vfio_region_cpr_find() be gated on cpr_exec_is_incoming(), or should
the vfio-user attach path also install the blocker?

> +static void vfio_region_cpr_save(VFIORegion *region, int index)
> +{
[ ... ]
> +    cpr_save_ramblock(name, (cpr_ramblock_t) { (uintptr_t)addr, size });
> +}

[Severity: Low]
Is it intended that BAR mappings, including read-only ones, now go into the
same ramblock list that cpr_exec_cb() walks for the -cpr-ram-rdonly debug
option?

With that option set, cpr_exec_cb() calls
cpr_walk_ramblock(mark_ram_rdonly), and mark_ram_rw() later calls
qemu_mprotect_rw() on each entry and abort()s on failure:

    if (qemu_mprotect_rw((void *) ram.addr, ram.length)) {
        error_report("qemu_mprotect_rw() failed on memory region %s:"
        ...
        abort();

A BAR that vfio_region_mmap() mapped read-only (no
VFIO_REGION_INFO_FLAG_WRITE) would be turned into PROT_READ|PROT_WRITE by
cpr_ram_restore_rw(). If a driver rejects mprotect on these device PFN
mappings, QEMU would abort.

I did not confirm that any driver refuses mprotect. Should these entries be
excluded from the mprotect walks?

[Severity: Low]
Can a preserved BAR mapping that new QEMU never claims be left behind?

The only place a saved mapping is claimed is vfio_region_mmap():

    region->mmaps[i].mmap = vfio_region_cpr_find(region, i);
    if (region->mmaps[i].mmap) {
        goto mapped;
    }

The only cleanup is cpr_delete_ramblock() in vfio_subregion_unmap() and
vfio_region_finalize(), and both run only for regions that were set up on
the new side. If new QEMU never reaches vfio_region_mmap() for a region
(for example a different x-no-mmap setting, a changed region layout, or a
failed realize), the mapping stays mapped with its MADV_DOEXEC mark and its
cpr_state.ramblocks entry.

A later cpr-exec would then apply MADV_DOEXEC to it again through
cpr_walk_ramblock(preserve_ram). Because it is never unmapped, a driver
such as the NVIDIA vGPU driver would still see the BAR as mapped.

Is there a sweep of unclaimed region entries planned? None of the later
patches in the series appear to add one.

-- 
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261103-vfio_v1-v7-0-4467fdccbbe6@virtuozzo.com?part=33

  reply	other threads:[~2026-11-03 14:38 UTC|newest]

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

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=010701a1a1d88344-56f27a4c-ab30-4a82-8740-c48017502bb1-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