Re: [RFC PATCH 2/3] luo: Export feature support to vmlinux section
From: Pratyush Yadav
Date: Thu Oct 15 2026 - 09:28:45 EST
Hi Logan,
On Wed, Sep 02 2026, Logan Odell wrote:
> Create a liveupdate_features section that contains the feature
> information for a given liveupdate component. Add the LUO component
> first. These can be compared between two kernels to determine live
> update compatibility. Features marked as required in the running kernel
> will need to have that feature marked as supported in the next kernel to
> be eligible for compatibility.
>
> Suggested-by: Pratyush Yadav <pratyush@xxxxxxxxxx>
> Signed-off-by: Logan Odell <loganodell@xxxxxxxxxx>
I was thinking about this a bit more. We don't really ship the vmlinux
directly. On x86 it is a PE/COFF image, on arm64 the Image format strips
ELF information and is a raw binary file.
So this information would not be accessible to the kexec loader/luod. So
perhaps as part of the build we parse the section and output a file with
the versions? And then it can be packaged with the likes of System.map
for example?
> ---
> include/asm-generic/vmlinux.lds.h | 12 +++++++++++
> include/linux/kho/abi/luo.h | 34 +++++++++++++++++++++++++++++++
> include/linux/liveupdate.h | 12 +++++++++++
> kernel/liveupdate/luo_core.c | 16 +++++++++++++++
> 4 files changed, 74 insertions(+)
>
> diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
> index 5659f4b5a125..aed4e282a78c 100644
> --- a/include/asm-generic/vmlinux.lds.h
> +++ b/include/asm-generic/vmlinux.lds.h
> @@ -359,6 +359,17 @@
> #define THERMAL_TABLE(name)
> #endif
>
> +#ifdef CONFIG_LIVEUPDATE
> +#define LIVEUPDATE_FEATURES \
> + . = ALIGN(8); \
> + .liveupdate_features : AT(ADDR(.liveupdate_features) - LOAD_OFFSET) { \
> + KEEP(*(.liveupdate_sec_hdr)) \
> + KEEP(*(.liveupdate_features)) \
> + }
> +#else
> +#define LIVEUPDATE_FEATURES
> +#endif
> +
> #define KERNEL_DTB() \
> STRUCT_ALIGN(); \
> __dtb_start = .; \
> @@ -554,6 +565,7 @@
> RO_EXCEPTION_TABLE \
> NOTES \
> BTF \
> + LIVEUPDATE_FEATURES \
> \
> . = ALIGN((align)); \
> __end_rodata = .;
> diff --git a/include/linux/kho/abi/luo.h b/include/linux/kho/abi/luo.h
> index 0a7662a0cf9a..5b25e1b48cf5 100644
> --- a/include/linux/kho/abi/luo.h
> +++ b/include/linux/kho/abi/luo.h
> @@ -230,4 +230,38 @@ struct luo_flb_ser {
> #define LIVEUPDATE_TEST_FLB_COMPATIBLE(i) "liveupdate-test-flb-v" #i
> #endif
>
> +#define LIVEUPDATE_VER_HDR_MAGIC 0x4c565550 /* 'LVUP' */
> +#define LIVEUPDATE_VER_HDR_VER 1
> +
> +/**
> + * struct liveupdate_ver_hdr - Header of vmlinux section with version lists
> + * @magic: Magic number ('LVUP').
> + * @version: Version of the header format.
> + *
> + * This struct is the header for the vmlinux section ".liveupdate_features". The
> + * section contains the list of feature/version entries that the kernel supports.
> + */
> +struct liveupdate_ver_hdr {
> + u32 magic;
> + u32 version;
Should we do feature flags along with the version to extend in
backwards-compatible way?
> +} __packed;
> +
> +/**
> + * struct liveupdate_feature_entry - Live update feature/version entry
> + * @name: Name of the subsystem or feature ("luo" for core).
> + * @feat_bytes: Number of bytes covered by supp, req, and active bitmaps (e.g. 8).
> + * @reserved: Reserved / padding for alignment.
> + * @supp: Bitmask of supported features.
> + * @req: Bitmask of required features.
> + * @active: Bitmask of active features.
> + */
How should we model FLB dependencies here? And how do we export FLB
capabilities?
> +struct liveupdate_feature_entry {
> + char name[LIVEUPDATE_HNDL_COMPAT_LENGTH];
> + u32 feat_bytes;
> + u32 reserved;
> + u64 supp;
> + u64 req;
> + u64 active;
> +} __packed;
> +
> #endif /* _LINUX_KHO_ABI_LUO_H */
> diff --git a/include/linux/liveupdate.h b/include/linux/liveupdate.h
> index 6051abc0612c..e058df23fed1 100644
> --- a/include/linux/liveupdate.h
> +++ b/include/linux/liveupdate.h
> @@ -229,6 +229,16 @@ struct liveupdate_flb {
>
> #ifdef CONFIG_LIVEUPDATE
>
> +#define LIVEUPDATE_FEATURE_ENTRY(_id, _name, _supp, _req, _active) \
> + static const struct liveupdate_feature_entry __lu_feat_##_id \
> + __used __section(".liveupdate_features") __aligned(8) = { \
> + .name = _name, \
> + .feat_bytes = sizeof(u64), \
> + .supp = (_supp), \
> + .req = (_req), \
> + .active = (_active), \
> + }
> +
> /* Return true if live update orchestrator is enabled */
> bool liveupdate_enabled(void);
>
> @@ -259,6 +269,8 @@ int liveupdate_get_token_outgoing(struct liveupdate_session *s,
>
> #else /* CONFIG_LIVEUPDATE */
>
> +#define LIVEUPDATE_FEATURE_ENTRY(_id, _name, _supp, _req, _active)
> +
> static inline bool liveupdate_enabled(void)
> {
> return false;
> diff --git a/kernel/liveupdate/luo_core.c b/kernel/liveupdate/luo_core.c
> index 6add1ecc463f..27413f895174 100644
> --- a/kernel/liveupdate/luo_core.c
> +++ b/kernel/liveupdate/luo_core.c
> @@ -64,6 +64,22 @@
> #include "kexec_handover_internal.h"
> #include "luo_internal.h"
>
> +/*
> + * This is the header for the ".liveupdate_features" section in vmlinux.
> + * The linker makes sure that this header precedes the entries.
> + */
> +static const struct liveupdate_ver_hdr ver_hdr
> + __used __section(".liveupdate_sec_hdr") __aligned(8) = {
> + .magic = LIVEUPDATE_VER_HDR_MAGIC,
> + .version = LIVEUPDATE_VER_HDR_VER,
> +};
> +
> +/* Core LUO features */
> +LIVEUPDATE_FEATURE_ENTRY(luo_core, "luo",
> + LUO_CORE_FEATURES_SUPP,
> + LUO_CORE_FEATURES_REQ,
> + LUO_CORE_FEATURES_ACTIVE);
> +
> static struct {
> bool enabled;
> struct luo_ser *luo_ser_out;
--
Regards,
Pratyush Yadav