* [PATCH v2 01/22] liveupdate: Export symbols needed by modules
2026-01-29 21:24 [PATCH v2 00/22] vfio/pci: Base Live Update support for VFIO device files David Matlack
@ 2026-01-29 21:24 ` David Matlack
2026-01-29 21:24 ` [PATCH v2 02/22] PCI: Add API to track PCI devices preserved across Live Update David Matlack
` (20 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: David Matlack @ 2026-01-29 21:24 UTC (permalink / raw)
To: Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Matlack, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
Export liveupdate_enabled(), liveupdate_register_file_handler(), and
liveupdate_unregister_file_handler(). All of these will be used by
vfio-pci in a subsequent commit, which can be built as a module.
Signed-off-by: David Matlack <dmatlack@google.com>
---
kernel/liveupdate/luo_core.c | 1 +
kernel/liveupdate/luo_file.c | 2 ++
2 files changed, 3 insertions(+)
diff --git a/kernel/liveupdate/luo_core.c b/kernel/liveupdate/luo_core.c
index dda7bb57d421..59d7793d9444 100644
--- a/kernel/liveupdate/luo_core.c
+++ b/kernel/liveupdate/luo_core.c
@@ -255,6 +255,7 @@ bool liveupdate_enabled(void)
{
return luo_global.enabled;
}
+EXPORT_SYMBOL_GPL(liveupdate_enabled);
/**
* DOC: LUO ioctl Interface
diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c
index 35d2a8b1a0df..32759e846bc9 100644
--- a/kernel/liveupdate/luo_file.c
+++ b/kernel/liveupdate/luo_file.c
@@ -872,6 +872,7 @@ int liveupdate_register_file_handler(struct liveupdate_file_handler *fh)
luo_session_resume();
return err;
}
+EXPORT_SYMBOL_GPL(liveupdate_register_file_handler);
/**
* liveupdate_unregister_file_handler - Unregister a liveupdate file handler
@@ -917,3 +918,4 @@ int liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh)
liveupdate_test_register(fh);
return err;
}
+EXPORT_SYMBOL_GPL(liveupdate_unregister_file_handler);
--
2.53.0.rc1.225.gd81095ad13-goog
^ permalink raw reply [flat|nested] 32+ messages in thread* [PATCH v2 02/22] PCI: Add API to track PCI devices preserved across Live Update
2026-01-29 21:24 [PATCH v2 00/22] vfio/pci: Base Live Update support for VFIO device files David Matlack
2026-01-29 21:24 ` [PATCH v2 01/22] liveupdate: Export symbols needed by modules David Matlack
@ 2026-01-29 21:24 ` David Matlack
2026-02-01 6:38 ` Zhu Yanjun
2026-01-29 21:24 ` [PATCH v2 03/22] PCI: Inherit bus numbers from previous kernel during " David Matlack
` (19 subsequent siblings)
21 siblings, 1 reply; 32+ messages in thread
From: David Matlack @ 2026-01-29 21:24 UTC (permalink / raw)
To: Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Matlack, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
Add an API to enable the PCI subsystem to track all devices that are
preserved across a Live Update, including both incoming devices (passed
from the previous kernel) and outgoing devices (passed to the next
kernel).
Use PCI segment number and BDF to keep track of devices across Live
Update. This means the kernel must keep both identifiers constant across
a Live Update for any preserved device. VFs are not supported for now,
since that requires preserving SR-IOV state on the device to ensure the
same number of VFs appear after kexec and with the same BDFs.
Drivers that preserve devices across Live Update can now register their
struct liveupdate_file_handler with the PCI subsystem so that the PCI
subsystem can allocate and manage File-Lifecycle-Bound (FLB) global data
to track the list of incoming and outgoing preserved devices.
pci_liveupdate_register_fh(driver_fh)
pci_liveupdate_unregister_fh(driver_fh)
Drivers can notify the PCI subsystem whenever a device is preserved and
unpreserved with the following APIs:
pci_liveupdate_outgoing_preserve(pci_dev)
pci_liveupdate_outgoing_unpreserve(pci_dev)
After a Live Update, the PCI subsystem fetches its FLB global data
from the previous kernel from the Live Update Orchestrator (LUO) during
device initialization to determine which devices were preserved.
Drivers can check if a device was preserved before userspace retrieves
the file for it via pci_dev->liveupdate_incoming.
Once a driver has finished restoring an incoming preserved device, it
can notify the PCI subsystem with the following call, which clears
pci_dev->liveupdate_incoming.
pci_liveupdate_incoming_finish(pci_dev)
This API will be used in subsequent commits by the vfio-pci driver to
preserve VFIO devices across Live Update and by the PCI subsystem.
Signed-off-by: David Matlack <dmatlack@google.com>
---
drivers/pci/Makefile | 1 +
drivers/pci/liveupdate.c | 212 ++++++++++++++++++++++++++++++++++++
drivers/pci/probe.c | 2 +
include/linux/kho/abi/pci.h | 55 ++++++++++
include/linux/pci.h | 47 ++++++++
5 files changed, 317 insertions(+)
create mode 100644 drivers/pci/liveupdate.c
create mode 100644 include/linux/kho/abi/pci.h
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 8c259a9a8796..a32f7658b9e5 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSFS) += pci-sysfs.o slot.o
obj-$(CONFIG_ACPI) += pci-acpi.o
obj-$(CONFIG_GENERIC_PCI_IOMAP) += iomap.o
+obj-$(CONFIG_LIVEUPDATE) += liveupdate.o
endif
obj-$(CONFIG_OF) += of.o
diff --git a/drivers/pci/liveupdate.c b/drivers/pci/liveupdate.c
new file mode 100644
index 000000000000..182cfc793b80
--- /dev/null
+++ b/drivers/pci/liveupdate.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (c) 2025, Google LLC.
+ * David Matlack <dmatlack@google.com>
+ */
+
+#include <linux/bsearch.h>
+#include <linux/io.h>
+#include <linux/kexec_handover.h>
+#include <linux/kho/abi/pci.h>
+#include <linux/liveupdate.h>
+#include <linux/mutex.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/sort.h>
+
+static DEFINE_MUTEX(pci_flb_outgoing_lock);
+
+static int pci_flb_preserve(struct liveupdate_flb_op_args *args)
+{
+ struct pci_dev *dev = NULL;
+ int max_nr_devices = 0;
+ struct pci_ser *ser;
+ unsigned long size;
+
+ for_each_pci_dev(dev)
+ max_nr_devices++;
+
+ size = struct_size_t(struct pci_ser, devices, max_nr_devices);
+
+ ser = kho_alloc_preserve(size);
+ if (IS_ERR(ser))
+ return PTR_ERR(ser);
+
+ ser->max_nr_devices = max_nr_devices;
+
+ args->obj = ser;
+ args->data = virt_to_phys(ser);
+ return 0;
+}
+
+static void pci_flb_unpreserve(struct liveupdate_flb_op_args *args)
+{
+ struct pci_ser *ser = args->obj;
+
+ WARN_ON_ONCE(ser->nr_devices);
+ kho_unpreserve_free(ser);
+}
+
+static int pci_flb_retrieve(struct liveupdate_flb_op_args *args)
+{
+ args->obj = phys_to_virt(args->data);
+ return 0;
+}
+
+static void pci_flb_finish(struct liveupdate_flb_op_args *args)
+{
+ kho_restore_free(args->obj);
+}
+
+static struct liveupdate_flb_ops pci_liveupdate_flb_ops = {
+ .preserve = pci_flb_preserve,
+ .unpreserve = pci_flb_unpreserve,
+ .retrieve = pci_flb_retrieve,
+ .finish = pci_flb_finish,
+ .owner = THIS_MODULE,
+};
+
+static struct liveupdate_flb pci_liveupdate_flb = {
+ .ops = &pci_liveupdate_flb_ops,
+ .compatible = PCI_LUO_FLB_COMPATIBLE,
+};
+
+#define INIT_PCI_DEV_SER(_dev) { \
+ .domain = pci_domain_nr((_dev)->bus), \
+ .bdf = pci_dev_id(_dev), \
+}
+
+static int pci_dev_ser_cmp(const void *__a, const void *__b)
+{
+ const struct pci_dev_ser *a = __a, *b = __b;
+
+ return cmp_int(a->domain << 16 | a->bdf, b->domain << 16 | b->bdf);
+}
+
+static struct pci_dev_ser *pci_ser_find(struct pci_ser *ser,
+ struct pci_dev *dev)
+{
+ const struct pci_dev_ser key = INIT_PCI_DEV_SER(dev);
+
+ return bsearch(&key, ser->devices, ser->nr_devices,
+ sizeof(key), pci_dev_ser_cmp);
+}
+
+static int pci_ser_delete(struct pci_ser *ser, struct pci_dev *dev)
+{
+ struct pci_dev_ser *dev_ser;
+ int i;
+
+ dev_ser = pci_ser_find(ser, dev);
+ if (!dev_ser)
+ return -ENOENT;
+
+ for (i = dev_ser - ser->devices; i < ser->nr_devices - 1; i++)
+ ser->devices[i] = ser->devices[i + 1];
+
+ ser->nr_devices--;
+ return 0;
+}
+
+int pci_liveupdate_outgoing_preserve(struct pci_dev *dev)
+{
+ struct pci_dev_ser new = INIT_PCI_DEV_SER(dev);
+ struct pci_ser *ser;
+ int i, ret;
+
+ /* Preserving VFs is not supported yet. */
+ if (dev->is_virtfn)
+ return -EINVAL;
+
+ guard(mutex)(&pci_flb_outgoing_lock);
+
+ if (dev->liveupdate_outgoing)
+ return -EBUSY;
+
+ ret = liveupdate_flb_get_outgoing(&pci_liveupdate_flb, (void **)&ser);
+ if (ret)
+ return ret;
+
+ if (ser->nr_devices == ser->max_nr_devices)
+ return -E2BIG;
+
+ for (i = ser->nr_devices; i > 0; i--) {
+ struct pci_dev_ser *prev = &ser->devices[i - 1];
+ int cmp = pci_dev_ser_cmp(&new, prev);
+
+ if (WARN_ON_ONCE(!cmp))
+ return -EBUSY;
+
+ if (cmp > 0)
+ break;
+
+ ser->devices[i] = *prev;
+ }
+
+ ser->devices[i] = new;
+ ser->nr_devices++;
+ dev->liveupdate_outgoing = true;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pci_liveupdate_outgoing_preserve);
+
+void pci_liveupdate_outgoing_unpreserve(struct pci_dev *dev)
+{
+ struct pci_ser *ser;
+ int ret;
+
+ guard(mutex)(&pci_flb_outgoing_lock);
+
+ ret = liveupdate_flb_get_outgoing(&pci_liveupdate_flb, (void **)&ser);
+ if (WARN_ON_ONCE(ret))
+ return;
+
+ WARN_ON_ONCE(pci_ser_delete(ser, dev));
+ dev->liveupdate_outgoing = false;
+}
+EXPORT_SYMBOL_GPL(pci_liveupdate_outgoing_unpreserve);
+
+u32 pci_liveupdate_incoming_nr_devices(void)
+{
+ struct pci_ser *ser;
+ int ret;
+
+ ret = liveupdate_flb_get_incoming(&pci_liveupdate_flb, (void **)&ser);
+ if (ret)
+ return 0;
+
+ return ser->nr_devices;
+}
+EXPORT_SYMBOL_GPL(pci_liveupdate_incoming_nr_devices);
+
+void pci_liveupdate_setup_device(struct pci_dev *dev)
+{
+ struct pci_ser *ser;
+ int ret;
+
+ ret = liveupdate_flb_get_incoming(&pci_liveupdate_flb, (void **)&ser);
+ if (ret)
+ return;
+
+ dev->liveupdate_incoming = !!pci_ser_find(ser, dev);
+}
+EXPORT_SYMBOL_GPL(pci_liveupdate_setup_device);
+
+void pci_liveupdate_incoming_finish(struct pci_dev *dev)
+{
+ dev->liveupdate_incoming = false;
+}
+EXPORT_SYMBOL_GPL(pci_liveupdate_incoming_finish);
+
+int pci_liveupdate_register_fh(struct liveupdate_file_handler *fh)
+{
+ return liveupdate_register_flb(fh, &pci_liveupdate_flb);
+}
+EXPORT_SYMBOL_GPL(pci_liveupdate_register_fh);
+
+int pci_liveupdate_unregister_fh(struct liveupdate_file_handler *fh)
+{
+ return liveupdate_unregister_flb(fh, &pci_liveupdate_flb);
+}
+EXPORT_SYMBOL_GPL(pci_liveupdate_unregister_fh);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 37329095e5fe..af6356c5a156 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -2060,6 +2060,8 @@ int pci_setup_device(struct pci_dev *dev)
if (pci_early_dump)
early_dump_pci_device(dev);
+ pci_liveupdate_setup_device(dev);
+
/* Need to have dev->class ready */
dev->cfg_size = pci_cfg_space_size(dev);
diff --git a/include/linux/kho/abi/pci.h b/include/linux/kho/abi/pci.h
new file mode 100644
index 000000000000..6577767f8da6
--- /dev/null
+++ b/include/linux/kho/abi/pci.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Copyright (c) 2025, Google LLC.
+ * David Matlack <dmatlack@google.com>
+ */
+
+#ifndef _LINUX_KHO_ABI_PCI_H
+#define _LINUX_KHO_ABI_PCI_H
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+/**
+ * DOC: PCI File-Lifecycle Bound (FLB) Live Update ABI
+ *
+ * This header defines the ABI for preserving core PCI state across kexec using
+ * Live Update File-Lifecycle Bound (FLB) data.
+ *
+ * This interface is a contract. Any modification to any of the serialization
+ * structs defined here constitutes a breaking change. Such changes require
+ * incrementing the version number in the PCI_LUO_FLB_COMPATIBLE string.
+ */
+
+#define PCI_LUO_FLB_COMPATIBLE "pci-v1"
+
+/**
+ * struct pci_dev_ser - Serialized state about a single PCI device.
+ *
+ * @domain: The device's PCI domain number (segment).
+ * @bdf: The device's PCI bus, device, and function number.
+ */
+struct pci_dev_ser {
+ u16 domain;
+ u16 bdf;
+} __packed;
+
+/**
+ * struct pci_ser - PCI Subsystem Live Update State
+ *
+ * This struct tracks state about all devices that are being preserved across
+ * a Live Update for the next kernel.
+ *
+ * @max_nr_devices: The length of the devices[] flexible array.
+ * @nr_devices: The number of devices that were preserved.
+ * @devices: Flexible array of pci_dev_ser structs for each device. Guaranteed
+ * to be sorted ascending by domain and bdf.
+ */
+struct pci_ser {
+ u64 max_nr_devices;
+ u64 nr_devices;
+ struct pci_dev_ser devices[];
+} __packed;
+
+#endif /* _LINUX_KHO_ABI_PCI_H */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 7e36936bb37a..9ead6d84aef6 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -40,6 +40,7 @@
#include <linux/resource_ext.h>
#include <linux/msi_api.h>
#include <uapi/linux/pci.h>
+#include <linux/liveupdate.h>
#include <linux/pci_ids.h>
@@ -582,6 +583,10 @@ struct pci_dev {
u8 tph_mode; /* TPH mode */
u8 tph_req_type; /* TPH requester type */
#endif
+#ifdef CONFIG_LIVEUPDATE
+ unsigned int liveupdate_incoming:1; /* Preserved by previous kernel */
+ unsigned int liveupdate_outgoing:1; /* Preserved for next kernel */
+#endif
};
static inline struct pci_dev *pci_physfn(struct pci_dev *dev)
@@ -2854,4 +2859,46 @@ void pci_uevent_ers(struct pci_dev *pdev, enum pci_ers_result err_type);
WARN_ONCE(condition, "%s %s: " fmt, \
dev_driver_string(&(pdev)->dev), pci_name(pdev), ##arg)
+#ifdef CONFIG_LIVEUPDATE
+int pci_liveupdate_outgoing_preserve(struct pci_dev *dev);
+void pci_liveupdate_outgoing_unpreserve(struct pci_dev *dev);
+void pci_liveupdate_setup_device(struct pci_dev *dev);
+u32 pci_liveupdate_incoming_nr_devices(void);
+void pci_liveupdate_incoming_finish(struct pci_dev *dev);
+int pci_liveupdate_register_fh(struct liveupdate_file_handler *fh);
+int pci_liveupdate_unregister_fh(struct liveupdate_file_handler *fh);
+#else /* !CONFIG_LIVEUPDATE */
+static inline int pci_liveupdate_outgoing_preserve(struct pci_dev *dev)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline void pci_liveupdate_outgoing_unpreserve(struct pci_dev *dev)
+{
+}
+
+static inline void pci_liveupdate_setup_device(struct pci_dev *dev)
+{
+}
+
+static inline u32 pci_liveupdate_incoming_nr_devices(void)
+{
+ return 0;
+}
+
+static inline void pci_liveupdate_incoming_finish(struct pci_dev *dev)
+{
+}
+
+static inline int pci_liveupdate_register_fh(struct liveupdate_file_handler *fh)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int pci_liveupdate_unregister_fh(struct liveupdate_file_handler *fh)
+{
+ return -EOPNOTSUPP;
+}
+#endif /* !CONFIG_LIVEUPDATE */
+
#endif /* LINUX_PCI_H */
--
2.53.0.rc1.225.gd81095ad13-goog
^ permalink raw reply [flat|nested] 32+ messages in thread* Re: [PATCH v2 02/22] PCI: Add API to track PCI devices preserved across Live Update
2026-01-29 21:24 ` [PATCH v2 02/22] PCI: Add API to track PCI devices preserved across Live Update David Matlack
@ 2026-02-01 6:38 ` Zhu Yanjun
2026-02-02 18:14 ` David Matlack
0 siblings, 1 reply; 32+ messages in thread
From: Zhu Yanjun @ 2026-02-01 6:38 UTC (permalink / raw)
To: David Matlack, Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Rientjes, Jacob Pan, Jason Gunthorpe,
Jason Gunthorpe, Jonathan Corbet, Josh Hilke, Kevin Tian, kexec,
kvm, Leon Romanovsky, Leon Romanovsky, linux-doc, linux-kernel,
linux-kselftest, linux-mm, linux-pci, Lukas Wunner,
Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu
在 2026/1/29 13:24, David Matlack 写道:
> Add an API to enable the PCI subsystem to track all devices that are
> preserved across a Live Update, including both incoming devices (passed
> from the previous kernel) and outgoing devices (passed to the next
> kernel).
>
> Use PCI segment number and BDF to keep track of devices across Live
> Update. This means the kernel must keep both identifiers constant across
> a Live Update for any preserved device. VFs are not supported for now,
> since that requires preserving SR-IOV state on the device to ensure the
> same number of VFs appear after kexec and with the same BDFs.
>
> Drivers that preserve devices across Live Update can now register their
> struct liveupdate_file_handler with the PCI subsystem so that the PCI
> subsystem can allocate and manage File-Lifecycle-Bound (FLB) global data
> to track the list of incoming and outgoing preserved devices.
>
> pci_liveupdate_register_fh(driver_fh)
> pci_liveupdate_unregister_fh(driver_fh)
Can the above 2 functions support the virtual devices? For example,
bonding, veth, iSWAP and RXE.
These virtual devices do not have BDF. As such, I am not sure if your
patches take these virtual devices in to account.
Thanks a lot.
Zhu Yanjun
>
> Drivers can notify the PCI subsystem whenever a device is preserved and
> unpreserved with the following APIs:
>
> pci_liveupdate_outgoing_preserve(pci_dev)
> pci_liveupdate_outgoing_unpreserve(pci_dev)
>
> After a Live Update, the PCI subsystem fetches its FLB global data
> from the previous kernel from the Live Update Orchestrator (LUO) during
> device initialization to determine which devices were preserved.
>
> Drivers can check if a device was preserved before userspace retrieves
> the file for it via pci_dev->liveupdate_incoming.
>
> Once a driver has finished restoring an incoming preserved device, it
> can notify the PCI subsystem with the following call, which clears
> pci_dev->liveupdate_incoming.
>
> pci_liveupdate_incoming_finish(pci_dev)
>
> This API will be used in subsequent commits by the vfio-pci driver to
> preserve VFIO devices across Live Update and by the PCI subsystem.
>
> Signed-off-by: David Matlack <dmatlack@google.com>
> ---
> drivers/pci/Makefile | 1 +
> drivers/pci/liveupdate.c | 212 ++++++++++++++++++++++++++++++++++++
> drivers/pci/probe.c | 2 +
> include/linux/kho/abi/pci.h | 55 ++++++++++
> include/linux/pci.h | 47 ++++++++
> 5 files changed, 317 insertions(+)
> create mode 100644 drivers/pci/liveupdate.c
> create mode 100644 include/linux/kho/abi/pci.h
>
> diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
> index 8c259a9a8796..a32f7658b9e5 100644
> --- a/drivers/pci/Makefile
> +++ b/drivers/pci/Makefile
> @@ -16,6 +16,7 @@ obj-$(CONFIG_PROC_FS) += proc.o
> obj-$(CONFIG_SYSFS) += pci-sysfs.o slot.o
> obj-$(CONFIG_ACPI) += pci-acpi.o
> obj-$(CONFIG_GENERIC_PCI_IOMAP) += iomap.o
> +obj-$(CONFIG_LIVEUPDATE) += liveupdate.o
> endif
>
> obj-$(CONFIG_OF) += of.o
> diff --git a/drivers/pci/liveupdate.c b/drivers/pci/liveupdate.c
> new file mode 100644
> index 000000000000..182cfc793b80
> --- /dev/null
> +++ b/drivers/pci/liveupdate.c
> @@ -0,0 +1,212 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * Copyright (c) 2025, Google LLC.
> + * David Matlack <dmatlack@google.com>
> + */
> +
> +#include <linux/bsearch.h>
> +#include <linux/io.h>
> +#include <linux/kexec_handover.h>
> +#include <linux/kho/abi/pci.h>
> +#include <linux/liveupdate.h>
> +#include <linux/mutex.h>
> +#include <linux/mm.h>
> +#include <linux/pci.h>
> +#include <linux/sort.h>
> +
> +static DEFINE_MUTEX(pci_flb_outgoing_lock);
> +
> +static int pci_flb_preserve(struct liveupdate_flb_op_args *args)
> +{
> + struct pci_dev *dev = NULL;
> + int max_nr_devices = 0;
> + struct pci_ser *ser;
> + unsigned long size;
> +
> + for_each_pci_dev(dev)
> + max_nr_devices++;
> +
> + size = struct_size_t(struct pci_ser, devices, max_nr_devices);
> +
> + ser = kho_alloc_preserve(size);
> + if (IS_ERR(ser))
> + return PTR_ERR(ser);
> +
> + ser->max_nr_devices = max_nr_devices;
> +
> + args->obj = ser;
> + args->data = virt_to_phys(ser);
> + return 0;
> +}
> +
> +static void pci_flb_unpreserve(struct liveupdate_flb_op_args *args)
> +{
> + struct pci_ser *ser = args->obj;
> +
> + WARN_ON_ONCE(ser->nr_devices);
> + kho_unpreserve_free(ser);
> +}
> +
> +static int pci_flb_retrieve(struct liveupdate_flb_op_args *args)
> +{
> + args->obj = phys_to_virt(args->data);
> + return 0;
> +}
> +
> +static void pci_flb_finish(struct liveupdate_flb_op_args *args)
> +{
> + kho_restore_free(args->obj);
> +}
> +
> +static struct liveupdate_flb_ops pci_liveupdate_flb_ops = {
> + .preserve = pci_flb_preserve,
> + .unpreserve = pci_flb_unpreserve,
> + .retrieve = pci_flb_retrieve,
> + .finish = pci_flb_finish,
> + .owner = THIS_MODULE,
> +};
> +
> +static struct liveupdate_flb pci_liveupdate_flb = {
> + .ops = &pci_liveupdate_flb_ops,
> + .compatible = PCI_LUO_FLB_COMPATIBLE,
> +};
> +
> +#define INIT_PCI_DEV_SER(_dev) { \
> + .domain = pci_domain_nr((_dev)->bus), \
> + .bdf = pci_dev_id(_dev), \
> +}
> +
> +static int pci_dev_ser_cmp(const void *__a, const void *__b)
> +{
> + const struct pci_dev_ser *a = __a, *b = __b;
> +
> + return cmp_int(a->domain << 16 | a->bdf, b->domain << 16 | b->bdf);
> +}
> +
> +static struct pci_dev_ser *pci_ser_find(struct pci_ser *ser,
> + struct pci_dev *dev)
> +{
> + const struct pci_dev_ser key = INIT_PCI_DEV_SER(dev);
> +
> + return bsearch(&key, ser->devices, ser->nr_devices,
> + sizeof(key), pci_dev_ser_cmp);
> +}
> +
> +static int pci_ser_delete(struct pci_ser *ser, struct pci_dev *dev)
> +{
> + struct pci_dev_ser *dev_ser;
> + int i;
> +
> + dev_ser = pci_ser_find(ser, dev);
> + if (!dev_ser)
> + return -ENOENT;
> +
> + for (i = dev_ser - ser->devices; i < ser->nr_devices - 1; i++)
> + ser->devices[i] = ser->devices[i + 1];
> +
> + ser->nr_devices--;
> + return 0;
> +}
> +
> +int pci_liveupdate_outgoing_preserve(struct pci_dev *dev)
> +{
> + struct pci_dev_ser new = INIT_PCI_DEV_SER(dev);
> + struct pci_ser *ser;
> + int i, ret;
> +
> + /* Preserving VFs is not supported yet. */
> + if (dev->is_virtfn)
> + return -EINVAL;
> +
> + guard(mutex)(&pci_flb_outgoing_lock);
> +
> + if (dev->liveupdate_outgoing)
> + return -EBUSY;
> +
> + ret = liveupdate_flb_get_outgoing(&pci_liveupdate_flb, (void **)&ser);
> + if (ret)
> + return ret;
> +
> + if (ser->nr_devices == ser->max_nr_devices)
> + return -E2BIG;
> +
> + for (i = ser->nr_devices; i > 0; i--) {
> + struct pci_dev_ser *prev = &ser->devices[i - 1];
> + int cmp = pci_dev_ser_cmp(&new, prev);
> +
> + if (WARN_ON_ONCE(!cmp))
> + return -EBUSY;
> +
> + if (cmp > 0)
> + break;
> +
> + ser->devices[i] = *prev;
> + }
> +
> + ser->devices[i] = new;
> + ser->nr_devices++;
> + dev->liveupdate_outgoing = true;
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(pci_liveupdate_outgoing_preserve);
> +
> +void pci_liveupdate_outgoing_unpreserve(struct pci_dev *dev)
> +{
> + struct pci_ser *ser;
> + int ret;
> +
> + guard(mutex)(&pci_flb_outgoing_lock);
> +
> + ret = liveupdate_flb_get_outgoing(&pci_liveupdate_flb, (void **)&ser);
> + if (WARN_ON_ONCE(ret))
> + return;
> +
> + WARN_ON_ONCE(pci_ser_delete(ser, dev));
> + dev->liveupdate_outgoing = false;
> +}
> +EXPORT_SYMBOL_GPL(pci_liveupdate_outgoing_unpreserve);
> +
> +u32 pci_liveupdate_incoming_nr_devices(void)
> +{
> + struct pci_ser *ser;
> + int ret;
> +
> + ret = liveupdate_flb_get_incoming(&pci_liveupdate_flb, (void **)&ser);
> + if (ret)
> + return 0;
> +
> + return ser->nr_devices;
> +}
> +EXPORT_SYMBOL_GPL(pci_liveupdate_incoming_nr_devices);
> +
> +void pci_liveupdate_setup_device(struct pci_dev *dev)
> +{
> + struct pci_ser *ser;
> + int ret;
> +
> + ret = liveupdate_flb_get_incoming(&pci_liveupdate_flb, (void **)&ser);
> + if (ret)
> + return;
> +
> + dev->liveupdate_incoming = !!pci_ser_find(ser, dev);
> +}
> +EXPORT_SYMBOL_GPL(pci_liveupdate_setup_device);
> +
> +void pci_liveupdate_incoming_finish(struct pci_dev *dev)
> +{
> + dev->liveupdate_incoming = false;
> +}
> +EXPORT_SYMBOL_GPL(pci_liveupdate_incoming_finish);
> +
> +int pci_liveupdate_register_fh(struct liveupdate_file_handler *fh)
> +{
> + return liveupdate_register_flb(fh, &pci_liveupdate_flb);
> +}
> +EXPORT_SYMBOL_GPL(pci_liveupdate_register_fh);
> +
> +int pci_liveupdate_unregister_fh(struct liveupdate_file_handler *fh)
> +{
> + return liveupdate_unregister_flb(fh, &pci_liveupdate_flb);
> +}
> +EXPORT_SYMBOL_GPL(pci_liveupdate_unregister_fh);
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index 37329095e5fe..af6356c5a156 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -2060,6 +2060,8 @@ int pci_setup_device(struct pci_dev *dev)
> if (pci_early_dump)
> early_dump_pci_device(dev);
>
> + pci_liveupdate_setup_device(dev);
> +
> /* Need to have dev->class ready */
> dev->cfg_size = pci_cfg_space_size(dev);
>
> diff --git a/include/linux/kho/abi/pci.h b/include/linux/kho/abi/pci.h
> new file mode 100644
> index 000000000000..6577767f8da6
> --- /dev/null
> +++ b/include/linux/kho/abi/pci.h
> @@ -0,0 +1,55 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +/*
> + * Copyright (c) 2025, Google LLC.
> + * David Matlack <dmatlack@google.com>
> + */
> +
> +#ifndef _LINUX_KHO_ABI_PCI_H
> +#define _LINUX_KHO_ABI_PCI_H
> +
> +#include <linux/compiler.h>
> +#include <linux/types.h>
> +
> +/**
> + * DOC: PCI File-Lifecycle Bound (FLB) Live Update ABI
> + *
> + * This header defines the ABI for preserving core PCI state across kexec using
> + * Live Update File-Lifecycle Bound (FLB) data.
> + *
> + * This interface is a contract. Any modification to any of the serialization
> + * structs defined here constitutes a breaking change. Such changes require
> + * incrementing the version number in the PCI_LUO_FLB_COMPATIBLE string.
> + */
> +
> +#define PCI_LUO_FLB_COMPATIBLE "pci-v1"
> +
> +/**
> + * struct pci_dev_ser - Serialized state about a single PCI device.
> + *
> + * @domain: The device's PCI domain number (segment).
> + * @bdf: The device's PCI bus, device, and function number.
> + */
> +struct pci_dev_ser {
> + u16 domain;
> + u16 bdf;
> +} __packed;
> +
> +/**
> + * struct pci_ser - PCI Subsystem Live Update State
> + *
> + * This struct tracks state about all devices that are being preserved across
> + * a Live Update for the next kernel.
> + *
> + * @max_nr_devices: The length of the devices[] flexible array.
> + * @nr_devices: The number of devices that were preserved.
> + * @devices: Flexible array of pci_dev_ser structs for each device. Guaranteed
> + * to be sorted ascending by domain and bdf.
> + */
> +struct pci_ser {
> + u64 max_nr_devices;
> + u64 nr_devices;
> + struct pci_dev_ser devices[];
> +} __packed;
> +
> +#endif /* _LINUX_KHO_ABI_PCI_H */
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 7e36936bb37a..9ead6d84aef6 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -40,6 +40,7 @@
> #include <linux/resource_ext.h>
> #include <linux/msi_api.h>
> #include <uapi/linux/pci.h>
> +#include <linux/liveupdate.h>
>
> #include <linux/pci_ids.h>
>
> @@ -582,6 +583,10 @@ struct pci_dev {
> u8 tph_mode; /* TPH mode */
> u8 tph_req_type; /* TPH requester type */
> #endif
> +#ifdef CONFIG_LIVEUPDATE
> + unsigned int liveupdate_incoming:1; /* Preserved by previous kernel */
> + unsigned int liveupdate_outgoing:1; /* Preserved for next kernel */
> +#endif
> };
>
> static inline struct pci_dev *pci_physfn(struct pci_dev *dev)
> @@ -2854,4 +2859,46 @@ void pci_uevent_ers(struct pci_dev *pdev, enum pci_ers_result err_type);
> WARN_ONCE(condition, "%s %s: " fmt, \
> dev_driver_string(&(pdev)->dev), pci_name(pdev), ##arg)
>
> +#ifdef CONFIG_LIVEUPDATE
> +int pci_liveupdate_outgoing_preserve(struct pci_dev *dev);
> +void pci_liveupdate_outgoing_unpreserve(struct pci_dev *dev);
> +void pci_liveupdate_setup_device(struct pci_dev *dev);
> +u32 pci_liveupdate_incoming_nr_devices(void);
> +void pci_liveupdate_incoming_finish(struct pci_dev *dev);
> +int pci_liveupdate_register_fh(struct liveupdate_file_handler *fh);
> +int pci_liveupdate_unregister_fh(struct liveupdate_file_handler *fh);
> +#else /* !CONFIG_LIVEUPDATE */
> +static inline int pci_liveupdate_outgoing_preserve(struct pci_dev *dev)
> +{
> + return -EOPNOTSUPP;
> +}
> +
> +static inline void pci_liveupdate_outgoing_unpreserve(struct pci_dev *dev)
> +{
> +}
> +
> +static inline void pci_liveupdate_setup_device(struct pci_dev *dev)
> +{
> +}
> +
> +static inline u32 pci_liveupdate_incoming_nr_devices(void)
> +{
> + return 0;
> +}
> +
> +static inline void pci_liveupdate_incoming_finish(struct pci_dev *dev)
> +{
> +}
> +
> +static inline int pci_liveupdate_register_fh(struct liveupdate_file_handler *fh)
> +{
> + return -EOPNOTSUPP;
> +}
> +
> +static inline int pci_liveupdate_unregister_fh(struct liveupdate_file_handler *fh)
> +{
> + return -EOPNOTSUPP;
> +}
> +#endif /* !CONFIG_LIVEUPDATE */
> +
> #endif /* LINUX_PCI_H */
>
--
Best Regards,
Yanjun.Zhu
^ permalink raw reply [flat|nested] 32+ messages in thread* Re: [PATCH v2 02/22] PCI: Add API to track PCI devices preserved across Live Update
2026-02-01 6:38 ` Zhu Yanjun
@ 2026-02-02 18:14 ` David Matlack
2026-02-04 0:10 ` Yanjun.Zhu
0 siblings, 1 reply; 32+ messages in thread
From: David Matlack @ 2026-02-02 18:14 UTC (permalink / raw)
To: Zhu Yanjun
Cc: Alex Williamson, Adithya Jayachandran, Alexander Graf,
Alex Mastro, Alistair Popple, Andrew Morton, Ankit Agrawal,
Bjorn Helgaas, Chris Li, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu
On Sat, Jan 31, 2026 at 10:38 PM Zhu Yanjun <yanjun.zhu@linux.dev> wrote:
>
> 在 2026/1/29 13:24, David Matlack 写道:
> > Add an API to enable the PCI subsystem to track all devices that are
> > preserved across a Live Update, including both incoming devices (passed
> > from the previous kernel) and outgoing devices (passed to the next
> > kernel).
> >
> > Use PCI segment number and BDF to keep track of devices across Live
> > Update. This means the kernel must keep both identifiers constant across
> > a Live Update for any preserved device. VFs are not supported for now,
> > since that requires preserving SR-IOV state on the device to ensure the
> > same number of VFs appear after kexec and with the same BDFs.
> >
> > Drivers that preserve devices across Live Update can now register their
> > struct liveupdate_file_handler with the PCI subsystem so that the PCI
> > subsystem can allocate and manage File-Lifecycle-Bound (FLB) global data
> > to track the list of incoming and outgoing preserved devices.
> >
> > pci_liveupdate_register_fh(driver_fh)
> > pci_liveupdate_unregister_fh(driver_fh)
>
> Can the above 2 functions support the virtual devices? For example,
> bonding, veth, iSWAP and RXE.
>
> These virtual devices do not have BDF. As such, I am not sure if your
> patches take these virtual devices in to account.
No this patch series only supports PCI devices, since those are the
only devices so far we've needed to support.
I am not familiar with any of the devices that you mentioned. If they
are virtual then does that mean it's all just software? In that case I
would be curious to know what problem is solved by preserving them in
the kernel, vs. tearing them down and rebuilding them across a Live
Udpate.
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v2 02/22] PCI: Add API to track PCI devices preserved across Live Update
2026-02-02 18:14 ` David Matlack
@ 2026-02-04 0:10 ` Yanjun.Zhu
2026-02-20 19:03 ` David Matlack
0 siblings, 1 reply; 32+ messages in thread
From: Yanjun.Zhu @ 2026-02-04 0:10 UTC (permalink / raw)
To: David Matlack
Cc: Alex Williamson, Adithya Jayachandran, Alexander Graf,
Alex Mastro, Alistair Popple, Andrew Morton, Ankit Agrawal,
Bjorn Helgaas, Chris Li, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu
On 2/2/26 10:14 AM, David Matlack wrote:
> On Sat, Jan 31, 2026 at 10:38 PM Zhu Yanjun <yanjun.zhu@linux.dev> wrote:
>> 在 2026/1/29 13:24, David Matlack 写道:
>>> Add an API to enable the PCI subsystem to track all devices that are
>>> preserved across a Live Update, including both incoming devices (passed
>>> from the previous kernel) and outgoing devices (passed to the next
>>> kernel).
>>>
>>> Use PCI segment number and BDF to keep track of devices across Live
>>> Update. This means the kernel must keep both identifiers constant across
>>> a Live Update for any preserved device. VFs are not supported for now,
>>> since that requires preserving SR-IOV state on the device to ensure the
>>> same number of VFs appear after kexec and with the same BDFs.
>>>
>>> Drivers that preserve devices across Live Update can now register their
>>> struct liveupdate_file_handler with the PCI subsystem so that the PCI
>>> subsystem can allocate and manage File-Lifecycle-Bound (FLB) global data
>>> to track the list of incoming and outgoing preserved devices.
>>>
>>> pci_liveupdate_register_fh(driver_fh)
>>> pci_liveupdate_unregister_fh(driver_fh)
>> Can the above 2 functions support the virtual devices? For example,
>> bonding, veth, iSWAP and RXE.
>>
>> These virtual devices do not have BDF. As such, I am not sure if your
>> patches take these virtual devices in to account.
> No this patch series only supports PCI devices, since those are the
> only devices so far we've needed to support.
>
> I am not familiar with any of the devices that you mentioned. If they
> are virtual then does that mean it's all just software? In that case I
> would be curious to know what problem is solved by preserving them in
> the kernel, vs. tearing them down and rebuilding them across a Live
> Udpate.
Bonding, veth, rxe, and siw can be used in KVM environments.
Although these are software-only virtual devices with no associated
hardware,
they may maintain state that is observable by userspace.
As a result, Live Update should preserve their state across the update.
Zhu Yanjun
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [PATCH v2 02/22] PCI: Add API to track PCI devices preserved across Live Update
2026-02-04 0:10 ` Yanjun.Zhu
@ 2026-02-20 19:03 ` David Matlack
0 siblings, 0 replies; 32+ messages in thread
From: David Matlack @ 2026-02-20 19:03 UTC (permalink / raw)
To: Yanjun.Zhu
Cc: Alex Williamson, Adithya Jayachandran, Alexander Graf,
Alex Mastro, Alistair Popple, Andrew Morton, Ankit Agrawal,
Bjorn Helgaas, Chris Li, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu
On Tue, Feb 3, 2026 at 4:10 PM Yanjun.Zhu <yanjun.zhu@linux.dev> wrote:
>
> On 2/2/26 10:14 AM, David Matlack wrote:
> > On Sat, Jan 31, 2026 at 10:38 PM Zhu Yanjun <yanjun.zhu@linux.dev> wrote:
> >> 在 2026/1/29 13:24, David Matlack 写道:
> >>> Add an API to enable the PCI subsystem to track all devices that are
> >>> preserved across a Live Update, including both incoming devices (passed
> >>> from the previous kernel) and outgoing devices (passed to the next
> >>> kernel).
> >>>
> >>> Use PCI segment number and BDF to keep track of devices across Live
> >>> Update. This means the kernel must keep both identifiers constant across
> >>> a Live Update for any preserved device. VFs are not supported for now,
> >>> since that requires preserving SR-IOV state on the device to ensure the
> >>> same number of VFs appear after kexec and with the same BDFs.
> >>>
> >>> Drivers that preserve devices across Live Update can now register their
> >>> struct liveupdate_file_handler with the PCI subsystem so that the PCI
> >>> subsystem can allocate and manage File-Lifecycle-Bound (FLB) global data
> >>> to track the list of incoming and outgoing preserved devices.
> >>>
> >>> pci_liveupdate_register_fh(driver_fh)
> >>> pci_liveupdate_unregister_fh(driver_fh)
> >> Can the above 2 functions support the virtual devices? For example,
> >> bonding, veth, iSWAP and RXE.
> >>
> >> These virtual devices do not have BDF. As such, I am not sure if your
> >> patches take these virtual devices in to account.
> > No this patch series only supports PCI devices, since those are the
> > only devices so far we've needed to support.
> >
> > I am not familiar with any of the devices that you mentioned. If they
> > are virtual then does that mean it's all just software? In that case I
> > would be curious to know what problem is solved by preserving them in
> > the kernel, vs. tearing them down and rebuilding them across a Live
> > Udpate.
>
> Bonding, veth, rxe, and siw can be used in KVM environments.
>
> Although these are software-only virtual devices with no associated
> hardware,
>
> they may maintain state that is observable by userspace.
>
> As a result, Live Update should preserve their state across the update.
Sorry for taking so long to get back to you.
Userspace should serialize the state of those devices out of the
kernel, persist it in memory or on disk across Live Update, and then
recreate it after Live Update.
This is why, for example, KVM does not need to direclty participate in
Live Update. The VMM serializes all KVM state from the kernel, saves
it, and then constructs a completely new KVM VM after the Live Update
using that state. KVM will only need to participate in Live Update
once there is hardware requirement. For example, I believe some of the
Confidential Computing hardware virtualization extensions require
certain memory structures used by hardware remain in place and cannot
be reallocated after Live Update. KVM would have to participate to
preserve those and reassociate them with the right VM after Live
Update.
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 03/22] PCI: Inherit bus numbers from previous kernel during Live Update
2026-01-29 21:24 [PATCH v2 00/22] vfio/pci: Base Live Update support for VFIO device files David Matlack
2026-01-29 21:24 ` [PATCH v2 01/22] liveupdate: Export symbols needed by modules David Matlack
2026-01-29 21:24 ` [PATCH v2 02/22] PCI: Add API to track PCI devices preserved across Live Update David Matlack
@ 2026-01-29 21:24 ` David Matlack
2026-01-29 21:24 ` [PATCH v2 04/22] vfio/pci: Register a file handler with Live Update Orchestrator David Matlack
` (18 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: David Matlack @ 2026-01-29 21:24 UTC (permalink / raw)
To: Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Matlack, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
Inherit bus numbers from the previous kernel during a Live Update when
one or more PCI devices are being preserved. This is necessary so that
preserved devices can DMA through the IOMMU during a Live Update
(changing bus numbers would break IOMMU translation).
Signed-off-by: David Matlack <dmatlack@google.com>
---
drivers/pci/probe.c | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index af6356c5a156..ca6e5f79debb 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1351,6 +1351,20 @@ static bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub)
return true;
}
+static bool pci_assign_all_busses(void)
+{
+ /*
+ * During a Live Update where devices are preserved by the previous
+ * kernel, inherit all bus numbers assigned by the previous kernel. Bus
+ * numbers must remain stable for preserved devices so that they can
+ * perform DMA during the Live Update uninterrupted.
+ */
+ if (pci_liveupdate_incoming_nr_devices())
+ return false;
+
+ return pcibios_assign_all_busses();
+}
+
/*
* pci_scan_bridge_extend() - Scan buses behind a bridge
* @bus: Parent bus the bridge is on
@@ -1378,6 +1392,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
int max, unsigned int available_buses,
int pass)
{
+ bool assign_all_busses = pci_assign_all_busses();
struct pci_bus *child;
int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
u32 buses, i, j = 0;
@@ -1424,7 +1439,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
pci_write_config_word(dev, PCI_BRIDGE_CONTROL,
bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT);
- if ((secondary || subordinate) && !pcibios_assign_all_busses() &&
+ if ((secondary || subordinate) && !assign_all_busses &&
!is_cardbus && !broken) {
unsigned int cmax, buses;
@@ -1467,7 +1482,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
* do in the second pass.
*/
if (!pass) {
- if (pcibios_assign_all_busses() || broken || is_cardbus)
+ if (assign_all_busses || broken || is_cardbus)
/*
* Temporarily disable forwarding of the
@@ -1542,7 +1557,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
max+i+1))
break;
while (parent->parent) {
- if ((!pcibios_assign_all_busses()) &&
+ if (!assign_all_busses &&
(parent->busn_res.end > max) &&
(parent->busn_res.end <= max+i)) {
j = 1;
--
2.53.0.rc1.225.gd81095ad13-goog
^ permalink raw reply [flat|nested] 32+ messages in thread* [PATCH v2 04/22] vfio/pci: Register a file handler with Live Update Orchestrator
2026-01-29 21:24 [PATCH v2 00/22] vfio/pci: Base Live Update support for VFIO device files David Matlack
` (2 preceding siblings ...)
2026-01-29 21:24 ` [PATCH v2 03/22] PCI: Inherit bus numbers from previous kernel during " David Matlack
@ 2026-01-29 21:24 ` David Matlack
2026-02-06 22:37 ` Yanjun.Zhu
2026-01-29 21:24 ` [PATCH v2 05/22] vfio/pci: Preserve vfio-pci device files across Live Update David Matlack
` (17 subsequent siblings)
21 siblings, 1 reply; 32+ messages in thread
From: David Matlack @ 2026-01-29 21:24 UTC (permalink / raw)
To: Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Matlack, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
From: Vipin Sharma <vipinsh@google.com>
Register a live update file handler for vfio-pci device files. Add stub
implementations of all required callbacks so that registration does not
fail (i.e. to avoid breaking git-bisect).
This file handler will be extended in subsequent commits to enable a
device bound to vfio-pci to run without interruption while the host is
going through a kexec Live Update.
Signed-off-by: Vipin Sharma <vipinsh@google.com>
Co-developed-by: David Matlack <dmatlack@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
MAINTAINERS | 1 +
drivers/vfio/pci/Makefile | 1 +
drivers/vfio/pci/vfio_pci.c | 9 +++-
drivers/vfio/pci/vfio_pci_liveupdate.c | 69 ++++++++++++++++++++++++++
drivers/vfio/pci/vfio_pci_priv.h | 14 ++++++
include/linux/kho/abi/vfio_pci.h | 28 +++++++++++
6 files changed, 121 insertions(+), 1 deletion(-)
create mode 100644 drivers/vfio/pci/vfio_pci_liveupdate.c
create mode 100644 include/linux/kho/abi/vfio_pci.h
diff --git a/MAINTAINERS b/MAINTAINERS
index a671e3d4e8be..7d6cdecedb05 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27520,6 +27520,7 @@ F: Documentation/ABI/testing/debugfs-vfio
F: Documentation/ABI/testing/sysfs-devices-vfio-dev
F: Documentation/driver-api/vfio.rst
F: drivers/vfio/
+F: include/linux/kho/abi/vfio_pci.h
F: include/linux/vfio.h
F: include/linux/vfio_pci_core.h
F: include/uapi/linux/vfio.h
diff --git a/drivers/vfio/pci/Makefile b/drivers/vfio/pci/Makefile
index e0a0757dd1d2..23305ebc418b 100644
--- a/drivers/vfio/pci/Makefile
+++ b/drivers/vfio/pci/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_VFIO_PCI_CORE) += vfio-pci-core.o
vfio-pci-y := vfio_pci.o
vfio-pci-$(CONFIG_VFIO_PCI_IGD) += vfio_pci_igd.o
+vfio-pci-$(CONFIG_LIVEUPDATE) += vfio_pci_liveupdate.o
obj-$(CONFIG_VFIO_PCI) += vfio-pci.o
obj-$(CONFIG_MLX5_VFIO_PCI) += mlx5/
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index 0c771064c0b8..19e88322af2c 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -258,6 +258,10 @@ static int __init vfio_pci_init(void)
int ret;
bool is_disable_vga = true;
+ ret = vfio_pci_liveupdate_init();
+ if (ret)
+ return ret;
+
#ifdef CONFIG_VFIO_PCI_VGA
is_disable_vga = disable_vga;
#endif
@@ -266,8 +270,10 @@ static int __init vfio_pci_init(void)
/* Register and scan for devices */
ret = pci_register_driver(&vfio_pci_driver);
- if (ret)
+ if (ret) {
+ vfio_pci_liveupdate_cleanup();
return ret;
+ }
vfio_pci_fill_ids();
@@ -281,6 +287,7 @@ module_init(vfio_pci_init);
static void __exit vfio_pci_cleanup(void)
{
pci_unregister_driver(&vfio_pci_driver);
+ vfio_pci_liveupdate_cleanup();
}
module_exit(vfio_pci_cleanup);
diff --git a/drivers/vfio/pci/vfio_pci_liveupdate.c b/drivers/vfio/pci/vfio_pci_liveupdate.c
new file mode 100644
index 000000000000..b84e63c0357b
--- /dev/null
+++ b/drivers/vfio/pci/vfio_pci_liveupdate.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (c) 2025, Google LLC.
+ * Vipin Sharma <vipinsh@google.com>
+ * David Matlack <dmatlack@google.com>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kho/abi/vfio_pci.h>
+#include <linux/liveupdate.h>
+#include <linux/errno.h>
+
+#include "vfio_pci_priv.h"
+
+static bool vfio_pci_liveupdate_can_preserve(struct liveupdate_file_handler *handler,
+ struct file *file)
+{
+ return false;
+}
+
+static int vfio_pci_liveupdate_preserve(struct liveupdate_file_op_args *args)
+{
+ return -EOPNOTSUPP;
+}
+
+static void vfio_pci_liveupdate_unpreserve(struct liveupdate_file_op_args *args)
+{
+}
+
+static int vfio_pci_liveupdate_retrieve(struct liveupdate_file_op_args *args)
+{
+ return -EOPNOTSUPP;
+}
+
+static void vfio_pci_liveupdate_finish(struct liveupdate_file_op_args *args)
+{
+}
+
+static const struct liveupdate_file_ops vfio_pci_liveupdate_file_ops = {
+ .can_preserve = vfio_pci_liveupdate_can_preserve,
+ .preserve = vfio_pci_liveupdate_preserve,
+ .unpreserve = vfio_pci_liveupdate_unpreserve,
+ .retrieve = vfio_pci_liveupdate_retrieve,
+ .finish = vfio_pci_liveupdate_finish,
+ .owner = THIS_MODULE,
+};
+
+static struct liveupdate_file_handler vfio_pci_liveupdate_fh = {
+ .ops = &vfio_pci_liveupdate_file_ops,
+ .compatible = VFIO_PCI_LUO_FH_COMPATIBLE,
+};
+
+int __init vfio_pci_liveupdate_init(void)
+{
+ if (!liveupdate_enabled())
+ return 0;
+
+ return liveupdate_register_file_handler(&vfio_pci_liveupdate_fh);
+}
+
+void vfio_pci_liveupdate_cleanup(void)
+{
+ if (!liveupdate_enabled())
+ return;
+
+ liveupdate_unregister_file_handler(&vfio_pci_liveupdate_fh);
+}
diff --git a/drivers/vfio/pci/vfio_pci_priv.h b/drivers/vfio/pci/vfio_pci_priv.h
index 27ac280f00b9..68966ec64e51 100644
--- a/drivers/vfio/pci/vfio_pci_priv.h
+++ b/drivers/vfio/pci/vfio_pci_priv.h
@@ -133,4 +133,18 @@ static inline void vfio_pci_dma_buf_move(struct vfio_pci_core_device *vdev,
}
#endif
+#ifdef CONFIG_LIVEUPDATE
+int __init vfio_pci_liveupdate_init(void);
+void vfio_pci_liveupdate_cleanup(void);
+#else
+static inline int vfio_pci_liveupdate_init(void)
+{
+ return 0;
+}
+
+static inline void vfio_pci_liveupdate_cleanup(void)
+{
+}
+#endif /* CONFIG_LIVEUPDATE */
+
#endif
diff --git a/include/linux/kho/abi/vfio_pci.h b/include/linux/kho/abi/vfio_pci.h
new file mode 100644
index 000000000000..37a845eed972
--- /dev/null
+++ b/include/linux/kho/abi/vfio_pci.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Copyright (c) 2025, Google LLC.
+ * Vipin Sharma <vipinsh@google.com>
+ * David Matlack <dmatlack@google.com>
+ */
+
+#ifndef _LINUX_LIVEUPDATE_ABI_VFIO_PCI_H
+#define _LINUX_LIVEUPDATE_ABI_VFIO_PCI_H
+
+/**
+ * DOC: VFIO PCI Live Update ABI
+ *
+ * This header defines the ABI for preserving the state of a VFIO PCI device
+ * files across a kexec reboot using LUO.
+ *
+ * Device metadata is 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
+ * incrementing the version number in the VFIO_PCI_LUO_FH_COMPATIBLE string.
+ */
+
+#define VFIO_PCI_LUO_FH_COMPATIBLE "vfio-pci-v1"
+
+#endif /* _LINUX_LIVEUPDATE_ABI_VFIO_PCI_H */
--
2.53.0.rc1.225.gd81095ad13-goog
^ permalink raw reply [flat|nested] 32+ messages in thread* Re: [PATCH v2 04/22] vfio/pci: Register a file handler with Live Update Orchestrator
2026-01-29 21:24 ` [PATCH v2 04/22] vfio/pci: Register a file handler with Live Update Orchestrator David Matlack
@ 2026-02-06 22:37 ` Yanjun.Zhu
2026-02-06 23:14 ` David Matlack
0 siblings, 1 reply; 32+ messages in thread
From: Yanjun.Zhu @ 2026-02-06 22:37 UTC (permalink / raw)
To: David Matlack, Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Rientjes, Jacob Pan, Jason Gunthorpe,
Jason Gunthorpe, Jonathan Corbet, Josh Hilke, Kevin Tian, kexec,
kvm, Leon Romanovsky, Leon Romanovsky, linux-doc, linux-kernel,
linux-kselftest, linux-mm, linux-pci, Lukas Wunner,
Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu
On 1/29/26 1:24 PM, David Matlack wrote:
> From: Vipin Sharma <vipinsh@google.com>
>
> Register a live update file handler for vfio-pci device files. Add stub
> implementations of all required callbacks so that registration does not
> fail (i.e. to avoid breaking git-bisect).
>
> This file handler will be extended in subsequent commits to enable a
> device bound to vfio-pci to run without interruption while the host is
> going through a kexec Live Update.
>
> Signed-off-by: Vipin Sharma <vipinsh@google.com>
> Co-developed-by: David Matlack <dmatlack@google.com>
> Signed-off-by: David Matlack <dmatlack@google.com>
> ---
> MAINTAINERS | 1 +
> drivers/vfio/pci/Makefile | 1 +
> drivers/vfio/pci/vfio_pci.c | 9 +++-
> drivers/vfio/pci/vfio_pci_liveupdate.c | 69 ++++++++++++++++++++++++++
> drivers/vfio/pci/vfio_pci_priv.h | 14 ++++++
> include/linux/kho/abi/vfio_pci.h | 28 +++++++++++
> 6 files changed, 121 insertions(+), 1 deletion(-)
> create mode 100644 drivers/vfio/pci/vfio_pci_liveupdate.c
> create mode 100644 include/linux/kho/abi/vfio_pci.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index a671e3d4e8be..7d6cdecedb05 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -27520,6 +27520,7 @@ F: Documentation/ABI/testing/debugfs-vfio
> F: Documentation/ABI/testing/sysfs-devices-vfio-dev
> F: Documentation/driver-api/vfio.rst
> F: drivers/vfio/
> +F: include/linux/kho/abi/vfio_pci.h
> F: include/linux/vfio.h
> F: include/linux/vfio_pci_core.h
> F: include/uapi/linux/vfio.h
> diff --git a/drivers/vfio/pci/Makefile b/drivers/vfio/pci/Makefile
> index e0a0757dd1d2..23305ebc418b 100644
> --- a/drivers/vfio/pci/Makefile
> +++ b/drivers/vfio/pci/Makefile
> @@ -7,6 +7,7 @@ obj-$(CONFIG_VFIO_PCI_CORE) += vfio-pci-core.o
>
> vfio-pci-y := vfio_pci.o
> vfio-pci-$(CONFIG_VFIO_PCI_IGD) += vfio_pci_igd.o
> +vfio-pci-$(CONFIG_LIVEUPDATE) += vfio_pci_liveupdate.o
> obj-$(CONFIG_VFIO_PCI) += vfio-pci.o
>
> obj-$(CONFIG_MLX5_VFIO_PCI) += mlx5/
> diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
> index 0c771064c0b8..19e88322af2c 100644
> --- a/drivers/vfio/pci/vfio_pci.c
> +++ b/drivers/vfio/pci/vfio_pci.c
> @@ -258,6 +258,10 @@ static int __init vfio_pci_init(void)
> int ret;
> bool is_disable_vga = true;
>
> + ret = vfio_pci_liveupdate_init();
> + if (ret)
> + return ret;
> +
> #ifdef CONFIG_VFIO_PCI_VGA
> is_disable_vga = disable_vga;
> #endif
> @@ -266,8 +270,10 @@ static int __init vfio_pci_init(void)
>
> /* Register and scan for devices */
> ret = pci_register_driver(&vfio_pci_driver);
> - if (ret)
> + if (ret) {
> + vfio_pci_liveupdate_cleanup();
> return ret;
> + }
>
> vfio_pci_fill_ids();
>
> @@ -281,6 +287,7 @@ module_init(vfio_pci_init);
> static void __exit vfio_pci_cleanup(void)
> {
> pci_unregister_driver(&vfio_pci_driver);
> + vfio_pci_liveupdate_cleanup();
> }
> module_exit(vfio_pci_cleanup);
>
> diff --git a/drivers/vfio/pci/vfio_pci_liveupdate.c b/drivers/vfio/pci/vfio_pci_liveupdate.c
> new file mode 100644
> index 000000000000..b84e63c0357b
> --- /dev/null
> +++ b/drivers/vfio/pci/vfio_pci_liveupdate.c
> @@ -0,0 +1,69 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * Copyright (c) 2025, Google LLC.
> + * Vipin Sharma <vipinsh@google.com>
> + * David Matlack <dmatlack@google.com>
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/kho/abi/vfio_pci.h>
> +#include <linux/liveupdate.h>
> +#include <linux/errno.h>
> +
> +#include "vfio_pci_priv.h"
> +
> +static bool vfio_pci_liveupdate_can_preserve(struct liveupdate_file_handler *handler,
> + struct file *file)
> +{
> + return false;
> +}
> +
> +static int vfio_pci_liveupdate_preserve(struct liveupdate_file_op_args *args)
> +{
> + return -EOPNOTSUPP;
> +}
> +
> +static void vfio_pci_liveupdate_unpreserve(struct liveupdate_file_op_args *args)
> +{
> +}
> +
> +static int vfio_pci_liveupdate_retrieve(struct liveupdate_file_op_args *args)
> +{
> + return -EOPNOTSUPP;
> +}
> +
> +static void vfio_pci_liveupdate_finish(struct liveupdate_file_op_args *args)
> +{
> +}
> +
> +static const struct liveupdate_file_ops vfio_pci_liveupdate_file_ops = {
> + .can_preserve = vfio_pci_liveupdate_can_preserve,
> + .preserve = vfio_pci_liveupdate_preserve,
> + .unpreserve = vfio_pci_liveupdate_unpreserve,
> + .retrieve = vfio_pci_liveupdate_retrieve,
> + .finish = vfio_pci_liveupdate_finish,
> + .owner = THIS_MODULE,
> +};
> +
> +static struct liveupdate_file_handler vfio_pci_liveupdate_fh = {
> + .ops = &vfio_pci_liveupdate_file_ops,
> + .compatible = VFIO_PCI_LUO_FH_COMPATIBLE,
> +};
> +
> +int __init vfio_pci_liveupdate_init(void)
> +{
> + if (!liveupdate_enabled())
> + return 0;
813 int liveupdate_register_file_handler(struct liveupdate_file_handler *fh)
814 {
815 struct liveupdate_file_handler *fh_iter;
816 int err;
817
818 if (!liveupdate_enabled())
819 return -EOPNOTSUPP;
In the function liveupdate_register_file_handler, liveupdate_enabled is also checked.
as such, it is not necessary to check here?
+
+ return liveupdate_register_file_handler(&vfio_pci_liveupdate_fh);
+}
+
+void vfio_pci_liveupdate_cleanup(void)
+{
+ if (!liveupdate_enabled())
+ return;
+
ditto
Zhu Yanjun
> + liveupdate_unregister_file_handler(&vfio_pci_liveupdate_fh);
> +}
> diff --git a/drivers/vfio/pci/vfio_pci_priv.h b/drivers/vfio/pci/vfio_pci_priv.h
> index 27ac280f00b9..68966ec64e51 100644
> --- a/drivers/vfio/pci/vfio_pci_priv.h
> +++ b/drivers/vfio/pci/vfio_pci_priv.h
> @@ -133,4 +133,18 @@ static inline void vfio_pci_dma_buf_move(struct vfio_pci_core_device *vdev,
> }
> #endif
>
> +#ifdef CONFIG_LIVEUPDATE
> +int __init vfio_pci_liveupdate_init(void);
> +void vfio_pci_liveupdate_cleanup(void);
> +#else
> +static inline int vfio_pci_liveupdate_init(void)
> +{
> + return 0;
> +}
> +
> +static inline void vfio_pci_liveupdate_cleanup(void)
> +{
> +}
> +#endif /* CONFIG_LIVEUPDATE */
> +
> #endif
> diff --git a/include/linux/kho/abi/vfio_pci.h b/include/linux/kho/abi/vfio_pci.h
> new file mode 100644
> index 000000000000..37a845eed972
> --- /dev/null
> +++ b/include/linux/kho/abi/vfio_pci.h
> @@ -0,0 +1,28 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +/*
> + * Copyright (c) 2025, Google LLC.
> + * Vipin Sharma <vipinsh@google.com>
> + * David Matlack <dmatlack@google.com>
> + */
> +
> +#ifndef _LINUX_LIVEUPDATE_ABI_VFIO_PCI_H
> +#define _LINUX_LIVEUPDATE_ABI_VFIO_PCI_H
> +
> +/**
> + * DOC: VFIO PCI Live Update ABI
> + *
> + * This header defines the ABI for preserving the state of a VFIO PCI device
> + * files across a kexec reboot using LUO.
> + *
> + * Device metadata is 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
> + * incrementing the version number in the VFIO_PCI_LUO_FH_COMPATIBLE string.
> + */
> +
> +#define VFIO_PCI_LUO_FH_COMPATIBLE "vfio-pci-v1"
> +
> +#endif /* _LINUX_LIVEUPDATE_ABI_VFIO_PCI_H */
^ permalink raw reply [flat|nested] 32+ messages in thread* Re: [PATCH v2 04/22] vfio/pci: Register a file handler with Live Update Orchestrator
2026-02-06 22:37 ` Yanjun.Zhu
@ 2026-02-06 23:14 ` David Matlack
0 siblings, 0 replies; 32+ messages in thread
From: David Matlack @ 2026-02-06 23:14 UTC (permalink / raw)
To: Yanjun.Zhu
Cc: Alex Williamson, Adithya Jayachandran, Alexander Graf,
Alex Mastro, Alistair Popple, Andrew Morton, Ankit Agrawal,
Bjorn Helgaas, Chris Li, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu
On 2026-02-06 02:37 PM, Yanjun.Zhu wrote:
> On 1/29/26 1:24 PM, David Matlack wrote:
> > +int __init vfio_pci_liveupdate_init(void)
> > +{
> > + if (!liveupdate_enabled())
> > + return 0;
> 813 int liveupdate_register_file_handler(struct liveupdate_file_handler *fh)
> 814 {
> 815 struct liveupdate_file_handler *fh_iter;
> 816 int err;
> 817
> 818 if (!liveupdate_enabled())
>
> 819 return -EOPNOTSUPP;
>
> In the function liveupdate_register_file_handler, liveupdate_enabled is also checked.
> as such, it is not necessary to check here?
Yeah that is a bit odd. I see that memfd_luo_init() just checks for
-EOPNOTSUPP. We can do the same thing here.
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 05/22] vfio/pci: Preserve vfio-pci device files across Live Update
2026-01-29 21:24 [PATCH v2 00/22] vfio/pci: Base Live Update support for VFIO device files David Matlack
` (3 preceding siblings ...)
2026-01-29 21:24 ` [PATCH v2 04/22] vfio/pci: Register a file handler with Live Update Orchestrator David Matlack
@ 2026-01-29 21:24 ` David Matlack
2026-01-29 21:24 ` [PATCH v2 06/22] vfio/pci: Retrieve preserved device files after " David Matlack
` (16 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: David Matlack @ 2026-01-29 21:24 UTC (permalink / raw)
To: Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Matlack, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
From: Vipin Sharma <vipinsh@google.com>
Implement the live update file handler callbacks to preserve a vfio-pci
device across a Live Update. Subsequent commits will enable userspace to
then retrieve this file after the Live Update.
Live Update support is scoped only to cdev files (i.e. not
VFIO_GROUP_GET_DEVICE_FD files).
State about each device is serialized into a new ABI struct
vfio_pci_core_device_ser. The contents of this struct are preserved
across the Live Update to the next kernel using a combination of
Kexec-Handover (KHO) to preserve the page(s) holding the struct and the
Live Update Orchestrator (LUO) to preserve the physical address of the
struct.
For now the only contents of struct vfio_pci_core_device_ser the
device's PCI segment number and BDF, so that the device can be uniquely
identified after the Live Update.
Require that userspace disables interrupts on the device prior to
freeze() so that the device does not send any interrupts until new
interrupt handlers have been set up by the next kernel.
Reset the device and restore its state in the freeze() callback. This
ensures the device can be received by the next kernel in a consistent
state. Eventually this will be dropped and the device can be preserved
across in a running state, but that requires further work in VFIO and
the core PCI layer.
Note that LUO holds a reference to this file when it is preserved. So
VFIO is guaranteed that vfio_df_device_last_close() will not be called
on this device no matter what userspace does.
Signed-off-by: Vipin Sharma <vipinsh@google.com>
Co-developed-by: David Matlack <dmatlack@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
drivers/vfio/pci/vfio_pci.c | 2 +-
drivers/vfio/pci/vfio_pci_liveupdate.c | 84 +++++++++++++++++++++++++-
drivers/vfio/pci/vfio_pci_priv.h | 2 +
drivers/vfio/vfio.h | 13 ----
drivers/vfio/vfio_main.c | 10 +--
include/linux/kho/abi/vfio_pci.h | 15 +++++
include/linux/vfio.h | 28 +++++++++
7 files changed, 129 insertions(+), 25 deletions(-)
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index 19e88322af2c..0260afb9492d 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -125,7 +125,7 @@ static int vfio_pci_open_device(struct vfio_device *core_vdev)
return 0;
}
-static const struct vfio_device_ops vfio_pci_ops = {
+const struct vfio_device_ops vfio_pci_ops = {
.name = "vfio-pci",
.init = vfio_pci_core_init_dev,
.release = vfio_pci_core_release_dev,
diff --git a/drivers/vfio/pci/vfio_pci_liveupdate.c b/drivers/vfio/pci/vfio_pci_liveupdate.c
index b84e63c0357b..f01de98f1b75 100644
--- a/drivers/vfio/pci/vfio_pci_liveupdate.c
+++ b/drivers/vfio/pci/vfio_pci_liveupdate.c
@@ -8,25 +8,104 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/kexec_handover.h>
#include <linux/kho/abi/vfio_pci.h>
#include <linux/liveupdate.h>
#include <linux/errno.h>
+#include <linux/vfio.h>
#include "vfio_pci_priv.h"
static bool vfio_pci_liveupdate_can_preserve(struct liveupdate_file_handler *handler,
struct file *file)
{
- return false;
+ struct vfio_device_file *df = to_vfio_device_file(file);
+
+ if (!df)
+ return false;
+
+ /* Live Update support is limited to cdev files. */
+ if (df->group)
+ return false;
+
+ return df->device->ops == &vfio_pci_ops;
}
static int vfio_pci_liveupdate_preserve(struct liveupdate_file_op_args *args)
{
- return -EOPNOTSUPP;
+ struct vfio_device *device = vfio_device_from_file(args->file);
+ struct vfio_pci_core_device_ser *ser;
+ struct vfio_pci_core_device *vdev;
+ struct pci_dev *pdev;
+
+ vdev = container_of(device, struct vfio_pci_core_device, vdev);
+ pdev = vdev->pdev;
+
+ if (IS_ENABLED(CONFIG_VFIO_PCI_ZDEV_KVM))
+ return -EINVAL;
+
+ if (vfio_pci_is_intel_display(pdev))
+ return -EINVAL;
+
+ ser = kho_alloc_preserve(sizeof(*ser));
+ if (IS_ERR(ser))
+ return PTR_ERR(ser);
+
+ ser->bdf = pci_dev_id(pdev);
+ ser->domain = pci_domain_nr(pdev->bus);
+
+ args->serialized_data = virt_to_phys(ser);
+ return 0;
}
static void vfio_pci_liveupdate_unpreserve(struct liveupdate_file_op_args *args)
{
+ kho_unpreserve_free(phys_to_virt(args->serialized_data));
+}
+
+static int vfio_pci_liveupdate_freeze(struct liveupdate_file_op_args *args)
+{
+ struct vfio_device *device = vfio_device_from_file(args->file);
+ struct vfio_pci_core_device *vdev;
+ struct pci_dev *pdev;
+ int ret;
+
+ vdev = container_of(device, struct vfio_pci_core_device, vdev);
+ pdev = vdev->pdev;
+
+ guard(mutex)(&device->dev_set->lock);
+
+ /*
+ * Userspace must disable interrupts on the device prior to freeze so
+ * that the device does not send any interrupts until new interrupt
+ * handlers have been established by the next kernel.
+ */
+ if (vdev->irq_type != VFIO_PCI_NUM_IRQS) {
+ pci_err(pdev, "Freeze failed! Interrupts are still enabled.\n");
+ return -EINVAL;
+ }
+
+ pci_dev_lock(pdev);
+
+ ret = pci_load_saved_state(pdev, vdev->pci_saved_state);
+ if (ret)
+ goto out;
+
+ /*
+ * Reset the device and restore it back to its original state before
+ * handing it to the next kernel.
+ *
+ * Eventually both of these should be dropped and the device should be
+ * kept running with its current state across the Live Update.
+ */
+ if (vdev->reset_works)
+ ret = __pci_reset_function_locked(pdev);
+
+ pci_restore_state(pdev);
+
+out:
+ pci_dev_unlock(pdev);
+ return ret;
}
static int vfio_pci_liveupdate_retrieve(struct liveupdate_file_op_args *args)
@@ -42,6 +121,7 @@ static const struct liveupdate_file_ops vfio_pci_liveupdate_file_ops = {
.can_preserve = vfio_pci_liveupdate_can_preserve,
.preserve = vfio_pci_liveupdate_preserve,
.unpreserve = vfio_pci_liveupdate_unpreserve,
+ .freeze = vfio_pci_liveupdate_freeze,
.retrieve = vfio_pci_liveupdate_retrieve,
.finish = vfio_pci_liveupdate_finish,
.owner = THIS_MODULE,
diff --git a/drivers/vfio/pci/vfio_pci_priv.h b/drivers/vfio/pci/vfio_pci_priv.h
index 68966ec64e51..d3da79b7b03c 100644
--- a/drivers/vfio/pci/vfio_pci_priv.h
+++ b/drivers/vfio/pci/vfio_pci_priv.h
@@ -11,6 +11,8 @@
/* Cap maximum number of ioeventfds per device (arbitrary) */
#define VFIO_PCI_IOEVENTFD_MAX 1000
+extern const struct vfio_device_ops vfio_pci_ops;
+
struct vfio_pci_ioeventfd {
struct list_head next;
struct vfio_pci_core_device *vdev;
diff --git a/drivers/vfio/vfio.h b/drivers/vfio/vfio.h
index 50128da18bca..6b89edbbf174 100644
--- a/drivers/vfio/vfio.h
+++ b/drivers/vfio/vfio.h
@@ -16,17 +16,6 @@ struct iommufd_ctx;
struct iommu_group;
struct vfio_container;
-struct vfio_device_file {
- struct vfio_device *device;
- struct vfio_group *group;
-
- u8 access_granted;
- u32 devid; /* only valid when iommufd is valid */
- spinlock_t kvm_ref_lock; /* protect kvm field */
- struct kvm *kvm;
- struct iommufd_ctx *iommufd; /* protected by struct vfio_device_set::lock */
-};
-
void vfio_device_put_registration(struct vfio_device *device);
bool vfio_device_try_get_registration(struct vfio_device *device);
int vfio_df_open(struct vfio_device_file *df);
@@ -34,8 +23,6 @@ void vfio_df_close(struct vfio_device_file *df);
struct vfio_device_file *
vfio_allocate_device_file(struct vfio_device *device);
-extern const struct file_operations vfio_device_fops;
-
#ifdef CONFIG_VFIO_NOIOMMU
extern bool vfio_noiommu __read_mostly;
#else
diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c
index f7df90c423b4..276f615f0c28 100644
--- a/drivers/vfio/vfio_main.c
+++ b/drivers/vfio/vfio_main.c
@@ -1436,15 +1436,7 @@ const struct file_operations vfio_device_fops = {
.show_fdinfo = vfio_device_show_fdinfo,
#endif
};
-
-static struct vfio_device *vfio_device_from_file(struct file *file)
-{
- struct vfio_device_file *df = file->private_data;
-
- if (file->f_op != &vfio_device_fops)
- return NULL;
- return df->device;
-}
+EXPORT_SYMBOL_GPL(vfio_device_fops);
/**
* vfio_file_is_valid - True if the file is valid vfio file
diff --git a/include/linux/kho/abi/vfio_pci.h b/include/linux/kho/abi/vfio_pci.h
index 37a845eed972..9bf58a2f3820 100644
--- a/include/linux/kho/abi/vfio_pci.h
+++ b/include/linux/kho/abi/vfio_pci.h
@@ -9,6 +9,9 @@
#ifndef _LINUX_LIVEUPDATE_ABI_VFIO_PCI_H
#define _LINUX_LIVEUPDATE_ABI_VFIO_PCI_H
+#include <linux/compiler.h>
+#include <linux/types.h>
+
/**
* DOC: VFIO PCI Live Update ABI
*
@@ -25,4 +28,16 @@
#define VFIO_PCI_LUO_FH_COMPATIBLE "vfio-pci-v1"
+/**
+ * struct vfio_pci_core_device_ser - Serialized state of a single VFIO PCI
+ * device.
+ *
+ * @bdf: The device's PCI bus, device, and function number.
+ * @domain: The device's PCI domain number (segment).
+ */
+struct vfio_pci_core_device_ser {
+ u16 bdf;
+ u16 domain;
+} __packed;
+
#endif /* _LINUX_LIVEUPDATE_ABI_VFIO_PCI_H */
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index e90859956514..9aa1587fea19 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -81,6 +81,34 @@ struct vfio_device {
#endif
};
+struct vfio_device_file {
+ struct vfio_device *device;
+ struct vfio_group *group;
+
+ u8 access_granted;
+ u32 devid; /* only valid when iommufd is valid */
+ spinlock_t kvm_ref_lock; /* protect kvm field */
+ struct kvm *kvm;
+ struct iommufd_ctx *iommufd; /* protected by struct vfio_device_set::lock */
+};
+
+extern const struct file_operations vfio_device_fops;
+
+static inline struct vfio_device_file *to_vfio_device_file(struct file *file)
+{
+ if (file->f_op != &vfio_device_fops)
+ return NULL;
+
+ return file->private_data;
+}
+
+static inline struct vfio_device *vfio_device_from_file(struct file *file)
+{
+ struct vfio_device_file *df = to_vfio_device_file(file);
+
+ return df ? df->device : NULL;
+}
+
/**
* struct vfio_device_ops - VFIO bus driver device callbacks
*
--
2.53.0.rc1.225.gd81095ad13-goog
^ permalink raw reply [flat|nested] 32+ messages in thread* [PATCH v2 06/22] vfio/pci: Retrieve preserved device files after Live Update
2026-01-29 21:24 [PATCH v2 00/22] vfio/pci: Base Live Update support for VFIO device files David Matlack
` (4 preceding siblings ...)
2026-01-29 21:24 ` [PATCH v2 05/22] vfio/pci: Preserve vfio-pci device files across Live Update David Matlack
@ 2026-01-29 21:24 ` David Matlack
2026-01-29 21:24 ` [PATCH v2 07/22] vfio/pci: Notify PCI subsystem about devices preserved across " David Matlack
` (15 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: David Matlack @ 2026-01-29 21:24 UTC (permalink / raw)
To: Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Matlack, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
From: Vipin Sharma <vipinsh@google.com>
Enable userspace to retrieve preserved VFIO device files from VFIO after
a Live Update by implementing the retrieve() and finish() file handler
callbacks.
Use an anonymous inode when creating the file, since the retrieved
device file is not opened through any particular cdev inode, and the
cdev inode does not matter in practice.
For now the retrieved file is functionally equivalent a opening the
corresponding VFIO cdev file. Subsequent commits will leverage the
preserved state associated with the retrieved file to preserve bits of
the device across Live Update.
Signed-off-by: Vipin Sharma <vipinsh@google.com>
Co-developed-by: David Matlack <dmatlack@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
drivers/vfio/device_cdev.c | 21 ++++++---
drivers/vfio/pci/vfio_pci_liveupdate.c | 60 +++++++++++++++++++++++++-
drivers/vfio/vfio_main.c | 13 ++++++
include/linux/vfio.h | 12 ++++++
4 files changed, 98 insertions(+), 8 deletions(-)
diff --git a/drivers/vfio/device_cdev.c b/drivers/vfio/device_cdev.c
index 8ceca24ac136..935f84a35875 100644
--- a/drivers/vfio/device_cdev.c
+++ b/drivers/vfio/device_cdev.c
@@ -16,14 +16,8 @@ void vfio_init_device_cdev(struct vfio_device *device)
device->cdev.owner = THIS_MODULE;
}
-/*
- * device access via the fd opened by this function is blocked until
- * .open_device() is called successfully during BIND_IOMMUFD.
- */
-int vfio_device_fops_cdev_open(struct inode *inode, struct file *filep)
+int __vfio_device_fops_cdev_open(struct vfio_device *device, struct file *filep)
{
- struct vfio_device *device = container_of(inode->i_cdev,
- struct vfio_device, cdev);
struct vfio_device_file *df;
int ret;
@@ -52,6 +46,19 @@ int vfio_device_fops_cdev_open(struct inode *inode, struct file *filep)
vfio_device_put_registration(device);
return ret;
}
+EXPORT_SYMBOL_GPL(__vfio_device_fops_cdev_open);
+
+/*
+ * device access via the fd opened by this function is blocked until
+ * .open_device() is called successfully during BIND_IOMMUFD.
+ */
+int vfio_device_fops_cdev_open(struct inode *inode, struct file *filep)
+{
+ struct vfio_device *device = container_of(inode->i_cdev,
+ struct vfio_device, cdev);
+
+ return __vfio_device_fops_cdev_open(device, filep);
+}
static void vfio_df_get_kvm_safe(struct vfio_device_file *df)
{
diff --git a/drivers/vfio/pci/vfio_pci_liveupdate.c b/drivers/vfio/pci/vfio_pci_liveupdate.c
index f01de98f1b75..7f4117181fd0 100644
--- a/drivers/vfio/pci/vfio_pci_liveupdate.c
+++ b/drivers/vfio/pci/vfio_pci_liveupdate.c
@@ -8,6 +8,8 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/anon_inodes.h>
+#include <linux/file.h>
#include <linux/kexec_handover.h>
#include <linux/kho/abi/vfio_pci.h>
#include <linux/liveupdate.h>
@@ -108,13 +110,68 @@ static int vfio_pci_liveupdate_freeze(struct liveupdate_file_op_args *args)
return ret;
}
+static int match_device(struct device *dev, const void *arg)
+{
+ struct vfio_device *device = container_of(dev, struct vfio_device, device);
+ const struct vfio_pci_core_device_ser *ser = arg;
+ struct pci_dev *pdev;
+
+ pdev = dev_is_pci(device->dev) ? to_pci_dev(device->dev) : NULL;
+ if (!pdev)
+ return false;
+
+ return ser->bdf == pci_dev_id(pdev) && ser->domain == pci_domain_nr(pdev->bus);
+}
+
static int vfio_pci_liveupdate_retrieve(struct liveupdate_file_op_args *args)
{
- return -EOPNOTSUPP;
+ struct vfio_pci_core_device_ser *ser;
+ struct vfio_device *device;
+ struct file *file;
+ int ret;
+
+ ser = phys_to_virt(args->serialized_data);
+
+ device = vfio_find_device(ser, match_device);
+ if (!device)
+ return -ENODEV;
+
+ /*
+ * Simulate opening the character device using an anonymous inode. The
+ * returned file has the same properties as a cdev file (e.g. operations
+ * are blocked until BIND_IOMMUFD is called).
+ */
+ file = anon_inode_getfile_fmode("[vfio-device-liveupdate]",
+ &vfio_device_fops, NULL,
+ O_RDWR, FMODE_PREAD | FMODE_PWRITE);
+ if (IS_ERR(file)) {
+ ret = PTR_ERR(file);
+ goto out;
+ }
+
+ ret = __vfio_device_fops_cdev_open(device, file);
+ if (ret) {
+ fput(file);
+ goto out;
+ }
+
+ args->file = file;
+
+out:
+ /* Drop the reference from vfio_find_device() */
+ put_device(&device->device);
+
+ return ret;
+}
+
+static bool vfio_pci_liveupdate_can_finish(struct liveupdate_file_op_args *args)
+{
+ return args->retrieved;
}
static void vfio_pci_liveupdate_finish(struct liveupdate_file_op_args *args)
{
+ kho_restore_free(phys_to_virt(args->serialized_data));
}
static const struct liveupdate_file_ops vfio_pci_liveupdate_file_ops = {
@@ -123,6 +180,7 @@ static const struct liveupdate_file_ops vfio_pci_liveupdate_file_ops = {
.unpreserve = vfio_pci_liveupdate_unpreserve,
.freeze = vfio_pci_liveupdate_freeze,
.retrieve = vfio_pci_liveupdate_retrieve,
+ .can_finish = vfio_pci_liveupdate_can_finish,
.finish = vfio_pci_liveupdate_finish,
.owner = THIS_MODULE,
};
diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c
index 276f615f0c28..89c5feef75d5 100644
--- a/drivers/vfio/vfio_main.c
+++ b/drivers/vfio/vfio_main.c
@@ -13,6 +13,7 @@
#include <linux/cdev.h>
#include <linux/compat.h>
#include <linux/device.h>
+#include <linux/device/class.h>
#include <linux/fs.h>
#include <linux/idr.h>
#include <linux/iommu.h>
@@ -1758,6 +1759,18 @@ int vfio_dma_rw(struct vfio_device *device, dma_addr_t iova, void *data,
}
EXPORT_SYMBOL(vfio_dma_rw);
+struct vfio_device *vfio_find_device(const void *data, device_match_t match)
+{
+ struct device *device;
+
+ device = class_find_device(vfio.device_class, NULL, data, match);
+ if (!device)
+ return NULL;
+
+ return container_of(device, struct vfio_device, device);
+}
+EXPORT_SYMBOL_GPL(vfio_find_device);
+
/*
* Module/class support
*/
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index 9aa1587fea19..dc592dc00f89 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -419,4 +419,16 @@ int vfio_virqfd_enable(void *opaque, int (*handler)(void *, void *),
void vfio_virqfd_disable(struct virqfd **pvirqfd);
void vfio_virqfd_flush_thread(struct virqfd **pvirqfd);
+#if IS_ENABLED(CONFIG_VFIO_DEVICE_CDEV)
+int __vfio_device_fops_cdev_open(struct vfio_device *device, struct file *filep);
+#else
+static inline int __vfio_device_fops_cdev_open(struct vfio_device *device,
+ struct file *filep)
+{
+ return -EOPNOTSUPP;
+}
+#endif /* IS_ENABLED(CONFIG_VFIO_DEVICE_CDEV) */
+
+struct vfio_device *vfio_find_device(const void *data, device_match_t match);
+
#endif /* VFIO_H */
--
2.53.0.rc1.225.gd81095ad13-goog
^ permalink raw reply [flat|nested] 32+ messages in thread* [PATCH v2 07/22] vfio/pci: Notify PCI subsystem about devices preserved across Live Update
2026-01-29 21:24 [PATCH v2 00/22] vfio/pci: Base Live Update support for VFIO device files David Matlack
` (5 preceding siblings ...)
2026-01-29 21:24 ` [PATCH v2 06/22] vfio/pci: Retrieve preserved device files after " David Matlack
@ 2026-01-29 21:24 ` David Matlack
2026-01-29 21:24 ` [PATCH v2 08/22] vfio: Enforce preserved devices are retrieved via LIVEUPDATE_SESSION_RETRIEVE_FD David Matlack
` (14 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: David Matlack @ 2026-01-29 21:24 UTC (permalink / raw)
To: Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Matlack, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
Notify the PCI subsystem about devices vfio-pci is preserving across
Live Update by registering the vfio-pci liveupdate file handler with the
PCI subsystem's FLB handler.
Notably this will ensure that devices preserved through vfio-pci will
have their PCI bus numbers preserved across Live Update, allowing VFIO
to use BDF as a key to identify the device across the Live Update and
(in the future) allow the device to continue DMA operations across
the Live Update.
This also enables VFIO to detect that a device was preserved before
userspace first retrieves the file from it, which will be used in
subsequent commits.
Signed-off-by: David Matlack <dmatlack@google.com>
---
drivers/vfio/pci/vfio_pci_liveupdate.c | 25 ++++++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/drivers/vfio/pci/vfio_pci_liveupdate.c b/drivers/vfio/pci/vfio_pci_liveupdate.c
index 7f4117181fd0..ad915352303f 100644
--- a/drivers/vfio/pci/vfio_pci_liveupdate.c
+++ b/drivers/vfio/pci/vfio_pci_liveupdate.c
@@ -53,6 +53,8 @@ static int vfio_pci_liveupdate_preserve(struct liveupdate_file_op_args *args)
if (IS_ERR(ser))
return PTR_ERR(ser);
+ pci_liveupdate_outgoing_preserve(pdev);
+
ser->bdf = pci_dev_id(pdev);
ser->domain = pci_domain_nr(pdev->bus);
@@ -62,6 +64,9 @@ static int vfio_pci_liveupdate_preserve(struct liveupdate_file_op_args *args)
static void vfio_pci_liveupdate_unpreserve(struct liveupdate_file_op_args *args)
{
+ struct vfio_device *device = vfio_device_from_file(args->file);
+
+ pci_liveupdate_outgoing_unpreserve(to_pci_dev(device->dev));
kho_unpreserve_free(phys_to_virt(args->serialized_data));
}
@@ -171,6 +176,9 @@ static bool vfio_pci_liveupdate_can_finish(struct liveupdate_file_op_args *args)
static void vfio_pci_liveupdate_finish(struct liveupdate_file_op_args *args)
{
+ struct vfio_device *device = vfio_device_from_file(args->file);
+
+ pci_liveupdate_incoming_finish(to_pci_dev(device->dev));
kho_restore_free(phys_to_virt(args->serialized_data));
}
@@ -192,10 +200,24 @@ static struct liveupdate_file_handler vfio_pci_liveupdate_fh = {
int __init vfio_pci_liveupdate_init(void)
{
+ int ret;
+
if (!liveupdate_enabled())
return 0;
- return liveupdate_register_file_handler(&vfio_pci_liveupdate_fh);
+ ret = liveupdate_register_file_handler(&vfio_pci_liveupdate_fh);
+ if (ret)
+ return ret;
+
+ ret = pci_liveupdate_register_fh(&vfio_pci_liveupdate_fh);
+ if (ret)
+ goto error;
+
+ return 0;
+
+error:
+ liveupdate_unregister_file_handler(&vfio_pci_liveupdate_fh);
+ return ret;
}
void vfio_pci_liveupdate_cleanup(void)
@@ -203,5 +225,6 @@ void vfio_pci_liveupdate_cleanup(void)
if (!liveupdate_enabled())
return;
+ WARN_ON_ONCE(pci_liveupdate_unregister_fh(&vfio_pci_liveupdate_fh));
liveupdate_unregister_file_handler(&vfio_pci_liveupdate_fh);
}
--
2.53.0.rc1.225.gd81095ad13-goog
^ permalink raw reply [flat|nested] 32+ messages in thread* [PATCH v2 08/22] vfio: Enforce preserved devices are retrieved via LIVEUPDATE_SESSION_RETRIEVE_FD
2026-01-29 21:24 [PATCH v2 00/22] vfio/pci: Base Live Update support for VFIO device files David Matlack
` (6 preceding siblings ...)
2026-01-29 21:24 ` [PATCH v2 07/22] vfio/pci: Notify PCI subsystem about devices preserved across " David Matlack
@ 2026-01-29 21:24 ` David Matlack
2026-01-29 21:24 ` [PATCH v2 09/22] vfio/pci: Store incoming Live Update state in struct vfio_pci_core_device David Matlack
` (13 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: David Matlack @ 2026-01-29 21:24 UTC (permalink / raw)
To: Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Matlack, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
Enforce that files for incoming (preserved by previous kernel) VFIO
devices are retrieved via LIVEUPDATE_SESSION_RETRIEVE_FD rather than by
opening the corresponding VFIO character device or via
VFIO_GROUP_GET_DEVICE_FD.
Both of these methods would result in VFIO initializing the device
without access to the preserved state of the device passed by the
previous kernel.
Signed-off-by: David Matlack <dmatlack@google.com>
---
drivers/vfio/device_cdev.c | 4 ++++
drivers/vfio/group.c | 9 +++++++++
include/linux/vfio.h | 18 ++++++++++++++++++
3 files changed, 31 insertions(+)
diff --git a/drivers/vfio/device_cdev.c b/drivers/vfio/device_cdev.c
index 935f84a35875..355447e2add3 100644
--- a/drivers/vfio/device_cdev.c
+++ b/drivers/vfio/device_cdev.c
@@ -57,6 +57,10 @@ int vfio_device_fops_cdev_open(struct inode *inode, struct file *filep)
struct vfio_device *device = container_of(inode->i_cdev,
struct vfio_device, cdev);
+ /* Device file must be retrieved via LIVEUPDATE_SESSION_RETRIEVE_FD */
+ if (vfio_liveupdate_incoming_is_preserved(device))
+ return -EBUSY;
+
return __vfio_device_fops_cdev_open(device, filep);
}
diff --git a/drivers/vfio/group.c b/drivers/vfio/group.c
index d47ffada6912..63fc4d656215 100644
--- a/drivers/vfio/group.c
+++ b/drivers/vfio/group.c
@@ -311,6 +311,15 @@ static int vfio_group_ioctl_get_device_fd(struct vfio_group *group,
if (IS_ERR(device))
return PTR_ERR(device);
+ /*
+ * This device was preserved across a Live Update. Accessing it via
+ * VFIO_GROUP_GET_DEVICE_FD is not allowed.
+ */
+ if (vfio_liveupdate_incoming_is_preserved(device)) {
+ vfio_device_put_registration(device);
+ return -EBUSY;
+ }
+
fd = FD_ADD(O_CLOEXEC, vfio_device_open_file(device));
if (fd < 0)
vfio_device_put_registration(device);
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index dc592dc00f89..0921847b18b5 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -16,6 +16,7 @@
#include <linux/cdev.h>
#include <uapi/linux/vfio.h>
#include <linux/iova_bitmap.h>
+#include <linux/pci.h>
struct kvm;
struct iommufd_ctx;
@@ -431,4 +432,21 @@ static inline int __vfio_device_fops_cdev_open(struct vfio_device *device,
struct vfio_device *vfio_find_device(const void *data, device_match_t match);
+#ifdef CONFIG_LIVEUPDATE
+static inline bool vfio_liveupdate_incoming_is_preserved(struct vfio_device *device)
+{
+ struct device *d = device->dev;
+
+ if (dev_is_pci(d))
+ return to_pci_dev(d)->liveupdate_incoming;
+
+ return false;
+}
+#else
+static inline bool vfio_liveupdate_incoming_is_preserved(struct vfio_device *device)
+{
+ return false;
+}
+#endif
+
#endif /* VFIO_H */
--
2.53.0.rc1.225.gd81095ad13-goog
^ permalink raw reply [flat|nested] 32+ messages in thread* [PATCH v2 09/22] vfio/pci: Store incoming Live Update state in struct vfio_pci_core_device
2026-01-29 21:24 [PATCH v2 00/22] vfio/pci: Base Live Update support for VFIO device files David Matlack
` (7 preceding siblings ...)
2026-01-29 21:24 ` [PATCH v2 08/22] vfio: Enforce preserved devices are retrieved via LIVEUPDATE_SESSION_RETRIEVE_FD David Matlack
@ 2026-01-29 21:24 ` David Matlack
2026-01-29 21:24 ` [PATCH v2 10/22] vfio/pci: Skip reset of preserved device after Live Update David Matlack
` (12 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: David Matlack @ 2026-01-29 21:24 UTC (permalink / raw)
To: Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Matlack, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
Stash a pointer to a device's incoming Live Updated state in struct
vfio_pci_core_device. This will enable subsequent commits to use the
preserved state when initializing the device.
To enable VFIO to safely access this pointer during device enablement,
require that the device is fully enabled before returning true from
can_finish(). This is synchronized by vfio_pci_core.c setting
vdev->liveupdate_incoming_state to NULL under dev_set lock once it's
done using it.
Signed-off-by: David Matlack <dmatlack@google.com>
---
drivers/vfio/pci/vfio_pci_core.c | 2 +-
drivers/vfio/pci/vfio_pci_liveupdate.c | 17 ++++++++++++++++-
include/linux/vfio_pci_core.h | 1 +
3 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
index 3a11e6f450f7..b01b94d81e28 100644
--- a/drivers/vfio/pci/vfio_pci_core.c
+++ b/drivers/vfio/pci/vfio_pci_core.c
@@ -569,7 +569,7 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev)
if (!vfio_vga_disabled() && vfio_pci_is_vga(pdev))
vdev->has_vga = true;
-
+ vdev->liveupdate_incoming_state = NULL;
return 0;
out_free_zdev:
diff --git a/drivers/vfio/pci/vfio_pci_liveupdate.c b/drivers/vfio/pci/vfio_pci_liveupdate.c
index ad915352303f..1ad7379c70c4 100644
--- a/drivers/vfio/pci/vfio_pci_liveupdate.c
+++ b/drivers/vfio/pci/vfio_pci_liveupdate.c
@@ -131,6 +131,7 @@ static int match_device(struct device *dev, const void *arg)
static int vfio_pci_liveupdate_retrieve(struct liveupdate_file_op_args *args)
{
struct vfio_pci_core_device_ser *ser;
+ struct vfio_pci_core_device *vdev;
struct vfio_device *device;
struct file *file;
int ret;
@@ -160,6 +161,9 @@ static int vfio_pci_liveupdate_retrieve(struct liveupdate_file_op_args *args)
goto out;
}
+ vdev = container_of(device, struct vfio_pci_core_device, vdev);
+ vdev->liveupdate_incoming_state = ser;
+
args->file = file;
out:
@@ -171,7 +175,18 @@ static int vfio_pci_liveupdate_retrieve(struct liveupdate_file_op_args *args)
static bool vfio_pci_liveupdate_can_finish(struct liveupdate_file_op_args *args)
{
- return args->retrieved;
+ struct vfio_pci_core_device *vdev;
+ struct vfio_device *device;
+
+ if (!args->retrieved)
+ return false;
+
+ device = vfio_device_from_file(args->file);
+ vdev = container_of(device, struct vfio_pci_core_device, vdev);
+
+ /* Check that vdev->liveupdate_incoming_state is no longer in use. */
+ guard(mutex)(&device->dev_set->lock);
+ return !vdev->liveupdate_incoming_state;
}
static void vfio_pci_liveupdate_finish(struct liveupdate_file_op_args *args)
diff --git a/include/linux/vfio_pci_core.h b/include/linux/vfio_pci_core.h
index 1ac86896875c..350c30f84a13 100644
--- a/include/linux/vfio_pci_core.h
+++ b/include/linux/vfio_pci_core.h
@@ -143,6 +143,7 @@ struct vfio_pci_core_device {
struct notifier_block nb;
struct rw_semaphore memory_lock;
struct list_head dmabufs;
+ struct vfio_pci_core_device_ser *liveupdate_incoming_state;
};
enum vfio_pci_io_width {
--
2.53.0.rc1.225.gd81095ad13-goog
^ permalink raw reply [flat|nested] 32+ messages in thread* [PATCH v2 10/22] vfio/pci: Skip reset of preserved device after Live Update
2026-01-29 21:24 [PATCH v2 00/22] vfio/pci: Base Live Update support for VFIO device files David Matlack
` (8 preceding siblings ...)
2026-01-29 21:24 ` [PATCH v2 09/22] vfio/pci: Store incoming Live Update state in struct vfio_pci_core_device David Matlack
@ 2026-01-29 21:24 ` David Matlack
2026-01-29 22:21 ` Jacob Pan
2026-01-29 21:24 ` [PATCH v2 11/22] docs: liveupdate: Document VFIO device file preservation David Matlack
` (11 subsequent siblings)
21 siblings, 1 reply; 32+ messages in thread
From: David Matlack @ 2026-01-29 21:24 UTC (permalink / raw)
To: Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Matlack, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
From: Vipin Sharma <vipinsh@google.com>
Do not reset the device when a Live Update preserved vfio-pci device is
retrieved and first enabled. vfio_pci_liveupdate_freeze() guarantees the
device is reset prior to Live Update, so there's no reason to reset it
again after Live Update.
Since VFIO normally uses the initial reset to detect if the device
supports function resets, pass that from the previous kernel via
struct vfio_pci_core_dev_ser.
Signed-off-by: Vipin Sharma <vipinsh@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
drivers/vfio/pci/vfio_pci_core.c | 22 +++++++++++++++++-----
drivers/vfio/pci/vfio_pci_liveupdate.c | 1 +
include/linux/kho/abi/vfio_pci.h | 2 ++
include/linux/vfio_pci_core.h | 1 +
4 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
index b01b94d81e28..c9f73f597797 100644
--- a/drivers/vfio/pci/vfio_pci_core.c
+++ b/drivers/vfio/pci/vfio_pci_core.c
@@ -515,12 +515,24 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev)
if (ret)
goto out_power;
- /* If reset fails because of the device lock, fail this path entirely */
- ret = pci_try_reset_function(pdev);
- if (ret == -EAGAIN)
- goto out_disable_device;
+ if (vdev->liveupdate_incoming_state) {
+ /*
+ * This device was preserved by the previous kernel across a
+ * Live Update, so it does not need to be reset.
+ */
+ vdev->reset_works = vdev->liveupdate_incoming_state->reset_works;
+ } else {
+ /*
+ * If reset fails because of the device lock, fail this path
+ * entirely.
+ */
+ ret = pci_try_reset_function(pdev);
+ if (ret == -EAGAIN)
+ goto out_disable_device;
+
+ vdev->reset_works = !ret;
+ }
- vdev->reset_works = !ret;
pci_save_state(pdev);
vdev->pci_saved_state = pci_store_saved_state(pdev);
if (!vdev->pci_saved_state)
diff --git a/drivers/vfio/pci/vfio_pci_liveupdate.c b/drivers/vfio/pci/vfio_pci_liveupdate.c
index 1ad7379c70c4..c52d6bdb455f 100644
--- a/drivers/vfio/pci/vfio_pci_liveupdate.c
+++ b/drivers/vfio/pci/vfio_pci_liveupdate.c
@@ -57,6 +57,7 @@ static int vfio_pci_liveupdate_preserve(struct liveupdate_file_op_args *args)
ser->bdf = pci_dev_id(pdev);
ser->domain = pci_domain_nr(pdev->bus);
+ ser->reset_works = vdev->reset_works;
args->serialized_data = virt_to_phys(ser);
return 0;
diff --git a/include/linux/kho/abi/vfio_pci.h b/include/linux/kho/abi/vfio_pci.h
index 9bf58a2f3820..6c3d3c6dfc09 100644
--- a/include/linux/kho/abi/vfio_pci.h
+++ b/include/linux/kho/abi/vfio_pci.h
@@ -34,10 +34,12 @@
*
* @bdf: The device's PCI bus, device, and function number.
* @domain: The device's PCI domain number (segment).
+ * @reset_works: Non-zero if the device supports function resets.
*/
struct vfio_pci_core_device_ser {
u16 bdf;
u16 domain;
+ u8 reset_works;
} __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 350c30f84a13..95835298e29e 100644
--- a/include/linux/vfio_pci_core.h
+++ b/include/linux/vfio_pci_core.h
@@ -16,6 +16,7 @@
#include <linux/types.h>
#include <linux/uuid.h>
#include <linux/notifier.h>
+#include <linux/kho/abi/vfio_pci.h>
#ifndef VFIO_PCI_CORE_H
#define VFIO_PCI_CORE_H
--
2.53.0.rc1.225.gd81095ad13-goog
^ permalink raw reply [flat|nested] 32+ messages in thread* Re: [PATCH v2 10/22] vfio/pci: Skip reset of preserved device after Live Update
2026-01-29 21:24 ` [PATCH v2 10/22] vfio/pci: Skip reset of preserved device after Live Update David Matlack
@ 2026-01-29 22:21 ` Jacob Pan
2026-01-29 22:33 ` David Matlack
0 siblings, 1 reply; 32+ messages in thread
From: Jacob Pan @ 2026-01-29 22:21 UTC (permalink / raw)
To: David Matlack
Cc: Alex Williamson, Adithya Jayachandran, Alexander Graf,
Alex Mastro, Alistair Popple, Andrew Morton, Ankit Agrawal,
Bjorn Helgaas, Chris Li, David Rientjes, Jason Gunthorpe,
Jason Gunthorpe, Jonathan Corbet, Josh Hilke, Kevin Tian, kexec,
kvm, Leon Romanovsky, Leon Romanovsky, linux-doc, linux-kernel,
linux-kselftest, linux-mm, linux-pci, Lukas Wunner,
Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
Hi David,
On Thu, 29 Jan 2026 21:24:57 +0000
David Matlack <dmatlack@google.com> wrote:
> From: Vipin Sharma <vipinsh@google.com>
>
> Do not reset the device when a Live Update preserved vfio-pci device
> is retrieved and first enabled. vfio_pci_liveupdate_freeze()
> guarantees the device is reset prior to Live Update, so there's no
> reason to reset it again after Live Update.
>
> Since VFIO normally uses the initial reset to detect if the device
> supports function resets, pass that from the previous kernel via
> struct vfio_pci_core_dev_ser.
>
> Signed-off-by: Vipin Sharma <vipinsh@google.com>
> Signed-off-by: David Matlack <dmatlack@google.com>
> ---
> drivers/vfio/pci/vfio_pci_core.c | 22 +++++++++++++++++-----
> drivers/vfio/pci/vfio_pci_liveupdate.c | 1 +
> include/linux/kho/abi/vfio_pci.h | 2 ++
> include/linux/vfio_pci_core.h | 1 +
> 4 files changed, 21 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/vfio/pci/vfio_pci_core.c
> b/drivers/vfio/pci/vfio_pci_core.c index b01b94d81e28..c9f73f597797
> 100644 --- a/drivers/vfio/pci/vfio_pci_core.c
> +++ b/drivers/vfio/pci/vfio_pci_core.c
> @@ -515,12 +515,24 @@ int vfio_pci_core_enable(struct
> vfio_pci_core_device *vdev) if (ret)
> goto out_power;
>
> - /* If reset fails because of the device lock, fail this path
> entirely */
> - ret = pci_try_reset_function(pdev);
> - if (ret == -EAGAIN)
> - goto out_disable_device;
> + if (vdev->liveupdate_incoming_state) {
> + /*
> + * This device was preserved by the previous kernel
> across a
> + * Live Update, so it does not need to be reset.
> + */
> + vdev->reset_works =
> vdev->liveupdate_incoming_state->reset_works;
Just wondering what happened to skipping the bus master clearing. I
understand this version does not preserve the device itself yet; I’m
just curious whether there were specific difficulties that led to
dropping the earlier patch which skipped clearing bus master.
> + } else {
> + /*
> + * If reset fails because of the device lock, fail
> this path
> + * entirely.
> + */
> + ret = pci_try_reset_function(pdev);
> + if (ret == -EAGAIN)
> + goto out_disable_device;
> +
> + vdev->reset_works = !ret;
> + }
>
> - vdev->reset_works = !ret;
> pci_save_state(pdev);
> vdev->pci_saved_state = pci_store_saved_state(pdev);
> if (!vdev->pci_saved_state)
> diff --git a/drivers/vfio/pci/vfio_pci_liveupdate.c
> b/drivers/vfio/pci/vfio_pci_liveupdate.c index
> 1ad7379c70c4..c52d6bdb455f 100644 ---
> a/drivers/vfio/pci/vfio_pci_liveupdate.c +++
> b/drivers/vfio/pci/vfio_pci_liveupdate.c @@ -57,6 +57,7 @@ static int
> vfio_pci_liveupdate_preserve(struct liveupdate_file_op_args *args)
> ser->bdf = pci_dev_id(pdev);
> ser->domain = pci_domain_nr(pdev->bus);
> + ser->reset_works = vdev->reset_works;
>
> args->serialized_data = virt_to_phys(ser);
> return 0;
> diff --git a/include/linux/kho/abi/vfio_pci.h
> b/include/linux/kho/abi/vfio_pci.h index 9bf58a2f3820..6c3d3c6dfc09
> 100644 --- a/include/linux/kho/abi/vfio_pci.h
> +++ b/include/linux/kho/abi/vfio_pci.h
> @@ -34,10 +34,12 @@
> *
> * @bdf: The device's PCI bus, device, and function number.
> * @domain: The device's PCI domain number (segment).
> + * @reset_works: Non-zero if the device supports function resets.
> */
> struct vfio_pci_core_device_ser {
> u16 bdf;
> u16 domain;
> + u8 reset_works;
> } __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 350c30f84a13..95835298e29e
> 100644 --- a/include/linux/vfio_pci_core.h
> +++ b/include/linux/vfio_pci_core.h
> @@ -16,6 +16,7 @@
> #include <linux/types.h>
> #include <linux/uuid.h>
> #include <linux/notifier.h>
> +#include <linux/kho/abi/vfio_pci.h>
>
> #ifndef VFIO_PCI_CORE_H
> #define VFIO_PCI_CORE_H
^ permalink raw reply [flat|nested] 32+ messages in thread* Re: [PATCH v2 10/22] vfio/pci: Skip reset of preserved device after Live Update
2026-01-29 22:21 ` Jacob Pan
@ 2026-01-29 22:33 ` David Matlack
2026-01-30 0:31 ` Jacob Pan
0 siblings, 1 reply; 32+ messages in thread
From: David Matlack @ 2026-01-29 22:33 UTC (permalink / raw)
To: Jacob Pan
Cc: Alex Williamson, Adithya Jayachandran, Alexander Graf,
Alex Mastro, Alistair Popple, Andrew Morton, Ankit Agrawal,
Bjorn Helgaas, Chris Li, David Rientjes, Jason Gunthorpe,
Jason Gunthorpe, Jonathan Corbet, Josh Hilke, Kevin Tian, kexec,
kvm, Leon Romanovsky, Leon Romanovsky, linux-doc, linux-kernel,
linux-kselftest, linux-mm, linux-pci, Lukas Wunner,
Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
On 2026-01-29 02:21 PM, Jacob Pan wrote:
> On Thu, 29 Jan 2026 21:24:57 +0000 David Matlack <dmatlack@google.com> wrote:
> > diff --git a/drivers/vfio/pci/vfio_pci_core.c
> > b/drivers/vfio/pci/vfio_pci_core.c index b01b94d81e28..c9f73f597797
> > 100644 --- a/drivers/vfio/pci/vfio_pci_core.c
> > +++ b/drivers/vfio/pci/vfio_pci_core.c
> > @@ -515,12 +515,24 @@ int vfio_pci_core_enable(struct
> > vfio_pci_core_device *vdev) if (ret)
> > goto out_power;
> >
> > - /* If reset fails because of the device lock, fail this path
> > entirely */
> > - ret = pci_try_reset_function(pdev);
> > - if (ret == -EAGAIN)
> > - goto out_disable_device;
> > + if (vdev->liveupdate_incoming_state) {
> > + /*
> > + * This device was preserved by the previous kernel
> > across a
> > + * Live Update, so it does not need to be reset.
> > + */
> > + vdev->reset_works =
> > vdev->liveupdate_incoming_state->reset_works;
>
> Just wondering what happened to skipping the bus master clearing. I
> understand this version does not preserve the device itself yet; I’m
> just curious whether there were specific difficulties that led to
> dropping the earlier patch which skipped clearing bus master.
Hi Jacob,
There's several places where bus master gets cleared that we need to
eventually eliminate to fully preserve the device.
1. vfio_pci_liveupdate_freeze() clears it during shutdown when it
restores vdev->pci_saved_state.
2. pci_device_shutdown() clears it during shutdown.
3. vfio_pci_core_enable() clears it when the preserved device file
is bound to an iommufd after the Live Update (in
vfio_pci_core_enable()).
I think it would be safe to skip (3) in this series, since that's very
similar to how this series skips resets during vfio_pci_core_enable()
for preserved devices.
But I don't think it would be safe to skip (1) or (2) until the attached
iommufd is fully preserved.
If you are just asking about (3) then I agree it could be skipped and I
can include that in the next version.
^ permalink raw reply [flat|nested] 32+ messages in thread* Re: [PATCH v2 10/22] vfio/pci: Skip reset of preserved device after Live Update
2026-01-29 22:33 ` David Matlack
@ 2026-01-30 0:31 ` Jacob Pan
0 siblings, 0 replies; 32+ messages in thread
From: Jacob Pan @ 2026-01-30 0:31 UTC (permalink / raw)
To: David Matlack
Cc: Alex Williamson, Adithya Jayachandran, Alexander Graf,
Alex Mastro, Alistair Popple, Andrew Morton, Ankit Agrawal,
Bjorn Helgaas, Chris Li, David Rientjes, Jason Gunthorpe,
Jason Gunthorpe, Jonathan Corbet, Josh Hilke, Kevin Tian, kexec,
kvm, Leon Romanovsky, Leon Romanovsky, linux-doc, linux-kernel,
linux-kselftest, linux-mm, linux-pci, Lukas Wunner,
Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
Hi David,
On Thu, 29 Jan 2026 22:33:13 +0000
David Matlack <dmatlack@google.com> wrote:
> On 2026-01-29 02:21 PM, Jacob Pan wrote:
> > On Thu, 29 Jan 2026 21:24:57 +0000 David Matlack
> > <dmatlack@google.com> wrote:
>
> > > diff --git a/drivers/vfio/pci/vfio_pci_core.c
> > > b/drivers/vfio/pci/vfio_pci_core.c index
> > > b01b94d81e28..c9f73f597797 100644 ---
> > > a/drivers/vfio/pci/vfio_pci_core.c +++
> > > b/drivers/vfio/pci/vfio_pci_core.c @@ -515,12 +515,24 @@ int
> > > vfio_pci_core_enable(struct vfio_pci_core_device *vdev) if (ret)
> > > goto out_power;
> > >
> > > - /* If reset fails because of the device lock, fail this
> > > path entirely */
> > > - ret = pci_try_reset_function(pdev);
> > > - if (ret == -EAGAIN)
> > > - goto out_disable_device;
> > > + if (vdev->liveupdate_incoming_state) {
> > > + /*
> > > + * This device was preserved by the previous
> > > kernel across a
> > > + * Live Update, so it does not need to be reset.
> > > + */
> > > + vdev->reset_works =
> > > vdev->liveupdate_incoming_state->reset_works;
> >
> > Just wondering what happened to skipping the bus master clearing. I
> > understand this version does not preserve the device itself yet; I’m
> > just curious whether there were specific difficulties that led to
> > dropping the earlier patch which skipped clearing bus master.
>
> Hi Jacob,
>
> There's several places where bus master gets cleared that we need to
> eventually eliminate to fully preserve the device.
>
> 1. vfio_pci_liveupdate_freeze() clears it during shutdown when it
> restores vdev->pci_saved_state.
> 2. pci_device_shutdown() clears it during shutdown.
> 3. vfio_pci_core_enable() clears it when the preserved device file
> is bound to an iommufd after the Live Update (in
> vfio_pci_core_enable()).
>
> I think it would be safe to skip (3) in this series, since that's very
> similar to how this series skips resets during vfio_pci_core_enable()
> for preserved devices.
>
> But I don't think it would be safe to skip (1) or (2) until the
> attached iommufd is fully preserved.
>
> If you are just asking about (3) then I agree it could be skipped and
> I can include that in the next version.
I was just asking about (3) and trying to understand the asymmetric
handling compared to reset. I don’t have a strong preference since this
is temporary—thanks for the explanation.
I’ve been testing my noiommu cdev patches on top of yours, and so far
they behave the same as with a real IOMMU. As you noted, however, final
device preservation still depends on iommufd.
^ permalink raw reply [flat|nested] 32+ messages in thread
* [PATCH v2 11/22] docs: liveupdate: Document VFIO device file preservation
2026-01-29 21:24 [PATCH v2 00/22] vfio/pci: Base Live Update support for VFIO device files David Matlack
` (9 preceding siblings ...)
2026-01-29 21:24 ` [PATCH v2 10/22] vfio/pci: Skip reset of preserved device after Live Update David Matlack
@ 2026-01-29 21:24 ` David Matlack
2026-01-29 21:24 ` [PATCH v2 12/22] selftests/liveupdate: Move luo_test_utils.* into a reusable library David Matlack
` (10 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: David Matlack @ 2026-01-29 21:24 UTC (permalink / raw)
To: Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Matlack, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
Add documentation for preserving VFIO device files across a Live Update,
as well as some generic file preservation documentation. This
documentation will be extended in the future as new types of files are
supported and new dependency/ordering requirements are added.
Signed-off-by: David Matlack <dmatlack@google.com>
---
Documentation/userspace-api/liveupdate.rst | 144 +++++++++++++++++++++
1 file changed, 144 insertions(+)
diff --git a/Documentation/userspace-api/liveupdate.rst b/Documentation/userspace-api/liveupdate.rst
index 41c0473e4f16..dbf1e4aeddd7 100644
--- a/Documentation/userspace-api/liveupdate.rst
+++ b/Documentation/userspace-api/liveupdate.rst
@@ -14,6 +14,150 @@ ioctl uAPI
===========
.. kernel-doc:: include/uapi/linux/liveupdate.h
+File Preservation
+=================
+
+Files can be preserved across Live Update in sessions. Since only one process
+can open /dev/liveupdate, sessions must be created by a centralized process
+(e.g. "luod") and then passed via UDS to lower privilege processes (e.g. VMMs)
+for them to preserve their own files.
+
+luod::
+
+ luo_fd = open("/dev/liveupdate", ...);
+
+ ...
+
+ // Create a new session with the given name.
+ struct liveupdate_ioctl_create_session arg = {
+ .size = sizeof(arg),
+ .name = SESSION_NAME,
+ };
+ ioctl(luo_fd, LIVEUPDATE_IOCTL_CREATE_SESSION, &arg);
+
+ // Send session_fd to the VMM over UDS.
+ send_session_fd(..., arg.fd);
+
+VMM::
+
+ // Receive the newly created session from luod over UDS
+ session_fd = create_session(SESSION_NAME);
+
+ ...
+
+ // Preserve a file with a unique token value in the session.
+ struct liveupdate_session_preserve_fd arg = {
+ .size = sizeof(arg),
+ .fd = fd,
+ .token = TOKEN,
+ }
+ ioctl(session_fd, LIVEUPDATE_SESSION_PRESERVE_FD, &arg);
+
+Files can be unpreserved with the LIVEUPDATE_SESSION_UNPRESERVE_FD ioctl. They
+are also unpreserved once the last reference to the session is dropped. To
+carry preserved files across a Live Update, references must be kept on the
+session files through the reboot(LINUX_REBOOT_CMD_KEXEC) syscall.
+
+While a file is preserved in a session, the kernel holds an extra reference
+to it to prevent it from being destroyed.
+
+Only the following types of files support LIVEUPDATE_SESSION_PRESERVE_FD. More
+types of files are expected to be added in the future.
+
+ - memfd
+ - VFIO character device files (vfio-pci only)
+
+File Retrieval
+==============
+
+Files that are preserved in a session retrieved after
+reboot(LINUX_REBOOT_CMD_KEXEC).
+
+luod::
+
+ luo_fd = open("/dev/liveupdate", ...);
+
+ ...
+
+ struct liveupdate_ioctl_retrieve_session arg = {
+ .size = sizeof(arg),
+ .name = SESSION_NAME,
+ };
+ ioctl(luo_fd, LIVEUPDATE_IOCTL_RETRIEVE_SESSION, &arg);
+
+ // Send session_fd to VMM over UDS.
+ send_session_fd(..., arg.fd);
+
+VMM::
+
+ // Receive the retrieved session from luod over UDS
+ session_fd = retrieve_session(SESSION_NAME);
+
+ ...
+
+ // Retrieve the file associated with the token from the session.
+ struct liveupdate_session_retrieve_fd arg = {
+ .size = sizeof(arg),
+ .token = TOKEN,
+ };
+ ioctl(session_fd, LIVEUPDATE_SESSION_RETRIEVE_FD, &arg);
+
+ ...
+
+ ioctl(session_fd, LIVEUPDATE_SESSION_FINISH, ...);
+
+A session can only be finished once all of the files within it have been
+retrieved, and are fully restored from the kernel's perspective. The exact
+requirements will vary by file type.
+
+VFIO Character Device (cdev) Files
+==================================
+
+The kernel supports preserving VFIO character device files across Live Update
+within a session::
+
+ device_fd = open("/dev/vfio/devices/X");
+
+ ...
+
+ ioctl(session_fd, LIVEUPDATE_SESSION_PRESERVE_FD, { ..., device_fd, ...});
+
+Attempting to preserve files acquired via VFIO_GROUP_GET_DEVICE_FD will fail.
+
+Since the kernel holds an extra reference to files preserved in sessions, there
+is no way for the underlying PCI device to be unbound from vfio-pci while it
+is being preserved.
+
+When a VFIO device file is preserved in a session, interrupts must be disabled
+on the device prior to reboot(LINUX_REBOOT_CMD_KEXEC), or the kexec will fail.
+
+Preserved VFIO device files can be retrieved after a Live Update just like any
+other preserved file::
+
+ ioctl(session_fd, LIVEUPDATE_SESSION_RETRIEVE_FD, &arg);
+ device_fd = arg.fd;
+
+ ...
+
+ ioctl(session_fd, LIVEUPDATE_SESSION_FINISH, ...);
+
+Prior to LIVEUPDATE_SESSION_FINISH, preserved devices must be retrieved from
+the session and bound to an iommufd. Attempting to open the device through
+its character device (/dev/vfio/devices/X) or VFIO_GROUP_GET_DEVICE_FD will
+fail with -EBUSY.
+
+The eventual goal of these support is to preserve devices running uninterrupted
+across a Live Update. However there are many steps still needed to achieve this
+(see Future Work below). So for now, VFIO will reset and restore the device
+back into an idle state during reboot(LINUX_REBOOT_CMD_KEXEC).
+
+Future work:
+
+ - Preservation of iommufd files
+ - Preservation of IOMMU driver state
+ - Preservation of PCI state (BAR resources, device state, bridge state, ...)
+ - Preservation of vfio-pci driver state
+
See Also
========
--
2.53.0.rc1.225.gd81095ad13-goog
^ permalink raw reply [flat|nested] 32+ messages in thread* [PATCH v2 12/22] selftests/liveupdate: Move luo_test_utils.* into a reusable library
2026-01-29 21:24 [PATCH v2 00/22] vfio/pci: Base Live Update support for VFIO device files David Matlack
` (10 preceding siblings ...)
2026-01-29 21:24 ` [PATCH v2 11/22] docs: liveupdate: Document VFIO device file preservation David Matlack
@ 2026-01-29 21:24 ` David Matlack
2026-01-29 21:25 ` [PATCH v2 13/22] selftests/liveupdate: Add helpers to preserve/retrieve FDs David Matlack
` (9 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: David Matlack @ 2026-01-29 21:24 UTC (permalink / raw)
To: Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Matlack, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
From: Vipin Sharma <vipinsh@google.com>
Move luo_test_utils.[ch] into a lib/ directory and pull the rules to
build them out into a separate make script. This will enable these
utilities to be also built by and used within other selftests (such as
VFIO) in subsequent commits.
No functional change intended.
Signed-off-by: Vipin Sharma <vipinsh@google.com>
Co-developed-by: David Matlack <dmatlack@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
tools/testing/selftests/liveupdate/.gitignore | 1 +
tools/testing/selftests/liveupdate/Makefile | 14 ++++---------
.../include/libliveupdate.h} | 8 ++++----
.../selftests/liveupdate/lib/libliveupdate.mk | 20 +++++++++++++++++++
.../{luo_test_utils.c => lib/liveupdate.c} | 2 +-
.../selftests/liveupdate/luo_kexec_simple.c | 2 +-
.../selftests/liveupdate/luo_multi_session.c | 2 +-
7 files changed, 32 insertions(+), 17 deletions(-)
rename tools/testing/selftests/liveupdate/{luo_test_utils.h => lib/include/libliveupdate.h} (87%)
create mode 100644 tools/testing/selftests/liveupdate/lib/libliveupdate.mk
rename tools/testing/selftests/liveupdate/{luo_test_utils.c => lib/liveupdate.c} (99%)
diff --git a/tools/testing/selftests/liveupdate/.gitignore b/tools/testing/selftests/liveupdate/.gitignore
index 661827083ab6..18a0c7036cf3 100644
--- a/tools/testing/selftests/liveupdate/.gitignore
+++ b/tools/testing/selftests/liveupdate/.gitignore
@@ -3,6 +3,7 @@
!/**/
!*.c
!*.h
+!*.mk
!*.sh
!.gitignore
!config
diff --git a/tools/testing/selftests/liveupdate/Makefile b/tools/testing/selftests/liveupdate/Makefile
index 080754787ede..a060cc21f27f 100644
--- a/tools/testing/selftests/liveupdate/Makefile
+++ b/tools/testing/selftests/liveupdate/Makefile
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-LIB_C += luo_test_utils.c
-
TEST_GEN_PROGS += liveupdate
TEST_GEN_PROGS_EXTENDED += luo_kexec_simple
@@ -10,25 +8,21 @@ TEST_GEN_PROGS_EXTENDED += luo_multi_session
TEST_FILES += do_kexec.sh
include ../lib.mk
+include lib/libliveupdate.mk
CFLAGS += $(KHDR_INCLUDES)
CFLAGS += -Wall -O2 -Wno-unused-function
CFLAGS += -MD
-LIB_O := $(patsubst %.c, $(OUTPUT)/%.o, $(LIB_C))
TEST_O := $(patsubst %, %.o, $(TEST_GEN_PROGS))
TEST_O += $(patsubst %, %.o, $(TEST_GEN_PROGS_EXTENDED))
-TEST_DEP_FILES := $(patsubst %.o, %.d, $(LIB_O))
+TEST_DEP_FILES := $(patsubst %.o, %.d, $(LIBLIVEUPDATE_O))
TEST_DEP_FILES += $(patsubst %.o, %.d, $(TEST_O))
-include $(TEST_DEP_FILES)
-$(LIB_O): $(OUTPUT)/%.o: %.c
- $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
-
-$(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/%: %.o $(LIB_O)
- $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $< $(LIB_O) $(LDLIBS) -o $@
+$(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/%: %.o $(LIBLIVEUPDATE_O)
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $< $(LIBLIVEUPDATE_O) $(LDLIBS) -o $@
-EXTRA_CLEAN += $(LIB_O)
EXTRA_CLEAN += $(TEST_O)
EXTRA_CLEAN += $(TEST_DEP_FILES)
diff --git a/tools/testing/selftests/liveupdate/luo_test_utils.h b/tools/testing/selftests/liveupdate/lib/include/libliveupdate.h
similarity index 87%
rename from tools/testing/selftests/liveupdate/luo_test_utils.h
rename to tools/testing/selftests/liveupdate/lib/include/libliveupdate.h
index 90099bf49577..4390a2737930 100644
--- a/tools/testing/selftests/liveupdate/luo_test_utils.h
+++ b/tools/testing/selftests/liveupdate/lib/include/libliveupdate.h
@@ -7,13 +7,13 @@
* Utility functions for LUO kselftests.
*/
-#ifndef LUO_TEST_UTILS_H
-#define LUO_TEST_UTILS_H
+#ifndef SELFTESTS_LIVEUPDATE_LIB_LIVEUPDATE_H
+#define SELFTESTS_LIVEUPDATE_LIB_LIVEUPDATE_H
#include <errno.h>
#include <string.h>
#include <linux/liveupdate.h>
-#include "../kselftest.h"
+#include "../../../kselftest.h"
#define LUO_DEVICE "/dev/liveupdate"
@@ -41,4 +41,4 @@ typedef void (*luo_test_stage2_fn)(int luo_fd, int state_session_fd);
int luo_test(int argc, char *argv[], const char *state_session_name,
luo_test_stage1_fn stage1, luo_test_stage2_fn stage2);
-#endif /* LUO_TEST_UTILS_H */
+#endif /* SELFTESTS_LIVEUPDATE_LIB_LIVEUPDATE_H */
diff --git a/tools/testing/selftests/liveupdate/lib/libliveupdate.mk b/tools/testing/selftests/liveupdate/lib/libliveupdate.mk
new file mode 100644
index 000000000000..fffd95b085b6
--- /dev/null
+++ b/tools/testing/selftests/liveupdate/lib/libliveupdate.mk
@@ -0,0 +1,20 @@
+include $(top_srcdir)/scripts/subarch.include
+ARCH ?= $(SUBARCH)
+
+LIBLIVEUPDATE_SRCDIR := $(selfdir)/liveupdate/lib
+
+LIBLIVEUPDATE_C := liveupdate.c
+
+LIBLIVEUPDATE_OUTPUT := $(OUTPUT)/libliveupdate
+
+LIBLIVEUPDATE_O := $(patsubst %.c, $(LIBLIVEUPDATE_OUTPUT)/%.o, $(LIBLIVEUPDATE_C))
+
+LIBLIVEUPDATE_O_DIRS := $(shell dirname $(LIBLIVEUPDATE_O) | uniq)
+$(shell mkdir -p $(LIBLIVEUPDATE_O_DIRS))
+
+CFLAGS += -I$(LIBLIVEUPDATE_SRCDIR)/include
+
+$(LIBLIVEUPDATE_O): $(LIBLIVEUPDATE_OUTPUT)/%.o : $(LIBLIVEUPDATE_SRCDIR)/%.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+EXTRA_CLEAN += $(LIBLIVEUPDATE_OUTPUT)
diff --git a/tools/testing/selftests/liveupdate/luo_test_utils.c b/tools/testing/selftests/liveupdate/lib/liveupdate.c
similarity index 99%
rename from tools/testing/selftests/liveupdate/luo_test_utils.c
rename to tools/testing/selftests/liveupdate/lib/liveupdate.c
index 3c8721c505df..60121873f685 100644
--- a/tools/testing/selftests/liveupdate/luo_test_utils.c
+++ b/tools/testing/selftests/liveupdate/lib/liveupdate.c
@@ -21,7 +21,7 @@
#include <errno.h>
#include <stdarg.h>
-#include "luo_test_utils.h"
+#include <libliveupdate.h>
int luo_open_device(void)
{
diff --git a/tools/testing/selftests/liveupdate/luo_kexec_simple.c b/tools/testing/selftests/liveupdate/luo_kexec_simple.c
index d7ac1f3dc4cb..786ac93b9ae3 100644
--- a/tools/testing/selftests/liveupdate/luo_kexec_simple.c
+++ b/tools/testing/selftests/liveupdate/luo_kexec_simple.c
@@ -8,7 +8,7 @@
* across a single kexec reboot.
*/
-#include "luo_test_utils.h"
+#include <libliveupdate.h>
#define TEST_SESSION_NAME "test-session"
#define TEST_MEMFD_TOKEN 0x1A
diff --git a/tools/testing/selftests/liveupdate/luo_multi_session.c b/tools/testing/selftests/liveupdate/luo_multi_session.c
index 0ee2d795beef..aac24a5f5ce3 100644
--- a/tools/testing/selftests/liveupdate/luo_multi_session.c
+++ b/tools/testing/selftests/liveupdate/luo_multi_session.c
@@ -9,7 +9,7 @@
* files.
*/
-#include "luo_test_utils.h"
+#include <libliveupdate.h>
#define SESSION_EMPTY_1 "multi-test-empty-1"
#define SESSION_EMPTY_2 "multi-test-empty-2"
--
2.53.0.rc1.225.gd81095ad13-goog
^ permalink raw reply [flat|nested] 32+ messages in thread* [PATCH v2 13/22] selftests/liveupdate: Add helpers to preserve/retrieve FDs
2026-01-29 21:24 [PATCH v2 00/22] vfio/pci: Base Live Update support for VFIO device files David Matlack
` (11 preceding siblings ...)
2026-01-29 21:24 ` [PATCH v2 12/22] selftests/liveupdate: Move luo_test_utils.* into a reusable library David Matlack
@ 2026-01-29 21:25 ` David Matlack
2026-01-29 21:25 ` [PATCH v2 14/22] vfio: selftests: Build liveupdate library in VFIO selftests David Matlack
` (8 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: David Matlack @ 2026-01-29 21:25 UTC (permalink / raw)
To: Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Matlack, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
From: Vipin Sharma <vipinsh@google.com>
Add helper functions to preserve and retrieve file descriptors from an
LUO session. These will be used be used in subsequent commits to
preserve FDs other than memfd.
No functional change intended.
Signed-off-by: Vipin Sharma <vipinsh@google.com>
Co-developed-by: David Matlack <dmatlack@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
.../liveupdate/lib/include/libliveupdate.h | 3 ++
.../selftests/liveupdate/lib/liveupdate.c | 41 +++++++++++++++----
2 files changed, 35 insertions(+), 9 deletions(-)
diff --git a/tools/testing/selftests/liveupdate/lib/include/libliveupdate.h b/tools/testing/selftests/liveupdate/lib/include/libliveupdate.h
index 4390a2737930..4c93d043d2b3 100644
--- a/tools/testing/selftests/liveupdate/lib/include/libliveupdate.h
+++ b/tools/testing/selftests/liveupdate/lib/include/libliveupdate.h
@@ -26,6 +26,9 @@ int luo_create_session(int luo_fd, const char *name);
int luo_retrieve_session(int luo_fd, const char *name);
int luo_session_finish(int session_fd);
+int luo_session_preserve_fd(int session_fd, int fd, int token);
+int luo_session_retrieve_fd(int session_fd, int token);
+
int create_and_preserve_memfd(int session_fd, int token, const char *data);
int restore_and_verify_memfd(int session_fd, int token, const char *expected_data);
diff --git a/tools/testing/selftests/liveupdate/lib/liveupdate.c b/tools/testing/selftests/liveupdate/lib/liveupdate.c
index 60121873f685..9bf4f16ca0a4 100644
--- a/tools/testing/selftests/liveupdate/lib/liveupdate.c
+++ b/tools/testing/selftests/liveupdate/lib/liveupdate.c
@@ -54,9 +54,35 @@ int luo_retrieve_session(int luo_fd, const char *name)
return arg.fd;
}
+int luo_session_preserve_fd(int session_fd, int fd, int token)
+{
+ struct liveupdate_session_preserve_fd arg = {
+ .size = sizeof(arg),
+ .fd = fd,
+ .token = token,
+ };
+
+ if (ioctl(session_fd, LIVEUPDATE_SESSION_PRESERVE_FD, &arg))
+ return -errno;
+
+ return 0;
+}
+
+int luo_session_retrieve_fd(int session_fd, int token)
+{
+ struct liveupdate_session_retrieve_fd arg = {
+ .size = sizeof(arg),
+ .token = token,
+ };
+
+ if (ioctl(session_fd, LIVEUPDATE_SESSION_RETRIEVE_FD, &arg))
+ return -errno;
+
+ return arg.fd;
+}
+
int create_and_preserve_memfd(int session_fd, int token, const char *data)
{
- struct liveupdate_session_preserve_fd arg = { .size = sizeof(arg) };
long page_size = sysconf(_SC_PAGE_SIZE);
void *map = MAP_FAILED;
int mfd = -1, ret = -1;
@@ -75,9 +101,8 @@ int create_and_preserve_memfd(int session_fd, int token, const char *data)
snprintf(map, page_size, "%s", data);
munmap(map, page_size);
- arg.fd = mfd;
- arg.token = token;
- if (ioctl(session_fd, LIVEUPDATE_SESSION_PRESERVE_FD, &arg) < 0)
+ ret = luo_session_preserve_fd(session_fd, mfd, token);
+ if (ret)
goto out;
ret = 0;
@@ -92,15 +117,13 @@ int create_and_preserve_memfd(int session_fd, int token, const char *data)
int restore_and_verify_memfd(int session_fd, int token,
const char *expected_data)
{
- struct liveupdate_session_retrieve_fd arg = { .size = sizeof(arg) };
long page_size = sysconf(_SC_PAGE_SIZE);
void *map = MAP_FAILED;
int mfd = -1, ret = -1;
- arg.token = token;
- if (ioctl(session_fd, LIVEUPDATE_SESSION_RETRIEVE_FD, &arg) < 0)
- return -errno;
- mfd = arg.fd;
+ mfd = luo_session_retrieve_fd(session_fd, token);
+ if (mfd < 0)
+ return mfd;
map = mmap(NULL, page_size, PROT_READ, MAP_SHARED, mfd, 0);
if (map == MAP_FAILED)
--
2.53.0.rc1.225.gd81095ad13-goog
^ permalink raw reply [flat|nested] 32+ messages in thread* [PATCH v2 14/22] vfio: selftests: Build liveupdate library in VFIO selftests
2026-01-29 21:24 [PATCH v2 00/22] vfio/pci: Base Live Update support for VFIO device files David Matlack
` (12 preceding siblings ...)
2026-01-29 21:25 ` [PATCH v2 13/22] selftests/liveupdate: Add helpers to preserve/retrieve FDs David Matlack
@ 2026-01-29 21:25 ` David Matlack
2026-01-29 21:25 ` [PATCH v2 15/22] vfio: selftests: Add Makefile support for TEST_GEN_PROGS_EXTENDED David Matlack
` (7 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: David Matlack @ 2026-01-29 21:25 UTC (permalink / raw)
To: Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Matlack, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
From: Vipin Sharma <vipinsh@google.com>
Import and build liveupdate selftest library in VFIO selftests.
It allows to use liveupdate ioctls in VFIO selftests
Signed-off-by: Vipin Sharma <vipinsh@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
tools/testing/selftests/vfio/Makefile | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile
index 3c796ca99a50..1e50998529fd 100644
--- a/tools/testing/selftests/vfio/Makefile
+++ b/tools/testing/selftests/vfio/Makefile
@@ -12,6 +12,7 @@ TEST_FILES += scripts/setup.sh
include ../lib.mk
include lib/libvfio.mk
+include ../liveupdate/lib/libliveupdate.mk
CFLAGS += -I$(top_srcdir)/tools/include
CFLAGS += -MD
@@ -19,11 +20,15 @@ CFLAGS += $(EXTRA_CFLAGS)
LDFLAGS += -pthread
-$(TEST_GEN_PROGS): %: %.o $(LIBVFIO_O)
- $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $< $(LIBVFIO_O) $(LDLIBS) -o $@
+LIBS_O := $(LIBVFIO_O)
+LIBS_O += $(LIBLIVEUPDATE_O)
+
+$(TEST_GEN_PROGS): %: %.o $(LIBS_O)
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $< $(LIBS_O) $(LDLIBS) -o $@
TEST_GEN_PROGS_O = $(patsubst %, %.o, $(TEST_GEN_PROGS))
-TEST_DEP_FILES = $(patsubst %.o, %.d, $(TEST_GEN_PROGS_O) $(LIBVFIO_O))
+TEST_DEP_FILES := $(patsubst %.o, %.d, $(TEST_GEN_PROGS_O))
+TEST_DEP_FILES += $(patsubst %.o, %.d, $(LIBS_O))
-include $(TEST_DEP_FILES)
EXTRA_CLEAN += $(TEST_GEN_PROGS_O) $(TEST_DEP_FILES)
--
2.53.0.rc1.225.gd81095ad13-goog
^ permalink raw reply [flat|nested] 32+ messages in thread* [PATCH v2 15/22] vfio: selftests: Add Makefile support for TEST_GEN_PROGS_EXTENDED
2026-01-29 21:24 [PATCH v2 00/22] vfio/pci: Base Live Update support for VFIO device files David Matlack
` (13 preceding siblings ...)
2026-01-29 21:25 ` [PATCH v2 14/22] vfio: selftests: Build liveupdate library in VFIO selftests David Matlack
@ 2026-01-29 21:25 ` David Matlack
2026-01-29 21:25 ` [PATCH v2 16/22] vfio: selftests: Add vfio_pci_liveupdate_uapi_test David Matlack
` (6 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: David Matlack @ 2026-01-29 21:25 UTC (permalink / raw)
To: Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Matlack, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
Add Makefile support for TEST_GEN_PROGS_EXTENDED targets. These tests
are not run by default.
TEST_GEN_PROGS_EXTENDED will be used for Live Update selftests in
subsequent commits. These selftests must be run manually because they
require the user/runner to perform additional actions, such as kexec,
during the test.
Signed-off-by: David Matlack <dmatlack@google.com>
---
tools/testing/selftests/vfio/Makefile | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile
index 1e50998529fd..f9c040094d4a 100644
--- a/tools/testing/selftests/vfio/Makefile
+++ b/tools/testing/selftests/vfio/Makefile
@@ -23,12 +23,15 @@ LDFLAGS += -pthread
LIBS_O := $(LIBVFIO_O)
LIBS_O += $(LIBLIVEUPDATE_O)
-$(TEST_GEN_PROGS): %: %.o $(LIBS_O)
+$(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED): %: %.o $(LIBS_O)
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $< $(LIBS_O) $(LDLIBS) -o $@
-TEST_GEN_PROGS_O = $(patsubst %, %.o, $(TEST_GEN_PROGS))
-TEST_DEP_FILES := $(patsubst %.o, %.d, $(TEST_GEN_PROGS_O))
+TESTS_O := $(patsubst %, %.o, $(TEST_GEN_PROGS))
+TESTS_O += $(patsubst %, %.o, $(TEST_GEN_PROGS_EXTENDED))
+
+TEST_DEP_FILES := $(patsubst %.o, %.d, $(TESTS_O))
TEST_DEP_FILES += $(patsubst %.o, %.d, $(LIBS_O))
-include $(TEST_DEP_FILES)
-EXTRA_CLEAN += $(TEST_GEN_PROGS_O) $(TEST_DEP_FILES)
+EXTRA_CLEAN += $(TESTS_O)
+EXTRA_CLEAN += $(TEST_DEP_FILES)
--
2.53.0.rc1.225.gd81095ad13-goog
^ permalink raw reply [flat|nested] 32+ messages in thread* [PATCH v2 16/22] vfio: selftests: Add vfio_pci_liveupdate_uapi_test
2026-01-29 21:24 [PATCH v2 00/22] vfio/pci: Base Live Update support for VFIO device files David Matlack
` (14 preceding siblings ...)
2026-01-29 21:25 ` [PATCH v2 15/22] vfio: selftests: Add Makefile support for TEST_GEN_PROGS_EXTENDED David Matlack
@ 2026-01-29 21:25 ` David Matlack
2026-01-29 21:25 ` [PATCH v2 17/22] vfio: selftests: Initialize vfio_pci_device using a VFIO cdev FD David Matlack
` (5 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: David Matlack @ 2026-01-29 21:25 UTC (permalink / raw)
To: Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Matlack, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
Add a selftest to exercise preserving a various VFIO files through
/dev/liveupdate. Ensure that VFIO cdev device files can be preserved and
everything else (group-based device files, group files, and container
files) all fail.
Signed-off-by: David Matlack <dmatlack@google.com>
---
tools/testing/selftests/vfio/Makefile | 1 +
.../vfio/vfio_pci_liveupdate_uapi_test.c | 93 +++++++++++++++++++
2 files changed, 94 insertions(+)
create mode 100644 tools/testing/selftests/vfio/vfio_pci_liveupdate_uapi_test.c
diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile
index f9c040094d4a..666310872217 100644
--- a/tools/testing/selftests/vfio/Makefile
+++ b/tools/testing/selftests/vfio/Makefile
@@ -4,6 +4,7 @@ TEST_GEN_PROGS += vfio_iommufd_setup_test
TEST_GEN_PROGS += vfio_pci_device_test
TEST_GEN_PROGS += vfio_pci_device_init_perf_test
TEST_GEN_PROGS += vfio_pci_driver_test
+TEST_GEN_PROGS += vfio_pci_liveupdate_uapi_test
TEST_FILES += scripts/cleanup.sh
TEST_FILES += scripts/lib.sh
diff --git a/tools/testing/selftests/vfio/vfio_pci_liveupdate_uapi_test.c b/tools/testing/selftests/vfio/vfio_pci_liveupdate_uapi_test.c
new file mode 100644
index 000000000000..3b4276b2532c
--- /dev/null
+++ b/tools/testing/selftests/vfio/vfio_pci_liveupdate_uapi_test.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <libliveupdate.h>
+#include <libvfio.h>
+#include <kselftest_harness.h>
+
+static const char *device_bdf;
+
+FIXTURE(vfio_pci_liveupdate_uapi_test) {
+ int luo_fd;
+ int session_fd;
+ struct iommu *iommu;
+ struct vfio_pci_device *device;
+};
+
+FIXTURE_VARIANT(vfio_pci_liveupdate_uapi_test) {
+ const char *iommu_mode;
+};
+
+#define FIXTURE_VARIANT_ADD_IOMMU_MODE(_iommu_mode) \
+FIXTURE_VARIANT_ADD(vfio_pci_liveupdate_uapi_test, _iommu_mode) { \
+ .iommu_mode = #_iommu_mode, \
+}
+
+FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES();
+#undef FIXTURE_VARIANT_ADD_IOMMU_MODE
+
+FIXTURE_SETUP(vfio_pci_liveupdate_uapi_test)
+{
+ self->luo_fd = luo_open_device();
+ ASSERT_GE(self->luo_fd, 0);
+
+ self->session_fd = luo_create_session(self->luo_fd, "session");
+ ASSERT_GE(self->session_fd, 0);
+
+ self->iommu = iommu_init(variant->iommu_mode);
+ self->device = vfio_pci_device_init(device_bdf, self->iommu);
+}
+
+FIXTURE_TEARDOWN(vfio_pci_liveupdate_uapi_test)
+{
+ vfio_pci_device_cleanup(self->device);
+ iommu_cleanup(self->iommu);
+ close(self->session_fd);
+ close(self->luo_fd);
+}
+
+TEST_F(vfio_pci_liveupdate_uapi_test, preserve_device)
+{
+ int ret;
+
+ ret = luo_session_preserve_fd(self->session_fd, self->device->fd, 0);
+
+ /* Preservation should only be supported for VFIO cdev files. */
+ ASSERT_EQ(ret, self->iommu->iommufd ? 0 : -ENOENT);
+}
+
+TEST_F(vfio_pci_liveupdate_uapi_test, preserve_group_fails)
+{
+ int ret;
+
+ if (self->iommu->iommufd)
+ return;
+
+ ret = luo_session_preserve_fd(self->session_fd, self->device->group_fd, 0);
+ ASSERT_EQ(ret, -ENOENT);
+}
+
+TEST_F(vfio_pci_liveupdate_uapi_test, preserve_container_fails)
+{
+ int ret;
+
+ if (self->iommu->iommufd)
+ return;
+
+ ret = luo_session_preserve_fd(self->session_fd, self->iommu->container_fd, 0);
+ ASSERT_EQ(ret, -ENOENT);
+}
+
+int main(int argc, char *argv[])
+{
+ int fd;
+
+ fd = luo_open_device();
+ if (fd < 0) {
+ printf("open(%s) failed: %s, skipping\n", LUO_DEVICE, strerror(errno));
+ return KSFT_SKIP;
+ }
+ close(fd);
+
+ device_bdf = vfio_selftests_get_bdf(&argc, argv);
+ return test_harness_run(argc, argv);
+}
--
2.53.0.rc1.225.gd81095ad13-goog
^ permalink raw reply [flat|nested] 32+ messages in thread* [PATCH v2 17/22] vfio: selftests: Initialize vfio_pci_device using a VFIO cdev FD
2026-01-29 21:24 [PATCH v2 00/22] vfio/pci: Base Live Update support for VFIO device files David Matlack
` (15 preceding siblings ...)
2026-01-29 21:25 ` [PATCH v2 16/22] vfio: selftests: Add vfio_pci_liveupdate_uapi_test David Matlack
@ 2026-01-29 21:25 ` David Matlack
2026-01-29 21:25 ` [PATCH v2 18/22] vfio: selftests: Add vfio_pci_liveupdate_kexec_test David Matlack
` (4 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: David Matlack @ 2026-01-29 21:25 UTC (permalink / raw)
To: Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Matlack, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
From: Vipin Sharma <vipinsh@google.com>
Use the given VFIO cdev FD to initialize vfio_pci_device in VFIO
selftests. Add the assertion to make sure that passed cdev FD is not
used with legacy VFIO APIs. If VFIO cdev FD is provided then do not open
the device instead use the FD for any interaction with the device.
This API will allow to write selftests where VFIO device FD is preserved
using liveupdate and retrieved later using liveupdate ioctl after kexec.
Signed-off-by: Vipin Sharma <vipinsh@google.com>
Co-developed-by: David Matlack <dmatlack@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
.../lib/include/libvfio/vfio_pci_device.h | 3 ++
.../selftests/vfio/lib/vfio_pci_device.c | 33 ++++++++++++++-----
2 files changed, 27 insertions(+), 9 deletions(-)
diff --git a/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
index 2858885a89bb..896dfde88118 100644
--- a/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
+++ b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
@@ -38,6 +38,9 @@ struct vfio_pci_device {
#define dev_info(_dev, _fmt, ...) printf("%s: " _fmt, (_dev)->bdf, ##__VA_ARGS__)
#define dev_err(_dev, _fmt, ...) fprintf(stderr, "%s: " _fmt, (_dev)->bdf, ##__VA_ARGS__)
+struct vfio_pci_device *__vfio_pci_device_init(const char *bdf,
+ struct iommu *iommu,
+ int device_fd);
struct vfio_pci_device *vfio_pci_device_init(const char *bdf, struct iommu *iommu);
void vfio_pci_device_cleanup(struct vfio_pci_device *device);
diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
index fac4c0ecadef..08bb582eaa8f 100644
--- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c
+++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
@@ -318,19 +318,27 @@ static void vfio_device_attach_iommufd_pt(int device_fd, u32 pt_id)
ioctl_assert(device_fd, VFIO_DEVICE_ATTACH_IOMMUFD_PT, &args);
}
-static void vfio_pci_iommufd_setup(struct vfio_pci_device *device, const char *bdf)
+static void vfio_pci_iommufd_setup(struct vfio_pci_device *device,
+ const char *bdf, int device_fd)
{
- const char *cdev_path = vfio_pci_get_cdev_path(bdf);
+ const char *cdev_path;
- device->fd = open(cdev_path, O_RDWR);
- VFIO_ASSERT_GE(device->fd, 0);
- free((void *)cdev_path);
+ if (device_fd >= 0) {
+ device->fd = device_fd;
+ } else {
+ cdev_path = vfio_pci_get_cdev_path(bdf);
+ device->fd = open(cdev_path, O_RDWR);
+ VFIO_ASSERT_GE(device->fd, 0);
+ free((void *)cdev_path);
+ }
vfio_device_bind_iommufd(device->fd, device->iommu->iommufd);
vfio_device_attach_iommufd_pt(device->fd, device->iommu->ioas_id);
}
-struct vfio_pci_device *vfio_pci_device_init(const char *bdf, struct iommu *iommu)
+struct vfio_pci_device *__vfio_pci_device_init(const char *bdf,
+ struct iommu *iommu,
+ int device_fd)
{
struct vfio_pci_device *device;
@@ -341,10 +349,12 @@ struct vfio_pci_device *vfio_pci_device_init(const char *bdf, struct iommu *iomm
device->iommu = iommu;
device->bdf = bdf;
- if (iommu->mode->container_path)
+ if (iommu->mode->container_path) {
+ VFIO_ASSERT_EQ(device_fd, -1);
vfio_pci_container_setup(device, bdf);
- else
- vfio_pci_iommufd_setup(device, bdf);
+ } else {
+ vfio_pci_iommufd_setup(device, bdf, device_fd);
+ }
vfio_pci_device_setup(device);
vfio_pci_driver_probe(device);
@@ -352,6 +362,11 @@ struct vfio_pci_device *vfio_pci_device_init(const char *bdf, struct iommu *iomm
return device;
}
+struct vfio_pci_device *vfio_pci_device_init(const char *bdf, struct iommu *iommu)
+{
+ return __vfio_pci_device_init(bdf, iommu, /*device_fd=*/-1);
+}
+
void vfio_pci_device_cleanup(struct vfio_pci_device *device)
{
int i;
--
2.53.0.rc1.225.gd81095ad13-goog
^ permalink raw reply [flat|nested] 32+ messages in thread* [PATCH v2 18/22] vfio: selftests: Add vfio_pci_liveupdate_kexec_test
2026-01-29 21:24 [PATCH v2 00/22] vfio/pci: Base Live Update support for VFIO device files David Matlack
` (16 preceding siblings ...)
2026-01-29 21:25 ` [PATCH v2 17/22] vfio: selftests: Initialize vfio_pci_device using a VFIO cdev FD David Matlack
@ 2026-01-29 21:25 ` David Matlack
2026-01-29 21:25 ` [PATCH v2 19/22] vfio: selftests: Expose iommu_modes to tests David Matlack
` (3 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: David Matlack @ 2026-01-29 21:25 UTC (permalink / raw)
To: Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Matlack, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
From: Vipin Sharma <vipinsh@google.com>
Add a selftest to exercise preserving a vfio-pci device across a Live
Update. For now the test is extremely simple and just verifies that the
device file can be preserved and retrieved. In the future this test will
be extended to verify more parts about device preservation as they are
implemented.
This test is added to TEST_GEN_PROGS_EXTENDED since it must be run
manually along with a kexec.
To run this test manually:
$ tools/testing/selftests/vfio/scripts/setup.sh 0000:00:04.0
$ tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test --stage 1 0000:00:04.0
$ kexec ... # NOTE: Exact method will be distro-dependent
$ tools/testing/selftests/vfio/scripts/setup.sh 0000:00:04.0
$ tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test --stage 2 0000:00:04.0
The second call to setup.sh is necessary because preserved devices are
not bound to a driver after Live Update. Such devices must be manually
bound by userspace after Live Update via driver_override.
This test is considered passing if all commands exit with 0.
Signed-off-by: Vipin Sharma <vipinsh@google.com>
Co-developed-by: David Matlack <dmatlack@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
tools/testing/selftests/vfio/Makefile | 4 +
.../vfio/vfio_pci_liveupdate_kexec_test.c | 89 +++++++++++++++++++
2 files changed, 93 insertions(+)
create mode 100644 tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c
diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile
index 666310872217..55d685f6e540 100644
--- a/tools/testing/selftests/vfio/Makefile
+++ b/tools/testing/selftests/vfio/Makefile
@@ -6,6 +6,10 @@ TEST_GEN_PROGS += vfio_pci_device_init_perf_test
TEST_GEN_PROGS += vfio_pci_driver_test
TEST_GEN_PROGS += vfio_pci_liveupdate_uapi_test
+# This test must be run manually since it requires the user/automation to
+# perform a kexec during the test.
+TEST_GEN_PROGS_EXTENDED += vfio_pci_liveupdate_kexec_test
+
TEST_FILES += scripts/cleanup.sh
TEST_FILES += scripts/lib.sh
TEST_FILES += scripts/run.sh
diff --git a/tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c b/tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c
new file mode 100644
index 000000000000..15b3e3af91d1
--- /dev/null
+++ b/tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <libliveupdate.h>
+#include <libvfio.h>
+
+static const char *device_bdf;
+
+static char state_session[LIVEUPDATE_SESSION_NAME_LENGTH];
+static char device_session[LIVEUPDATE_SESSION_NAME_LENGTH];
+
+enum {
+ STATE_TOKEN,
+ DEVICE_TOKEN,
+};
+
+static void before_kexec(int luo_fd)
+{
+ struct vfio_pci_device *device;
+ struct iommu *iommu;
+ int session_fd;
+ int ret;
+
+ iommu = iommu_init("iommufd");
+ device = vfio_pci_device_init(device_bdf, iommu);
+
+ create_state_file(luo_fd, state_session, STATE_TOKEN, /*next_stage=*/2);
+
+ session_fd = luo_create_session(luo_fd, device_session);
+ VFIO_ASSERT_GE(session_fd, 0);
+
+ printf("Preserving device in session\n");
+ ret = luo_session_preserve_fd(session_fd, device->fd, DEVICE_TOKEN);
+ VFIO_ASSERT_EQ(ret, 0);
+
+ close(luo_fd);
+ daemonize_and_wait();
+}
+
+static void after_kexec(int luo_fd, int state_session_fd)
+{
+ struct vfio_pci_device *device;
+ struct iommu *iommu;
+ int session_fd;
+ int device_fd;
+ int stage;
+
+ restore_and_read_stage(state_session_fd, STATE_TOKEN, &stage);
+ VFIO_ASSERT_EQ(stage, 2);
+
+ session_fd = luo_retrieve_session(luo_fd, device_session);
+ VFIO_ASSERT_GE(session_fd, 0);
+
+ printf("Finishing the session before retrieving the device (should fail)\n");
+ VFIO_ASSERT_NE(luo_session_finish(session_fd), 0);
+
+ printf("Retrieving the device FD from LUO\n");
+ device_fd = luo_session_retrieve_fd(session_fd, DEVICE_TOKEN);
+ VFIO_ASSERT_GE(device_fd, 0);
+
+ printf("Finishing the session before binding to iommufd (should fail)\n");
+ VFIO_ASSERT_NE(luo_session_finish(session_fd), 0);
+
+ printf("Binding the device to an iommufd and setting it up\n");
+ iommu = iommu_init("iommufd");
+
+ /*
+ * This will invoke various ioctls on device_fd such as
+ * VFIO_DEVICE_GET_INFO. So this is a decent sanity test
+ * that LUO actually handed us back a valid VFIO device
+ * file and not something else.
+ */
+ device = __vfio_pci_device_init(device_bdf, iommu, device_fd);
+
+ printf("Finishing the session\n");
+ VFIO_ASSERT_EQ(luo_session_finish(session_fd), 0);
+
+ vfio_pci_device_cleanup(device);
+ iommu_cleanup(iommu);
+}
+
+int main(int argc, char *argv[])
+{
+ device_bdf = vfio_selftests_get_bdf(&argc, argv);
+
+ sprintf(device_session, "device-%s", device_bdf);
+ sprintf(state_session, "state-%s", device_bdf);
+
+ return luo_test(argc, argv, state_session, before_kexec, after_kexec);
+}
--
2.53.0.rc1.225.gd81095ad13-goog
^ permalink raw reply [flat|nested] 32+ messages in thread* [PATCH v2 19/22] vfio: selftests: Expose iommu_modes to tests
2026-01-29 21:24 [PATCH v2 00/22] vfio/pci: Base Live Update support for VFIO device files David Matlack
` (17 preceding siblings ...)
2026-01-29 21:25 ` [PATCH v2 18/22] vfio: selftests: Add vfio_pci_liveupdate_kexec_test David Matlack
@ 2026-01-29 21:25 ` David Matlack
2026-01-29 21:25 ` [PATCH v2 20/22] vfio: selftests: Expose low-level helper routines for setting up struct vfio_pci_device David Matlack
` (2 subsequent siblings)
21 siblings, 0 replies; 32+ messages in thread
From: David Matlack @ 2026-01-29 21:25 UTC (permalink / raw)
To: Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Matlack, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
Expose the list of iommu_modes to enable tests that want to iterate
through all possible iommu modes.
Signed-off-by: David Matlack <dmatlack@google.com>
---
tools/testing/selftests/vfio/lib/include/libvfio/iommu.h | 2 ++
tools/testing/selftests/vfio/lib/iommu.c | 4 +++-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h b/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
index 5c9b9dc6d993..a03ff2281f11 100644
--- a/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
+++ b/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
@@ -15,6 +15,8 @@ struct iommu_mode {
unsigned long iommu_type;
};
+extern const struct iommu_mode iommu_modes[];
+extern const int nr_iommu_modes;
extern const char *default_iommu_mode;
struct dma_region {
diff --git a/tools/testing/selftests/vfio/lib/iommu.c b/tools/testing/selftests/vfio/lib/iommu.c
index 58b7fb7430d4..add35dbc83f8 100644
--- a/tools/testing/selftests/vfio/lib/iommu.c
+++ b/tools/testing/selftests/vfio/lib/iommu.c
@@ -23,7 +23,7 @@
const char *default_iommu_mode = "iommufd";
/* Reminder: Keep in sync with FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(). */
-static const struct iommu_mode iommu_modes[] = {
+const struct iommu_mode iommu_modes[] = {
{
.name = "vfio_type1_iommu",
.container_path = "/dev/vfio/vfio",
@@ -49,6 +49,8 @@ static const struct iommu_mode iommu_modes[] = {
},
};
+const int nr_iommu_modes = ARRAY_SIZE(iommu_modes);
+
static const struct iommu_mode *lookup_iommu_mode(const char *iommu_mode)
{
int i;
--
2.53.0.rc1.225.gd81095ad13-goog
^ permalink raw reply [flat|nested] 32+ messages in thread* [PATCH v2 20/22] vfio: selftests: Expose low-level helper routines for setting up struct vfio_pci_device
2026-01-29 21:24 [PATCH v2 00/22] vfio/pci: Base Live Update support for VFIO device files David Matlack
` (18 preceding siblings ...)
2026-01-29 21:25 ` [PATCH v2 19/22] vfio: selftests: Expose iommu_modes to tests David Matlack
@ 2026-01-29 21:25 ` David Matlack
2026-01-29 21:25 ` [PATCH v2 21/22] vfio: selftests: Verify that opening VFIO device fails during Live Update David Matlack
2026-01-29 21:25 ` [PATCH v2 22/22] vfio: selftests: Add continuous DMA to vfio_pci_liveupdate_kexec_test David Matlack
21 siblings, 0 replies; 32+ messages in thread
From: David Matlack @ 2026-01-29 21:25 UTC (permalink / raw)
To: Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Matlack, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
Expose a few low-level helper routings for setting up vfio_pci_device
structs. These routines will be used in a subsequent commit to assert
that VFIO_GROUP_GET_DEVICE_FD fails under certain conditions.
Signed-off-by: David Matlack <dmatlack@google.com>
---
.../lib/include/libvfio/vfio_pci_device.h | 5 +++
.../selftests/vfio/lib/vfio_pci_device.c | 33 +++++++++++++------
2 files changed, 28 insertions(+), 10 deletions(-)
diff --git a/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
index 896dfde88118..2389c7698335 100644
--- a/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
+++ b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
@@ -125,4 +125,9 @@ static inline bool vfio_pci_device_match(struct vfio_pci_device *device,
const char *vfio_pci_get_cdev_path(const char *bdf);
+/* Low-level routines for setting up a struct vfio_pci_device */
+struct vfio_pci_device *vfio_pci_device_alloc(const char *bdf, struct iommu *iommu);
+void vfio_pci_group_setup(struct vfio_pci_device *device);
+void vfio_pci_iommu_setup(struct vfio_pci_device *device);
+
#endif /* SELFTESTS_VFIO_LIB_INCLUDE_LIBVFIO_VFIO_PCI_DEVICE_H */
diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
index 08bb582eaa8f..76597c84e956 100644
--- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c
+++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
@@ -198,7 +198,7 @@ static unsigned int vfio_pci_get_group_from_dev(const char *bdf)
return group;
}
-static void vfio_pci_group_setup(struct vfio_pci_device *device, const char *bdf)
+void vfio_pci_group_setup(struct vfio_pci_device *device)
{
struct vfio_group_status group_status = {
.argsz = sizeof(group_status),
@@ -206,7 +206,7 @@ static void vfio_pci_group_setup(struct vfio_pci_device *device, const char *bdf
char group_path[32];
int group;
- group = vfio_pci_get_group_from_dev(bdf);
+ group = vfio_pci_get_group_from_dev(device->bdf);
snprintf(group_path, sizeof(group_path), "/dev/vfio/%d", group);
device->group_fd = open(group_path, O_RDWR);
@@ -218,14 +218,12 @@ static void vfio_pci_group_setup(struct vfio_pci_device *device, const char *bdf
ioctl_assert(device->group_fd, VFIO_GROUP_SET_CONTAINER, &device->iommu->container_fd);
}
-static void vfio_pci_container_setup(struct vfio_pci_device *device, const char *bdf)
+void vfio_pci_iommu_setup(struct vfio_pci_device *device)
{
struct iommu *iommu = device->iommu;
unsigned long iommu_type = iommu->mode->iommu_type;
int ret;
- vfio_pci_group_setup(device, bdf);
-
ret = ioctl(iommu->container_fd, VFIO_CHECK_EXTENSION, iommu_type);
VFIO_ASSERT_GT(ret, 0, "VFIO IOMMU type %lu not supported\n", iommu_type);
@@ -235,8 +233,14 @@ static void vfio_pci_container_setup(struct vfio_pci_device *device, const char
* because the IOMMU type is already set.
*/
(void)ioctl(iommu->container_fd, VFIO_SET_IOMMU, (void *)iommu_type);
+}
- device->fd = ioctl(device->group_fd, VFIO_GROUP_GET_DEVICE_FD, bdf);
+static void vfio_pci_container_setup(struct vfio_pci_device *device)
+{
+ vfio_pci_group_setup(device);
+ vfio_pci_iommu_setup(device);
+
+ device->fd = ioctl(device->group_fd, VFIO_GROUP_GET_DEVICE_FD, device->bdf);
VFIO_ASSERT_GE(device->fd, 0);
}
@@ -336,9 +340,7 @@ static void vfio_pci_iommufd_setup(struct vfio_pci_device *device,
vfio_device_attach_iommufd_pt(device->fd, device->iommu->ioas_id);
}
-struct vfio_pci_device *__vfio_pci_device_init(const char *bdf,
- struct iommu *iommu,
- int device_fd)
+struct vfio_pci_device *vfio_pci_device_alloc(const char *bdf, struct iommu *iommu)
{
struct vfio_pci_device *device;
@@ -349,9 +351,20 @@ struct vfio_pci_device *__vfio_pci_device_init(const char *bdf,
device->iommu = iommu;
device->bdf = bdf;
+ return device;
+}
+
+struct vfio_pci_device *__vfio_pci_device_init(const char *bdf,
+ struct iommu *iommu,
+ int device_fd)
+{
+ struct vfio_pci_device *device;
+
+ device = vfio_pci_device_alloc(bdf, iommu);
+
if (iommu->mode->container_path) {
VFIO_ASSERT_EQ(device_fd, -1);
- vfio_pci_container_setup(device, bdf);
+ vfio_pci_container_setup(device);
} else {
vfio_pci_iommufd_setup(device, bdf, device_fd);
}
--
2.53.0.rc1.225.gd81095ad13-goog
^ permalink raw reply [flat|nested] 32+ messages in thread* [PATCH v2 21/22] vfio: selftests: Verify that opening VFIO device fails during Live Update
2026-01-29 21:24 [PATCH v2 00/22] vfio/pci: Base Live Update support for VFIO device files David Matlack
` (19 preceding siblings ...)
2026-01-29 21:25 ` [PATCH v2 20/22] vfio: selftests: Expose low-level helper routines for setting up struct vfio_pci_device David Matlack
@ 2026-01-29 21:25 ` David Matlack
2026-01-29 21:25 ` [PATCH v2 22/22] vfio: selftests: Add continuous DMA to vfio_pci_liveupdate_kexec_test David Matlack
21 siblings, 0 replies; 32+ messages in thread
From: David Matlack @ 2026-01-29 21:25 UTC (permalink / raw)
To: Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Matlack, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
Verify that opening a VFIO device through its cdev file and via
VFIO_GROUP_GET_DEVICE_FD both fail with -EBUSY if the device was
preserved across a Live Update. When a device file is preserve across a
Live Update, the file must be retrieved from /dev/liveupdate, not from
VFIO directly.
Signed-off-by: David Matlack <dmatlack@google.com>
---
.../vfio/vfio_pci_liveupdate_kexec_test.c | 38 +++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c b/tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c
index 15b3e3af91d1..65c48196e44e 100644
--- a/tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c
+++ b/tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c
@@ -36,6 +36,42 @@ static void before_kexec(int luo_fd)
daemonize_and_wait();
}
+static void check_open_vfio_device_fails(void)
+{
+ const char *cdev_path = vfio_pci_get_cdev_path(device_bdf);
+ struct vfio_pci_device *device;
+ struct iommu *iommu;
+ int ret, i;
+
+ printf("Checking open(%s) fails\n", cdev_path);
+ ret = open(cdev_path, O_RDWR);
+ VFIO_ASSERT_EQ(ret, -1);
+ VFIO_ASSERT_EQ(errno, EBUSY);
+ free((void *)cdev_path);
+
+ for (i = 0; i < nr_iommu_modes; i++) {
+ if (!iommu_modes[i].container_path)
+ continue;
+
+ iommu = iommu_init(iommu_modes[i].name);
+
+ device = vfio_pci_device_alloc(device_bdf, iommu);
+ vfio_pci_group_setup(device);
+ vfio_pci_iommu_setup(device);
+
+ printf("Checking ioctl(group_fd, VFIO_GROUP_GET_DEVICE_FD, \"%s\") fails (%s)\n",
+ device_bdf, iommu_modes[i].name);
+
+ ret = ioctl(device->group_fd, VFIO_GROUP_GET_DEVICE_FD, device->bdf);
+ VFIO_ASSERT_EQ(ret, -1);
+ VFIO_ASSERT_EQ(errno, EBUSY);
+
+ close(device->group_fd);
+ free(device);
+ iommu_cleanup(iommu);
+ }
+}
+
static void after_kexec(int luo_fd, int state_session_fd)
{
struct vfio_pci_device *device;
@@ -44,6 +80,8 @@ static void after_kexec(int luo_fd, int state_session_fd)
int device_fd;
int stage;
+ check_open_vfio_device_fails();
+
restore_and_read_stage(state_session_fd, STATE_TOKEN, &stage);
VFIO_ASSERT_EQ(stage, 2);
--
2.53.0.rc1.225.gd81095ad13-goog
^ permalink raw reply [flat|nested] 32+ messages in thread* [PATCH v2 22/22] vfio: selftests: Add continuous DMA to vfio_pci_liveupdate_kexec_test
2026-01-29 21:24 [PATCH v2 00/22] vfio/pci: Base Live Update support for VFIO device files David Matlack
` (20 preceding siblings ...)
2026-01-29 21:25 ` [PATCH v2 21/22] vfio: selftests: Verify that opening VFIO device fails during Live Update David Matlack
@ 2026-01-29 21:25 ` David Matlack
21 siblings, 0 replies; 32+ messages in thread
From: David Matlack @ 2026-01-29 21:25 UTC (permalink / raw)
To: Alex Williamson
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro,
Alistair Popple, Andrew Morton, Ankit Agrawal, Bjorn Helgaas,
Chris Li, David Matlack, David Rientjes, Jacob Pan,
Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet, Josh Hilke,
Kevin Tian, kexec, kvm, Leon Romanovsky, Leon Romanovsky,
linux-doc, linux-kernel, linux-kselftest, linux-mm, linux-pci,
Lukas Wunner, Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Rodrigo Vivi, Saeed Mahameed,
Samiullah Khawaja, Shuah Khan, Thomas Hellström,
Tomita Moeko, Vipin Sharma, Vivek Kasireddy, William Tu, Yi Liu,
Zhu Yanjun
Add a long-running DMA memcpy operation to
vfio_pci_liveupdate_kexec_test so that the device attempts to perform
DMAs continuously during the Live Update.
At this point iommufd preservation is not supported and bus mastering is
not kept enabled on the device during across the kexec, so most of these
DMAs will be dropped. However this test ensures that the current device
preservation support does not lead to system instability or crashes if
the device is active. And once iommufd and bus mastering are preserved,
this test can be relaxed to check that the DMA operations completed
successfully.
Signed-off-by: David Matlack <dmatlack@google.com>
---
.../vfio/vfio_pci_liveupdate_kexec_test.c | 129 ++++++++++++++++++
1 file changed, 129 insertions(+)
diff --git a/tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c b/tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c
index 65c48196e44e..36bddfbb88ed 100644
--- a/tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c
+++ b/tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c
@@ -1,8 +1,16 @@
// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/sizes.h>
+#include <sys/mman.h>
+
#include <libliveupdate.h>
#include <libvfio.h>
+#define MEMCPY_SIZE SZ_1G
+#define DRIVER_SIZE SZ_1M
+#define MEMFD_SIZE (MEMCPY_SIZE + DRIVER_SIZE)
+
+static struct dma_region memcpy_region;
static const char *device_bdf;
static char state_session[LIVEUPDATE_SESSION_NAME_LENGTH];
@@ -11,8 +19,89 @@ static char device_session[LIVEUPDATE_SESSION_NAME_LENGTH];
enum {
STATE_TOKEN,
DEVICE_TOKEN,
+ MEMFD_TOKEN,
};
+static void dma_memcpy_one(struct vfio_pci_device *device)
+{
+ void *src = memcpy_region.vaddr, *dst;
+ u64 size;
+
+ size = min_t(u64, memcpy_region.size / 2, device->driver.max_memcpy_size);
+ dst = src + size;
+
+ memset(src, 1, size);
+ memset(dst, 0, size);
+
+ printf("Kicking off 1 DMA memcpy operations of size 0x%lx...\n", size);
+ vfio_pci_driver_memcpy(device,
+ to_iova(device, src),
+ to_iova(device, dst),
+ size);
+
+ VFIO_ASSERT_EQ(memcmp(src, dst, size), 0);
+}
+
+static void dma_memcpy_start(struct vfio_pci_device *device)
+{
+ void *src = memcpy_region.vaddr, *dst;
+ u64 count, size;
+
+ size = min_t(u64, memcpy_region.size / 2, device->driver.max_memcpy_size);
+ dst = src + size;
+
+ /*
+ * Rough Math: If we assume the device will perform memcpy at a rate of
+ * 30GB/s then 7200GB of transfers will run for about 4 minutes.
+ */
+ count = (u64)7200 * SZ_1G / size;
+ count = min_t(u64, count, device->driver.max_memcpy_count);
+
+ memset(src, 1, size / 2);
+ memset(dst, 0, size / 2);
+
+ printf("Kicking off %lu DMA memcpy operations of size 0x%lx...\n", count, size);
+ vfio_pci_driver_memcpy_start(device,
+ to_iova(device, src),
+ to_iova(device, dst),
+ size, count);
+}
+
+static void dma_memfd_map(struct vfio_pci_device *device, int fd)
+{
+ void *vaddr;
+
+ vaddr = mmap(NULL, MEMFD_SIZE, PROT_WRITE, MAP_SHARED, fd, 0);
+ VFIO_ASSERT_NE(vaddr, MAP_FAILED);
+
+ memcpy_region.iova = SZ_4G;
+ memcpy_region.size = MEMCPY_SIZE;
+ memcpy_region.vaddr = vaddr;
+ iommu_map(device->iommu, &memcpy_region);
+
+ device->driver.region.iova = memcpy_region.iova + memcpy_region.size;
+ device->driver.region.size = DRIVER_SIZE;
+ device->driver.region.vaddr = vaddr + memcpy_region.size;
+ iommu_map(device->iommu, &device->driver.region);
+}
+
+static void dma_memfd_setup(struct vfio_pci_device *device, int session_fd)
+{
+ int fd, ret;
+
+ fd = memfd_create("dma-buffer", 0);
+ VFIO_ASSERT_GE(fd, 0);
+
+ ret = fallocate(fd, 0, 0, MEMFD_SIZE);
+ VFIO_ASSERT_EQ(ret, 0);
+
+ printf("Preserving memfd of size 0x%x in session\n", MEMFD_SIZE);
+ ret = luo_session_preserve_fd(session_fd, fd, MEMFD_TOKEN);
+ VFIO_ASSERT_EQ(ret, 0);
+
+ dma_memfd_map(device, fd);
+}
+
static void before_kexec(int luo_fd)
{
struct vfio_pci_device *device;
@@ -32,6 +121,27 @@ static void before_kexec(int luo_fd)
ret = luo_session_preserve_fd(session_fd, device->fd, DEVICE_TOKEN);
VFIO_ASSERT_EQ(ret, 0);
+ dma_memfd_setup(device, session_fd);
+
+ /*
+ * If the device has a selftests driver, kick off a long-running DMA
+ * operation to exercise the device trying to DMA during a Live Update.
+ * Since iommufd preservation is not supported yet, these DMAs should be
+ * dropped. So this is just looking to verify that the system does not
+ * fall over and crash as a result of a busy device being preserved.
+ */
+ if (device->driver.ops) {
+ vfio_pci_driver_init(device);
+ dma_memcpy_start(device);
+
+ /*
+ * Disable interrupts on the device or freeze() will fail.
+ * Unfortunately there isn't a way to easily have a test for
+ * that here since the check happens during shutdown.
+ */
+ vfio_pci_msix_disable(device);
+ }
+
close(luo_fd);
daemonize_and_wait();
}
@@ -78,6 +188,7 @@ static void after_kexec(int luo_fd, int state_session_fd)
struct iommu *iommu;
int session_fd;
int device_fd;
+ int memfd;
int stage;
check_open_vfio_device_fails();
@@ -88,6 +199,10 @@ static void after_kexec(int luo_fd, int state_session_fd)
session_fd = luo_retrieve_session(luo_fd, device_session);
VFIO_ASSERT_GE(session_fd, 0);
+ printf("Retrieving memfd from LUO\n");
+ memfd = luo_session_retrieve_fd(session_fd, MEMFD_TOKEN);
+ VFIO_ASSERT_GE(memfd, 0);
+
printf("Finishing the session before retrieving the device (should fail)\n");
VFIO_ASSERT_NE(luo_session_finish(session_fd), 0);
@@ -109,9 +224,23 @@ static void after_kexec(int luo_fd, int state_session_fd)
*/
device = __vfio_pci_device_init(device_bdf, iommu, device_fd);
+ dma_memfd_map(device, memfd);
+
printf("Finishing the session\n");
VFIO_ASSERT_EQ(luo_session_finish(session_fd), 0);
+ /*
+ * Once iommufd preservation is supported and the device is kept fully
+ * running across the Live Update, this should wait for the long-
+ * running DMA memcpy operation kicked off in before_kexec() to
+ * complete. But for now we expect the device to be reset so just
+ * trigger a single memcpy to make sure it's still functional.
+ */
+ if (device->driver.ops) {
+ vfio_pci_driver_init(device);
+ dma_memcpy_one(device);
+ }
+
vfio_pci_device_cleanup(device);
iommu_cleanup(iommu);
}
--
2.53.0.rc1.225.gd81095ad13-goog
^ permalink raw reply [flat|nested] 32+ messages in thread