* [PATCH v4 08/16] vfio: selftests: Build liveupdate library in VFIO selftests
From: Vipin Sharma @ 2026-05-11 23:47 UTC (permalink / raw)
To: kvm, linux-doc, linux-kernel, linux-kselftest, linux-pci
Cc: ajayachandra, alex, amastro, ankita, apopple, chrisl, corbet,
dmatlack, graf, jacob.pan, jgg, jgg, jrhilke, julianr, kevin.tian,
leon, leonro, lukas, michal.winiarski, parav, pasha.tatashin,
praan, pratyush, rananta, rientjes, rodrigo.vivi, rppt, saeedm,
skhan, skhawaja, vipinsh, vivek.kasireddy, witu, yanjun.zhu,
yi.l.liu
In-Reply-To: <20260511234802.2280368-1-vipinsh@google.com>
Import and build liveupdate selftest library in VFIO selftests.
It allows to use liveupdate ioctls in VFIO selftests
Co-developed-by: David Matlack <dmatlack@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
Signed-off-by: Vipin Sharma <vipinsh@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 0684932d91bf..7865b2aa011c 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.54.0.563.g4f69b47b94-goog
^ permalink raw reply related
* [PATCH v4 07/16] docs: liveupdate: Add documentation for VFIO PCI
From: Vipin Sharma @ 2026-05-11 23:47 UTC (permalink / raw)
To: kvm, linux-doc, linux-kernel, linux-kselftest, linux-pci
Cc: ajayachandra, alex, amastro, ankita, apopple, chrisl, corbet,
dmatlack, graf, jacob.pan, jgg, jgg, jrhilke, julianr, kevin.tian,
leon, leonro, lukas, michal.winiarski, parav, pasha.tatashin,
praan, pratyush, rananta, rientjes, rodrigo.vivi, rppt, saeedm,
skhan, skhawaja, vipinsh, vivek.kasireddy, witu, yanjun.zhu,
yi.l.liu
In-Reply-To: <20260511234802.2280368-1-vipinsh@google.com>
From: David Matlack <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>
Signed-off-by: Vipin Sharma <vipinsh@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 b6c33c2bcc7c..737c5ed1ce38 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27979,6 +27979,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.54.0.563.g4f69b47b94-goog
^ permalink raw reply related
* [PATCH v4 06/16] vfio/pci: Store incoming Live Update state in struct vfio_pci_core_device
From: Vipin Sharma @ 2026-05-11 23:47 UTC (permalink / raw)
To: kvm, linux-doc, linux-kernel, linux-kselftest, linux-pci
Cc: ajayachandra, alex, amastro, ankita, apopple, chrisl, corbet,
dmatlack, graf, jacob.pan, jgg, jgg, jrhilke, julianr, kevin.tian,
leon, leonro, lukas, michal.winiarski, parav, pasha.tatashin,
praan, pratyush, rananta, rientjes, rodrigo.vivi, rppt, saeedm,
skhan, skhawaja, vipinsh, vivek.kasireddy, witu, yanjun.zhu,
yi.l.liu
In-Reply-To: <20260511234802.2280368-1-vipinsh@google.com>
From: David Matlack <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>
Signed-off-by: Vipin Sharma <vipinsh@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 1726d4d41b57..da013b4b1e94 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 731a3e34085f..7b841a1e7fcc 100644
--- a/drivers/vfio/pci/vfio_pci_liveupdate.c
+++ b/drivers/vfio/pci/vfio_pci_liveupdate.c
@@ -249,6 +249,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;
@@ -265,6 +266,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() */
@@ -274,7 +278,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.54.0.563.g4f69b47b94-goog
^ permalink raw reply related
* [PATCH v4 05/16] vfio: Enforce preserved devices are retrieved via LIVEUPDATE_SESSION_RETRIEVE_FD
From: Vipin Sharma @ 2026-05-11 23:47 UTC (permalink / raw)
To: kvm, linux-doc, linux-kernel, linux-kselftest, linux-pci
Cc: ajayachandra, alex, amastro, ankita, apopple, chrisl, corbet,
dmatlack, graf, jacob.pan, jgg, jgg, jrhilke, julianr, kevin.tian,
leon, leonro, lukas, michal.winiarski, parav, pasha.tatashin,
praan, pratyush, rananta, rientjes, rodrigo.vivi, rppt, saeedm,
skhan, skhawaja, vipinsh, vivek.kasireddy, witu, yanjun.zhu,
yi.l.liu
In-Reply-To: <20260511234802.2280368-1-vipinsh@google.com>
From: David Matlack <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>
Co-developed-by: Vipin Sharma <vipinsh@google.com>
Signed-off-by: Vipin Sharma <vipinsh@google.com>
---
drivers/vfio/device_cdev.c | 8 ++++++++
drivers/vfio/group.c | 9 +++++++++
drivers/vfio/pci/vfio_pci_liveupdate.c | 6 ++++++
drivers/vfio/vfio.h | 18 ++++++++++++++++++
4 files changed, 41 insertions(+)
diff --git a/drivers/vfio/device_cdev.c b/drivers/vfio/device_cdev.c
index 1ab07ccaf3ab..4df0495941c6 100644
--- a/drivers/vfio/device_cdev.c
+++ b/drivers/vfio/device_cdev.c
@@ -49,6 +49,14 @@ static int vfio_device_cdev_open(struct vfio_device *device, struct file **filep
}
*filep = file;
+ } else if (vfio_liveupdate_incoming_is_preserved(device)) {
+ /*
+ * Since it is live update preserved device, it must be
+ * retrieved via LIVEUPDATE_SESSION_RETRIEVE_FD instead of
+ * opening /dev/vfio/devices/vfioX.
+ */
+ ret = -EBUSY;
+ goto err_free_device_file;
}
file->private_data = df;
diff --git a/drivers/vfio/group.c b/drivers/vfio/group.c
index b2299e5bc6df..62b4eaabc829 100644
--- a/drivers/vfio/group.c
+++ b/drivers/vfio/group.c
@@ -316,6 +316,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 11c3bc8a8dcd..731a3e34085f 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 0854f3fa1a22..5269fe021ee3 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;
@@ -461,4 +462,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.54.0.563.g4f69b47b94-goog
^ permalink raw reply related
* [PATCH v4 04/16] vfio/pci: Notify PCI subsystem about devices preserved across Live Update
From: Vipin Sharma @ 2026-05-11 23:47 UTC (permalink / raw)
To: kvm, linux-doc, linux-kernel, linux-kselftest, linux-pci
Cc: ajayachandra, alex, amastro, ankita, apopple, chrisl, corbet,
dmatlack, graf, jacob.pan, jgg, jgg, jrhilke, julianr, kevin.tian,
leon, leonro, lukas, michal.winiarski, parav, pasha.tatashin,
praan, pratyush, rananta, rientjes, rodrigo.vivi, rppt, saeedm,
skhan, skhawaja, vipinsh, vivek.kasireddy, witu, yanjun.zhu,
yi.l.liu
In-Reply-To: <20260511234802.2280368-1-vipinsh@google.com>
From: David Matlack <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>
Co-developed-by: Vipin Sharma <vipinsh@google.com>
Signed-off-by: Vipin Sharma <vipinsh@google.com>
---
drivers/vfio/pci/vfio_pci_liveupdate.c | 44 +++++++++++++++++++++++---
1 file changed, 40 insertions(+), 4 deletions(-)
diff --git a/drivers/vfio/pci/vfio_pci_liveupdate.c b/drivers/vfio/pci/vfio_pci_liveupdate.c
index 9142aaea94f2..11c3bc8a8dcd 100644
--- a/drivers/vfio/pci/vfio_pci_liveupdate.c
+++ b/drivers/vfio/pci/vfio_pci_liveupdate.c
@@ -71,6 +71,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
* =====================
*
@@ -141,23 +144,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));
}
@@ -256,6 +273,15 @@ 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;
+
+ if (!args->file) {
+ pr_err("Finish called on an unretrieved file.\n");
+ return;
+ }
+
+ device = vfio_device_from_file(args->file);
+ pci_liveupdate_finish(to_pci_dev(device->dev));
kho_restore_free(phys_to_virt(args->serialized_data));
}
@@ -280,13 +306,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)
{
+ pci_liveupdate_unregister_flb(&vfio_pci_liveupdate_fh);
liveupdate_unregister_file_handler(&vfio_pci_liveupdate_fh);
}
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply related
* [PATCH v4 03/16] vfio/pci: Retrieve preserved device files after Live Update
From: Vipin Sharma @ 2026-05-11 23:47 UTC (permalink / raw)
To: kvm, linux-doc, linux-kernel, linux-kselftest, linux-pci
Cc: ajayachandra, alex, amastro, ankita, apopple, chrisl, corbet,
dmatlack, graf, jacob.pan, jgg, jgg, jrhilke, julianr, kevin.tian,
leon, leonro, lukas, michal.winiarski, parav, pasha.tatashin,
praan, pratyush, rananta, rientjes, rodrigo.vivi, rppt, saeedm,
skhan, skhawaja, vipinsh, vivek.kasireddy, witu, yanjun.zhu,
yi.l.liu
In-Reply-To: <20260511234802.2280368-1-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.
Co-developed-by: David Matlack <dmatlack@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
Signed-off-by: Vipin Sharma <vipinsh@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..1ab07ccaf3ab 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:
+ kfree(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 5cc57bf39dbe..9142aaea94f2 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
* ============
@@ -90,6 +96,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/errno.h>
+#include <linux/file.h>
#include <linux/kexec_handover.h>
#include <linux/kho/abi/vfio_pci.h>
#include <linux/liveupdate.h>
@@ -203,13 +210,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 = {
@@ -218,6 +265,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 2148b00491e4..33e082af9a08 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>
@@ -1787,6 +1788,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 f5f7ece51f8f..0b61aeff8216 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -431,4 +431,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.54.0.563.g4f69b47b94-goog
^ permalink raw reply related
* [PATCH v4 02/16] vfio/pci: Preserve vfio-pci device files across Live Update
From: Vipin Sharma @ 2026-05-11 23:47 UTC (permalink / raw)
To: kvm, linux-doc, linux-kernel, linux-kselftest, linux-pci
Cc: ajayachandra, alex, amastro, ankita, apopple, chrisl, corbet,
dmatlack, graf, jacob.pan, jgg, jgg, jrhilke, julianr, kevin.tian,
leon, leonro, lukas, michal.winiarski, parav, pasha.tatashin,
praan, pratyush, rananta, rientjes, rodrigo.vivi, rppt, saeedm,
skhan, skhawaja, vipinsh, vivek.kasireddy, witu, yanjun.zhu,
yi.l.liu
In-Reply-To: <20260511234802.2280368-1-vipinsh@google.com>
Implement the live update file handler callbacks to preserve a vfio-pci
device across a Live Update. Subsequent commits will enable userspace to
then retrieve this file after the Live Update.
Live Update support is scoped only to cdev files (i.e. not
VFIO_GROUP_GET_DEVICE_FD files).
State about each device is serialized into a new ABI struct
vfio_pci_core_device_ser. The contents of this struct are preserved
across the Live Update to the next kernel using a combination of
Kexec-Handover (KHO) to preserve the page(s) holding the struct and the
Live Update Orchestrator (LUO) to preserve the physical address of the
struct.
For now the only contents of struct vfio_pci_core_device_ser the
device's PCI segment number and BDF, so that the device can be uniquely
identified after the Live Update.
Require that userspace disables interrupts on the device prior to
freeze() so that the device does not send any interrupts until new
interrupt handlers have been set up by the next kernel.
Reset the device and restore its state in the freeze() callback. This
ensures the device can be received by the next kernel in a consistent
state. Eventually this will be dropped and the device can be preserved
across in a running state, but that requires further work in VFIO and
the core PCI layer.
Note that LUO holds a reference to this file when it is preserved. So
VFIO is guaranteed that vfio_df_device_last_close() will not be called
on this device until userspace has unpreserved the file using LUO.
Co-developed-by: David Matlack <dmatlack@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
Signed-off-by: Vipin Sharma <vipinsh@google.com>
---
drivers/vfio/pci/Kconfig | 6 +-
drivers/vfio/pci/vfio_pci.c | 2 +-
drivers/vfio/pci/vfio_pci_core.c | 60 +++++----
drivers/vfio/pci/vfio_pci_liveupdate.c | 178 ++++++++++++++++++++++++-
drivers/vfio/pci/vfio_pci_priv.h | 5 +
drivers/vfio/vfio_main.c | 3 +-
include/linux/kho/abi/vfio_pci.h | 15 +++
include/linux/vfio.h | 2 +
8 files changed, 242 insertions(+), 29 deletions(-)
diff --git a/drivers/vfio/pci/Kconfig b/drivers/vfio/pci/Kconfig
index c12d614fc6c4..019de053f116 100644
--- a/drivers/vfio/pci/Kconfig
+++ b/drivers/vfio/pci/Kconfig
@@ -45,13 +45,15 @@ config VFIO_PCI_IGD
config VFIO_PCI_LIVEUPDATE
bool "VFIO PCI support for Live Update (EXPERIMENTAL)"
- depends on PCI_LIVEUPDATE
+ depends on PCI_LIVEUPDATE && VFIO_DEVICE_CDEV
help
Support for preserving devices bound to vfio-pci across a Live
Update. This option should only be enabled by developers working on
implementing this support. Once enough support has landed in the
kernel, this option will no longer be marked EXPERIMENTAL.
+ Enabling this will disable support for VFIO PCI DMA buffer.
+
If you don't know what to do here, say N.
endif
@@ -68,7 +70,7 @@ config VFIO_PCI_ZDEV_KVM
To enable s390x KVM vfio-pci extensions, say Y.
config VFIO_PCI_DMABUF
- def_bool y if VFIO_PCI_CORE && PCI_P2PDMA && DMA_SHARED_BUFFER
+ def_bool y if VFIO_PCI_CORE && PCI_P2PDMA && DMA_SHARED_BUFFER && !VFIO_PCI_LIVEUPDATE
source "drivers/vfio/pci/mlx5/Kconfig"
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index 5038265f3af5..439d14d79d8f 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -125,7 +125,7 @@ static int vfio_pci_open_device(struct vfio_device *core_vdev)
return 0;
}
-static const struct vfio_device_ops vfio_pci_ops = {
+const struct vfio_device_ops vfio_pci_ops = {
.name = "vfio-pci",
.init = vfio_pci_core_init_dev,
.release = vfio_pci_core_release_dev,
diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
index ad52abc46c04..1726d4d41b57 100644
--- a/drivers/vfio/pci/vfio_pci_core.c
+++ b/drivers/vfio/pci/vfio_pci_core.c
@@ -585,9 +585,42 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev)
}
EXPORT_SYMBOL_GPL(vfio_pci_core_enable);
+void vfio_pci_core_try_reset(struct vfio_pci_core_device *vdev)
+{
+ struct pci_dev *pdev = vdev->pdev;
+ struct pci_dev *bridge = pci_upstream_bridge(pdev);
+
+ lockdep_assert_held(&vdev->vdev.dev_set->lock);
+
+ if (!vdev->reset_works)
+ return;
+
+ /*
+ * Try to get the locks ourselves to prevent a deadlock. The
+ * success of this is dependent on being able to lock the device,
+ * which is not always possible.
+ *
+ * We cannot use the "try" reset interface here, since that will
+ * overwrite the previously restored configuration information.
+ */
+ if (bridge && !pci_dev_trylock(bridge))
+ return;
+
+ if (!pci_dev_trylock(pdev))
+ goto out;
+
+ if (!__pci_reset_function_locked(pdev))
+ vdev->needs_reset = false;
+
+ pci_dev_unlock(pdev);
+out:
+ if (bridge)
+ pci_dev_unlock(bridge);
+}
+EXPORT_SYMBOL_GPL(vfio_pci_core_try_reset);
+
void vfio_pci_core_disable(struct vfio_pci_core_device *vdev)
{
- struct pci_dev *bridge;
struct pci_dev *pdev = vdev->pdev;
struct vfio_pci_dummy_resource *dummy_res, *tmp;
struct vfio_pci_ioeventfd *ioeventfd, *ioeventfd_tmp;
@@ -687,27 +720,7 @@ void vfio_pci_core_disable(struct vfio_pci_core_device *vdev)
*/
pci_write_config_word(pdev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
- /*
- * Try to get the locks ourselves to prevent a deadlock. The
- * success of this is dependent on being able to lock the device,
- * which is not always possible.
- * We can not use the "try" reset interface here, which will
- * overwrite the previously restored configuration information.
- */
- if (vdev->reset_works) {
- bridge = pci_upstream_bridge(pdev);
- if (bridge && !pci_dev_trylock(bridge))
- goto out_restore_state;
- if (pci_dev_trylock(pdev)) {
- if (!__pci_reset_function_locked(pdev))
- vdev->needs_reset = false;
- pci_dev_unlock(pdev);
- }
- if (bridge)
- pci_dev_unlock(bridge);
- }
-
-out_restore_state:
+ vfio_pci_core_try_reset(vdev);
pci_restore_state(pdev);
out:
pci_disable_device(pdev);
@@ -1613,7 +1626,7 @@ ssize_t vfio_pci_core_write(struct vfio_device *core_vdev, const char __user *bu
}
EXPORT_SYMBOL_GPL(vfio_pci_core_write);
-static void vfio_pci_zap_bars(struct vfio_pci_core_device *vdev)
+void vfio_pci_zap_bars(struct vfio_pci_core_device *vdev)
{
struct vfio_device *core_vdev = &vdev->vdev;
loff_t start = VFIO_PCI_INDEX_TO_OFFSET(VFIO_PCI_BAR0_REGION_INDEX);
@@ -1622,6 +1635,7 @@ static void vfio_pci_zap_bars(struct vfio_pci_core_device *vdev)
unmap_mapping_range(core_vdev->inode->i_mapping, start, len, true);
}
+EXPORT_SYMBOL_GPL(vfio_pci_zap_bars);
void vfio_pci_zap_and_down_write_memory_lock(struct vfio_pci_core_device *vdev)
{
diff --git a/drivers/vfio/pci/vfio_pci_liveupdate.c b/drivers/vfio/pci/vfio_pci_liveupdate.c
index 1c74854600ea..5cc57bf39dbe 100644
--- a/drivers/vfio/pci/vfio_pci_liveupdate.c
+++ b/drivers/vfio/pci/vfio_pci_liveupdate.c
@@ -6,28 +6,201 @@
* David Matlack <dmatlack@google.com>
*/
+/**
+ * DOC: VFIO PCI Preservation via LUO
+ *
+ * VFIO PCI devices can be preserved over a kexec using the Live Update
+ * Orchestrator (LUO) file preservation. This allows userspace (such as a VMM)
+ * to transfer an in-use device to the next kernel.
+ *
+ * .. note::
+ * The support for preserving VFIO PCI devices is currently *partial* and
+ * should be considered *experimental*. It should only be used by developers
+ * working on expanding the support for the time being.
+ *
+ * To avoid accidental usage while the support is still experimental, this
+ * support is hidden behind a default-disable config option
+ * ``CONFIG_VFIO_PCI_LIVEUPDATE``. Once the kernel support has stabilized and
+ * become complete, this option will be enabled by default when
+ * ``CONFIG_VFIO_PCI`` and ``CONFIG_LIVEUPDATE`` are enabled.
+ *
+ * Usage Example
+ * =============
+ *
+ * VFIO PCI devices can be preserved across a kexec by preserving the file
+ * associated with the device in a LUO session::
+ *
+ * device_fd = open("/dev/vfio/devices/vfioX");
+ * ...
+ * ioctl(session_fd, LIVEUPDATE_SESSION_PRESERVE_FD, { ..., device_fd, ...});
+ *
+ * .. note::
+ * LUO will hold an extra reference to the device file for as long as it is
+ * preserved, so there is no way for the file to be destroyed or the device
+ * to be unbound from the vfio-pci driver while it is preserved.
+ *
+ * Retrieving the file after kexec is not yet supported.
+ *
+ * Restrictions
+ * ============
+ *
+ * The kernel imposes the following restrictions when preserving VFIO devices:
+ *
+ * * The device must be bound to the ``vfio-pci`` driver.
+ *
+ * * ``CONFIG_VFIO_PCI_ZDEV_KVM`` must not be enabled. This may be relaxed in
+ * the future.
+ *
+ * * The device must not be an Intel display device. This may be relaxed in
+ * the future.
+ *
+ * * No support for VFIO PCI DMA buffer. This is to keep code simpler, it will
+ * be removed in future.
+ *
+ * * The device file descriptor must be obtained by opening the VFIO character
+ * device (``/dev/vfio/devices/vfioX``) and not via
+ * ``VFIO_GROUP_GET_DEVICE_FD``.
+ *
+ * * The device must have interrupt disable prior to kexec. Failure to disable
+ * interrupts on the device will cause the ``reboot(LINUX_REBOOT_CMD_KEXEC)``
+ * syscall (to initiate the kexec) to fail.
+ *
+ * Preservation Behavior
+ * =====================
+ *
+ * The eventual goal of this support is to avoid disrupting the workload, state,
+ * or configuration of each preserved device during a Live Update. This would
+ * include allowing the device to perform DMA to preserved memory buffers and
+ * perform P2P DMA to other preserved devices. However, there are many pieces
+ * that still need to land in the kernel.
+ *
+ * For now, VFIO only preserves the following state for for devices:
+ *
+ * * The PCI Segment, Bus, Device, and Function numbers of the device. The
+ * kernel guarantees the these will not change across a kexec when a device
+ * is preserved.
+ *
+ * Since the kernel is not yet prepared to preserve all parts of the device and
+ * its dependencies (such as DMA mappings), VFIO currently resets and restores
+ * preserved devices back into an idle state during kexec, before handing off
+ * control to the next kernel. This will be relaxed in future versions of the
+ * kernel once it is safe to allow the device to keep running across kexec.
+ */
+
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/errno.h>
+#include <linux/kexec_handover.h>
#include <linux/kho/abi/vfio_pci.h>
#include <linux/liveupdate.h>
#include <linux/module.h>
+#include <linux/vfio.h>
#include "vfio_pci_priv.h"
static bool vfio_pci_liveupdate_can_preserve(struct liveupdate_file_handler *handler,
struct file *file)
{
- return false;
+ struct vfio_device *device = vfio_device_from_file(file);
+ struct vfio_pci_core_device *vdev;
+ struct pci_dev *pdev;
+
+ if (!device)
+ return false;
+
+ /* Live Update support is limited to cdev files. */
+ if (!vfio_device_cdev_opened(device))
+ return false;
+
+ if (device->ops != &vfio_pci_ops)
+ return false;
+
+ vdev = container_of(device, struct vfio_pci_core_device, vdev);
+ pdev = vdev->pdev;
+
+ /*
+ * Don't support specialized vfio-pci devices for now since they haven't
+ * been tested.
+ */
+ if (IS_ENABLED(CONFIG_VFIO_PCI_ZDEV_KVM) || vfio_pci_is_intel_display(pdev))
+ return false;
+
+ return true;
}
static int vfio_pci_liveupdate_preserve(struct liveupdate_file_op_args *args)
{
- return -EOPNOTSUPP;
+ struct vfio_device *device = vfio_device_from_file(args->file);
+ struct vfio_pci_core_device_ser *ser;
+ struct vfio_pci_core_device *vdev;
+ struct pci_dev *pdev;
+
+ vdev = container_of(device, struct vfio_pci_core_device, vdev);
+ pdev = vdev->pdev;
+
+ ser = kho_alloc_preserve(sizeof(*ser));
+ if (IS_ERR(ser))
+ return PTR_ERR(ser);
+
+ ser->bdf = pci_dev_id(pdev);
+ ser->domain = pci_domain_nr(pdev->bus);
+
+ args->serialized_data = virt_to_phys(ser);
+ return 0;
}
static void vfio_pci_liveupdate_unpreserve(struct liveupdate_file_op_args *args)
{
+ kho_unpreserve_free(phys_to_virt(args->serialized_data));
+}
+
+static int vfio_pci_liveupdate_freeze(struct liveupdate_file_op_args *args)
+{
+ struct vfio_device *device = vfio_device_from_file(args->file);
+ struct vfio_pci_core_device *vdev;
+ struct pci_dev *pdev;
+ int ret;
+
+ vdev = container_of(device, struct vfio_pci_core_device, vdev);
+ pdev = vdev->pdev;
+
+ guard(mutex)(&device->dev_set->lock);
+
+ /*
+ * Userspace must disable interrupts on the device prior to freeze so
+ * that the device does not send any interrupts until new interrupt
+ * handlers have been established by the next kernel.
+ */
+ if (vdev->irq_type != VFIO_PCI_NUM_IRQS) {
+ pci_err(pdev, "Freeze failed! Interrupts are still enabled.\n");
+ return -EINVAL;
+ }
+
+ guard(rwsem_write)(&vdev->memory_lock);
+
+ /*
+ * Userspace must make sure device is not in the lower power state for
+ * live update. We may relax this in future.
+ */
+ if (pdev->current_state != PCI_D0) {
+ pci_err(pdev, "Freeze failed! Device not in D0 state.\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Reset is a temporary measure to provide kernel after kexec a clean
+ * device while VFIO live update work is under development and not
+ * fully supported. It will go away once continuous DMA support is
+ * added to device preservation.
+ */
+ vfio_pci_zap_bars(vdev);
+ ret = pci_load_saved_state(pdev, vdev->pci_saved_state);
+ if (ret)
+ return ret;
+ pci_clear_master(pdev);
+ vfio_pci_core_try_reset(vdev);
+ pci_restore_state(pdev);
+ return 0;
}
static int vfio_pci_liveupdate_retrieve(struct liveupdate_file_op_args *args)
@@ -43,6 +216,7 @@ static const struct liveupdate_file_ops vfio_pci_liveupdate_file_ops = {
.can_preserve = vfio_pci_liveupdate_can_preserve,
.preserve = vfio_pci_liveupdate_preserve,
.unpreserve = vfio_pci_liveupdate_unpreserve,
+ .freeze = vfio_pci_liveupdate_freeze,
.retrieve = vfio_pci_liveupdate_retrieve,
.finish = vfio_pci_liveupdate_finish,
.owner = THIS_MODULE,
diff --git a/drivers/vfio/pci/vfio_pci_priv.h b/drivers/vfio/pci/vfio_pci_priv.h
index c130ac53c4f9..20d942a7d9b7 100644
--- a/drivers/vfio/pci/vfio_pci_priv.h
+++ b/drivers/vfio/pci/vfio_pci_priv.h
@@ -11,6 +11,10 @@
/* Cap maximum number of ioeventfds per device (arbitrary) */
#define VFIO_PCI_IOEVENTFD_MAX 1000
+extern const struct vfio_device_ops vfio_pci_ops;
+
+void vfio_pci_core_try_reset(struct vfio_pci_core_device *vdev);
+
struct vfio_pci_ioeventfd {
struct list_head next;
struct vfio_pci_core_device *vdev;
@@ -72,6 +76,7 @@ void vfio_pci_zap_and_down_write_memory_lock(struct vfio_pci_core_device *vdev);
u16 vfio_pci_memory_lock_and_enable(struct vfio_pci_core_device *vdev);
void vfio_pci_memory_unlock_and_restore(struct vfio_pci_core_device *vdev,
u16 cmd);
+void vfio_pci_zap_bars(struct vfio_pci_core_device *vdev);
#ifdef CONFIG_VFIO_PCI_IGD
bool vfio_pci_is_intel_display(struct pci_dev *pdev);
diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c
index 8666f35fb3f0..2148b00491e4 100644
--- a/drivers/vfio/vfio_main.c
+++ b/drivers/vfio/vfio_main.c
@@ -1457,7 +1457,7 @@ const struct file_operations vfio_device_fops = {
#endif
};
-static struct vfio_device *vfio_device_from_file(struct file *file)
+struct vfio_device *vfio_device_from_file(struct file *file)
{
struct vfio_device_file *df = file->private_data;
@@ -1465,6 +1465,7 @@ static struct vfio_device *vfio_device_from_file(struct file *file)
return NULL;
return df->device;
}
+EXPORT_SYMBOL_GPL(vfio_device_from_file);
/**
* vfio_file_is_valid - True if the file is valid vfio file
diff --git a/include/linux/kho/abi/vfio_pci.h b/include/linux/kho/abi/vfio_pci.h
index 67e8199eec59..229a13ac1e52 100644
--- a/include/linux/kho/abi/vfio_pci.h
+++ b/include/linux/kho/abi/vfio_pci.h
@@ -9,6 +9,9 @@
#ifndef _LINUX_LIVEUPDATE_ABI_VFIO_PCI_H
#define _LINUX_LIVEUPDATE_ABI_VFIO_PCI_H
+#include <linux/compiler.h>
+#include <linux/types.h>
+
/**
* DOC: VFIO PCI Live Update ABI
*
@@ -25,4 +28,16 @@
#define VFIO_PCI_LUO_FH_COMPATIBLE "vfio-pci-v1"
+/**
+ * struct vfio_pci_core_device_ser - Serialized state of a single VFIO PCI
+ * device.
+ *
+ * @domain: The device's PCI domain number (segment).
+ * @bdf: The device's PCI bus, device, and function number.
+ */
+struct vfio_pci_core_device_ser {
+ u32 domain;
+ u16 bdf;
+} __packed;
+
#endif /* _LINUX_LIVEUPDATE_ABI_VFIO_PCI_H */
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index 31b826efba00..f5f7ece51f8f 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -81,6 +81,8 @@ struct vfio_device {
struct dentry *debug_root;
};
+struct vfio_device *vfio_device_from_file(struct file *file);
+
/**
* struct vfio_device_ops - VFIO bus driver device callbacks
*
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply related
* [PATCH v4 01/16] vfio/pci: Register a file handler with Live Update Orchestrator
From: Vipin Sharma @ 2026-05-11 23:47 UTC (permalink / raw)
To: kvm, linux-doc, linux-kernel, linux-kselftest, linux-pci
Cc: ajayachandra, alex, amastro, ankita, apopple, chrisl, corbet,
dmatlack, graf, jacob.pan, jgg, jgg, jrhilke, julianr, kevin.tian,
leon, leonro, lukas, michal.winiarski, parav, pasha.tatashin,
praan, pratyush, rananta, rientjes, rodrigo.vivi, rppt, saeedm,
skhan, skhawaja, vipinsh, vivek.kasireddy, witu, yanjun.zhu,
yi.l.liu
In-Reply-To: <20260511234802.2280368-1-vipinsh@google.com>
Register a live update file handler for vfio-pci device files. Add stub
implementations of all required callbacks so that registration does not
fail (i.e. to avoid breaking git-bisect).
This file handler will be extended in subsequent commits to enable a
device bound to vfio-pci to run without interruption while the host is
going through a kexec Live Update.
Put this support behind a new Kconfig VFIO_PCI_LIVEUPDATE that is marked
experimental and default-disabled until more of the device preservation
support has landed in the kernel.
Co-developed-by: David Matlack <dmatlack@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
Signed-off-by: Vipin Sharma <vipinsh@google.com>
---
MAINTAINERS | 1 +
drivers/vfio/pci/Kconfig | 12 +++++
drivers/vfio/pci/Makefile | 1 +
drivers/vfio/pci/vfio_pci.c | 11 +++-
drivers/vfio/pci/vfio_pci_liveupdate.c | 70 ++++++++++++++++++++++++++
drivers/vfio/pci/vfio_pci_priv.h | 14 ++++++
include/linux/kho/abi/vfio_pci.h | 28 +++++++++++
7 files changed, 136 insertions(+), 1 deletion(-)
create mode 100644 drivers/vfio/pci/vfio_pci_liveupdate.c
create mode 100644 include/linux/kho/abi/vfio_pci.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 42dbac2c2ed3..b6c33c2bcc7c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27980,6 +27980,7 @@ F: Documentation/ABI/testing/debugfs-vfio
F: Documentation/ABI/testing/sysfs-devices-vfio-dev
F: Documentation/driver-api/vfio.rst
F: drivers/vfio/
+F: include/linux/kho/abi/vfio_pci.h
F: include/linux/vfio.h
F: include/linux/vfio_pci_core.h
F: include/uapi/linux/vfio.h
diff --git a/drivers/vfio/pci/Kconfig b/drivers/vfio/pci/Kconfig
index 296bf01e185e..c12d614fc6c4 100644
--- a/drivers/vfio/pci/Kconfig
+++ b/drivers/vfio/pci/Kconfig
@@ -42,6 +42,18 @@ config VFIO_PCI_IGD
and LPC bridge config space.
To enable Intel IGD assignment through vfio-pci, say Y.
+
+config VFIO_PCI_LIVEUPDATE
+ bool "VFIO PCI support for Live Update (EXPERIMENTAL)"
+ depends on PCI_LIVEUPDATE
+ help
+ Support for preserving devices bound to vfio-pci across a Live
+ Update. This option should only be enabled by developers working on
+ implementing this support. Once enough support has landed in the
+ kernel, this option will no longer be marked EXPERIMENTAL.
+
+ If you don't know what to do here, say N.
+
endif
config VFIO_PCI_ZDEV_KVM
diff --git a/drivers/vfio/pci/Makefile b/drivers/vfio/pci/Makefile
index 6138f1bf241d..bf296ab1c967 100644
--- a/drivers/vfio/pci/Makefile
+++ b/drivers/vfio/pci/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_VFIO_PCI_CORE) += vfio-pci-core.o
vfio-pci-y := vfio_pci.o
vfio-pci-$(CONFIG_VFIO_PCI_IGD) += vfio_pci_igd.o
+vfio-pci-$(CONFIG_VFIO_PCI_LIVEUPDATE) += vfio_pci_liveupdate.o
obj-$(CONFIG_VFIO_PCI) += vfio-pci.o
obj-$(CONFIG_MLX5_VFIO_PCI) += mlx5/
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index 0c771064c0b8..5038265f3af5 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -264,10 +264,14 @@ static int __init vfio_pci_init(void)
vfio_pci_core_set_params(nointxmask, is_disable_vga, disable_idle_d3);
+ ret = vfio_pci_liveupdate_init();
+ if (ret)
+ return ret;
+
/* Register and scan for devices */
ret = pci_register_driver(&vfio_pci_driver);
if (ret)
- return ret;
+ goto err_liveupdate_cleanup;
vfio_pci_fill_ids();
@@ -275,12 +279,17 @@ static int __init vfio_pci_init(void)
pr_warn("device denylist disabled.\n");
return 0;
+
+err_liveupdate_cleanup:
+ vfio_pci_liveupdate_cleanup();
+ return ret;
}
module_init(vfio_pci_init);
static void __exit vfio_pci_cleanup(void)
{
pci_unregister_driver(&vfio_pci_driver);
+ vfio_pci_liveupdate_cleanup();
}
module_exit(vfio_pci_cleanup);
diff --git a/drivers/vfio/pci/vfio_pci_liveupdate.c b/drivers/vfio/pci/vfio_pci_liveupdate.c
new file mode 100644
index 000000000000..1c74854600ea
--- /dev/null
+++ b/drivers/vfio/pci/vfio_pci_liveupdate.c
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (c) 2026, Google LLC.
+ * Vipin Sharma <vipinsh@google.com>
+ * David Matlack <dmatlack@google.com>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/errno.h>
+#include <linux/kho/abi/vfio_pci.h>
+#include <linux/liveupdate.h>
+#include <linux/module.h>
+
+#include "vfio_pci_priv.h"
+
+static bool vfio_pci_liveupdate_can_preserve(struct liveupdate_file_handler *handler,
+ struct file *file)
+{
+ return false;
+}
+
+static int vfio_pci_liveupdate_preserve(struct liveupdate_file_op_args *args)
+{
+ return -EOPNOTSUPP;
+}
+
+static void vfio_pci_liveupdate_unpreserve(struct liveupdate_file_op_args *args)
+{
+}
+
+static int vfio_pci_liveupdate_retrieve(struct liveupdate_file_op_args *args)
+{
+ return -EOPNOTSUPP;
+}
+
+static void vfio_pci_liveupdate_finish(struct liveupdate_file_op_args *args)
+{
+}
+
+static const struct liveupdate_file_ops vfio_pci_liveupdate_file_ops = {
+ .can_preserve = vfio_pci_liveupdate_can_preserve,
+ .preserve = vfio_pci_liveupdate_preserve,
+ .unpreserve = vfio_pci_liveupdate_unpreserve,
+ .retrieve = vfio_pci_liveupdate_retrieve,
+ .finish = vfio_pci_liveupdate_finish,
+ .owner = THIS_MODULE,
+};
+
+static struct liveupdate_file_handler vfio_pci_liveupdate_fh = {
+ .ops = &vfio_pci_liveupdate_file_ops,
+ .compatible = VFIO_PCI_LUO_FH_COMPATIBLE,
+};
+
+int __init vfio_pci_liveupdate_init(void)
+{
+ int ret;
+
+ ret = liveupdate_register_file_handler(&vfio_pci_liveupdate_fh);
+ if (ret && ret != -EOPNOTSUPP)
+ return ret;
+
+ return 0;
+}
+
+void vfio_pci_liveupdate_cleanup(void)
+{
+ liveupdate_unregister_file_handler(&vfio_pci_liveupdate_fh);
+}
diff --git a/drivers/vfio/pci/vfio_pci_priv.h b/drivers/vfio/pci/vfio_pci_priv.h
index fca9d0dfac90..c130ac53c4f9 100644
--- a/drivers/vfio/pci/vfio_pci_priv.h
+++ b/drivers/vfio/pci/vfio_pci_priv.h
@@ -137,4 +137,18 @@ static inline void vfio_pci_dma_buf_move(struct vfio_pci_core_device *vdev,
}
#endif
+#ifdef CONFIG_VFIO_PCI_LIVEUPDATE
+int __init vfio_pci_liveupdate_init(void);
+void vfio_pci_liveupdate_cleanup(void);
+#else
+static inline int vfio_pci_liveupdate_init(void)
+{
+ return 0;
+}
+
+static inline void vfio_pci_liveupdate_cleanup(void)
+{
+}
+#endif /* CONFIG_VFIO_PCI_LIVEUPDATE */
+
#endif
diff --git a/include/linux/kho/abi/vfio_pci.h b/include/linux/kho/abi/vfio_pci.h
new file mode 100644
index 000000000000..67e8199eec59
--- /dev/null
+++ b/include/linux/kho/abi/vfio_pci.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Copyright (c) 2026, Google LLC.
+ * Vipin Sharma <vipinsh@google.com>
+ * David Matlack <dmatlack@google.com>
+ */
+
+#ifndef _LINUX_LIVEUPDATE_ABI_VFIO_PCI_H
+#define _LINUX_LIVEUPDATE_ABI_VFIO_PCI_H
+
+/**
+ * DOC: VFIO PCI Live Update ABI
+ *
+ * VFIO uses the ABI defined below for preserving device files across a kexec
+ * reboot using LUO.
+ *
+ * Device metadata is serialized into memory which is then handed to the next
+ * kernel via KHO.
+ *
+ * This interface is a contract. Any modification to any of the serialization
+ * structs defined here constitutes a breaking change. Such changes require
+ * incrementing the version number in the VFIO_PCI_LUO_FH_COMPATIBLE string.
+ */
+
+#define VFIO_PCI_LUO_FH_COMPATIBLE "vfio-pci-v1"
+
+#endif /* _LINUX_LIVEUPDATE_ABI_VFIO_PCI_H */
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply related
* [PATCH v4 00/16] vfio/pci: Base Live Update support for VFIO
From: Vipin Sharma @ 2026-05-11 23:47 UTC (permalink / raw)
To: kvm, linux-doc, linux-kernel, linux-kselftest, linux-pci
Cc: ajayachandra, alex, amastro, ankita, apopple, chrisl, corbet,
dmatlack, graf, jacob.pan, jgg, jgg, jrhilke, julianr, kevin.tian,
leon, leonro, lukas, michal.winiarski, parav, pasha.tatashin,
praan, pratyush, rananta, rientjes, rodrigo.vivi, rppt, saeedm,
skhan, skhawaja, vipinsh, vivek.kasireddy, witu, yanjun.zhu,
yi.l.liu
Hello,
This series can be found on Github:
https://github.com/shvipin/linux vfio/liveupdate/v4
It adds the base support to enable Live Update feature for VFIO devices.
In v3 of this series, both core PCI subsystem and VFIO changes were
together. Based on the feedbacks on the patches, increasing
complexities and the overall number of patches, we have split the effort
in two parts, PCI and VFIO.
v4 version of PCI work is here:
https://lore.kernel.org/linux-pci/20260423212316.3431746-1-dmatlack@google.com/
This series is the VFIO part, built on top of PCI v4. Going forward,
work on both subsystem will be independent and we may not be making same
version releases in sync. However, VFIO changes will always be on the top of
some version of PCI changes.
Overview
--------
This series made following changes to support VFIO live update:
1. VFIO Live Update feature is put behind VFIO_PCI_LIVEUPDATE config
option. It also requires that VFIO_DEVICE_CDEV config is enabled.
1. To keep things simple in this series, enabling this option will
disable VFIO_PCI_DMABUF. This is temporary.
1. A VFIO cdev FD can be preserved via Live Update session and
retrieved after kexec via the same session.
2. Getting the preserved device FD after kexec via legacy VFIO group
APIs or by directly opening /dev/vfio/devices/vfioX will error out.
User has to get the FD from Live Update subsystem.
3. For now, only FD is preserved, underlying device and its states are
not.
4. To keep the next kernel safe, just before the kexec, VFIO resets
the device, disables BME and restores the original state of the
device. This is temporary and will be removed when we have added
full support of the Live Update.
5. New VFIO selftests have been added which interacts with VFIO
- vfio_pci_liveupdate_uapi_test
- vfio_pci_liveupdate_kexec_test
liveupdate.
6. Documentations have been added for kernel docs.
Dependencies
------------
This series has following dependencies as shown in the diagram
|---------------------------|
| VFIO v4 |
|---------------------------|
| Liveupdate Selftests[1] |
|---------------------------|
| PCI v4 [2] |
|---------------------------|
| Liveupdate Refcount [3] |
|---------------------------|
[1] https://lore.kernel.org/all/20260511201155.1488670-1-vipinsh@google.com/
These selftests changes are needed by other selftests also (iommu, kvm),
so, I have sent them separately.
[2] https://lore.kernel.org/linux-pci/20260423212316.3431746-1-dmatlack@google.com/
This is the PCI v4, which adds the live update support in PCI core.
[3] https://lore.kernel.org/lkml/20260423174032.3140399-1-dmatlack@google.com/
PCI v4 is dependent on this.
Github branch I have mentioned at the top has all of these dependencies.
Testing
-------
Series has been tested using new VFIO live update selftests in both qemu and
bare-metal environment. In bare-metal environment, it was ran using the
Intel DSA PCIe device.
vfio_pci_liveupdate_kexec_test test is executed as following
$ ./setup.sh 0000:00:04.0
$ ./vfio_pci_liveupdate_kexec_test --stage 1 0000:6a:01.0
$ kexec --reuse-cmdline -l -s /boot/vmlinuz
$ kexec -e
$ ./setup.sh 0000:00:04.0
$ ./vfio_pci_liveupdate_kexec_test --stage 2 0000:6a:01.0
Kernel commandline used for booting the VM and testing had following
options passed
- liveupdate=on
- kho=on
- vfio_iommu_type1.allow_unsafe_interrupts=Y
- vfio_pci.enable_sriov=Y
- vfio_pci.disable_denylist=Y
- vfio.enable_unsafe_noiommu_mode=Y
Changelog
---------
v4:
- Addressed sashiko feedback regarding issues in resetting the devize
in freeze
- Dropped the patch which was skipping reset of preserved VFIO device
after kexec when user opens the device. This will be added back in
future but for now not needed as freeze() is also resetting the
device before kexec.
- Kernel doc and comment updates based on feedbacks.
v3: https://lore.kernel.org/kvm/20260323235817.1960573-1-dmatlack@google.com/
v2: https://lore.kernel.org/kvm/20260129212510.967611-1-dmatlack@google.com/
v1: https://lore.kernel.org/kvm/20251126193608.2678510-1-dmatlack@google.com/
rfc: https://lore.kernel.org/kvm/20251018000713.677779-1-vipinsh@google.com/
David Matlack (10):
vfio/pci: Notify PCI subsystem about devices preserved across Live
Update
vfio: Enforce preserved devices are retrieved via
LIVEUPDATE_SESSION_RETRIEVE_FD
vfio/pci: Store incoming Live Update state in struct
vfio_pci_core_device
docs: liveupdate: Add documentation for VFIO PCI
vfio: selftests: Add vfio_pci_liveupdate_uapi_test
vfio: selftests: Add Makefile support for TEST_GEN_PROGS_EXTENDED
vfio: selftests: Expose iommu_modes to tests
vfio: selftests: Expose low-level helper routines for setting up
struct vfio_pci_device
vfio: selftests: Verify that opening VFIO device fails during Live
Update
vfio: selftests: Add continuous DMA to vfio_pci_liveupdate_kexec_test
Vipin Sharma (6):
vfio/pci: Register a file handler with Live Update Orchestrator
vfio/pci: Preserve vfio-pci device files across Live Update
vfio/pci: Retrieve preserved device files after Live Update
vfio: selftests: Build liveupdate library in VFIO selftests
vfio: selftests: Initialize vfio_pci_device using a VFIO cdev FD
vfio: selftests: Add vfio_pci_liveupdate_kexec_test
Documentation/core-api/liveupdate.rst | 1 +
.../driver-api/vfio_pci_liveupdate.rst | 23 ++
MAINTAINERS | 2 +
drivers/vfio/device_cdev.c | 67 +++-
drivers/vfio/group.c | 9 +
drivers/vfio/pci/Kconfig | 16 +-
drivers/vfio/pci/Makefile | 1 +
drivers/vfio/pci/vfio_pci.c | 13 +-
drivers/vfio/pci/vfio_pci_core.c | 62 ++--
drivers/vfio/pci/vfio_pci_liveupdate.c | 349 ++++++++++++++++++
drivers/vfio/pci/vfio_pci_priv.h | 19 +
drivers/vfio/vfio.h | 18 +
drivers/vfio/vfio_main.c | 16 +-
include/linux/kho/abi/vfio_pci.h | 43 +++
include/linux/vfio.h | 13 +
include/linux/vfio_pci_core.h | 2 +
tools/testing/selftests/vfio/Makefile | 23 +-
.../vfio/lib/include/libvfio/iommu.h | 2 +
.../lib/include/libvfio/vfio_pci_device.h | 8 +
tools/testing/selftests/vfio/lib/iommu.c | 4 +-
.../selftests/vfio/lib/vfio_pci_device.c | 60 ++-
.../vfio/vfio_pci_liveupdate_kexec_test.c | 256 +++++++++++++
.../vfio/vfio_pci_liveupdate_uapi_test.c | 93 +++++
23 files changed, 1041 insertions(+), 59 deletions(-)
create mode 100644 Documentation/driver-api/vfio_pci_liveupdate.rst
create mode 100644 drivers/vfio/pci/vfio_pci_liveupdate.c
create mode 100644 include/linux/kho/abi/vfio_pci.h
create mode 100644 tools/testing/selftests/vfio/vfio_pci_liveupdate_kexec_test.c
create mode 100644 tools/testing/selftests/vfio/vfio_pci_liveupdate_uapi_test.c
base-commit: 2a4c0c11c0193889446cdb6f1540cc2b9aff97dd
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply
* Re: [RFC net-next 0/4] devlink: Add boot-time defaults
From: Jakub Kicinski @ 2026-05-11 23:41 UTC (permalink / raw)
To: Jiri Pirko
Cc: Mark Bloch, Eric Dumazet, Paolo Abeni, Andrew Lunn,
David S. Miller, Jonathan Corbet, Shuah Khan, Simon Horman,
Saeed Mahameed, Leon Romanovsky, Tariq Toukan, Andrew Morton,
Borislav Petkov (AMD), Randy Dunlap, Dave Hansen,
Christian Brauner, Petr Mladek, Peter Zijlstra (Intel),
Thomas Gleixner, Pawan Gupta, Dapeng Mi, Kees Cook, Marco Elver,
Eric Biggers, Li RongQing, Paul E. McKenney, linux-doc,
linux-kernel, netdev, linux-rdma
In-Reply-To: <agGOeqeNwJGJ_-2A@FV6GYCPJ69>
On Mon, 11 May 2026 10:42:56 +0200 Jiri Pirko wrote:
> Sun, May 10, 2026 at 06:37:32PM +0200, kuba@kernel.org wrote:
> >On Sat, 9 May 2026 09:01:23 +0200 Jiri Pirko wrote:
> >> Sat, May 09, 2026 at 02:52:13AM +0200, kuba@kernel.org wrote:
> >> As "a non-SR-IOV user", what extra representors you talk about? When you
> >> have pfs only, you don't have anything extra. Just 1 netdev per-pf, one
> >> devlink port per-pf. What's extra about it? When you don't have VFs/SFs.
> >> Everyhing is the same:
> >
> >Some devices have separate uplink ports and PF representors.
> >As I said, what you're proposing isn't going to work for all drivers.
>
> Well, the point is, mlx5 appears to the the one needing this, not other
> drivers. What I'm trying to point at, mlx5 should not need this.
> It makes things compicated, adding a ugly knob for no good reason.
> Legacy/switchdev mode, in both, the non-sriov/eswitch user should not
> see different behaviour. The mode is an eswitch attribute.
>
> devlink dev eswitch set - sets devlink device eswitch attributes
> mode { legacy | switchdev }
> Set eswitch mode
>
> legacy - Legacy SRIOV
>
> switchdev - SRIOV switchdev offloads
>
>
> Briefly looking over other drivers, looks like ice, bnxt, octeon, sfc,
> there is no new entity created in case of switching to switchdev mode.
> The only driver that creates separate pf entities seems to be nfp,
> but the mode seems to be determined by the app being run (loaded
> firmware).
>
> Am I missing something?
Hm. Okay, I wasn't aware that mlx5 was the only driver that did
heavy-duty reinit for switching modes.
> >> I look at it from the perspective that from some CX generation,
> >> switchdev mode should be default. So that is a device-based decision.
> >> I believe as such it can optionally be permanenty configured (nv config)
> >> on older device. Why not?
> >
> >Feels a bit arbitrary and won't cover all cases. The question should be
>
> What cases it does not cover? I don't follow.
Other FW and HW versions. People are still using EOL devices (CX4/CX5),
IIUC the nvmem config path would require FW upgrade.
> >why you are nacking a more reasonable solution. Keeping Linux config in
> >Linux params.
>
> What's reasonable about adding basically a module option (kernel cmdline
> is pretty much the same) for no reason?
The initial patch as posted added this to a mlx5-specific module param.
If we need a module param IMO generic one is much better.
Doesn't matter if other drivers take no time to reinit into switchdev
mode, having to switch mlx5 with a module param and all the rest in
runtime is not the best user experience?
^ permalink raw reply
* Re: [PATCH v17 02/11] cxl/ras: Unify Endpoint and Port AER trace events
From: Dan Williams (nvidia) @ 2026-05-11 23:28 UTC (permalink / raw)
To: Bowman, Terry, Dan Williams (nvidia), Jonathan Cameron
Cc: dave, dave.jiang, alison.schofield, bhelgaas, shiju.jose, ming.li,
Smita.KoralahalliChannabasappa, rrichter, dan.carpenter,
PradeepVineshReddy.Kodamati, lukas, Benjamin.Cheatham,
sathyanarayanan.kuppuswamy, vishal.l.verma, alucerop, ira.weiny,
corbet, rafael, xueshuai, linux-cxl, linux-kernel, linux-pci,
linux-acpi, linux-doc, Mauro Carvalho Chehab
In-Reply-To: <09796934-e093-44e6-b6e2-2d0dd5a29673@amd.com>
Bowman, Terry wrote:
> On 5/8/2026 10:49 PM, Dan Williams (nvidia) wrote:
> > Jonathan Cameron wrote:
> >> On Thu, 7 May 2026 13:33:45 -0500
> >> "Bowman, Terry" <terry.bowman@amd.com> wrote:
> > [..]
> >>>> This concerns me (sorry I wasn't paying attention to the v16 thread).
> >>>> It is a userspace regression against code that is out in the wild and typically
> >>>> not updated in sync with the kernel.
> >>>>
> >>>> If you are suggesting breaking ras-daemon at the very least +CC the maintainer.
> >
> > Sorry, that was not the intent, see below.
> >
> >>>>
> >>>> To get to a unified tracepoint add a new one that does what you want, but
> >>>> maintain the existing ones as well. Userspace can then migrate and maybe
> >>>> in 5+ years time we can delete the non unified ones.
> >>>>
> >>>> No actually comments on the code, just left it all here for Mauro,
> >>>>
> >>>> Thanks,
> >>>>
> >>>> Jonathan
> >>>>
> >>>
> >>> Dan was clear about using a single set of CE and UE handlers for all CXL RAS
> >>> protocol errors. While I understand there may be concerns, please direct any
> >>> objections to Dan and clarify what changes are required to avoid this
> >>> repeatedly going back and forth.
> >>>
> >>> [1] https://lore.kernel.org/linux-cxl/69cb2d5ba3111_178904100b7@dwillia2-mobl4.notmuch/
> >>
> >> Sure - Dan's on this thread so I'm sure he'll see it sooner or later.
> >>
> >> Perhaps I'm missing something that makes this less critical than it appears.
> >
> > No, it is breakage and a thinko on my part on the advice to Terry on the
> > backwards compatibility rules for tracepoints. At the time I was only
> > tracking data type and order of the payload. I.e. string at same
> > position. However, the name of the argument is ABI.
> >
> > Something like this incremental fixup I think gets this back on track.
> > It keeps legacy ABI support for "memdev" field in the payload. It
> > incrementally lets updated userspace understand "port" and "dport"
> > events. It stops us from growing a new set of events just to update the
> > arguments. It enhances the CPER events to now handle switch ports in
> > addition to endpoint ports.
> >
> > The bulk of the change is passing @port and @dport to the CXL trace
> > events instead of a plain @dev.
> >
>
> Thanks Dan and Jonathan,
>
> I have a few questions.
>
> Does this miss logging the Upstream SwitchPort device errors? Add another
> entry "uport=$"?
>
> How does the user know which of the devices (memdev, port, or dport) is the
> erroring device? Do the traces need another string variable inidicating which
> device triggered the error?
I expect that can be determined from what values get populated.
Endpoint:
memdev=memX port=endpointY dport= host=parent(memX)
Downstream:
memdev= port=portX dport=dport_dev(dportY) host=uport_dev(portX)
Upstream:
memdev= port=portX dport= host=uport_dev(portX)
If dport= is populated, that is the device that triggered the error,
otherwise it is the host= value.
> And, I need to confirm: the Endpoint is NULL unless the CXL Port is an Endpoint
> Port?
You mean memdev is empty, right?
^ permalink raw reply
* Re: [PATCH] killswitch: add per-function short-circuit mitigation primitive
From: Sasha Levin @ 2026-05-11 23:05 UTC (permalink / raw)
To: Andrew Morton
Cc: Michal Hocko, Breno Leitao, corbet, skhan, linux-doc,
linux-kernel, linux-kselftest, gregkh
In-Reply-To: <20260511153158.bad58633e2c8d247322ebb4b@linux-foundation.org>
On Mon, May 11, 2026 at 03:31:58PM -0700, Andrew Morton wrote:
>On Mon, 11 May 2026 15:07:51 +0200 Michal Hocko <mhocko@suse.com> wrote:
>
>> > 2) It's common to run hundreds of different kernel versions across a
>> > fleet. Since livepatch is kernel-specific, a single CVE suddenly
>> > requires building and deploying hundreds of individual livepatches—
>> > far less practical than a simple sysfs write.
>>
>> LP is certainly a more laborous solution.
>
><another please-educate-akpm email>
>
>Does a livepatch *have* to be distributed as a ready-to-load kernel
>module?
>
>Is it not possible to distribute a "livepatch" to the fleet as a single
>string? Send out "make function some_bad_function() return -EINVAL"
>and let scripting on each machine figure out how to locally write,
>build, sign and install such a livepatch?
>
>That would require that each machine locally contains enough data for
>it to be able to build a kernel for the currently-running kernel, and
>that each machine contains a build environment.
So we'll need to have a kernel build env, the sources for the current kernel,
debug info, and some sort of a semantic patch (.cocci?) to make the
transformation. I think we could even script all of that per-distro, yes.
>I *think* this is feasible on distro-based machines? But perhaps not
>on stripped-down hyperscalar boxen?
Few concerns:
1. Tiny/embedded machines that will have a really hard time building a kernel
either because of storage, CPU power, etc... Consider something like your home
router running OpenWRT.
Actually, this is a good example for a killswitch too I think. I went digging
for issues that would affect OpenWRT routers, and
https://www.cve.org/CVERecord?id=CVE-2024-1086 is a good example: OpenWRT
supports user namespaces to allow containers to run on the router, so any
container could then compromise the router.
There's no way to build kernel modules on the router - no toolchain nor storage.
With killswitch, you could simply do something like:
echo "engage nft_verdict_init -1" > /sys/kernel/security/killswitch/control
Which, if I understand the code correctly, would disable us from adding any new
netfilter rules, but existing rules would keep working (and on most routers the
rules are fairly static).
2. Having to install a build env is not only wasteful but also not secure. For
example, a certain hyperscaler we both know does not allow compilers on
production machines. It's probably a good practice for regular distro based
machines too.
3. With secure boot a user can't load their own unsigned modules, so the user
will need to spin their own kernel and enroll their keys. Having to turn off
secure boot is a really bad solution too.
4. Nightmare as far as reproducibility goes: think of all the odd
compiler/toolchain/etc combos you'll encounter. No way to track what went
wrong, where, and how.
--
Thanks,
Sasha
^ permalink raw reply
* Re: [PATCH] killswitch: add per-function short-circuit mitigation primitive
From: Song Liu @ 2026-05-11 23:01 UTC (permalink / raw)
To: Andrew Morton
Cc: Michal Hocko, Breno Leitao, Sasha Levin, corbet, skhan, linux-doc,
linux-kernel, linux-kselftest, gregkh
In-Reply-To: <20260511153158.bad58633e2c8d247322ebb4b@linux-foundation.org>
On Mon, May 11, 2026 at 3:32 PM Andrew Morton <akpm@linux-foundation.org> wrote:
>
> On Mon, 11 May 2026 15:07:51 +0200 Michal Hocko <mhocko@suse.com> wrote:
>
> > > 2) It's common to run hundreds of different kernel versions across a
> > > fleet. Since livepatch is kernel-specific, a single CVE suddenly
> > > requires building and deploying hundreds of individual livepatches—
> > > far less practical than a simple sysfs write.
> >
> > LP is certainly a more laborous solution.
>
> <another please-educate-akpm email>
>
> Does a livepatch *have* to be distributed as a ready-to-load kernel
> module?
As of today, livepatch is loaded to the kernel as a module. It requires
kernel config CONFIG_LIVEPATCH. If CONFIG_LIVEPATCH is not
set in the running kernel, livepatch module won't work.
> Is it not possible to distribute a "livepatch" to the fleet as a single
> string? Send out "make function some_bad_function() return -EINVAL"
> and let scripting on each machine figure out how to locally write,
> build, sign and install such a livepatch?
With CONFIG_LIVEPATCH, and with proper toolchain and keys,
this is surely possible. But I guess this comes with some security
concerns (sharing the keys, etc.).
> That would require that each machine locally contains enough data for
> it to be able to build a kernel for the currently-running kernel, and
> that each machine contains a build environment.
>
> I *think* this is feasible on distro-based machines? But perhaps not
> on stripped-down hyperscalar boxen?
Do most distro machines have CONFIG_LIVEPATCH enabled?
AFAICT, Ubuntu 26.04 does have it enabled.
Thanks,
Song
^ permalink raw reply
* Re: [PATCH v6 01/22] mm/swap: decouple swap cache from physical swap infrastructure
From: Yosry Ahmed @ 2026-05-11 22:46 UTC (permalink / raw)
To: Nhat Pham
Cc: kasong, Liam.Howlett, akpm, apopple, axelrasmussen, baohua,
baolin.wang, bhe, byungchul, cgroups, chengming.zhou, chrisl,
corbet, david, dev.jain, gourry, hannes, hughd, jannh,
joshua.hahnjy, lance.yang, lenb, linux-doc, linux-kernel,
linux-mm, linux-pm, lorenzo.stoakes, matthew.brost, mhocko,
muchun.song, npache, pavel, peterx, peterz, pfalcato, rafael,
rakie.kim, roman.gushchin, rppt, ryan.roberts, shakeel.butt,
shikemeng, surenb, tglx, vbabka, weixugc, ying.huang, yosry.ahmed,
yuanchu, zhengqi.arch, ziy, kernel-team, riel, haowenchao22
In-Reply-To: <20260505153854.1612033-2-nphamcs@gmail.com>
On Tue, May 05, 2026 at 08:38:30AM -0700, Nhat Pham wrote:
> When we virtualize the swap space, we will manage swap cache at the
> virtual swap layer. To prepare for this, decouple swap cache from
> physical swap infrastructure.
>
> We will also remove all the swap cache related helpers of swap table. We
> will keep the rest of the swap table infrastructure, which will be
> repurposed to serve as the rmap (physical -> virtual swap mapping)
> later.
I didn't look through the entire series, but let me ask the same
high-level question I asked before. Instead of moving things out of the
swap table, why not reuse the swap table as the representation of the
virtual swap space? Seems like most/all metadata is already moved there
in a nice concise format.
>
> Note that with this patch, we will move to a single global lock to
> synchronize swap cache accesses. This is temporarily, as the swap cache
> will be re-partitioned in to (virtual) swap clusters once we move the
> swap cache to the soon-to-be-introduced virtual swap layer.
>
> Signed-off-by: Nhat Pham <nphamcs@gmail.com>
^ permalink raw reply
* Re: [RFC PATCH 3/5] mm: zswap: load fully stored large folios
From: Yosry Ahmed @ 2026-05-11 22:38 UTC (permalink / raw)
To: fujunjie
Cc: Andrew Morton, Johannes Weiner, Chris Li, Kairui Song, Nhat Pham,
linux-mm, linux-kernel, linux-doc, Jonathan Corbet,
David Hildenbrand, Ryan Roberts, Barry Song, Baolin Wang,
Chengming Zhou, Baoquan He, Lorenzo Stoakes, Michal Hocko,
Roman Gushchin, Shakeel Butt
In-Reply-To: <tencent_69E7E93D1E47766E922D48B9EA9FD1140D09@qq.com>
On Fri, May 08, 2026 at 08:20:31PM +0000, fujunjie wrote:
> zswap_store() already stores every base page of a large folio as a
> separate zswap entry and tears the whole folio back down on store
> failure. The load side still rejects any large folio, which forces the
> swapin path to avoid mTHP swapin once zswap has ever been enabled.
>
> Use zswap_entry_batch() to distinguish three cases: the whole range is
> absent from zswap and should fall through to the disk backend, the whole
> range is present and can be decompressed one base page at a time, or the
> range is mixed and must be treated as an invalid large-folio backend
> selection.
>
> After all entries decompress successfully, mark the folio uptodate and
> dirty, account the mTHP swpin stat once for the folio, account one ZSWPIN
> event per base page, and invalidate each zswap entry because the
> swapcache folio becomes authoritative.
>
> Signed-off-by: fujunjie <fujunjie1@qq.com>
> ---
> Documentation/admin-guide/mm/transhuge.rst | 4 +-
> mm/zswap.c | 65 ++++++++++++++--------
> 2 files changed, 45 insertions(+), 24 deletions(-)
>
> diff --git a/Documentation/admin-guide/mm/transhuge.rst b/Documentation/admin-guide/mm/transhuge.rst
> index 5fbc3d89bb07..05456906aff6 100644
> --- a/Documentation/admin-guide/mm/transhuge.rst
> +++ b/Documentation/admin-guide/mm/transhuge.rst
> @@ -644,8 +644,8 @@ zswpout
> piece without splitting.
>
> swpin
> - is incremented every time a huge page is swapped in from a non-zswap
> - swap device in one piece.
> + is incremented every time a huge page is swapped in from swap I/O or
> + zswap in one piece.
>
> swpin_fallback
> is incremented if swapin fails to allocate or charge a huge page
> diff --git a/mm/zswap.c b/mm/zswap.c
> index 27c14b8edd15..863ca1e896ed 100644
> --- a/mm/zswap.c
> +++ b/mm/zswap.c
> @@ -28,6 +28,7 @@
> #include <crypto/acompress.h>
> #include <crypto/scatterwalk.h>
> #include <linux/zswap.h>
> +#include <linux/huge_mm.h>
> #include <linux/mm_types.h>
> #include <linux/page-flags.h>
> #include <linux/swapops.h>
> @@ -1614,20 +1615,23 @@ bool zswap_store(struct folio *folio)
> * NOT marked up-to-date, so that an IO error is emitted (e.g. do_swap_page()
> * will SIGBUS).
> *
> - * -EINVAL: if the swapped out content was in zswap, but the page belongs
> - * to a large folio, which is not supported by zswap. The folio is unlocked,
> - * but NOT marked up-to-date, so that an IO error is emitted (e.g.
> - * do_swap_page() will SIGBUS).
> + * -EINVAL: if the folio spans a mix of zswap and non-zswap entries. The
> + * folio is unlocked, but NOT marked up-to-date, so that an IO error is
> + * emitted (e.g. do_swap_page() will SIGBUS). Large folio swapin should
> + * reject such ranges before calling zswap_load().
> *
> - * -ENOENT: if the swapped out content was not in zswap. The folio remains
> + * -ENOENT: if the swapped out content was not in zswap. For a large folio,
> + * this means the whole folio range was not in zswap. The folio remains
> * locked on return.
> */
> int zswap_load(struct folio *folio)
> {
> swp_entry_t swp = folio->swap;
> pgoff_t offset = swp_offset(swp);
> - struct xarray *tree = swap_zswap_tree(swp);
> struct zswap_entry *entry;
> + int nr_pages = folio_nr_pages(folio);
> + bool is_zswap;
> + int index;
>
> VM_WARN_ON_ONCE(!folio_test_locked(folio));
> VM_WARN_ON_ONCE(!folio_test_swapcache(folio));
> @@ -1635,30 +1639,36 @@ int zswap_load(struct folio *folio)
> if (zswap_never_enabled())
> return -ENOENT;
>
> - /*
> - * Large folios should not be swapped in while zswap is being used, as
> - * they are not properly handled. Zswap does not properly load large
> - * folios, and a large folio may only be partially in zswap.
> - */
> - if (WARN_ON_ONCE(folio_test_large(folio))) {
> + if (zswap_entry_batch(swp, nr_pages, &is_zswap) != nr_pages) {
> + WARN_ON_ONCE(folio_test_large(folio));
IIUC the condition can only be true for large folios, so I think just
WARN_ON_ONCE() in the if statement itself?
Taking a step back, this is doing xa_load() lookups that are repeated
again below. Maybe we should drop this check here and integrate the
check into the loop below (either all entries exist or don't)?
We might end up with a case where we decompress some parts of the folio
then return a failure, but this possibility already exists (e.g.
decompression failures).
> folio_unlock(folio);
> return -EINVAL;
> }
>
> - entry = xa_load(tree, offset);
> - if (!entry)
> + if (!is_zswap)
> return -ENOENT;
>
> - if (!zswap_decompress(entry, folio, 0)) {
> - folio_unlock(folio);
> - return -EIO;
> + for (index = 0; index < nr_pages; index++) {
> + swp_entry_t entry_swp = swp_entry(swp_type(swp),
> + offset + index);
> + struct xarray *tree = swap_zswap_tree(entry_swp);
> +
> + entry = xa_load(tree, offset + index);
> + if (WARN_ON_ONCE(!entry)) {
> + folio_unlock(folio);
> + return -EINVAL;
> + }
> +
> + if (!zswap_decompress(entry, folio, index)) {
> + folio_unlock(folio);
> + return -EIO;
> + }
> }
>
> folio_mark_uptodate(folio);
>
> - count_vm_event(ZSWPIN);
> - if (entry->objcg)
> - count_objcg_events(entry->objcg, ZSWPIN, 1);
> + count_mthp_stat(folio_order(folio), MTHP_STAT_SWPIN);
Not a problem with this patch, but I wonder why different swapin
implementations are making this call instead of putting it in a
higher-level (e.g. alloc_swap_folio()).
> + count_vm_events(ZSWPIN, nr_pages);
>
> /*
> * We are reading into the swapcache, invalidate zswap entry.
> @@ -1668,8 +1678,19 @@ int zswap_load(struct folio *folio)
> * compression work.
> */
> folio_mark_dirty(folio);
> - xa_erase(tree, offset);
> - zswap_entry_free(entry);
> +
> + for (index = 0; index < nr_pages; index++) {
> + swp_entry_t entry_swp = swp_entry(swp_type(swp),
> + offset + index);
> + struct xarray *tree = swap_zswap_tree(entry_swp);
> +
> + entry = xa_erase(tree, offset + index);
> + if (WARN_ON_ONCE(!entry))
> + continue;
> + if (entry->objcg)
> + count_objcg_events(entry->objcg, ZSWPIN, 1);
Hmm I was wondering how the stat update should be handled here. It is
possible that a folio was swapped out from one memcg and is being
swapped in by a process in a different memcg. For order-0 folios, the
folio gets charged to the swapout memcg.
However, looking at alloc_swap_folio() ->
mem_cgroup_swapin_charge_folio(), it seems like we charge mTHP folios to
the swapout memcg of the first swap entry. This seems a bit arbitrary.
Focusing at the code here, seems like we'll count the swapin against the
swapout memcg, which is good in terms of keeping ZSWPIN and ZSWPOUT
balanced. However, it seems like it's possible that the folio is being
charged to a different memcg here than the swapout memcg, so we may end
up counting ZSWPIN in one memcg but charging the folio in another.
I am not sure if this is practically a problem, but something doesn't
sound right. Johannes (and other memcg folks), were these the intended
charging semantics for mTHP swapin? Is it reasonable to count ZSWPIN in
one memcg and charge the folio in another?
> + zswap_entry_free(entry);
> + }
>
> folio_unlock(folio);
> return 0;
> --
> 2.34.1
>
>
^ permalink raw reply
* Re: [PATCH v17 10/11] PCI/CXL: Mask/Unmask CXL protocol errors
From: Dave Jiang @ 2026-05-11 22:36 UTC (permalink / raw)
To: Bowman, Terry, dave, jic23, alison.schofield, djbw, bhelgaas,
shiju.jose, ming.li, Smita.KoralahalliChannabasappa, rrichter,
dan.carpenter, PradeepVineshReddy.Kodamati, lukas,
Benjamin.Cheatham, sathyanarayanan.kuppuswamy, vishal.l.verma,
alucerop, ira.weiny, corbet, rafael, xueshuai, linux-cxl
Cc: linux-kernel, linux-pci, linux-acpi, linux-doc
In-Reply-To: <8ab3325b-175f-4664-a046-6f4b1d472816@amd.com>
On 5/11/26 2:04 PM, Bowman, Terry wrote:
> On 5/6/2026 1:00 PM, Dave Jiang wrote:
>>
>>
>> On 5/5/26 10:30 AM, Terry Bowman wrote:
>>> CXL protocol errors are not enabled for all CXL devices after boot. They
>>> must be enabled in order to process CXL protocol errors. Provide matching
>>> teardown helpers so the masks are restored when a CXL Port or Downstream
>>> Port goes away.
>>>
>>> Add pci_aer_mask_internal_errors() as the symmetric counterpart to
>>> pci_aer_unmask_internal_errors() and export both for the cxl_core module.
>>>
>>> Introduce cxl_unmask_proto_interrupts() and cxl_mask_proto_interrupts()
>>> in cxl_core to wrap the PCI helpers with the dev_is_pci() and
>>> pcie_aer_is_native() gating CXL needs. Both helpers tolerate a NULL
>>> @dev so teardown callers do not have to special-case it.
>>>
>>> Wire cxl_unmask_proto_interrupts() into the success path of
>>> cxl_dport_map_ras() and devm_cxl_port_ras_setup() so the unmask only
>>> runs when the RAS register block was actually mapped. Pair each unmask
>>> with a devm_add_action_or_reset() registration of
>>> cxl_mask_proto_interrupts() scoped to the cxl_port device. The mask is
>>> then restored when the cxl_port device releases its devres. This
>>> applies to Endpoints, Upstream Switch Ports, Downstream Switch Ports,
>>> and Root Ports.
>>>
>>> Co-developed-by: Dan Williams <djbw@kernel.org>
>>> Signed-off-by: Dan Williams <djbw@kernel.org>
>>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>>
>> Reviewed-by: Dave Jiang <dave.jiang@intel.com>
>>
>> I do wonder if we should save the original mask values and write those back rather than blindly remask everything when we are done.
>>
>>
>
> Hi Dave,
>
> This is only masking/unmasking the internal error bit. The other mask bits are not
> modified.
Hi Terry,
My point is we lost the original register values for internal error on exit. We probably should restore whatever was in the register before we unmasked. Currently it comes to us with everything masked. But maybe in the future in may not be and we don't want to go chasing that side effect.
DJ
>
> - Terry
>
>
>>>
>>> ---
>>>
>>> Changes in v16->v17:
>>> - Drop redundant cxl_mask_proto_interrupts() calls from unregister_port()
>>> and cxl_dport_remove(); the devres action registered alongside the unmask
>>> is the sole mask path.
>>> - Update title
>>> - Remove unnecessary check for aer_capabilities
>>> - Gate cxl_unmask_proto_interrupts() on pcie_aer_is_native()
>>> - Add pci_aer_mask_internal_errors() and cxl_mask_proto_interrupts()
>>> - Only unmask on successful cxl_map_component_regs()
>>> - NULL-check @dev in cxl_{un,}mask_proto_interrupts()
>>> - Drop static and declare in core/core.h
>>>
>>> Change in v15 -> v16:
>>> - None
>>>
>>> Change in v14 -> v15:
>>> - None
>>>
>>> Changes in v13->v14:
>>> - Update commit title's prefix (Bjorn)
>>>
>>> Changes in v12->v13:
>>> - Add dev and dev_is_pci() NULL checks in cxl_unmask_proto_interrupts() (Terry)
>>> - Add Dave Jiang's and Ben's review-by
>>>
>>> Changes in v11->v12:
>>> - None
>>> ---
>>> drivers/cxl/core/core.h | 4 +++
>>> drivers/cxl/core/ras.c | 63 ++++++++++++++++++++++++++++++++++++++---
>>> drivers/pci/pcie/aer.c | 25 ++++++++++++++++
>>> include/linux/aer.h | 2 ++
>>> 4 files changed, 90 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
>>> index 2c7387506dfb..ff39985d363f 100644
>>> --- a/drivers/cxl/core/core.h
>>> +++ b/drivers/cxl/core/core.h
>>> @@ -190,6 +190,8 @@ void cxl_dport_map_rch_aer(struct cxl_dport *dport);
>>> void cxl_disable_rch_root_ints(struct cxl_dport *dport);
>>> void cxl_handle_rdport_errors(struct pci_dev *pdev);
>>> void devm_cxl_dport_ras_setup(struct cxl_dport *dport);
>>> +void cxl_unmask_proto_interrupts(struct device *dev);
>>> +void cxl_mask_proto_interrupts(struct device *dev);
>>> #else
>>> static inline int cxl_ras_init(void)
>>> {
>>> @@ -207,6 +209,8 @@ static inline void cxl_dport_map_rch_aer(struct cxl_dport *dport) { }
>>> static inline void cxl_disable_rch_root_ints(struct cxl_dport *dport) { }
>>> static inline void cxl_handle_rdport_errors(struct pci_dev *pdev) { }
>>> static inline void devm_cxl_dport_ras_setup(struct cxl_dport *dport) { }
>>> +static inline void cxl_unmask_proto_interrupts(struct device *dev) { }
>>> +static inline void cxl_mask_proto_interrupts(struct device *dev) { }
>>> #endif /* CONFIG_CXL_RAS */
>>>
>>> int cxl_gpf_port_setup(struct cxl_dport *dport);
>>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>>> index a98ce0f412ad..b45e2b539b5f 100644
>>> --- a/drivers/cxl/core/ras.c
>>> +++ b/drivers/cxl/core/ras.c
>>> @@ -66,16 +66,59 @@ static void cxl_cper_prot_err_work_fn(struct work_struct *work)
>>> }
>>> static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
>>>
>>> +void cxl_unmask_proto_interrupts(struct device *dev)
>>> +{
>>> + struct pci_dev *pdev;
>>> +
>>> + if (!dev || !dev_is_pci(dev))
>>> + return;
>>> +
>>> + pdev = to_pci_dev(dev);
>>> + if (!pcie_aer_is_native(pdev))
>>> + return;
>>> +
>>> + pci_aer_unmask_internal_errors(pdev);
>>> +}
>>> +
>>> +void cxl_mask_proto_interrupts(struct device *dev)
>>> +{
>>> + struct pci_dev *pdev;
>>> +
>>> + if (!dev || !dev_is_pci(dev))
>>> + return;
>>> +
>>> + pdev = to_pci_dev(dev);
>>> + if (!pcie_aer_is_native(pdev))
>>> + return;
>>> +
>>> + pci_aer_mask_internal_errors(pdev);
>>> +}
>>> +
>>> +static void cxl_mask_proto_irqs(void *dev)
>>> +{
>>> + cxl_mask_proto_interrupts(dev);
>>> +}
>>> +
>>> static void cxl_dport_map_ras(struct cxl_dport *dport)
>>> {
>>> struct cxl_register_map *map = &dport->reg_map;
>>> struct device *dev = dport->dport_dev;
>>>
>>> - if (!map->component_map.ras.valid)
>>> + if (!map->component_map.ras.valid) {
>>> dev_dbg(dev, "RAS registers not found\n");
>>> - else if (cxl_map_component_regs(map, &dport->regs.component,
>>> - BIT(CXL_CM_CAP_CAP_ID_RAS)))
>>> + return;
>>> + }
>>> +
>>> + if (cxl_map_component_regs(map, &dport->regs.component,
>>> + BIT(CXL_CM_CAP_CAP_ID_RAS))) {
>>> dev_dbg(dev, "Failed to map RAS capability.\n");
>>> + return;
>>> + }
>>> +
>>> + cxl_unmask_proto_interrupts(dev);
>>> + if (devm_add_action_or_reset(dport_to_host(dport),
>>> + cxl_mask_proto_irqs, dev))
>>> + dev_warn(dev, "failed to register CXL proto-irq mask cleanup\n");
>>> }
>>>
>>> /**
>>> @@ -109,6 +152,7 @@ EXPORT_SYMBOL_NS_GPL(devm_cxl_dport_rch_ras_setup, "CXL");
>>> void devm_cxl_port_ras_setup(struct cxl_port *port)
>>> {
>>> struct cxl_register_map *map = &port->reg_map;
>>> + struct device *dev;
>>>
>>> if (!map->component_map.ras.valid) {
>>> dev_dbg(&port->dev, "RAS registers not found\n");
>>> @@ -117,8 +161,19 @@ void devm_cxl_port_ras_setup(struct cxl_port *port)
>>>
>>> map->host = &port->dev;
>>> if (cxl_map_component_regs(map, &port->regs,
>>> - BIT(CXL_CM_CAP_CAP_ID_RAS)))
>>> + BIT(CXL_CM_CAP_CAP_ID_RAS))) {
>>> dev_dbg(&port->dev, "Failed to map RAS capability\n");
>>> + return;
>>> + }
>>> +
>>> + dev = is_cxl_endpoint(port) ? port->uport_dev->parent : port->uport_dev;
>>> + if (!dev_is_pci(dev))
>>> + return;
>>> +
>>> + cxl_unmask_proto_interrupts(dev);
>>> + if (devm_add_action_or_reset(&port->dev, cxl_mask_proto_irqs, dev))
>>> + dev_warn(&port->dev,
>>> + "Failed to register CXL proto-irq mask cleanup\n");
>>> }
>>> EXPORT_SYMBOL_NS_GPL(devm_cxl_port_ras_setup, "CXL");
>>>
>>> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
>>> index b9c6c7b97217..eaa36fe0eb31 100644
>>> --- a/drivers/pci/pcie/aer.c
>>> +++ b/drivers/pci/pcie/aer.c
>>> @@ -1151,6 +1151,31 @@ void pci_aer_unmask_internal_errors(struct pci_dev *dev)
>>> */
>>> EXPORT_SYMBOL_FOR_MODULES(pci_aer_unmask_internal_errors, "cxl_core");
>>>
>>> +/**
>>> + * pci_aer_mask_internal_errors - mask internal errors
>>> + * @dev: pointer to the pci_dev data structure
>>> + *
>>> + * Mask internal errors in the Uncorrectable and Correctable Error
>>> + * Mask registers.
>>> + *
>>> + * Note: AER must be enabled and supported by the device which must be
>>> + * checked in advance, e.g. with pcie_aer_is_native().
>>> + */
>>> +void pci_aer_mask_internal_errors(struct pci_dev *dev)
>>> +{
>>> + int aer = dev->aer_cap;
>>> + u32 mask;
>>> +
>>> + pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_MASK, &mask);
>>> + mask |= PCI_ERR_UNC_INTN;
>>> + pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_MASK, mask);
>>> +
>>> + pci_read_config_dword(dev, aer + PCI_ERR_COR_MASK, &mask);
>>> + mask |= PCI_ERR_COR_INTERNAL;
>>> + pci_write_config_dword(dev, aer + PCI_ERR_COR_MASK, mask);
>>> +}
>>> +EXPORT_SYMBOL_FOR_MODULES(pci_aer_mask_internal_errors, "cxl_core");
>>> +
>>> /**
>>> * pci_aer_handle_error - handle logging error into an event log
>>> * @dev: pointer to pci_dev data structure of error source device
>>> diff --git a/include/linux/aer.h b/include/linux/aer.h
>>> index 979ed2f9fd38..c52db62d4c7e 100644
>>> --- a/include/linux/aer.h
>>> +++ b/include/linux/aer.h
>>> @@ -71,6 +71,7 @@ int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
>>> void pci_aer_clear_fatal_status(struct pci_dev *dev);
>>> int pcie_aer_is_native(struct pci_dev *dev);
>>> void pci_aer_unmask_internal_errors(struct pci_dev *dev);
>>> +void pci_aer_mask_internal_errors(struct pci_dev *dev);
>>> #else
>>> static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
>>> {
>>> @@ -79,6 +80,7 @@ static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
>>> static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
>>> static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }
>>> static inline void pci_aer_unmask_internal_errors(struct pci_dev *dev) { }
>>> +static inline void pci_aer_mask_internal_errors(struct pci_dev *dev) { }
>>> #endif
>>>
>>> #ifdef CONFIG_CXL_RAS
>>
>
^ permalink raw reply
* Re: [PATCH] killswitch: add per-function short-circuit mitigation primitive
From: Andrew Morton @ 2026-05-11 22:31 UTC (permalink / raw)
To: Michal Hocko
Cc: Breno Leitao, Sasha Levin, corbet, skhan, linux-doc, linux-kernel,
linux-kselftest, gregkh
In-Reply-To: <agHUp8ulaWJ75WU5@tiehlicka>
On Mon, 11 May 2026 15:07:51 +0200 Michal Hocko <mhocko@suse.com> wrote:
> > 2) It's common to run hundreds of different kernel versions across a
> > fleet. Since livepatch is kernel-specific, a single CVE suddenly
> > requires building and deploying hundreds of individual livepatches—
> > far less practical than a simple sysfs write.
>
> LP is certainly a more laborous solution.
<another please-educate-akpm email>
Does a livepatch *have* to be distributed as a ready-to-load kernel
module?
Is it not possible to distribute a "livepatch" to the fleet as a single
string? Send out "make function some_bad_function() return -EINVAL"
and let scripting on each machine figure out how to locally write,
build, sign and install such a livepatch?
That would require that each machine locally contains enough data for
it to be able to build a kernel for the currently-running kernel, and
that each machine contains a build environment.
I *think* this is feasible on distro-based machines? But perhaps not
on stripped-down hyperscalar boxen?
^ permalink raw reply
* [PATCH AUTOSEL 7.0-6.6] docs: cgroup-v1: Update charge-commit section
From: Sasha Levin @ 2026-05-11 22:19 UTC (permalink / raw)
To: patches, stable
Cc: T.J. Mercier, Tejun Heo, Sasha Levin, lizefan.x, hannes, corbet,
cgroups, linux-doc, linux-kernel
In-Reply-To: <20260511221931.2370053-1-sashal@kernel.org>
From: "T.J. Mercier" <tjmercier@google.com>
[ Upstream commit d8769544bde51b0ac980d10f8fe9f9fed6c95995 ]
Commit 1d8f136a421f ("memcg/hugetlb: remove memcg hugetlb
try-commit-cancel protocol") removed mem_cgroup_commit_charge() and
mem_cgroup_cancel_charge(), but the docs still refer to those functions.
There is no longer any charge cancellation.
Update the docs to match the code.
Signed-off-by: T.J. Mercier <tjmercier@google.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
Step 1.1 Record: subsystem `docs: cgroup-v1`; action verb `Update`;
intent: update `Documentation/admin-guide/cgroup-v1/memcg_test.rst` so
the charge-commit section matches current memcg code.
Step 1.2 Record: tags present: `Signed-off-by: T.J. Mercier
<tjmercier@google.com>` and `Signed-off-by: Tejun Heo <tj@kernel.org>`.
No `Fixes:`, `Reported-by:`, `Tested-by:`, `Reviewed-by:`, `Acked-by:`,
`Link:`, or `Cc: stable@vger.kernel.org` tags in the committed message.
Step 1.3 Record: the body says commit `1d8f136a421f` removed
`mem_cgroup_commit_charge()` and `mem_cgroup_cancel_charge()`, while the
cgroup-v1 memcg docs still name them and describe cancellation.
Symptom/failure mode: incorrect documentation only. Version information:
the referenced removal commit is from 2025-01-13 in the local object
database; candidate commit is from 2026-04-30. Root cause: docs were not
updated when the code was changed.
Step 1.4 Record: this is not a hidden runtime bug fix. It is an explicit
documentation correctness fix.
## Phase 2: Diff Analysis
Step 2.1 Record: one file changed: `Documentation/admin-
guide/cgroup-v1/memcg_test.rst`, `2 insertions(+), 4 deletions(-)`. No
functions modified. Scope: single-file documentation-only surgical
change.
Step 2.2 Record: before, the section was titled `charge-commit-cancel`,
listed `mem_cgroup_commit_charge()` or `mem_cgroup_cancel_charge()`, and
described `cancel()`. After, it is titled `charge-commit`, lists
`commit_charge()`, and removes the cancellation text.
Step 2.3 Record: bug category is documentation/comment correctness.
Specific mechanism: removes stale references to APIs that are absent in
current `6.19.y`/`7.0.y` code and in `origin/master`.
Step 2.4 Record: fix quality is obviously correct for trees whose memcg
code no longer has `mem_cgroup_commit_charge()` /
`mem_cgroup_cancel_charge()`. Regression risk is zero runtime risk, but
there is a branch-selection concern: `stable/linux-6.12.y` still
contains those functions, so this exact doc update would be misleading
there.
## Phase 3: Git History Investigation
Step 3.1 Record: `git blame` before the candidate shows the stale doc
lines came from `f3f5edc5e41e` in this repository’s history. `git blame
origin/master` shows the changed lines attributed to `d8769544bde51`.
Step 3.2 Record: no `Fixes:` tag. I still inspected referenced commit
`1d8f136a421f26747e58c01281cba5bffae8d289`; it removed prototypes and
implementations for `mem_cgroup_commit_charge()`,
`mem_cgroup_cancel_charge()`, and related hugetlb try/commit/cancel
helpers.
Step 3.3 Record: recent history for `Documentation/admin-
guide/cgroup-v1/memcg_test.rst` on `origin/master` has only the file
introduction/import commit and this candidate. Related path history
shows the candidate was merged via `cgroup-for-7.1-rc2-fixes`. No
prerequisite doc series found.
Step 3.4 Record: author `T.J. Mercier` has at least one other cgroup-
related commit in `origin/master`; Tejun Heo is listed in `MAINTAINERS`
as cgroup maintainer and committed the patch.
Step 3.5 Record: no code dependencies for the patch itself. It can apply
standalone to the current `stable/linux-7.0.y` checkout. Applicability
must be gated by whether the target tree’s code has removed the old
APIs.
## Phase 4: Mailing List And External Research
Step 4.1 Record: `b4 dig -c d8769544bde51...` found the original
submission at
`https://patch.msgid.link/20260430201142.240387-1-tjmercier@google.com`.
`b4 dig -a` found only v1 of a single-patch series. The mbox contains
Tejun’s reply: “Applied to cgroup/for-7.1-fixes.” No NAKs or concerns
found in the saved thread.
Step 4.2 Record: `b4 dig -w` shows recipients included cgroup
maintainers/list and docs list: `tj@kernel.org`, `hannes@cmpxchg.org`,
`mkoutny@suse.com`, `cgroups@vger.kernel.org`, `corbet@lwn.net`,
`skhan@linuxfoundation.org`, `linux-doc@vger.kernel.org`, `linux-
kernel@vger.kernel.org`.
Step 4.3 Record: no `Reported-by` or bug-report `Link:` tags. No syzbot,
bugzilla, or user-impact bug report applies.
Step 4.4 Record: b4 found a standalone single-patch series, not part of
a multi-patch dependency chain.
Step 4.5 Record: web search did not find stable-list discussion for this
exact patch. `WebFetch` to lore/patch.msgid was blocked by Anubis, but
b4 successfully fetched the mbox.
## Phase 5: Code Semantic Analysis
Step 5.1 Record: no functions modified by the diff.
Step 5.2 Record: no callers affected by the diff. For documentation
accuracy, I verified current `stable/linux-7.0.y` code has
`commit_charge()` callers in `charge_memcg()`,
`mem_cgroup_replace_folio()`, and `mem_cgroup_migrate()`.
Step 5.3 Record: no changed callees. The relevant current code has
`commit_charge()` assigning `folio->memcg_data`, and callers also invoke
`memcg1_commit_charge()` where appropriate.
Step 5.4 Record: runtime reachability is not relevant because no
executable code changes.
Step 5.5 Record: similar stale docs pattern exists in stable branches;
however code state differs by branch. `6.19.y`/`7.0.y` have stale docs
and no old API. `6.12.y` still has `mem_cgroup_commit_charge()` and
`mem_cgroup_cancel_charge()` in code.
## Phase 6: Cross-Referencing And Stable Tree Analysis
Step 6.1 Record: buggy stale documentation exists in
`stable/linux-7.0.y`, `stable/linux-6.19.y`, `stable/linux-6.18.y`,
`stable/linux-6.6.y`, `stable/linux-6.1.y`, `stable/linux-5.15.y`, and
`stable/linux-5.10.y` by exact doc grep. I verified the old APIs are
absent in several of those trees, but `stable/linux-6.12.y` still
contains `mem_cgroup_commit_charge()` and `mem_cgroup_cancel_charge()`,
so this exact upstream text is not universally correct for all
maintained stable lines.
Step 6.2 Record: `git apply --check` of the candidate diff succeeds on
the current `stable/linux-7.0.y` checkout. Expected backport difficulty:
clean for trees with matching doc context; branch-specific review needed
for `6.12.y`.
Step 6.3 Record: no related stable fix for this exact doc update found
by local stable branch ancestry checks or web search.
## Phase 7: Subsystem And Maintainer Context
Step 7.1 Record: subsystem is cgroup-v1 memcg documentation.
Criticality: peripheral/runtime-none; important only for documentation
correctness.
Step 7.2 Record: cgroup and memcg areas are active; recent
`origin/master` history includes multiple cgroup/mm fixes. The candidate
was applied by the cgroup maintainer.
## Phase 8: Impact And Risk Assessment
Step 8.1 Record: affected population is documentation readers and
developers/admins consulting old cgroup-v1 memcg internals. No kernel
runtime users are affected.
Step 8.2 Record: trigger condition is reading or relying on the stale
documentation. Unprivileged users cannot trigger a kernel failure
because there is no runtime behavior.
Step 8.3 Record: failure mode is incorrect documentation. Severity: LOW.
It can mislead developers/admins, but it does not fix crash, corruption,
leak, deadlock, or security behavior.
Step 8.4 Record: benefit is low but real for documentation correctness,
especially because the stable rules exception allows
documentation/comment fixes and runtime risk is zero. Risk is very low
for branches whose code matches the new text; risk is documentation-
regression risk if applied to a branch like `6.12.y` where cancellation
APIs still exist.
## Phase 9: Final Synthesis
Step 9.1 Record: evidence for backporting: tiny docs-only patch;
corrects verified stale references in current `7.0.y` and `6.19.y`;
applied by cgroup maintainer; no runtime regression risk; documentation
fixes are allowed. Evidence against: no runtime bug or user-visible
stability issue; not correct for every stable branch, specifically
verified `6.12.y` still has the old commit/cancel APIs. Unresolved: I
did not exhaustively validate every maintained stable branch’s memcg API
state.
Step 9.2 Stable rules checklist:
1. Obviously correct and tested? Yes for matching-code branches;
verified by code grep, `git diff --check`, and `git apply --check` on
`7.0.y`.
2. Fixes a real bug that affects users? It fixes incorrect
documentation, not runtime behavior.
3. Important issue? No runtime severity; LOW documentation correctness
issue.
4. Small and contained? Yes, 6-line docs-only diff in one file.
5. No new features or APIs? Yes.
6. Can apply to stable trees? Yes to at least current `7.0.y`; should
not be applied blindly to `6.12.y`.
Step 9.3 Record: exception category is documentation fix.
Step 9.4 Decision: backport is acceptable for stable trees whose memcg
implementation no longer has charge cancellation APIs. It should be
excluded from trees like `6.12.y` where the old APIs still exist. With
that branch-selection caveat, this qualifies under the documentation-fix
exception.
Verification:
- [Phase 1] Parsed candidate commit
`d8769544bde51b0ac980d10f8fe9f9fed6c95995`: only two Signed-off-by
tags, no bug/report/stable tags.
- [Phase 2] `git show --stat --patch`: confirmed one docs file, `2
insertions(+), 4 deletions(-)`.
- [Phase 3] `git show 1d8f136a421f...`: confirmed referenced commit
removed `mem_cgroup_commit_charge()` and `mem_cgroup_cancel_charge()`
from mainline code.
- [Phase 3] `git log origin/master --grep`: found candidate and merge
via `cgroup-for-7.1-rc2-fixes`.
- [Phase 4] `b4 dig`: found lore thread and exact patch-id match.
- [Phase 4] `b4 dig -a`: only v1 single-patch series.
- [Phase 4] `b4 dig -w`: relevant cgroup and docs maintainers/lists were
included.
- [Phase 4] Saved mbox: confirmed Tejun replied “Applied to
cgroup/for-7.1-fixes”; no NAKs or stable nomination found.
- [Phase 5] `rg`/`git grep`: confirmed current code uses
`commit_charge()` and no longer has old API names in `7.0.y`.
- [Phase 6] `git apply --check`: candidate applies cleanly to current
`7.0.y`.
- [Phase 6] Branch checks: `6.12.y` still has
`mem_cgroup_commit_charge()` and `mem_cgroup_cancel_charge()`, so this
patch must not be applied there unchanged.
- [Phase 8] Runtime impact verified as none because only
`Documentation/admin-guide/cgroup-v1/memcg_test.rst` changes.
**YES**
Documentation/admin-guide/cgroup-v1/memcg_test.rst | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/Documentation/admin-guide/cgroup-v1/memcg_test.rst b/Documentation/admin-guide/cgroup-v1/memcg_test.rst
index 9f8e27355cba5..7c7cd457cf695 100644
--- a/Documentation/admin-guide/cgroup-v1/memcg_test.rst
+++ b/Documentation/admin-guide/cgroup-v1/memcg_test.rst
@@ -47,21 +47,19 @@ Please note that implementation details can be changed.
Called when swp_entry's refcnt goes down to 0. A charge against swap
disappears.
-3. charge-commit-cancel
+3. charge-commit
=======================
Memcg pages are charged in two steps:
- mem_cgroup_try_charge()
- - mem_cgroup_commit_charge() or mem_cgroup_cancel_charge()
+ - commit_charge()
At try_charge(), there are no flags to say "this page is charged".
at this point, usage += PAGE_SIZE.
At commit(), the page is associated with the memcg.
- At cancel(), simply usage -= PAGE_SIZE.
-
Under below explanation, we assume CONFIG_SWAP=y.
4. Anonymous
--
2.53.0
^ permalink raw reply related
* Re: [RFC PATCH 0/5] mm: support zswap-backed anonymous large folio swapin
From: Yosry Ahmed @ 2026-05-11 22:13 UTC (permalink / raw)
To: fujunjie
Cc: Andrew Morton, Chris Li, Kairui Song, Johannes Weiner, Nhat Pham,
linux-mm, linux-kernel, linux-doc, Jonathan Corbet,
David Hildenbrand, Ryan Roberts, Barry Song, Baolin Wang,
Chengming Zhou, Baoquan He, Lorenzo Stoakes
In-Reply-To: <tencent_8B437BE4F586C162950BF71954316C1EDB05@qq.com>
On Fri, May 08, 2026 at 08:18:29PM +0000, fujunjie wrote:
> Hi,
>
> This RFC explores anonymous large folio swapin when a contiguous swap
> range is backed consistently by zswap.
>
> Large folio swapout to zswap is already supported by storing each base
> page in the folio as a separate zswap entry. The anonymous synchronous
> swapin path has remained order-0 once zswap has ever been enabled:
> zswap_load() rejected large folios, and alloc_swap_folio() avoided large
> folio allocation to protect against mixed backend ranges.
>
> This RFC keeps the scope intentionally conservative. It does not try to
> read one large folio from mixed zswap and disk backends, and it does not
> change shmem swapin. Shmem still has its existing zswap fallback and is
> left for later discussion. For anonymous swapin, the backend rule is made
> explicit:
>
> - a range fully absent from zswap can keep using the disk backend
> - a range fully present in zswap can be decompressed into a large folio
> - a mixed zswap/non-zswap range falls back to order-0 swapin
>
> The series adds a zswap range query helper, teaches zswap_load() to
> decompress all-zswap large folios one base page at a time, accounts mTHP
> swpin for zswap-loaded large folios, retries synchronous large-folio
> insertion races with order-0 swapin, and removes the anonymous
> zswap-never-enabled restriction once mixed ranges are filtered.
>
> I tested the series with a full bzImage build using CONFIG_ZSWAP=y,
> CONFIG_ZRAM=y, CONFIG_MEMCG=y and CONFIG_THP_SWAP=y.
>
> The QEMU/KVM runs covered both the fully-zswap path and the mixed-backend
> fallback path. In the all-zswap run, a 512MiB anonymous mapping was faulted
> as 8192 64KiB groups, reclaimed into zswap, and faulted back. Reclaim
> reported mthp64_zswpout=8192 and zswpout=131072. Refault then reported
> mthp64_swpin=8192 and zswpin=131072, and pagemap/kpageflags showed 8192
> order-4 THP groups in the mapping.
>
> In the mixed-backend run, the workload used a 64MiB anonymous mapping
> split into 1024 64KiB groups. After shrinker debugfs wrote back exactly
> one zswap base-page entry, refault left 1023 order-4 THP groups and one
> order-0 mixed group. The kernel stats matched that shape:
> mthp64_swpin=1023, zswpin=16383 and zswpwb=1.
>
> CONFIG_SHRINKER_DEBUG is only a test aid for making that one zswap
> writeback deterministic; it is not required by the implementation.
>
> Nhat Pham's active Virtual Swap Space series is adjacent work. It moves
> swap cache and zswap entry state into a virtual swap descriptor, and lists
> mixed backing THP swapin as a future use case. This RFC is independent and
> works with the current swap/zswap infrastructure, but may need rebasing if
> VSS lands first.
>
> Feedback would be especially helpful on:
>
> 1. whether it makes sense to support all-zswap large folio swapin first,
> while keeping mixed zswap/disk ranges on the order-0 fallback path
I think so, yes, but based on my read of the code this RFC only affects
synchornous swapin, which is more-or-less zram+zswap. This is an
uncommon setup outside of testing.
> 2. whether a follow-up for mixed zswap/disk large folio swapin would be
> useful after this RFC
That's a heavier lift and I think we should consider this in the
longer-term, once the virtual swap work settles down. This is
conceptually not a zswap thing, you can have parts of a folio on disk,
in zswap, in the zeromap, etc. So it needs to be handled at a higher
layer (virtual swap for example).
>
> Thanks.
>
> ---
>
> fujunjie (5):
> mm: zswap: decompress into a folio subpage
> mm: zswap: add a zswap entry batch helper
> mm: zswap: load fully stored large folios
> mm: swap: fall back to order-0 after large swapin races
> mm: swap: allow zswap-backed large folio swapin
>
> Documentation/admin-guide/mm/transhuge.rst | 4 +-
> include/linux/zswap.h | 9 ++
> mm/memory.c | 67 ++++++++-----
> mm/swap_state.c | 23 +++--
> mm/zswap.c | 111 ++++++++++++++++-----
> 5 files changed, 154 insertions(+), 60 deletions(-)
>
>
> base-commit: 917719c412c48687d4a176965d1fa35320ec457c
> --
> 2.34.1
>
>
^ permalink raw reply
* Re: [PATCH] crypto: af_alg - Document the deprecation of AF_ALG
From: Eric Biggers @ 2026-05-11 21:38 UTC (permalink / raw)
To: Ignat Korchagin
Cc: Kamran Khan, Jeff Barnes, Andy Lutomirski,
linux-crypto@vger.kernel.org, Herbert Xu,
linux-doc@vger.kernel.org, linux-api@vger.kernel.org,
linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
Linus Torvalds
In-Reply-To: <3bfcf406-fdde-4303-9bd6-0d8d21ddba37@linux.win>
On Mon, May 11, 2026 at 10:03:21PM +0100, Ignat Korchagin wrote:
> I don't think fully discounting hardware offloading is beneficial here. HW
> accelerators will be produced and without a common interface vendors would
> start implementing their own "bespoke" drivers with bespoke userspace
> interfaces (we already had such proposals), which in turn may introduce more
> attack surface. Yes, AF_ALG needs substantial improvement, but at least it
> can be a standardisation point.
That isn't the best way to accelerate symmetric crypto anymore though,
if it ever was. This has been known for a long time.
> > In any case, any hypothetical security benefit provided by AF_ALG would
> > have to be *very high* to outweigh the continuous stream of
> > vulnerabilities in it. I understand that people using AF_ALG might not
> > be familiar with that continuous stream of vulnerabilities, but it would
>
>
> Is it actually that much compared to other features/subsystems, like eBPF or
> user namespaces? But we don't rush to deprecate those - instead trying to
> harden them and come up with better design.
There are plenty of other kernel features with a large attack surface,
of course. But they tend to be much more useful than AF_ALG. It's all
about weighing benefits vs. risks.
When we get the point where a large number of Linux users *had* to
disable AF_ALG as an emergency vulnerability response, and at the same
time their systems weren't even using AF_ALG so nothing even broke and
they could have just done that to begin with, I think we get a very
clear idea of which side is heavier for AF_ALG in the real world.
The main relevance of AF_ALG to the Linux community is that it allows
their systems to be exploited.
- Eric
^ permalink raw reply
* Re: [PATCH v13 3/4] gpio: rpmsg: add generic rpmsg GPIO driver
From: Shah, Tanmay @ 2026-05-11 21:35 UTC (permalink / raw)
To: Mathieu Poirier, tanmay.shah
Cc: Arnaud POULIQUEN, Beleswar Prasad Padhi, Shenwei Wang,
Andrew Lunn, Linus Walleij, Bartosz Golaszewski, Jonathan Corbet,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
Frank Li, Sascha Hauer, Shuah Khan, linux-gpio@vger.kernel.org,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
Pengutronix Kernel Team, Fabio Estevam, Peng Fan,
devicetree@vger.kernel.org, linux-remoteproc@vger.kernel.org,
imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org,
dl-linux-imx, Bartosz Golaszewski
In-Reply-To: <CANLsYkz8HpM_8eS7DjN_jmYs4T7P9xY0jYmdiAx5WO=_1zvFpQ@mail.gmail.com>
On 5/11/2026 12:58 PM, Mathieu Poirier wrote:
> On Mon, 11 May 2026 at 10:47, Shah, Tanmay <tanmays@amd.com> wrote:
>>
>>
>>
>> On 5/5/2026 10:52 AM, Shah, Tanmay wrote:
>>>
>>>
>>> On 5/5/2026 4:28 AM, Arnaud POULIQUEN wrote:
>>>> Hi Tanmay,
>>>>
>>>> On 5/4/26 21:19, Shah, Tanmay wrote:
>>>>>
>>>>> Hello all,
>>>>>
>>>>> I have started reviewing this work as well.
>>>>> Thanks Shenwei for this work.
>>>>>
>>>>> I have gone through only the current revision, and would like to provide
>>>>> idea on how to achieve GPIO number multiplexing with the RPMsg protocol.
>>>>> Also, have some bindings related question.
>>>>>
>>>>> Please see below:
>>>>>
>>>>> On 4/30/2026 11:40 AM, Arnaud POULIQUEN wrote:
>>>>>>
>>>>>>
>>>>>> On 4/30/26 14:56, Beleswar Prasad Padhi wrote:
>>>>>>> Hello Arnaud,
>>>>>>>
>>>>>>> On 30/04/26 13:05, Arnaud POULIQUEN wrote:
>>>>>>>> Hello,
>>>>>>>>
>>>>>>>> On 4/29/26 21:20, Mathieu Poirier wrote:
>>>>>>>>> On Wed, 29 Apr 2026 at 12:07, Padhi, Beleswar <b-padhi@ti.com> wrote:
>>>>>>>>>>
>>>>>>>>>> Hi Mathieu,
>>>>>>>>>>
>>>>>>>>>> On 4/29/2026 11:03 PM, Mathieu Poirier wrote:
>>>>>>>>>>> On Wed, 29 Apr 2026 at 10:53, Shenwei Wang <shenwei.wang@nxp.com>
>>>>>>>>>>> wrote:
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>> -----Original Message-----
>>>>>>>>>>>>> From: Mathieu Poirier <mathieu.poirier@linaro.org>
>>>>>>>>>>>>> Sent: Wednesday, April 29, 2026 10:42 AM
>>>>>>>>>>>>> To: Shenwei Wang <shenwei.wang@nxp.com>
>>>>>>>>>>>>> Cc: Andrew Lunn <andrew@lunn.ch>; Padhi, Beleswar <b-
>>>>>>>>>>>>> padhi@ti.com>; Linus
>>>>>>>>>>>>> Walleij <linusw@kernel.org>; Bartosz Golaszewski
>>>>>>>>>>>>> <brgl@kernel.org>; Jonathan
>>>>>>>>>>>>> Corbet <corbet@lwn.net>; Rob Herring <robh@kernel.org>;
>>>>>>>>>>>>> Krzysztof Kozlowski
>>>>>>>>>>>>> <krzk+dt@kernel.org>; Conor Dooley <conor+dt@kernel.org>; Bjorn
>>>>>>>>>>>>> Andersson
>>>>>>>>>>>>> <andersson@kernel.org>; Frank Li <frank.li@nxp.com>; Sascha Hauer
>>>>>>>>>>>>> <s.hauer@pengutronix.de>; Shuah Khan
>>>>>>>>>>>>> <skhan@linuxfoundation.org>; linux-
>>>>>>>>>>>>> gpio@vger.kernel.org; linux-doc@vger.kernel.org; linux-
>>>>>>>>>>>>> kernel@vger.kernel.org;
>>>>>>>>>>>>> Pengutronix Kernel Team <kernel@pengutronix.de>; Fabio Estevam
>>>>>>>>>>>>> <festevam@gmail.com>; Peng Fan <peng.fan@nxp.com>;
>>>>>>>>>>>>> devicetree@vger.kernel.org; linux-remoteproc@vger.kernel.org;
>>>>>>>>>>>>> imx@lists.linux.dev; linux-arm-kernel@lists.infradead.org; dl-
>>>>>>>>>>>>> linux-imx <linux-
>>>>>>>>>>>>> imx@nxp.com>; Bartosz Golaszewski <brgl@bgdev.pl>
>>>>>>>>>>>>> Subject: [EXT] Re: [PATCH v13 3/4] gpio: rpmsg: add generic
>>>>>>>>>>>>> rpmsg GPIO driver
>>>>>>>>>>>>> On Tue, Apr 28, 2026 at 03:24:59PM +0000, Shenwei Wang wrote:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> -----Original Message-----
>>>>>>>>>>>>>>> From: Andrew Lunn <andrew@lunn.ch>
>>>>>>>>>>>>>>> Sent: Monday, April 27, 2026 3:49 PM
>>>>>>>>>>>>>>> To: Shenwei Wang <shenwei.wang@nxp.com>
>>>>>>>>>>>>>>> Cc: Padhi, Beleswar <b-padhi@ti.com>; Linus Walleij
>>>>>>>>>>>>>>> <linusw@kernel.org>; Bartosz Golaszewski <brgl@kernel.org>;
>>>>>>>>>>>>>>> Jonathan
>>>>>>>>>>>>>>> Corbet <corbet@lwn.net>; Rob Herring <robh@kernel.org>;
>>>>>>>>>>>>>>> Krzysztof
>>>>>>>>>>>>>>> Kozlowski <krzk+dt@kernel.org>; Conor Dooley
>>>>>>>>>>>>>>> <conor+dt@kernel.org>;
>>>>>>>>>>>>>>> Bjorn Andersson <andersson@kernel.org>; Mathieu Poirier
>>>>>>>>>>>>>>> <mathieu.poirier@linaro.org>; Frank Li <frank.li@nxp.com>;
>>>>>>>>>>>>>>> Sascha
>>>>>>>>>>>>>>> Hauer <s.hauer@pengutronix.de>; Shuah Khan
>>>>>>>>>>>>>>> <skhan@linuxfoundation.org>; linux-gpio@vger.kernel.org; linux-
>>>>>>>>>>>>>>> doc@vger.kernel.org; linux-kernel@vger.kernel.org; Pengutronix
>>>>>>>>>>>>>>> Kernel Team <kernel@pengutronix.de>; Fabio Estevam
>>>>>>>>>>>>>>> <festevam@gmail.com>; Peng Fan <peng.fan@nxp.com>;
>>>>>>>>>>>>>>> devicetree@vger.kernel.org; linux- remoteproc@vger.kernel.org;
>>>>>>>>>>>>>>> imx@lists.linux.dev; linux-arm- kernel@lists.infradead.org;
>>>>>>>>>>>>>>> dl-linux-imx <linux-imx@nxp.com>; Bartosz Golaszewski
>>>>>>>>>>>>>>> <brgl@bgdev.pl>
>>>>>>>>>>>>>>> Subject: [EXT] Re: [PATCH v13 3/4] gpio: rpmsg: add generic
>>>>>>>>>>>>>>> rpmsg
>>>>>>>>>>>>>>> GPIO driver
>>>>>>>>>>>>>>>>> struct virtio_gpio_response {
>>>>>>>>>>>>>>>>> __u8 status;
>>>>>>>>>>>>>>>>> __u8 value;
>>>>>>>>>>>>>>>>> };
>>>>>>>>>>>>>>>> It is the same message format. Please see the message
>>>>>>>>>>>>>>>> definition
>>>>>>>>>>>>>>> (GET_DIRECTION) below:
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> + +-----+-----+-----+-----+-----+----+
>>>>>>>>>>>>>>>> + |0x00 |0x01 |0x02 |0x03 |0x04 |0x05|
>>>>>>>>>>>>>>>> + | 1 | 2 |port |line | err | dir|
>>>>>>>>>>>>>>>> + +-----+-----+-----+-----+-----+----+
>>>>>>>>>>>>>>> Sorry, but i don't see how two u8 vs six u8 are the same
>>>>>>>>>>>>>>> message format.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Some changes to the message format are necessary.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Virtio uses two communication channels (virtqueues): one for
>>>>>>>>>>>>>> requests and
>>>>>>>>>>>>> replies, and a second one for events.
>>>>>>>>>>>>>> In contrast, rpmsg provides only a single communication
>>>>>>>>>>>>>> channel, so a
>>>>>>>>>>>>>> type field is required to distinguish between different kinds
>>>>>>>>>>>>>> of messages.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Since rpmsg replies and events share the same message format,
>>>>>>>>>>>>>> an additional
>>>>>>>>>>>>> line is introduced to handle both cases.
>>>>>>>>>>>>>> Finally, rpmsg supports multiple GPIO controllers, so a port
>>>>>>>>>>>>>> field is added to
>>>>>>>>>>>>> uniquely identify the target controller.
>>>>>>>>>>>>>
>>>>>>>>>>>>> I have commented on this before - RPMSG is already providing
>>>>>>>>>>>>> multiplexing
>>>>>>>>>>>>> capability by way of endpoints. There is no need for a port
>>>>>>>>>>>>> field. One endpoint,
>>>>>>>>>>>>> one GPIO controller.
>>>>>>>>>>>>>
>>>>>>>>>>>> You still need a way to let the remote side know which port the
>>>>>>>>>>>> endpoint maps to, either
>>>>>>>>>>>> by embedding the port information in the message (the current
>>>>>>>>>>>> way), or by sending it
>>>>>>>>>>>> separately.
>>>>>>>>>>>>
>>>>>>>>>>> An endpoint is created with every namespace request. There
>>>>>>>>>>> should be
>>>>>>>>>>> one namespace request for every GPIO controller, which yields a
>>>>>>>>>>> unique
>>>>>>>>>>> endpoint for each controller and eliminates the need for an extra
>>>>>>>>>>> field to identify them.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Right, but this can still be done by just having one namespace
>>>>>>>>>> request.
>>>>>>>>>> We can create new endpoints bound to an existing namespace/
>>>>>>>>>> channel by
>>>>>>>>>> invoking rpmsg_create_ept(). This is what I suggested here too:
>>>>>>>>>> https://lore.kernel.org/all/29485742-6e49-482e-
>>>>>>>>>> b73d-228295daaeec@ti.com/
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> I will look at your suggestion (i.e link above) later this week or
>>>>>>>>> next week.
>>>>>>>>>
>>>>>>>>>> My mental model looks like this for the complete picture:
>>>>>>>>>>
>>>>>>>>>> 1. namespace/channel#1 = rpmsg-io
>>>>>>>>>> a. ept1 -> gpio-controller@1
>>>>>>>>>> b. ept2 -> gpio-controller@2
>>>>>>>>>>
>>>>>
>>>>> If my understanding of what gpio-controller is right, than this won't
>>>>> work. We need one rpmsg channel per gpio-controller, and in most cases
>>>>> there will be only one GPIO-controller on the remote side. If there are
>>>>> multiple or multiple instances of same controller, than we need separate
>>>>> channel name for that controller just like we would have separate device
>>>>> on the Linux.
>>>>
>>>> As done in ehe rpmsg_tty driver it could be instantiated several times with
>>>> the same channel/service name. This would imply a specific rpmsg to
>>>> retreive
>>>> the gpio controller index from the remote side.
>>>>>
>>>>>>>>>
>>>>>>>>> I've asked for one endpoint per GPIO controller since the very
>>>>>>>>> beginning. I don't yet have a strong opinion on whether to use one
>>>>>>>>> namespace request per GPIO controller or a single request that spins
>>>>>>>>> off multiple endpoints. I'll have to look at your link and
>>>>>>>>> reflect on
>>>>>>>>> that. Regardless of how we proceed on that front, multiplexing needs
>>>>>>>>> to happen at the endpoint level rather than the packet level.
>>>>>>>>> This is
>>>>>>>>> the only way this work can move forward.
>>>>>>>>>
>>>>>>>>
>>>>>>>> I would be more in favor of Mathieu’s proposal: “An endpoint is
>>>>>>>> created with every namespace request.”
>>>>>>>>
>>>>>>>> If the endpoint is created only on the Linux side, how do we match
>>>>>>>> the Linux endpoint address with the local port field on the remote
>>>>>>>> side?
>>>>>>>
>>>>>>>
>>>>>>> Simply by sending a message to the remote containing the newly created
>>>>>>> endpoint and the port idx. Note that is this done just one time, after
>>>>>>> this
>>>>>>> Linux need not have the port field in the message everytime its sending
>>>>>>> a message.
>>>>>>>
>>>>>>>>
>>>>>>>> With a multi-namespace approach, the namespace could be rpmsg-io-
>>>>>>>> [addr], where [addr] corresponds to the GPIO controller address in
>>>>>>>> the DT. This would:
>>>>>>>
>>>>>>>
>>>>>>> You will face the same problem in this case also that you asked above:
>>>>>>> "how do we match the Linux endpoint address with the local port field
>>>>>>> on the remote side?"
>>>>>>
>>>>>> Sorry I probably introduced confusion here
>>>>>> my sentence should be;
>>>>>> With a multi-namespace approach, the namespace could be rpmsg-io-
>>>>>> [port],
>>>>>> where [port] corresponds to the GPIO controller port in the DT.
>>>>>>
>>>>>>
>>>>>> For instance:
>>>>>>
>>>>>> rpmsg {
>>>>>> rpmsg-io {
>>>>>> #address-cells = <1>;
>>>>>> #size-cells = <0>;
>>>>>>
>>>>>> gpio@25 {
>>>>>> compatible = "rpmsg-gpio";
>>>>>> reg = <25>;
>>>>>> gpio-controller;
>>>>>> #gpio-cells = <2>;
>>>>>> #interrupt-cells = <2>;
>>>>>> interrupt-controller;
>>>>>> };
>>>>>>
>>>>>> gpio@32 {
>>>>>> compatible = "rpmsg-gpio";
>>>>>> reg = <32>;
>>>>>> gpio-controller;
>>>>>> #gpio-cells = <2>;
>>>>>> #interrupt-cells = <2>;
>>>>>> interrupt-controller;
>>>>>> };
>>>>>> };
>>>>>> };
>>>>>>
>>>>>> rpmsg-io-25 would match with gpio@25
>>>>>> rpmsg-io-32 would match with gpio@32
>>>>>>
>>>>>
>>>>> The problem with this approach is, we will endup creating way too many
>>>>> RPMsg devices/channels. i.e. one channel per one GPIO. That limits how
>>>>> many GPIOs can be handled by remote from memory perspective. At
>>>>> somepoint we might just run-out of number ept & channels created by the
>>>>> remote. As of now, open-amp library supports 128 epts I think.
>>>>
>>>> Right, I proposed a solution in my previous answer to Beleswar who has
>>>> the same concern.
>>>>
>>>>>
>>>>>>
>>>>>>>
>>>>>>> Because the endpoint that is created on a namespace request is also
>>>>>>> dynamic in nature. How will the remote know which endpoint addr
>>>>>>> Linux allocated for a namespace that it announced?
>>>>>>>
>>>>>>> As an example/PoC, I created a firmware example which announces
>>>>>>> 2 name services to Linux, one is the standard "rpmsg_chrdev" and
>>>>>>> the other is a TI specific name service "ti.ipc4.ping-pong". You can
>>>>>>> see it created 2 different addresses (0x400 and 0x401) for each of
>>>>>>> the name service request from the same firmware:
>>>>>>>
>>>>>>> root@j784s4-evm:~# dmesg | grep virtio0 | grep -i channel
>>>>>>> [ 9.290275] virtio_rpmsg_bus virtio0: creating channel
>>>>>>> ti.ipc4.ping-pong addr 0xd
>>>>>>> [ 9.311230] virtio_rpmsg_bus virtio0: creating channel rpmsg_chrdev
>>>>>>> addr 0xe
>>>>>>> [ 9.496645] rpmsg_chrdev virtio0.rpmsg_chrdev.-1.14: DEBUG: Channel
>>>>>>> formed from src = 0x400 to dst = 0xe
>>>>>>> [ 9.707255] rpmsg_client_sample virtio0.ti.ipc4.ping-pong.-1.13:
>>>>>>> new channel: 0x401 -> 0xd!
>>>>>>>
>>>>>>> So in this case, rpmsg-io-1 can have different ept addr than rpmsg-io-2
>>>>>>> Back to same problem. Simple solution is to reply to remote with the
>>>>>>> created ept addr and the index.
>>>>>>
>>>>>> That why I would like to suggest to use the name service field to
>>>>>> identify the port/controller, instead of the endpoint address.
>>>>>>>
>>>>>>>>
>>>>>>>> - match the RPMsg probe with the DT,
>>>>>>>
>>>>>>>
>>>>>>> We can probe from all controllers with a single name service
>>>>>>> announcement too.
>>>>>>>
>>>>>>>> - provide a simple mapping between the port and the endpoint on both
>>>>>>>> sides,
>>>>>>>
>>>>>>>
>>>>>>> We are trying to get rid of this mapping from Linux side to adapt
>>>>>>> the gpio-virtio design.
>>>>>>>
>>>>>>>> - allow multiple endpoints on the remote side,
>>>>>>>
>>>>>>>
>>>>>>> We can support this as well with single nameservice model.
>>>>>>> There is no limitation. Remote has to send a message with
>>>>>>> its newly created ept that's all.
>>>>>>>
>>>>>>>> - provide a simple discovery mechanism for remote capabilities.
>>>>>>>
>>>>>>>
>>>>>>> A single announcement: "rpmsg-io" is also discovery mechanism.
>>>>>>>
>>>>>>> Feel free to let me know if you have concerns with any of the
>>>>>>> suggestions!
>>>>>>
>>>>>> My only concern, whatever the solution, is that we find a smart
>>>>>> solution to associate the correct endpoint with the correct GPIO
>>>>>> port/controller defined in the DT.
>>>>>>
>>>>>> I may have misunderstood your solution. Could you please help me
>>>>>> understand your proposal by explaining how you would handle three
>>>>>> GPIO ports defined in the DT, considering that the endpoint
>>>>>> addresses on the Linux side can be random?
>>>>>> If I assume there is a unique endpoint on the remote side,
>>>>>> I do not understand how you can match, on the firmware side,
>>>>>> the Linux endpoint address to the GPIO port.
>>>>>>
>>>>>> Thanks and Regards,Arnaud
>>>>>>
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Beleswar
>>>>>>>
>>>>>>>>
>>>>>>>> Regards,
>>>>>>>> Arnaud
>>>>>>>>
>>>>>>>>>> 2. namespace/channel#2 = rpmsg-i2c
>>>>>>>>>> a. ept1 -> i2c@1
>>>>>>>>>> b. ept2 -> i2c@2
>>>>>>>>>> c. ept3 -> i2c@3
>>>>>>>>>>
>>>>>>>>>> etc...
>>>>>>>>>>
>>>>>
>>>>> Just want to clear-up few terms before I jump to the solution:
>>>>>
>>>>> **RPMsg channel/device**:
>>>>> - These are devices announced by the remote processor, and created by
>>>>> linux. They are created at: /sys/bus/rpmsg/devices
>>>>> - The channel format: <name>.<src ept>.<dst ept>
>>>>>
>>>>> **RPMsg endpoint**:
>>>>> - Endpoint is differnt than channel. Single channel can have multiple
>>>>> endpoints, and represented in the linux with: /dev/rpmsg? devices.
>>>>>
>>>>> To create endpoint device, we have rpmsg_create_ept API, which takes
>>>>> channel information as input, which has src-ept, dst-ept.
>>>>>
>>>>> Following is proposed solution:
>>>>>
>>>>> 1) Assign RPMsg channel/device per rpmsg-gpio controller (Not per GPIO
>>>>> pin/port).
>>>>> - In our case that would be, single rpmsg-io node. (That makes me
>>>>> question if bindings are correct or not).
>>>>>
>>>>> 2) Assign GPIO number as src ept.
>>>>>
>>>>> i.e. *rpmsg-io.<GPIO number>.<dst ept>*. Do not randomly assign src
>>>>> endpoint.
>>>>>
>>>>> Now, RPMSG channel by spec reserves first 1024 endpoints [1], so we can
>>>>> add 1024 offset to the GPIO number:
>>>>>
>>>>> so, when calling rpmsg_create_ept() API, we assing src_endpoint as:
>>>>> (GPIO_NUMBER + RPMSG_RESERVED_ADDRESSES)
>>>>>
>>>>> Now on the remote side, there is single channel and only single-endpoint
>>>>> is needed that is mapped to the rpmsg-io channel callback.
>>>>>
>>>>> That callback will receive all the payloads from the Linux, which will
>>>>> have src-ept i.e. (RPMSG_RESERVED_ADDRESSES + GPIO_NUMBER).
>>>>
>>>>
>>>> Interesting approach. I also tried to find a similar solution.
>>>>
>>>> The question here is: how can we guarantee continuous addresses? Given
>>>> the static and dynamic allocation of endpoint addresses that are
>>>> implemented, my conclusion was that it is not reliable enough.
>>>>
>>>> but perhaps I missed something...
>>>>
>>>>>
>>>>> It can retrieve GPIO_NUMBER easily, and convert to appropriate pin based
>>>>> on platform specific logic.
>>>>>
>>>>> This doesn't need PORT information at all. Also it makes sure that
>>>>> remote is using only single-endpoint so not much memory is used.
>>>>>
>>>>> *Example*:
>>>>> If only rpmsg-gpio channel is created by the remote side, than following
>>>>> is the representation of the devices when GPIO 25, 26, 27 is assigned to
>>>>> the rpmsg-io controller:
>>>>>
>>>>> Linux Remote
>>>>>
>>>>> rpmsg-channel: rpmsg-gpio.0x400.0x400
>>>>>
>>>>> /dev/rpmsg0 - GPIO25 ept (rpmsg-gpio.0x419.0x400)-|
>>>>> |
>>>>> /dev/rpmsg1 - GPIO26 ept (rpmsg-gpio.0x41a.0x400)-|-> rpmsg-gpio.*.0x400
>>>>> |
>>>>> /dev/rpmsg2 - GPIO27 ept (rpmsg-gpio.0x41b.0x400)-| 0x400 ept callback.
>>>>>
>>>>>
>>>>> *On remote side*:
>>>>>
>>>>> ept_0x400_callback(..., int src_ept, ...,)
>>>>> {
>>>>> int gpio_num = src_ept - RPMSG_RESERVED_ADDRESSES;
>>>>> // platform specific logic to convert gpio num to proper pin,
>>>>> // just like you would convert gpio num to pin on a linux gpio
>>>>> controller.
>>>>> }
>>>>>
>>>>> My question on the binding:
>>>>>
>>>>> Why each GPIO is represented with the separate node? I think rpmsg-gpio
>>>>> can be represented just any other GPIO controller? Please let me know if
>>>>> I am missing something. So rpmsg channel/rpmsg device is not created per
>>>>> GPIO, but per controller. GPIO number multiplexing should be done with
>>>>> rpmsg src ept, that removes the need of having each GPIO as a separate
>>>>> node.
>>>>>
>>>>>
>>>>> rpmsg_gpio: rpmsg-gpio@0 {
>>>>> compatible = "rpmsg-gpio";
>>>>> reg = <0>;
>>>>> gpio-controller;
>>>>> #gpio-cells = <2>;
>>>>> #interrupt-cells = <2>;
>>>>> interrupt-controller;
>>>>> };
>>>>>
>>>>> Then in DT, use like regular GPIO, but with the rpmsg-gpio controller:
>>>>>
>>>>> rpmsg-gpios = <&rpmsg_gpio (GPIO NUM) (flags)>;
>>>>>
>>>>> If the intent to create separate gpio nodes was only for the channel
>>>>> creation, then it's not really needed.
>>>>>
>>>>> [1]
>>>>> https://github.com/torvalds/linux/
>>>>> blob/6d35786de28116ecf78797a62b84e6bf3c45aa5a/drivers/rpmsg/
>>>>> virtio_rpmsg_bus.c#L136
>>>>>
>>>>
>>>> It is already the case. bindings declare GPIO controllers, not directly
>>>> GPIOs in:
>>>>
>>>> [PATCH v13 2/4] dt-bindings: remoteproc: imx_rproc: Add "rpmsg" subnode
>>>> support
>>>>
>>>> The discussion is around having an unique RPmsg endpoint for all
>>>> GPIO controller or one RPmsg endpoint per GPIO controller.
>>>>
>>>
>>> Endpoint where remote side or linux side?
>>>
>>> If unique endpoint on remote side per gpio controller then it makes sense.
>>>
>>> Unique endpoint on linux side doesn't make sense. Instead, unique
>>> channel per gpio controller makes sense, and each channel will have
>>> multiple endpoints on linux side. As I replied to Beleswar on the other
>>> email, I will copy past my answer here too:
>>>
>>>
>>> To be more specific:
>>>
>>> Linux: remote:
>>>
>>> ch1: rpmsg-gpio.-1.1024 -> gpio-controller@1024
>>> - gpio-line ept1
>>> - gpio-line ept2 -> They all map to same callback_ept_1024.
>>> - gpio-line ept3
>>>
>>> ch2: rpmsg-gpio.-1.1025 -> gpio-controller@1025
>>> - gpio-line ept1
>>> - gpio-line ept2 -> They all map to same callback_ept_1025.
>>> - gpio-line ept3
>>>
>>
>>
>> Hi Mathieu,
>>
>> So upon more brain storming in this approach I found limitation:
>>
>> This approach won't work if host OS is any other OS but Linux. For
>> example, if the remote OS is zephyr/baremetal using open-amp, then Only
>> Linux <-> zephyr combination will work, and we won't be able to re-use
>> this approach for zephyr <-> zephyr use case. The concept of rpmsg
>> channel/device exist only in the linux kernel implementation. This
>> brings another question: Should the protocol we decide work on other use
>> cases as well? Or Linux must be the Host OS for this protocol ?
>>
>
> Linux and Zephyr are very distinct OS, each with their own subsystems
> and characteristics. The design we choose here involves RPMSG and,
> inherently, Linux. We can't make decisions based on what may
> potentially happen in Zephyr.
>
>>
>> I think your & Arnaud's proposed approach of single endpoint per
>> gpio-controller on both side makes more sense, as it will work
>> regardless of any OS on host or remote side.
>>
>
> Arnaud, Beleswar, Andrew and I are all advocating for one endpoint per
> GPIO controller. The remaining issue it about the best way to work
> out source and destination addresses between Linux and the remote
> processor. I'm running out of time for today but I'll return to this
> thread with a final analysis by the end of the week.
>
Okay. Then that means multiple endpoints on Linux side can be considered.
If we decide to go single-endpoint per device on both side, then for
that here is the proposal to represent src ept and dst ept:
When we represent any device under rpmsg bus node, I think it should be
considered remote's view of the adddress space. So ideally we can
convert it to Linux view of the address space, via 'ranges' property.
So bindings should include 'ranges' property in the parent node. Then
linux view of the start address becomes src ept, and remote view of the
start address becomes dest ept. The remote view of the start address is
expected to be the static src endpoint on the remote side.
Following representation of the rpmsg devices (gpio, i2c, spi or any other):
rpmsg {
#address-cells = <1>;
#size-cells = <1>;
rpmsg-io {
compatible = "rpmsg-io-bus";
ranges = <remote_view_addr(dst ept) linux_view_addr(src ept) size>;
#address-cells = <1>;
#size-cells = <1>;
gpio@remote_view_addr(or dst ept) {
compatible = "rpmsg-io";
reg = <remote_view_addr addr_space_size>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};
...
};
};
Example device-tree:
rpmsg {
#address-cells = <1>;
#size-cells = <1>;
rpmsg-io {
compatible = "rpmsg-io-bus";
ranges = <0x10000 0x50000 0x1000>,
<0x20000 0x60000 0x1000>;
#address-cells = <1>;
#size-cells = <1>;
gpio@10000 {
compatible = "rpmsg-io";
reg = <0x10000 0x1000>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};
gpio@20000 {
compatible = "rpmsg-io";
reg = <0x20000 0x1000>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};
};
};
Thanks,
Tanmay
>> To be more specific this will look like following:
>>
>> Host (Linux) Remote (baremetal/RTOS)
>>
>> rpmsg ch/device 1:
>> - rpmsg ept 1 <------> rpmsg ept 1 gpio-controller 0
>>
>> rpmsg ch/device 2:
>> - rpmsg ept 2 <------> rpmsg ept 2 gpio-controller 1
>>
>>
>> The question is, how to decide src ept, and dest ept on both sides?
>> I still think it should be static endpoints.
>>
>> I will get back with more reasoning on that.
>>
>>> On the remote side, we have to hardcode Which rpmsg controller is mapped
>>> to which endpoint.
>>>
>>>> Or did I misunderstand your questions?
>>>>
>>>> Thanks,
>>>> Arnaud
>>>>
>>>
>>>
>>> I gave this patch more time yesterday, and I think the 'reg' property
>>> should represent remote endpoint, instead of the gpio-controller index.
>>>
>>> So in this approach remote implementation is expected to provide
>>> hard-coded (static) endpoints for each gpio-controller instance, and
>>> that same number should be represented with the 'reg' property.
>>>
>>> On remote side:
>>>
>>> #define RPMSG_GPIO_0_CONTROLLER_EPT (RPMSG_RESERVED_ADDRESSES + 1) // 1024
>>>
>>> ept_1024_callback() {
>>>
>>> // handle appropriate gpio port ()
>>>
>>> }
>>>
>>> On linux side:
>>>
>>> So new representation of controller:
>>>
>>> rpmsg_gpio_0: gpio@1024 {
>>> compatible = "rpmsg-gpio";
>>> reg = <1024>;
>>> gpio-controller;
>>> #gpio-cells = <2>;
>>> #interrupt-cells = <2>;
>>> interrupt-controller;
>>> };
>>>
>>> rpmsg_gpio_1: gpio@1025 {
>>> compatible = "rpmsg-gpio";
>>> reg = <1025>;
>>> gpio-controller;
>>> #gpio-cells = <2>;
>>> #interrupt-cells = <2>;
>>> interrupt-controller;
>>> };
>>>
>>> gpios = <&rpmsg_gpio_0 (GPIO NUM or PIN) flags>,
>>> <&rpmsg_gpio_1 (GPIO NUM or PIN) flags>;
>>>
>>> Now in the linux driver:
>>>
>>> You can easily retrieve destination endpoint when we want to send the
>>> command to the gpio controller via device's "reg" property.
>>>
>>> This approach also provides built-in security as well. Because now
>>> gpio-controller instance is hardcoded with the endpoint callback, it
>>> can't be modified/addressed without changing the 'reg' property.
>>>
>>> Just like you wouldn't change device address for the instance of the
>>> gpio-controller right?
>>>
>>> This approach can be easily adapted to all the other rpmsg controllers
>>> as well.
>>>
>>> So, dynamic endpoint allocation doesn't make sense in this case. Dynamic
>>> endpoint allocation makes more sense for user-space apps which don't
>>> really care about endpoints and only payloads.
>>>
>>> But, here we are multiplexing device-addresses with endpoints, and so it
>>> has to be fixed, and presented via 'reg' property. So, firmware can't
>>> change device-address without Linux knowing it.
>>>
>>> Thanks,
>>> Tanmay
>>>
>>>
>>>>
>>>>>>>>>> This way device groups are isolated with each channel/namespace, and
>>>>>>>>>> instances within each device groups are also respected with specific
>>>>>>>>>> endpoints.
>>>>>>>>>>
>>>>>>>>>> Thanks,
>>>>>>>>>> Beleswar
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
^ permalink raw reply
* Re: [PATCH mm-unstable v17 00/14] khugepaged: mTHP support
From: Andrew Morton @ 2026-05-11 21:04 UTC (permalink / raw)
To: Nico Pache
Cc: linux-doc, linux-kernel, linux-mm, linux-trace-kernel, aarcange,
anshuman.khandual, apopple, baohua, baolin.wang, byungchul,
catalin.marinas, cl, corbet, dave.hansen, david, dev.jain, gourry,
hannes, hughd, jack, jackmanb, jannh, jglisse, joshua.hahnjy, kas,
lance.yang, liam, ljs, mathieu.desnoyers, matthew.brost, mhiramat,
mhocko, peterx, pfalcato, rakie.kim, raquini, rdunlap,
richard.weiyang, rientjes, rostedt, rppt, ryan.roberts, shivankg,
sunnanyong, surenb, thomas.hellstrom, tiwai, usamaarif642, vbabka,
vishal.moola, wangkefeng.wang, will, willy, yang, ying.huang, ziy,
zokeefe
In-Reply-To: <20260511185817.686831-1-npache@redhat.com>
On Mon, 11 May 2026 12:58:00 -0600 Nico Pache <npache@redhat.com> wrote:
> The following series provides khugepaged with the capability to collapse
> anonymous memory regions to mTHPs.
Thanks, I've updated mm.git's mm-new branch to this version.
> V17 Changes:
> - Added Acks/RB
> - New patch(5): split the mmap_read_unlock() locking contract change out of
> "generalize collapse_huge_page" into its own patch; add a comment
> documenting the enter/exit-with-lock-dropped contract (Usama, David)
> - [patch 03] Add const to max_ptes_none/shared/swap variables; improve the
> three helper docstrings; replace the paragraphs with inline comments;
> note that sysctl values are now snapshotted once per scan (Usama, David)
> - [patch 04] Add SCAN_INVALID_PTES_NONE result code and return it instead
> of SCAN_FAIL when collapse_max_ptes_none() returns -EINVAL (Usama);
> snapshot khugepaged_max_ptes_none into a local variable to fix race on
> the two comparisons (Usama); clean up mTHP docstring paragraphs into
> inline comments; fix commit message wording (David)
> - [patch 06] Remove /* PMD collapse */ and /* mTHP collapse */ comments
> (David); move const declarations to top of variable list (David); add
> comment explaining that map_anon_folio_pte_nopf() calls set_ptes under
> pmd_ptl and is safe because PMD is expected to be none (Usama)
> - [patch 08] Shorten sysfs counter documentation for
> collapse_exceed_swap/shared_pte to concise one-liners; trim
> collapse_exceed_none_pte description; fix "dont" → "do not" (David)
> - [patch 10] Keep vm_flags parameter in khugepaged_enter_vma() and
> collapse_allowable_orders() rather than dropping it and reading
> vma->vm_flags internally; pass vm_flags explicitly at all three
> collapse_allowable_orders() call sites (David, sashskio)
> - [patch 11] Fix MTHP_STACK_SIZE: was exponential (~128); correct formula
> is (height + 1) for a DFS on a binary tree rewrite comment to explain
> the DFS sizing (sashskio)
> - [patch 12] Replace SCAN_PAGE_LRU with SCAN_PAGE_LAZYFREE in the
> "goto next_order" early-bail cases; non-LRU page failures cannot be
> recovered at any order and belong in the default (return) path
> - [patch 13] Use tva_flags == TVA_KHUGEPAGED (strict equality) instead of
> tva_flags & TVA_KHUGEPAGED; flatten nested if into single condition;
> retain vm_flags parameter; pass vm_flags to collapse_allowable_orders()
Here's how v17 altered mm.git:
Documentation/admin-guide/mm/transhuge.rst | 24 ---
include/linux/khugepaged.h | 6
include/trace/events/huge_memory.h | 3
mm/huge_memory.c | 2
mm/khugepaged.c | 152 ++++++++++---------
mm/vma.c | 6
tools/testing/vma/include/stubs.h | 3
7 files changed, 99 insertions(+), 97 deletions(-)
--- a/Documentation/admin-guide/mm/transhuge.rst~b
+++ a/Documentation/admin-guide/mm/transhuge.rst
@@ -725,27 +725,17 @@ nr_anon_partially_mapped
collapse_exceed_none_pte
The number of collapse attempts that failed due to exceeding the
- max_ptes_none threshold. For mTHP collapse, Currently only max_ptes_none
- values of 0 and (HPAGE_PMD_NR - 1) are supported. Any other value will
- emit a warning and no mTHP collapse will be attempted. khugepaged will
- try to collapse to the largest enabled (m)THP size; if it fails, it will
- try the next lower enabled mTHP size. This counter records the number of
- times a collapse attempt was skipped for exceeding the max_ptes_none
- threshold, and khugepaged will move on to the next available mTHP size.
+ max_ptes_none threshold.
collapse_exceed_swap_pte
- The number of anonymous mTHP PTE ranges which were unable to collapse due
- to containing at least one swap PTE. Currently khugepaged does not
- support collapsing mTHP regions that contain a swap PTE. This counter can
- be used to monitor the number of khugepaged mTHP collapses that failed
- due to the presence of a swap PTE.
+ The number of collapse attempts that failed due to exceeding the
+ max_ptes_swap threshold. For non-PMD orders this occurs if a mTHP range
+ contains at least one swap PTE.
collapse_exceed_shared_pte
- The number of anonymous mTHP PTE ranges which were unable to collapse due
- to containing at least one shared PTE. Currently khugepaged does not
- support collapsing mTHP PTE ranges that contain a shared PTE. This
- counter can be used to monitor the number of khugepaged mTHP collapses
- that failed due to the presence of a shared PTE.
+ The number of collapse attempts that failed due to exceeding the
+ max_ptes_shared threshold. For non-PMD orders this occurs if a mTHP range
+ contains at least one shared PTE.
As the system ages, allocating huge pages may be expensive as the
system uses memory compaction to copy data around memory to free a
--- a/include/linux/khugepaged.h~b
+++ a/include/linux/khugepaged.h
@@ -13,7 +13,8 @@ extern void khugepaged_destroy(void);
extern int start_stop_khugepaged(void);
extern void __khugepaged_enter(struct mm_struct *mm);
extern void __khugepaged_exit(struct mm_struct *mm);
-extern void khugepaged_enter_vma(struct vm_area_struct *vma);
+extern void khugepaged_enter_vma(struct vm_area_struct *vma,
+ vm_flags_t vm_flags);
extern void khugepaged_min_free_kbytes_update(void);
extern bool current_is_khugepaged(void);
void collapse_pte_mapped_thp(struct mm_struct *mm, unsigned long addr,
@@ -37,7 +38,8 @@ static inline void khugepaged_fork(struc
static inline void khugepaged_exit(struct mm_struct *mm)
{
}
-static inline void khugepaged_enter_vma(struct vm_area_struct *vma)
+static inline void khugepaged_enter_vma(struct vm_area_struct *vma,
+ vm_flags_t vm_flags)
{
}
static inline void collapse_pte_mapped_thp(struct mm_struct *mm,
--- a/include/trace/events/huge_memory.h~b
+++ a/include/trace/events/huge_memory.h
@@ -39,7 +39,8 @@
EM( SCAN_STORE_FAILED, "store_failed") \
EM( SCAN_COPY_MC, "copy_poisoned_page") \
EM( SCAN_PAGE_FILLED, "page_filled") \
- EMe(SCAN_PAGE_DIRTY_OR_WRITEBACK, "page_dirty_or_writeback")
+ EM(SCAN_PAGE_DIRTY_OR_WRITEBACK, "page_dirty_or_writeback") \
+ EMe(SCAN_INVALID_PTES_NONE, "invalid_ptes_none")
#undef EM
#undef EMe
--- a/mm/huge_memory.c~b
+++ a/mm/huge_memory.c
@@ -1571,7 +1571,7 @@ vm_fault_t do_huge_pmd_anonymous_page(st
ret = vmf_anon_prepare(vmf);
if (ret)
return ret;
- khugepaged_enter_vma(vma);
+ khugepaged_enter_vma(vma, vma->vm_flags);
if (!(vmf->flags & FAULT_FLAG_WRITE) &&
!mm_forbids_zeropage(vma->vm_mm) &&
--- a/mm/khugepaged.c~b
+++ a/mm/khugepaged.c
@@ -61,6 +61,7 @@ enum scan_result {
SCAN_COPY_MC,
SCAN_PAGE_FILLED,
SCAN_PAGE_DIRTY_OR_WRITEBACK,
+ SCAN_INVALID_PTES_NONE,
};
#define CREATE_TRACE_POINTS
@@ -101,16 +102,15 @@ static struct kmem_cache *mm_slot_cache
#define KHUGEPAGED_MIN_MTHP_ORDER 2
/*
- * The maximum number of mTHP ranges that can be stored on the stack.
- * This is calculated based on the number of PTE entries in a PTE page table
- * and the minimum mTHP order.
+ * mthp_collapse() does an iterative DFS over a binary tree, from
+ * HPAGE_PMD_ORDER down to KHUGEPAGED_MIN_MTHP_ORDER. The max stack
+ * size needed for a DFS on a binary tree is height + 1, where
+ * height = HPAGE_PMD_ORDER - KHUGEPAGED_MIN_MTHP_ORDER.
*
- * ilog2 is needed in place of HPAGE_PMD_ORDER due to some architectures
- * (ie ppc64le) not defining HPAGE_PMD_ORDER until after build time.
- *
- * At most there will be 1 << (PMD_ORDER - KHUGEPAGED_MIN_MTHP_ORDER) mTHP ranges
+ * ilog2 is used in place of HPAGE_PMD_ORDER because some architectures
+ * (e.g. ppc64le) do not define HPAGE_PMD_ORDER until after build time.
*/
-#define MTHP_STACK_SIZE (1UL << (ilog2(MAX_PTRS_PER_PTE) - KHUGEPAGED_MIN_MTHP_ORDER))
+#define MTHP_STACK_SIZE (ilog2(MAX_PTRS_PER_PTE) - KHUGEPAGED_MIN_MTHP_ORDER + 1)
/*
* Defines a range of PTE entries in a PTE page table which are being
@@ -380,89 +380,87 @@ static bool pte_none_or_zero(pte_t pte)
}
/**
- * collapse_max_ptes_none - Calculate maximum allowed empty PTEs for collapse
+ * collapse_max_ptes_none - Calculate maximum allowed none-page or zero-page
+ * PTEs for the given collapse operation.
* @cc: The collapse control struct
* @vma: The vma to check for userfaultfd
* @order: The folio order being collapsed to
*
- * If we are not in khugepaged mode use HPAGE_PMD_NR to allow any
- * empty page. For PMD-sized collapses (order == HPAGE_PMD_ORDER), use the
- * configured khugepaged_max_ptes_none value.
- *
- * For mTHP collapses, we currently only support khugepaged_max_pte_none values
- * of 0 or (KHUGEPAGED_MAX_PTES_LIMIT). Any other value will emit a warning and
- * no mTHP collapse will be attempted
- *
- * Return: Maximum number of empty PTEs allowed for the collapse operation
+ * Return: Maximum number of none-page or zero-page PTEs allowed for the
+ * collapse operation.
*/
static int collapse_max_ptes_none(struct collapse_control *cc,
struct vm_area_struct *vma, unsigned int order)
{
+ unsigned int max_ptes_none = khugepaged_max_ptes_none;
+ // If the vma is userfaultfd-armed, allow no none-page or zero-page PTEs.
if (vma && userfaultfd_armed(vma))
return 0;
+ // for MADV_COLLAPSE, allow any none-page or zero-page PTEs.
if (!cc->is_khugepaged)
return HPAGE_PMD_NR;
+ // for PMD collapse, respect the user defined maximum.
if (is_pmd_order(order))
- return khugepaged_max_ptes_none;
+ return max_ptes_none;
/* Zero/non-present collapse disabled. */
- if (!khugepaged_max_ptes_none)
+ if (!max_ptes_none)
return 0;
- if (khugepaged_max_ptes_none == KHUGEPAGED_MAX_PTES_LIMIT)
+ // for mTHP collapse with the sysctl value set to KHUGEPAGED_MAX_PTES_LIMIT,
+ // scale the maximum number of PTEs to the order of the collapse.
+ if (max_ptes_none == KHUGEPAGED_MAX_PTES_LIMIT)
return (1 << order) - 1;
+ // We currently only support max_ptes_none values of 0 or KHUGEPAGED_MAX_PTES_LIMIT.
+ // Emit a warning and return -EINVAL.
pr_warn_once("mTHP collapse only supports max_ptes_none values of 0 or %u\n",
KHUGEPAGED_MAX_PTES_LIMIT);
return -EINVAL;
}
/**
- * collapse_max_ptes_shared - Calculate maximum allowed shared PTEs for collapse
+ * collapse_max_ptes_shared - Calculate maximum allowed PTEs that map shared
+ * anonymous pages for the given collapse operation.
* @cc: The collapse control struct
* @order: The folio order being collapsed to
*
- * If we are not in khugepaged mode use HPAGE_PMD_NR to allow any
- * shared page.
- *
- * For mTHP collapses, we currently dont support collapsing memory with
- * shared memory.
- *
- * Return: Maximum number of shared PTEs allowed for the collapse operation
+ * Return: Maximum number of PTEs that map shared anonymous pages for the
+ * collapse operation
*/
static unsigned int collapse_max_ptes_shared(struct collapse_control *cc,
unsigned int order)
{
+ // for MADV_COLLAPSE, do not restrict the number of PTEs that map shared
+ // anonymous pages.
if (!cc->is_khugepaged)
return HPAGE_PMD_NR;
+ // for mTHP collapse do not allow collapsing anonymous memory pages that
+ // are shared between processes.
if (!is_pmd_order(order))
return 0;
-
+ // for PMD collapse, respect the user defined maximum.
return khugepaged_max_ptes_shared;
}
/**
- * collapse_max_ptes_swap - Calculate maximum allowed swap PTEs for collapse
+ * collapse_max_ptes_swap - Calculate the maximum allowed non-present PTEs or the
+ * maximum allowed non-present pagecache entries for the given collapse operation.
* @cc: The collapse control struct
* @order: The folio order being collapsed to
*
- * If we are not in khugepaged mode use HPAGE_PMD_NR to allow any
- * swap page.
- *
- * For PMD-sized collapses (order == HPAGE_PMD_ORDER), use the configured
- * khugepaged_max_ptes_swap value.
- *
- * For mTHP collapses, we currently dont support collapsing memory with
- * swapped out memory.
- *
- * Return: Maximum number of swap PTEs allowed for the collapse operation
+ * Return: Maximum number of non-present PTEs or the maximum allowed non-present
+ * pagecache entries for the collapse operation.
*/
static unsigned int collapse_max_ptes_swap(struct collapse_control *cc,
unsigned int order)
{
+ // for MADV_COLLAPSE, do not restrict the number PTEs entries or
+ // pagecache entries that are non-present.
if (!cc->is_khugepaged)
return HPAGE_PMD_NR;
+ // for mTHP collapse do not allow any non-present PTEs or pagecache entries.
if (!is_pmd_order(order))
return 0;
-
+ // for PMD collapse, respect the user defined maximum.
return khugepaged_max_ptes_swap;
}
@@ -478,7 +476,7 @@ int hugepage_madvise(struct vm_area_stru
* register it here without waiting a page fault that
* may not happen any time soon.
*/
- khugepaged_enter_vma(vma);
+ khugepaged_enter_vma(vma, *vm_flags);
break;
case MADV_NOHUGEPAGE:
*vm_flags &= ~VM_HUGEPAGE;
@@ -579,26 +577,26 @@ void __khugepaged_enter(struct mm_struct
/* Check what orders are allowed based on the vma and collapse type */
static unsigned long collapse_allowable_orders(struct vm_area_struct *vma,
- enum tva_type tva_flags)
+ vm_flags_t vm_flags, enum tva_type tva_flags)
{
unsigned long orders;
/* If khugepaged is scanning an anonymous vma, allow mTHP collapse */
- if ((tva_flags & TVA_KHUGEPAGED) && vma_is_anonymous(vma))
+ if ((tva_flags == TVA_KHUGEPAGED) && vma_is_anonymous(vma))
orders = THP_ORDERS_ALL_ANON;
else
orders = BIT(HPAGE_PMD_ORDER);
- return thp_vma_allowable_orders(vma, vma->vm_flags, tva_flags, orders);
+ return thp_vma_allowable_orders(vma, vm_flags, tva_flags, orders);
}
-void khugepaged_enter_vma(struct vm_area_struct *vma)
+void khugepaged_enter_vma(struct vm_area_struct *vma,
+ vm_flags_t vm_flags)
{
if (!mm_flags_test(MMF_VM_HUGEPAGE, vma->vm_mm) &&
- hugepage_enabled()) {
- if (collapse_allowable_orders(vma, TVA_KHUGEPAGED))
- __khugepaged_enter(vma->vm_mm);
- }
+ collapse_allowable_orders(vma, vm_flags, TVA_KHUGEPAGED) &&
+ hugepage_enabled())
+ __khugepaged_enter(vma->vm_mm);
}
void __khugepaged_exit(struct mm_struct *mm)
@@ -683,7 +681,7 @@ static enum scan_result __collapse_huge_
unsigned int max_ptes_shared = collapse_max_ptes_shared(cc, order);
if (max_ptes_none < 0)
- return result;
+ return SCAN_INVALID_PTES_NONE;
for (_pte = pte; _pte < pte + nr_pages;
_pte++, addr += PAGE_SIZE) {
@@ -905,6 +903,7 @@ static void __collapse_huge_page_copy_fa
{
const unsigned long nr_pages = 1UL << order;
spinlock_t *pmd_ptl;
+
/*
* Re-establish the PMD to point to the original page table
* entry. Restoring PMD needs to be done prior to releasing
@@ -944,6 +943,7 @@ static enum scan_result __collapse_huge_
const unsigned long nr_pages = 1UL << order;
unsigned int i;
enum scan_result result = SCAN_SUCCEED;
+
/*
* Copying pages' contents is subject to memory poison at any iteration.
*/
@@ -1263,10 +1263,20 @@ static enum scan_result alloc_charge_fol
return SCAN_SUCCEED;
}
+/*
+ * collapse_huge_page expects the mmap_read_lock to be dropped before
+ * entering this function. The function will also always return with the lock
+ * dropped. The function starts by allocation a folio, which can potentially
+ * take a long time if it involves sync compaction, and we do not need to hold
+ * the mmap_lock during that. We must recheck the vma after taking it again in
+ * write mode.
+ */
static enum scan_result collapse_huge_page(struct mm_struct *mm, unsigned long start_addr,
int referenced, int unmapped, struct collapse_control *cc,
unsigned int order)
{
+ const unsigned long pmd_addr = start_addr & HPAGE_PMD_MASK;
+ const unsigned long end_addr = start_addr + (PAGE_SIZE << order);
LIST_HEAD(compound_pagelist);
pmd_t *pmd, _pmd;
pte_t *pte = NULL;
@@ -1277,8 +1287,6 @@ static enum scan_result collapse_huge_pa
struct vm_area_struct *vma;
struct mmu_notifier_range range;
bool anon_vma_locked = false;
- const unsigned long pmd_addr = start_addr & HPAGE_PMD_MASK;
- const unsigned long end_addr = start_addr + (PAGE_SIZE << order);
result = alloc_charge_folio(&folio, mm, cc, order);
if (result != SCAN_SUCCEED)
@@ -1399,11 +1407,16 @@ static enum scan_result collapse_huge_pa
__folio_mark_uptodate(folio);
spin_lock(pmd_ptl);
WARN_ON_ONCE(!pmd_none(*pmd));
- if (is_pmd_order(order)) { /* PMD collapse */
+ if (is_pmd_order(order)) {
pgtable = pmd_pgtable(_pmd);
pgtable_trans_huge_deposit(mm, pmd, pgtable);
map_anon_folio_pmd_nopf(folio, pmd, vma, pmd_addr);
- } else { /* mTHP collapse */
+ } else {
+ /*
+ * set_ptes is called in map_anon_folio_pte_nopf with the
+ * pmd_ptl lock still held; this is safe as the PMD is expected
+ * to be none. The pmd entry is then repopulated below.
+ */
map_anon_folio_pte_nopf(folio, pte, vma, start_addr, /*uffd_wp=*/ false);
smp_wmb(); /* make PTEs visible before PMD. See pmd_install() */
pmd_populate(mm, pmd, pmd_pgtable(_pmd));
@@ -1538,12 +1551,12 @@ static int mthp_collapse(struct mm_struc
case SCAN_EXCEED_SHARED_PTE:
case SCAN_PAGE_LOCK:
case SCAN_PAGE_COUNT:
- case SCAN_PAGE_LRU:
case SCAN_PAGE_NULL:
case SCAN_DEL_PAGE_LRU:
case SCAN_PTE_NON_PRESENT:
case SCAN_PTE_UFFD_WP:
case SCAN_ALLOC_HUGE_PAGE_FAIL:
+ case SCAN_PAGE_LAZYFREE:
goto next_order;
/* Cases where no further collapse is possible */
default:
@@ -1569,6 +1582,10 @@ static enum scan_result collapse_scan_pm
struct vm_area_struct *vma, unsigned long start_addr,
bool *lock_dropped, struct collapse_control *cc)
{
+ int max_ptes_none = collapse_max_ptes_none(cc, vma, HPAGE_PMD_ORDER);
+ const unsigned int max_ptes_shared = collapse_max_ptes_shared(cc, HPAGE_PMD_ORDER);
+ const unsigned int max_ptes_swap = collapse_max_ptes_swap(cc, HPAGE_PMD_ORDER);
+ enum tva_type tva_flags = cc->is_khugepaged ? TVA_KHUGEPAGED : TVA_FORCED_COLLAPSE;
pmd_t *pmd;
pte_t *pte, *_pte, pteval;
int i;
@@ -1580,10 +1597,6 @@ static enum scan_result collapse_scan_pm
unsigned long enabled_orders;
spinlock_t *ptl;
int node = NUMA_NO_NODE, unmapped = 0;
- int max_ptes_none = collapse_max_ptes_none(cc, vma, HPAGE_PMD_ORDER);
- unsigned int max_ptes_shared = collapse_max_ptes_shared(cc, HPAGE_PMD_ORDER);
- unsigned int max_ptes_swap = collapse_max_ptes_swap(cc, HPAGE_PMD_ORDER);
- enum tva_type tva_flags = cc->is_khugepaged ? TVA_KHUGEPAGED : TVA_FORCED_COLLAPSE;
VM_BUG_ON(start_addr & ~HPAGE_PMD_MASK);
@@ -1597,7 +1610,7 @@ static enum scan_result collapse_scan_pm
memset(cc->node_load, 0, sizeof(cc->node_load));
nodes_clear(cc->alloc_nmask);
- enabled_orders = collapse_allowable_orders(vma, tva_flags);
+ enabled_orders = collapse_allowable_orders(vma, vma->vm_flags, tva_flags);
/*
* If PMD is the only enabled order, enforce max_ptes_none, otherwise
@@ -1757,12 +1770,7 @@ static enum scan_result collapse_scan_pm
out_unmap:
pte_unmap_unlock(pte, ptl);
if (result == SCAN_SUCCEED) {
- /*
- * Before allocating the hugepage, release the mmap_lock read lock.
- * The allocation can take potentially a long time if it involves
- * sync compaction, and we do not need to hold the mmap_lock during
- * that. We will recheck the vma after taking it again in write mode.
- */
+ /* collapse_huge_page expects the lock to be dropped before calling */
mmap_read_unlock(mm);
nr_collapsed = mthp_collapse(mm, start_addr, referenced, unmapped,
cc, enabled_orders);
@@ -2657,14 +2665,14 @@ static enum scan_result collapse_scan_fi
unsigned long addr, struct file *file, pgoff_t start,
struct collapse_control *cc)
{
+ const int max_ptes_none = collapse_max_ptes_none(cc, NULL, HPAGE_PMD_ORDER);
+ const unsigned int max_ptes_swap = collapse_max_ptes_swap(cc, HPAGE_PMD_ORDER);
struct folio *folio = NULL;
struct address_space *mapping = file->f_mapping;
XA_STATE(xas, &mapping->i_pages, start);
int present, swap;
int node = NUMA_NO_NODE;
enum scan_result result = SCAN_SUCCEED;
- int max_ptes_none = collapse_max_ptes_none(cc, NULL, HPAGE_PMD_ORDER);
- unsigned int max_ptes_swap = collapse_max_ptes_swap(cc, HPAGE_PMD_ORDER);
present = 0;
swap = 0;
@@ -2867,7 +2875,7 @@ static void collapse_scan_mm_slot(unsign
cc->progress++;
break;
}
- if (!collapse_allowable_orders(vma, TVA_KHUGEPAGED)) {
+ if (!collapse_allowable_orders(vma, vma->vm_flags, TVA_KHUGEPAGED)) {
cc->progress++;
continue;
}
@@ -3177,7 +3185,7 @@ int madvise_collapse(struct vm_area_stru
BUG_ON(vma->vm_start > start);
BUG_ON(vma->vm_end < end);
- if (!collapse_allowable_orders(vma, TVA_FORCED_COLLAPSE))
+ if (!collapse_allowable_orders(vma, vma->vm_flags, TVA_FORCED_COLLAPSE))
return -EINVAL;
cc = kmalloc_obj(*cc);
--- a/mm/vma.c~b
+++ a/mm/vma.c
@@ -989,7 +989,7 @@ static __must_check struct vm_area_struc
goto abort;
vma_set_flags_mask(vmg->target, sticky_flags);
- khugepaged_enter_vma(vmg->target);
+ khugepaged_enter_vma(vmg->target, vmg->vm_flags);
vmg->state = VMA_MERGE_SUCCESS;
return vmg->target;
@@ -1110,7 +1110,7 @@ struct vm_area_struct *vma_merge_new_ran
* following VMA if we have VMAs on both sides.
*/
if (vmg->target && !vma_expand(vmg)) {
- khugepaged_enter_vma(vmg->target);
+ khugepaged_enter_vma(vmg->target, vmg->vm_flags);
vmg->state = VMA_MERGE_SUCCESS;
return vmg->target;
}
@@ -2589,7 +2589,7 @@ static int __mmap_new_vma(struct mmap_st
* call covers the non-merge case.
*/
if (!vma_is_anonymous(vma))
- khugepaged_enter_vma(vma);
+ khugepaged_enter_vma(vma, map->vm_flags);
*vmap = vma;
return 0;
--- a/tools/testing/vma/include/stubs.h~b
+++ a/tools/testing/vma/include/stubs.h
@@ -183,7 +183,8 @@ static inline bool mpol_equal(struct mem
return true;
}
-static inline void khugepaged_enter_vma(struct vm_area_struct *vma)
+static inline void khugepaged_enter_vma(struct vm_area_struct *vma,
+ vm_flags_t vm_flags)
{
}
_
^ permalink raw reply
* Re: [PATCH v17 10/11] PCI/CXL: Mask/Unmask CXL protocol errors
From: Bowman, Terry @ 2026-05-11 21:04 UTC (permalink / raw)
To: Dave Jiang, dave, jic23, alison.schofield, djbw, bhelgaas,
shiju.jose, ming.li, Smita.KoralahalliChannabasappa, rrichter,
dan.carpenter, PradeepVineshReddy.Kodamati, lukas,
Benjamin.Cheatham, sathyanarayanan.kuppuswamy, vishal.l.verma,
alucerop, ira.weiny, corbet, rafael, xueshuai, linux-cxl
Cc: linux-kernel, linux-pci, linux-acpi, linux-doc
In-Reply-To: <38155e50-c0c0-4f51-9777-243f0dd049ca@intel.com>
On 5/6/2026 1:00 PM, Dave Jiang wrote:
>
>
> On 5/5/26 10:30 AM, Terry Bowman wrote:
>> CXL protocol errors are not enabled for all CXL devices after boot. They
>> must be enabled in order to process CXL protocol errors. Provide matching
>> teardown helpers so the masks are restored when a CXL Port or Downstream
>> Port goes away.
>>
>> Add pci_aer_mask_internal_errors() as the symmetric counterpart to
>> pci_aer_unmask_internal_errors() and export both for the cxl_core module.
>>
>> Introduce cxl_unmask_proto_interrupts() and cxl_mask_proto_interrupts()
>> in cxl_core to wrap the PCI helpers with the dev_is_pci() and
>> pcie_aer_is_native() gating CXL needs. Both helpers tolerate a NULL
>> @dev so teardown callers do not have to special-case it.
>>
>> Wire cxl_unmask_proto_interrupts() into the success path of
>> cxl_dport_map_ras() and devm_cxl_port_ras_setup() so the unmask only
>> runs when the RAS register block was actually mapped. Pair each unmask
>> with a devm_add_action_or_reset() registration of
>> cxl_mask_proto_interrupts() scoped to the cxl_port device. The mask is
>> then restored when the cxl_port device releases its devres. This
>> applies to Endpoints, Upstream Switch Ports, Downstream Switch Ports,
>> and Root Ports.
>>
>> Co-developed-by: Dan Williams <djbw@kernel.org>
>> Signed-off-by: Dan Williams <djbw@kernel.org>
>> Signed-off-by: Terry Bowman <terry.bowman@amd.com>
>
> Reviewed-by: Dave Jiang <dave.jiang@intel.com>
>
> I do wonder if we should save the original mask values and write those back rather than blindly remask everything when we are done.
>
>
Hi Dave,
This is only masking/unmasking the internal error bit. The other mask bits are not
modified.
- Terry
>>
>> ---
>>
>> Changes in v16->v17:
>> - Drop redundant cxl_mask_proto_interrupts() calls from unregister_port()
>> and cxl_dport_remove(); the devres action registered alongside the unmask
>> is the sole mask path.
>> - Update title
>> - Remove unnecessary check for aer_capabilities
>> - Gate cxl_unmask_proto_interrupts() on pcie_aer_is_native()
>> - Add pci_aer_mask_internal_errors() and cxl_mask_proto_interrupts()
>> - Only unmask on successful cxl_map_component_regs()
>> - NULL-check @dev in cxl_{un,}mask_proto_interrupts()
>> - Drop static and declare in core/core.h
>>
>> Change in v15 -> v16:
>> - None
>>
>> Change in v14 -> v15:
>> - None
>>
>> Changes in v13->v14:
>> - Update commit title's prefix (Bjorn)
>>
>> Changes in v12->v13:
>> - Add dev and dev_is_pci() NULL checks in cxl_unmask_proto_interrupts() (Terry)
>> - Add Dave Jiang's and Ben's review-by
>>
>> Changes in v11->v12:
>> - None
>> ---
>> drivers/cxl/core/core.h | 4 +++
>> drivers/cxl/core/ras.c | 63 ++++++++++++++++++++++++++++++++++++++---
>> drivers/pci/pcie/aer.c | 25 ++++++++++++++++
>> include/linux/aer.h | 2 ++
>> 4 files changed, 90 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
>> index 2c7387506dfb..ff39985d363f 100644
>> --- a/drivers/cxl/core/core.h
>> +++ b/drivers/cxl/core/core.h
>> @@ -190,6 +190,8 @@ void cxl_dport_map_rch_aer(struct cxl_dport *dport);
>> void cxl_disable_rch_root_ints(struct cxl_dport *dport);
>> void cxl_handle_rdport_errors(struct pci_dev *pdev);
>> void devm_cxl_dport_ras_setup(struct cxl_dport *dport);
>> +void cxl_unmask_proto_interrupts(struct device *dev);
>> +void cxl_mask_proto_interrupts(struct device *dev);
>> #else
>> static inline int cxl_ras_init(void)
>> {
>> @@ -207,6 +209,8 @@ static inline void cxl_dport_map_rch_aer(struct cxl_dport *dport) { }
>> static inline void cxl_disable_rch_root_ints(struct cxl_dport *dport) { }
>> static inline void cxl_handle_rdport_errors(struct pci_dev *pdev) { }
>> static inline void devm_cxl_dport_ras_setup(struct cxl_dport *dport) { }
>> +static inline void cxl_unmask_proto_interrupts(struct device *dev) { }
>> +static inline void cxl_mask_proto_interrupts(struct device *dev) { }
>> #endif /* CONFIG_CXL_RAS */
>>
>> int cxl_gpf_port_setup(struct cxl_dport *dport);
>> diff --git a/drivers/cxl/core/ras.c b/drivers/cxl/core/ras.c
>> index a98ce0f412ad..b45e2b539b5f 100644
>> --- a/drivers/cxl/core/ras.c
>> +++ b/drivers/cxl/core/ras.c
>> @@ -66,16 +66,59 @@ static void cxl_cper_prot_err_work_fn(struct work_struct *work)
>> }
>> static DECLARE_WORK(cxl_cper_prot_err_work, cxl_cper_prot_err_work_fn);
>>
>> +void cxl_unmask_proto_interrupts(struct device *dev)
>> +{
>> + struct pci_dev *pdev;
>> +
>> + if (!dev || !dev_is_pci(dev))
>> + return;
>> +
>> + pdev = to_pci_dev(dev);
>> + if (!pcie_aer_is_native(pdev))
>> + return;
>> +
>> + pci_aer_unmask_internal_errors(pdev);
>> +}
>> +
>> +void cxl_mask_proto_interrupts(struct device *dev)
>> +{
>> + struct pci_dev *pdev;
>> +
>> + if (!dev || !dev_is_pci(dev))
>> + return;
>> +
>> + pdev = to_pci_dev(dev);
>> + if (!pcie_aer_is_native(pdev))
>> + return;
>> +
>> + pci_aer_mask_internal_errors(pdev);
>> +}
>> +
>> +static void cxl_mask_proto_irqs(void *dev)
>> +{
>> + cxl_mask_proto_interrupts(dev);
>> +}
>> +
>> static void cxl_dport_map_ras(struct cxl_dport *dport)
>> {
>> struct cxl_register_map *map = &dport->reg_map;
>> struct device *dev = dport->dport_dev;
>>
>> - if (!map->component_map.ras.valid)
>> + if (!map->component_map.ras.valid) {
>> dev_dbg(dev, "RAS registers not found\n");
>> - else if (cxl_map_component_regs(map, &dport->regs.component,
>> - BIT(CXL_CM_CAP_CAP_ID_RAS)))
>> + return;
>> + }
>> +
>> + if (cxl_map_component_regs(map, &dport->regs.component,
>> + BIT(CXL_CM_CAP_CAP_ID_RAS))) {
>> dev_dbg(dev, "Failed to map RAS capability.\n");
>> + return;
>> + }
>> +
>> + cxl_unmask_proto_interrupts(dev);
>> + if (devm_add_action_or_reset(dport_to_host(dport),
>> + cxl_mask_proto_irqs, dev))
>> + dev_warn(dev, "failed to register CXL proto-irq mask cleanup\n");
>> }
>>
>> /**
>> @@ -109,6 +152,7 @@ EXPORT_SYMBOL_NS_GPL(devm_cxl_dport_rch_ras_setup, "CXL");
>> void devm_cxl_port_ras_setup(struct cxl_port *port)
>> {
>> struct cxl_register_map *map = &port->reg_map;
>> + struct device *dev;
>>
>> if (!map->component_map.ras.valid) {
>> dev_dbg(&port->dev, "RAS registers not found\n");
>> @@ -117,8 +161,19 @@ void devm_cxl_port_ras_setup(struct cxl_port *port)
>>
>> map->host = &port->dev;
>> if (cxl_map_component_regs(map, &port->regs,
>> - BIT(CXL_CM_CAP_CAP_ID_RAS)))
>> + BIT(CXL_CM_CAP_CAP_ID_RAS))) {
>> dev_dbg(&port->dev, "Failed to map RAS capability\n");
>> + return;
>> + }
>> +
>> + dev = is_cxl_endpoint(port) ? port->uport_dev->parent : port->uport_dev;
>> + if (!dev_is_pci(dev))
>> + return;
>> +
>> + cxl_unmask_proto_interrupts(dev);
>> + if (devm_add_action_or_reset(&port->dev, cxl_mask_proto_irqs, dev))
>> + dev_warn(&port->dev,
>> + "Failed to register CXL proto-irq mask cleanup\n");
>> }
>> EXPORT_SYMBOL_NS_GPL(devm_cxl_port_ras_setup, "CXL");
>>
>> diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
>> index b9c6c7b97217..eaa36fe0eb31 100644
>> --- a/drivers/pci/pcie/aer.c
>> +++ b/drivers/pci/pcie/aer.c
>> @@ -1151,6 +1151,31 @@ void pci_aer_unmask_internal_errors(struct pci_dev *dev)
>> */
>> EXPORT_SYMBOL_FOR_MODULES(pci_aer_unmask_internal_errors, "cxl_core");
>>
>> +/**
>> + * pci_aer_mask_internal_errors - mask internal errors
>> + * @dev: pointer to the pci_dev data structure
>> + *
>> + * Mask internal errors in the Uncorrectable and Correctable Error
>> + * Mask registers.
>> + *
>> + * Note: AER must be enabled and supported by the device which must be
>> + * checked in advance, e.g. with pcie_aer_is_native().
>> + */
>> +void pci_aer_mask_internal_errors(struct pci_dev *dev)
>> +{
>> + int aer = dev->aer_cap;
>> + u32 mask;
>> +
>> + pci_read_config_dword(dev, aer + PCI_ERR_UNCOR_MASK, &mask);
>> + mask |= PCI_ERR_UNC_INTN;
>> + pci_write_config_dword(dev, aer + PCI_ERR_UNCOR_MASK, mask);
>> +
>> + pci_read_config_dword(dev, aer + PCI_ERR_COR_MASK, &mask);
>> + mask |= PCI_ERR_COR_INTERNAL;
>> + pci_write_config_dword(dev, aer + PCI_ERR_COR_MASK, mask);
>> +}
>> +EXPORT_SYMBOL_FOR_MODULES(pci_aer_mask_internal_errors, "cxl_core");
>> +
>> /**
>> * pci_aer_handle_error - handle logging error into an event log
>> * @dev: pointer to pci_dev data structure of error source device
>> diff --git a/include/linux/aer.h b/include/linux/aer.h
>> index 979ed2f9fd38..c52db62d4c7e 100644
>> --- a/include/linux/aer.h
>> +++ b/include/linux/aer.h
>> @@ -71,6 +71,7 @@ int pci_aer_clear_nonfatal_status(struct pci_dev *dev);
>> void pci_aer_clear_fatal_status(struct pci_dev *dev);
>> int pcie_aer_is_native(struct pci_dev *dev);
>> void pci_aer_unmask_internal_errors(struct pci_dev *dev);
>> +void pci_aer_mask_internal_errors(struct pci_dev *dev);
>> #else
>> static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
>> {
>> @@ -79,6 +80,7 @@ static inline int pci_aer_clear_nonfatal_status(struct pci_dev *dev)
>> static inline void pci_aer_clear_fatal_status(struct pci_dev *dev) { }
>> static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; }
>> static inline void pci_aer_unmask_internal_errors(struct pci_dev *dev) { }
>> +static inline void pci_aer_mask_internal_errors(struct pci_dev *dev) { }
>> #endif
>>
>> #ifdef CONFIG_CXL_RAS
>
^ permalink raw reply
* Re: [PATCH] crypto: af_alg - Document the deprecation of AF_ALG
From: Ignat Korchagin @ 2026-05-11 21:03 UTC (permalink / raw)
To: Eric Biggers, Kamran Khan
Cc: Jeff Barnes, Andy Lutomirski, linux-crypto@vger.kernel.org,
Herbert Xu, linux-doc@vger.kernel.org, linux-api@vger.kernel.org,
linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
Linus Torvalds
In-Reply-To: <20260510163204.GA2279@sol>
On 10/05/2026 17:32, Eric Biggers wrote:
> On Sun, May 10, 2026 at 08:54:07AM -0700, Kamran Khan wrote:
>> Hi,
>>
>> AF_ALG is useful not just for hardware-offloading, but also for memory
>> isolation so that applications only get oracle access to the crypto keys and
>> a memory-safety vulnerability in user applications would not immediately put
>> the secret key material at risk.
> Note that if that memory-safety vulnerability leads to code execution in
> the application, then it doesn't matter that it "only" has oracle
> access. It can still decrypt any data encrypted by that key.
I don't think fully discounting hardware offloading is beneficial here.
HW accelerators will be produced and without a common interface vendors
would start implementing their own "bespoke" drivers with bespoke
userspace interfaces (we already had such proposals), which in turn may
introduce more attack surface. Yes, AF_ALG needs substantial
improvement, but at least it can be a standardisation point.
> The relevant threat model would be arbitrary reads, not any
> "memory-safety vulnerability".
>
>> I understand and appreciate the concern with complex attack surface and the
>> increased frequency of attacks in this area. But I fear that completely
>> removing AF_ALG increases the risk for userspace applications relying on it
>> for memory isolation.
>>
>> What alternatives do userspace applications have on Linux for ensuring
>> crypto keys are not exposed in user memory? That is, FreeBSD and NetBSD
>> natively provide /dev/crypto; removing AF_ALG would kill the only equivalent
>> option on the Linux side for kernel-delegated cryptography.
> The standard solution is simply to use an isolated userspace process
> like ssh-agent. Yes, the keys will be in "user memory". But "not
> exposed in user memory" is *not* a correct statement of the problem.
>
> (Also note that protecting not-actively-in-use data from arbitrary read
> primitives doesn't require cryptography at all. That can be done simply
> by using mprotect() to remove read permission from the memory, then
> temporarily adding it back when it needs to be accessed.)
>
> In any case, any hypothetical security benefit provided by AF_ALG would
> have to be *very high* to outweigh the continuous stream of
> vulnerabilities in it. I understand that people using AF_ALG might not
> be familiar with that continuous stream of vulnerabilities, but it would
Is it actually that much compared to other features/subsystems, like
eBPF or user namespaces? But we don't rush to deprecate those - instead
trying to harden them and come up with better design.
> be worth spending some time researching what has been going on.
>
> - Eric
Ignat
^ permalink raw reply
* [pdx86-platform-drivers-x86:review-ilpo-next 21/30] htmldocs: Warning: MAINTAINERS references a file that doesn't exist: Documentation/devicetree/bindings/embedded-controller/qcom,hamoa-crd-ec.yaml
From: kernel test robot @ 2026-05-11 20:59 UTC (permalink / raw)
To: Sibi Sankar
Cc: oe-kbuild-all, Andy Shevchenko, Hans de Goede,
Ilpo Järvinen , Maya Matuszczyk, Dmitry Baryshkov,
Anvesh Jain P, linux-doc
tree: https://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git review-ilpo-next
head: 165e81354eefd5551358112773f24027aac59d5a
commit: 5c44f48e91deefdd42e567a2779d331937c97cd0 [21/30] platform: arm64: Add driver for EC found on Qualcomm reference devices
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/20260511/202605112207.TL7dR71j-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/202605112207.TL7dR71j-lkp@intel.com/
All warnings (new ones prefixed by >>):
Warning: Documentation/translations/zh_CN/how-to.rst references a file that doesn't exist: Documentation/xxx/xxx.rst
Warning: Documentation/translations/zh_CN/networking/xfrm_proc.rst references a file that doesn't exist: Documentation/networking/xfrm_proc.rst
Warning: Documentation/translations/zh_CN/scsi/scsi_mid_low_api.rst references a file that doesn't exist: Documentation/Configure.help
Warning: MAINTAINERS references a file that doesn't exist: Documentation/ABI/testing/sysfs-platform-ayaneo
Warning: MAINTAINERS references a file that doesn't exist: Documentation/devicetree/bindings/display/bridge/megachips-stdpxxxx-ge-b850v3-fw.txt
>> Warning: MAINTAINERS references a file that doesn't exist: Documentation/devicetree/bindings/embedded-controller/qcom,hamoa-crd-ec.yaml
Warning: arch/powerpc/sysdev/mpic.c references a file that doesn't exist: Documentation/devicetree/bindings/powerpc/fsl/mpic.txt
Warning: drivers/net/ethernet/smsc/Kconfig references a file that doesn't exist: file:Documentation/networking/device_drivers/ethernet/smsc/smc9.rst
Warning: rust/kernel/sync/atomic/ordering.rs references a file that doesn't exist: srctree/tools/memory-model/Documentation/explanation.txt
Warning: tools/docs/documentation-file-ref-check references a file that doesn't exist: Documentation/virtual/lguest/lguest.c
Warning: tools/docs/documentation-file-ref-check references a file that doesn't exist: m,\b(\S*)(Documentation/[A-Za-z0-9
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox