[PATCH v2 4/5] kunit: add test for ref_trace_final_put
From: Eugene Mavick via B4 Relay <devnull+m.mavick.dev@kernel.org>
Date: 2026-07-10 05:31:36
Also in:
b4-sent, linux-mm, lkml
Subsystem:
library code, the rest · Maintainers:
Andrew Morton, Linus Torvalds
From: Eugene Mavick <redacted> Add a KUnit test suite for the ref_trace_final_put tracepoint. The test registers a probe function and triggers both refcount_t and percpu_ref final put paths, verifying that the tracepoint fires correctly and that the recorded fields match expected values. Signed-off-by: Eugene Mavick <redacted> --- v2: -fix v1 bug where test gave consistent false pass -make probe minimal, and only check obj and store the values -add test_init macro to register and reset count -move value checking to new test_exit macro -move MAINTAINERS file entries to new MAINTAINERS commit -v1:https://lore.kernel.org/all/20260705-refcount-final-put-trace-v1-4-cdd0014626a9@mavick.dev/ (local) --- lib/Kconfig | 10 ++++ lib/tests/Makefile | 1 + lib/tests/ref_trace_kunit.c | 136 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+)
diff --git a/lib/Kconfig b/lib/Kconfig
index 00a9509636c1..c29b2ccb3c31 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig@@ -52,6 +52,16 @@ config PACKING_KUNIT_TEST When in doubt, say N. +config REF_TRACE_KUNIT_TEST + bool "ref_trace kunit test" if !KUNIT_ALL_TESTS + depends on KUNIT && FTRACE + default KUNIT_ALL_TESTS + help + This option enables the KUnit test suite for the ref_trace_final_put + tracepoint. + + If unsure, say N + config BITREVERSE tristate
diff --git a/lib/tests/Makefile b/lib/tests/Makefile
index 7e9c2fa52e35..828a030ad8c7 100644
--- a/lib/tests/Makefile
+++ b/lib/tests/Makefile@@ -57,5 +57,6 @@ obj-$(CONFIG_USERCOPY_KUNIT_TEST) += usercopy_kunit.o obj-$(CONFIG_UTIL_MACROS_KUNIT) += util_macros_kunit.o obj-$(CONFIG_RATELIMIT_KUNIT_TEST) += test_ratelimit.o obj-$(CONFIG_UUID_KUNIT_TEST) += uuid_kunit.o +obj-$(CONFIG_REF_TRACE_KUNIT_TEST) += ref_trace_kunit.o obj-$(CONFIG_TEST_RUNTIME_MODULE) += module/
diff --git a/lib/tests/ref_trace_kunit.c b/lib/tests/ref_trace_kunit.c
new file mode 100644
index 000000000000..5c7e9d29a030
--- /dev/null
+++ b/lib/tests/ref_trace_kunit.c@@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/kernel.h> +#include <kunit/test.h> +#include <linux/compiler_attributes.h> +#include <linux/wait_bit.h> +#include <linux/instruction_pointer.h> +#include <linux/kallsyms.h> +#include <linux/percpu-refcount.h> +#include <linux/refcount.h> +#include <linux/types.h> +#include <linux/atomic.h> +#include <trace/events/ref_trace.h> + +struct data { + unsigned long caller; + const char *fn; + const void *obj; + atomic_t count; +}; + +struct data capture; + +const void *chk_obj; + +#define test_init() \ + do { \ + KUNIT_EXPECT_FALSE( \ + test, register_trace_ref_trace_final_put(probe, NULL)); \ + \ + atomic_set_release(&capture.count, 0); \ + \ + chk_obj = &obj; \ + } while (0) + + +#define test_exit(func_name) \ + do { \ + /* wait for probe completion */ \ + wait_var_event( \ + &capture.count, \ + atomic_read_acquire(&capture.count) != 0); \ + \ + unregister_trace_ref_trace_final_put(probe, NULL); \ + \ + KUNIT_EXPECT_EQ(test, atomic_read_acquire(&capture.count), 1); \ + /* \ + * caller testing may be flaky \ + * due to compile optimisations so omit \ + */ \ + KUNIT_EXPECT_STREQ(test, capture.fn, #func_name); \ + KUNIT_EXPECT_PTR_EQ(test, capture.obj, &obj); \ + } while (0) + +static void probe( + void *ignore, + unsigned long caller, + const char *fn, + const void *obj) +{ + //prevent non test func final_puts from changing captured values + if (chk_obj != obj) + return; + + capture.caller = caller; + capture.fn = fn; + capture.obj = obj; + + atomic_inc_return_release(&capture.count); //increase count +} + +static noinline void test_refcount_sub_and_test(struct kunit *test) +{ + refcount_t obj; + + test_init(); + refcount_set(&obj, 2); + + KUNIT_EXPECT_FALSE(test, refcount_dec_and_test(&obj)); + KUNIT_EXPECT_TRUE(test, refcount_dec_and_test(&obj)); + + test_exit(__refcount_sub_and_test); +} + +static __always_inline void test_refcount_dec_if_one(struct kunit *test) +{ + refcount_t obj; + + test_init(); + refcount_set(&obj, 2); + + KUNIT_EXPECT_FALSE(test, refcount_dec_and_test(&obj)); + KUNIT_EXPECT_TRUE(test, refcount_dec_if_one(&obj)); + + test_exit(refcount_dec_if_one); +} +static void dummy_release(struct percpu_ref *ref) {} + +static noinline void test_percpu_ref_put_many(struct kunit *test) +{ + struct percpu_ref obj; + + test_init(); + + KUNIT_EXPECT_FALSE(test, percpu_ref_init(&obj, dummy_release, 0, GFP_KERNEL)); + + percpu_ref_get(&obj); + percpu_ref_get(&obj); + + percpu_ref_put(&obj); + percpu_ref_put(&obj); + + percpu_ref_switch_to_atomic_sync(&obj); + + percpu_ref_put(&obj); + + test_exit(percpu_ref_put_many); + percpu_ref_exit(&obj); +} + +static struct kunit_case __refdata ref_trace_test_cases[] = { + KUNIT_CASE(test_refcount_sub_and_test), + KUNIT_CASE(test_refcount_dec_if_one), + KUNIT_CASE(test_percpu_ref_put_many), + {} +}; + +static struct kunit_suite ref_trace_test_suite = { + .name = "ref-trace", + .test_cases = ref_trace_test_cases +}; + +kunit_test_suites(&ref_trace_test_suite); + +MODULE_AUTHOR("Eugene Mavick <m@mavick.dev>"); +MODULE_DESCRIPTION("KUnit test for ref_trace"); +MODULE_LICENSE("GPL");
--
2.51.2