* 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 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
* [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 10/24] vfio: Enforce preserved devices are retrieved via LIVEUPDATE_SESSION_RETRIEVE_FD
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>
Enforce that files for incoming (preserved by previous kernel) VFIO
devices are retrieved via LIVEUPDATE_SESSION_RETRIEVE_FD rather than by
opening the corresponding VFIO character device or via
VFIO_GROUP_GET_DEVICE_FD.
Both of these methods would result in VFIO initializing the device
without access to the preserved state of the device passed by the
previous kernel.
Reviewed-by: Pranjal Shrivastava <praan@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
drivers/vfio/device_cdev.c | 4 ++++
drivers/vfio/group.c | 9 +++++++++
drivers/vfio/pci/vfio_pci_liveupdate.c | 6 ++++++
drivers/vfio/vfio.h | 18 ++++++++++++++++++
4 files changed, 37 insertions(+)
diff --git a/drivers/vfio/device_cdev.c b/drivers/vfio/device_cdev.c
index edf322315a41..6844684a3d8e 100644
--- a/drivers/vfio/device_cdev.c
+++ b/drivers/vfio/device_cdev.c
@@ -91,6 +91,10 @@ 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);
+ /* Device file must be retrieved via LIVEUPDATE_SESSION_RETRIEVE_FD */
+ if (vfio_liveupdate_incoming_is_preserved(device))
+ return -EBUSY;
+
return vfio_device_cdev_open(device, &file);
}
diff --git a/drivers/vfio/group.c b/drivers/vfio/group.c
index 4f15016d2a5f..0fa9761b13d3 100644
--- a/drivers/vfio/group.c
+++ b/drivers/vfio/group.c
@@ -311,6 +311,15 @@ static int vfio_group_ioctl_get_device_fd(struct vfio_group *group,
if (IS_ERR(device))
return PTR_ERR(device);
+ /*
+ * This device was preserved across a Live Update. Accessing it via
+ * VFIO_GROUP_GET_DEVICE_FD is not allowed.
+ */
+ if (vfio_liveupdate_incoming_is_preserved(device)) {
+ vfio_device_put_registration(device);
+ return -EBUSY;
+ }
+
fd = FD_ADD(O_CLOEXEC, vfio_device_open_file(device));
if (fd < 0)
vfio_device_put_registration(device);
diff --git a/drivers/vfio/pci/vfio_pci_liveupdate.c b/drivers/vfio/pci/vfio_pci_liveupdate.c
index b960ec3ffbf2..6f760ace7065 100644
--- a/drivers/vfio/pci/vfio_pci_liveupdate.c
+++ b/drivers/vfio/pci/vfio_pci_liveupdate.c
@@ -47,6 +47,12 @@
* ...
* ioctl(session_fd, LIVEUPDATE_SESSION_FINISH, ...);
*
+ * .. note::
+ * After kexec, if a device was preserved by the previous kernel, attempting
+ * to open a new file for the device via its character device
+ * (``/dev/vfio/devices/X``) or via ``VFIO_GROUP_GET_DEVICE_FD`` will fail
+ * with ``-EBUSY``.
+ *
* Restrictions
* ============
*
diff --git a/drivers/vfio/vfio.h b/drivers/vfio/vfio.h
index 50128da18bca..8fcc98cf9577 100644
--- a/drivers/vfio/vfio.h
+++ b/drivers/vfio/vfio.h
@@ -11,6 +11,7 @@
#include <linux/cdev.h>
#include <linux/module.h>
#include <linux/vfio.h>
+#include <linux/pci.h>
struct iommufd_ctx;
struct iommu_group;
@@ -462,4 +463,21 @@ static inline void vfio_device_debugfs_init(struct vfio_device *vdev) { }
static inline void vfio_device_debugfs_exit(struct vfio_device *vdev) { }
#endif /* CONFIG_VFIO_DEBUGFS */
+#ifdef CONFIG_PCI_LIVEUPDATE
+static inline bool vfio_liveupdate_incoming_is_preserved(struct vfio_device *device)
+{
+ struct device *d = device->dev;
+
+ if (dev_is_pci(d))
+ return to_pci_dev(d)->liveupdate_incoming;
+
+ return false;
+}
+#else
+static inline bool vfio_liveupdate_incoming_is_preserved(struct vfio_device *device)
+{
+ return false;
+}
+#endif /* CONFIG_PCI_LIVEUPDATE */
+
#endif
--
2.53.0.983.g0bb29b3bc5-goog
^ permalink raw reply related
* [PATCH v3 11/24] vfio/pci: Store incoming Live Update state in struct vfio_pci_core_device
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>
Stash a pointer to a device's incoming Live Updated state in struct
vfio_pci_core_device. This will enable subsequent commits to use the
preserved state when initializing the device.
To enable VFIO to safely access this pointer during device enablement,
require that the device is fully enabled before returning true from
can_finish(). This is synchronized by vfio_pci_core.c setting
vdev->liveupdate_incoming_state to NULL under dev_set lock once it's
done using it.
Signed-off-by: David Matlack <dmatlack@google.com>
---
drivers/vfio/pci/vfio_pci_core.c | 2 +-
drivers/vfio/pci/vfio_pci_liveupdate.c | 17 ++++++++++++++++-
include/linux/vfio_pci_core.h | 2 ++
3 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
index 81f941323641..d7c472cf4729 100644
--- a/drivers/vfio/pci/vfio_pci_core.c
+++ b/drivers/vfio/pci/vfio_pci_core.c
@@ -568,7 +568,7 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev)
if (!vfio_vga_disabled() && vfio_pci_is_vga(pdev))
vdev->has_vga = true;
-
+ vdev->liveupdate_incoming_state = NULL;
return 0;
out_free_zdev:
diff --git a/drivers/vfio/pci/vfio_pci_liveupdate.c b/drivers/vfio/pci/vfio_pci_liveupdate.c
index 6f760ace7065..8d6681e1d328 100644
--- a/drivers/vfio/pci/vfio_pci_liveupdate.c
+++ b/drivers/vfio/pci/vfio_pci_liveupdate.c
@@ -226,6 +226,7 @@ static int match_device(struct device *dev, const void *arg)
static int vfio_pci_liveupdate_retrieve(struct liveupdate_file_op_args *args)
{
struct vfio_pci_core_device_ser *ser;
+ struct vfio_pci_core_device *vdev;
struct vfio_device *device;
struct file *file;
int ret = 0;
@@ -246,6 +247,9 @@ static int vfio_pci_liveupdate_retrieve(struct liveupdate_file_op_args *args)
goto out;
}
+ vdev = container_of(device, struct vfio_pci_core_device, vdev);
+ vdev->liveupdate_incoming_state = ser;
+
args->file = file;
out:
/* Drop the reference from vfio_find_device() */
@@ -255,7 +259,18 @@ static int vfio_pci_liveupdate_retrieve(struct liveupdate_file_op_args *args)
static bool vfio_pci_liveupdate_can_finish(struct liveupdate_file_op_args *args)
{
- return args->retrieve_status > 0;
+ struct vfio_pci_core_device *vdev;
+ struct vfio_device *device;
+
+ if (args->retrieve_status <= 0)
+ return false;
+
+ device = vfio_device_from_file(args->file);
+ vdev = container_of(device, struct vfio_pci_core_device, vdev);
+
+ /* Check that vdev->liveupdate_incoming_state is no longer in use. */
+ guard(mutex)(&device->dev_set->lock);
+ return !vdev->liveupdate_incoming_state;
}
static void vfio_pci_liveupdate_finish(struct liveupdate_file_op_args *args)
diff --git a/include/linux/vfio_pci_core.h b/include/linux/vfio_pci_core.h
index 2ebba746c18f..0c508dd8d1ac 100644
--- a/include/linux/vfio_pci_core.h
+++ b/include/linux/vfio_pci_core.h
@@ -26,6 +26,7 @@
#define VFIO_PCI_OFFSET_MASK (((u64)(1) << VFIO_PCI_OFFSET_SHIFT) - 1)
struct vfio_pci_core_device;
+struct vfio_pci_core_device_ser;
struct vfio_pci_region;
struct p2pdma_provider;
struct dma_buf_attachment;
@@ -142,6 +143,7 @@ struct vfio_pci_core_device {
struct notifier_block nb;
struct rw_semaphore memory_lock;
struct list_head dmabufs;
+ struct vfio_pci_core_device_ser *liveupdate_incoming_state;
};
enum vfio_pci_io_width {
--
2.53.0.983.g0bb29b3bc5-goog
^ permalink raw reply related
* [PATCH v3 12/24] vfio/pci: Skip reset of preserved device 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>
Do not reset the device when a Live Update preserved vfio-pci device is
retrieved and first enabled. vfio_pci_liveupdate_freeze() guarantees the
device is reset prior to Live Update, so there's no reason to reset it
again after Live Update.
Since VFIO normally uses the initial reset to detect if the device
supports function resets, pass that from the previous kernel via
struct vfio_pci_core_dev_ser.
Signed-off-by: Vipin Sharma <vipinsh@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
drivers/vfio/pci/vfio_pci_core.c | 31 ++++++++++++++++++++++----
drivers/vfio/pci/vfio_pci_liveupdate.c | 4 ++++
include/linux/kho/abi/vfio_pci.h | 4 +++-
3 files changed, 34 insertions(+), 5 deletions(-)
diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
index d7c472cf4729..849a3b57d56b 100644
--- a/drivers/vfio/pci/vfio_pci_core.c
+++ b/drivers/vfio/pci/vfio_pci_core.c
@@ -16,6 +16,7 @@
#include <linux/file.h>
#include <linux/interrupt.h>
#include <linux/iommu.h>
+#include <linux/kho/abi/vfio_pci.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/notifier.h>
@@ -494,6 +495,30 @@ static const struct dev_pm_ops vfio_pci_core_pm_ops = {
NULL)
};
+static int vfio_pci_core_probe_reset(struct vfio_pci_core_device *vdev)
+{
+ int ret;
+
+ /*
+ * This device was preserved by the previous kernel across a Live
+ * Update, so it does not need to be reset and reset_works can be
+ * inherited from the previous kernel.
+ */
+ if (vdev->liveupdate_incoming_state) {
+ vdev->reset_works = vdev->liveupdate_incoming_state->reset_works;
+ return 0;
+ }
+
+ ret = pci_try_reset_function(vdev->pdev);
+
+ /* Bail if the device lock cannot be acquired. */
+ if (ret == -EAGAIN)
+ return ret;
+
+ vdev->reset_works = !ret;
+ return 0;
+}
+
int vfio_pci_core_enable(struct vfio_pci_core_device *vdev)
{
struct pci_dev *pdev = vdev->pdev;
@@ -514,12 +539,10 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev)
if (ret)
goto out_power;
- /* If reset fails because of the device lock, fail this path entirely */
- ret = pci_try_reset_function(pdev);
- if (ret == -EAGAIN)
+ ret = vfio_pci_core_probe_reset(vdev);
+ if (ret)
goto out_disable_device;
- vdev->reset_works = !ret;
pci_save_state(pdev);
vdev->pci_saved_state = pci_store_saved_state(pdev);
if (!vdev->pci_saved_state)
diff --git a/drivers/vfio/pci/vfio_pci_liveupdate.c b/drivers/vfio/pci/vfio_pci_liveupdate.c
index 8d6681e1d328..874c821bf6eb 100644
--- a/drivers/vfio/pci/vfio_pci_liveupdate.c
+++ b/drivers/vfio/pci/vfio_pci_liveupdate.c
@@ -91,6 +91,9 @@
* kernel guarantees the these will not change across a kexec when a device
* is preserved.
*
+ * * Whether or not the device supports function resets. This is necessary to
+ * avoid resetting the device after kexec to probe for reset support.
+ *
* 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
@@ -162,6 +165,7 @@ static int vfio_pci_liveupdate_preserve(struct liveupdate_file_op_args *args)
ser->bdf = pci_dev_id(pdev);
ser->domain = pci_domain_nr(pdev->bus);
+ ser->reset_works = vdev->reset_works;
args->serialized_data = virt_to_phys(ser);
return 0;
diff --git a/include/linux/kho/abi/vfio_pci.h b/include/linux/kho/abi/vfio_pci.h
index 876aaf81dd92..c057794a044f 100644
--- a/include/linux/kho/abi/vfio_pci.h
+++ b/include/linux/kho/abi/vfio_pci.h
@@ -26,7 +26,7 @@
* incrementing the version number in the VFIO_PCI_LUO_FH_COMPATIBLE string.
*/
-#define VFIO_PCI_LUO_FH_COMPATIBLE "vfio-pci-v1"
+#define VFIO_PCI_LUO_FH_COMPATIBLE "vfio-pci-v2"
/**
* struct vfio_pci_core_device_ser - Serialized state of a single VFIO PCI
@@ -34,10 +34,12 @@
*
* @domain: The device's PCI domain number (segment).
* @bdf: The device's PCI bus, device, and function number.
+ * @reset_works: Non-zero if the device supports function resets.
*/
struct vfio_pci_core_device_ser {
u32 domain;
u16 bdf;
+ u8 reset_works;
} __packed;
#endif /* _LINUX_LIVEUPDATE_ABI_VFIO_PCI_H */
--
2.53.0.983.g0bb29b3bc5-goog
^ permalink raw reply related
* [PATCH v3 13/24] docs: liveupdate: Add documentation for VFIO PCI
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>
Add documentation for preserving VFIO device files across a Live Update,
generated from the kernel-doc comments in the code.
Signed-off-by: David Matlack <dmatlack@google.com>
---
Documentation/core-api/liveupdate.rst | 1 +
.../driver-api/vfio_pci_liveupdate.rst | 23 +++++++++++++++++++
MAINTAINERS | 1 +
3 files changed, 25 insertions(+)
create mode 100644 Documentation/driver-api/vfio_pci_liveupdate.rst
diff --git a/Documentation/core-api/liveupdate.rst b/Documentation/core-api/liveupdate.rst
index d56a7760978a..c55d0d9d1d3b 100644
--- a/Documentation/core-api/liveupdate.rst
+++ b/Documentation/core-api/liveupdate.rst
@@ -34,6 +34,7 @@ The following types of file descriptors can be preserved
:maxdepth: 1
../mm/memfd_preservation
+ ../driver-api/vfio_pci_liveupdate
Public API
==========
diff --git a/Documentation/driver-api/vfio_pci_liveupdate.rst b/Documentation/driver-api/vfio_pci_liveupdate.rst
new file mode 100644
index 000000000000..1098b84e5ecd
--- /dev/null
+++ b/Documentation/driver-api/vfio_pci_liveupdate.rst
@@ -0,0 +1,23 @@
+.. SPDX-License-Identifier: GPL-2.0-or-later
+
+====================================
+VFIO PCI Device Preservation via LUO
+====================================
+
+.. kernel-doc:: drivers/vfio/pci/vfio_pci_liveupdate.c
+ :doc: VFIO PCI Preservation via LUO
+
+VFIO PCI Preservation ABI
+=========================
+
+.. kernel-doc:: include/linux/kho/abi/vfio_pci.h
+ :doc: VFIO PCI Live Update ABI
+
+.. kernel-doc:: include/linux/kho/abi/vfio_pci.h
+ :internal:
+
+See Also
+========
+
+- :doc:`/core-api/liveupdate`
+- :doc:`/core-api/kho/index`
diff --git a/MAINTAINERS b/MAINTAINERS
index a16a7ecc67a4..a6a31b94a4e8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27684,6 +27684,7 @@ T: git https://github.com/awilliam/linux-vfio.git
F: Documentation/ABI/testing/debugfs-vfio
F: Documentation/ABI/testing/sysfs-devices-vfio-dev
F: Documentation/driver-api/vfio.rst
+F: Documentation/driver-api/vfio_pci_liveupdate.rst
F: drivers/vfio/
F: include/linux/kho/abi/vfio_pci.h
F: include/linux/vfio.h
--
2.53.0.983.g0bb29b3bc5-goog
^ permalink raw reply related
* [PATCH v3 14/24] selftests/liveupdate: Move luo_test_utils.* into a reusable library
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>
Move luo_test_utils.[ch] into a lib/ directory and pull the rules to
build them out into a separate make script. This will enable these
utilities to be also built by and used within other selftests (such as
VFIO) in subsequent commits.
No functional change intended.
Signed-off-by: Vipin Sharma <vipinsh@google.com>
Co-developed-by: David Matlack <dmatlack@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
tools/testing/selftests/liveupdate/.gitignore | 1 +
tools/testing/selftests/liveupdate/Makefile | 14 ++++---------
.../include/libliveupdate.h} | 8 ++++----
.../selftests/liveupdate/lib/libliveupdate.mk | 20 +++++++++++++++++++
.../{luo_test_utils.c => lib/liveupdate.c} | 2 +-
.../selftests/liveupdate/luo_kexec_simple.c | 2 +-
.../selftests/liveupdate/luo_multi_session.c | 2 +-
7 files changed, 32 insertions(+), 17 deletions(-)
rename tools/testing/selftests/liveupdate/{luo_test_utils.h => lib/include/libliveupdate.h} (87%)
create mode 100644 tools/testing/selftests/liveupdate/lib/libliveupdate.mk
rename tools/testing/selftests/liveupdate/{luo_test_utils.c => lib/liveupdate.c} (99%)
diff --git a/tools/testing/selftests/liveupdate/.gitignore b/tools/testing/selftests/liveupdate/.gitignore
index 661827083ab6..18a0c7036cf3 100644
--- a/tools/testing/selftests/liveupdate/.gitignore
+++ b/tools/testing/selftests/liveupdate/.gitignore
@@ -3,6 +3,7 @@
!/**/
!*.c
!*.h
+!*.mk
!*.sh
!.gitignore
!config
diff --git a/tools/testing/selftests/liveupdate/Makefile b/tools/testing/selftests/liveupdate/Makefile
index 080754787ede..a060cc21f27f 100644
--- a/tools/testing/selftests/liveupdate/Makefile
+++ b/tools/testing/selftests/liveupdate/Makefile
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-LIB_C += luo_test_utils.c
-
TEST_GEN_PROGS += liveupdate
TEST_GEN_PROGS_EXTENDED += luo_kexec_simple
@@ -10,25 +8,21 @@ TEST_GEN_PROGS_EXTENDED += luo_multi_session
TEST_FILES += do_kexec.sh
include ../lib.mk
+include lib/libliveupdate.mk
CFLAGS += $(KHDR_INCLUDES)
CFLAGS += -Wall -O2 -Wno-unused-function
CFLAGS += -MD
-LIB_O := $(patsubst %.c, $(OUTPUT)/%.o, $(LIB_C))
TEST_O := $(patsubst %, %.o, $(TEST_GEN_PROGS))
TEST_O += $(patsubst %, %.o, $(TEST_GEN_PROGS_EXTENDED))
-TEST_DEP_FILES := $(patsubst %.o, %.d, $(LIB_O))
+TEST_DEP_FILES := $(patsubst %.o, %.d, $(LIBLIVEUPDATE_O))
TEST_DEP_FILES += $(patsubst %.o, %.d, $(TEST_O))
-include $(TEST_DEP_FILES)
-$(LIB_O): $(OUTPUT)/%.o: %.c
- $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
-
-$(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/%: %.o $(LIB_O)
- $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $< $(LIB_O) $(LDLIBS) -o $@
+$(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/%: %.o $(LIBLIVEUPDATE_O)
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $< $(LIBLIVEUPDATE_O) $(LDLIBS) -o $@
-EXTRA_CLEAN += $(LIB_O)
EXTRA_CLEAN += $(TEST_O)
EXTRA_CLEAN += $(TEST_DEP_FILES)
diff --git a/tools/testing/selftests/liveupdate/luo_test_utils.h b/tools/testing/selftests/liveupdate/lib/include/libliveupdate.h
similarity index 87%
rename from tools/testing/selftests/liveupdate/luo_test_utils.h
rename to tools/testing/selftests/liveupdate/lib/include/libliveupdate.h
index 90099bf49577..4390a2737930 100644
--- a/tools/testing/selftests/liveupdate/luo_test_utils.h
+++ b/tools/testing/selftests/liveupdate/lib/include/libliveupdate.h
@@ -7,13 +7,13 @@
* Utility functions for LUO kselftests.
*/
-#ifndef LUO_TEST_UTILS_H
-#define LUO_TEST_UTILS_H
+#ifndef SELFTESTS_LIVEUPDATE_LIB_LIVEUPDATE_H
+#define SELFTESTS_LIVEUPDATE_LIB_LIVEUPDATE_H
#include <errno.h>
#include <string.h>
#include <linux/liveupdate.h>
-#include "../kselftest.h"
+#include "../../../kselftest.h"
#define LUO_DEVICE "/dev/liveupdate"
@@ -41,4 +41,4 @@ typedef void (*luo_test_stage2_fn)(int luo_fd, int state_session_fd);
int luo_test(int argc, char *argv[], const char *state_session_name,
luo_test_stage1_fn stage1, luo_test_stage2_fn stage2);
-#endif /* LUO_TEST_UTILS_H */
+#endif /* SELFTESTS_LIVEUPDATE_LIB_LIVEUPDATE_H */
diff --git a/tools/testing/selftests/liveupdate/lib/libliveupdate.mk b/tools/testing/selftests/liveupdate/lib/libliveupdate.mk
new file mode 100644
index 000000000000..fffd95b085b6
--- /dev/null
+++ b/tools/testing/selftests/liveupdate/lib/libliveupdate.mk
@@ -0,0 +1,20 @@
+include $(top_srcdir)/scripts/subarch.include
+ARCH ?= $(SUBARCH)
+
+LIBLIVEUPDATE_SRCDIR := $(selfdir)/liveupdate/lib
+
+LIBLIVEUPDATE_C := liveupdate.c
+
+LIBLIVEUPDATE_OUTPUT := $(OUTPUT)/libliveupdate
+
+LIBLIVEUPDATE_O := $(patsubst %.c, $(LIBLIVEUPDATE_OUTPUT)/%.o, $(LIBLIVEUPDATE_C))
+
+LIBLIVEUPDATE_O_DIRS := $(shell dirname $(LIBLIVEUPDATE_O) | uniq)
+$(shell mkdir -p $(LIBLIVEUPDATE_O_DIRS))
+
+CFLAGS += -I$(LIBLIVEUPDATE_SRCDIR)/include
+
+$(LIBLIVEUPDATE_O): $(LIBLIVEUPDATE_OUTPUT)/%.o : $(LIBLIVEUPDATE_SRCDIR)/%.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
+
+EXTRA_CLEAN += $(LIBLIVEUPDATE_OUTPUT)
diff --git a/tools/testing/selftests/liveupdate/luo_test_utils.c b/tools/testing/selftests/liveupdate/lib/liveupdate.c
similarity index 99%
rename from tools/testing/selftests/liveupdate/luo_test_utils.c
rename to tools/testing/selftests/liveupdate/lib/liveupdate.c
index 3c8721c505df..60121873f685 100644
--- a/tools/testing/selftests/liveupdate/luo_test_utils.c
+++ b/tools/testing/selftests/liveupdate/lib/liveupdate.c
@@ -21,7 +21,7 @@
#include <errno.h>
#include <stdarg.h>
-#include "luo_test_utils.h"
+#include <libliveupdate.h>
int luo_open_device(void)
{
diff --git a/tools/testing/selftests/liveupdate/luo_kexec_simple.c b/tools/testing/selftests/liveupdate/luo_kexec_simple.c
index d7ac1f3dc4cb..786ac93b9ae3 100644
--- a/tools/testing/selftests/liveupdate/luo_kexec_simple.c
+++ b/tools/testing/selftests/liveupdate/luo_kexec_simple.c
@@ -8,7 +8,7 @@
* across a single kexec reboot.
*/
-#include "luo_test_utils.h"
+#include <libliveupdate.h>
#define TEST_SESSION_NAME "test-session"
#define TEST_MEMFD_TOKEN 0x1A
diff --git a/tools/testing/selftests/liveupdate/luo_multi_session.c b/tools/testing/selftests/liveupdate/luo_multi_session.c
index 0ee2d795beef..aac24a5f5ce3 100644
--- a/tools/testing/selftests/liveupdate/luo_multi_session.c
+++ b/tools/testing/selftests/liveupdate/luo_multi_session.c
@@ -9,7 +9,7 @@
* files.
*/
-#include "luo_test_utils.h"
+#include <libliveupdate.h>
#define SESSION_EMPTY_1 "multi-test-empty-1"
#define SESSION_EMPTY_2 "multi-test-empty-2"
--
2.53.0.983.g0bb29b3bc5-goog
^ permalink raw reply related
* [PATCH v3 15/24] selftests/liveupdate: Add helpers to preserve/retrieve FDs
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>
Add helper functions to preserve and retrieve file descriptors from an
LUO session. These will be used be used in subsequent commits to
preserve FDs other than memfd.
No functional change intended.
Signed-off-by: Vipin Sharma <vipinsh@google.com>
Co-developed-by: David Matlack <dmatlack@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
.../liveupdate/lib/include/libliveupdate.h | 3 ++
.../selftests/liveupdate/lib/liveupdate.c | 41 +++++++++++++++----
2 files changed, 35 insertions(+), 9 deletions(-)
diff --git a/tools/testing/selftests/liveupdate/lib/include/libliveupdate.h b/tools/testing/selftests/liveupdate/lib/include/libliveupdate.h
index 4390a2737930..2b04b3256382 100644
--- a/tools/testing/selftests/liveupdate/lib/include/libliveupdate.h
+++ b/tools/testing/selftests/liveupdate/lib/include/libliveupdate.h
@@ -26,6 +26,9 @@ int luo_create_session(int luo_fd, const char *name);
int luo_retrieve_session(int luo_fd, const char *name);
int luo_session_finish(int session_fd);
+int luo_session_preserve_fd(int session_fd, int fd, __u64 token);
+int luo_session_retrieve_fd(int session_fd, __u64 token);
+
int create_and_preserve_memfd(int session_fd, int token, const char *data);
int restore_and_verify_memfd(int session_fd, int token, const char *expected_data);
diff --git a/tools/testing/selftests/liveupdate/lib/liveupdate.c b/tools/testing/selftests/liveupdate/lib/liveupdate.c
index 60121873f685..3e070975a3ec 100644
--- a/tools/testing/selftests/liveupdate/lib/liveupdate.c
+++ b/tools/testing/selftests/liveupdate/lib/liveupdate.c
@@ -54,9 +54,35 @@ int luo_retrieve_session(int luo_fd, const char *name)
return arg.fd;
}
+int luo_session_preserve_fd(int session_fd, int fd, __u64 token)
+{
+ struct liveupdate_session_preserve_fd arg = {
+ .size = sizeof(arg),
+ .fd = fd,
+ .token = token,
+ };
+
+ if (ioctl(session_fd, LIVEUPDATE_SESSION_PRESERVE_FD, &arg))
+ return -errno;
+
+ return 0;
+}
+
+int luo_session_retrieve_fd(int session_fd, __u64 token)
+{
+ struct liveupdate_session_retrieve_fd arg = {
+ .size = sizeof(arg),
+ .token = token,
+ };
+
+ if (ioctl(session_fd, LIVEUPDATE_SESSION_RETRIEVE_FD, &arg))
+ return -errno;
+
+ return arg.fd;
+}
+
int create_and_preserve_memfd(int session_fd, int token, const char *data)
{
- struct liveupdate_session_preserve_fd arg = { .size = sizeof(arg) };
long page_size = sysconf(_SC_PAGE_SIZE);
void *map = MAP_FAILED;
int mfd = -1, ret = -1;
@@ -75,9 +101,8 @@ int create_and_preserve_memfd(int session_fd, int token, const char *data)
snprintf(map, page_size, "%s", data);
munmap(map, page_size);
- arg.fd = mfd;
- arg.token = token;
- if (ioctl(session_fd, LIVEUPDATE_SESSION_PRESERVE_FD, &arg) < 0)
+ ret = luo_session_preserve_fd(session_fd, mfd, token);
+ if (ret)
goto out;
ret = 0;
@@ -92,15 +117,13 @@ int create_and_preserve_memfd(int session_fd, int token, const char *data)
int restore_and_verify_memfd(int session_fd, int token,
const char *expected_data)
{
- struct liveupdate_session_retrieve_fd arg = { .size = sizeof(arg) };
long page_size = sysconf(_SC_PAGE_SIZE);
void *map = MAP_FAILED;
int mfd = -1, ret = -1;
- arg.token = token;
- if (ioctl(session_fd, LIVEUPDATE_SESSION_RETRIEVE_FD, &arg) < 0)
- return -errno;
- mfd = arg.fd;
+ mfd = luo_session_retrieve_fd(session_fd, token);
+ if (mfd < 0)
+ return mfd;
map = mmap(NULL, page_size, PROT_READ, MAP_SHARED, mfd, 0);
if (map == MAP_FAILED)
--
2.53.0.983.g0bb29b3bc5-goog
^ permalink raw reply related
* [PATCH v3 16/24] vfio: selftests: Build liveupdate library in VFIO selftests
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>
Import and build liveupdate selftest library in VFIO selftests.
It allows to use liveupdate ioctls in VFIO selftests
Signed-off-by: Vipin Sharma <vipinsh@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
tools/testing/selftests/vfio/Makefile | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile
index 8e90e409e91d..7f3c94da289d 100644
--- a/tools/testing/selftests/vfio/Makefile
+++ b/tools/testing/selftests/vfio/Makefile
@@ -20,6 +20,7 @@ TEST_FILES += scripts/setup.sh
include ../lib.mk
include lib/libvfio.mk
+include ../liveupdate/lib/libliveupdate.mk
CFLAGS += -I$(top_srcdir)/tools/include
CFLAGS += -MD
@@ -27,11 +28,15 @@ CFLAGS += $(EXTRA_CFLAGS)
LDFLAGS += -pthread
-$(TEST_GEN_PROGS): %: %.o $(LIBVFIO_O)
- $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $< $(LIBVFIO_O) $(LDLIBS) -o $@
+LIBS_O := $(LIBVFIO_O)
+LIBS_O += $(LIBLIVEUPDATE_O)
+
+$(TEST_GEN_PROGS): %: %.o $(LIBS_O)
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $< $(LIBS_O) $(LDLIBS) -o $@
TEST_GEN_PROGS_O = $(patsubst %, %.o, $(TEST_GEN_PROGS))
-TEST_DEP_FILES = $(patsubst %.o, %.d, $(TEST_GEN_PROGS_O) $(LIBVFIO_O))
+TEST_DEP_FILES := $(patsubst %.o, %.d, $(TEST_GEN_PROGS_O))
+TEST_DEP_FILES += $(patsubst %.o, %.d, $(LIBS_O))
-include $(TEST_DEP_FILES)
EXTRA_CLEAN += $(TEST_GEN_PROGS_O) $(TEST_DEP_FILES)
--
2.53.0.983.g0bb29b3bc5-goog
^ permalink raw reply related
* [PATCH v3 17/24] vfio: selftests: Add Makefile support for TEST_GEN_PROGS_EXTENDED
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>
Add Makefile support for TEST_GEN_PROGS_EXTENDED targets. These tests
are not run by default.
TEST_GEN_PROGS_EXTENDED will be used for Live Update selftests in
subsequent commits. These selftests must be run manually because they
require the user/runner to perform additional actions, such as kexec,
during the test.
Signed-off-by: David Matlack <dmatlack@google.com>
---
tools/testing/selftests/vfio/Makefile | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile
index 7f3c94da289d..9d5e390a61b7 100644
--- a/tools/testing/selftests/vfio/Makefile
+++ b/tools/testing/selftests/vfio/Makefile
@@ -31,14 +31,17 @@ LDFLAGS += -pthread
LIBS_O := $(LIBVFIO_O)
LIBS_O += $(LIBLIVEUPDATE_O)
-$(TEST_GEN_PROGS): %: %.o $(LIBS_O)
+$(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED): %: %.o $(LIBS_O)
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $< $(LIBS_O) $(LDLIBS) -o $@
-TEST_GEN_PROGS_O = $(patsubst %, %.o, $(TEST_GEN_PROGS))
-TEST_DEP_FILES := $(patsubst %.o, %.d, $(TEST_GEN_PROGS_O))
+TESTS_O := $(patsubst %, %.o, $(TEST_GEN_PROGS))
+TESTS_O += $(patsubst %, %.o, $(TEST_GEN_PROGS_EXTENDED))
+
+TEST_DEP_FILES := $(patsubst %.o, %.d, $(TESTS_O))
TEST_DEP_FILES += $(patsubst %.o, %.d, $(LIBS_O))
-include $(TEST_DEP_FILES)
-EXTRA_CLEAN += $(TEST_GEN_PROGS_O) $(TEST_DEP_FILES)
+EXTRA_CLEAN += $(TESTS_O)
+EXTRA_CLEAN += $(TEST_DEP_FILES)
endif
--
2.53.0.983.g0bb29b3bc5-goog
^ permalink raw reply related
* [PATCH v3 18/24] vfio: selftests: Add vfio_pci_liveupdate_uapi_test
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>
Add a selftest to exercise preserving a various VFIO files through
/dev/liveupdate. Ensure that VFIO cdev device files can be preserved and
everything else (group-based device files, group files, and container
files) all fail.
Signed-off-by: David Matlack <dmatlack@google.com>
---
tools/testing/selftests/vfio/Makefile | 1 +
.../vfio/vfio_pci_liveupdate_uapi_test.c | 93 +++++++++++++++++++
2 files changed, 94 insertions(+)
create mode 100644 tools/testing/selftests/vfio/vfio_pci_liveupdate_uapi_test.c
diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile
index 9d5e390a61b7..5b6e79593555 100644
--- a/tools/testing/selftests/vfio/Makefile
+++ b/tools/testing/selftests/vfio/Makefile
@@ -12,6 +12,7 @@ TEST_GEN_PROGS += vfio_iommufd_setup_test
TEST_GEN_PROGS += vfio_pci_device_test
TEST_GEN_PROGS += vfio_pci_device_init_perf_test
TEST_GEN_PROGS += vfio_pci_driver_test
+TEST_GEN_PROGS += vfio_pci_liveupdate_uapi_test
TEST_FILES += scripts/cleanup.sh
TEST_FILES += scripts/lib.sh
diff --git a/tools/testing/selftests/vfio/vfio_pci_liveupdate_uapi_test.c b/tools/testing/selftests/vfio/vfio_pci_liveupdate_uapi_test.c
new file mode 100644
index 000000000000..1d89b08ab0a4
--- /dev/null
+++ b/tools/testing/selftests/vfio/vfio_pci_liveupdate_uapi_test.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <libliveupdate.h>
+#include <libvfio.h>
+#include <kselftest_harness.h>
+
+static const char *device_bdf;
+
+FIXTURE(vfio_pci_liveupdate_uapi_test) {
+ int luo_fd;
+ int session_fd;
+ struct iommu *iommu;
+ struct vfio_pci_device *device;
+};
+
+FIXTURE_VARIANT(vfio_pci_liveupdate_uapi_test) {
+ const char *iommu_mode;
+};
+
+#define FIXTURE_VARIANT_ADD_IOMMU_MODE(_iommu_mode) \
+FIXTURE_VARIANT_ADD(vfio_pci_liveupdate_uapi_test, _iommu_mode) { \
+ .iommu_mode = #_iommu_mode, \
+}
+
+FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES();
+#undef FIXTURE_VARIANT_ADD_IOMMU_MODE
+
+FIXTURE_SETUP(vfio_pci_liveupdate_uapi_test)
+{
+ self->luo_fd = luo_open_device();
+ ASSERT_GE(self->luo_fd, 0);
+
+ self->session_fd = luo_create_session(self->luo_fd, "session");
+ ASSERT_GE(self->session_fd, 0);
+
+ self->iommu = iommu_init(variant->iommu_mode);
+ self->device = vfio_pci_device_init(device_bdf, self->iommu);
+}
+
+FIXTURE_TEARDOWN(vfio_pci_liveupdate_uapi_test)
+{
+ vfio_pci_device_cleanup(self->device);
+ iommu_cleanup(self->iommu);
+ close(self->session_fd);
+ close(self->luo_fd);
+}
+
+TEST_F(vfio_pci_liveupdate_uapi_test, preserve_device)
+{
+ int ret;
+
+ ret = luo_session_preserve_fd(self->session_fd, self->device->fd, 0);
+
+ /* Preservation should only be supported for VFIO cdev files. */
+ ASSERT_EQ(ret, self->iommu->iommufd ? 0 : -ENOENT);
+}
+
+TEST_F(vfio_pci_liveupdate_uapi_test, preserve_group_fails)
+{
+ int ret;
+
+ if (self->iommu->iommufd)
+ SKIP(return, "iommufd-mode does not have group files");
+
+ ret = luo_session_preserve_fd(self->session_fd, self->device->group_fd, 0);
+ ASSERT_EQ(ret, -ENOENT);
+}
+
+TEST_F(vfio_pci_liveupdate_uapi_test, preserve_container_fails)
+{
+ int ret;
+
+ if (self->iommu->iommufd)
+ SKIP(return, "iommufd-mode does not have container files");
+
+ ret = luo_session_preserve_fd(self->session_fd, self->iommu->container_fd, 0);
+ ASSERT_EQ(ret, -ENOENT);
+}
+
+int main(int argc, char *argv[])
+{
+ int fd;
+
+ fd = luo_open_device();
+ if (fd < 0)
+ ksft_exit_skip("open(%s) failed: %s, skipping\n",
+ LUO_DEVICE, strerror(errno));
+
+ close(fd);
+
+ device_bdf = vfio_selftests_get_bdf(&argc, argv);
+ return test_harness_run(argc, argv);
+}
--
2.53.0.983.g0bb29b3bc5-goog
^ permalink raw reply related
* [PATCH v3 19/24] vfio: selftests: Initialize vfio_pci_device using a VFIO cdev FD
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>
Use the given VFIO cdev FD to initialize vfio_pci_device in VFIO
selftests. Add the assertion to make sure that passed cdev FD is not
used with legacy VFIO APIs. If VFIO cdev FD is provided then do not open
the device instead use the FD for any interaction with the device.
This API will allow to write selftests where VFIO device FD is preserved
using liveupdate and retrieved later using liveupdate ioctl after kexec.
Signed-off-by: Vipin Sharma <vipinsh@google.com>
Co-developed-by: David Matlack <dmatlack@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
.../lib/include/libvfio/vfio_pci_device.h | 3 ++
.../selftests/vfio/lib/vfio_pci_device.c | 33 ++++++++++++++-----
2 files changed, 27 insertions(+), 9 deletions(-)
diff --git a/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
index 2858885a89bb..896dfde88118 100644
--- a/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
+++ b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
@@ -38,6 +38,9 @@ struct vfio_pci_device {
#define dev_info(_dev, _fmt, ...) printf("%s: " _fmt, (_dev)->bdf, ##__VA_ARGS__)
#define dev_err(_dev, _fmt, ...) fprintf(stderr, "%s: " _fmt, (_dev)->bdf, ##__VA_ARGS__)
+struct vfio_pci_device *__vfio_pci_device_init(const char *bdf,
+ struct iommu *iommu,
+ int device_fd);
struct vfio_pci_device *vfio_pci_device_init(const char *bdf, struct iommu *iommu);
void vfio_pci_device_cleanup(struct vfio_pci_device *device);
diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
index 4e5871f1ebc3..e9215c712cda 100644
--- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c
+++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
@@ -340,19 +340,27 @@ static void vfio_device_attach_iommufd_pt(int device_fd, u32 pt_id)
ioctl_assert(device_fd, VFIO_DEVICE_ATTACH_IOMMUFD_PT, &args);
}
-static void vfio_pci_iommufd_setup(struct vfio_pci_device *device, const char *bdf)
+static void vfio_pci_iommufd_setup(struct vfio_pci_device *device,
+ const char *bdf, int device_fd)
{
- const char *cdev_path = vfio_pci_get_cdev_path(bdf);
+ const char *cdev_path;
- device->fd = open(cdev_path, O_RDWR);
- VFIO_ASSERT_GE(device->fd, 0);
- free((void *)cdev_path);
+ if (device_fd >= 0) {
+ device->fd = device_fd;
+ } else {
+ cdev_path = vfio_pci_get_cdev_path(bdf);
+ device->fd = open(cdev_path, O_RDWR);
+ VFIO_ASSERT_GE(device->fd, 0);
+ free((void *)cdev_path);
+ }
vfio_device_bind_iommufd(device->fd, device->iommu->iommufd);
vfio_device_attach_iommufd_pt(device->fd, device->iommu->ioas_id);
}
-struct vfio_pci_device *vfio_pci_device_init(const char *bdf, struct iommu *iommu)
+struct vfio_pci_device *__vfio_pci_device_init(const char *bdf,
+ struct iommu *iommu,
+ int device_fd)
{
struct vfio_pci_device *device;
@@ -363,10 +371,12 @@ struct vfio_pci_device *vfio_pci_device_init(const char *bdf, struct iommu *iomm
device->iommu = iommu;
device->bdf = bdf;
- if (iommu->mode->container_path)
+ if (iommu->mode->container_path) {
+ VFIO_ASSERT_EQ(device_fd, -1);
vfio_pci_container_setup(device, bdf);
- else
- vfio_pci_iommufd_setup(device, bdf);
+ } else {
+ vfio_pci_iommufd_setup(device, bdf, device_fd);
+ }
vfio_pci_device_setup(device);
vfio_pci_driver_probe(device);
@@ -374,6 +384,11 @@ struct vfio_pci_device *vfio_pci_device_init(const char *bdf, struct iommu *iomm
return device;
}
+struct vfio_pci_device *vfio_pci_device_init(const char *bdf, struct iommu *iommu)
+{
+ return __vfio_pci_device_init(bdf, iommu, /*device_fd=*/-1);
+}
+
void vfio_pci_device_cleanup(struct vfio_pci_device *device)
{
int i;
--
2.53.0.983.g0bb29b3bc5-goog
^ permalink raw reply related
* [PATCH v3 20/24] vfio: selftests: Add vfio_pci_liveupdate_kexec_test
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>
Add a selftest to exercise preserving a vfio-pci device across a Live
Update. For now the test is extremely simple and just verifies that the
device file can be preserved and retrieved. In the future this test will
be extended to verify more parts about device preservation as they are
implemented.
This test is added to TEST_GEN_PROGS_EXTENDED since it must be run
manually along with a kexec.
To run this test manually:
$ tools/testing/selftests/vfio/scripts/setup.sh 0000:00:04.0
$ tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test --stage 1 0000:00:04.0
$ kexec ... # NOTE: Exact method will be distro-dependent
$ tools/testing/selftests/vfio/scripts/setup.sh 0000:00:04.0
$ tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test --stage 2 0000:00:04.0
The second call to setup.sh is necessary because preserved devices are
not bound to a driver after Live Update. Such devices must be manually
bound by userspace after Live Update via driver_override.
This test is considered passing if all commands exit with 0.
Signed-off-by: Vipin Sharma <vipinsh@google.com>
Co-developed-by: David Matlack <dmatlack@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
tools/testing/selftests/vfio/Makefile | 4 +
.../vfio/vfio_pci_liveupdate_kexec_test.c | 89 +++++++++++++++++++
2 files changed, 93 insertions(+)
create mode 100644 tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c
diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile
index 5b6e79593555..792c4245d4f7 100644
--- a/tools/testing/selftests/vfio/Makefile
+++ b/tools/testing/selftests/vfio/Makefile
@@ -14,6 +14,10 @@ TEST_GEN_PROGS += vfio_pci_device_init_perf_test
TEST_GEN_PROGS += vfio_pci_driver_test
TEST_GEN_PROGS += vfio_pci_liveupdate_uapi_test
+# This test must be run manually since it requires the user/automation to
+# perform a kexec during the test.
+TEST_GEN_PROGS_EXTENDED += vfio_pci_liveupdate_kexec_test
+
TEST_FILES += scripts/cleanup.sh
TEST_FILES += scripts/lib.sh
TEST_FILES += scripts/run.sh
diff --git a/tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c b/tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c
new file mode 100644
index 000000000000..15b3e3af91d1
--- /dev/null
+++ b/tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <libliveupdate.h>
+#include <libvfio.h>
+
+static const char *device_bdf;
+
+static char state_session[LIVEUPDATE_SESSION_NAME_LENGTH];
+static char device_session[LIVEUPDATE_SESSION_NAME_LENGTH];
+
+enum {
+ STATE_TOKEN,
+ DEVICE_TOKEN,
+};
+
+static void before_kexec(int luo_fd)
+{
+ struct vfio_pci_device *device;
+ struct iommu *iommu;
+ int session_fd;
+ int ret;
+
+ iommu = iommu_init("iommufd");
+ device = vfio_pci_device_init(device_bdf, iommu);
+
+ create_state_file(luo_fd, state_session, STATE_TOKEN, /*next_stage=*/2);
+
+ session_fd = luo_create_session(luo_fd, device_session);
+ VFIO_ASSERT_GE(session_fd, 0);
+
+ printf("Preserving device in session\n");
+ ret = luo_session_preserve_fd(session_fd, device->fd, DEVICE_TOKEN);
+ VFIO_ASSERT_EQ(ret, 0);
+
+ close(luo_fd);
+ daemonize_and_wait();
+}
+
+static void after_kexec(int luo_fd, int state_session_fd)
+{
+ struct vfio_pci_device *device;
+ struct iommu *iommu;
+ int session_fd;
+ int device_fd;
+ int stage;
+
+ restore_and_read_stage(state_session_fd, STATE_TOKEN, &stage);
+ VFIO_ASSERT_EQ(stage, 2);
+
+ session_fd = luo_retrieve_session(luo_fd, device_session);
+ VFIO_ASSERT_GE(session_fd, 0);
+
+ printf("Finishing the session before retrieving the device (should fail)\n");
+ VFIO_ASSERT_NE(luo_session_finish(session_fd), 0);
+
+ printf("Retrieving the device FD from LUO\n");
+ device_fd = luo_session_retrieve_fd(session_fd, DEVICE_TOKEN);
+ VFIO_ASSERT_GE(device_fd, 0);
+
+ printf("Finishing the session before binding to iommufd (should fail)\n");
+ VFIO_ASSERT_NE(luo_session_finish(session_fd), 0);
+
+ printf("Binding the device to an iommufd and setting it up\n");
+ iommu = iommu_init("iommufd");
+
+ /*
+ * This will invoke various ioctls on device_fd such as
+ * VFIO_DEVICE_GET_INFO. So this is a decent sanity test
+ * that LUO actually handed us back a valid VFIO device
+ * file and not something else.
+ */
+ device = __vfio_pci_device_init(device_bdf, iommu, device_fd);
+
+ printf("Finishing the session\n");
+ VFIO_ASSERT_EQ(luo_session_finish(session_fd), 0);
+
+ vfio_pci_device_cleanup(device);
+ iommu_cleanup(iommu);
+}
+
+int main(int argc, char *argv[])
+{
+ device_bdf = vfio_selftests_get_bdf(&argc, argv);
+
+ sprintf(device_session, "device-%s", device_bdf);
+ sprintf(state_session, "state-%s", device_bdf);
+
+ return luo_test(argc, argv, state_session, before_kexec, after_kexec);
+}
--
2.53.0.983.g0bb29b3bc5-goog
^ permalink raw reply related
* [PATCH v3 21/24] vfio: selftests: Expose iommu_modes to tests
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>
Expose the list of iommu_modes to enable tests that want to iterate
through all possible iommu modes.
Signed-off-by: David Matlack <dmatlack@google.com>
---
tools/testing/selftests/vfio/lib/include/libvfio/iommu.h | 2 ++
tools/testing/selftests/vfio/lib/iommu.c | 4 +++-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h b/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
index e9a3386a4719..4b9cbe262159 100644
--- a/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
+++ b/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
@@ -15,6 +15,8 @@ struct iommu_mode {
unsigned long iommu_type;
};
+extern const struct iommu_mode iommu_modes[];
+extern const int nr_iommu_modes;
extern const char *default_iommu_mode;
struct dma_region {
diff --git a/tools/testing/selftests/vfio/lib/iommu.c b/tools/testing/selftests/vfio/lib/iommu.c
index 035dac069d60..95a494f829d2 100644
--- a/tools/testing/selftests/vfio/lib/iommu.c
+++ b/tools/testing/selftests/vfio/lib/iommu.c
@@ -23,7 +23,7 @@
const char *default_iommu_mode = MODE_IOMMUFD;
/* Reminder: Keep in sync with FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(). */
-static const struct iommu_mode iommu_modes[] = {
+const struct iommu_mode iommu_modes[] = {
{
.name = MODE_VFIO_TYPE1_IOMMU,
.container_path = "/dev/vfio/vfio",
@@ -49,6 +49,8 @@ static const struct iommu_mode iommu_modes[] = {
},
};
+const int nr_iommu_modes = ARRAY_SIZE(iommu_modes);
+
static const struct iommu_mode *lookup_iommu_mode(const char *iommu_mode)
{
int i;
--
2.53.0.983.g0bb29b3bc5-goog
^ permalink raw reply related
* [PATCH v3 22/24] vfio: selftests: Expose low-level helper routines for setting up struct vfio_pci_device
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>
Expose a few low-level helper routings for setting up vfio_pci_device
structs. These routines will be used in a subsequent commit to assert
that VFIO_GROUP_GET_DEVICE_FD fails under certain conditions.
Signed-off-by: David Matlack <dmatlack@google.com>
---
.../lib/include/libvfio/vfio_pci_device.h | 5 +++
.../selftests/vfio/lib/vfio_pci_device.c | 33 +++++++++++++------
2 files changed, 28 insertions(+), 10 deletions(-)
diff --git a/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
index 896dfde88118..2389c7698335 100644
--- a/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
+++ b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
@@ -125,4 +125,9 @@ static inline bool vfio_pci_device_match(struct vfio_pci_device *device,
const char *vfio_pci_get_cdev_path(const char *bdf);
+/* Low-level routines for setting up a struct vfio_pci_device */
+struct vfio_pci_device *vfio_pci_device_alloc(const char *bdf, struct iommu *iommu);
+void vfio_pci_group_setup(struct vfio_pci_device *device);
+void vfio_pci_iommu_setup(struct vfio_pci_device *device);
+
#endif /* SELFTESTS_VFIO_LIB_INCLUDE_LIBVFIO_VFIO_PCI_DEVICE_H */
diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
index e9215c712cda..66ee268110e2 100644
--- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c
+++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
@@ -220,7 +220,7 @@ static unsigned int vfio_pci_get_group_from_dev(const char *bdf)
return group;
}
-static void vfio_pci_group_setup(struct vfio_pci_device *device, const char *bdf)
+void vfio_pci_group_setup(struct vfio_pci_device *device)
{
struct vfio_group_status group_status = {
.argsz = sizeof(group_status),
@@ -228,7 +228,7 @@ static void vfio_pci_group_setup(struct vfio_pci_device *device, const char *bdf
char group_path[32];
int group;
- group = vfio_pci_get_group_from_dev(bdf);
+ group = vfio_pci_get_group_from_dev(device->bdf);
snprintf(group_path, sizeof(group_path), "/dev/vfio/%d", group);
device->group_fd = open(group_path, O_RDWR);
@@ -240,14 +240,12 @@ static void vfio_pci_group_setup(struct vfio_pci_device *device, const char *bdf
ioctl_assert(device->group_fd, VFIO_GROUP_SET_CONTAINER, &device->iommu->container_fd);
}
-static void vfio_pci_container_setup(struct vfio_pci_device *device, const char *bdf)
+void vfio_pci_iommu_setup(struct vfio_pci_device *device)
{
struct iommu *iommu = device->iommu;
unsigned long iommu_type = iommu->mode->iommu_type;
int ret;
- vfio_pci_group_setup(device, bdf);
-
ret = ioctl(iommu->container_fd, VFIO_CHECK_EXTENSION, iommu_type);
VFIO_ASSERT_GT(ret, 0, "VFIO IOMMU type %lu not supported\n", iommu_type);
@@ -257,8 +255,14 @@ static void vfio_pci_container_setup(struct vfio_pci_device *device, const char
* because the IOMMU type is already set.
*/
(void)ioctl(iommu->container_fd, VFIO_SET_IOMMU, (void *)iommu_type);
+}
- device->fd = ioctl(device->group_fd, VFIO_GROUP_GET_DEVICE_FD, bdf);
+static void vfio_pci_container_setup(struct vfio_pci_device *device)
+{
+ vfio_pci_group_setup(device);
+ vfio_pci_iommu_setup(device);
+
+ device->fd = ioctl(device->group_fd, VFIO_GROUP_GET_DEVICE_FD, device->bdf);
VFIO_ASSERT_GE(device->fd, 0);
}
@@ -358,9 +362,7 @@ static void vfio_pci_iommufd_setup(struct vfio_pci_device *device,
vfio_device_attach_iommufd_pt(device->fd, device->iommu->ioas_id);
}
-struct vfio_pci_device *__vfio_pci_device_init(const char *bdf,
- struct iommu *iommu,
- int device_fd)
+struct vfio_pci_device *vfio_pci_device_alloc(const char *bdf, struct iommu *iommu)
{
struct vfio_pci_device *device;
@@ -371,9 +373,20 @@ struct vfio_pci_device *__vfio_pci_device_init(const char *bdf,
device->iommu = iommu;
device->bdf = bdf;
+ return device;
+}
+
+struct vfio_pci_device *__vfio_pci_device_init(const char *bdf,
+ struct iommu *iommu,
+ int device_fd)
+{
+ struct vfio_pci_device *device;
+
+ device = vfio_pci_device_alloc(bdf, iommu);
+
if (iommu->mode->container_path) {
VFIO_ASSERT_EQ(device_fd, -1);
- vfio_pci_container_setup(device, bdf);
+ vfio_pci_container_setup(device);
} else {
vfio_pci_iommufd_setup(device, bdf, device_fd);
}
--
2.53.0.983.g0bb29b3bc5-goog
^ permalink raw reply related
* [PATCH v3 23/24] vfio: selftests: Verify that opening VFIO device fails during 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>
Verify that opening a VFIO device through its cdev file and via
VFIO_GROUP_GET_DEVICE_FD both fail with -EBUSY if the device was
preserved across a Live Update. When a device file is preserve across a
Live Update, the file must be retrieved from /dev/liveupdate, not from
VFIO directly.
Signed-off-by: David Matlack <dmatlack@google.com>
---
.../vfio/vfio_pci_liveupdate_kexec_test.c | 38 +++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c b/tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c
index 15b3e3af91d1..65c48196e44e 100644
--- a/tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c
+++ b/tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c
@@ -36,6 +36,42 @@ static void before_kexec(int luo_fd)
daemonize_and_wait();
}
+static void check_open_vfio_device_fails(void)
+{
+ const char *cdev_path = vfio_pci_get_cdev_path(device_bdf);
+ struct vfio_pci_device *device;
+ struct iommu *iommu;
+ int ret, i;
+
+ printf("Checking open(%s) fails\n", cdev_path);
+ ret = open(cdev_path, O_RDWR);
+ VFIO_ASSERT_EQ(ret, -1);
+ VFIO_ASSERT_EQ(errno, EBUSY);
+ free((void *)cdev_path);
+
+ for (i = 0; i < nr_iommu_modes; i++) {
+ if (!iommu_modes[i].container_path)
+ continue;
+
+ iommu = iommu_init(iommu_modes[i].name);
+
+ device = vfio_pci_device_alloc(device_bdf, iommu);
+ vfio_pci_group_setup(device);
+ vfio_pci_iommu_setup(device);
+
+ printf("Checking ioctl(group_fd, VFIO_GROUP_GET_DEVICE_FD, \"%s\") fails (%s)\n",
+ device_bdf, iommu_modes[i].name);
+
+ ret = ioctl(device->group_fd, VFIO_GROUP_GET_DEVICE_FD, device->bdf);
+ VFIO_ASSERT_EQ(ret, -1);
+ VFIO_ASSERT_EQ(errno, EBUSY);
+
+ close(device->group_fd);
+ free(device);
+ iommu_cleanup(iommu);
+ }
+}
+
static void after_kexec(int luo_fd, int state_session_fd)
{
struct vfio_pci_device *device;
@@ -44,6 +80,8 @@ static void after_kexec(int luo_fd, int state_session_fd)
int device_fd;
int stage;
+ check_open_vfio_device_fails();
+
restore_and_read_stage(state_session_fd, STATE_TOKEN, &stage);
VFIO_ASSERT_EQ(stage, 2);
--
2.53.0.983.g0bb29b3bc5-goog
^ permalink raw reply related
* [PATCH v3 24/24] vfio: selftests: Add continuous DMA to vfio_pci_liveupdate_kexec_test
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>
Add a long-running DMA memcpy operation to
vfio_pci_liveupdate_kexec_test so that the device attempts to perform
DMAs continuously during the Live Update.
At this point iommufd preservation is not supported and bus mastering is
not kept enabled on the device during across the kexec, so most of these
DMAs will be dropped. However this test ensures that the current device
preservation support does not lead to system instability or crashes if
the device is active. And once iommufd and bus mastering are preserved,
this test can be relaxed to check that the DMA operations completed
successfully.
Signed-off-by: David Matlack <dmatlack@google.com>
---
.../vfio/vfio_pci_liveupdate_kexec_test.c | 129 ++++++++++++++++++
1 file changed, 129 insertions(+)
diff --git a/tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c b/tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c
index 65c48196e44e..36bddfbb88ed 100644
--- a/tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c
+++ b/tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c
@@ -1,8 +1,16 @@
// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/sizes.h>
+#include <sys/mman.h>
+
#include <libliveupdate.h>
#include <libvfio.h>
+#define MEMCPY_SIZE SZ_1G
+#define DRIVER_SIZE SZ_1M
+#define MEMFD_SIZE (MEMCPY_SIZE + DRIVER_SIZE)
+
+static struct dma_region memcpy_region;
static const char *device_bdf;
static char state_session[LIVEUPDATE_SESSION_NAME_LENGTH];
@@ -11,8 +19,89 @@ static char device_session[LIVEUPDATE_SESSION_NAME_LENGTH];
enum {
STATE_TOKEN,
DEVICE_TOKEN,
+ MEMFD_TOKEN,
};
+static void dma_memcpy_one(struct vfio_pci_device *device)
+{
+ void *src = memcpy_region.vaddr, *dst;
+ u64 size;
+
+ size = min_t(u64, memcpy_region.size / 2, device->driver.max_memcpy_size);
+ dst = src + size;
+
+ memset(src, 1, size);
+ memset(dst, 0, size);
+
+ printf("Kicking off 1 DMA memcpy operations of size 0x%lx...\n", size);
+ vfio_pci_driver_memcpy(device,
+ to_iova(device, src),
+ to_iova(device, dst),
+ size);
+
+ VFIO_ASSERT_EQ(memcmp(src, dst, size), 0);
+}
+
+static void dma_memcpy_start(struct vfio_pci_device *device)
+{
+ void *src = memcpy_region.vaddr, *dst;
+ u64 count, size;
+
+ size = min_t(u64, memcpy_region.size / 2, device->driver.max_memcpy_size);
+ dst = src + size;
+
+ /*
+ * Rough Math: If we assume the device will perform memcpy at a rate of
+ * 30GB/s then 7200GB of transfers will run for about 4 minutes.
+ */
+ count = (u64)7200 * SZ_1G / size;
+ count = min_t(u64, count, device->driver.max_memcpy_count);
+
+ memset(src, 1, size / 2);
+ memset(dst, 0, size / 2);
+
+ printf("Kicking off %lu DMA memcpy operations of size 0x%lx...\n", count, size);
+ vfio_pci_driver_memcpy_start(device,
+ to_iova(device, src),
+ to_iova(device, dst),
+ size, count);
+}
+
+static void dma_memfd_map(struct vfio_pci_device *device, int fd)
+{
+ void *vaddr;
+
+ vaddr = mmap(NULL, MEMFD_SIZE, PROT_WRITE, MAP_SHARED, fd, 0);
+ VFIO_ASSERT_NE(vaddr, MAP_FAILED);
+
+ memcpy_region.iova = SZ_4G;
+ memcpy_region.size = MEMCPY_SIZE;
+ memcpy_region.vaddr = vaddr;
+ iommu_map(device->iommu, &memcpy_region);
+
+ device->driver.region.iova = memcpy_region.iova + memcpy_region.size;
+ device->driver.region.size = DRIVER_SIZE;
+ device->driver.region.vaddr = vaddr + memcpy_region.size;
+ iommu_map(device->iommu, &device->driver.region);
+}
+
+static void dma_memfd_setup(struct vfio_pci_device *device, int session_fd)
+{
+ int fd, ret;
+
+ fd = memfd_create("dma-buffer", 0);
+ VFIO_ASSERT_GE(fd, 0);
+
+ ret = fallocate(fd, 0, 0, MEMFD_SIZE);
+ VFIO_ASSERT_EQ(ret, 0);
+
+ printf("Preserving memfd of size 0x%x in session\n", MEMFD_SIZE);
+ ret = luo_session_preserve_fd(session_fd, fd, MEMFD_TOKEN);
+ VFIO_ASSERT_EQ(ret, 0);
+
+ dma_memfd_map(device, fd);
+}
+
static void before_kexec(int luo_fd)
{
struct vfio_pci_device *device;
@@ -32,6 +121,27 @@ static void before_kexec(int luo_fd)
ret = luo_session_preserve_fd(session_fd, device->fd, DEVICE_TOKEN);
VFIO_ASSERT_EQ(ret, 0);
+ dma_memfd_setup(device, session_fd);
+
+ /*
+ * If the device has a selftests driver, kick off a long-running DMA
+ * operation to exercise the device trying to DMA during a Live Update.
+ * Since iommufd preservation is not supported yet, these DMAs should be
+ * dropped. So this is just looking to verify that the system does not
+ * fall over and crash as a result of a busy device being preserved.
+ */
+ if (device->driver.ops) {
+ vfio_pci_driver_init(device);
+ dma_memcpy_start(device);
+
+ /*
+ * Disable interrupts on the device or freeze() will fail.
+ * Unfortunately there isn't a way to easily have a test for
+ * that here since the check happens during shutdown.
+ */
+ vfio_pci_msix_disable(device);
+ }
+
close(luo_fd);
daemonize_and_wait();
}
@@ -78,6 +188,7 @@ static void after_kexec(int luo_fd, int state_session_fd)
struct iommu *iommu;
int session_fd;
int device_fd;
+ int memfd;
int stage;
check_open_vfio_device_fails();
@@ -88,6 +199,10 @@ static void after_kexec(int luo_fd, int state_session_fd)
session_fd = luo_retrieve_session(luo_fd, device_session);
VFIO_ASSERT_GE(session_fd, 0);
+ printf("Retrieving memfd from LUO\n");
+ memfd = luo_session_retrieve_fd(session_fd, MEMFD_TOKEN);
+ VFIO_ASSERT_GE(memfd, 0);
+
printf("Finishing the session before retrieving the device (should fail)\n");
VFIO_ASSERT_NE(luo_session_finish(session_fd), 0);
@@ -109,9 +224,23 @@ static void after_kexec(int luo_fd, int state_session_fd)
*/
device = __vfio_pci_device_init(device_bdf, iommu, device_fd);
+ dma_memfd_map(device, memfd);
+
printf("Finishing the session\n");
VFIO_ASSERT_EQ(luo_session_finish(session_fd), 0);
+ /*
+ * Once iommufd preservation is supported and the device is kept fully
+ * running across the Live Update, this should wait for the long-
+ * running DMA memcpy operation kicked off in before_kexec() to
+ * complete. But for now we expect the device to be reset so just
+ * trigger a single memcpy to make sure it's still functional.
+ */
+ if (device->driver.ops) {
+ vfio_pci_driver_init(device);
+ dma_memcpy_one(device);
+ }
+
vfio_pci_device_cleanup(device);
iommu_cleanup(iommu);
}
--
2.53.0.983.g0bb29b3bc5-goog
^ permalink raw reply related
* [netfilter-nf-next:testing 14/14] htmldocs: Documentation/networking/ipvs-sysctl.rst:40: WARNING: Block quote ends without a blank line; unexpected unindent. [docutils]
From: kernel test robot @ 2026-03-24 0:09 UTC (permalink / raw)
To: Julian Anastasov; +Cc: oe-kbuild-all, Florian Westphal, linux-doc
tree: https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next.git testing
head: 93cd433f9f3d3ef04f6c03a201f5d91ca2965dd9
commit: 93cd433f9f3d3ef04f6c03a201f5d91ca2965dd9 [14/14] ipvs: add conn_lfactor and svc_lfactor sysctl vars
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
docutils: docutils (Docutils 0.21.2, Python 3.13.5, on linux)
reproduce: (https://download.01.org/0day-ci/archive/20260324/202603240111.Z3ZKbxGg-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603240111.Z3ZKbxGg-lkp@intel.com/
All warnings (new ones prefixed by >>):
Non-Preserved Properties
======================== [docutils]
Documentation/networking/ipvs-sysctl.rst:39: ERROR: Unexpected indentation. [docutils]
>> Documentation/networking/ipvs-sysctl.rst:40: WARNING: Block quote ends without a blank line; unexpected unindent. [docutils]
Documentation/networking/skbuff:36: ./include/linux/skbuff.h:48: ERROR: Unexpected section title.
vim +40 Documentation/networking/ipvs-sysctl.rst
9
10 am_droprate - INTEGER
11 default 10
12
13 It sets the always mode drop rate, which is used in the mode 3
14 of the drop_rate defense.
15
16 amemthresh - INTEGER
17 default 1024
18
19 It sets the available memory threshold (in pages), which is
20 used in the automatic modes of defense. When there is no
21 enough available memory, the respective strategy will be
22 enabled and the variable is automatically set to 2, otherwise
23 the strategy is disabled and the variable is set to 1.
24
25 backup_only - BOOLEAN
26 - 0 - disabled (default)
27 - not 0 - enabled
28
29 If set, disable the director function while the server is
30 in backup mode to avoid packet loops for DR/TUN methods.
31
32 conn_lfactor - INTEGER
33 Possible values: -8 (larger table) .. 8 (smaller table)
34
35 Default: -4
36
37 Controls the sizing of the connection hash table based on the
38 load factor (number of connections per table buckets):
> 39 2^conn_lfactor = nodes / buckets
> 40 As result, the table grows if load increases and shrinks when
41 load decreases in the range of 2^8 - 2^conn_tab_bits (module
42 parameter).
43 The value is a shift count where negative values select
44 buckets = (connection hash nodes << -value) while positive
45 values select buckets = (connection hash nodes >> value). The
46 negative values reduce the collisions and reduce the time for
47 lookups but increase the table size. Positive values will
48 tolerate load above 100% when using smaller table is
49 preferred with the cost of more collisions. If using NAT
50 connections consider decreasing the value with one because
51 they add two nodes in the hash table.
52
53 Example:
54 -4: grow if load goes above 6% (buckets = nodes * 16)
55 2: grow if load goes above 400% (buckets = nodes / 4)
56
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: (sashiko review) [RFC PATCH v2 1/1] mm/damon: support MADV_COLLAPSE via DAMOS_COLLAPSE scheme action
From: SeongJae Park @ 2026-03-24 0:29 UTC (permalink / raw)
To: gutierrez.asier
Cc: SeongJae Park, artem.kuzin, stepanov.anatoly, wangkefeng.wang,
yanquanmin1, zuoze1, damon, akpm, ljs, Liam.Howlett, vbabka, rppt,
surenb, mhocko, corbet, skhan, linux-doc, linux-mm, linux-kernel
In-Reply-To: <20260323145646.4165053-2-gutierrez.asier@huawei-partners.com>
Forwarding Sashiko review for doing discussions via mails.
# review url: https://sashiko.dev/#/patchset/20260323145646.4165053-2-gutierrez.asier@huawei-partners.com
# start of sashiko.dev inline review
commit eaed291e6fae91842b1836c68bab867d53525db5
Author: Asier Gutierrez <gutierrez.asier@huawei-partners.com>
mm/damon: support MADV_COLLAPSE via DAMOS_COLLAPSE scheme action
This commit introduces a new DAMON action, DAMOS_COLLAPSE. It allows
DAMON to synchronously collapse an address range by calling madvise
with MADV_COLLAPSE.
Link: https://lore.kernel.org/damon/20260313000816.79933-1-sj@kernel.org/
[ ... ]
> diff --git a/tools/testing/selftests/damon/sysfs.py b/tools/testing/selftests/damon/sysfs.py
> index 3aa5c91548a5..c6476e63f4fb 100755
> --- a/tools/testing/selftests/damon/sysfs.py
> +++ b/tools/testing/selftests/damon/sysfs.py
> @@ -123,11 +123,12 @@ def assert_scheme_committed(scheme, dump):
> 'pageout': 2,
> 'hugepage': 3,
> 'nohugeapge': 4,
> - 'lru_prio': 5,
> - 'lru_deprio': 6,
> - 'migrate_hot': 7,
> - 'migrate_cold': 8,
> - 'stat': 9,
> + 'collapse': 5
> + 'lru_prio': 6,
Will this cause a Python syntax error when executing the selftest? It looks
like there is a missing comma after 'collapse': 5, which might break the
execution of the DAMON sysfs test suite.
# end of sashiko.dev inline review
# review url: https://sashiko.dev/#/patchset/20260323145646.4165053-2-gutierrez.asier@huawei-partners.com
#
# hkml [1] generated a draft of this mail. It can be regenerated
# using below command:
#
# hkml patch sashiko_dev --for_forwarding \
# 20260323145646.4165053-2-gutierrez.asier@huawei-partners.com
#
# [1] https://github.com/sjp38/hackermail
Sent using hkml (https://github.com/sjp38/hackermail)
^ permalink raw reply
* [PATCH BUNDLE v9] famfs: Fabric-Attached Memory File System
From: John Groves @ 2026-03-24 0:36 UTC (permalink / raw)
To: John Groves, Miklos Szeredi, Dan Williams, Bernd Schubert,
Alison Schofield
Cc: John Groves, Jonathan Corbet, Shuah Khan, Vishal Verma,
Dave Jiang, Matthew Wilcox, Jan Kara, Alexander Viro,
David Hildenbrand, Christian Brauner, Darrick J . Wong,
Randy Dunlap, Jeff Layton, Amir Goldstein, Jonathan Cameron,
Stefan Hajnoczi, Joanne Koong, Josef Bacik, Bagas Sanjaya,
Chen Linxuan, James Morse, Fuad Tabba, Sean Christopherson,
Shivank Garg, Ackerley Tng, Gregory Price, Aravind Ramesh,
Ajay Joshi, venkataravis@micron.com, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org, nvdimm@lists.linux.dev,
linux-cxl@vger.kernel.org, linux-fsdevel@vger.kernel.org
In-Reply-To: <20260324003630.4930-1-john@jagalactic.com>
This is a coordinated patch submission for famfs (Fabric-Attached Memory
File System) across three repositories:
1. Linux kernel dax (cover + 7 patches) - dax fsdev driver + fuse/famfs
integration
2. Linux kernel fs/fuse - famfs support into fuse. Depends on the dax
patches
NOTE: the fuse fuse package (second series) depends on the dax patches
(first series).
This bundle does not contain the user space libfuse and ndctl patches;
those will be sent separately to the respective projects.
Each series is posted as a reply to this cover message, with individual
patches replying to their respective series cover.
Overview
--------
Famfs exposes shared memory as a file system. It consumes shared memory
from dax devices and provides memory-mappable files that map directly to
the memory with no page cache involvement. Famfs differs from conventional
file systems in fs-dax mode in that it handles in-memory metadata in a
sharable way (which begins with never caching dirty shared metadata).
Famfs started as a standalone file system [1,2], but the consensus at
LSFMM 2024 and 2025 [3,4] was that it should be ported into fuse.
The key performance requirement is that famfs must resolve mapping faults
without upcalls. This is achieved by fully caching the file-to-devdax
metadata for all active files via two fuse client/server message/response
pairs: GET_FMAP and GET_DAXDEV.
Patch Series Summary
--------------------
Linux Kernel dax (V8, xx patches): New fsdev driver (drivers/dax/fsdev.c)
providing a devdax mode compatible with fs-dax. Devices can be switched
among 'devdax', 'fsdev' and 'system-ram' modes via daxctl or sysfs.
Linux kernel fuse (V8, xx patches: Famfs integration adding GET_FMAP and
GET_DAXDEV messages for caching file-to-dax mappings in the kernel.
Testing
-------
The famfs user space [5] includes comprehensive smoke and unit tests that
exercise all three components together. The ndctl series includes a
dedicated test for famfs mode transitions.
References
----------
[1] https://lore.kernel.org/linux-cxl/cover.1708709155.git.john@groves.net/
[2] https://lore.kernel.org/linux-cxl/cover.1714409084.git.john@groves.net/
[3] https://lwn.net/Articles/983105/ (LSFMM 2024)
[4] https://lwn.net/Articles/1020170/ (LSFMM 2025)
[5] https://famfs.org (famfs user space)
[6] https://lore.kernel.org/linux-cxl/20250703185032.46568-1-john@groves.net/ (V2)
[7] https://lore.kernel.org/linux-fsdevel/20260107153244.64703-1-john@groves.net/T/#m0000d8c00290f48c086b8b176c7525e410f8508c (related ndctl series)
--
John Groves
^ permalink raw reply
* [PATCH V9 0/8] dax: prepare for famfs
From: John Groves @ 2026-03-24 0:37 UTC (permalink / raw)
To: John Groves, Miklos Szeredi, Dan Williams, Bernd Schubert,
Alison Schofield
Cc: John Groves, Jonathan Corbet, Shuah Khan, Vishal Verma,
Dave Jiang, Matthew Wilcox, Jan Kara, Alexander Viro,
David Hildenbrand, Christian Brauner, Darrick J . Wong,
Randy Dunlap, Jeff Layton, Amir Goldstein, Jonathan Cameron,
Stefan Hajnoczi, Joanne Koong, Josef Bacik, Bagas Sanjaya,
Chen Linxuan, James Morse, Fuad Tabba, Sean Christopherson,
Shivank Garg, Ackerley Tng, Gregory Price, Aravind Ramesh,
Ajay Joshi, venkataravis@micron.com, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org, nvdimm@lists.linux.dev,
linux-cxl@vger.kernel.org, linux-fsdevel@vger.kernel.org,
John Groves
In-Reply-To: <0100019d1d45a702-37d7aa37-4b46-4c21-86db-bf9bd3d914bb-000000@email.amazonses.com>
From: John Groves <john@groves.net>
This patch series along with the bundled patches to fuse are available
as a git tag at [0].
Changes v8 -> v9
- Big clarifying comments in fs/dax.c:dax_folio_reset_order() in response
to Jonathan's comments/questions
- Added drivers/dax/Kconfig:CONFIG_DEV_DAX_FSDEV to control inclusion of the
new famfs dax mode (which is in drivers/dax/fsdev.c - bind that to a daxdev
and you have famfs mode)
- Some trivial refactoring, mostly per Jonathan's comments
Description:
This patch series introduces the required dax support for famfs.
Previous versions of the famfs series included both dax and fuse patches.
This series separates them into separate patch series' (and the fuse
series dependends on this dax series).
The famfs user space code can be found at [1]
Dax Overview:
This series introduces a new "famfs mode" of devdax, whose driver is
drivers/dax/fsdev.c. This driver supports dax_iomap_rw() and
dax_iomap_fault() calls against a character dax instance. A dax device
now can be converted among three modes: 'system-ram', 'devdax' and
'famfs' via daxctl or sysfs (e.g. unbind devdax and bind famfs instead).
In famfs mode, a dax device initializes its pages consistent with the
fsdaxmode of pmem. Raw read/write/mmap are not supported in this mode,
but famfs is happy in this mode - using dax_iomap_rw() for read/write and
dax_iomap_fault() for mmap faults.
Changes v7 -> v8
- dax: Added a devm action to clear folio state when unbinding fsdev.c
(thanks Allison)
- Added a missing device_lock() in fs_dax_get() (thanks Dave)
- Re-factored some __free blocks for inline declaration
- Used FIELD_PREP where appropriate
- Minor doc edits
Changes v6 -> v7
- Fixed a regression in famfs_interleave_fileofs_to_daxofs() that
was reported by Intel's kernel test robot
- Added a check in __fsdev_dax_direct_access() for negative return
from pgoff_to_phys(), which would indicate an out-of-range offset
- Fixed a bug in __famfs_meta_free(), where not all interleaved
extents were freed
- Added chunksize alignment checks in famfs_fuse_meta_alloc() and
famfs_interleave_fileofs_to_daxofs() as interleaved chunks must
be PTE or PMD aligned
- Simplified famfs_file_init_dax() a bit
- Re-ran CM's kernel code review prompts on the entire series and
fixed several minor issues
Changes v4 -> v5 -> v6
- None. Re-sending due to technical difficulties
Changes v3 [9] -> v4
- The patch "dax: prevent driver unbind while filesystem holds device"
has been dropped. Dan Williams indicated that the favored behavior is
for a file system to stop working if an underlying driver is unbound,
rather than preventing the unbind.
- The patch "famfs_fuse: Famfs mount opt: -o shadow=<shadowpath>" has
been dropped. Found a way for the famfs user space to do without the
-o opt (via getxattr).
- Squashed the fs/fuse/Kconfig patch into the first subsequent patch
that needed the change
("famfs_fuse: Basic fuse kernel ABI enablement for famfs")
- Many review comments addressed.
- Addressed minor kerneldoc infractions reported by test robot.
Changes v2 [7] -> v3
- Dax: Completely new fsdev driver (drivers/dax/fsdev.c) replaces the
dev_dax_iomap modifications to bus.c/device.c. Devdax devices can now
be switched among 'devdax', 'famfs' and 'system-ram' modes via daxctl
or sysfs.
- Dax: fsdev uses MEMORY_DEVICE_FS_DAX type and leaves folios at order-0
(no vmemmap_shift), allowing fs-dax to manage folio lifecycles
dynamically like pmem does.
- Dax: The "poisoned page" problem is properly fixed via
fsdev_clear_folio_state(), which clears stale mapping/compound state
when fsdev binds. The temporary WARN_ON_ONCE workaround in fs/dax.c
has been removed.
- Dax: Added dax_set_ops() so fsdev can set dax_operations at bind time
(and clear them on unbind), since the dax_device is created before we
know which driver will bind.
- Dax: Added custom bind/unbind sysfs handlers; unbind return -EBUSY if a
filesystem holds the device, preventing unbind while famfs is mounted.
- Fuse: Famfs mounts now require that the fuse server/daemon has
CAP_SYS_RAWIO because they expose raw memory devices.
- Fuse: Added DAX address_space_operations with noop_dirty_folio since
famfs is memory-backed with no writeback required.
- Rebased to latest kernels, fully compatible with Alistair Popple
et. al's recent dax refactoring.
- Ran this series through Chris Mason's code review AI prompts to check
for issues - several subtle problems found and fixed.
- Dropped RFC status - this version is intended to be mergeable.
Changes v1 [8] -> v2:
- The GET_FMAP message/response has been moved from LOOKUP to OPEN, as
was the pretty much unanimous consensus.
- Made the response payload to GET_FMAP variable sized (patch 12)
- Dodgy kerneldoc comments cleaned up or removed.
- Fixed memory leak of fc->shadow in patch 11 (thanks Joanne)
- Dropped many pr_debug and pr_notice calls
References
[0] - https://github.com/jagalactic/linux/tree/famfs-v9 (this patch set)
[1] - https://famfs.org (famfs user space)
[2] - https://lore.kernel.org/linux-cxl/cover.1708709155.git.john@groves.net/
[3] - https://lore.kernel.org/linux-cxl/cover.1714409084.git.john@groves.net/
[4] - https://lwn.net/Articles/983105/ (lsfmm 2024)
[5] - https://lwn.net/Articles/1020170/ (lsfmm 2025)
[6] - https://lore.kernel.org/linux-cxl/cover.8068ad144a7eea4a813670301f4d2a86a8e68ec4.1740713401.git-series.apopple@nvidia.com/
[7] - https://lore.kernel.org/linux-fsdevel/20250703185032.46568-1-john@groves.net/ (famfs fuse v2)
[8] - https://lore.kernel.org/linux-fsdevel/20250421013346.32530-1-john@groves.net/ (famfs fuse v1)
[9] - https://lore.kernel.org/linux-fsdevel/20260107153244.64703-1-john@groves.net/T/#mb2c868801be16eca82dab239a1d201628534aea7 (famfs fuse v3)
John Groves (8):
dax: move dax_pgoff_to_phys from [drivers/dax/] device.c to bus.c
dax: Factor out dax_folio_reset_order() helper
dax: add fsdev.c driver for fs-dax on character dax
dax: Save the kva from memremap
dax: Add dax_operations for use by fs-dax on fsdev dax
dax: Add dax_set_ops() for setting dax_operations at bind time
dax: Add fs_dax_get() func to prepare dax for fs-dax usage
dax: export dax_dev_get()
MAINTAINERS | 8 +
drivers/dax/Kconfig | 11 ++
drivers/dax/Makefile | 2 +
drivers/dax/bus.c | 30 +++-
drivers/dax/bus.h | 3 +
drivers/dax/dax-private.h | 3 +
drivers/dax/device.c | 23 ---
drivers/dax/fsdev.c | 346 ++++++++++++++++++++++++++++++++++++++
drivers/dax/super.c | 107 +++++++++++-
fs/dax.c | 75 +++++++--
include/linux/dax.h | 20 ++-
11 files changed, 578 insertions(+), 50 deletions(-)
create mode 100644 drivers/dax/fsdev.c
base-commit: c369299895a591d96745d6492d4888259b004a9e
--
2.53.0
^ permalink raw reply
* [PATCH V9 1/8] dax: move dax_pgoff_to_phys from [drivers/dax/] device.c to bus.c
From: John Groves @ 2026-03-24 0:37 UTC (permalink / raw)
To: John Groves, Miklos Szeredi, Dan Williams, Bernd Schubert,
Alison Schofield
Cc: John Groves, Jonathan Corbet, Shuah Khan, Vishal Verma,
Dave Jiang, Matthew Wilcox, Jan Kara, Alexander Viro,
David Hildenbrand, Christian Brauner, Darrick J . Wong,
Randy Dunlap, Jeff Layton, Amir Goldstein, Jonathan Cameron,
Stefan Hajnoczi, Joanne Koong, Josef Bacik, Bagas Sanjaya,
Chen Linxuan, James Morse, Fuad Tabba, Sean Christopherson,
Shivank Garg, Ackerley Tng, Gregory Price, Aravind Ramesh,
Ajay Joshi, venkataravis@micron.com, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org, nvdimm@lists.linux.dev,
linux-cxl@vger.kernel.org, linux-fsdevel@vger.kernel.org,
John Groves, Ira Weiny
In-Reply-To: <0100019d1d463523-617e8165-a084-4d91-aa5e-13778264d5d4-000000@email.amazonses.com>
From: John Groves <john@groves.net>
This function will be used by both device.c and fsdev.c, but both are
loadable modules. Moving to bus.c puts it in core and makes it available
to both.
No code changes - just relocated.
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Signed-off-by: John Groves <john@groves.net>
---
drivers/dax/bus.c | 24 ++++++++++++++++++++++++
drivers/dax/device.c | 23 -----------------------
2 files changed, 24 insertions(+), 23 deletions(-)
diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c
index c94c09622516..e4bd5c9f006c 100644
--- a/drivers/dax/bus.c
+++ b/drivers/dax/bus.c
@@ -1417,6 +1417,30 @@ static const struct device_type dev_dax_type = {
.groups = dax_attribute_groups,
};
+/* see "strong" declaration in tools/testing/nvdimm/dax-dev.c */
+__weak phys_addr_t dax_pgoff_to_phys(struct dev_dax *dev_dax, pgoff_t pgoff,
+ unsigned long size)
+{
+ int i;
+
+ for (i = 0; i < dev_dax->nr_range; i++) {
+ struct dev_dax_range *dax_range = &dev_dax->ranges[i];
+ struct range *range = &dax_range->range;
+ unsigned long long pgoff_end;
+ phys_addr_t phys;
+
+ pgoff_end = dax_range->pgoff + PHYS_PFN(range_len(range)) - 1;
+ if (pgoff < dax_range->pgoff || pgoff > pgoff_end)
+ continue;
+ phys = PFN_PHYS(pgoff - dax_range->pgoff) + range->start;
+ if (phys + size - 1 <= range->end)
+ return phys;
+ break;
+ }
+ return -1;
+}
+EXPORT_SYMBOL_GPL(dax_pgoff_to_phys);
+
static struct dev_dax *__devm_create_dev_dax(struct dev_dax_data *data)
{
struct dax_region *dax_region = data->dax_region;
diff --git a/drivers/dax/device.c b/drivers/dax/device.c
index 528e81240c4d..2d2dbfd35e94 100644
--- a/drivers/dax/device.c
+++ b/drivers/dax/device.c
@@ -57,29 +57,6 @@ static int check_vma(struct dev_dax *dev_dax, struct vm_area_struct *vma,
vma->vm_file, func);
}
-/* see "strong" declaration in tools/testing/nvdimm/dax-dev.c */
-__weak phys_addr_t dax_pgoff_to_phys(struct dev_dax *dev_dax, pgoff_t pgoff,
- unsigned long size)
-{
- int i;
-
- for (i = 0; i < dev_dax->nr_range; i++) {
- struct dev_dax_range *dax_range = &dev_dax->ranges[i];
- struct range *range = &dax_range->range;
- unsigned long long pgoff_end;
- phys_addr_t phys;
-
- pgoff_end = dax_range->pgoff + PHYS_PFN(range_len(range)) - 1;
- if (pgoff < dax_range->pgoff || pgoff > pgoff_end)
- continue;
- phys = PFN_PHYS(pgoff - dax_range->pgoff) + range->start;
- if (phys + size - 1 <= range->end)
- return phys;
- break;
- }
- return -1;
-}
-
static void dax_set_mapping(struct vm_fault *vmf, unsigned long pfn,
unsigned long fault_size)
{
--
2.53.0
^ permalink raw reply related
* [PATCH V9 2/8] dax: Factor out dax_folio_reset_order() helper
From: John Groves @ 2026-03-24 0:38 UTC (permalink / raw)
To: John Groves, Miklos Szeredi, Dan Williams, Bernd Schubert,
Alison Schofield
Cc: John Groves, Jonathan Corbet, Shuah Khan, Vishal Verma,
Dave Jiang, Matthew Wilcox, Jan Kara, Alexander Viro,
David Hildenbrand, Christian Brauner, Darrick J . Wong,
Randy Dunlap, Jeff Layton, Amir Goldstein, Jonathan Cameron,
Stefan Hajnoczi, Joanne Koong, Josef Bacik, Bagas Sanjaya,
Chen Linxuan, James Morse, Fuad Tabba, Sean Christopherson,
Shivank Garg, Ackerley Tng, Gregory Price, Aravind Ramesh,
Ajay Joshi, venkataravis@micron.com, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org, nvdimm@lists.linux.dev,
linux-cxl@vger.kernel.org, linux-fsdevel@vger.kernel.org,
Jonathan Cameron, Ira Weiny, John Groves
In-Reply-To: <0100019d1d463523-617e8165-a084-4d91-aa5e-13778264d5d4-000000@email.amazonses.com>
From: John Groves <John@Groves.net>
Both fs/dax.c:dax_folio_put() and drivers/dax/fsdev.c:
fsdev_clear_folio_state() (the latter coming in the next commit after this
one) contain nearly identical code to reset a compound DAX folio back to
order-0 pages. Factor this out into a shared helper function.
The new dax_folio_reset_order() function:
- Clears the folio's mapping and share count
- Resets compound folio state via folio_reset_order()
- Clears PageHead and compound_head for each sub-page
- Restores the pgmap pointer for each resulting order-0 folio
- Returns the original folio order (for callers that need to advance by
that many pages)
Two intentional differences from the original dax_folio_put() logic:
1. folio->share is cleared unconditionally. This is correct because the DAX
subsystem maintains the invariant that share != 0 only when mapping == NULL
(enforced by dax_folio_make_shared()). dax_folio_put() ensures share has
reached zero before calling this helper, so the unconditional clear is safe.
2. folio->pgmap is now explicitly restored for order-0 folios. For the
dax_folio_put() caller this is a no-op (reads and writes back the same
field). It is intentional for the upcoming fsdev_clear_folio_state()
caller, which converts previously-compound folios and needs pgmap
re-established for all pages regardless of order.
This simplifies fsdev_clear_folio_state() from ~50 lines to ~15 lines.
Suggested-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Signed-off-by: John Groves <john@groves.net>
---
fs/dax.c | 74 ++++++++++++++++++++++++++++++++++-----------
include/linux/dax.h | 1 +
2 files changed, 57 insertions(+), 18 deletions(-)
diff --git a/fs/dax.c b/fs/dax.c
index 289e6254aa30..eba86802a7a7 100644
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -378,6 +378,59 @@ static void dax_folio_make_shared(struct folio *folio)
folio->share = 1;
}
+/**
+ * dax_folio_reset_order - Reset a compound DAX folio to order-0 pages
+ * @folio: The folio to reset
+ *
+ * Splits a compound folio back into individual order-0 pages,
+ * clearing compound state and restoring pgmap pointers.
+ *
+ * Returns: the original folio order (0 if already order-0)
+ */
+int dax_folio_reset_order(struct folio *folio)
+{
+ struct dev_pagemap *pgmap = page_pgmap(&folio->page);
+ int order = folio_order(folio);
+
+ /*
+ * DAX maintains the invariant that folio->share != 0 only when
+ * folio->mapping == NULL (enforced by dax_folio_make_shared()).
+ * Equivalently: folio->mapping != NULL implies folio->share == 0.
+ * Callers ensure share has been decremented to zero before
+ * calling here, so unconditionally clearing both fields is
+ * correct.
+ */
+ folio->mapping = NULL;
+ folio->share = 0;
+
+ if (!order) {
+ /*
+ * Restore pgmap explicitly even for order-0 folios. For
+ * the dax_folio_put() caller this is a no-op (same value),
+ * but fsdev_clear_folio_state() may call this on folios
+ * that were previously compound and need pgmap
+ * re-established.
+ */
+ folio->pgmap = pgmap;
+ return 0;
+ }
+
+ folio_reset_order(folio);
+
+ for (int i = 0; i < (1UL << order); i++) {
+ struct page *page = folio_page(folio, i);
+ struct folio *f = (struct folio *)page;
+
+ ClearPageHead(page);
+ clear_compound_head(page);
+ f->mapping = NULL;
+ f->share = 0;
+ f->pgmap = pgmap;
+ }
+
+ return order;
+}
+
static inline unsigned long dax_folio_put(struct folio *folio)
{
unsigned long ref;
@@ -391,28 +444,13 @@ static inline unsigned long dax_folio_put(struct folio *folio)
if (ref)
return ref;
- folio->mapping = NULL;
- order = folio_order(folio);
- if (!order)
- return 0;
- folio_reset_order(folio);
+ order = dax_folio_reset_order(folio);
+ /* Debug check: verify refcounts are zero for all sub-folios */
for (i = 0; i < (1UL << order); i++) {
- struct dev_pagemap *pgmap = page_pgmap(&folio->page);
struct page *page = folio_page(folio, i);
- struct folio *new_folio = (struct folio *)page;
-
- ClearPageHead(page);
- clear_compound_head(page);
- new_folio->mapping = NULL;
- /*
- * Reset pgmap which was over-written by
- * prep_compound_page().
- */
- new_folio->pgmap = pgmap;
- new_folio->share = 0;
- WARN_ON_ONCE(folio_ref_count(new_folio));
+ WARN_ON_ONCE(folio_ref_count((struct folio *)page));
}
return ref;
diff --git a/include/linux/dax.h b/include/linux/dax.h
index bf103f317cac..73cfc1a7c8f1 100644
--- a/include/linux/dax.h
+++ b/include/linux/dax.h
@@ -153,6 +153,7 @@ static inline void fs_put_dax(struct dax_device *dax_dev, void *holder)
#if IS_ENABLED(CONFIG_FS_DAX)
int dax_writeback_mapping_range(struct address_space *mapping,
struct dax_device *dax_dev, struct writeback_control *wbc);
+int dax_folio_reset_order(struct folio *folio);
struct page *dax_layout_busy_page(struct address_space *mapping);
struct page *dax_layout_busy_page_range(struct address_space *mapping, loff_t start, loff_t end);
--
2.53.0
^ permalink raw reply related
* [PATCH V9 3/8] dax: add fsdev.c driver for fs-dax on character dax
From: John Groves @ 2026-03-24 0:38 UTC (permalink / raw)
To: John Groves, Miklos Szeredi, Dan Williams, Bernd Schubert,
Alison Schofield
Cc: John Groves, Jonathan Corbet, Shuah Khan, Vishal Verma,
Dave Jiang, Matthew Wilcox, Jan Kara, Alexander Viro,
David Hildenbrand, Christian Brauner, Darrick J . Wong,
Randy Dunlap, Jeff Layton, Amir Goldstein, Jonathan Cameron,
Stefan Hajnoczi, Joanne Koong, Josef Bacik, Bagas Sanjaya,
Chen Linxuan, James Morse, Fuad Tabba, Sean Christopherson,
Shivank Garg, Ackerley Tng, Gregory Price, Aravind Ramesh,
Ajay Joshi, venkataravis@micron.com, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org, nvdimm@lists.linux.dev,
linux-cxl@vger.kernel.org, linux-fsdevel@vger.kernel.org,
John Groves
In-Reply-To: <0100019d1d463523-617e8165-a084-4d91-aa5e-13778264d5d4-000000@email.amazonses.com>
From: John Groves <john@groves.net>
The new fsdev driver provides pages/folios initialized compatibly with
fsdax - normal rather than devdax-style refcounting, and starting out
with order-0 folios.
When fsdev binds to a daxdev, it is usually (always?) switching from the
devdax mode (device.c), which pre-initializes compound folios according
to its alignment. Fsdev uses fsdev_clear_folio_state() to switch the
folios into a fsdax-compatible state.
A side effect of this is that raw mmap doesn't (can't?) work on an fsdev
dax instance. Accordingly, The fsdev driver does not provide raw mmap -
devices must be put in 'devdax' mode (drivers/dax/device.c) to get raw
mmap capability.
In this commit is just the framework, which remaps pages/folios compatibly
with fsdax.
Enabling dax changes:
- bus.h: add DAXDRV_FSDEV_TYPE driver type
- bus.c: allow DAXDRV_FSDEV_TYPE drivers to bind to daxdevs
- dax.h: prototype inode_dax(), which fsdev needs
Suggested-by: Dan Williams <dan.j.williams@intel.com>
Suggested-by: Gregory Price <gourry@gourry.net>
Signed-off-by: John Groves <john@groves.net>
---
MAINTAINERS | 8 ++
drivers/dax/Kconfig | 11 ++
drivers/dax/Makefile | 2 +
drivers/dax/bus.c | 4 +
drivers/dax/bus.h | 1 +
drivers/dax/fsdev.c | 245 +++++++++++++++++++++++++++++++++++++++++++
fs/dax.c | 1 +
7 files changed, 272 insertions(+)
create mode 100644 drivers/dax/fsdev.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 7d10988cbc62..eedf4cce56ed 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7298,6 +7298,14 @@ L: linux-cxl@vger.kernel.org
S: Supported
F: drivers/dax/
+DEVICE DIRECT ACCESS (DAX) [fsdev_dax]
+M: John Groves <jgroves@micron.com>
+M: John Groves <John@Groves.net>
+L: nvdimm@lists.linux.dev
+L: linux-cxl@vger.kernel.org
+S: Supported
+F: drivers/dax/fsdev.c
+
DEVICE FREQUENCY (DEVFREQ)
M: MyungJoo Ham <myungjoo.ham@samsung.com>
M: Kyungmin Park <kyungmin.park@samsung.com>
diff --git a/drivers/dax/Kconfig b/drivers/dax/Kconfig
index d656e4c0eb84..7051b70980d5 100644
--- a/drivers/dax/Kconfig
+++ b/drivers/dax/Kconfig
@@ -61,6 +61,17 @@ config DEV_DAX_HMEM_DEVICES
depends on DEV_DAX_HMEM && DAX
def_bool y
+config DEV_DAX_FSDEV
+ tristate "FSDEV DAX: fs-dax compatible devdax driver"
+ depends on DEV_DAX && FS_DAX
+ help
+ Support fs-dax access to DAX devices via a character device
+ interface. Unlike device_dax (which pre-initializes compound folios
+ based on device alignment), this driver leaves folios at order-0 so
+ that fs-dax filesystems can manage folio order dynamically.
+
+ Say M if unsure.
+
config DEV_DAX_KMEM
tristate "KMEM DAX: map dax-devices as System-RAM"
default DEV_DAX
diff --git a/drivers/dax/Makefile b/drivers/dax/Makefile
index 5ed5c39857c8..ba35bda7abef 100644
--- a/drivers/dax/Makefile
+++ b/drivers/dax/Makefile
@@ -4,11 +4,13 @@ obj-$(CONFIG_DEV_DAX) += device_dax.o
obj-$(CONFIG_DEV_DAX_KMEM) += kmem.o
obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem.o
obj-$(CONFIG_DEV_DAX_CXL) += dax_cxl.o
+obj-$(CONFIG_DEV_DAX_FSDEV) += fsdev_dax.o
dax-y := super.o
dax-y += bus.o
device_dax-y := device.o
dax_pmem-y := pmem.o
dax_cxl-y := cxl.o
+fsdev_dax-y := fsdev.o
obj-y += hmem/
diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c
index e4bd5c9f006c..562e2b06f61a 100644
--- a/drivers/dax/bus.c
+++ b/drivers/dax/bus.c
@@ -81,6 +81,10 @@ static int dax_match_type(const struct dax_device_driver *dax_drv, struct device
!IS_ENABLED(CONFIG_DEV_DAX_KMEM))
return 1;
+ /* fsdev driver can also bind to device-type dax devices */
+ if (dax_drv->type == DAXDRV_FSDEV_TYPE && type == DAXDRV_DEVICE_TYPE)
+ return 1;
+
return 0;
}
diff --git a/drivers/dax/bus.h b/drivers/dax/bus.h
index cbbf64443098..880bdf7e72d7 100644
--- a/drivers/dax/bus.h
+++ b/drivers/dax/bus.h
@@ -31,6 +31,7 @@ struct dev_dax *devm_create_dev_dax(struct dev_dax_data *data);
enum dax_driver_type {
DAXDRV_KMEM_TYPE,
DAXDRV_DEVICE_TYPE,
+ DAXDRV_FSDEV_TYPE,
};
struct dax_device_driver {
diff --git a/drivers/dax/fsdev.c b/drivers/dax/fsdev.c
new file mode 100644
index 000000000000..8b5c6976ad17
--- /dev/null
+++ b/drivers/dax/fsdev.c
@@ -0,0 +1,245 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2026 Micron Technology, Inc. */
+#include <linux/memremap.h>
+#include <linux/pagemap.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/slab.h>
+#include <linux/dax.h>
+#include <linux/uio.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include "dax-private.h"
+#include "bus.h"
+
+/*
+ * FS-DAX compatible devdax driver
+ *
+ * Unlike drivers/dax/device.c which pre-initializes compound folios based
+ * on device alignment (via vmemmap_shift), this driver leaves folios
+ * uninitialized similar to pmem. This allows fs-dax filesystems like famfs
+ * to work without needing special handling for pre-initialized folios.
+ *
+ * Key differences from device.c:
+ * - pgmap type is MEMORY_DEVICE_FS_DAX (not MEMORY_DEVICE_GENERIC)
+ * - vmemmap_shift is NOT set (folios remain order-0)
+ * - fs-dax can dynamically create compound folios as needed
+ * - No mmap support - all access is through fs-dax/iomap
+ */
+
+static void fsdev_cdev_del(void *cdev)
+{
+ cdev_del(cdev);
+}
+
+static void fsdev_kill(void *dev_dax)
+{
+ kill_dev_dax(dev_dax);
+}
+
+/*
+ * Page map operations for FS-DAX mode
+ * Similar to fsdax_pagemap_ops in drivers/nvdimm/pmem.c
+ *
+ * Note: folio_free callback is not needed for MEMORY_DEVICE_FS_DAX.
+ * The core mm code in free_zone_device_folio() handles the wake_up_var()
+ * directly for this memory type.
+ */
+static int fsdev_pagemap_memory_failure(struct dev_pagemap *pgmap,
+ unsigned long pfn, unsigned long nr_pages, int mf_flags)
+{
+ struct dev_dax *dev_dax = pgmap->owner;
+ u64 offset = PFN_PHYS(pfn) - dev_dax->ranges[0].range.start;
+ u64 len = nr_pages << PAGE_SHIFT;
+
+ return dax_holder_notify_failure(dev_dax->dax_dev, offset,
+ len, mf_flags);
+}
+
+static const struct dev_pagemap_ops fsdev_pagemap_ops = {
+ .memory_failure = fsdev_pagemap_memory_failure,
+};
+
+/*
+ * Clear any stale folio state from pages in the given range.
+ * This is necessary because device_dax pre-initializes compound folios
+ * based on vmemmap_shift, and that state may persist after driver unbind.
+ * Since fsdev_dax uses MEMORY_DEVICE_FS_DAX without vmemmap_shift, fs-dax
+ * expects to find clean order-0 folios that it can build into compound
+ * folios on demand.
+ *
+ * At probe time, no filesystem should be mounted yet, so all mappings
+ * are stale and must be cleared along with compound state.
+ */
+static void fsdev_clear_folio_state(struct dev_dax *dev_dax)
+{
+ for (int i = 0; i < dev_dax->nr_range; i++) {
+ struct range *range = &dev_dax->ranges[i].range;
+ unsigned long pfn = PHYS_PFN(range->start);
+ unsigned long end_pfn = PHYS_PFN(range->end) + 1;
+
+ while (pfn < end_pfn) {
+ struct folio *folio = pfn_folio(pfn);
+ int order = dax_folio_reset_order(folio);
+
+ pfn += 1UL << order;
+ }
+ }
+}
+
+static void fsdev_clear_folio_state_action(void *data)
+{
+ fsdev_clear_folio_state(data);
+}
+
+static int fsdev_open(struct inode *inode, struct file *filp)
+{
+ struct dax_device *dax_dev = inode_dax(inode);
+ struct dev_dax *dev_dax = dax_get_private(dax_dev);
+
+ filp->private_data = dev_dax;
+
+ return 0;
+}
+
+static int fsdev_release(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+static const struct file_operations fsdev_fops = {
+ .llseek = noop_llseek,
+ .owner = THIS_MODULE,
+ .open = fsdev_open,
+ .release = fsdev_release,
+};
+
+static int fsdev_dax_probe(struct dev_dax *dev_dax)
+{
+ struct dax_device *dax_dev = dev_dax->dax_dev;
+ struct device *dev = &dev_dax->dev;
+ struct dev_pagemap *pgmap;
+ struct inode *inode;
+ struct cdev *cdev;
+ void *addr;
+ int rc, i;
+
+ if (static_dev_dax(dev_dax)) {
+ if (dev_dax->nr_range > 1) {
+ dev_warn(dev, "static pgmap / multi-range device conflict\n");
+ return -EINVAL;
+ }
+
+ pgmap = dev_dax->pgmap;
+ } else {
+ size_t pgmap_size;
+
+ if (dev_dax->pgmap) {
+ dev_warn(dev, "dynamic-dax with pre-populated page map\n");
+ return -EINVAL;
+ }
+
+ pgmap_size = struct_size(pgmap, ranges, dev_dax->nr_range - 1);
+ pgmap = devm_kzalloc(dev, pgmap_size, GFP_KERNEL);
+ if (!pgmap)
+ return -ENOMEM;
+
+ pgmap->nr_range = dev_dax->nr_range;
+ dev_dax->pgmap = pgmap;
+
+ for (i = 0; i < dev_dax->nr_range; i++) {
+ struct range *range = &dev_dax->ranges[i].range;
+
+ pgmap->ranges[i] = *range;
+ }
+ }
+
+ for (i = 0; i < dev_dax->nr_range; i++) {
+ struct range *range = &dev_dax->ranges[i].range;
+
+ if (!devm_request_mem_region(dev, range->start,
+ range_len(range), dev_name(dev))) {
+ dev_warn(dev, "mapping%d: %#llx-%#llx could not reserve range\n",
+ i, range->start, range->end);
+ return -EBUSY;
+ }
+ }
+
+ /*
+ * Use MEMORY_DEVICE_FS_DAX without setting vmemmap_shift, leaving
+ * folios at order-0. Unlike device.c (MEMORY_DEVICE_GENERIC), this
+ * lets fs-dax dynamically build compound folios as needed, similar
+ * to pmem behavior.
+ */
+ pgmap->type = MEMORY_DEVICE_FS_DAX;
+ pgmap->ops = &fsdev_pagemap_ops;
+ pgmap->owner = dev_dax;
+
+ addr = devm_memremap_pages(dev, pgmap);
+ if (IS_ERR(addr))
+ return PTR_ERR(addr);
+
+ /*
+ * Clear any stale compound folio state left over from a previous
+ * driver (e.g., device_dax with vmemmap_shift). Also register this
+ * as a devm action so folio state is cleared on unbind, ensuring
+ * clean pages for subsequent drivers (e.g., kmem for system-ram).
+ */
+ fsdev_clear_folio_state(dev_dax);
+ rc = devm_add_action_or_reset(dev, fsdev_clear_folio_state_action,
+ dev_dax);
+ if (rc)
+ return rc;
+
+ /* Detect whether the data is at a non-zero offset into the memory */
+ if (pgmap->range.start != dev_dax->ranges[0].range.start) {
+ u64 phys = dev_dax->ranges[0].range.start;
+ u64 pgmap_phys = dev_dax->pgmap[0].range.start;
+ u64 data_offset = 0;
+
+ if (!WARN_ON(pgmap_phys > phys))
+ data_offset = phys - pgmap_phys;
+
+ pr_debug("%s: offset detected phys=%llx pgmap_phys=%llx offset=%llx\n",
+ __func__, phys, pgmap_phys, data_offset);
+ }
+
+ inode = dax_inode(dax_dev);
+ cdev = inode->i_cdev;
+ cdev_init(cdev, &fsdev_fops);
+ cdev->owner = dev->driver->owner;
+ cdev_set_parent(cdev, &dev->kobj);
+ rc = cdev_add(cdev, dev->devt, 1);
+ if (rc)
+ return rc;
+
+ rc = devm_add_action_or_reset(dev, fsdev_cdev_del, cdev);
+ if (rc)
+ return rc;
+
+ run_dax(dax_dev);
+ return devm_add_action_or_reset(dev, fsdev_kill, dev_dax);
+}
+
+static struct dax_device_driver fsdev_dax_driver = {
+ .probe = fsdev_dax_probe,
+ .type = DAXDRV_FSDEV_TYPE,
+};
+
+static int __init dax_init(void)
+{
+ return dax_driver_register(&fsdev_dax_driver);
+}
+
+static void __exit dax_exit(void)
+{
+ dax_driver_unregister(&fsdev_dax_driver);
+}
+
+MODULE_AUTHOR("John Groves");
+MODULE_DESCRIPTION("FS-DAX Device: fs-dax compatible devdax driver");
+MODULE_LICENSE("GPL");
+module_init(dax_init);
+module_exit(dax_exit);
+MODULE_ALIAS_DAX_DEVICE(0);
diff --git a/fs/dax.c b/fs/dax.c
index eba86802a7a7..b91a2535149a 100644
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -430,6 +430,7 @@ int dax_folio_reset_order(struct folio *folio)
return order;
}
+EXPORT_SYMBOL_GPL(dax_folio_reset_order);
static inline unsigned long dax_folio_put(struct folio *folio)
{
--
2.53.0
^ permalink raw reply related
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