* [PATCH v3 09/24] vfio/pci: Notify PCI subsystem about devices preserved across Live Update
From: David Matlack @ 2026-03-23 23:58 UTC (permalink / raw)
To: Alex Williamson, Bjorn Helgaas
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro, Andrew Morton,
Ankit Agrawal, Arnd Bergmann, Askar Safin, Borislav Petkov (AMD),
Chris Li, Dapeng Mi, David Matlack, David Rientjes, Feng Tang,
Jacob Pan, Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet,
Josh Hilke, Kees Cook, Kevin Tian, kexec, kvm, Leon Romanovsky,
Leon Romanovsky, linux-doc, linux-kernel, linux-kselftest,
linux-mm, linux-pci, Li RongQing, Lukas Wunner, Marco Elver,
Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Paul E. McKenney, Pawan Gupta,
Peter Zijlstra (Intel), Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Randy Dunlap, Rodrigo Vivi,
Saeed Mahameed, Samiullah Khawaja, Shuah Khan, Vipin Sharma,
Vivek Kasireddy, William Tu, Yi Liu, Zhu Yanjun
In-Reply-To: <20260323235817.1960573-1-dmatlack@google.com>
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 | 44 +++++++++++++++++++++++---
1 file changed, 39 insertions(+), 5 deletions(-)
diff --git a/drivers/vfio/pci/vfio_pci_liveupdate.c b/drivers/vfio/pci/vfio_pci_liveupdate.c
index 4b83a02401aa..b960ec3ffbf2 100644
--- a/drivers/vfio/pci/vfio_pci_liveupdate.c
+++ b/drivers/vfio/pci/vfio_pci_liveupdate.c
@@ -67,6 +67,9 @@
* interrupts on the device will cause the ``reboot(LINUX_REBOOT_CMD_KEXEC)``
* syscall (to initiate the kexec) to fail.
*
+ * In addition, the device must meet all of the restrictions imposed by the
+ * core PCI layer documented at :doc:`/PCI/liveupdate`.
+ *
* Preservation Behavior
* =====================
*
@@ -136,23 +139,37 @@ static int vfio_pci_liveupdate_preserve(struct liveupdate_file_op_args *args)
struct vfio_pci_core_device_ser *ser;
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;
+ ret = pci_liveupdate_preserve(pdev);
+ if (ret)
+ return ret;
+
ser = kho_alloc_preserve(sizeof(*ser));
- if (IS_ERR(ser))
- return PTR_ERR(ser);
+ if (IS_ERR(ser)) {
+ ret = PTR_ERR(ser);
+ goto err_unpreserve;
+ }
ser->bdf = pci_dev_id(pdev);
ser->domain = pci_domain_nr(pdev->bus);
args->serialized_data = virt_to_phys(ser);
return 0;
+
+err_unpreserve:
+ pci_liveupdate_unpreserve(pdev);
+ return ret;
}
static void vfio_pci_liveupdate_unpreserve(struct liveupdate_file_op_args *args)
{
+ struct vfio_device *device = vfio_device_from_file(args->file);
+
+ pci_liveupdate_unpreserve(to_pci_dev(device->dev));
kho_unpreserve_free(phys_to_virt(args->serialized_data));
}
@@ -213,6 +230,10 @@ static int vfio_pci_liveupdate_retrieve(struct liveupdate_file_op_args *args)
if (!device)
return -ENODEV;
+ ret = pci_liveupdate_retrieve(to_pci_dev(device->dev));
+ if (ret)
+ goto out;
+
file = vfio_device_liveupdate_cdev_open(device);
if (IS_ERR(file)) {
ret = PTR_ERR(file);
@@ -233,6 +254,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_finish(to_pci_dev(device->dev));
kho_restore_free(phys_to_virt(args->serialized_data));
}
@@ -257,13 +281,23 @@ int __init vfio_pci_liveupdate_init(void)
int ret;
ret = liveupdate_register_file_handler(&vfio_pci_liveupdate_fh);
- if (ret && ret != -EOPNOTSUPP)
- return ret;
+ if (ret)
+ goto err_return;
+
+ ret = pci_liveupdate_register_flb(&vfio_pci_liveupdate_fh);
+ if (ret)
+ goto err_unregister;
return 0;
+
+err_unregister:
+ liveupdate_unregister_file_handler(&vfio_pci_liveupdate_fh);
+err_return:
+ return (ret == -EOPNOTSUPP) ? 0 : ret;
}
void vfio_pci_liveupdate_cleanup(void)
{
- liveupdate_unregister_file_handler(&vfio_pci_liveupdate_fh);
+ pci_liveupdate_unregister_flb(&vfio_pci_liveupdate_fh);
+ liveupdate_unregister_file_handler(&vfio_pci_liveupdate_fh);
}
--
2.53.0.983.g0bb29b3bc5-goog
^ permalink raw reply related
* [PATCH v3 08/24] vfio/pci: Retrieve preserved device files after Live Update
From: David Matlack @ 2026-03-23 23:58 UTC (permalink / raw)
To: Alex Williamson, Bjorn Helgaas
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro, Andrew Morton,
Ankit Agrawal, Arnd Bergmann, Askar Safin, Borislav Petkov (AMD),
Chris Li, Dapeng Mi, David Matlack, David Rientjes, Feng Tang,
Jacob Pan, Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet,
Josh Hilke, Kees Cook, Kevin Tian, kexec, kvm, Leon Romanovsky,
Leon Romanovsky, linux-doc, linux-kernel, linux-kselftest,
linux-mm, linux-pci, Li RongQing, Lukas Wunner, Marco Elver,
Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Paul E. McKenney, Pawan Gupta,
Peter Zijlstra (Intel), Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Randy Dunlap, Rodrigo Vivi,
Saeed Mahameed, Samiullah Khawaja, Shuah Khan, Vipin Sharma,
Vivek Kasireddy, William Tu, Yi Liu, Zhu Yanjun
In-Reply-To: <20260323235817.1960573-1-dmatlack@google.com>
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 | 59 ++++++++++++++++++++++----
drivers/vfio/pci/vfio_pci_liveupdate.c | 52 ++++++++++++++++++++++-
drivers/vfio/vfio_main.c | 13 ++++++
include/linux/vfio.h | 11 +++++
4 files changed, 124 insertions(+), 11 deletions(-)
diff --git a/drivers/vfio/device_cdev.c b/drivers/vfio/device_cdev.c
index 8ceca24ac136..edf322315a41 100644
--- a/drivers/vfio/device_cdev.c
+++ b/drivers/vfio/device_cdev.c
@@ -2,6 +2,7 @@
/*
* Copyright (c) 2023 Intel Corporation.
*/
+#include <linux/anon_inodes.h>
#include <linux/vfio.h>
#include <linux/iommufd.h>
@@ -16,15 +17,10 @@ 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)
+static int vfio_device_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;
+ struct file *file = *filep;
int ret;
/* Paired with the put in vfio_device_fops_release() */
@@ -37,22 +33,67 @@ int vfio_device_fops_cdev_open(struct inode *inode, struct file *filep)
goto err_put_registration;
}
- filep->private_data = df;
+ /*
+ * 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).
+ */
+ if (!file) {
+ 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 err_free_device_file;
+ }
+
+ *filep = file;
+ }
+
+ file->private_data = df;
/*
* Use the pseudo fs inode on the device to link all mmaps
* to the same address space, allowing us to unmap all vmas
* associated to this device using unmap_mapping_range().
*/
- filep->f_mapping = device->inode->i_mapping;
+ file->f_mapping = device->inode->i_mapping;
return 0;
+err_free_device_file:
+ kvfree(df);
err_put_registration:
vfio_device_put_registration(device);
return ret;
}
+struct file *vfio_device_liveupdate_cdev_open(struct vfio_device *device)
+{
+ struct file *file = NULL;
+ int ret;
+
+ ret = vfio_device_cdev_open(device, &file);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return file;
+}
+EXPORT_SYMBOL_GPL(vfio_device_liveupdate_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 *file)
+{
+ struct vfio_device *device = container_of(inode->i_cdev,
+ struct vfio_device, cdev);
+
+ return vfio_device_cdev_open(device, &file);
+}
+
static void vfio_df_get_kvm_safe(struct vfio_device_file *df)
{
spin_lock(&df->kvm_ref_lock);
diff --git a/drivers/vfio/pci/vfio_pci_liveupdate.c b/drivers/vfio/pci/vfio_pci_liveupdate.c
index c4ebc7c486e5..4b83a02401aa 100644
--- a/drivers/vfio/pci/vfio_pci_liveupdate.c
+++ b/drivers/vfio/pci/vfio_pci_liveupdate.c
@@ -39,7 +39,13 @@
* preserved, so there is no way for the file to be destroyed or the device
* to be unbound from the vfio-pci driver while it is preserved.
*
- * Retrieving the file after kexec is not yet supported.
+ * After kexec, the preserved VFIO device file can be retrieved from the session
+ * just like any other preserved file::
+ *
+ * ioctl(session_fd, LIVEUPDATE_SESSION_RETRIEVE_FD, &arg);
+ * device_fd = arg.fd;
+ * ...
+ * ioctl(session_fd, LIVEUPDATE_SESSION_FINISH, ...);
*
* Restrictions
* ============
@@ -85,6 +91,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/file.h>
#include <linux/kexec_handover.h>
#include <linux/kho/abi/vfio_pci.h>
#include <linux/liveupdate.h>
@@ -180,13 +187,53 @@ static int vfio_pci_liveupdate_freeze(struct liveupdate_file_op_args *args)
return 0;
}
+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 = 0;
+
+ ser = phys_to_virt(args->serialized_data);
+
+ device = vfio_find_device(ser, match_device);
+ if (!device)
+ return -ENODEV;
+
+ file = vfio_device_liveupdate_cdev_open(device);
+ if (IS_ERR(file)) {
+ ret = PTR_ERR(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->retrieve_status > 0;
}
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 = {
@@ -195,6 +242,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 8b222f71bbab..e5886235cad4 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>
@@ -1766,6 +1767,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 e9d3ddb715c5..7384965d15d7 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -393,4 +393,15 @@ 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)
+struct file *vfio_device_liveupdate_cdev_open(struct vfio_device *device);
+#else
+static inline struct file *vfio_device_liveupdate_cdev_open(struct vfio_device *device)
+{
+ return ERR_PTR(-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.983.g0bb29b3bc5-goog
^ permalink raw reply related
* Re: [PATCH v2 3/9] kernel/api: add debugfs interface for kernel API specifications
From: Sasha Levin @ 2026-03-23 23:58 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: linux-api, linux-kernel, linux-doc, linux-fsdevel, linux-kbuild,
linux-kselftest, workflows, tools, x86, Thomas Gleixner,
Paul E . McKenney, Jonathan Corbet, Dmitry Vyukov, Randy Dunlap,
Cyril Hrubis, Kees Cook, Jake Edge, David Laight, Askar Safin,
Gabriele Paoloni, Mauro Carvalho Chehab, Christian Brauner,
Alexander Viro, Andrew Morton, Masahiro Yamada, Shuah Khan,
Ingo Molnar, Arnd Bergmann
In-Reply-To: <2026032309-jargon-stalling-28c2@gregkh>
On Mon, Mar 23, 2026 at 02:52:58PM +0100, Greg Kroah-Hartman wrote:
>On Sun, Mar 22, 2026 at 08:10:17AM -0400, Sasha Levin wrote:
>> Add a debugfs interface to expose kernel API specifications at runtime.
>> This allows tools and users to query the complete API specifications
>> through the debugfs filesystem.
>>
>> The interface provides:
>> - /sys/kernel/debug/kapi/list - lists all available API specifications
>> - /sys/kernel/debug/kapi/specs/<name> - detailed info for each API
>>
>> Each specification file includes:
>> - Function name, version, and descriptions
>> - Execution context requirements and flags
>> - Parameter details with types, flags, and constraints
>> - Return value specifications and success conditions
>> - Error codes with descriptions and conditions
>> - Locking requirements and constraints
>> - Signal handling specifications
>> - Examples, notes, and deprecation status
>>
>> This enables runtime introspection of kernel APIs for documentation
>> tools, static analyzers, and debugging purposes.
>>
>> Signed-off-by: Sasha Levin <sashal@kernel.org>
>
>Debugfs logic looks sane, nice.
Thanks!
>But this only works if the kabi stuff is built into the kernel image,
>right? This doesn't work if any of these abi sections are in a module
>or am I missing that logic here?
That is correct, for now.
I'm only trying to tackle syscalls to begin with, and since no syscalls live in
modules, we have no need for module support.
--
Thanks,
Sasha
^ permalink raw reply
* [PATCH v3 07/24] vfio/pci: Preserve vfio-pci device files across Live Update
From: David Matlack @ 2026-03-23 23:57 UTC (permalink / raw)
To: Alex Williamson, Bjorn Helgaas
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro, Andrew Morton,
Ankit Agrawal, Arnd Bergmann, Askar Safin, Borislav Petkov (AMD),
Chris Li, Dapeng Mi, David Matlack, David Rientjes, Feng Tang,
Jacob Pan, Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet,
Josh Hilke, Kees Cook, Kevin Tian, kexec, kvm, Leon Romanovsky,
Leon Romanovsky, linux-doc, linux-kernel, linux-kselftest,
linux-mm, linux-pci, Li RongQing, Lukas Wunner, Marco Elver,
Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Paul E. McKenney, Pawan Gupta,
Peter Zijlstra (Intel), Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Randy Dunlap, Rodrigo Vivi,
Saeed Mahameed, Samiullah Khawaja, Shuah Khan, Vipin Sharma,
Vivek Kasireddy, William Tu, Yi Liu, Zhu Yanjun
In-Reply-To: <20260323235817.1960573-1-dmatlack@google.com>
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_core.c | 57 +++++----
drivers/vfio/pci/vfio_pci_liveupdate.c | 156 ++++++++++++++++++++++++-
drivers/vfio/pci/vfio_pci_priv.h | 4 +
drivers/vfio/vfio_main.c | 3 +-
include/linux/kho/abi/vfio_pci.h | 15 +++
include/linux/vfio.h | 2 +
7 files changed, 213 insertions(+), 26 deletions(-)
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index 41dcbe4ace67..351480d13f6e 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_core.c b/drivers/vfio/pci/vfio_pci_core.c
index d43745fe4c84..81f941323641 100644
--- a/drivers/vfio/pci/vfio_pci_core.c
+++ b/drivers/vfio/pci/vfio_pci_core.c
@@ -585,9 +585,42 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev)
}
EXPORT_SYMBOL_GPL(vfio_pci_core_enable);
+void vfio_pci_core_try_reset(struct vfio_pci_core_device *vdev)
+{
+ struct pci_dev *pdev = vdev->pdev;
+ struct pci_dev *bridge = pci_upstream_bridge(pdev);
+
+ lockdep_assert_held(&vdev->vdev.dev_set->lock);
+
+ if (!vdev->reset_works)
+ return;
+
+ /*
+ * Try to get the locks ourselves to prevent a deadlock. The
+ * success of this is dependent on being able to lock the device,
+ * which is not always possible.
+ *
+ * We cannot use the "try" reset interface here, since that will
+ * overwrite the previously restored configuration information.
+ */
+ if (bridge && !pci_dev_trylock(bridge))
+ return;
+
+ if (!pci_dev_trylock(pdev))
+ goto out;
+
+ if (!__pci_reset_function_locked(pdev))
+ vdev->needs_reset = false;
+
+ pci_dev_unlock(pdev);
+out:
+ if (bridge)
+ pci_dev_unlock(bridge);
+}
+EXPORT_SYMBOL_GPL(vfio_pci_core_try_reset);
+
void vfio_pci_core_disable(struct vfio_pci_core_device *vdev)
{
- struct pci_dev *bridge;
struct pci_dev *pdev = vdev->pdev;
struct vfio_pci_dummy_resource *dummy_res, *tmp;
struct vfio_pci_ioeventfd *ioeventfd, *ioeventfd_tmp;
@@ -687,27 +720,7 @@ void vfio_pci_core_disable(struct vfio_pci_core_device *vdev)
*/
pci_write_config_word(pdev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
- /*
- * Try to get the locks ourselves to prevent a deadlock. The
- * success of this is dependent on being able to lock the device,
- * which is not always possible.
- * We can not use the "try" reset interface here, which will
- * overwrite the previously restored configuration information.
- */
- if (vdev->reset_works) {
- bridge = pci_upstream_bridge(pdev);
- if (bridge && !pci_dev_trylock(bridge))
- goto out_restore_state;
- if (pci_dev_trylock(pdev)) {
- if (!__pci_reset_function_locked(pdev))
- vdev->needs_reset = false;
- pci_dev_unlock(pdev);
- }
- if (bridge)
- pci_dev_unlock(bridge);
- }
-
-out_restore_state:
+ vfio_pci_core_try_reset(vdev);
pci_restore_state(pdev);
out:
pci_disable_device(pdev);
diff --git a/drivers/vfio/pci/vfio_pci_liveupdate.c b/drivers/vfio/pci/vfio_pci_liveupdate.c
index 5ea5af46b159..c4ebc7c486e5 100644
--- a/drivers/vfio/pci/vfio_pci_liveupdate.c
+++ b/drivers/vfio/pci/vfio_pci_liveupdate.c
@@ -6,27 +6,178 @@
* David Matlack <dmatlack@google.com>
*/
+/**
+ * DOC: VFIO PCI Preservation via LUO
+ *
+ * VFIO PCI devices can be preserved over a kexec using the Live Update
+ * Orchestrator (LUO) file preservation. This allows userspace (such as a VMM)
+ * to transfer an in-use device to the next kernel.
+ *
+ * .. note::
+ * The support for preserving VFIO PCI devices is currently *partial* and
+ * should be considered *experimental*. It should only be used by developers
+ * working on expanding the support for the time being.
+ *
+ * To avoid accidental usage while the support is still experimental, this
+ * support is hidden behind a default-disable config option
+ * ``CONFIG_VFIO_PCI_LIVEUPDATE``. Once the kernel support has stabilized and
+ * become complete, this option will be enabled by default when
+ * ``CONFIG_VFIO_PCI`` and ``CONFIG_LIVEUPDATE`` are enabled.
+ *
+ * Usage Example
+ * =============
+ *
+ * VFIO PCI devices can be preserved across a kexec by preserving the file
+ * associated with the device in a LUO session::
+ *
+ * device_fd = open("/dev/vfio/devices/X");
+ * ...
+ * ioctl(session_fd, LIVEUPDATE_SESSION_PRESERVE_FD, { ..., device_fd, ...});
+ *
+ * .. note::
+ * LUO will hold an extra reference to the device file for as long as it is
+ * preserved, so there is no way for the file to be destroyed or the device
+ * to be unbound from the vfio-pci driver while it is preserved.
+ *
+ * Retrieving the file after kexec is not yet supported.
+ *
+ * Restrictions
+ * ============
+ *
+ * The kernel imposes the following restrictions when preserving VFIO devices:
+ *
+ * * The device must be bound to the ``vfio-pci`` driver.
+ *
+ * * ``CONFIG_VFIO_PCI_ZDEV_KVM`` must not be enabled. This may be relaxed in
+ * the future.
+ *
+ * * The device not be an Intel display device. This may be relaxed in the
+ * future.
+ *
+ * * The device file must have been acquired from the VFIO character device,
+ * not ``VFIO_GROUP_GET_DEVICE_FD``.
+ *
+ * * The device must have interrupt disable prior to kexec. Failure to disable
+ * interrupts on the device will cause the ``reboot(LINUX_REBOOT_CMD_KEXEC)``
+ * syscall (to initiate the kexec) to fail.
+ *
+ * Preservation Behavior
+ * =====================
+ *
+ * The eventual goal of this support is to avoid disrupting the workload, state,
+ * or configuration of each preserved device during a Live Update. This would
+ * include allowing the device to perform DMA to preserved memory buffers and
+ * perform P2P DMA to other preserved devices. However, there are many pieces
+ * that still need to land in the kernel.
+ *
+ * For now, VFIO only preserves the following state for for devices:
+ *
+ * * The PCI Segment, Bus, Device, and Function numbers of the device. The
+ * kernel guarantees the these will not change across a kexec when a device
+ * is preserved.
+ *
+ * Since the kernel is not yet prepared to preserve all parts of the device and
+ * its dependencies (such as DMA mappings), VFIO currently resets and restores
+ * preserved devices back into an idle state during kexec, before handing off
+ * control to the next kernel. This will be relaxed in future versions of the
+ * kernel once it is safe to allow the device to keep running across kexec.
+ */
+
#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 *device = vfio_device_from_file(file);
+ struct vfio_pci_core_device *vdev;
+ struct pci_dev *pdev;
+
+ if (!device)
+ return false;
+
+ /* Live Update support is limited to cdev files. */
+ if (!vfio_device_cdev_opened(device))
+ return false;
+
+ if (device->ops != &vfio_pci_ops)
+ return false;
+
+ vdev = container_of(device, struct vfio_pci_core_device, vdev);
+ pdev = vdev->pdev;
+
+ /*
+ * Don't support specialized vfio-pci devices for now since they haven't
+ * been tested.
+ */
+ if (IS_ENABLED(CONFIG_VFIO_PCI_ZDEV_KVM) || vfio_pci_is_intel_display(pdev))
+ return false;
+
+ return true;
}
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;
+
+ 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;
+ }
+
+ ret = pci_load_saved_state(pdev, vdev->pci_saved_state);
+ if (ret)
+ return ret;
+
+ vfio_pci_core_try_reset(vdev);
+ pci_restore_state(pdev);
+ return 0;
}
static int vfio_pci_liveupdate_retrieve(struct liveupdate_file_op_args *args)
@@ -42,6 +193,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 cbf46e09da30..fa5c7f544f8a 100644
--- a/drivers/vfio/pci/vfio_pci_priv.h
+++ b/drivers/vfio/pci/vfio_pci_priv.h
@@ -11,6 +11,10 @@
/* Cap maximum number of ioeventfds per device (arbitrary) */
#define VFIO_PCI_IOEVENTFD_MAX 1000
+extern const struct vfio_device_ops vfio_pci_ops;
+
+void vfio_pci_core_try_reset(struct vfio_pci_core_device *vdev);
+
struct vfio_pci_ioeventfd {
struct list_head next;
struct vfio_pci_core_device *vdev;
diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c
index 742477546b15..8b222f71bbab 100644
--- a/drivers/vfio/vfio_main.c
+++ b/drivers/vfio/vfio_main.c
@@ -1436,7 +1436,7 @@ const struct file_operations vfio_device_fops = {
#endif
};
-static struct vfio_device *vfio_device_from_file(struct file *file)
+struct vfio_device *vfio_device_from_file(struct file *file)
{
struct vfio_device_file *df = file->private_data;
@@ -1444,6 +1444,7 @@ static struct vfio_device *vfio_device_from_file(struct file *file)
return NULL;
return df->device;
}
+EXPORT_SYMBOL_GPL(vfio_device_from_file);
/**
* 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 e2412b455e61..876aaf81dd92 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.
+ *
+ * @domain: The device's PCI domain number (segment).
+ * @bdf: The device's PCI bus, device, and function number.
+ */
+struct vfio_pci_core_device_ser {
+ u32 domain;
+ u16 bdf;
+} __packed;
+
#endif /* _LINUX_LIVEUPDATE_ABI_VFIO_PCI_H */
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index e90859956514..e9d3ddb715c5 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -81,6 +81,8 @@ struct vfio_device {
#endif
};
+struct vfio_device *vfio_device_from_file(struct file *file);
+
/**
* struct vfio_device_ops - VFIO bus driver device callbacks
*
--
2.53.0.983.g0bb29b3bc5-goog
^ permalink raw reply related
* [PATCH v3 06/24] vfio/pci: Register a file handler with Live Update Orchestrator
From: David Matlack @ 2026-03-23 23:57 UTC (permalink / raw)
To: Alex Williamson, Bjorn Helgaas
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro, Andrew Morton,
Ankit Agrawal, Arnd Bergmann, Askar Safin, Borislav Petkov (AMD),
Chris Li, Dapeng Mi, David Matlack, David Rientjes, Feng Tang,
Jacob Pan, Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet,
Josh Hilke, Kees Cook, Kevin Tian, kexec, kvm, Leon Romanovsky,
Leon Romanovsky, linux-doc, linux-kernel, linux-kselftest,
linux-mm, linux-pci, Li RongQing, Lukas Wunner, Marco Elver,
Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Paul E. McKenney, Pawan Gupta,
Peter Zijlstra (Intel), Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Randy Dunlap, Rodrigo Vivi,
Saeed Mahameed, Samiullah Khawaja, Shuah Khan, Vipin Sharma,
Vivek Kasireddy, William Tu, Yi Liu, Zhu Yanjun
In-Reply-To: <20260323235817.1960573-1-dmatlack@google.com>
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.
Put this support behind a new Kconfig VFIO_PCI_LIVEUPDATE that is marked
experimental and default-disabled until more of the device preservation
support has landed in the kernel.
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/Kconfig | 11 ++++
drivers/vfio/pci/Makefile | 1 +
drivers/vfio/pci/vfio_pci.c | 12 ++++-
drivers/vfio/pci/vfio_pci_liveupdate.c | 69 ++++++++++++++++++++++++++
drivers/vfio/pci/vfio_pci_priv.h | 14 ++++++
include/linux/kho/abi/vfio_pci.h | 28 +++++++++++
7 files changed, 135 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 96ea84948d76..a16a7ecc67a4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27685,6 +27685,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/Kconfig b/drivers/vfio/pci/Kconfig
index 1e82b44bda1a..8f087f7b58c3 100644
--- a/drivers/vfio/pci/Kconfig
+++ b/drivers/vfio/pci/Kconfig
@@ -58,6 +58,17 @@ config VFIO_PCI_ZDEV_KVM
config VFIO_PCI_DMABUF
def_bool y if VFIO_PCI_CORE && PCI_P2PDMA && DMA_SHARED_BUFFER
+config VFIO_PCI_LIVEUPDATE
+ bool "VFIO PCI support for Live Update (EXPERIMENTAL)"
+ depends on VFIO_PCI && PCI_LIVEUPDATE
+ help
+ Support for preserving devices bound to vfio-pci across a Live
+ Update. This option should only be enabled by developers working on
+ implementing this support. Once enough support has landed in the
+ kernel, this option will no longer be marked EXPERIMENTAL.
+
+ If you don't know what to do here, say N.
+
source "drivers/vfio/pci/mlx5/Kconfig"
source "drivers/vfio/pci/hisilicon/Kconfig"
diff --git a/drivers/vfio/pci/Makefile b/drivers/vfio/pci/Makefile
index e0a0757dd1d2..f462df61edb9 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_VFIO_PCI_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..41dcbe4ace67 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -170,6 +170,7 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ret = vfio_pci_core_register_device(vdev);
if (ret)
goto out_put_vdev;
+
return 0;
out_put_vdev:
@@ -264,10 +265,14 @@ static int __init vfio_pci_init(void)
vfio_pci_core_set_params(nointxmask, is_disable_vga, disable_idle_d3);
+ ret = vfio_pci_liveupdate_init();
+ if (ret)
+ return ret;
+
/* Register and scan for devices */
ret = pci_register_driver(&vfio_pci_driver);
if (ret)
- return ret;
+ goto err_liveupdate_cleanup;
vfio_pci_fill_ids();
@@ -275,12 +280,17 @@ static int __init vfio_pci_init(void)
pr_warn("device denylist disabled.\n");
return 0;
+
+err_liveupdate_cleanup:
+ vfio_pci_liveupdate_cleanup();
+ return ret;
}
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..5ea5af46b159
--- /dev/null
+++ b/drivers/vfio/pci/vfio_pci_liveupdate.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (c) 2026, 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)
+{
+ int ret;
+
+ ret = liveupdate_register_file_handler(&vfio_pci_liveupdate_fh);
+ if (ret && ret != -EOPNOTSUPP)
+ return ret;
+
+ return 0;
+}
+
+void vfio_pci_liveupdate_cleanup(void)
+{
+ 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..cbf46e09da30 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_VFIO_PCI_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_VFIO_PCI_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..e2412b455e61
--- /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
+ *
+ * VFIO uses the ABI defined below for preserving device files across a kexec
+ * reboot using LUO.
+ *
+ * Device metadata is serialized into memory which is then handed to the next
+ * kernel via KHO.
+ *
+ * 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.983.g0bb29b3bc5-goog
^ permalink raw reply related
* [PATCH v3 04/24] PCI: Inherit bus numbers from previous kernel during Live Update
From: David Matlack @ 2026-03-23 23:57 UTC (permalink / raw)
To: Alex Williamson, Bjorn Helgaas
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro, Andrew Morton,
Ankit Agrawal, Arnd Bergmann, Askar Safin, Borislav Petkov (AMD),
Chris Li, Dapeng Mi, David Matlack, David Rientjes, Feng Tang,
Jacob Pan, Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet,
Josh Hilke, Kees Cook, Kevin Tian, kexec, kvm, Leon Romanovsky,
Leon Romanovsky, linux-doc, linux-kernel, linux-kselftest,
linux-mm, linux-pci, Li RongQing, Lukas Wunner, Marco Elver,
Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Paul E. McKenney, Pawan Gupta,
Peter Zijlstra (Intel), Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Randy Dunlap, Rodrigo Vivi,
Saeed Mahameed, Samiullah Khawaja, Shuah Khan, Vipin Sharma,
Vivek Kasireddy, William Tu, Yi Liu, Zhu Yanjun
In-Reply-To: <20260323235817.1960573-1-dmatlack@google.com>
Inherit bus numbers from the previous kernel during a Live Update when
one or more PCI devices are being preserved, even if pci=assign-busses
is enabled.
During a Live Update, preserved devices will be allowed to continue
performing memory transactions. Thus the kernel cannot change the fabric
topology, including changing bus numbers, since that would requiring
disabling and flushing any memory transactions first.
So if pci=assign-busses is enabled, ignore it during the Live Update and
inherit all bus numbers assigned by the previous kernel. This will not
break users that rely on pci=assign-busses for their system to function
correctly since the system can be assumed to be in a functional state
already if a Live Update is underway. In other words, pci=assign-busses
would establish a functional topology during the initial cold boot, and
then that topology would remain fixed across any subsequent Live
Updates.
Signed-off-by: David Matlack <dmatlack@google.com>
---
.../admin-guide/kernel-parameters.txt | 6 +++-
drivers/pci/liveupdate.c | 5 ++-
drivers/pci/probe.c | 35 ++++++++++++++++---
3 files changed, 40 insertions(+), 6 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 03a550630644..beff9f3f8e3b 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -5156,7 +5156,11 @@ Kernel parameters
explicitly which ones they are.
assign-busses [X86] Always assign all PCI bus
numbers ourselves, overriding
- whatever the firmware may have done.
+ whatever the firmware may have done. Ignored
+ during a Live Update, where the kernel must
+ inherit the PCI topology (including bus numbers)
+ to avoid interrupting ongoing memory
+ transactions of preserved devices.
usepirqmask [X86] Honor the possible IRQ mask stored
in the BIOS $PIR table. This is needed on
some systems with broken BIOSes, notably
diff --git a/drivers/pci/liveupdate.c b/drivers/pci/liveupdate.c
index a3dbe06650ff..c1251f4f8438 100644
--- a/drivers/pci/liveupdate.c
+++ b/drivers/pci/liveupdate.c
@@ -84,7 +84,10 @@
* Update:
*
* * The PCI Segment, Bus, Device, and Function numbers assigned to the device
- * are guaranteed to remain the same across Live Update.
+ * are guaranteed to remain the same across Live Update. Note that this is
+ * true even if pci=assign-busses is set on the command line. The kernel will
+ * always inherit bus numbers assigned by the previous kernel during a Live
+ * Update.
*
* This list will be extended in the future as new support is added.
*
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index c60222d45659..165056d71e66 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1369,6 +1369,34 @@ bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub)
return true;
}
+static bool pci_assign_all_busses(void)
+{
+ if (!pcibios_assign_all_busses())
+ return false;
+
+ /*
+ * During a Live Update, preserved devices are are allowed to continue
+ * performing memory transactions. Thus the kernel cannot change the
+ * fabric topology, including changing bus numbers, since that would
+ * requiring disabling and flushing any memory transactions first.
+ *
+ * So if pci=assign-busses is enabled, ignore it during the Live Update
+ * and inherit all bus numbers assigned by the previous kernel. This
+ * will not break users that rely on pci=assign-busses for their system
+ * to function correctly since the system can be assumed to be in a
+ * functional state already if a Live Update is underway. In other
+ * words, pci=assign-busses should be used to establish working bus
+ * numbers during the initial cold boot, and then that topology would
+ * then remain fixed across any subsequent Live Updates.
+ */
+ if (pci_liveupdate_incoming_nr_devices()) {
+ pr_info_once("Ignoring pci=assign-busses and inheriting bus numbers during Live Update\n");
+ return false;
+ }
+
+ return true;
+}
+
/*
* pci_scan_bridge_extend() - Scan buses behind a bridge
* @bus: Parent bus the bridge is on
@@ -1396,6 +1424,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
int max, unsigned int available_buses,
int pass)
{
+ const bool assign_all_busses = pci_assign_all_busses();
struct pci_bus *child;
u32 buses;
u16 bctl;
@@ -1448,8 +1477,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
goto out;
}
- if ((secondary || subordinate) &&
- !pcibios_assign_all_busses() && !broken) {
+ if ((secondary || subordinate) && !assign_all_busses && !broken) {
unsigned int cmax, buses;
/*
@@ -1491,8 +1519,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)
-
+ if (assign_all_busses || broken)
/*
* Temporarily disable forwarding of the
* configuration cycles on all bridges in
--
2.53.0.983.g0bb29b3bc5-goog
^ permalink raw reply related
* [PATCH v3 05/24] docs: liveupdate: Add documentation for PCI
From: David Matlack @ 2026-03-23 23:57 UTC (permalink / raw)
To: Alex Williamson, Bjorn Helgaas
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro, Andrew Morton,
Ankit Agrawal, Arnd Bergmann, Askar Safin, Borislav Petkov (AMD),
Chris Li, Dapeng Mi, David Matlack, David Rientjes, Feng Tang,
Jacob Pan, Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet,
Josh Hilke, Kees Cook, Kevin Tian, kexec, kvm, Leon Romanovsky,
Leon Romanovsky, linux-doc, linux-kernel, linux-kselftest,
linux-mm, linux-pci, Li RongQing, Lukas Wunner, Marco Elver,
Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Paul E. McKenney, Pawan Gupta,
Peter Zijlstra (Intel), Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Randy Dunlap, Rodrigo Vivi,
Saeed Mahameed, Samiullah Khawaja, Shuah Khan, Vipin Sharma,
Vivek Kasireddy, William Tu, Yi Liu, Zhu Yanjun
In-Reply-To: <20260323235817.1960573-1-dmatlack@google.com>
Add documentation files for the PCI subsystem's participation in Live
Update, generated from the kernel-doc comments the code.
Signed-off-by: David Matlack <dmatlack@google.com>
---
Documentation/PCI/liveupdate.rst | 23 +++++++++++++++++++++++
Documentation/core-api/liveupdate.rst | 1 +
2 files changed, 24 insertions(+)
create mode 100644 Documentation/PCI/liveupdate.rst
diff --git a/Documentation/PCI/liveupdate.rst b/Documentation/PCI/liveupdate.rst
new file mode 100644
index 000000000000..04c9b675e8df
--- /dev/null
+++ b/Documentation/PCI/liveupdate.rst
@@ -0,0 +1,23 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+===========================
+PCI Support for Live Update
+===========================
+
+.. kernel-doc:: drivers/pci/liveupdate.c
+ :doc: PCI Live Update
+
+PCI Preservation ABI
+====================
+
+.. kernel-doc:: include/linux/kho/abi/pci.h
+ :doc: PCI File-Lifecycle Bound (FLB) Live Update ABI
+
+.. kernel-doc:: include/linux/kho/abi/pci.h
+ :internal:
+
+See Also
+========
+
+ * :doc:`/core-api/liveupdate`
+ * :doc:`/core-api/kho/index`
diff --git a/Documentation/core-api/liveupdate.rst b/Documentation/core-api/liveupdate.rst
index 5a292d0f3706..d56a7760978a 100644
--- a/Documentation/core-api/liveupdate.rst
+++ b/Documentation/core-api/liveupdate.rst
@@ -70,3 +70,4 @@ See Also
- :doc:`Live Update uAPI </userspace-api/liveupdate>`
- :doc:`/core-api/kho/index`
+- :doc:`PCI </PCI/liveupdate>`
--
2.53.0.983.g0bb29b3bc5-goog
^ permalink raw reply related
* [PATCH v3 03/24] PCI: Require Live Update preserved devices are in singleton iommu_groups
From: David Matlack @ 2026-03-23 23:57 UTC (permalink / raw)
To: Alex Williamson, Bjorn Helgaas
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro, Andrew Morton,
Ankit Agrawal, Arnd Bergmann, Askar Safin, Borislav Petkov (AMD),
Chris Li, Dapeng Mi, David Matlack, David Rientjes, Feng Tang,
Jacob Pan, Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet,
Josh Hilke, Kees Cook, Kevin Tian, kexec, kvm, Leon Romanovsky,
Leon Romanovsky, linux-doc, linux-kernel, linux-kselftest,
linux-mm, linux-pci, Li RongQing, Lukas Wunner, Marco Elver,
Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Paul E. McKenney, Pawan Gupta,
Peter Zijlstra (Intel), Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Randy Dunlap, Rodrigo Vivi,
Saeed Mahameed, Samiullah Khawaja, Shuah Khan, Vipin Sharma,
Vivek Kasireddy, William Tu, Yi Liu, Zhu Yanjun
In-Reply-To: <20260323235817.1960573-1-dmatlack@google.com>
Require that Live Update preserved devices are in singleton iommu_groups
during preservation (outgoing kernel) and retrieval (incoming kernel).
PCI devices preserved across Live Update will be allowed to perform
memory transactions throughout the Live Update. Thus IOMMU groups for
preserved devices must remain fixed. Since all current use cases for
Live Update are for PCI devices in singleton iommu_groups, require that
as a starting point. This avoids the complexity of needing to enforce
arbitrary iommu_group topologies while still allowing all current use
cases.
Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
drivers/pci/liveupdate.c | 34 +++++++++++++++++++++++++++++++++-
1 file changed, 33 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/liveupdate.c b/drivers/pci/liveupdate.c
index bec7b3500057..a3dbe06650ff 100644
--- a/drivers/pci/liveupdate.c
+++ b/drivers/pci/liveupdate.c
@@ -75,6 +75,8 @@
*
* * The device must not be a Physical Function (PF).
*
+ * * The device must be the only device in its IOMMU group.
+ *
* Preservation Behavior
* =====================
*
@@ -105,6 +107,7 @@
#include <linux/bsearch.h>
#include <linux/io.h>
+#include <linux/iommu.h>
#include <linux/kexec_handover.h>
#include <linux/kho/abi/pci.h>
#include <linux/liveupdate.h>
@@ -222,6 +225,31 @@ static void pci_ser_delete(struct pci_ser *ser, struct pci_dev *dev)
ser->nr_devices--;
}
+static int count_devices(struct device *dev, void *__nr_devices)
+{
+ (*(int *)__nr_devices)++;
+ return 0;
+}
+
+static int pci_liveupdate_validate_iommu_group(struct pci_dev *dev)
+{
+ struct iommu_group *group;
+ int nr_devices = 0;
+
+ group = iommu_group_get(&dev->dev);
+ if (group) {
+ iommu_group_for_each_dev(group, &nr_devices, count_devices);
+ iommu_group_put(group);
+ }
+
+ if (nr_devices != 1) {
+ pci_warn(dev, "Live Update preserved devices must be in singleton iommu groups!");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
int pci_liveupdate_preserve(struct pci_dev *dev)
{
struct pci_dev_ser new = INIT_PCI_DEV_SER(dev);
@@ -232,6 +260,10 @@ int pci_liveupdate_preserve(struct pci_dev *dev)
if (dev->is_virtfn || dev->is_physfn)
return -EINVAL;
+ ret = pci_liveupdate_validate_iommu_group(dev);
+ if (ret)
+ return ret;
+
guard(mutex)(&pci_flb_outgoing_lock);
if (dev->liveupdate_outgoing)
@@ -357,7 +389,7 @@ int pci_liveupdate_retrieve(struct pci_dev *dev)
if (!dev->liveupdate_incoming)
return -EINVAL;
- return 0;
+ return pci_liveupdate_validate_iommu_group(dev);
}
EXPORT_SYMBOL_GPL(pci_liveupdate_retrieve);
--
2.53.0.983.g0bb29b3bc5-goog
^ permalink raw reply related
* [PATCH v3 02/24] PCI: Add API to track PCI devices preserved across Live Update
From: David Matlack @ 2026-03-23 23:57 UTC (permalink / raw)
To: Alex Williamson, Bjorn Helgaas
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro, Andrew Morton,
Ankit Agrawal, Arnd Bergmann, Askar Safin, Borislav Petkov (AMD),
Chris Li, Dapeng Mi, David Matlack, David Rientjes, Feng Tang,
Jacob Pan, Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet,
Josh Hilke, Kees Cook, Kevin Tian, kexec, kvm, Leon Romanovsky,
Leon Romanovsky, linux-doc, linux-kernel, linux-kselftest,
linux-mm, linux-pci, Li RongQing, Lukas Wunner, Marco Elver,
Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Paul E. McKenney, Pawan Gupta,
Peter Zijlstra (Intel), Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Randy Dunlap, Rodrigo Vivi,
Saeed Mahameed, Samiullah Khawaja, Shuah Khan, Vipin Sharma,
Vivek Kasireddy, William Tu, Yi Liu, Zhu Yanjun
In-Reply-To: <20260323235817.1960573-1-dmatlack@google.com>
Add an API to enable the PCI subsystem to participate in a Live Update
and track all devices that are being preserved by drivers. Since this
support is still under development, hide it behind a new Kconfig
PCI_LIVEUPDATE that is marked experimental.
This API will be used in subsequent commits by the vfio-pci driver to
preserve VFIO devices across Live Update.
Signed-off-by: David Matlack <dmatlack@google.com>
---
drivers/pci/Kconfig | 11 ++
drivers/pci/Makefile | 1 +
drivers/pci/liveupdate.c | 380 ++++++++++++++++++++++++++++++++++++
drivers/pci/pci.h | 14 ++
drivers/pci/probe.c | 2 +
include/linux/kho/abi/pci.h | 62 ++++++
include/linux/pci.h | 41 ++++
7 files changed, 511 insertions(+)
create mode 100644 drivers/pci/liveupdate.c
create mode 100644 include/linux/kho/abi/pci.h
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index e3f848ffb52a..05307d89c3f4 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -334,6 +334,17 @@ config VGA_ARB_MAX_GPUS
Reserves space in the kernel to maintain resource locking for
multiple GPUS. The overhead for each GPU is very small.
+config PCI_LIVEUPDATE
+ bool "PCI Live Update Support (EXPERIMENTAL)"
+ depends on PCI && LIVEUPDATE
+ help
+ Support for preserving PCI devices across a Live Update. This option
+ should only be enabled by developers working on implementing this
+ support. Once enough support as landed in the kernel, this option
+ will no longer be marked EXPERIMENTAL.
+
+ If unsure, say N.
+
source "drivers/pci/hotplug/Kconfig"
source "drivers/pci/controller/Kconfig"
source "drivers/pci/endpoint/Kconfig"
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 41ebc3b9a518..e8d003cb6757 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_PCI_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..bec7b3500057
--- /dev/null
+++ b/drivers/pci/liveupdate.c
@@ -0,0 +1,380 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (c) 2026, Google LLC.
+ * David Matlack <dmatlack@google.com>
+ */
+
+/**
+ * DOC: PCI Live Update
+ *
+ * The PCI subsystem participates in the Live Update process to enable drivers
+ * to preserve their PCI devices across kexec.
+ *
+ * Device preservation across Live Update is built on top of the Live Update
+ * Orchestrator (LUO) support for file preservation across kexec. Userspace
+ * indicates that a device should be preserved by preserving the file associated
+ * with the device with ``ioctl(LIVEUPDATE_SESSION_PRESERVE_FD)``.
+ *
+ * .. note::
+ * The support for preserving PCI devices across Live Update is currently
+ * *partial* and should be considered *experimental*. It should only be
+ * used by developers working on the implementation for the time being.
+ *
+ * To enable the support, enable ``CONFIG_PCI_LIVEUPDATE``.
+ *
+ * Driver API
+ * ==========
+ *
+ * Drivers that support file-based device preservation must register their
+ * ``liveupdate_file_handler`` with the PCI subsystem by calling
+ * ``pci_liveupdate_register_flb()``. This ensures the PCI subsystem will be
+ * notified whenever a device file is preserved so that ``struct pci_ser``
+ * can be allocated to track all preserved devices. This struct is an ABI
+ * and is eventually handed off to the next kernel via Kexec-Handover (KHO).
+ *
+ * In the "outgoing" kernel (before kexec), drivers should then notify the PCI
+ * subsystem directly whenever the preservation status for a device changes:
+ *
+ * * ``pci_liveupdate_preserve(pci_dev)``: The device is being preserved.
+ *
+ * * ``pci_liveupdate_unpreserve(pci_dev)``: The device is no longer being
+ * preserved (preservation is cancelled).
+ *
+ * In the "incoming" kernel (after kexec), drivers should notify the PCI
+ * subsystem with the following calls:
+ *
+ * * ``pci_liveupdate_retrieve(pci_dev)``: The device file is being retrieved
+ * by userspace.
+ *
+ * * ``pci_liveupdate_finish(pci_dev)``: The device is done participating in
+ * Live Update. After this point the device may no longer be even associated
+ * with the same driver.
+ *
+ * Incoming/Outgoing
+ * =================
+ *
+ * The state of each device's participation in Live Update is stored in
+ * ``struct pci_dev``:
+ *
+ * * ``liveupdate_outgoing``: True if the device is being preserved in the
+ * outgoing kernel. Set in ``pci_liveupdate_preserve()`` and cleared in
+ * ``pci_liveupdate_unpreserve()``.
+ *
+ * * ``liveupdate_incoming``: True if the device is preserved in the incoming
+ * kernel. Set during probing when the device is first created and cleared
+ * in ``pci_liveupdate_finish()``.
+ *
+ * Restrictions
+ * ============
+ *
+ * Preserved devices currently have the following restrictions. Each of these
+ * may be relaxed in the future.
+ *
+ * * The device must not be a Virtual Function (VF).
+ *
+ * * The device must not be a Physical Function (PF).
+ *
+ * Preservation Behavior
+ * =====================
+ *
+ * The kernel preserves the following state for devices preserved across a Live
+ * Update:
+ *
+ * * The PCI Segment, Bus, Device, and Function numbers assigned to the device
+ * are guaranteed to remain the same across Live Update.
+ *
+ * This list will be extended in the future as new support is added.
+ *
+ * Driver Binding
+ * ==============
+ *
+ * It is the driver's responsibility for ensuring that preserved devices are not
+ * released or bound to a different driver for as long as they are preserved. In
+ * practice, this is enforced by LUO taking an extra referenced to the preserved
+ * device file for as long as it is preserved.
+ *
+ * However, there is a window of time in the incoming kernel when a device is
+ * first probed and when userspace retrieves the device file with
+ * ``LIVEUPDATE_SESSION_RETRIEVE_FD`` when the device could be bound to any
+ * driver.
+ *
+ * It is currently userspace's responsibility to ensure that the device is bound
+ * to the correct driver in this window.
+ */
+
+#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>
+
+#include "pci.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;
+
+ /*
+ * Don't both accounting for VFs that could be created after this
+ * since preserving VFs is not supported yet. Also don't account
+ * for devices that could be hot-plugged after this since preserving
+ * hot-plugged devices across Live Update is not yet an expected
+ * use-case.
+ */
+ 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((u64)a->domain << 16 | a->bdf,
+ (u64)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 void 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);
+
+ /*
+ * This should never happen unless there is a kernel bug or
+ * corruption that causes the state in struct pci_ser to get
+ * out of sync with struct pci_dev.
+ */
+ if (pci_WARN_ONCE(dev, !dev_ser, "Cannot find preserved device!"))
+ return;
+
+ for (i = dev_ser - ser->devices; i < ser->nr_devices - 1; i++)
+ ser->devices[i] = ser->devices[i + 1];
+
+ ser->nr_devices--;
+}
+
+int pci_liveupdate_preserve(struct pci_dev *dev)
+{
+ struct pci_dev_ser new = INIT_PCI_DEV_SER(dev);
+ struct pci_ser *ser;
+ int i, ret;
+
+ /* SR-IOV is not supported yet. */
+ if (dev->is_virtfn || dev->is_physfn)
+ 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);
+
+ /*
+ * This should never happen unless there is a kernel bug or
+ * corruption that causes the state in struct pci_ser to get out
+ * of sync with struct pci_dev.
+ */
+ 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_preserve);
+
+void pci_liveupdate_unpreserve(struct pci_dev *dev)
+{
+ struct pci_ser *ser;
+ int ret;
+
+ /* This should never happen unless the caller (driver) is buggy */
+ if (WARN_ON_ONCE(!dev->liveupdate_outgoing))
+ return;
+
+ guard(mutex)(&pci_flb_outgoing_lock);
+
+ ret = liveupdate_flb_get_outgoing(&pci_liveupdate_flb, (void **)&ser);
+
+ /* This should never happen unless there is a bug in LUO */
+ if (WARN_ON_ONCE(ret))
+ return;
+
+ pci_ser_delete(ser, dev);
+ dev->liveupdate_outgoing = false;
+}
+EXPORT_SYMBOL_GPL(pci_liveupdate_unpreserve);
+
+static int pci_liveupdate_flb_get_incoming(struct pci_ser **serp)
+{
+ int ret;
+
+ ret = liveupdate_flb_get_incoming(&pci_liveupdate_flb, (void **)serp);
+
+ /* Live Update is not enabled. */
+ if (ret == -EOPNOTSUPP)
+ return ret;
+
+ /* Live Update is enabled, but there is no incoming FLB data. */
+ if (ret == -ENODATA)
+ return ret;
+
+ /*
+ * Live Update is enabled and there is incoming FLB data, but none of it
+ * matches pci_liveupdate_flb.compatible.
+ *
+ * This could mean that no PCI FLB data was passed by the previous
+ * kernel, but it could also mean the previous kernel used a different
+ * compatibility string (i.e.a different ABI). The latter deserves at
+ * least a WARN_ON_ONCE() but it cannot be distinguished from the
+ * former.
+ */
+ if (ret == -ENOENT) {
+ pr_info_once("PCI: No incoming FLB data detected during Live Update");
+ return ret;
+ }
+
+ /*
+ * There is incoming FLB data that matches pci_liveupdate_flb.compatible
+ * but it cannot be retrieved. Proceed with standard initialization as
+ * if there was not incoming PCI FLB data.
+ */
+ WARN_ONCE(ret, "PCI: Failed to retrieve incoming FLB data during Live Update");
+ return ret;
+}
+
+u32 pci_liveupdate_incoming_nr_devices(void)
+{
+ struct pci_ser *ser;
+
+ if (pci_liveupdate_flb_get_incoming(&ser))
+ return 0;
+
+ return ser->nr_devices;
+}
+
+void pci_liveupdate_setup_device(struct pci_dev *dev)
+{
+ struct pci_ser *ser;
+
+ if (pci_liveupdate_flb_get_incoming(&ser))
+ return;
+
+ if (!pci_ser_find(ser, dev))
+ return;
+
+ dev->liveupdate_incoming = true;
+}
+
+int pci_liveupdate_retrieve(struct pci_dev *dev)
+{
+ if (!dev->liveupdate_incoming)
+ return -EINVAL;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pci_liveupdate_retrieve);
+
+void pci_liveupdate_finish(struct pci_dev *dev)
+{
+ dev->liveupdate_incoming = false;
+}
+EXPORT_SYMBOL_GPL(pci_liveupdate_finish);
+
+int pci_liveupdate_register_flb(struct liveupdate_file_handler *fh)
+{
+ return liveupdate_register_flb(fh, &pci_liveupdate_flb);
+}
+EXPORT_SYMBOL_GPL(pci_liveupdate_register_flb);
+
+void pci_liveupdate_unregister_flb(struct liveupdate_file_handler *fh)
+{
+ liveupdate_unregister_flb(fh, &pci_liveupdate_flb);
+}
+EXPORT_SYMBOL_GPL(pci_liveupdate_unregister_flb);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 13d998fbacce..979cb9921340 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1434,4 +1434,18 @@ static inline int pci_msix_write_tph_tag(struct pci_dev *pdev, unsigned int inde
(PCI_CONF1_ADDRESS(bus, dev, func, reg) | \
PCI_CONF1_EXT_REG(reg))
+#ifdef CONFIG_PCI_LIVEUPDATE
+void pci_liveupdate_setup_device(struct pci_dev *dev);
+u32 pci_liveupdate_incoming_nr_devices(void);
+#else
+static inline void pci_liveupdate_setup_device(struct pci_dev *dev)
+{
+}
+
+static inline u32 pci_liveupdate_incoming_nr_devices(void)
+{
+ return 0;
+}
+#endif
+
#endif /* DRIVERS_PCI_H */
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index bccc7a4bdd79..c60222d45659 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -2064,6 +2064,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..7764795f6818
--- /dev/null
+++ b/include/linux/kho/abi/pci.h
@@ -0,0 +1,62 @@
+/* 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/bug.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.
+ * @reserved: Reserved (to naturally align struct pci_dev_ser).
+ */
+struct pci_dev_ser {
+ u32 domain;
+ u16 bdf;
+ u16 reserved;
+} __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;
+
+/* Ensure all elements of devices[] are naturally aligned. */
+static_assert(offsetof(struct pci_ser, devices) % sizeof(unsigned long) == 0);
+static_assert(sizeof(struct pci_dev_ser) % sizeof(unsigned long) == 0);
+
+#endif /* _LINUX_KHO_ABI_PCI_H */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 1c270f1d5123..27ee9846a2fd 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>
@@ -591,6 +592,10 @@ struct pci_dev {
u8 tph_mode; /* TPH mode */
u8 tph_req_type; /* TPH requester type */
#endif
+#ifdef CONFIG_PCI_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)
@@ -2871,4 +2876,40 @@ 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_PCI_LIVEUPDATE
+int pci_liveupdate_preserve(struct pci_dev *dev);
+void pci_liveupdate_unpreserve(struct pci_dev *dev);
+int pci_liveupdate_retrieve(struct pci_dev *dev);
+void pci_liveupdate_finish(struct pci_dev *dev);
+int pci_liveupdate_register_flb(struct liveupdate_file_handler *fh);
+void pci_liveupdate_unregister_flb(struct liveupdate_file_handler *fh);
+#else
+static inline int pci_liveupdate_preserve(struct pci_dev *dev)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline void pci_liveupdate_unpreserve(struct pci_dev *dev)
+{
+}
+
+static inline int pci_liveupdate_retrieve(struct pci_dev *dev)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline void pci_liveupdate_finish(struct pci_dev *dev)
+{
+}
+
+static inline int pci_liveupdate_register_flb(struct liveupdate_file_handler *fh)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline void pci_liveupdate_unregister_flb(struct liveupdate_file_handler *fh)
+{
+}
+#endif
+
#endif /* LINUX_PCI_H */
--
2.53.0.983.g0bb29b3bc5-goog
^ permalink raw reply related
* [PATCH v3 01/24] liveupdate: Export symbols needed by modules
From: David Matlack @ 2026-03-23 23:57 UTC (permalink / raw)
To: Alex Williamson, Bjorn Helgaas
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro, Andrew Morton,
Ankit Agrawal, Arnd Bergmann, Askar Safin, Borislav Petkov (AMD),
Chris Li, Dapeng Mi, David Matlack, David Rientjes, Feng Tang,
Jacob Pan, Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet,
Josh Hilke, Kees Cook, Kevin Tian, kexec, kvm, Leon Romanovsky,
Leon Romanovsky, linux-doc, linux-kernel, linux-kselftest,
linux-mm, linux-pci, Li RongQing, Lukas Wunner, Marco Elver,
Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Paul E. McKenney, Pawan Gupta,
Peter Zijlstra (Intel), Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Randy Dunlap, Rodrigo Vivi,
Saeed Mahameed, Samiullah Khawaja, Shuah Khan, Vipin Sharma,
Vivek Kasireddy, William Tu, Yi Liu, Zhu Yanjun
In-Reply-To: <20260323235817.1960573-1-dmatlack@google.com>
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.
Reviewed-by: Samiullah Khawaja <skhawaja@google.com>
Reviewed-by: Pranjal Shrivastava <praan@google.com>
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 a38ea4975824..cdc48d49e5e5 100644
--- a/kernel/liveupdate/luo_file.c
+++ b/kernel/liveupdate/luo_file.c
@@ -866,6 +866,7 @@ int liveupdate_register_file_handler(struct liveupdate_file_handler *fh)
return 0;
}
+EXPORT_SYMBOL_GPL(liveupdate_register_file_handler);
/**
* liveupdate_unregister_file_handler - Unregister a liveupdate file handler
@@ -884,3 +885,4 @@ void liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh)
list_del(&ACCESS_PRIVATE(fh, list));
}
}
+EXPORT_SYMBOL_GPL(liveupdate_unregister_file_handler);
--
2.53.0.983.g0bb29b3bc5-goog
^ permalink raw reply related
* [PATCH v3 00/24] vfio/pci: Base Live Update support for VFIO device files
From: David Matlack @ 2026-03-23 23:57 UTC (permalink / raw)
To: Alex Williamson, Bjorn Helgaas
Cc: Adithya Jayachandran, Alexander Graf, Alex Mastro, Andrew Morton,
Ankit Agrawal, Arnd Bergmann, Askar Safin, Borislav Petkov (AMD),
Chris Li, Dapeng Mi, David Matlack, David Rientjes, Feng Tang,
Jacob Pan, Jason Gunthorpe, Jason Gunthorpe, Jonathan Corbet,
Josh Hilke, Kees Cook, Kevin Tian, kexec, kvm, Leon Romanovsky,
Leon Romanovsky, linux-doc, linux-kernel, linux-kselftest,
linux-mm, linux-pci, Li RongQing, Lukas Wunner, Marco Elver,
Michał Winiarski, Mike Rapoport, Parav Pandit,
Pasha Tatashin, Paul E. McKenney, Pawan Gupta,
Peter Zijlstra (Intel), Pranjal Shrivastava, Pratyush Yadav,
Raghavendra Rao Ananta, Randy Dunlap, Rodrigo Vivi,
Saeed Mahameed, Samiullah Khawaja, Shuah Khan, Vipin Sharma,
Vivek Kasireddy, William Tu, Yi Liu, Zhu Yanjun
This series can be found on GitHub:
https://github.com/dmatlack/linux/tree/liveupdate/vfio/cdev/v3
This series adds the base support to preserve a VFIO device file across
a Live Update. "Base support" means that this allows userspace to
safely preserve a VFIO device file with LIVEUPDATE_SESSION_PRESERVE_FD
and retrieve it with LIVEUPDATE_SESSION_RETRIEVE_FD, but the device
itself is not preserved in a fully running state across Live Update.
This series aims to provide a foundation on which to build the rest of
the device preservation infrastructure, including:
1. Preservation of iommufd files [1]
2. Preservation of IOMMU driver state
3. Preservation of PCI state (BAR resources, device state, bridge state, ...)
4. Preservation of vfio-pci driver state
Steps 1 and 2 are already in-progress on the mailing list. We are
working on a detailed roadmap for steps 3 and 4.
Testing
-------
The patches at the end of this series provide comprehensive selftests
for the new code added by this series. The selftests have been validated
in both a VM environment using a virtio-net PCIe device, and in a
baremetal environment on an Intel EMR server with an Intel DSA PCIe
device.
Here is an example of how to run the new selftests:
vfio_pci_liveupdate_uapi_test:
$ tools/testing/selftests/vfio/scripts/setup.sh 0000:00:04.0
$ tools/testing/selftests/vfio/vfio_pci_liveupdate_uapi_test 0000:00:04.0
$ tools/testing/selftests/vfio/scripts/cleanup.sh
vfio_pci_liveupdate_kexec_test:
$ 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 ...
$ 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
$ tools/testing/selftests/vfio/scripts/cleanup.sh
It is also possible to run vfio_pci_liveupdate_kexec_test multiple times
to preserve multiple devices simultaneously across a Live Update. This
series has been tested with up to 8 devices concurrently preserved.
Dependencies
------------
This series is built on top of v7.0-rc4 plus a series from Pasha
Tatashin to fix the module refcounting in FLB:
https://lore.kernel.org/lkml/20260318141637.1870220-10-pasha.tatashin@soleen.com/
Changelog
---------
v3:
- Add logging & documentation for pci=assign-busses overrides (Pranjal)
- Use 2026 in drivers/pci/liveupdate.c (Pranjal)
- Use 2026 in drivers/vfio/pci/vfio_pci_liveupdate.c (Pranjal)
- Drop incoming/outgoing from PCI APIs (Sami)
- Eliminate duplicate extern declarations for vfio_device_fops
(Pranjal)
- Keep struct vfio_device_file private (Pranjal)
- Add comment about not supporting hot-plug (Pranjal)
- Add comment about not supporting VFs (Sami)
- Better error handling for liveupdate_flb_get_incoming() (Pranjal)
- Remove liveupdate_enabled() checks (Zhu)
- Remove liveupdate_enabled() checks in vfio_pci_liveupdate_init() (Pranjal)
- Drop IOMMU reference from bus number commit message (Bjorn)
- Add fabric rationale to commit message (Jason)
- Swap incoming ... outgoing ordering in commit message (Bjorn)
- Use vfio_device_cdev_opened() instead of df->group (Alex)
- Add comments for CONFIG_VFIO_PCI_ZDEV_KVM (Alex)
- Add comments for vfio_pci_is_intel_display() (Alex)
- Use pci_dev_try_lock() in freeze (Alex)
- Fix device reset locking in freeze() (me)
- Use u32 for domain in PCI (Bjorn)
- Use u32 for domain in VFIO (Bjorn)
- Make pci_liveupdate_incoming_nr_devices() private to drivers/pci/ (Bjorn)
- Fix dev->liveupdate_incoming readability (Bjorn)
- Take pci_ser_delete() out of WARN_ON_ONCE() (Bjorn)
- Drop reference to userspace & files from PCI commit message (Bjorn)
- Rename __vfio_device_fops_cdev_open() to vfio_device_cdev_open_file() (Alex)
- Fix NULL pointer dereference in release() (Alex)
- Handle return value of pci_liveupdate_outgoing_preserve() (Alex)
- Make pci_liveupdate_unregister_fh() unabe to fail. (Alex)
- Move vfio_liveupdate_incoming_is_preserved() to drivers/vfio/vfio.h (Alex)
- Add vfio_pci_core_probe_reset() (Alex)
- Forward declare ser struct in include/linux/vfio_pci_core.h (Alex)
- Bump compatibility string when adding reset_works (Alex)
- How will userspace detect partial preservation? (Alex)
- Require single device per iommu_group (Jason)
- Rename pci_liveupdate_register_fh() to pci_liveupdate_register_flb() (Vipin)
- Use ksft_exit_skip() and SKIP() (Vipin)
- Move documentation to code (Vipin)
- Use __u64 instead of int for token in Live Update selftest helpers (Gemini)
- Add documentation for drivers/pci/liveupdate.c (me)
v2: https://lore.kernel.org/kvm/20260129212510.967611-1-dmatlack@google.com/
v1: https://lore.kernel.org/kvm/20251126193608.2678510-1-dmatlack@google.com/
rfc: https://lore.kernel.org/kvm/20251018000713.677779-1-vipinsh@google.com/
Cc: Pranjal Shrivastava <praan@google.com>
Cc: Saeed Mahameed <saeedm@nvidia.com>
Cc: Adithya Jayachandran <ajayachandra@nvidia.com>
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: Parav Pandit <parav@nvidia.com>
Cc: Leon Romanovsky <leonro@nvidia.com>
Cc: William Tu <witu@nvidia.com>
Cc: Jacob Pan <jacob.pan@linux.microsoft.com>
Cc: Lukas Wunner <lukas@wunner.de>
Cc: Pasha Tatashin <pasha.tatashin@soleen.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Pratyush Yadav <pratyush@kernel.org>
Cc: Samiullah Khawaja <skhawaja@google.com>
Cc: Chris Li <chrisl@kernel.org>
Cc: Josh Hilke <jrhilke@google.com>
Cc: David Rientjes <rientjes@google.com>
[1] https://lore.kernel.org/linux-iommu/20251202230303.1017519-1-skhawaja@google.com/
David Matlack (15):
liveupdate: Export symbols needed by modules
PCI: Add API to track PCI devices preserved across Live Update
PCI: Require Live Update preserved devices are in singleton
iommu_groups
PCI: Inherit bus numbers from previous kernel during Live Update
docs: liveupdate: Add documentation for PCI
vfio/pci: Notify PCI subsystem about devices preserved across Live
Update
vfio: Enforce preserved devices are retrieved via
LIVEUPDATE_SESSION_RETRIEVE_FD
vfio/pci: Store incoming Live Update state in struct
vfio_pci_core_device
docs: liveupdate: Add documentation for VFIO PCI
vfio: selftests: Add Makefile support for TEST_GEN_PROGS_EXTENDED
vfio: selftests: Add vfio_pci_liveupdate_uapi_test
vfio: selftests: Expose iommu_modes to tests
vfio: selftests: Expose low-level helper routines for setting up
struct vfio_pci_device
vfio: selftests: Verify that opening VFIO device fails during Live
Update
vfio: selftests: Add continuous DMA to vfio_pci_liveupdate_kexec_test
Vipin Sharma (9):
vfio/pci: Register a file handler with Live Update Orchestrator
vfio/pci: Preserve vfio-pci device files across Live Update
vfio/pci: Retrieve preserved device files after Live Update
vfio/pci: Skip reset of preserved device after Live Update
selftests/liveupdate: Move luo_test_utils.* into a reusable library
selftests/liveupdate: Add helpers to preserve/retrieve FDs
vfio: selftests: Build liveupdate library in VFIO selftests
vfio: selftests: Initialize vfio_pci_device using a VFIO cdev FD
vfio: selftests: Add vfio_pci_liveupdate_kexec_test
Documentation/PCI/liveupdate.rst | 23 +
.../admin-guide/kernel-parameters.txt | 6 +-
Documentation/core-api/liveupdate.rst | 2 +
.../driver-api/vfio_pci_liveupdate.rst | 23 +
MAINTAINERS | 2 +
drivers/pci/Kconfig | 11 +
drivers/pci/Makefile | 1 +
drivers/pci/liveupdate.c | 415 ++++++++++++++++++
drivers/pci/pci.h | 14 +
drivers/pci/probe.c | 37 +-
drivers/vfio/device_cdev.c | 63 ++-
drivers/vfio/group.c | 9 +
drivers/vfio/pci/Kconfig | 11 +
drivers/vfio/pci/Makefile | 1 +
drivers/vfio/pci/vfio_pci.c | 14 +-
drivers/vfio/pci/vfio_pci_core.c | 90 ++--
drivers/vfio/pci/vfio_pci_liveupdate.c | 328 ++++++++++++++
drivers/vfio/pci/vfio_pci_priv.h | 18 +
drivers/vfio/vfio.h | 18 +
drivers/vfio/vfio_main.c | 16 +-
include/linux/kho/abi/pci.h | 62 +++
include/linux/kho/abi/vfio_pci.h | 45 ++
include/linux/pci.h | 41 ++
include/linux/vfio.h | 13 +
include/linux/vfio_pci_core.h | 2 +
kernel/liveupdate/luo_core.c | 1 +
kernel/liveupdate/luo_file.c | 2 +
tools/testing/selftests/liveupdate/.gitignore | 1 +
tools/testing/selftests/liveupdate/Makefile | 14 +-
.../include/libliveupdate.h} | 11 +-
.../selftests/liveupdate/lib/libliveupdate.mk | 20 +
.../{luo_test_utils.c => lib/liveupdate.c} | 43 +-
.../selftests/liveupdate/luo_kexec_simple.c | 2 +-
.../selftests/liveupdate/luo_multi_session.c | 2 +-
tools/testing/selftests/vfio/Makefile | 23 +-
.../vfio/lib/include/libvfio/iommu.h | 2 +
.../lib/include/libvfio/vfio_pci_device.h | 8 +
tools/testing/selftests/vfio/lib/iommu.c | 4 +-
.../selftests/vfio/lib/vfio_pci_device.c | 60 ++-
.../vfio/vfio_pci_liveupdate_kexec_test.c | 256 +++++++++++
.../vfio/vfio_pci_liveupdate_uapi_test.c | 93 ++++
41 files changed, 1715 insertions(+), 92 deletions(-)
create mode 100644 Documentation/PCI/liveupdate.rst
create mode 100644 Documentation/driver-api/vfio_pci_liveupdate.rst
create mode 100644 drivers/pci/liveupdate.c
create mode 100644 drivers/vfio/pci/vfio_pci_liveupdate.c
create mode 100644 include/linux/kho/abi/pci.h
create mode 100644 include/linux/kho/abi/vfio_pci.h
rename tools/testing/selftests/liveupdate/{luo_test_utils.h => lib/include/libliveupdate.h} (80%)
create mode 100644 tools/testing/selftests/liveupdate/lib/libliveupdate.mk
rename tools/testing/selftests/liveupdate/{luo_test_utils.c => lib/liveupdate.c} (89%)
create mode 100644 tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c
create mode 100644 tools/testing/selftests/vfio/vfio_pci_liveupdate_uapi_test.c
base-commit: 3251ac3df4374e4e94e4fbecf49ad1573933018a
prerequisite-patch-id: 37ebd38e2247ccb02e6a6c7543a378534d69a038
prerequisite-patch-id: 19c8469a9ae5cd13618481dd75012444330f80f9
prerequisite-patch-id: 2ba04f598993e2c2d941c4cd3f2dc1e98905d68b
prerequisite-patch-id: fcab928f6ee32a145667822ceca5e4f1f567d530
prerequisite-patch-id: 6d11347278609426baa9eacc1726b32b48d09a25
prerequisite-patch-id: 94a9e8a8cb6004e12de90fcc0068e8a8b12652de
prerequisite-patch-id: d658019a7ac7c82ebe4a6c6086457e27460174d3
prerequisite-patch-id: 41e68c9fc8e8c5e493497e87ca13577b3167cf80
--
2.53.0.983.g0bb29b3bc5-goog
^ permalink raw reply
* Re: [RFC PATCH v4 1/1] mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics
From: SeongJae Park @ 2026-03-23 23:54 UTC (permalink / raw)
To: Ravi Jonnalagadda
Cc: SeongJae Park, damon, linux-mm, linux-kernel, linux-doc, akpm,
corbet, bijan311, ajayjoshi, honggyu.kim, yunjeong.mun
In-Reply-To: <CALa+Y16i0f5D_ZTVcfVa1DgeZL1btvUJxjOvoyFEYNkT7K-grg@mail.gmail.com>
On Mon, 23 Mar 2026 12:41:42 -0700 Ravi Jonnalagadda <ravis.opensrc@gmail.com> wrote:
> On Sat, Mar 21, 2026 at 9:54 AM SeongJae Park <sj@kernel.org> wrote:
> >
> > On Fri, 20 Mar 2026 12:04:53 -0700 Ravi Jonnalagadda <ravis.opensrc@gmail.com> wrote:
> >
> > > Add new quota goal metrics for memory tiering that track scheme-eligible
> > > memory distribution across NUMA nodes:
> > >
> > > - DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP: ratio of eligible memory on a node
> > > - DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BP: ratio of eligible memory NOT on
> > > a node
> >
> > The description for the second metric should be "ratio of ineligible memory on
> > a node".
> >
>
> Got it. Will fix the commit message.
>
> > >
> > > These complementary metrics enable push-pull migration schemes that
> > > maintain a target memory distribution across different NUMA nodes
> > > representing different memory tiers, based on access patterns defined
> > > by each scheme.
> > >
> > > The metrics iterate scheme-eligible regions and use damon_get_folio()
> > > to determine NUMA node placement of each folio, calculating the ratio
> > > of eligible memory on the specified node versus total eligible memory.
> > >
> > > Suggested-by: SeongJae Park <sj@kernel.org>
> > > Signed-off-by: Ravi Jonnalagadda <ravis.opensrc@gmail.com>
> > > ---
> > > include/linux/damon.h | 6 ++
> > > mm/damon/core.c | 158 ++++++++++++++++++++++++++++++++++++---
> > > mm/damon/sysfs-schemes.c | 12 +++
> > > 3 files changed, 164 insertions(+), 12 deletions(-)
> > >
> > > diff --git a/include/linux/damon.h b/include/linux/damon.h
> > > index b1d8fd88a0fc..490918804f85 100644
> > > --- a/include/linux/damon.h
> > > +++ b/include/linux/damon.h
> > > @@ -193,6 +193,10 @@ enum damos_action {
> > > * @DAMOS_QUOTA_NODE_MEMCG_FREE_BP: MemFree ratio of a node for a cgroup.
> > > * @DAMOS_QUOTA_ACTIVE_MEM_BP: Active to total LRU memory ratio.
> > > * @DAMOS_QUOTA_INACTIVE_MEM_BP: Inactive to total LRU memory ratio.
> > > + * @DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP: Scheme-eligible memory ratio of a
> > > + * node.
> > > + * @DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BP: Scheme-ineligible memory ratio of a
> > > + * node.
> > > * @NR_DAMOS_QUOTA_GOAL_METRICS: Number of DAMOS quota goal metrics.
> > > *
> > > * Metrics equal to larger than @NR_DAMOS_QUOTA_GOAL_METRICS are unsupported.
> > > @@ -206,6 +210,8 @@ enum damos_quota_goal_metric {
> > > DAMOS_QUOTA_NODE_MEMCG_FREE_BP,
> > > DAMOS_QUOTA_ACTIVE_MEM_BP,
> > > DAMOS_QUOTA_INACTIVE_MEM_BP,
> > > + DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP,
> > > + DAMOS_QUOTA_NODE_INELIGIBLE_MEM_BP,
> > > NR_DAMOS_QUOTA_GOAL_METRICS,
> > > };
> > >
> > > diff --git a/mm/damon/core.c b/mm/damon/core.c
> > > index b9e12865622c..3e0ac65e34a0 100644
> > > --- a/mm/damon/core.c
> > > +++ b/mm/damon/core.c
> > > @@ -17,6 +17,8 @@
> > > #include <linux/string.h>
> > > #include <linux/string_choices.h>
> > >
> > > +#include "ops-common.h"
> > > +
> >
> > I don't find a reason to include this, and I'd like to avoid including that in
> > core.c unless it is really necessary. Could you please remove this?
> >
>
> The include was added because the implementation uses damon_get_folio() to
> determine NUMA node placement of folios when iterating eligible regions.
Thank you for clarifying, Ravi.
> Would you prefer that I move the damon_get_folio() declaration to
> include/linux/damon.h, or would you suggest a different approach such as
> adding an ops callback for the node calculation?
I'd like to keep it mm/damon/ internal if possible. Maybe adding new files,
say, mm/damon/common.{c,h} is one option.
Just keeping it as is for now with clarification comment (e.g., "including
ops-common.h for damon_get_folio()") for now, and revisiting for cleanup in
future could also be another option.
I slightly prefer the second option at the moment.
>
> > Below looks all good for RFC level code to move on to the next stage (dropping
> > RFC tag). :)
> >
>
> Thank you, SJ! Will send v5 with fixes once I hear back on the above.
Sounds good, looking forward to!
Thanks,
SJ
[...]
^ permalink raw reply
* Re: [RFC PATCH v4 0/1] mm/damon: add node_eligible_mem_bp and node_ineligible_mem_bp goal metrics
From: SeongJae Park @ 2026-03-23 23:45 UTC (permalink / raw)
To: Ravi Jonnalagadda
Cc: SeongJae Park, damon, linux-mm, linux-kernel, linux-doc, akpm,
corbet, bijan311, ajayjoshi, honggyu.kim, yunjeong.mun
In-Reply-To: <CALa+Y15sBCyVgGKC5994-WhS31nahyT=8uitDPG_isZ7sp_g_w@mail.gmail.com>
On Mon, 23 Mar 2026 12:23:49 -0700 Ravi Jonnalagadda <ravis.opensrc@gmail.com> wrote:
> On Sat, Mar 21, 2026 at 9:57 AM SeongJae Park <sj@kernel.org> wrote:
[...]
> > >
> > > Changes since v3:
> > > =================
> > >
> > > - The first two patches from v3 (goal_tuner initialization fix and
> > > esz=0 quota bypass fix) are now in damon/next. This submission
> >
> > It is not also in mm-unstable :)
What I really wanted to say is, s/not/now/
>
> Good to know. Will mention this in the next version.
I think Ravi understood what I really wanted to mean, though.
[...]
> Thank you! Will drop the RFC tag for v5.
Looking forward to!
Thanks,
SJ
[...]
^ permalink raw reply
* Re: [PATCH net-next v3 01/13] net: add address list snapshot and reconciliation infrastructure
From: Jakub Kicinski @ 2026-03-23 23:20 UTC (permalink / raw)
To: Stanislav Fomichev
Cc: netdev, davem, edumazet, pabeni, horms, corbet, skhan,
andrew+netdev, michael.chan, pavan.chebbi, anthony.l.nguyen,
przemyslaw.kitszel, saeedm, tariqt, mbloch, alexanderduyck,
kernel-team, johannes, sd, jianbol, dtatulea, mohsin.bashr,
jacob.e.keller, willemb, skhawaja, bestswngs, aleksandr.loktionov,
kees, linux-doc, linux-kernel, intel-wired-lan, linux-rdma,
linux-wireless, linux-kselftest, leon
In-Reply-To: <20260320012501.2033548-2-sdf@fomichev.me>
On Thu, 19 Mar 2026 18:24:49 -0700 Stanislav Fomichev wrote:
> +EXPORT_SYMBOL(__hw_addr_list_snapshot);
> +EXPORT_SYMBOL(__hw_addr_list_reconcile);
Why? For the kunit tests?
^ permalink raw reply
* Re: [PATCH net-next v3 03/13] net: introduce ndo_set_rx_mode_async and dev_rx_mode_work
From: Jakub Kicinski @ 2026-03-23 23:20 UTC (permalink / raw)
To: Stanislav Fomichev
Cc: netdev, davem, edumazet, pabeni, horms, corbet, skhan,
andrew+netdev, michael.chan, pavan.chebbi, anthony.l.nguyen,
przemyslaw.kitszel, saeedm, tariqt, mbloch, alexanderduyck,
kernel-team, johannes, sd, jianbol, dtatulea, mohsin.bashr,
jacob.e.keller, willemb, skhawaja, bestswngs, aleksandr.loktionov,
kees, linux-doc, linux-kernel, intel-wired-lan, linux-rdma,
linux-wireless, linux-kselftest, leon
In-Reply-To: <20260320012501.2033548-4-sdf@fomichev.me>
On Thu, 19 Mar 2026 18:24:51 -0700 Stanislav Fomichev wrote:
> diff --git a/Documentation/networking/netdevices.rst b/Documentation/networking/netdevices.rst
> index 35704d115312..dc83d78d3b27 100644
> --- a/Documentation/networking/netdevices.rst
> +++ b/Documentation/networking/netdevices.rst
> @@ -289,6 +289,14 @@ struct net_device synchronization rules
> ndo_set_rx_mode:
> Synchronization: netif_addr_lock spinlock.
> Context: BHs disabled
> + Notes: Deprecated in favor of sleepable ndo_set_rx_mode_async.
>
> +ndo_set_rx_mode_async:
> + Synchronization: rtnl_lock() semaphore. In addition, netdev instance
> + lock if the driver implements queue management or shaper API.
> + Context: process (from a work queue)
> + Notes: Sleepable version of ndo_set_rx_mode. Receives snapshots
It's probably just my weirdness but I find creating adjectives out
of random nouns by adding "-able" to be in poor taste. "sleepable"
took root in certain three letter subsystems but I hope it won't
in netdev.
Please use your words:
Notes: Async version of ndo_set_rx_mode which runs in process
context. Receives snapshots f the unicast and multicast address lists.
> + of the unicast and multicast address lists.
>
> ndo_setup_tc:
> ``TC_SETUP_BLOCK`` and ``TC_SETUP_FT`` are running under NFT locks
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index 469b7cdb3237..b05bdd67b807 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -1117,6 +1117,16 @@ struct netdev_net_notifier {
> * This function is called device changes address list filtering.
> * If driver handles unicast address filtering, it should set
> * IFF_UNICAST_FLT in its priv_flags.
> + * Cannot sleep, called with netif_addr_lock_bh held.
> + * Deprecated in favor of sleepable ndo_set_rx_mode_async.
> + *
> + * void (*ndo_set_rx_mode_async)(struct net_device *dev,
> + * struct netdev_hw_addr_list *uc,
> + * struct netdev_hw_addr_list *mc);
> + * Sleepable version of ndo_set_rx_mode. Called from a work queue
> + * with rtnl_lock and netdev_lock_ops(dev) held. The uc/mc parameters
> + * are snapshots of the address lists - iterate with
> + * netdev_hw_addr_list_for_each(ha, uc).
> *
> * int (*ndo_set_mac_address)(struct net_device *dev, void *addr);
> * This function is called when the Media Access Control address
> @@ -1437,6 +1447,9 @@ struct net_device_ops {
> void (*ndo_change_rx_flags)(struct net_device *dev,
> int flags);
> void (*ndo_set_rx_mode)(struct net_device *dev);
> + void (*ndo_set_rx_mode_async)(struct net_device *dev,
> + struct netdev_hw_addr_list *uc,
> + struct netdev_hw_addr_list *mc);
> int (*ndo_set_mac_address)(struct net_device *dev,
> void *addr);
> int (*ndo_validate_addr)(struct net_device *dev);
> @@ -1903,6 +1916,7 @@ enum netdev_reg_state {
> * has been enabled due to the need to listen to
> * additional unicast addresses in a device that
> * does not implement ndo_set_rx_mode()
> + * @rx_mode_work: Work queue entry for ndo_set_rx_mode_async()
> * @uc: unicast mac addresses
> * @mc: multicast mac addresses
> * @dev_addrs: list of device hw addresses
> @@ -2293,6 +2307,7 @@ struct net_device {
> unsigned int promiscuity;
> unsigned int allmulti;
> bool uc_promisc;
> + struct work_struct rx_mode_work;
> #ifdef CONFIG_LOCKDEP
> unsigned char nested_level;
> #endif
> @@ -4661,6 +4676,11 @@ static inline bool netif_device_present(const struct net_device *dev)
> return test_bit(__LINK_STATE_PRESENT, &dev->state);
> }
>
> +static inline bool netif_up_and_present(const struct net_device *dev)
> +{
> + return (dev->flags & IFF_UP) && netif_device_present(dev);
Is this really worth a dedicated helper? What are you trying to express
here semantically?
> +
> void netif_device_detach(struct net_device *dev);
>
> void netif_device_attach(struct net_device *dev);
> diff --git a/net/core/dev.c b/net/core/dev.c
> index 200d44883fc1..fedc423306fc 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -2381,6 +2381,8 @@ static void netstamp_clear(struct work_struct *work)
> static DECLARE_WORK(netstamp_work, netstamp_clear);
> #endif
>
> +static struct workqueue_struct *rx_mode_wq;
> +
> void net_enable_timestamp(void)
> {
> #ifdef CONFIG_JUMP_LABEL
> @@ -9669,22 +9671,84 @@ int netif_set_allmulti(struct net_device *dev, int inc, bool notify)
> return 0;
> }
>
> -/*
> - * Upload unicast and multicast address lists to device and
> - * configure RX filtering. When the device doesn't support unicast
> - * filtering it is put in promiscuous mode while unicast addresses
> - * are present.
> +static void dev_rx_mode_work(struct work_struct *work)
> +{
> + struct net_device *dev = container_of(work, struct net_device,
> + rx_mode_work);
> + struct netdev_hw_addr_list uc_snap, mc_snap, uc_ref, mc_ref;
> + const struct net_device_ops *ops = dev->netdev_ops;
> + int err;
> +
> + __hw_addr_init(&uc_snap);
> + __hw_addr_init(&mc_snap);
> + __hw_addr_init(&uc_ref);
> + __hw_addr_init(&mc_ref);
> +
> + rtnl_lock();
> + netdev_lock_ops(dev);
> +
> + if (!netif_up_and_present(dev))
> + goto out;
> +
> + if (ops->ndo_set_rx_mode_async) {
How did we get here if we don't have this op?
Are you planning to plumb more code thru this work in the future?
If yes the whole rx_mode handling should be in a dedicated helper
rather than indenting most of the function.
> + netif_addr_lock_bh(dev);
> +
> + err = __hw_addr_list_snapshot(&uc_snap, &dev->uc,
> + dev->addr_len);
> + if (!err)
> + err = __hw_addr_list_snapshot(&uc_ref, &dev->uc,
> + dev->addr_len);
> + if (!err)
> + err = __hw_addr_list_snapshot(&mc_snap, &dev->mc,
> + dev->addr_len);
> + if (!err)
> + err = __hw_addr_list_snapshot(&mc_ref, &dev->mc,
> + dev->addr_len);
This doesn't get slow with a few thousands of addresses?
> + netif_addr_unlock_bh(dev);
> +
> + if (err) {
> + netdev_WARN(dev, "failed to sync uc/mc addresses\n");
> + __hw_addr_flush(&uc_snap);
> + __hw_addr_flush(&uc_ref);
> + __hw_addr_flush(&mc_snap);
> + goto out;
> + }
> +
> + ops->ndo_set_rx_mode_async(dev, &uc_snap, &mc_snap);
> +
> + netif_addr_lock_bh(dev);
> + __hw_addr_list_reconcile(&dev->uc, &uc_snap,
> + &uc_ref, dev->addr_len);
> + __hw_addr_list_reconcile(&dev->mc, &mc_snap,
> + &mc_ref, dev->addr_len);
> + netif_addr_unlock_bh(dev);
> + }
> +
> +out:
> + netdev_unlock_ops(dev);
> + rtnl_unlock();
> +}
> +
> +/**
> + * __dev_set_rx_mode() - upload unicast and multicast address lists to device
> + * and configure RX filtering.
> + * @dev: device
> + *
> + * When the device doesn't support unicast filtering it is put in promiscuous
> + * mode while unicast addresses are present.
> */
> void __dev_set_rx_mode(struct net_device *dev)
> {
> const struct net_device_ops *ops = dev->netdev_ops;
>
> /* dev_open will call this function so the list will stay sane. */
> - if (!(dev->flags&IFF_UP))
> + if (!netif_up_and_present(dev))
> return;
>
> - if (!netif_device_present(dev))
> + if (ops->ndo_set_rx_mode_async) {
> + queue_work(rx_mode_wq, &dev->rx_mode_work);
> return;
> + }
>
> if (!(dev->priv_flags & IFF_UNICAST_FLT)) {
> /* Unicast addresses changes may only happen under the rtnl,
> @@ -11708,6 +11772,16 @@ void netdev_run_todo(void)
>
> __rtnl_unlock();
>
> + /* Make sure all pending rx_mode work completes before returning.
> + *
> + * rx_mode_wq may be NULL during early boot:
> + * core_initcall(netlink_proto_init) vs subsys_initcall(net_dev_init).
> + *
> + * Check current_work() to avoid flushing from the wq.
> + */
> + if (rx_mode_wq && !current_work())
> + flush_workqueue(rx_mode_wq);
Can we give the work a reference on the netdev (at init time) and
cancel + release it here instead of flushing / waiting?
> /* Wait for rcu callbacks to finish before next phase */
> if (!list_empty(&list))
> rcu_barrier();
> @@ -12099,6 +12173,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
> #endif
>
> mutex_init(&dev->lock);
> + INIT_WORK(&dev->rx_mode_work, dev_rx_mode_work);
>
> dev->priv_flags = IFF_XMIT_DST_RELEASE | IFF_XMIT_DST_RELEASE_PERM;
> setup(dev);
> @@ -12203,6 +12278,8 @@ void free_netdev(struct net_device *dev)
>
> kfree(rcu_dereference_protected(dev->ingress_queue, 1));
>
> + cancel_work_sync(&dev->rx_mode_work);
Should never happen so maybe wrap it in a WARN ?
> /* Flush device addresses */
> dev_addr_flush(dev);
>
> @@ -13296,6 +13373,10 @@ static int __init net_dev_init(void)
> if (register_pernet_device(&default_device_ops))
> goto out;
>
> + rx_mode_wq = alloc_ordered_workqueue("rx_mode_wq", 0);
> + if (!rx_mode_wq)
> + goto out;
> +
> open_softirq(NET_TX_SOFTIRQ, net_tx_action);
> open_softirq(NET_RX_SOFTIRQ, net_rx_action);
>
^ permalink raw reply
* [RFC PATCH v5 04/10] Docs/admin-guide/mm/damon/usage: update for pause file
From: SeongJae Park @ 2026-03-23 23:15 UTC (permalink / raw)
Cc: SeongJae Park, Liam R. Howlett, Andrew Morton, David Hildenbrand,
Jonathan Corbet, Lorenzo Stoakes, Michal Hocko, Mike Rapoport,
Shuah Khan, Suren Baghdasaryan, Vlastimil Babka, damon, linux-doc,
linux-kernel, linux-mm
In-Reply-To: <20260323231538.84452-1-sj@kernel.org>
Update DAMON usage document for the DAMON context execution pause/resume
feature.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
Documentation/admin-guide/mm/damon/usage.rst | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/Documentation/admin-guide/mm/damon/usage.rst b/Documentation/admin-guide/mm/damon/usage.rst
index 534e1199cf091..bfdb717441f05 100644
--- a/Documentation/admin-guide/mm/damon/usage.rst
+++ b/Documentation/admin-guide/mm/damon/usage.rst
@@ -66,7 +66,8 @@ comma (",").
│ :ref:`kdamonds <sysfs_kdamonds>`/nr_kdamonds
│ │ :ref:`0 <sysfs_kdamond>`/state,pid,refresh_ms
│ │ │ :ref:`contexts <sysfs_contexts>`/nr_contexts
- │ │ │ │ :ref:`0 <sysfs_context>`/avail_operations,operations,addr_unit
+ │ │ │ │ :ref:`0 <sysfs_context>`/avail_operations,operations,addr_unit,
+ │ │ │ │ pause
│ │ │ │ │ :ref:`monitoring_attrs <sysfs_monitoring_attrs>`/
│ │ │ │ │ │ intervals/sample_us,aggr_us,update_us
│ │ │ │ │ │ │ intervals_goal/access_bp,aggrs,min_sample_us,max_sample_us
@@ -194,9 +195,9 @@ details). At the moment, only one context per kdamond is supported, so only
contexts/<N>/
-------------
-In each context directory, three files (``avail_operations``, ``operations``
-and ``addr_unit``) and three directories (``monitoring_attrs``, ``targets``,
-and ``schemes``) exist.
+In each context directory, four files (``avail_operations``, ``operations``,
+``addr_unit`` and ``pause``) and three directories (``monitoring_attrs``,
+``targets``, and ``schemes``) exist.
DAMON supports multiple types of :ref:`monitoring operations
<damon_design_configurable_operations_set>`, including those for virtual address
@@ -214,6 +215,9 @@ reading from the ``operations`` file.
``addr_unit`` file is for setting and getting the :ref:`address unit
<damon_design_addr_unit>` parameter of the operations set.
+``pause`` file is for setting and getting the :ref:`pause request
+<damon_design_execution_model_and_data_structures>` parameter of the context.
+
.. _sysfs_monitoring_attrs:
contexts/<N>/monitoring_attrs/
--
2.47.3
^ permalink raw reply related
* [RFC PATCH v5 03/10] Docs/mm/damon/design: update for context pause/resume feature
From: SeongJae Park @ 2026-03-23 23:15 UTC (permalink / raw)
Cc: SeongJae Park, Liam R. Howlett, Andrew Morton, David Hildenbrand,
Jonathan Corbet, Lorenzo Stoakes, Michal Hocko, Mike Rapoport,
Shuah Khan, Suren Baghdasaryan, Vlastimil Babka, damon, linux-doc,
linux-kernel, linux-mm
In-Reply-To: <20260323231538.84452-1-sj@kernel.org>
Update DAMON design document for the context execution pause/resume
feature.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
Documentation/mm/damon/design.rst | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/Documentation/mm/damon/design.rst b/Documentation/mm/damon/design.rst
index afc7d52bda2f7..510ec6375178d 100644
--- a/Documentation/mm/damon/design.rst
+++ b/Documentation/mm/damon/design.rst
@@ -19,6 +19,13 @@ types of monitoring.
To know how user-space can do the configurations and start/stop DAMON, refer to
:ref:`DAMON sysfs interface <sysfs_interface>` documentation.
+Users can also request each context execution to be paused and resumed. When
+it is paused, the kdamond does nothing other than applying online parameter
+update.
+
+To know how user-space can pause/resume each context, refer to :ref:`DAMON
+sysfs context <sysfs_context>` usage documentation.
+
Overall Architecture
====================
--
2.47.3
^ permalink raw reply related
* [RFC PATCH v5 00/10] mm/damon: let DAMON be paused and resumed
From: SeongJae Park @ 2026-03-23 23:15 UTC (permalink / raw)
Cc: SeongJae Park, Liam R. Howlett, Andrew Morton, Brendan Higgins,
David Gow, David Hildenbrand, Jonathan Corbet, Lorenzo Stoakes,
Michal Hocko, Mike Rapoport, Shuah Khan, Shuah Khan,
Suren Baghdasaryan, Vlastimil Babka, damon, kunit-dev, linux-doc,
linux-kernel, linux-kselftest, linux-mm
DAMON utilizes a few mechanisms that enhance itself over time. Adaptive
regions adjustment, goal-based DAMOS quota auto-tuning and monitoring
intervals auto-tuning like self-training mechanisms are such examples.
It also adds access frequency stability information (age) to the
monitoring results, which makes it enhanced over time.
Sometimes users have to stop DAMON. In this case, DAMON internal state
that enhanced over the time of the last execution simply goes away.
Restarted DAMON have to train itself and enhance its output from the
scratch. This makes DAMON less useful in such cases. Introducing three
such use cases below.
Investigation of DAMON. It is best to do the investigation online,
especially when it is a production environment. DAMON therefore
provides features for such online investigations, including DAMOS stats,
monitoring result snapshot exposure, and multiple tracepoints. When
those are insufficient, and there are additional clues that could be
interfered by DAMON, users have to temporarily stop DAMON to collect the
additional clues. It is not very useful since many of DAMON internal
clues are gone when DAMON is stopped. The loss of the monitoring
results that improved over time is also problematic, especially in
production environments.
Monitoring of workloads that have different user-known phases. For
example, in Android, applications are known to have very different
access patterns and behaviors when they are running on the foreground
and the background. It can therefore be useful to separate monitoring
of apps based on whether they are running on the foreground and on the
background. Having two DAMON threads per application that paused and
resumed for the apps foreground/background switches can be useful for
the purpose. But such pause/resume of the execution is not supported.
Tests of DAMON. A few DAMON selftests are using drgn to dump the
internal DAMON status. The tests show if the dumped status is the same
as what the test code expected. Because DAMON keeps running and
modifying its internal status, there are chances of data races that can
cause false test results. Stopping DAMON can avoid the race. But,
since the internal state of DAMON is dropped, the test coverage will be
limited.
Let DAMON execution be paused and resumed without loss of the internal
state, to overhaul the limitations. For this, introduce a new DAMON
context parameter, namely 'pause'. API callers can update it while the
context is running, using the online parameters update functions
(damon_commit_ctx() and damon_call()). Once it is set, kdamond_fn()
main loop will do only limited works excluding the monitoring and DAMOS
works, while sleeping sampling intervals per the work. The limited
works include handling of the online parameters update. Hence users can
unset the 'pause' parameter again. Once it is unset, kdamond_fn() main
loop will do all the work again (resumed). Under the paused state, it
also does stop condition checks and handling of it, so that paused DAMON
can also be stopped if needed. Expose the feature to the user space via
DAMON sysfs interface. Also, update existing drgn-based tests to test
and use the feature.
Tests
=====
I confirmed the feature functionality using real time tracing ('perf
trace' or 'trace-cmd stream') of damon:damon_aggregated DAMON
tracepoint. By pausing and resuming the DAMON execution, I was able to
see the trace stops and continued as expected. Note that the pause
feature support is added to DAMON user-space tool (damo) after v3.1.9.
Users can use '--pause_ctx' command line option of damo for that, and I
actually used it for my test. The extended drgn-based selftests are
also testing a part of the functionality.
Patches Sequence
================
Patch 1 introduces the new core API for the pause feature. Patch 2
extend DAMON sysfs interface for the new parameter. Patches 3-5 update
design, usage and ABI documents for the new sysfs file, respectively.
The following five patches are for tests. Patch 6 implements a new
kunit test for the pause parameter online commitment. Patches 7 and 8
extend DAMON selftest helpers to support the new feature. Patch 9
extends selftest to test the commitment of the feature. Finally, patch
10 updates existing selftest to be safe from the race condition using
the pause/resume feature.
Changelog
=========
Changes from RFC v4
(https://lore.kerneel.org/20260322155728.81434-1-sj@kernel.org)
- Fix typo: selftets.
- Fix wrong selftests kdamonds resume iteration.
Changes from v1 (or, RFC v3)
(https://lore.kernel.org/20260321181343.93971-1-sj@kernel.org)
- Add RFC tag again.
- Handle maybe_corrupted inside pause-loop.
- Reduce unnecessary commits in sysfs.py selftest.
Changes from RFC v2
(https://lore.kernel.org/20260319052157.99433-1-sj@kernel.org)
- Move damon_ctx->pause to public fields section.
- Wordsmith design doc change.
- Fix unintended resume of contexts in multiple contexts use case.
- Rebase to latest mm-new.
Changes from RFC v1
(https://lore.kernel.org/20260315210012.94846-1-sj@kernel.org)
- Continuously cancel new damos_walk() requests when paused.
- Initialize damon_sysfs_context->pause.
- Make sysfs.py dump-purpose pausing to work for all contexts.
SeongJae Park (10):
mm/damon/core: introduce damon_ctx->paused
mm/damon/sysfs: add pause file under context dir
Docs/mm/damon/design: update for context pause/resume feature
Docs/admin-guide/mm/damon/usage: update for pause file
Docs/ABI/damon: update for pause sysfs file
mm/damon/tests/core-kunit: test pause commitment
selftests/damon/_damon_sysfs: support pause file staging
selftests/damon/drgn_dump_damon_status: dump pause
selftests/damon/sysfs.py: check pause on assert_ctx_committed()
selftests/damon/sysfs.py: pause DAMON before dumping status
.../ABI/testing/sysfs-kernel-mm-damon | 7 ++++
Documentation/admin-guide/mm/damon/usage.rst | 12 ++++--
Documentation/mm/damon/design.rst | 7 ++++
include/linux/damon.h | 2 +
mm/damon/core.c | 9 +++++
mm/damon/sysfs.c | 31 +++++++++++++++
mm/damon/tests/core-kunit.h | 4 ++
tools/testing/selftests/damon/_damon_sysfs.py | 10 ++++-
.../selftests/damon/drgn_dump_damon_status.py | 1 +
tools/testing/selftests/damon/sysfs.py | 39 +++++++++++++++++++
10 files changed, 117 insertions(+), 5 deletions(-)
base-commit: 4219363684c17e8704b4fd4ceac8940924a94b3d
--
2.47.3
^ permalink raw reply
* Re: [PATCH v6 26/40] arm_mpam: resctrl: Add kunit test for control format conversions
From: Gavin Shan @ 2026-03-23 23:10 UTC (permalink / raw)
To: Ben Horgan
Cc: amitsinght, baisheng.gao, baolin.wang, carl, dave.martin, david,
dfustini, fenghuay, james.morse, jonathan.cameron, kobak,
lcherian, linux-arm-kernel, linux-kernel, peternewman,
punit.agrawal, quic_jiles, reinette.chatre, rohit.mathew, scott,
sdonthineni, tan.shaopeng, xhao, catalin.marinas, will, corbet,
maz, oupton, joey.gouly, suzuki.poulose, kvmarm, zengheng4,
linux-doc, Shaopeng Tan
In-Reply-To: <20260313144617.3420416-27-ben.horgan@arm.com>
On 3/14/26 12:46 AM, Ben Horgan wrote:
> From: Dave Martin <Dave.Martin@arm.com>
>
> resctrl specifies the format of the control schemes, and these don't match
> the hardware.
>
> Some of the conversions are a bit hairy - add some kunit tests.
>
> Tested-by: Gavin Shan <gshan@redhat.com>
> Tested-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
> Tested-by: Peter Newman <peternewman@google.com>
> Tested-by: Zeng Heng <zengheng4@huawei.com>
> Tested-by: Punit Agrawal <punit.agrawal@oss.qualcomm.com>
> Reviewed-by: Zeng Heng <zengheng4@huawei.com>
> Reviewed-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> [morse: squashed enough of Dave's fixes in here that it's his patch now!]
> Signed-off-by: James Morse <james.morse@arm.com>
> Signed-off-by: Ben Horgan <ben.horgan@arm.com>
> ---
> Changes since v2:
> Include additional values from the latest spec
> ---
> drivers/resctrl/mpam_resctrl.c | 4 +
> drivers/resctrl/test_mpam_resctrl.c | 315 ++++++++++++++++++++++++++++
> 2 files changed, 319 insertions(+)
> create mode 100644 drivers/resctrl/test_mpam_resctrl.c
>
Reviewed-by: Gavin Shan <gshan@redhat.com>
^ permalink raw reply
* Re: [PATCH v6 25/40] arm_mpam: resctrl: Add support for 'MB' resource
From: Gavin Shan @ 2026-03-23 23:09 UTC (permalink / raw)
To: Ben Horgan
Cc: amitsinght, baisheng.gao, baolin.wang, carl, dave.martin, david,
dfustini, fenghuay, james.morse, jonathan.cameron, kobak,
lcherian, linux-arm-kernel, linux-kernel, peternewman,
punit.agrawal, quic_jiles, reinette.chatre, rohit.mathew, scott,
sdonthineni, tan.shaopeng, xhao, catalin.marinas, will, corbet,
maz, oupton, joey.gouly, suzuki.poulose, kvmarm, zengheng4,
linux-doc, Shaopeng Tan
In-Reply-To: <20260313144617.3420416-26-ben.horgan@arm.com>
Hi Ben,
On 3/14/26 12:46 AM, Ben Horgan wrote:
> From: James Morse <james.morse@arm.com>
>
> resctrl supports 'MB', as a percentage throttling of traffic from the
> L3. This is the control that mba_sc uses, so ideally the class chosen
> should be as close as possible to the counters used for mbm_total. If there
> is a single L3, it's the last cache, and the topology of the memory matches
> then the traffic at the memory controller will be equivalent to that at
> egress of the L3. If these conditions are met allow the memory class to
> back MB.
>
> MB's percentage control should be backed either with the fixed point
> fraction MBW_MAX or bandwidth portion bitmaps. The bandwidth portion
> bitmaps is not used as its tricky to pick which bits to use to avoid
> contention, and may be possible to expose this as something other than a
> percentage in the future.
>
> Tested-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
> Tested-by: Zeng Heng <zengheng4@huawei.com>
> Tested-by: Punit Agrawal <punit.agrawal@oss.qualcomm.com>
> Reviewed-by: Zeng Heng <zengheng4@huawei.com>
> Reviewed-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
> Co-developed-by: Dave Martin <Dave.Martin@arm.com>
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> Signed-off-by: James Morse <james.morse@arm.com>>
> Signed-off-by: Ben Horgan <ben.horgan@arm.com>
> ---
> Changes since v2:
> Code flow change
> Commit message 'or'
>
> Changes since v3:
> initialise tmp_cpumask
> update commit message
> check the traffic matches l3
> update comment on candidate_class update, only mbm_total
> drop tags due to rework
>
> Changes since v4:
> Move __free declarations to point of first use
> New line for a '{'
> set r->alloc_capable last (Reinette)
>
> Changes since v5:
> Mention L3 needs to be the last cache in commit message
> Consider memory side caches and numa nodes
> ---
> drivers/resctrl/mpam_resctrl.c | 287 ++++++++++++++++++++++++++++++++-
> 1 file changed, 286 insertions(+), 1 deletion(-)
>
One comment below and it deserves to be addressed if we have another respin:
Reviewed-by: Gavin Shan <gshan@redhat.com>
> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
> index 93c8a9608ed4..cad65cf7d12d 100644
> --- a/drivers/resctrl/mpam_resctrl.c
> +++ b/drivers/resctrl/mpam_resctrl.c
> @@ -267,6 +267,33 @@ static bool cache_has_usable_cpor(struct mpam_class *class)
> return class->props.cpbm_wd <= 32;
> }
>
> +static bool mba_class_use_mbw_max(struct mpam_props *cprops)
> +{
> + return (mpam_has_feature(mpam_feat_mbw_max, cprops) &&
> + cprops->bwa_wd);
> +}
> +
> +static bool class_has_usable_mba(struct mpam_props *cprops)
> +{
> + return mba_class_use_mbw_max(cprops);
> +}
> +
> +/*
> + * Calculate the worst-case percentage change from each implemented step
> + * in the control.
> + */
> +static u32 get_mba_granularity(struct mpam_props *cprops)
> +{
> + if (!mba_class_use_mbw_max(cprops))
> + return 0;
> +
> + /*
> + * bwa_wd is the number of bits implemented in the 0.xxx
> + * fixed point fraction. 1 bit is 50%, 2 is 25% etc.
> + */
> + return DIV_ROUND_UP(MAX_MBA_BW, 1 << cprops->bwa_wd);
> +}
> +
> /*
> * Each fixed-point hardware value architecturally represents a range
> * of values: the full range 0% - 100% is split contiguously into
> @@ -317,6 +344,166 @@ static u16 percent_to_mbw_max(u8 pc, struct mpam_props *cprops)
> return val;
> }
>
> +static u32 get_mba_min(struct mpam_props *cprops)
> +{
> + if (!mba_class_use_mbw_max(cprops)) {
> + WARN_ON_ONCE(1);
> + return 0;
> + }
> +
> + return mbw_max_to_percent(0, cprops);
> +}
> +
> +/* Find the L3 cache that has affinity with this CPU */
> +static int find_l3_equivalent_bitmask(int cpu, cpumask_var_t tmp_cpumask)
> +{
> + u32 cache_id = get_cpu_cacheinfo_id(cpu, 3);
> +
> + lockdep_assert_cpus_held();
> +
> + return mpam_get_cpumask_from_cache_id(cache_id, 3, tmp_cpumask);
> +}
> +
> +/*
> + * topology_matches_l3() - Is the provided class the same shape as L3
> + * @victim: The class we'd like to pretend is L3.
> + *
> + * resctrl expects all the world's a Xeon, and all counters are on the
> + * L3. We allow some mapping counters on other classes. This requires
> + * that the CPU->domain mapping is the same kind of shape.
> + *
> + * Using cacheinfo directly would make this work even if resctrl can't
> + * use the L3 - but cacheinfo can't tell us anything about offline CPUs.
> + * Using the L3 resctrl domain list also depends on CPUs being online.
> + * Using the mpam_class we picked for L3 so we can use its domain list
> + * assumes that there are MPAM controls on the L3.
> + * Instead, this path eventually uses the mpam_get_cpumask_from_cache_id()
> + * helper which can tell us about offline CPUs ... but getting the cache_id
> + * to start with relies on at least one CPU per L3 cache being online at
> + * boot.
> + *
> + * Walk the victim component list and compare the affinity mask with the
> + * corresponding L3. The topology matches if each victim:component's affinity
> + * mask is the same as the CPU's corresponding L3's. These lists/masks are
> + * computed from firmware tables so don't change at runtime.
> + */
> +static bool topology_matches_l3(struct mpam_class *victim)
> +{
> + int cpu, err;
> + struct mpam_component *victim_iter;
> +
> + lockdep_assert_cpus_held();
> +
> + cpumask_var_t __free(free_cpumask_var) tmp_cpumask = CPUMASK_VAR_NULL;
> + if (!alloc_cpumask_var(&tmp_cpumask, GFP_KERNEL))
> + return false;
> +
> + guard(srcu)(&mpam_srcu);
> + list_for_each_entry_srcu(victim_iter, &victim->components, class_list,
> + srcu_read_lock_held(&mpam_srcu)) {
> + if (cpumask_empty(&victim_iter->affinity)) {
> + pr_debug("class %u has CPU-less component %u - can't match L3!\n",
> + victim->level, victim_iter->comp_id);
> + return false;
> + }
> +
> + cpu = cpumask_any_and(&victim_iter->affinity, cpu_online_mask);
> + if (WARN_ON_ONCE(cpu >= nr_cpu_ids))
> + return false;
> +
> + cpumask_clear(tmp_cpumask);
> + err = find_l3_equivalent_bitmask(cpu, tmp_cpumask);
> + if (err) {
> + pr_debug("Failed to find L3's equivalent component to class %u component %u\n",
> + victim->level, victim_iter->comp_id);
> + return false;
> + }
> +
> + /* Any differing bits in the affinity mask? */
> + if (!cpumask_equal(tmp_cpumask, &victim_iter->affinity)) {
> + pr_debug("class %u component %u has Mismatched CPU mask with L3 equivalent\n"
> + "L3:%*pbl != victim:%*pbl\n",
> + victim->level, victim_iter->comp_id,
> + cpumask_pr_args(tmp_cpumask),
> + cpumask_pr_args(&victim_iter->affinity));
> +
> + return false;
> + }
> + }
> +
> + return true;
> +}
> +
> +/*
> + * Test if the traffic for a class matches that at egress from the L3. For
> + * MSC at memory controllers this is only possible if there is a single L3
> + * as otherwise the counters at the memory can include bandwidth from the
> + * non-local L3.
> + */
> +static bool traffic_matches_l3(struct mpam_class *class)
> +{
> + int err, cpu;
> +
> + lockdep_assert_cpus_held();
> +
> + if (class->type == MPAM_CLASS_CACHE && class->level == 3)
> + return true;
> +
> + if (class->type == MPAM_CLASS_CACHE && class->level != 3) {
> + pr_debug("class %u is a different cache from L3\n", class->level);
> + return false;
> + }
> +
> + if (class->type != MPAM_CLASS_MEMORY) {
> + pr_debug("class %u is neither of type cache or memory\n", class->level);
> + return false;
> + }
> +
We bail if the calss isn't MPAM_CLASS_MEMORY here ...
> + cpumask_var_t __free(free_cpumask_var) tmp_cpumask = CPUMASK_VAR_NULL;
> + if (!alloc_cpumask_var(&tmp_cpumask, GFP_KERNEL)) {
> + pr_debug("cpumask allocation failed\n");
> + return false;
> + }
> +
> + if (class->type != MPAM_CLASS_MEMORY) {
> + pr_debug("class %u is neither of type cache or memory\n",
> + class->level);
> + return false;
> + }
> +
Duplicated check here as the previous one. So this check can be dropped.
> + cpu = cpumask_any_and(&class->affinity, cpu_online_mask);
> + err = find_l3_equivalent_bitmask(cpu, tmp_cpumask);
> + if (err) {
> + pr_debug("Failed to find L3 downstream to cpu %d\n", cpu);
> + return false;
> + }
> +
> + if (!cpumask_equal(tmp_cpumask, cpu_possible_mask)) {
> + pr_debug("There is more than one L3\n");
> + return false;
> + }
> +
> + /* Be strict; the traffic might stop in the intermediate cache. */
> + if (get_cpu_cacheinfo_id(cpu, 4) != -1) {
> + pr_debug("L3 isn't the last level of cache\n");
> + return false;
> + }
> +
> + if (num_possible_nodes() > 1) {
> + pr_debug("There is more than one numa node\n");
> + return false;
> + }
> +
> +#ifdef CONFIG_HMEM_REPORTING
> + if (node_devices[cpu_to_node(cpu)]->cache_dev) {
> + pr_debug("There is a memory side cache\n");
> + return false;
> + }
> +#endif
> +
> + return true;
> +}
> +
> /* Test whether we can export MPAM_CLASS_CACHE:{2,3}? */
> static void mpam_resctrl_pick_caches(void)
> {
> @@ -358,9 +545,68 @@ static void mpam_resctrl_pick_caches(void)
> }
> }
>
> +static void mpam_resctrl_pick_mba(void)
> +{
> + struct mpam_class *class, *candidate_class = NULL;
> + struct mpam_resctrl_res *res;
> +
> + lockdep_assert_cpus_held();
> +
> + guard(srcu)(&mpam_srcu);
> + list_for_each_entry_srcu(class, &mpam_classes, classes_list,
> + srcu_read_lock_held(&mpam_srcu)) {
> + struct mpam_props *cprops = &class->props;
> +
> + if (class->level != 3 && class->type == MPAM_CLASS_CACHE) {
> + pr_debug("class %u is a cache but not the L3\n", class->level);
> + continue;
> + }
> +
> + if (!class_has_usable_mba(cprops)) {
> + pr_debug("class %u has no bandwidth control\n",
> + class->level);
> + continue;
> + }
> +
> + if (!cpumask_equal(&class->affinity, cpu_possible_mask)) {
> + pr_debug("class %u has missing CPUs\n", class->level);
> + continue;
> + }
> +
> + if (!topology_matches_l3(class)) {
> + pr_debug("class %u topology doesn't match L3\n",
> + class->level);
> + continue;
> + }
> +
> + if (!traffic_matches_l3(class)) {
> + pr_debug("class %u traffic doesn't match L3 egress\n",
> + class->level);
> + continue;
> + }
> +
> + /*
> + * Pick a resource to be MBA that as close as possible to
> + * the L3. mbm_total counts the bandwidth leaving the L3
> + * cache and MBA should correspond as closely as possible
> + * for proper operation of mba_sc.
> + */
> + if (!candidate_class || class->level < candidate_class->level)
> + candidate_class = class;
> + }
> +
> + if (candidate_class) {
> + pr_debug("selected class %u to back MBA\n",
> + candidate_class->level);
> + res = &mpam_resctrl_controls[RDT_RESOURCE_MBA];
> + res->class = candidate_class;
> + }
> +}
> +
> static int mpam_resctrl_control_init(struct mpam_resctrl_res *res)
> {
> struct mpam_class *class = res->class;
> + struct mpam_props *cprops = &class->props;
> struct rdt_resource *r = &res->resctrl_res;
>
> switch (r->rid) {
> @@ -392,6 +638,19 @@ static int mpam_resctrl_control_init(struct mpam_resctrl_res *res)
> r->cache.shareable_bits = resctrl_get_default_ctrl(r);
> r->alloc_capable = true;
> break;
> + case RDT_RESOURCE_MBA:
> + r->schema_fmt = RESCTRL_SCHEMA_RANGE;
> + r->ctrl_scope = RESCTRL_L3_CACHE;
> +
> + r->membw.delay_linear = true;
> + r->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED;
> + r->membw.min_bw = get_mba_min(cprops);
> + r->membw.max_bw = MAX_MBA_BW;
> + r->membw.bw_gran = get_mba_granularity(cprops);
> +
> + r->name = "MB";
> + r->alloc_capable = true;
> + break;
> default:
> return -EINVAL;
> }
> @@ -406,7 +665,17 @@ static int mpam_resctrl_pick_domain_id(int cpu, struct mpam_component *comp)
> if (class->type == MPAM_CLASS_CACHE)
> return comp->comp_id;
>
> - /* TODO: repaint domain ids to match the L3 domain ids */
> + if (topology_matches_l3(class)) {
> + /* Use the corresponding L3 component ID as the domain ID */
> + int id = get_cpu_cacheinfo_id(cpu, 3);
> +
> + /* Implies topology_matches_l3() made a mistake */
> + if (WARN_ON_ONCE(id == -1))
> + return comp->comp_id;
> +
> + return id;
> + }
> +
> /* Otherwise, expose the ID used by the firmware table code. */
> return comp->comp_id;
> }
> @@ -446,6 +715,12 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
> case RDT_RESOURCE_L3:
> configured_by = mpam_feat_cpor_part;
> break;
> + case RDT_RESOURCE_MBA:
> + if (mpam_has_feature(mpam_feat_mbw_max, cprops)) {
> + configured_by = mpam_feat_mbw_max;
> + break;
> + }
> + fallthrough;
> default:
> return resctrl_get_default_ctrl(r);
> }
> @@ -457,6 +732,8 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
> switch (configured_by) {
> case mpam_feat_cpor_part:
> return cfg->cpbm;
> + case mpam_feat_mbw_max:
> + return mbw_max_to_percent(cfg->mbw_max, cprops);
> default:
> return resctrl_get_default_ctrl(r);
> }
> @@ -504,6 +781,13 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
> cfg.cpbm = cfg_val;
> mpam_set_feature(mpam_feat_cpor_part, &cfg);
> break;
> + case RDT_RESOURCE_MBA:
> + if (mpam_has_feature(mpam_feat_mbw_max, cprops)) {
> + cfg.mbw_max = percent_to_mbw_max(cfg_val, cprops);
> + mpam_set_feature(mpam_feat_mbw_max, &cfg);
> + break;
> + }
> + fallthrough;
> default:
> return -EINVAL;
> }
> @@ -775,6 +1059,7 @@ int mpam_resctrl_setup(void)
>
> /* Find some classes to use for controls */
> mpam_resctrl_pick_caches();
> + mpam_resctrl_pick_mba();
>
> /* Initialise the resctrl structures from the classes */
> for_each_mpam_resctrl_control(res, rid) {
Thanks,
Gavin
^ permalink raw reply
* Re: [PATCH 0/2] kallsyms: show typed function parameters in oops/WARN dumps
From: Sasha Levin @ 2026-03-23 23:08 UTC (permalink / raw)
To: Andrew Morton
Cc: Masahiro Yamada, Nathan Chancellor, Nicolas Schier,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Peter Zijlstra, Josh Poimboeuf, Petr Mladek,
Alexei Starovoitov, Jonathan Corbet, David Gow, Kees Cook,
Greg KH, Luis Chamberlain, Steven Rostedt, Helge Deller,
Randy Dunlap, Geert Uytterhoeven, Juergen Gross, James Bottomley,
Alexey Dobriyan, Vlastimil Babka, Laurent Pinchart, Petr Pavlu,
x86, linux-kernel, linux-kbuild, linux-doc, linux-modules, bpf
In-Reply-To: <20260323155057.29b8e17d10421962d5ed798d@linux-foundation.org>
On Mon, Mar 23, 2026 at 03:50:57PM -0700, Andrew Morton wrote:
>On Mon, 23 Mar 2026 12:48:55 -0400 Sasha Levin <sashal@kernel.org> wrote:
>
>> Building on the lineinfo series, this adds typed function parameter
>> display to oops and WARN dumps. A build-time tool extracts parameter
>> names and types from DWARF, and the kernel maps pt_regs to the calling
>> convention at crash time. When BTF is available, struct pointer
>> parameters are dereferenced and their members displayed.
>
>mm.git is full and I'm seriously looking at loadshedded. Can we please
>leave this until next cycle, give your "kallsyms: embed source file:line
>info in kernel stack traces", v4 time to settle in?
Definitely.
If you want to ignore these, and related patches that might appear in the next
couple of weeks, I'll plan to send them to you in an organized series after
-rc1.
--
Thanks,
Sasha
^ permalink raw reply
* Re: [PATCH] docs: add advanced search for kernel documentation
From: Randy Dunlap @ 2026-03-23 23:01 UTC (permalink / raw)
To: Rito Rhymes, Jonathan Corbet, Mauro Carvalho Chehab, linux-doc
Cc: Shuah Khan, linux-kernel
In-Reply-To: <DHAJ2FE2Z4OL.ZUA8AQEMPC01@ritovision.com>
On 3/23/26 3:50 PM, Rito Rhymes wrote:
> I believe I identified the issue as a Sphinx version compatibility
> problem.
>
> I've been working on a more robust reroll. I expect to have it by
> tomorrow, and we can test it when you're ready.
Sounds good. Thanks.
--
~Randy
^ permalink raw reply
* Re: [PATCH 0/2] kallsyms: show typed function parameters in oops/WARN dumps
From: Sasha Levin @ 2026-03-23 22:58 UTC (permalink / raw)
To: Alexey Dobriyan
Cc: Andrew Morton, Masahiro Yamada, Nathan Chancellor, Nicolas Schier,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Peter Zijlstra, Josh Poimboeuf, Petr Mladek,
Alexei Starovoitov, Jonathan Corbet, David Gow, Kees Cook,
Greg KH, Luis Chamberlain, Steven Rostedt, Helge Deller,
Randy Dunlap, Geert Uytterhoeven, Juergen Gross, James Bottomley,
Vlastimil Babka, Laurent Pinchart, Petr Pavlu, x86, linux-kernel,
linux-kbuild, linux-doc, linux-modules, bpf
In-Reply-To: <cdd61497-8d50-4fc5-aec8-47286e23d537@p183>
On Mon, Mar 23, 2026 at 09:43:59PM +0300, Alexey Dobriyan wrote:
>On Mon, Mar 23, 2026 at 12:48:55PM -0400, Sasha Levin wrote:
>> Function parameters (paraminfo_demo_crash):
>> uts (struct new_utsname *) = 0xffffffffb8ca8d00
>> .sysname = "Linux" .nodename = "localhost"
>> .release = "7.0.0-rc2-00006-g3190..." .version = "#45 SMP PRE"
>> file (struct file * ) = 0xffffa0a3c250acc0
>> .f_mode = (fmode_t)67993630 .f_op = (struct file_operations *)0xffffffffb7237620
>> .f_flags = (unsigned int)32769 .f_cred = (struct cred *)0xffffa0a3c2e06a80
>> .dentry = (struct dentry *)0xffffa0a3c0978cc0
>
>Should this be in crash's format?
>
> struct dentry ffffffffffff0000
The format currently used comes from the kernel's own BTF show infrastructure.
crash's struct dentry ffffffffffff0000 syntax is specific to crash. drgn, GDB,
bpftool, and the kernel's own BTF rendering all use the (struct type *)0xaddr
notation we're already using. Adopting crash's format would make this output
inconsistent with all other BTF-based output in the kernel, and would also lose
the member name context (.dentry).
--
Thanks,
Sasha
^ permalink raw reply
* Re: [PATCH v6 24/40] arm_mpam: resctrl: Wait for cacheinfo to be ready
From: Gavin Shan @ 2026-03-23 22:53 UTC (permalink / raw)
To: Ben Horgan
Cc: amitsinght, baisheng.gao, baolin.wang, carl, dave.martin, david,
dfustini, fenghuay, james.morse, jonathan.cameron, kobak,
lcherian, linux-arm-kernel, linux-kernel, peternewman,
punit.agrawal, quic_jiles, reinette.chatre, rohit.mathew, scott,
sdonthineni, tan.shaopeng, xhao, catalin.marinas, will, corbet,
maz, oupton, joey.gouly, suzuki.poulose, kvmarm, zengheng4,
linux-doc, Shaopeng Tan
In-Reply-To: <20260313144617.3420416-25-ben.horgan@arm.com>
On 3/14/26 12:46 AM, Ben Horgan wrote:
> In order to calculate the rmid realloc threshold the size of the cache
> needs to be known. Cache domains will also be named after the cache id. So
> that this information can be extracted from cacheinfo we need to wait for
> it to be ready. The cacheinfo information is populated in device_initcall()
> so we wait for that.
>
> Tested-by: Gavin Shan <gshan@redhat.com>
> Tested-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
> Tested-by: Peter Newman <peternewman@google.com>
> Tested-by: Zeng Heng <zengheng4@huawei.com>
> Tested-by: Punit Agrawal <punit.agrawal@oss.qualcomm.com>
> Reviewed-by: Zeng Heng <zengheng4@huawei.com>
> Reviewed-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
> Signed-off-by: James Morse <james.morse@arm.com>
> [horgan: split out from another patch]
> Signed-off-by: Ben Horgan <ben.horgan@arm.com>
> ---
> This is moved into it's own patch to allow all uses of cacheinfo to be
> valid when they are introduced.
> ---
> drivers/resctrl/mpam_resctrl.c | 19 +++++++++++++++++++
> 1 file changed, 19 insertions(+)
>
Reviewed-by: Gavin Shan <gshan@redhat.com>
^ permalink raw reply
* Re: [PATCH 0/2] kallsyms: show typed function parameters in oops/WARN dumps
From: Andrew Morton @ 2026-03-23 22:50 UTC (permalink / raw)
To: Sasha Levin
Cc: Masahiro Yamada, Nathan Chancellor, Nicolas Schier,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
H. Peter Anvin, Peter Zijlstra, Josh Poimboeuf, Petr Mladek,
Alexei Starovoitov, Jonathan Corbet, David Gow, Kees Cook,
Greg KH, Luis Chamberlain, Steven Rostedt, Helge Deller,
Randy Dunlap, Geert Uytterhoeven, Juergen Gross, James Bottomley,
Alexey Dobriyan, Vlastimil Babka, Laurent Pinchart, Petr Pavlu,
x86, linux-kernel, linux-kbuild, linux-doc, linux-modules, bpf
In-Reply-To: <20260323164858.1939248-1-sashal@kernel.org>
On Mon, 23 Mar 2026 12:48:55 -0400 Sasha Levin <sashal@kernel.org> wrote:
> Building on the lineinfo series, this adds typed function parameter
> display to oops and WARN dumps. A build-time tool extracts parameter
> names and types from DWARF, and the kernel maps pt_regs to the calling
> convention at crash time. When BTF is available, struct pointer
> parameters are dereferenced and their members displayed.
mm.git is full and I'm seriously looking at loadshedded. Can we please
leave this until next cycle, give your "kallsyms: embed source file:line
info in kernel stack traces", v4 time to settle in?
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox