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 <[email protected]> --- .../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 <[email protected]> Description: (RO) the list of CPUs that can be brought online. + +What: /sys/devices/system/cpu/preserved +Date: March 2026 +Contact: Pasha Tatashin <[email protected]> +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 <[email protected]> +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

