All of lore.kernel.org
 help / color / mirror / Atom feed
From: Yafang Shao <laoar.shao@gmail.com>
To: jpoimboe@kernel.org, jikos@kernel.org, mbenes@suse.cz,
	pmladek@suse.com, joe.lawrence@redhat.com, song@kernel.org
Cc: live-patching@vger.kernel.org, Yafang Shao <laoar.shao@gmail.com>
Subject: [PATCH v5 7/9] selftests: livepatch: Add provides/obsoletes test scenarios
Date: Sun,  9 Aug 2026 17:19:51 +0800	[thread overview]
Message-ID: <20260809091954.22930-8-laoar.shao@gmail.com> (raw)
In-Reply-To: <20260809091954.22930-1-laoar.shao@gmail.com>

Now that the legacy "replace" field has been replaced by the
provides/obsoletes mechanism, add test scenarios to verify the new
behavior.

Fill in the #else branches of the test modules that were left as
TODO placeholders in the previous patch:

- test_klp_atomic_replace.c gains provides and obsoletes module
  parameters for the provides/obsoletes based tests.

- test_klp_callbacks_demo2.c gains a provides module parameter.

- test_klp_livepatch.c gains a provides module parameter so that it
  can be loaded with a specific provides id for coexistence tests.

- test_klp_state.c and test_klp_state2.c add a comment in the #else
  branch noting that provides=0 (the default) is equivalent to the
  previous .replace=true behavior.

Add test-provides.sh with four test scenarios:

1. provides=0 replaces provides=0: two livepatches with provides=0
   that modify different functions; the second replaces the first.

2. Same provides replaces: two livepatches with provides=1 that
   modify different functions; the second replaces the first.

3. Obsoletes replaces: a livepatch with provides=2 and obsoletes=[1]
   replaces a livepatch with provides=1. The provides/obsoletes sysfs
   values are verified.

4. provides=0 coexists with provides=1: two livepatches with
   different provides ids that modify different functions coexist,
   verifying that provides=0 does not replace a patch with a
   different provides id.

The provides/obsoletes based tests only run on kernels that no longer
support the legacy "replace" attribute.

Assisted-by: Comagic:DeepSeek-V4-Flash
Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
---
 tools/testing/selftests/livepatch/Makefile    |   3 +-
 .../livepatch/test-provides-obsoletes.sh      | 195 ++++++++++++++++++
 .../test_modules/test_klp_atomic_replace.c    |  22 +-
 .../test_modules/test_klp_callbacks_demo2.c   |  12 +-
 .../test_modules/test_klp_livepatch.c         |   9 +
 .../livepatch/test_modules/test_klp_state.c   |   5 +-
 .../livepatch/test_modules/test_klp_state2.c  |   5 +-
 7 files changed, 226 insertions(+), 25 deletions(-)
 create mode 100755 tools/testing/selftests/livepatch/test-provides-obsoletes.sh

diff --git a/tools/testing/selftests/livepatch/Makefile b/tools/testing/selftests/livepatch/Makefile
index a080eb54a215..38f98594d883 100644
--- a/tools/testing/selftests/livepatch/Makefile
+++ b/tools/testing/selftests/livepatch/Makefile
@@ -11,7 +11,8 @@ TEST_PROGS := \
 	test-ftrace.sh \
 	test-sysfs.sh \
 	test-syscall.sh \
-	test-kprobe.sh
+	test-kprobe.sh \
+	test-provides-obsoletes.sh
 
 TEST_FILES := settings
 
diff --git a/tools/testing/selftests/livepatch/test-provides-obsoletes.sh b/tools/testing/selftests/livepatch/test-provides-obsoletes.sh
new file mode 100755
index 000000000000..c740d463f556
--- /dev/null
+++ b/tools/testing/selftests/livepatch/test-provides-obsoletes.sh
@@ -0,0 +1,195 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2026 Yafang Shao <laoar.shao@gmail.com>
+
+. $(dirname $0)/functions.sh
+
+MOD_ATOMIC=test_klp_atomic_replace
+MOD_LIVEPATCH=test_klp_livepatch
+
+setup_config
+
+detect_replace_attr
+
+# The provides/obsoletes based tests only run on kernels that no longer
+# support the legacy "replace" attribute.
+if [[ "$HAS_REPLACE_ATTR" == "1" ]]; then
+	echo "SKIP: kernel still supports the legacy replace attribute"
+	exit $ksft_skip
+fi
+
+
+# - load a livepatch with provides=0 (cmdline), then another with
+#   provides=0 (meminfo). The second replaces the first (same provides).
+# - unload the remaining livepatch
+
+start_test "provides 0 replaces provides 0"
+
+load_lp $MOD_LIVEPATCH provides=0
+load_lp $MOD_ATOMIC provides=0
+
+mods=($SYSFS_KLP_DIR/*)
+nmods=${#mods[@]}
+if [[ "$nmods" -ne 1 ]]; then
+	die "Expecting one module listed, found $nmods"
+fi
+check_sysfs_value "$MOD_ATOMIC" "enabled" "1"
+
+disable_lp $MOD_ATOMIC
+unload_lp $MOD_ATOMIC
+unload_lp $MOD_LIVEPATCH
+
+check_result "% insmod test_modules/$MOD_LIVEPATCH.ko provides=0
+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
+% insmod test_modules/$MOD_ATOMIC.ko provides=0
+livepatch: enabling patch '$MOD_ATOMIC'
+livepatch: '$MOD_ATOMIC': initializing patching transition
+livepatch: '$MOD_ATOMIC': starting patching transition
+livepatch: '$MOD_ATOMIC': completing patching transition
+livepatch: '$MOD_ATOMIC': patching complete
+% echo 0 > /sys/kernel/livepatch/$MOD_ATOMIC/enabled
+livepatch: '$MOD_ATOMIC': initializing unpatching transition
+livepatch: '$MOD_ATOMIC': starting unpatching transition
+livepatch: '$MOD_ATOMIC': completing unpatching transition
+livepatch: '$MOD_ATOMIC': unpatching complete
+% rmmod $MOD_ATOMIC
+% rmmod $MOD_LIVEPATCH"
+
+
+# - load a livepatch with provides=1 (cmdline), then another with
+#   provides=1 (meminfo). The second replaces the first (same provides).
+# - unload the remaining livepatch
+
+start_test "same provides replaces"
+
+load_lp $MOD_LIVEPATCH provides=1
+load_lp $MOD_ATOMIC provides=1
+
+mods=($SYSFS_KLP_DIR/*)
+nmods=${#mods[@]}
+if [[ "$nmods" -ne 1 ]]; then
+	die "Expecting one module listed, found $nmods"
+fi
+check_sysfs_value "$MOD_ATOMIC" "enabled" "1"
+
+disable_lp $MOD_ATOMIC
+unload_lp $MOD_ATOMIC
+unload_lp $MOD_LIVEPATCH
+
+check_result "% insmod test_modules/$MOD_LIVEPATCH.ko provides=1
+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
+% insmod test_modules/$MOD_ATOMIC.ko provides=1
+livepatch: enabling patch '$MOD_ATOMIC'
+livepatch: '$MOD_ATOMIC': initializing patching transition
+livepatch: '$MOD_ATOMIC': starting patching transition
+livepatch: '$MOD_ATOMIC': completing patching transition
+livepatch: '$MOD_ATOMIC': patching complete
+% echo 0 > /sys/kernel/livepatch/$MOD_ATOMIC/enabled
+livepatch: '$MOD_ATOMIC': initializing unpatching transition
+livepatch: '$MOD_ATOMIC': starting unpatching transition
+livepatch: '$MOD_ATOMIC': completing unpatching transition
+livepatch: '$MOD_ATOMIC': unpatching complete
+% rmmod $MOD_ATOMIC
+% rmmod $MOD_LIVEPATCH"
+
+
+# - load a livepatch with provides=1 (cmdline), then another with
+#   provides=2 and obsoletes=[1] (meminfo). The second replaces the
+#   first (obsoletes contains the first patch's provides id).
+# - verify the provides/obsoletes sysfs values
+# - unload the remaining livepatch
+
+start_test "obsoletes replaces"
+
+load_lp $MOD_LIVEPATCH provides=1
+load_lp $MOD_ATOMIC provides=2 obsoletes=1
+
+mods=($SYSFS_KLP_DIR/*)
+nmods=${#mods[@]}
+if [[ "$nmods" -ne 1 ]]; then
+	die "Expecting one module listed, found $nmods"
+fi
+check_sysfs_value "$MOD_ATOMIC" "provides" "2"
+check_sysfs_value "$MOD_ATOMIC" "obsoletes" "1"
+
+disable_lp $MOD_ATOMIC
+unload_lp $MOD_ATOMIC
+unload_lp $MOD_LIVEPATCH
+
+check_result "% insmod test_modules/$MOD_LIVEPATCH.ko provides=1
+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
+% insmod test_modules/$MOD_ATOMIC.ko provides=2 obsoletes=1
+livepatch: enabling patch '$MOD_ATOMIC'
+livepatch: '$MOD_ATOMIC': initializing patching transition
+livepatch: '$MOD_ATOMIC': starting patching transition
+livepatch: '$MOD_ATOMIC': completing patching transition
+livepatch: '$MOD_ATOMIC': patching complete
+% echo 0 > /sys/kernel/livepatch/$MOD_ATOMIC/enabled
+livepatch: '$MOD_ATOMIC': initializing unpatching transition
+livepatch: '$MOD_ATOMIC': starting unpatching transition
+livepatch: '$MOD_ATOMIC': completing unpatching transition
+livepatch: '$MOD_ATOMIC': unpatching complete
+% rmmod $MOD_ATOMIC
+% rmmod $MOD_LIVEPATCH"
+
+
+# - load two livepatches with different provides ids that modify
+#   different functions and verify that they coexist
+# - in particular, verify that provides=0 does NOT replace a patch
+#   with a different provides id
+# - unload both livepatches
+
+start_test "provides 0 coexists with provides 1"
+
+load_lp $MOD_LIVEPATCH provides=0
+load_lp $MOD_ATOMIC provides=1
+
+mods=($SYSFS_KLP_DIR/*)
+nmods=${#mods[@]}
+if [[ "$nmods" -ne 2 ]]; then
+	die "Expecting two modules listed, found $nmods"
+fi
+
+disable_lp $MOD_LIVEPATCH
+unload_lp $MOD_LIVEPATCH
+disable_lp $MOD_ATOMIC
+unload_lp $MOD_ATOMIC
+
+check_result "% insmod test_modules/$MOD_LIVEPATCH.ko provides=0
+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
+% insmod test_modules/$MOD_ATOMIC.ko provides=1
+livepatch: enabling patch '$MOD_ATOMIC'
+livepatch: '$MOD_ATOMIC': initializing patching transition
+livepatch: '$MOD_ATOMIC': starting patching transition
+livepatch: '$MOD_ATOMIC': completing patching transition
+livepatch: '$MOD_ATOMIC': patching complete
+% echo 0 > /sys/kernel/livepatch/$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
+% rmmod $MOD_LIVEPATCH
+% echo 0 > /sys/kernel/livepatch/$MOD_ATOMIC/enabled
+livepatch: '$MOD_ATOMIC': initializing unpatching transition
+livepatch: '$MOD_ATOMIC': starting unpatching transition
+livepatch: '$MOD_ATOMIC': completing unpatching transition
+livepatch: '$MOD_ATOMIC': unpatching complete
+% rmmod $MOD_ATOMIC"
+
+exit 0
diff --git a/tools/testing/selftests/livepatch/test_modules/test_klp_atomic_replace.c b/tools/testing/selftests/livepatch/test_modules/test_klp_atomic_replace.c
index 4b3ed17886e7..b0ed924eeeed 100644
--- a/tools/testing/selftests/livepatch/test_modules/test_klp_atomic_replace.c
+++ b/tools/testing/selftests/livepatch/test_modules/test_klp_atomic_replace.c
@@ -12,10 +12,15 @@ static int replace;
 module_param(replace, int, 0644);
 MODULE_PARM_DESC(replace, "replace (default=0)");
 #else
-/*
- * TODO: Add provides/obsoletes module parameters for the
- * provides/obsoletes based tests (to be added later).
- */
+static unsigned int provides;
+module_param(provides, uint, 0644);
+MODULE_PARM_DESC(provides, "provides id (default=0)");
+
+#define KLP_MAX_OBSOLETES 16
+static unsigned int obsoletes[KLP_MAX_OBSOLETES];
+static int nr_obsoletes;
+module_param_array(obsoletes, uint, &nr_obsoletes, 0644);
+MODULE_PARM_DESC(obsoletes, "obsoletes provides ids");
 #endif
 
 #include <linux/seq_file.h>
@@ -53,10 +58,11 @@ static int test_klp_atomic_replace_init(void)
 #ifdef KLP_HAS_REPLACE
 	patch.replace = replace;
 #else
-	/*
-	 * TODO: Set provides/obsoletes from the module parameters
-	 * for the provides/obsoletes based tests (to be added later).
-	 */
+	patch.provides = provides;
+	if (nr_obsoletes > 0) {
+		patch.obsoletes = obsoletes;
+		patch.nr_obsoletes = nr_obsoletes;
+	}
 #endif
 	return klp_enable_patch(&patch);
 }
