| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/07/05 01:45 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch only adds a tracepoint (`ref_trace_final_put`) to reference counting functions (`percpu_ref_put_many` and `__refcount_sub_and_test`) and a KUnit test for it. Tracepoints are considered purely decorative changes that do not functionally alter the execution flow, so this patch does not require fuzzing.",
"WorthFuzzing": false
} |
| 1/1 | 2026/07/05 01:45 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 927c86b256e7f27f1512ffae77357c82920e9ce6\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Sun Jul 5 01:45:23 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/MAINTAINERS b/MAINTAINERS\nindex 10e8253181d321..7c387ed746ee51 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -4210,7 +4210,10 @@ S:\tMaintained\n F:\tDocumentation/atomic_*.txt\n F:\tarch/*/include/asm/atomic*.h\n F:\tinclude/*/atomic*.h\n+F:\tinclude/linux/ref_trace.h\n F:\tinclude/linux/refcount.h\n+F:\tlib/ref_trace.h\n+F:\tlib/tests/ref_trace_kunit.c\n F:\tscripts/atomic/\n F:\trust/kernel/sync/atomic.rs\n F:\trust/kernel/sync/atomic/\ndiff --git a/include/linux/percpu-refcount.h b/include/linux/percpu-refcount.h\nindex d73a1c08c3e3c0..55543ecdf60cfb 100644\n--- a/include/linux/percpu-refcount.h\n+++ b/include/linux/percpu-refcount.h\n@@ -55,6 +55,7 @@\n #include \u003clinux/rcupdate.h\u003e\n #include \u003clinux/types.h\u003e\n #include \u003clinux/gfp.h\u003e\n+#include \u003clinux/ref_trace.h\u003e\n \n struct percpu_ref;\n typedef void (percpu_ref_func_t)(struct percpu_ref *);\n@@ -331,8 +332,10 @@ static inline void percpu_ref_put_many(struct percpu_ref *ref, unsigned long nr)\n \n \tif (__ref_is_percpu(ref, \u0026percpu_count))\n \t\tthis_cpu_sub(*percpu_count, nr);\n-\telse if (unlikely(atomic_long_sub_and_test(nr, \u0026ref-\u003edata-\u003ecount)))\n+\telse if (unlikely(atomic_long_sub_and_test(nr, \u0026ref-\u003edata-\u003ecount))) {\n+\t\ttrace_ref_final_put(ref);\n \t\tref-\u003edata-\u003erelease(ref);\n+\t}\n \n \trcu_read_unlock();\n }\ndiff --git a/include/linux/ref_trace.h b/include/linux/ref_trace.h\nnew file mode 100644\nindex 00000000000000..54e9fba9e3e9f4\n--- /dev/null\n+++ b/include/linux/ref_trace.h\n@@ -0,0 +1,26 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+#ifndef _LINUX_REF_TRACE_H\n+#define _LINUX_REF_TRACE_H\n+\n+#include \u003clinux/tracepoint-defs.h\u003e\n+#include \u003clinux/instruction_pointer.h\u003e\n+\n+/* Declare the tracepoint so tracepoint_enabled() can be used */\n+DECLARE_TRACEPOINT(ref_trace_final_put);\n+\n+#ifdef CONFIG_TRACEPOINTS\n+/* Wrapper function implemented in lib/ref_trace.c */\n+extern void do_ref_trace_final_put(unsigned long caller, const char *fn, const void *obj);\n+\n+#define trace_ref_final_put(obj)\t\t\t\t\t\t\\\n+\tdo {\t\t\t\t\t\t\t\t\t\\\n+\t\tif (tracepoint_enabled(ref_trace_final_put))\t\t\t\\\n+\t\t\tdo_ref_trace_final_put(_RET_IP_, __func__, obj);\t\\\n+\t} while (0)\n+\n+#else /* !CONFIG_TRACEPOINTS */\n+static inline void do_ref_trace_final_put(unsigned long caller, const char *fn, const void *obj) { }\n+#define trace_ref_final_put(obj) do { } while (0)\n+#endif\n+\n+#endif /* _LINUX_REF_TRACE_H */\ndiff --git a/include/linux/refcount.h b/include/linux/refcount.h\nindex ba7657ced2817f..7b1fbf326a21c6 100644\n--- a/include/linux/refcount.h\n+++ b/include/linux/refcount.h\n@@ -107,6 +107,7 @@\n #include \u003clinux/limits.h\u003e\n #include \u003clinux/refcount_types.h\u003e\n #include \u003clinux/spinlock_types.h\u003e\n+#include \u003clinux/ref_trace.h\u003e\n \n struct mutex;\n \n@@ -393,6 +394,7 @@ bool __refcount_sub_and_test(int i, refcount_t *r, int *oldp)\n \n \tif (old \u003e 0 \u0026\u0026 old == i) {\n \t\tsmp_acquire__after_ctrl_dep();\n+\t\ttrace_ref_final_put(r);\n \t\treturn true;\n \t}\n \ndiff --git a/include/trace/events/ref_trace.h b/include/trace/events/ref_trace.h\nnew file mode 100644\nindex 00000000000000..e6037a325be262\n--- /dev/null\n+++ b/include/trace/events/ref_trace.h\n@@ -0,0 +1,46 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+#undef TRACE_SYSTEM\n+#define TRACE_SYSTEM ref_trace\n+\n+#if !defined(_TRACE_REF_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)\n+#define _TRACE_REF_TRACE_H\n+\n+#include \u003clinux/tracepoint.h\u003e\n+\n+/**\n+ * ref_trace_final_put - trace when a reference count reaches zero\n+ * @caller: function that called the refcounting\n+ * function(refcount_sub_and_test, percpu_ref_put_many)\n+ * @fn: refcounting function(eg refcount_sub_and_test)\n+ * @obj: refcount object(struct percpu_ref, refcount_t)\n+ *\n+ * Tracepoint instrumentation can be added using the ref_trace_final_put\n+ * macro defined in include/linux/ref_trace.h\n+ * which uses _RET_IP_ and __func__ for caller and fn arguments respectively,\n+ * thus only requiring obj arg to be supplied\n+ */\n+TRACE_EVENT(ref_trace_final_put,\n+\n+\tTP_PROTO(unsigned long caller, const char *fn, const void *obj),\n+\n+\tTP_ARGS(caller, fn, obj),\n+\n+\tTP_STRUCT__entry(\n+\t__field(unsigned long, caller)\n+\t__string(fn, fn)\n+\t__field(const void *, obj)\n+\t),\n+\n+\tTP_fast_assign(\n+\t__entry-\u003ecaller = caller;\n+\t__assign_str(fn);\n+\t__entry-\u003eobj = obj;\n+\t),\n+\n+\tTP_printk(\"caller=%pS fn=%s obj=%p\", (void *)__entry-\u003ecaller, __get_str(fn), __entry-\u003eobj)\n+);\n+\n+#endif /* _TRACE_REF_TRACE_H */\n+\n+/* This part must be outside protection */\n+#include \u003ctrace/define_trace.h\u003e\ndiff --git a/lib/Kconfig b/lib/Kconfig\nindex 00a9509636c187..c29b2ccb3c3117 100644\n--- a/lib/Kconfig\n+++ b/lib/Kconfig\n@@ -52,6 +52,16 @@ config PACKING_KUNIT_TEST\n \n \t When in doubt, say N.\n \n+config REF_TRACE_KUNIT_TEST\n+\tbool \"ref_trace kunit test\" if !KUNIT_ALL_TESTS\n+\tdepends on KUNIT \u0026\u0026 FTRACE\n+\tdefault KUNIT_ALL_TESTS\n+\thelp\n+\t This option enables the KUnit test suite for the ref_trace_final_put\n+\t tracepoint.\n+\n+\t If unsure, say N\n+\n config BITREVERSE\n \ttristate\n \ndiff --git a/lib/Makefile b/lib/Makefile\nindex f33a24bf1c19ad..41737090a95db9 100644\n--- a/lib/Makefile\n+++ b/lib/Makefile\n@@ -335,3 +335,5 @@ CONTEXT_ANALYSIS_test_context-analysis.o := y\n obj-$(CONFIG_CONTEXT_ANALYSIS_TEST) += test_context-analysis.o\n \n subdir-$(CONFIG_FORTIFY_SOURCE) += test_fortify\n+\n+obj-$(CONFIG_TRACEPOINTS) += ref_trace.o\ndiff --git a/lib/ref_trace.c b/lib/ref_trace.c\nnew file mode 100644\nindex 00000000000000..25f7c17c7c4758\n--- /dev/null\n+++ b/lib/ref_trace.c\n@@ -0,0 +1,12 @@\n+// SPDX-License-Identifier: GPL-2.0\n+#define CREATE_TRACE_POINTS\n+#include \u003ctrace/events/ref_trace.h\u003e\n+\n+//Wrapper function for functions defined entirely in header files\n+void do_ref_trace_final_put(unsigned long caller, const char *fn, const void *obj)\n+{\n+\ttrace_ref_trace_final_put(caller, fn, obj);\n+}\n+EXPORT_SYMBOL_GPL(do_ref_trace_final_put);\n+\n+EXPORT_TRACEPOINT_SYMBOL_GPL(ref_trace_final_put);\ndiff --git a/lib/tests/Makefile b/lib/tests/Makefile\nindex 7e9c2fa52e35a4..828a030ad8c710 100644\n--- a/lib/tests/Makefile\n+++ b/lib/tests/Makefile\n@@ -57,5 +57,6 @@ obj-$(CONFIG_USERCOPY_KUNIT_TEST) += usercopy_kunit.o\n obj-$(CONFIG_UTIL_MACROS_KUNIT) += util_macros_kunit.o\n obj-$(CONFIG_RATELIMIT_KUNIT_TEST) += test_ratelimit.o\n obj-$(CONFIG_UUID_KUNIT_TEST) += uuid_kunit.o\n+obj-$(CONFIG_REF_TRACE_KUNIT_TEST) += ref_trace_kunit.o\n \n obj-$(CONFIG_TEST_RUNTIME_MODULE)\t\t+= module/\ndiff --git a/lib/tests/ref_trace_kunit.c b/lib/tests/ref_trace_kunit.c\nnew file mode 100644\nindex 00000000000000..2ece6c840fe0ad\n--- /dev/null\n+++ b/lib/tests/ref_trace_kunit.c\n@@ -0,0 +1,138 @@\n+// SPDX-License-Identifier: GPL-2.0\n+#include \u003clinux/kernel.h\u003e\n+#include \u003ckunit/test.h\u003e\n+#include \u003clinux/wait_bit.h\u003e\n+#include \u003clinux/instruction_pointer.h\u003e\n+#include \u003clinux/kallsyms.h\u003e\n+#include \u003clinux/percpu-refcount.h\u003e\n+#include \u003clinux/refcount.h\u003e\n+#include \u003ctrace/events/ref_trace.h\u003e\n+\n+struct data {\n+\tunsigned long caller;\n+\tconst char *fn;\n+\tconst void *obj;\n+\tint *flag;\n+\tstruct kunit *test;\n+};\n+\n+struct data refc_chk;\n+struct data pcpu_chk;\n+\n+//called when tracepoint fires\n+static void probe(\n+\t void *ignore,\n+\t unsigned long caller,\n+\t const char *fn,\n+\t const void *obj)\n+{\n+\tstruct data *chk_val;\n+\n+\tchar func_name[KSYM_SYMBOL_LEN];\n+\n+\tsprint_symbol_no_offset(func_name, caller);\n+\n+\tif (!strcmp(func_name, \"test_refcount\")) {\n+\t\tchk_val = \u0026refc_chk;\n+\t\tKUNIT_EXPECT_FALSE(chk_val-\u003etest, memcmp(obj, chk_val-\u003eobj, sizeof(refcount_t)));\n+\t} else if (!strcmp(func_name, \"test_percpu\")) {\n+\t\tchk_val = \u0026pcpu_chk;\n+\t\tKUNIT_EXPECT_FALSE(chk_val-\u003etest, memcmp(\n+\t\t\tobj, chk_val-\u003eobj, sizeof(struct percpu_ref)));\n+\t} else {\n+\t\t//non test function origin trace events\n+\t\treturn;\n+\t}\n+\n+\tstruct kunit *test = chk_val-\u003etest;\n+\tint *flag = chk_val-\u003eflag;\n+\n+\t//ensure past flag writes are done before reading\n+\tKUNIT_EXPECT_EQ(test, 1, smp_load_acquire(flag));\n+\tKUNIT_EXPECT_EQ(test, caller, chk_val-\u003ecaller);\n+\n+\tsmp_store_release(flag, 0); //signal probe completion\n+}\n+\n+\n+\n+static void test_refcount(struct kunit *test)\n+{\n+\trefcount_t refc;\n+\tint flag_addr = 0;\n+\n+\trefc_chk.caller = (unsigned long)\u0026test_refcount;\n+\trefc_chk.fn = \"__refcount_sub_and_test\";\n+\trefc_chk.obj = \u0026refc;\n+\trefc_chk.flag = \u0026flag_addr;\n+\trefc_chk.test = test;\n+\n+\tint *flag = refc_chk.flag;\n+\n+\tKUNIT_EXPECT_FALSE(test, register_trace_ref_trace_final_put(probe, NULL));\n+\n+\trefcount_set(\u0026refc, 2);\n+\n+\tKUNIT_EXPECT_FALSE(test, refcount_dec_and_test(\u0026refc));\n+\n+\tsmp_store_release(flag, 1); //signal final put can happen\n+\n+\tKUNIT_EXPECT_TRUE(test, refcount_dec_and_test(\u0026refc));\n+\n+\twait_var_event(flag, smp_load_acquire(flag)); //wait for probe completion\n+\tunregister_trace_ref_trace_final_put(probe, NULL);\n+}\n+\n+static void dummy_release(struct percpu_ref *ref) {}\n+\n+static void test_percpu(struct kunit *test)\n+{\n+\tstruct percpu_ref pcpu_ref;\n+\n+\tint flag_addr = 1;\n+\n+\tpcpu_chk.caller = (unsigned long)\u0026test_percpu;\n+\tpcpu_chk.fn = \"percpu_ref_put_many\";\n+\tpcpu_chk.obj = \u0026pcpu_ref;\n+\tpcpu_chk.flag = \u0026flag_addr;\n+\tpcpu_chk.test = test;\n+\n+\tint *flag = pcpu_chk.flag;\n+\n+\tKUNIT_EXPECT_FALSE(test, register_trace_ref_trace_final_put(probe, NULL));\n+\n+\tKUNIT_EXPECT_FALSE(test, percpu_ref_init(\u0026pcpu_ref, dummy_release, 0, GFP_KERNEL));\n+\n+\tpercpu_ref_get(\u0026pcpu_ref);\n+\tpercpu_ref_get(\u0026pcpu_ref);\n+\n+\tpercpu_ref_put(\u0026pcpu_ref);\n+\tpercpu_ref_put(\u0026pcpu_ref);\n+\n+\tpercpu_ref_switch_to_atomic_sync(\u0026pcpu_ref);\n+\n+\tsmp_store_release(flag, 1); //signal final put can happen\n+\n+\tpercpu_ref_put(\u0026pcpu_ref);\n+\n+\twait_var_event(flag, smp_load_acquire(flag)); //wait for probe completion\n+\tunregister_trace_ref_trace_final_put(probe, NULL);\n+\tpercpu_ref_exit(\u0026pcpu_ref);\n+}\n+\n+static struct kunit_case __refdata ref_trace_test_cases[] = {\n+\tKUNIT_CASE(test_refcount),\n+\tKUNIT_CASE(test_percpu),\n+\t{}\n+};\n+\n+static struct kunit_suite ref_trace_test_suite = {\n+\t.name = \"ref-trace\",\n+\t.test_cases = ref_trace_test_cases,\n+};\n+\n+kunit_test_suites(\u0026ref_trace_test_suite);\n+\n+MODULE_AUTHOR(\"Eugene Mavick \u003cm@mavick.dev\u003e\");\n+MODULE_DESCRIPTION(\"KUnit test for ref_trace\");\n+MODULE_LICENSE(\"GPL\");\n"
} |
| 2/1 | 2026/07/05 01:45 | agent | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch only adds a tracepoint (`ref_trace_final_put`) to reference counting functions (`percpu_ref_put_many` and `__refcount_sub_and_test`) and a KUnit test for it. Tracepoints are considered purely decorative changes that do not functionally alter the execution flow, so this patch does not require fuzzing.",
"WorthFuzzing": false
}Instruction: You are an expert Linux kernel maintainer. Your job is to review a provided patch series and determine if it makes functional changes to the kernel that should be fuzzed. IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively use your code access tools to examine the actual source code and confirm any assumptions. Return WorthFuzzing=false if the patch only contains: - Modifications to Documentation/, Kconfig files, or code comments. - Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints. - Changes to numeric constants or macros that do not functionally alter execution flow. - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim). If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true. When returning WorthFuzzing=true, you MUST ALSO: 1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols. Avoid listing generic hot-path functions to prevent skewed test distributions. 2. Identify any specific CONFIG_ options required to properly test this new/modified feature. Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions. Do not list too generic configs (we already have them enabled). Only list those that specifically cover the modified code. List them in the EnableConfigs output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4"). Prefer calling several tools at the same time to save round-trips. Use set-results tool to provide results of the analysis. It must be called exactly once before the final reply. Ignore results of this tool. Prompt: For your convenience, here is the diff of the changes:
commit 927c86b256e7f27f1512ffae77357c82920e9ce6
Author: syz-cluster <triage@syzkaller.com>
Date: Sun Jul 5 01:45:23 2026 +0000
syz-cluster: applied patch under review
diff --git a/MAINTAINERS b/MAINTAINERS
index 10e8253181d321..7c387ed746ee51 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4210,7 +4210,10 @@ S: Maintained
F: Documentation/atomic_*.txt
F: arch/*/include/asm/atomic*.h
F: include/*/atomic*.h
+F: include/linux/ref_trace.h
F: include/linux/refcount.h
+F: lib/ref_trace.h
+F: lib/tests/ref_trace_kunit.c
F: scripts/atomic/
F: rust/kernel/sync/atomic.rs
F: rust/kernel/sync/atomic/
diff --git a/include/linux/percpu-refcount.h b/include/linux/percpu-refcount.h
index d73a1c08c3e3c0..55543ecdf60cfb 100644
--- a/include/linux/percpu-refcount.h
+++ b/include/linux/percpu-refcount.h
@@ -55,6 +55,7 @@
#include <linux/rcupdate.h>
#include <linux/types.h>
#include <linux/gfp.h>
+#include <linux/ref_trace.h>
struct percpu_ref;
typedef void (percpu_ref_func_t)(struct percpu_ref *);
@@ -331,8 +332,10 @@ static inline void percpu_ref_put_many(struct percpu_ref *ref, unsigned long nr)
if (__ref_is_percpu(ref, &percpu_count))
this_cpu_sub(*percpu_count, nr);
- else if (unlikely(atomic_long_sub_and_test(nr, &ref->data->count)))
+ else if (unlikely(atomic_long_sub_and_test(nr, &ref->data->count))) {
+ trace_ref_final_put(ref);
ref->data->release(ref);
+ }
rcu_read_unlock();
}
diff --git a/include/linux/ref_trace.h b/include/linux/ref_trace.h
new file mode 100644
index 00000000000000..54e9fba9e3e9f4
--- /dev/null
+++ b/include/linux/ref_trace.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_REF_TRACE_H
+#define _LINUX_REF_TRACE_H
+
+#include <linux/tracepoint-defs.h>
+#include <linux/instruction_pointer.h>
+
+/* Declare the tracepoint so tracepoint_enabled() can be used */
+DECLARE_TRACEPOINT(ref_trace_final_put);
+
+#ifdef CONFIG_TRACEPOINTS
+/* Wrapper function implemented in lib/ref_trace.c */
+extern void do_ref_trace_final_put(unsigned long caller, const char *fn, const void *obj);
+
+#define trace_ref_final_put(obj) \
+ do { \
+ if (tracepoint_enabled(ref_trace_final_put)) \
+ do_ref_trace_final_put(_RET_IP_, __func__, obj); \
+ } while (0)
+
+#else /* !CONFIG_TRACEPOINTS */
+static inline void do_ref_trace_final_put(unsigned long caller, const char *fn, const void *obj) { }
+#define trace_ref_final_put(obj) do { } while (0)
+#endif
+
+#endif /* _LINUX_REF_TRACE_H */
diff --git a/include/linux/refcount.h b/include/linux/refcount.h
index ba7657ced2817f..7b1fbf326a21c6 100644
--- a/include/linux/refcount.h
+++ b/include/linux/refcount.h
@@ -107,6 +107,7 @@
#include <linux/limits.h>
#include <linux/refcount_types.h>
#include <linux/spinlock_types.h>
+#include <linux/ref_trace.h>
struct mutex;
@@ -393,6 +394,7 @@ bool __refcount_sub_and_test(int i, refcount_t *r, int *oldp)
if (old > 0 && old == i) {
smp_acquire__after_ctrl_dep();
+ trace_ref_final_put(r);
return true;
}
diff --git a/include/trace/events/ref_trace.h b/include/trace/events/ref_trace.h
new file mode 100644
index 00000000000000..e6037a325be262
--- /dev/null
+++ b/include/trace/events/ref_trace.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM ref_trace
+
+#if !defined(_TRACE_REF_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_REF_TRACE_H
+
+#include <linux/tracepoint.h>
+
+/**
+ * ref_trace_final_put - trace when a reference count reaches zero
+ * @caller: function that called the refcounting
+ * function(refcount_sub_and_test, percpu_ref_put_many)
+ * @fn: refcounting function(eg refcount_sub_and_test)
+ * @obj: refcount object(struct percpu_ref, refcount_t)
+ *
+ * Tracepoint instrumentation can be added using the ref_trace_final_put
+ * macro defined in include/linux/ref_trace.h
+ * which uses _RET_IP_ and __func__ for caller and fn arguments respectively,
+ * thus only requiring obj arg to be supplied
+ */
+TRACE_EVENT(ref_trace_final_put,
+
+ TP_PROTO(unsigned long caller, const char *fn, const void *obj),
+
+ TP_ARGS(caller, fn, obj),
+
+ TP_STRUCT__entry(
+ __field(unsigned long, caller)
+ __string(fn, fn)
+ __field(const void *, obj)
+ ),
+
+ TP_fast_assign(
+ __entry->caller = caller;
+ __assign_str(fn);
+ __entry->obj = obj;
+ ),
+
+ TP_printk("caller=%pS fn=%s obj=%p", (void *)__entry->caller, __get_str(fn), __entry->obj)
+);
+
+#endif /* _TRACE_REF_TRACE_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/lib/Kconfig b/lib/Kconfig
index 00a9509636c187..c29b2ccb3c3117 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/Makefile b/lib/Makefile
index f33a24bf1c19ad..41737090a95db9 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -335,3 +335,5 @@ CONTEXT_ANALYSIS_test_context-analysis.o := y
obj-$(CONFIG_CONTEXT_ANALYSIS_TEST) += test_context-analysis.o
subdir-$(CONFIG_FORTIFY_SOURCE) += test_fortify
+
+obj-$(CONFIG_TRACEPOINTS) += ref_trace.o
diff --git a/lib/ref_trace.c b/lib/ref_trace.c
new file mode 100644
index 00000000000000..25f7c17c7c4758
--- /dev/null
+++ b/lib/ref_trace.c
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+#define CREATE_TRACE_POINTS
+#include <trace/events/ref_trace.h>
+
+//Wrapper function for functions defined entirely in header files
+void do_ref_trace_final_put(unsigned long caller, const char *fn, const void *obj)
+{
+ trace_ref_trace_final_put(caller, fn, obj);
+}
+EXPORT_SYMBOL_GPL(do_ref_trace_final_put);
+
+EXPORT_TRACEPOINT_SYMBOL_GPL(ref_trace_final_put);
diff --git a/lib/tests/Makefile b/lib/tests/Makefile
index 7e9c2fa52e35a4..828a030ad8c710 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 00000000000000..2ece6c840fe0ad
--- /dev/null
+++ b/lib/tests/ref_trace_kunit.c
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
+#include <kunit/test.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 <trace/events/ref_trace.h>
+
+struct data {
+ unsigned long caller;
+ const char *fn;
+ const void *obj;
+ int *flag;
+ struct kunit *test;
+};
+
+struct data refc_chk;
+struct data pcpu_chk;
+
+//called when tracepoint fires
+static void probe(
+ void *ignore,
+ unsigned long caller,
+ const char *fn,
+ const void *obj)
+{
+ struct data *chk_val;
+
+ char func_name[KSYM_SYMBOL_LEN];
+
+ sprint_symbol_no_offset(func_name, caller);
+
+ if (!strcmp(func_name, "test_refcount")) {
+ chk_val = &refc_chk;
+ KUNIT_EXPECT_FALSE(chk_val->test, memcmp(obj, chk_val->obj, sizeof(refcount_t)));
+ } else if (!strcmp(func_name, "test_percpu")) {
+ chk_val = &pcpu_chk;
+ KUNIT_EXPECT_FALSE(chk_val->test, memcmp(
+ obj, chk_val->obj, sizeof(struct percpu_ref)));
+ } else {
+ //non test function origin trace events
+ return;
+ }
+
+ struct kunit *test = chk_val->test;
+ int *flag = chk_val->flag;
+
+ //ensure past flag writes are done before reading
+ KUNIT_EXPECT_EQ(test, 1, smp_load_acquire(flag));
+ KUNIT_EXPECT_EQ(test, caller, chk_val->caller);
+
+ smp_store_release(flag, 0); //signal probe completion
+}
+
+
+
+static void test_refcount(struct kunit *test)
+{
+ refcount_t refc;
+ int flag_addr = 0;
+
+ refc_chk.caller = (unsigned long)&test_refcount;
+ refc_chk.fn = "__refcount_sub_and_test";
+ refc_chk.obj = &refc;
+ refc_chk.flag = &flag_addr;
+ refc_chk.test = test;
+
+ int *flag = refc_chk.flag;
+
+ KUNIT_EXPECT_FALSE(test, register_trace_ref_trace_final_put(probe, NULL));
+
+ refcount_set(&refc, 2);
+
+ KUNIT_EXPECT_FALSE(test, refcount_dec_and_test(&refc));
+
+ smp_store_release(flag, 1); //signal final put can happen
+
+ KUNIT_EXPECT_TRUE(test, refcount_dec_and_test(&refc));
+
+ wait_var_event(flag, smp_load_acquire(flag)); //wait for probe completion
+ unregister_trace_ref_trace_final_put(probe, NULL);
+}
+
+static void dummy_release(struct percpu_ref *ref) {}
+
+static void test_percpu(struct kunit *test)
+{
+ struct percpu_ref pcpu_ref;
+
+ int flag_addr = 1;
+
+ pcpu_chk.caller = (unsigned long)&test_percpu;
+ pcpu_chk.fn = "percpu_ref_put_many";
+ pcpu_chk.obj = &pcpu_ref;
+ pcpu_chk.flag = &flag_addr;
+ pcpu_chk.test = test;
+
+ int *flag = pcpu_chk.flag;
+
+ KUNIT_EXPECT_FALSE(test, register_trace_ref_trace_final_put(probe, NULL));
+
+ KUNIT_EXPECT_FALSE(test, percpu_ref_init(&pcpu_ref, dummy_release, 0, GFP_KERNEL));
+
+ percpu_ref_get(&pcpu_ref);
+ percpu_ref_get(&pcpu_ref);
+
+ percpu_ref_put(&pcpu_ref);
+ percpu_ref_put(&pcpu_ref);
+
+ percpu_ref_switch_to_atomic_sync(&pcpu_ref);
+
+ smp_store_release(flag, 1); //signal final put can happen
+
+ percpu_ref_put(&pcpu_ref);
+
+ wait_var_event(flag, smp_load_acquire(flag)); //wait for probe completion
+ unregister_trace_ref_trace_final_put(probe, NULL);
+ percpu_ref_exit(&pcpu_ref);
+}
+
+static struct kunit_case __refdata ref_trace_test_cases[] = {
+ KUNIT_CASE(test_refcount),
+ KUNIT_CASE(test_percpu),
+ {}
+};
+
+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");
|
| 3/2 | 2026/07/05 01:45 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 5812 output: 106 thoughts: 578 Thoughts: **Analyzing the Patch for Fuzzing Worthiness** Okay, so I've got this patch adding a new tracepoint, `ref_trace_final_put`, that triggers when a reference count hits zero. It seems to modify a few core files: `percpu-refcount.h` and `refcount.h`, where it's injecting calls to `trace_ref_final_put`. Additionally, it adds the necessary tracepoint definitions, a wrapper function in `lib/ref_trace.c`, and a KUnit test. Now, let's see... the instructions say to mark patches as `WorthFuzzing=false` if they are, and I quote, "Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints." Bingo! This is explicitly a tracepoint. The patch is solely adding tracing capabilities, and a test for those capabilities. Just to be absolutely certain, let me quickly double-check the code. In `percpu-refcount.h`, they've added the tracepoint call right before the `release` function; completely decorative, confirming the instructions. Likewise, in `refcount.h`, they've added the tracepoint call just before returning. The remaining files are all just supporting the new tracepoint. Yep, it's clear: it's purely adding a tracepoint and associated infrastructure. Therefore, `WorthFuzzing=false`. I'll use `set-results` to submit the evaluation. |
| 4/2 | 2026/07/05 01:45 | tool | set-results |
0mArgs:{
"EnableConfigs": [],
"FocusSymbols": [],
"Reasoning": "The patch only adds a tracepoint (`ref_trace_final_put`) to reference counting functions (`percpu_ref_put_many` and `__refcount_sub_and_test`) and a KUnit test for it. Tracepoints are considered purely decorative changes that do not functionally alter the execution flow, so this patch does not require fuzzing.",
"WorthFuzzing": false
}Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch only adds a tracepoint (`ref_trace_final_put`) to reference counting functions (`percpu_ref_put_many` and `__refcount_sub_and_test`) and a KUnit test for it. Tracepoints are considered purely decorative changes that do not functionally alter the execution flow, so this patch does not require fuzzing.",
"WorthFuzzing": false
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|