The per-object callbacks have been replaced by per-state callbacks and will be removed soon. A selftest previously loaded two livepatched modules to ensure that the per-object callbacks were called for both. Although per-state callbacks are only invoked when the live patch is enabled or disabled, it is still important to verify that multiple objects can be live-patched. Convert the test into a generic one by reusing the speaker test module to create the second target module. In the second variant, speaker_welcome() will only print "(2)" after the function name to distinguish it, while keeping the real function name the same to maintain simplicity. Signed-off-by: Petr Mladek <pmladek@xxxxxxxx> --- .../selftests/livepatch/test-callbacks.sh | 59 ---------------- .../testing/selftests/livepatch/test-order.sh | 69 +++++++++++++++++++ .../selftests/livepatch/test_modules/Makefile | 1 + .../livepatch/test_modules/test_klp_speaker.c | 8 ++- .../test_modules/test_klp_speaker2.c | 8 +++ .../test_modules/test_klp_speaker_livepatch.c | 26 ++++++- 6 files changed, 110 insertions(+), 61 deletions(-) create mode 100644 tools/testing/selftests/livepatch/test_modules/test_klp_speaker2.c diff --git a/tools/testing/selftests/livepatch/test-callbacks.sh b/tools/testing/selftests/livepatch/test-callbacks.sh index 614ed0aa2e40..a9bb90920c0a 100755 --- a/tools/testing/selftests/livepatch/test-callbacks.sh +++ b/tools/testing/selftests/livepatch/test-callbacks.sh @@ -93,65 +93,6 @@ $MOD_LIVEPATCH: post_unpatch_callback: vmlinux livepatch: '$MOD_LIVEPATCH': unpatching complete % rmmod $MOD_LIVEPATCH" - -# Test loading multiple targeted kernel modules. This test-case is -# mainly for comparing with the next test-case. -# -# - Load a target "busy" kernel module which kicks off a worker function -# that immediately exits. -# -# - Proceed with loading the livepatch and another ordinary target -# module. Post-patch callbacks are executed and the transition -# completes quickly. - -start_test "multiple target modules" - -load_mod $MOD_TARGET_BUSY block_transition=N -load_lp $MOD_LIVEPATCH -load_mod $MOD_TARGET -unload_mod $MOD_TARGET -disable_lp $MOD_LIVEPATCH -unload_lp $MOD_LIVEPATCH -unload_mod $MOD_TARGET_BUSY - -check_result "% insmod test_modules/$MOD_TARGET_BUSY.ko block_transition=N -$MOD_TARGET_BUSY: ${MOD_TARGET_BUSY}_init -$MOD_TARGET_BUSY: busymod_work_func enter -$MOD_TARGET_BUSY: busymod_work_func exit -% insmod test_modules/$MOD_LIVEPATCH.ko -livepatch: enabling patch '$MOD_LIVEPATCH' -livepatch: '$MOD_LIVEPATCH': initializing patching transition -$MOD_LIVEPATCH: pre_patch_callback: vmlinux -$MOD_LIVEPATCH: pre_patch_callback: $MOD_TARGET_BUSY -> [MODULE_STATE_LIVE] Normal state -livepatch: '$MOD_LIVEPATCH': starting patching transition -livepatch: '$MOD_LIVEPATCH': completing patching transition -$MOD_LIVEPATCH: post_patch_callback: vmlinux -$MOD_LIVEPATCH: post_patch_callback: $MOD_TARGET_BUSY -> [MODULE_STATE_LIVE] Normal state -livepatch: '$MOD_LIVEPATCH': patching complete -% insmod test_modules/$MOD_TARGET.ko -livepatch: applying patch '$MOD_LIVEPATCH' to loading module '$MOD_TARGET' -$MOD_LIVEPATCH: pre_patch_callback: $MOD_TARGET -> [MODULE_STATE_COMING] Full formed, running module_init -$MOD_LIVEPATCH: post_patch_callback: $MOD_TARGET -> [MODULE_STATE_COMING] Full formed, running module_init -$MOD_TARGET: ${MOD_TARGET}_init -% rmmod $MOD_TARGET -$MOD_TARGET: ${MOD_TARGET}_exit -$MOD_LIVEPATCH: pre_unpatch_callback: $MOD_TARGET -> [MODULE_STATE_GOING] Going away -livepatch: reverting patch '$MOD_LIVEPATCH' on unloading module '$MOD_TARGET' -$MOD_LIVEPATCH: post_unpatch_callback: $MOD_TARGET -> [MODULE_STATE_GOING] Going away -% echo 0 > $SYSFS_KLP_DIR/$MOD_LIVEPATCH/enabled -livepatch: '$MOD_LIVEPATCH': initializing unpatching transition -$MOD_LIVEPATCH: pre_unpatch_callback: vmlinux -$MOD_LIVEPATCH: pre_unpatch_callback: $MOD_TARGET_BUSY -> [MODULE_STATE_LIVE] Normal state -livepatch: '$MOD_LIVEPATCH': starting unpatching transition -livepatch: '$MOD_LIVEPATCH': completing unpatching transition -$MOD_LIVEPATCH: post_unpatch_callback: vmlinux -$MOD_LIVEPATCH: post_unpatch_callback: $MOD_TARGET_BUSY -> [MODULE_STATE_LIVE] Normal state -livepatch: '$MOD_LIVEPATCH': unpatching complete -% rmmod $MOD_LIVEPATCH -% rmmod $MOD_TARGET_BUSY -$MOD_TARGET_BUSY: ${MOD_TARGET_BUSY}_exit" - - # A similar test as the previous one, but force the "busy" kernel module # to block the livepatch transition. # diff --git a/tools/testing/selftests/livepatch/test-order.sh b/tools/testing/selftests/livepatch/test-order.sh index 869b06605597..189132b01bac 100755 --- a/tools/testing/selftests/livepatch/test-order.sh +++ b/tools/testing/selftests/livepatch/test-order.sh @@ -7,6 +7,7 @@ MOD_LIVEPATCH=test_klp_speaker_livepatch MOD_TARGET=test_klp_speaker +MOD_TARGET2=test_klp_speaker2 setup_config @@ -224,3 +225,71 @@ livepatch: '$MOD_LIVEPATCH': starting unpatching transition livepatch: '$MOD_LIVEPATCH': completing unpatching transition livepatch: '$MOD_LIVEPATCH': unpatching complete % rmmod $MOD_LIVEPATCH" + +# Test loading multiple targeted kernel modules. +# +# Load the first target module before the livepatch and the second one later. +# Disable and unload them in the opposite order. +# +# The module loader hooks should print a message about applying/reverting +# the livepatch for the 2nd module when it is being loaded/unloaded. +# +# The expected state is double-checked by reading "welcome" parameter +# of both target modules. The livepatched variant should be printed +# when both the target and livepatch modules are loaded. + +start_test "multiple target modules" + +load_mod $MOD_TARGET +read_module_param $MOD_TARGET welcome + +load_lp $MOD_LIVEPATCH +read_module_param $MOD_TARGET welcome +check_object_patched $MOD_LIVEPATCH $MOD_TARGET "1" +check_object_patched $MOD_LIVEPATCH $MOD_TARGET2 "0" + +load_mod $MOD_TARGET2 +read_module_param $MOD_TARGET2 welcome +check_object_patched $MOD_LIVEPATCH $MOD_TARGET "1" +check_object_patched $MOD_LIVEPATCH $MOD_TARGET2 "1" + +unload_mod $MOD_TARGET2 +check_object_patched $MOD_LIVEPATCH $MOD_TARGET "1" +check_object_patched $MOD_LIVEPATCH $MOD_TARGET2 "0" + +disable_lp $MOD_LIVEPATCH +read_module_param $MOD_TARGET welcome + +unload_lp $MOD_LIVEPATCH +unload_mod $MOD_TARGET + +check_result "% insmod test_modules/$MOD_TARGET.ko +$MOD_TARGET: ${MOD_TARGET}_init +% cat $SYSFS_MODULE_DIR/$MOD_TARGET/parameters/welcome +$MOD_TARGET: speaker_welcome: Hello, World! +% insmod test_modules/$MOD_LIVEPATCH.ko +livepatch: enabling patch '$MOD_LIVEPATCH' +livepatch: '$MOD_LIVEPATCH': initializing patching transition +livepatch: '$MOD_LIVEPATCH': starting patching transition +livepatch: '$MOD_LIVEPATCH': completing patching transition +livepatch: '$MOD_LIVEPATCH': patching complete +% cat $SYSFS_MODULE_DIR/$MOD_TARGET/parameters/welcome +$MOD_LIVEPATCH: lp_speaker_welcome: Ladies and gentleman, ... +% insmod test_modules/$MOD_TARGET2.ko +livepatch: applying patch '$MOD_LIVEPATCH' to loading module '$MOD_TARGET2' +$MOD_TARGET2: ${MOD_TARGET}_init +% cat $SYSFS_MODULE_DIR/$MOD_TARGET2/parameters/welcome +$MOD_LIVEPATCH: lp_speaker2_welcome(2): Ladies and gentleman, ... +% rmmod $MOD_TARGET2 +$MOD_TARGET2: ${MOD_TARGET}_exit +livepatch: reverting patch '$MOD_LIVEPATCH' on unloading module '$MOD_TARGET2' +% echo 0 > $SYSFS_KLP_DIR/$MOD_LIVEPATCH/enabled +livepatch: '$MOD_LIVEPATCH': initializing unpatching transition +livepatch: '$MOD_LIVEPATCH': starting unpatching transition +livepatch: '$MOD_LIVEPATCH': completing unpatching transition +livepatch: '$MOD_LIVEPATCH': unpatching complete +% cat $SYSFS_MODULE_DIR/$MOD_TARGET/parameters/welcome +$MOD_TARGET: speaker_welcome: Hello, World! +% rmmod $MOD_LIVEPATCH +% rmmod $MOD_TARGET +$MOD_TARGET: ${MOD_TARGET}_exit" diff --git a/tools/testing/selftests/livepatch/test_modules/Makefile b/tools/testing/selftests/livepatch/test_modules/Makefile index 0978c489a67a..72a817d1ddd9 100644 --- a/tools/testing/selftests/livepatch/test_modules/Makefile +++ b/tools/testing/selftests/livepatch/test_modules/Makefile @@ -10,6 +10,7 @@ obj-m += test_klp_atomic_replace.o \ test_klp_livepatch.o \ test_klp_shadow_vars.o \ test_klp_speaker.o \ + test_klp_speaker2.o \ test_klp_speaker_livepatch.o \ test_klp_state.o \ test_klp_state2.o \ diff --git a/tools/testing/selftests/livepatch/test_modules/test_klp_speaker.c b/tools/testing/selftests/livepatch/test_modules/test_klp_speaker.c index 22f6e5fcb009..92c577addb8e 100644 --- a/tools/testing/selftests/livepatch/test_modules/test_klp_speaker.c +++ b/tools/testing/selftests/livepatch/test_modules/test_klp_speaker.c @@ -6,6 +6,10 @@ #include <linux/module.h> #include <linux/printk.h> +#ifndef SPEAKER_ID +#define SPEAKER_ID "" +#endif + /** * test_klp_speaker - test module for testing misc livepatching features * @@ -15,12 +19,14 @@ * * - Log the greeting by reading the "welcome" module parameter, see * welcome_get(). + * + * - Reuse the module source for more speakers, see SPEAKER_ID. */ noinline static void speaker_welcome(void) { - pr_info("%s: Hello, World!\n", __func__); + pr_info("%s%s: Hello, World!\n", __func__, SPEAKER_ID); } static int welcome_get(char *buffer, const struct kernel_param *kp) diff --git a/tools/testing/selftests/livepatch/test_modules/test_klp_speaker2.c b/tools/testing/selftests/livepatch/test_modules/test_klp_speaker2.c new file mode 100644 index 000000000000..d38ab51414bf --- /dev/null +++ b/tools/testing/selftests/livepatch/test_modules/test_klp_speaker2.c @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2023 SUSE + +/* Use versioned function name for livepatched functions */ +#define SPEAKER_ID "(2)" + +/* Same module with the same features. */ +#include "test_klp_speaker.c" diff --git a/tools/testing/selftests/livepatch/test_modules/test_klp_speaker_livepatch.c b/tools/testing/selftests/livepatch/test_modules/test_klp_speaker_livepatch.c index 26a8dd15f723..8d7e74a69a5d 100644 --- a/tools/testing/selftests/livepatch/test_modules/test_klp_speaker_livepatch.c +++ b/tools/testing/selftests/livepatch/test_modules/test_klp_speaker_livepatch.c @@ -17,11 +17,23 @@ * * - Improve the speaker's greeting from "Hello, World!" to * "Ladies and gentleman, ..." + * + * - Support more speaker modules, see __lp_speaker_welcome(). */ +static void __lp_speaker_welcome(const char *caller_func, const char *speaker_id) +{ + pr_info("%s%s: Ladies and gentleman, ...\n", caller_func, speaker_id); +} + static void lp_speaker_welcome(void) { - pr_info("%s: Ladies and gentleman, ...\n", __func__); + __lp_speaker_welcome(__func__, ""); +} + +static void lp_speaker2_welcome(void) +{ + __lp_speaker_welcome(__func__, "(2)"); } static struct klp_func test_klp_speaker_funcs[] = { @@ -32,11 +44,23 @@ static struct klp_func test_klp_speaker_funcs[] = { { } }; +static struct klp_func test_klp_speaker2_funcs[] = { + { + .old_name = "speaker_welcome", + .new_func = lp_speaker2_welcome, + }, + { } +}; + static struct klp_object objs[] = { { .name = "test_klp_speaker", .funcs = test_klp_speaker_funcs, }, + { + .name = "test_klp_speaker2", + .funcs = test_klp_speaker2_funcs, + }, { } }; -- 2.47.1