diff --git a/tools/testing/selftests/livepatch/test_modules/test_klp_callbacks_demo2.c b/tools/testing/selftests/livepatch/test_modules/test_klp_callbacks_demo2.c
index 135da6d4d882..a0e7b7d1e198 100644
--- a/tools/testing/selftests/livepatch/test_modules/test_klp_callbacks_demo2.c
+++ b/tools/testing/selftests/livepatch/test_modules/test_klp_callbacks_demo2.c
@@ -12,10 +12,9 @@ static int replace;
 module_param(replace, int, 0644);
 MODULE_PARM_DESC(replace, "replace (default=0)");
 #else
-/*
- * TODO: Add provides/obsoletes module parameters for the
- * provides/obsoletes based tests (to be added later).
- */
+static unsigned int provides;
+module_param(provides, uint, 0644);
+MODULE_PARM_DESC(provides, "provides id (default=0)");
 #endif
 
 static const char *const module_state[] = {
@@ -89,10 +88,7 @@ static int test_klp_callbacks_demo2_init(void)
 #ifdef KLP_HAS_REPLACE
 	patch.replace = replace;
 #else
-	/*
-	 * TODO: Set provides/obsoletes from the module parameters
-	 * for the provides/obsoletes based tests (to be added later).
-	 */
+	patch.provides = provides;
 #endif
 	return klp_enable_patch(&patch);
 }
