[RFC PATCH 16/46] liveupdate: cpu_preserve: Add sysfs interface
From: Pasha Tatashin
Date: Sun Sep 20 2026 - 15:40:14 EST
Expose /sys/devices/system/cpu/preserved (global cpumask of preserved
cores) and /sys/devices/system/cpu/cpuX/preserve (per-CPU preservation
attribute and file descriptor target for LUO sessions), and document
both attributes in Documentation/ABI/testing/sysfs-devices-system-cpu.
Signed-off-by: Pasha Tatashin <pasha.tatashin@xxxxxxxxxx>
---
.../ABI/testing/sysfs-devices-system-cpu | 20 ++++++++
kernel/liveupdate/cpu_preserve.c | 49 +++++++++++++++++++
2 files changed, 69 insertions(+)
diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu
index 82d10d556cc8..88ab03efd433 100644
--- a/Documentation/ABI/testing/sysfs-devices-system-cpu
+++ b/Documentation/ABI/testing/sysfs-devices-system-cpu
@@ -806,3 +806,23 @@ Date: Nov 2022
Contact: Linux kernel mailing list <linux-kernel@xxxxxxxxxxxxxxx>
Description:
(RO) the list of CPUs that can be brought online.
+
+What: /sys/devices/system/cpu/preserved
+Date: March 2026
+Contact: Pasha Tatashin <pasha.tatashin@xxxxxxxxxx>
+Description:
+ (RO) cpumask list of physical CPUs currently isolated and
+ preserved across a host kernel live update. Note the naming
+ distinction from the per-CPU /sys/devices/system/cpu/cpuX/preserve
+ attribute.
+
+What: /sys/devices/system/cpu/cpuX/preserve
+Date: March 2026
+Contact: Pasha Tatashin <pasha.tatashin@xxxxxxxxxx>
+Description:
+ (RO) returns 1 if cpuX is currently preserved across a host
+ kernel live update, 0 otherwise. Although read-only, this sysfs
+ node exists to be opened and passed by file descriptor to a Live
+ Update Orchestrator (LUO) session via LIVEUPDATE_SESSION_PRESERVE_FD
+ to request preservation of cpuX across kexec.
+
diff --git a/kernel/liveupdate/cpu_preserve.c b/kernel/liveupdate/cpu_preserve.c
index c5fd3a07ccb5..cc27d1624d29 100644
--- a/kernel/liveupdate/cpu_preserve.c
+++ b/kernel/liveupdate/cpu_preserve.c
@@ -606,3 +606,52 @@ static int __init cpu_preserve_early_init(void)
return 0;
}
early_initcall(cpu_preserve_early_init);
+static ssize_t preserved_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sysfs_emit(buf, "%*pbl\n",
+ cpumask_pr_args(cpu_get_preserved_mask()));
+}
+static DEVICE_ATTR_RO(preserved);
+
+static ssize_t preserve_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sysfs_emit(buf, "%d\n", cpu_is_preserved(dev->id));
+}
+static DEVICE_ATTR_RO(preserve);
+
+static int __init cpu_preserve_sysfs_init(void)
+{
+ struct device *dev_root = bus_get_dev_root(&cpu_subsys);
+ int cpu, ret;
+
+ if (dev_root) {
+ ret = sysfs_create_file(&dev_root->kobj, &dev_attr_preserved.attr);
+ put_device(dev_root);
+ if (ret)
+ pr_warn("Failed to create cpu preserved sysfs attribute: %d\n", ret);
+ }
+
+ for_each_possible_cpu(cpu) {
+ struct device *dev = get_cpu_device(cpu);
+
+ if (!dev && cpu_is_preserved(cpu)) {
+ set_cpu_present(cpu, true);
+ arch_register_cpu(cpu);
+ dev = get_cpu_device(cpu);
+ }
+
+ if (dev) {
+ ret = sysfs_create_file(&dev->kobj, &dev_attr_preserve.attr);
+ if (ret)
+ pr_warn("Failed to create cpu%d preserve sysfs attribute: %d\n",
+ cpu, ret);
+ }
+
+ if (cpu_is_preserved(cpu))
+ set_cpu_present(cpu, false);
+ }
+ return 0;
+}
+late_initcall(cpu_preserve_sysfs_init);
--
2.55.0.1082.g2b9226bbc0-goog