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 6/9] selftests: livepatch: Adapt atomic replace tests to provides/obsoletes
Date: Sun,  9 Aug 2026 17:19:50 +0800	[thread overview]
Message-ID: <20260809091954.22930-7-laoar.shao@gmail.com> (raw)
In-Reply-To: <20260809091954.22930-1-laoar.shao@gmail.com>

The legacy "replace" field in struct klp_patch was replaced by the
provides/obsoletes mechanism. As a result, the atomic replace
selftests fail to build against kernels that only support
provides/obsoletes.

Adapt the selftests so that they build and run on both old and new
kernels:

- test_modules/Makefile detects whether the kernel header still
  declares the "replace" field. If so, it passes KLP_HAS_REPLACE to
  the modules via ccflags-y.

- test_klp_atomic_replace.c and other source files using .replace guard
  their replace module parameter and .replace assignment with
  #ifdef KLP_HAS_REPLACE. The #else branches are left as TODO
  placeholders for the upcoming provides/obsoletes based tests.

- functions.sh adds detect_replace_attr(), which loads a temporary
  livepatch and checks for the /sys/kernel/livepatch/<patch>/replace
  attribute, setting HAS_REPLACE_ATTR accordingly.

- test-livepatch.sh and test-callbacks.sh run the tests that depend
  on multiple livepatches coexisting or on the atomic replace
  behavior ("multiple livepatches" and "atomic replace") only when
  HAS_REPLACE_ATTR is set. These scenarios do not apply to the new
  kernel, where provides=0 replaces any other livepatch by default.

The provides/obsoletes based selftests will be added later.

Assisted-by: Comagic:DeepSeek-V4-Flash
Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
---
 tools/testing/selftests/livepatch/functions.sh   | 15 +++++++++++++++
 .../selftests/livepatch/test-callbacks.sh        |  6 ++++++
 .../selftests/livepatch/test-livepatch.sh        |  6 ++++++
 .../selftests/livepatch/test_modules/Makefile    | 10 ++++++++++
 .../test_modules/test_klp_atomic_replace.c       | 16 ++++++++++++++++
 .../test_modules/test_klp_callbacks_demo2.c      | 16 ++++++++++++++++
 .../livepatch/test_modules/test_klp_state.c      |  7 +++++++
 .../livepatch/test_modules/test_klp_state2.c     |  7 +++++++
 8 files changed, 83 insertions(+)

diff --git a/tools/testing/selftests/livepatch/functions.sh b/tools/testing/selftests/livepatch/functions.sh
index 30dc677b2f45..17810521d069 100644
--- a/tools/testing/selftests/livepatch/functions.sh
+++ b/tools/testing/selftests/livepatch/functions.sh
@@ -351,6 +351,21 @@ function does_sysfs_exist() {
 	[[ -f "$SYSFS_KLP_DIR/$mod/$attr" ]]
 }
 
+# detect_replace_attr() - detect whether the running kernel still exposes
+# the legacy "replace" sysfs attribute and set HAS_REPLACE_ATTR
+# accordingly. The atomic replace tests are only run when the attribute
+# is present. The provides/obsoletes based tests will be added later.
+function detect_replace_attr() {
+	HAS_REPLACE_ATTR=0
+
+	load_lp test_klp_livepatch
+	if does_sysfs_exist test_klp_livepatch "replace"; then
+		HAS_REPLACE_ATTR=1
+	fi
+	disable_lp test_klp_livepatch
+	unload_lp test_klp_livepatch
+}
+
 # check_sysfs_rights(modname, rel_path, expected_rights) - check sysfs
 # path permissions
 #	modname - livepatch module creating the sysfs interface
diff --git a/tools/testing/selftests/livepatch/test-callbacks.sh b/tools/testing/selftests/livepatch/test-callbacks.sh
index 2a03deb26a12..e9b2dc6ea099 100755
--- a/tools/testing/selftests/livepatch/test-callbacks.sh
+++ b/tools/testing/selftests/livepatch/test-callbacks.sh
@@ -11,6 +11,8 @@ MOD_TARGET_BUSY=test_klp_callbacks_busy
 
 setup_config
 
+detect_replace_attr
+
 
 # Test a combination of loading a kernel module and a livepatch that
 # patches a function in the first module.  Load the target module
@@ -451,6 +453,7 @@ $MOD_TARGET_BUSY: busymod_work_func exit
 $MOD_TARGET_BUSY: ${MOD_TARGET_BUSY}_exit"
 
 
+if [[ "$HAS_REPLACE_ATTR" == "1" ]]; then
 # Test loading multiple livepatches.  This test-case is mainly for comparing
 # with the next test-case.
 #
@@ -499,8 +502,10 @@ $MOD_LIVEPATCH: post_unpatch_callback: vmlinux
 livepatch: '$MOD_LIVEPATCH': unpatching complete
 % rmmod $MOD_LIVEPATCH2
 % rmmod $MOD_LIVEPATCH"
+fi
 
 
+if [[ "$HAS_REPLACE_ATTR" == "1" ]]; then
 # Load multiple livepatches, but the second as an 'atomic-replace'
 # patch.  When the latter loads, the original livepatch should be
 # disabled and *none* of its pre/post-unpatch callbacks executed.  On
@@ -548,6 +553,7 @@ $MOD_LIVEPATCH2: post_unpatch_callback: vmlinux
 livepatch: '$MOD_LIVEPATCH2': unpatching complete
 % rmmod $MOD_LIVEPATCH2
 % rmmod $MOD_LIVEPATCH"
+fi
 
 
 exit 0
diff --git a/tools/testing/selftests/livepatch/test-livepatch.sh b/tools/testing/selftests/livepatch/test-livepatch.sh
index c44c5341a2f1..b3b7cd81e3d0 100755
--- a/tools/testing/selftests/livepatch/test-livepatch.sh
+++ b/tools/testing/selftests/livepatch/test-livepatch.sh
@@ -13,6 +13,8 @@ MOD_TARGET_PATCH=test_klp_mod_patch
 
 setup_config
 
+detect_replace_attr
+
 
 # - load a livepatch that modifies the output from /proc/cmdline and
 #   verify correct behavior
@@ -49,6 +51,7 @@ livepatch: '$MOD_LIVEPATCH1': unpatching complete
 % rmmod $MOD_LIVEPATCH1"
 
 
+if [[ "$HAS_REPLACE_ATTR" == "1" ]]; then
 # - load a livepatch that modifies the output from /proc/cmdline and
 #   verify correct behavior
 # - load another livepatch and verify that both livepatches are active
@@ -107,8 +110,10 @@ livepatch: '$MOD_LIVEPATCH1': starting unpatching transition
 livepatch: '$MOD_LIVEPATCH1': completing unpatching transition
 livepatch: '$MOD_LIVEPATCH1': unpatching complete
 % rmmod $MOD_LIVEPATCH1"
+fi
 
 
+if [[ "$HAS_REPLACE_ATTR" == "1" ]]; then
 # - load a livepatch that modifies the output from /proc/cmdline and
 #   verify correct behavior
 # - load two additional livepatches and check the number of livepatch modules
@@ -196,6 +201,7 @@ livepatch: '$MOD_REPLACE': starting unpatching transition
 livepatch: '$MOD_REPLACE': completing unpatching transition
 livepatch: '$MOD_REPLACE': unpatching complete
 % rmmod $MOD_REPLACE"
+fi
 
 
 # - load a target module that provides /proc/test_klp_mod_target with
diff --git a/tools/testing/selftests/livepatch/test_modules/Makefile b/tools/testing/selftests/livepatch/test_modules/Makefile
index a13d398585dc..29c55df36046 100644
--- a/tools/testing/selftests/livepatch/test_modules/Makefile
+++ b/tools/testing/selftests/livepatch/test_modules/Makefile
@@ -16,6 +16,16 @@ obj-m += test_klp_atomic_replace.o \
 	test_klp_state3.o \
 	test_klp_syscall.o
 
+# The legacy "replace" field was replaced by provides/obsoletes. When the
+# kernel (KDIR) still supports "replace", pass KLP_HAS_REPLACE to the
+# modules so that they can #ifdef the legacy "replace" code. Otherwise
+# the modules are built with the provides/obsoletes based code (to be
+# added later).
+KLP_HAS_REPLACE := $(shell grep -q 'bool replace' $(KDIR)/include/linux/livepatch.h 2>/dev/null && echo y)
+ifeq ($(KLP_HAS_REPLACE),y)
+ccflags-y += -DKLP_HAS_REPLACE
+endif
+
 # Ensure that KDIR exists, otherwise skip the compilation
 modules:
 ifneq ("$(wildcard $(KDIR))", "")
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 5af7093ca00c..4b3ed17886e7 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
@@ -7,9 +7,16 @@
 #include <linux/kernel.h>
 #include <linux/livepatch.h>
 
+#ifdef KLP_HAS_REPLACE
 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).
+ */
+#endif
 
 #include <linux/seq_file.h>
 static int livepatch_meminfo_proc_show(struct seq_file *m, void *v)
@@ -36,12 +43,21 @@ static struct klp_object objs[] = {
 static struct klp_patch patch = {
 	.mod = THIS_MODULE,
 	.objs = objs,
+#ifdef KLP_HAS_REPLACE
 	/* set .replace in the init function below for demo purposes */
+#endif
 };
 
 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).
+	 */
+#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 5417573e80af..135da6d4d882 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
@@ -7,9 +7,16 @@
 #include <linux/kernel.h>
 #include <linux/livepatch.h>
 
+#ifdef KLP_HAS_REPLACE
 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).
+ */
+#endif
 
 static const char *const module_state[] = {
 	[MODULE_STATE_LIVE]	= "[MODULE_STATE_LIVE] Normal state",
@@ -72,12 +79,21 @@ static struct klp_object objs[] = {
 static struct klp_patch patch = {
 	.mod = THIS_MODULE,
 	.objs = objs,
+#ifdef KLP_HAS_REPLACE
 	/* set .replace in the init function below for demo purposes */
+#endif
 };
 
 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).
+	 */
+#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 57a4253acb01..3492472e5d07 100644
--- a/tools/testing/selftests/livepatch/test_modules/test_klp_state.c
+++ b/tools/testing/selftests/livepatch/test_modules/test_klp_state.c
@@ -142,7 +142,14 @@ static struct klp_patch patch = {
 	.mod = THIS_MODULE,
 	.objs = objs,
 	.states = states,
+#ifdef KLP_HAS_REPLACE
 	.replace = true,
+#else
+/*
+ * TODO: Add provides/obsoletes module parameters for the
+ * provides/obsoletes based tests (to be added later).
+ */
+#endif
 };
 
 static int test_klp_callbacks_demo_init(void)
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 c978ea4d5e67..8160b565a659 100644
--- a/tools/testing/selftests/livepatch/test_modules/test_klp_state2.c
+++ b/tools/testing/selftests/livepatch/test_modules/test_klp_state2.c
@@ -171,7 +171,14 @@ static struct klp_patch patch = {
 	.mod = THIS_MODULE,
 	.objs = objs,
 	.states = states,
+#ifdef KLP_HAS_REPLACE
 	.replace = true,
+#else
+/*
+ * TODO: Add provides/obsoletes module parameters for the
+ * provides/obsoletes based tests (to be added later).
+ */
+#endif
 };
 
 static int test_klp_callbacks_demo_init(void)
-- 
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 ` Yafang Shao [this message]
2026-08-09  9:33   ` [PATCH v5 6/9] selftests: livepatch: Adapt atomic replace tests to provides/obsoletes sashiko-bot
2026-08-09  9:45     ` Yafang Shao
2026-08-09  9:19 ` [PATCH v5 7/9] selftests: livepatch: Add provides/obsoletes test scenarios Yafang Shao
2026-08-09  9:31   ` 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-7-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.