Re: [PATCH v6 07/27] vfio/pci: Preserve vfio-pci device files across Live Update
From: Samiullah Khawaja
Date: Fri Nov 06 2026 - 17:36:00 EST
On Mon, Nov 02, 2026 at 07:36:36AM -0800, Vipin Sharma wrote:
Implement the Live Update file handler callbacks to preserve a vfio-pci
device in noiommu mode across a Live Update while keeping it running
across kexec. Subsequent commits will enable userspace to retrieve and
take over this file after the Live Update.
State about each device is serialized into struct vfio_pci_core_device_ser
using Kexec-Handover (KHO) to preserve the pages holding the struct and
the Live Update Orchestrator (LUO) to preserve the physical address of
the struct.
Key design notes and constraints:
* Noiommu-only policy and bound cdev requirement: can_preserve() verifies
that the preserved file is a bound vfio-pci cdev file descriptor via
vfio_file_is_bound_cdev(), and preserve() requires the device to be in
noiommu mode via vfio_device_is_noiommu() (returning -EOPNOTSUPP
otherwise). CONFIG_VFIO_PCI_LIVEUPDATE now depends on
CONFIG_VFIO_DEVICE_CDEV and CONFIG_VFIO_NOIOMMU.
* Serialized state: During preserve(), serialize the PCI domain, BDF,
config space size, reset_works flag, and the initial pci_saved_state
captured when the device was first opened. During freeze(), snapshot
the virtualized PCI config space (vconfig) and capability map
(pci_config_map).
* Keep-running freeze and unfreeze: Do not reset the device, clear
PCI_COMMAND_MASTER, zap BAR mappings, or revoke dma-bufs during
freeze(). Validate that VFIO interrupts are disabled, that the device
is in PCI_D0 (and not in VFIO runtime PM low-power mode), and that
SR-IOV is not enabled, as VFs are not preserved and the next kernel
disables SR-IOV on the running device. Then mask physical INTx
(recording the prior state) and mark the device frozen. If the
Live Update is aborted after freeze(), unfreeze() restores the physical
INTx state and clears liveupdate_frozen so the existing FD remains
usable.
* TOCTOU synchronization: vfio_pci_dev_is_frozen() is checked locklessly
on entry to the ioctl, read/write and mmap paths, and re-checked under
a lock that freeze() holds before any operation that could change the
device or vconfig: under vdev->igate in vfio_pci_ioctl_set_irqs() and
around every config-space write in vfio_pci_config_rw_single(), under
vdev->memory_lock in vfio_pci_runtime_pm_entry(),
vfio_pci_ioctl_reset() and the SR-IOV enable path of
vfio_pci_core_sriov_configure(), and under dev_set->lock in
vfio_pci_dev_set_hot_reset(). A racing operation thus either completes
before freeze() takes its snapshot or fails, while existing BAR mmaps,
ioeventfds and dma-bufs keep working. Serializing config writes on
igate covers the PCI_COMMAND, INTx disable emulation, power state and
FLR paths at one point (the INTx disable emulation now uses the
igate-held __vfio_pci_intx_mask() and __vfio_pci_intx_unmask()
helpers), and also serializes the irq_type and virq_disabled accesses
of config writes with VFIO_DEVICE_SET_IRQS.
Co-developed-by: David Matlack <dmatlack@xxxxxxxxxx>
Signed-off-by: David Matlack <dmatlack@xxxxxxxxxx>
Signed-off-by: Vipin Sharma <vipinsh@xxxxxxxxxx>
---
drivers/vfio/pci/Kconfig | 2 +-
drivers/vfio/pci/vfio_pci_config.c | 19 +-
drivers/vfio/pci/vfio_pci_core.c | 49 +++-
drivers/vfio/pci/vfio_pci_intrs.c | 4 +-
drivers/vfio/pci/vfio_pci_liveupdate.c | 303 ++++++++++++++++++++++++-
drivers/vfio/pci/vfio_pci_priv.h | 13 ++
include/linux/kho/abi/vfio_pci.h | 52 ++++-
include/linux/vfio_pci_core.h | 4 +
8 files changed, 434 insertions(+), 12 deletions(-)
[snip]
diff --git a/include/linux/kho/abi/vfio_pci.h b/include/linux/kho/abi/vfio_pci.h
index 67e8199eec59..725043a44b55 100644
--- a/include/linux/kho/abi/vfio_pci.h
+++ b/include/linux/kho/abi/vfio_pci.h
@@ -9,14 +9,19 @@
#ifndef _LINUX_LIVEUPDATE_ABI_VFIO_PCI_H
#define _LINUX_LIVEUPDATE_ABI_VFIO_PCI_H
+#include <linux/bits.h>
+#include <linux/compiler.h>
+#include <linux/types.h>
+
/**
* DOC: VFIO PCI Live Update ABI
*
* VFIO uses the ABI defined below for preserving device files across a kexec
* reboot using LUO.
*
- * Device metadata is serialized into memory which is then handed to the next
- * kernel via KHO.
+ * Device metadata, virtualized PCI configuration space, VFIO's capability map,
+ * and the initial PCI saved state captured when the device was first opened are
+ * serialized into memory which is then handed to the next kernel via KHO.
*
* This interface is a contract. Any modification to any of the serialization
* structs defined here constitutes a breaking change. Such changes require
@@ -25,4 +30,47 @@
#define VFIO_PCI_LUO_FH_COMPATIBLE "vfio-pci-v1"
+/**
+ * define VFIO_PCI_SER_RESET_WORKS - Device supports function reset.
+ *
+ * Set in &vfio_pci_core_device_ser.flags when the preserved device had
+ * ``vdev->reset_works == true`` prior to kexec.
+ */
+#define VFIO_PCI_SER_RESET_WORKS BIT(0)
+
+#define VFIO_PCI_SER_KNOWN_FLAGS VFIO_PCI_SER_RESET_WORKS
+
+/**
+ * struct vfio_pci_core_device_ser - Serialized state of a single VFIO PCI
+ * device.
+ *
+ * @domain: The device's PCI domain number (segment).
+ * @bdf: The device's PCI bus, device, and function number.
+ * @cfg_size: Size in bytes of the device's PCI configuration space
+ * (``PCI_CFG_SPACE_SIZE`` or ``PCI_CFG_SPACE_EXP_SIZE``).
+ * @size: Total size in bytes of this serialized buffer, equal to
+ * ``sizeof(struct vfio_pci_core_device_ser) + 2 * @cfg_size + @saved_state_size``.
+ * @flags: Bitmask of ``VFIO_PCI_SER_*`` flags; unknown bits are rejected.
+ * @saved_state_size: Size in bytes of the serialized &struct pci_saved_state_ser
+ * blob stored in @data after ``config_map``, or 0 if none.
+ * @reserved: Reserved for future use; must be 0.
+ * @data: Variable-length payload containing, in order:
+ * 1. ``u8 vconfig[@cfg_size]`` - VFIO virtualized config space snapshot
+ * captured during ``freeze()``.
+ * 2. ``u8 config_map[@cfg_size]`` - VFIO capability map snapshot
+ * captured during ``freeze()``.
+ * 3. ``u8 saved_state[@saved_state_size]`` - serialized
+ * &struct pci_saved_state_ser captured during ``preserve()``.
+ */
+struct vfio_pci_core_device_ser {
+ u32 domain;
+ u16 bdf;
+ u16 cfg_size;
+ u32 size;
+ u32 flags;
+ u32 saved_state_size;
We will need space for iommufd_token when we preserve that, we should
probably add it now as otherwise the compatibility would be broken when
we add it? Is the reserved here for that?
+ u32 reserved;
+ u8 data[];
+} __packed;
+
#endif /* _LINUX_LIVEUPDATE_ABI_VFIO_PCI_H */
diff --git a/include/linux/vfio_pci_core.h b/include/linux/vfio_pci_core.h
index 9a1674c152aa..6bae7581f4f4 100644
--- a/include/linux/vfio_pci_core.h
+++ b/include/linux/vfio_pci_core.h
@@ -149,6 +149,10 @@ struct vfio_pci_core_device {
struct notifier_block nb;
struct rw_semaphore memory_lock;
struct list_head dmabufs;
+#ifdef CONFIG_VFIO_PCI_LIVEUPDATE
+ bool liveupdate_frozen;
+ bool liveupdate_intx_disabled;
+#endif
};
enum vfio_pci_io_width {
--
2.56.0.317.g454f8302e1-goog
Thanks,
Sami