diff --git a/tools/testing/selftests/livepatch/test_modules/test_klp_livepatch.c b/tools/testing/selftests/livepatch/test_modules/test_klp_livepatch.c
index aff08199de71..fa2bc6ec921d 100644
--- a/tools/testing/selftests/livepatch/test_modules/test_klp_livepatch.c
+++ b/tools/testing/selftests/livepatch/test_modules/test_klp_livepatch.c
@@ -7,6 +7,12 @@
 #include <linux/kernel.h>
 #include <linux/livepatch.h>
 
+#ifndef KLP_HAS_REPLACE
+static unsigned int provides;
+module_param(provides, uint, 0644);
+MODULE_PARM_DESC(provides, "provides id (default=0)");
+#endif
+
 #include <linux/seq_file.h>
 static int livepatch_cmdline_proc_show(struct seq_file *m, void *v)
 {
@@ -36,6 +42,9 @@ static struct klp_patch patch = {
 
 static int test_klp_livepatch_init(void)
 {
+#ifndef KLP_HAS_REPLACE
+	patch.provides = provides;
+#endif
 	return klp_enable_patch(&patch);
 }
 
diff --git a/tools/testing/selftests/livepatch/test_modules/test_klp_state.c b/tools/testing/selftests/livepatch/test_modules/test_klp_state.c
index 3492472e5d07..313401a5506e 100644
--- a/tools/testing/selftests/livepatch/test_modules/test_klp_state.c
+++ b/tools/testing/selftests/livepatch/test_modules/test_klp_state.c
@@ -145,10 +145,7 @@ static struct klp_patch patch = {
 #ifdef KLP_HAS_REPLACE
 	.replace = true,
 #else
-/*
- * TODO: Add provides/obsoletes module parameters for the
- * provides/obsoletes based tests (to be added later).
- */
+	/* provides=0 by default, replaces all provides=0 patches */
 #endif
 };
 
diff --git a/tools/testing/selftests/livepatch/test_modules/test_klp_state2.c b/tools/testing/selftests/livepatch/test_modules/test_klp_state2.c
index 8160b565a659..1afc2cabc39d 100644
--- a/tools/testing/selftests/livepatch/test_modules/test_klp_state2.c
+++ b/tools/testing/selftests/livepatch/test_modules/test_klp_state2.c
@@ -174,10 +174,7 @@ static struct klp_patch patch = {
 #ifdef KLP_HAS_REPLACE
 	.replace = true,
 #else
-/*
- * TODO: Add provides/obsoletes module parameters for the
- * provides/obsoletes based tests (to be added later).
- */
+	/* provides=0 by default, replaces all provides=0 patches */
 #endif
 };
 
-- 
2.52.0


  parent reply	other threads:[~2026-08-09  9:20 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-09  9:19 [PATCH v5 0/9] livepatch: Introduce replace set support Yafang Shao
2026-08-09  9:19 ` [PATCH v5 1/9] livepatch: Fix wrong index in funcs cleanup error path Yafang Shao
2026-08-09  9:28   ` sashiko-bot
2026-08-09  9:36     ` Yafang Shao
2026-08-09  9:19 ` [PATCH v5 2/9] livepatch: Make klp_find_func() non static Yafang Shao
2026-08-09  9:32   ` sashiko-bot
2026-08-09  9:39     ` Yafang Shao
2026-08-09  9:19 ` [PATCH v5 3/9] livepatch: Call klp_init_patch_early() earlier Yafang Shao
2026-08-09  9:40   ` sashiko-bot
2026-08-09  9:19 ` [PATCH v5 4/9] livepatch: Implement replace set for scoped atomic replace Yafang Shao
2026-08-09  9:33   ` sashiko-bot
2026-08-09  9:19 ` [PATCH v5 5/9] livepatch: Deprecate stack_order Yafang Shao
2026-08-09  9:19 ` [PATCH v5 6/9] selftests: livepatch: Adapt atomic replace tests to provides/obsoletes Yafang Shao
2026-08-09  9:33   ` sashiko-bot
2026-08-09  9:45     ` Yafang Shao
2026-08-09  9:19 ` Yafang Shao [this message]
2026-08-09  9:31   ` [PATCH v5 7/9] selftests: livepatch: Add provides/obsoletes test scenarios sashiko-bot
2026-08-09  9:19 ` [PATCH v5 8/9] selftests: livepatch: Add test for state ID conflict across provides Yafang Shao
2026-08-09  9:19 ` [PATCH v5 9/9] selftests: livepatch: Add test for function " Yafang Shao
2026-08-09  9:49   ` sashiko-bot

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=20260809091954.22930-8-laoar.shao@gmail.com \
    --to=laoar.shao@gmail.com \
    --cc=jikos@kernel.org \
    --cc=joe.lawrence@redhat.com \
    --cc=jpoimboe@kernel.org \
    --cc=live-patching@vger.kernel.org \
    --cc=mbenes@suse.cz \
    --cc=pmladek@suse.com \
    --cc=song@kernel.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.