From: Eugene Mavick <[email protected]>

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 <[email protected]>
---
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/[email protected]/
---
 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 <[email protected]>");
+MODULE_DESCRIPTION("KUnit test for ref_trace");
+MODULE_LICENSE("GPL");

-- 
2.51.2



Reply via email to