From: Chris Down <chris@chrisdown.name>
To: Pasha Tatashin <pasha.tatashin@soleen.com>,
Mike Rapoport <rppt@kernel.org>,
Pratyush Yadav <pratyush@kernel.org>
Cc: Alexander Graf <graf@amazon.com>,
Baoquan He <baoquan.he@linux.dev>,
Jonathan Corbet <corbet@lwn.net>,
Shuah Khan <skhan@linuxfoundation.org>,
kexec@lists.infradead.org, linux-mm@kvack.org,
linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kselftest@vger.kernel.org, kernel-team@meta.com
Subject: [PATCH 6/9] kho: Expose rejected handovers that look like cold boots
Date: Tue, 10 Nov 2026 23:53:30 -0800 [thread overview]
Message-ID: <abfe907e8da92802cd5e0c843d8013e4d229aab3.1794383544.git.chris@chrisdown.name> (raw)
In-Reply-To: <cover.1794383544.git.chris@chrisdown.name>
At Meta, our rollout needs to stop if the new kernel rejects the KHO
handover. For example, if it doesn't recognise the handover FDT's
compatible string, it can boot normally with all the preserved state
lost. LUO's incoming/state reads "none", as on a cold boot. We log
"disabling KHO revival", but our fleet collector reads procfs and sysfs
and can't rely on kernel logs from every host.
Let's add /sys/kernel/kexec/kho_incoming/state so the collector can tell
a rejected handover from an ordinary boot. "revived" means the kernel
accepted the handover and completed the preserved memory map walk. LUO
reports the outcome of restoring sessions separately.
Signed-off-by: Chris Down <chris@chrisdown.name>
---
.../ABI/testing/sysfs-class-misc-liveupdate | 3 ++
.../ABI/testing/sysfs-kernel-kexec-kdump | 12 +++++++
Documentation/admin-guide/mm/kho.rst | 3 ++
include/linux/kexec_handover.h | 2 ++
kernel/kexec_core.c | 13 ++++++-
kernel/liveupdate/kexec_handover.c | 34 +++++++++++++++++++
6 files changed, 66 insertions(+), 1 deletion(-)
diff --git a/Documentation/ABI/testing/sysfs-class-misc-liveupdate b/Documentation/ABI/testing/sysfs-class-misc-liveupdate
index 25e3b49d7aeb..608f788ef0fa 100644
--- a/Documentation/ABI/testing/sysfs-class-misc-liveupdate
+++ b/Documentation/ABI/testing/sysfs-class-misc-liveupdate
@@ -19,6 +19,9 @@ Description: read only
"deserialized" The sessions can be retrieved.
"failed" Deserialization failed. Opening
/dev/liveupdate returns -EIO.
+
+ See /sys/kernel/kexec/kho_incoming/state for the status of
+ the underlying KHO handover.
Users: system monitoring
What: /sys/class/misc/liveupdate/incoming/sessions
diff --git a/Documentation/ABI/testing/sysfs-kernel-kexec-kdump b/Documentation/ABI/testing/sysfs-kernel-kexec-kdump
index 80941a7d8a7c..5636cd060cb2 100644
--- a/Documentation/ABI/testing/sysfs-kernel-kexec-kdump
+++ b/Documentation/ABI/testing/sysfs-kernel-kexec-kdump
@@ -67,3 +67,15 @@ Description: read only
Total size of the KHO bootmem regions in bytes. Returns 0
when KHO is disabled.
User: system monitoring
+
+What: /sys/kernel/kexec/kho_incoming/state
+Date: Nov 2026
+Contact: kexec@lists.infradead.org
+Description: read only
+ Status of the incoming KHO handover:
+
+ "none" No handover was passed to this kernel.
+ "revived" The kernel accepted the handover and completed
+ the walk of its preserved memory map.
+ "failed" The kernel rejected the handover.
+User: system monitoring
diff --git a/Documentation/admin-guide/mm/kho.rst b/Documentation/admin-guide/mm/kho.rst
index c329d720bf25..9d74d4ce18b5 100644
--- a/Documentation/admin-guide/mm/kho.rst
+++ b/Documentation/admin-guide/mm/kho.rst
@@ -88,6 +88,9 @@ sysfs Interfaces
Total size of the KHO bootmem regions in bytes, or 0 when KHO is
disabled.
+``/sys/kernel/kexec/kho_incoming/state``
+ Status of the incoming KHO handover.
+
See Documentation/ABI/testing/sysfs-kernel-kexec-kdump for the sysfs ABI.
debugfs Interfaces
diff --git a/include/linux/kexec_handover.h b/include/linux/kexec_handover.h
index 736d51e79fd2..1f37d2300e26 100644
--- a/include/linux/kexec_handover.h
+++ b/include/linux/kexec_handover.h
@@ -42,6 +42,8 @@ void kho_populate(phys_addr_t fdt_phys, u64 fdt_len, phys_addr_t bootmem_phys,
bool kho_bootmem_overlap(phys_addr_t phys, size_t size);
phys_addr_t kho_bootmem_size(void);
+extern const struct attribute_group kho_incoming_attr_group;
+
static inline enum migratetype kho_bootmem_migratetype(unsigned long pfn,
enum migratetype mt)
{
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index ed105e6351eb..c1085a53b7f4 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -1372,7 +1372,18 @@ static struct kexec_link_entry kexec_links[] = {
};
static struct kobject *kexec_kobj;
-ATTRIBUTE_GROUPS(kexec);
+
+static const struct attribute_group kexec_group = {
+ .attrs = kexec_attrs,
+};
+
+static const struct attribute_group *kexec_groups[] = {
+ &kexec_group,
+#ifdef CONFIG_KEXEC_HANDOVER
+ &kho_incoming_attr_group,
+#endif
+ NULL
+};
static int __init init_kexec_sysctl(void)
{
diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c
index 21d77e29d2bb..dfd6fa7e4a71 100644
--- a/kernel/liveupdate/kexec_handover.c
+++ b/kernel/liveupdate/kexec_handover.c
@@ -19,6 +19,7 @@
#include <linux/kexec.h>
#include <linux/kexec_handover.h>
#include <linux/kho_radix_tree.h>
+#include <linux/kobject.h>
#include <linux/utsname.h>
#include <linux/kho/abi/kexec_handover.h>
#include <linux/kho/abi/kexec_metadata.h>
@@ -97,11 +98,18 @@ static struct kho_out kho_out = {
},
};
+enum kho_incoming_state {
+ KHO_INCOMING_NONE,
+ KHO_INCOMING_REVIVED,
+ KHO_INCOMING_FAILED,
+};
+
struct kho_in {
phys_addr_t fdt_phys;
phys_addr_t bootmem_phys;
char previous_release[__NEW_UTS_LEN + 1];
u32 kexec_count;
+ enum kho_incoming_state state;
struct kho_debugfs dbg;
struct kho_radix_tree radix_tree;
};
@@ -957,6 +965,29 @@ phys_addr_t kho_bootmem_size(void)
return size;
}
+static const char * const kho_incoming_state_names[] = {
+ [KHO_INCOMING_NONE] = "none",
+ [KHO_INCOMING_REVIVED] = "revived",
+ [KHO_INCOMING_FAILED] = "failed",
+};
+
+static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ return sysfs_emit(buf, "%s\n", kho_incoming_state_names[kho_in.state]);
+}
+static struct kobj_attribute state_attr = __ATTR_RO(state);
+
+static struct attribute *kho_incoming_attrs[] = {
+ &state_attr.attr,
+ NULL
+};
+
+const struct attribute_group kho_incoming_attr_group = {
+ .name = "kho_incoming",
+ .attrs = kho_incoming_attrs,
+};
+
/*
* Look for free blocks of 1G. This is a heuristic chosen to work efficiently
* with large systems with hundreds of gigabytes of memory. It will work poorly
@@ -1753,6 +1784,7 @@ static void __init kho_mem_retrieve(void)
*/
kho_in.fdt_phys = 0;
kho_in.radix_tree.root = NULL;
+ kho_in.state = KHO_INCOMING_FAILED;
}
static __init int kho_out_fdt_setup(void)
@@ -1992,6 +2024,7 @@ void __init kho_memory_init_early(void)
*/
kho_in.fdt_phys = 0;
kho_in.bootmem_phys = 0;
+ kho_in.state = KHO_INCOMING_FAILED;
}
void __init kho_memory_init(void)
@@ -2090,6 +2123,7 @@ void __init kho_populate(phys_addr_t fdt_phys, u64 fdt_len,
unmap_fdt:
early_memunmap(fdt, fdt_len);
report:
+ kho_in.state = populated ? KHO_INCOMING_REVIVED : KHO_INCOMING_FAILED;
if (!populated)
pr_warn("disabling KHO revival\n");
}
--
2.54.0
next prev parent reply other threads:[~2026-11-11 7:53 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-11 7:52 [PATCH 0/9] kho, liveupdate: KHO/LUO observability Chris Down
2026-11-11 7:52 ` [PATCH 1/9] kho: Reclaim the metadata page left reserved after kexec Chris Down
2026-11-11 7:53 ` [PATCH 2/9] kho: Make bootmem reservations visible to fleet monitoring Chris Down
2026-11-11 7:53 ` [PATCH 3/9] liveupdate: Make failed retrieves distinguishable from dropped files Chris Down
2026-11-11 7:53 ` [PATCH 4/9] selftests/liveupdate: Catch incorrect file accounting across kexec Chris Down
2026-11-11 7:53 ` [PATCH 5/9] selftests/kho: Catch missing or zero bootmem reports before kexec Chris Down
2026-11-11 7:53 ` Chris Down [this message]
2026-11-11 7:53 ` [PATCH 7/9] kho: Report how much handover memory is preserved and restored Chris Down
2026-11-11 7:53 ` [PATCH 8/9] liveupdate: Expose the sequence number for consecutive live updates Chris Down
2026-11-11 7:53 ` [PATCH 9/9] selftests/liveupdate: Check handover revival, sequence and memory stats Chris Down
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=abfe907e8da92802cd5e0c843d8013e4d229aab3.1794383544.git.chris@chrisdown.name \
--to=chris@chrisdown.name \
--cc=baoquan.he@linux.dev \
--cc=corbet@lwn.net \
--cc=graf@amazon.com \
--cc=kernel-team@meta.com \
--cc=kexec@lists.infradead.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=pasha.tatashin@soleen.com \
--cc=pratyush@kernel.org \
--cc=rppt@kernel.org \
--cc=skhan@linuxfoundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®