Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

tests/liveupdate: add in-kernel liveupdate test

Introduce an in-kernel test module to validate the core logic of the Live
Update Orchestrator's File-Lifecycle-Bound feature. This provides a
low-level, controlled environment to test FLB registration and callback
invocation without requiring userspace interaction or actual kexec
reboots.

The test is enabled by the CONFIG_LIVEUPDATE_TEST Kconfig option.

Link: https://lkml.kernel.org/r/20251218155752.3045808-6-pasha.tatashin@soleen.com
Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Cc: Alexander Graf <graf@amazon.com>
Cc: David Gow <davidgow@google.com>
Cc: David Matlack <dmatlack@google.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Kees Cook <kees@kernel.org>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Petr Mladek <pmladek@suse.com>
Cc: Pratyush Yadav <pratyush@kernel.org>
Cc: Samiullah Khawaja <skhawaja@google.com>
Cc: Tamir Duberstein <tamird@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Pasha Tatashin and committed by
Andrew Morton
f653ff7a cab056f2

+203 -1
+1
MAINTAINERS
··· 14652 14652 F: include/linux/liveupdate/ 14653 14653 F: include/uapi/linux/liveupdate.h 14654 14654 F: kernel/liveupdate/ 14655 + F: lib/tests/liveupdate.c 14655 14656 F: mm/memfd_luo.c 14656 14657 F: tools/testing/selftests/liveupdate/ 14657 14658
+5
include/linux/kho/abi/luo.h
··· 239 239 u64 count; 240 240 } __packed; 241 241 242 + /* Kernel Live Update Test ABI */ 243 + #ifdef CONFIG_LIVEUPDATE_TEST 244 + #define LIVEUPDATE_TEST_FLB_COMPATIBLE(i) "liveupdate-test-flb-v" #i 245 + #endif 246 + 242 247 #endif /* _LINUX_KHO_ABI_LUO_H */
+7 -1
kernel/liveupdate/luo_file.c
··· 864 864 list_add_tail(&ACCESS_PRIVATE(fh, list), &luo_file_handler_list); 865 865 luo_session_resume(); 866 866 867 + liveupdate_test_register(fh); 868 + 867 869 return 0; 868 870 869 871 err_resume: ··· 897 895 if (!liveupdate_enabled()) 898 896 return -EOPNOTSUPP; 899 897 898 + liveupdate_test_unregister(fh); 899 + 900 900 if (!luo_session_quiesce()) 901 - return -EBUSY; 901 + goto err_register; 902 902 903 903 if (!list_empty(&ACCESS_PRIVATE(fh, flb_list))) 904 904 goto err_resume; ··· 913 909 914 910 err_resume: 915 911 luo_session_resume(); 912 + err_register: 913 + liveupdate_test_register(fh); 916 914 return err; 917 915 }
+8
kernel/liveupdate/luo_internal.h
··· 107 107 int __init luo_flb_setup_incoming(void *fdt); 108 108 void luo_flb_serialize(void); 109 109 110 + #ifdef CONFIG_LIVEUPDATE_TEST 111 + void liveupdate_test_register(struct liveupdate_file_handler *fh); 112 + void liveupdate_test_unregister(struct liveupdate_file_handler *fh); 113 + #else 114 + static inline void liveupdate_test_register(struct liveupdate_file_handler *fh) { } 115 + static inline void liveupdate_test_unregister(struct liveupdate_file_handler *fh) { } 116 + #endif 117 + 110 118 #endif /* _LINUX_LUO_INTERNAL_H */
+23
lib/Kconfig.debug
··· 2825 2825 2826 2826 If unsure, say N. 2827 2827 2828 + config LIVEUPDATE_TEST 2829 + bool "Live Update Kernel Test" 2830 + default n 2831 + depends on LIVEUPDATE 2832 + help 2833 + Enable a built-in kernel test module for the Live Update 2834 + Orchestrator. 2835 + 2836 + This module validates the File-Lifecycle-Bound subsystem by 2837 + registering a set of mock FLB objects with any real file handlers 2838 + that support live update (such as the memfd handler). 2839 + 2840 + When live update operations are performed, this test module will 2841 + output messages to the kernel log (dmesg), confirming that its 2842 + registration and various callback functions (preserve, retrieve, 2843 + finish, etc.) are being invoked correctly. 2844 + 2845 + This is a debugging and regression testing tool for developers 2846 + working on the Live Update subsystem. It should not be enabled in 2847 + production kernels. 2848 + 2849 + If unsure, say N 2850 + 2828 2851 config CMDLINE_KUNIT_TEST 2829 2852 tristate "KUnit test for cmdline API" if !KUNIT_ALL_TESTS 2830 2853 depends on KUNIT
+1
lib/tests/Makefile
··· 30 30 obj-$(CONFIG_KFIFO_KUNIT_TEST) += kfifo_kunit.o 31 31 obj-$(CONFIG_TEST_LIST_SORT) += test_list_sort.o 32 32 obj-$(CONFIG_LINEAR_RANGES_TEST) += test_linear_ranges.o 33 + obj-$(CONFIG_LIVEUPDATE_TEST) += liveupdate.o 33 34 34 35 CFLAGS_longest_symbol_kunit.o += $(call cc-disable-warning, missing-prototypes) 35 36 obj-$(CONFIG_LONGEST_SYM_KUNIT_TEST) += longest_symbol_kunit.o
+158
lib/tests/liveupdate.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + /* 4 + * Copyright (c) 2025, Google LLC. 5 + * Pasha Tatashin <pasha.tatashin@soleen.com> 6 + */ 7 + 8 + #define pr_fmt(fmt) KBUILD_MODNAME " test: " fmt 9 + 10 + #include <linux/cleanup.h> 11 + #include <linux/errno.h> 12 + #include <linux/init.h> 13 + #include <linux/liveupdate.h> 14 + #include <linux/module.h> 15 + #include "../../kernel/liveupdate/luo_internal.h" 16 + 17 + static const struct liveupdate_flb_ops test_flb_ops; 18 + #define DEFINE_TEST_FLB(i) { \ 19 + .ops = &test_flb_ops, \ 20 + .compatible = LIVEUPDATE_TEST_FLB_COMPATIBLE(i), \ 21 + } 22 + 23 + /* Number of Test FLBs to register with every file handler */ 24 + #define TEST_NFLBS 3 25 + static struct liveupdate_flb test_flbs[TEST_NFLBS] = { 26 + DEFINE_TEST_FLB(0), 27 + DEFINE_TEST_FLB(1), 28 + DEFINE_TEST_FLB(2), 29 + }; 30 + 31 + #define TEST_FLB_MAGIC_BASE 0xFEEDF00DCAFEBEE0ULL 32 + 33 + static int test_flb_preserve(struct liveupdate_flb_op_args *argp) 34 + { 35 + ptrdiff_t index = argp->flb - test_flbs; 36 + 37 + pr_info("%s: preserve was triggered\n", argp->flb->compatible); 38 + argp->data = TEST_FLB_MAGIC_BASE + index; 39 + 40 + return 0; 41 + } 42 + 43 + static void test_flb_unpreserve(struct liveupdate_flb_op_args *argp) 44 + { 45 + pr_info("%s: unpreserve was triggered\n", argp->flb->compatible); 46 + } 47 + 48 + static int test_flb_retrieve(struct liveupdate_flb_op_args *argp) 49 + { 50 + ptrdiff_t index = argp->flb - test_flbs; 51 + u64 expected_data = TEST_FLB_MAGIC_BASE + index; 52 + 53 + if (argp->data == expected_data) { 54 + pr_info("%s: found flb data from the previous boot\n", 55 + argp->flb->compatible); 56 + argp->obj = (void *)argp->data; 57 + } else { 58 + pr_err("%s: ERROR - incorrect data handle: %llx, expected %llx\n", 59 + argp->flb->compatible, argp->data, expected_data); 60 + return -EINVAL; 61 + } 62 + 63 + return 0; 64 + } 65 + 66 + static void test_flb_finish(struct liveupdate_flb_op_args *argp) 67 + { 68 + ptrdiff_t index = argp->flb - test_flbs; 69 + void *expected_obj = (void *)(TEST_FLB_MAGIC_BASE + index); 70 + 71 + if (argp->obj == expected_obj) { 72 + pr_info("%s: finish was triggered\n", argp->flb->compatible); 73 + } else { 74 + pr_err("%s: ERROR - finish called with invalid object\n", 75 + argp->flb->compatible); 76 + } 77 + } 78 + 79 + static const struct liveupdate_flb_ops test_flb_ops = { 80 + .preserve = test_flb_preserve, 81 + .unpreserve = test_flb_unpreserve, 82 + .retrieve = test_flb_retrieve, 83 + .finish = test_flb_finish, 84 + .owner = THIS_MODULE, 85 + }; 86 + 87 + static void liveupdate_test_init(void) 88 + { 89 + static DEFINE_MUTEX(init_lock); 90 + static bool initialized; 91 + int i; 92 + 93 + guard(mutex)(&init_lock); 94 + 95 + if (initialized) 96 + return; 97 + 98 + for (i = 0; i < TEST_NFLBS; i++) { 99 + struct liveupdate_flb *flb = &test_flbs[i]; 100 + void *obj; 101 + int err; 102 + 103 + err = liveupdate_flb_get_incoming(flb, &obj); 104 + if (err && err != -ENODATA && err != -ENOENT) { 105 + pr_err("liveupdate_flb_get_incoming for %s failed: %pe\n", 106 + flb->compatible, ERR_PTR(err)); 107 + } 108 + } 109 + initialized = true; 110 + } 111 + 112 + void liveupdate_test_register(struct liveupdate_file_handler *fh) 113 + { 114 + int err, i; 115 + 116 + liveupdate_test_init(); 117 + 118 + for (i = 0; i < TEST_NFLBS; i++) { 119 + struct liveupdate_flb *flb = &test_flbs[i]; 120 + 121 + err = liveupdate_register_flb(fh, flb); 122 + if (err) { 123 + pr_err("Failed to register %s %pe\n", 124 + flb->compatible, ERR_PTR(err)); 125 + } 126 + } 127 + 128 + err = liveupdate_register_flb(fh, &test_flbs[0]); 129 + if (!err || err != -EEXIST) { 130 + pr_err("Failed: %s should be already registered, but got err: %pe\n", 131 + test_flbs[0].compatible, ERR_PTR(err)); 132 + } 133 + 134 + pr_info("Registered %d FLBs with file handler: [%s]\n", 135 + TEST_NFLBS, fh->compatible); 136 + } 137 + 138 + void liveupdate_test_unregister(struct liveupdate_file_handler *fh) 139 + { 140 + int err, i; 141 + 142 + for (i = 0; i < TEST_NFLBS; i++) { 143 + struct liveupdate_flb *flb = &test_flbs[i]; 144 + 145 + err = liveupdate_unregister_flb(fh, flb); 146 + if (err) { 147 + pr_err("Failed to unregister %s %pe\n", 148 + flb->compatible, ERR_PTR(err)); 149 + } 150 + } 151 + 152 + pr_info("Unregistered %d FLBs from file handler: [%s]\n", 153 + TEST_NFLBS, fh->compatible); 154 + } 155 + 156 + MODULE_LICENSE("GPL"); 157 + MODULE_AUTHOR("Pasha Tatashin <pasha.tatashin@soleen.com>"); 158 + MODULE_DESCRIPTION("In-kernel test for LUO mechanism");