| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/07/11 23:08 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch only adds a tracepoint for reference counting (`ref_trace_final_put`) and a corresponding KUnit test. It does not introduce functional changes to the kernel logic that require fuzzing.",
"WorthFuzzing": false
} |
| 1/1 | 2026/07/11 23:08 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit b61cbf4b0e0864de8d2bd2e1e38d024707fb7544\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Sat Jul 11 23:07:58 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/MAINTAINERS b/MAINTAINERS\nindex 10e8253181d321..2dbb7441906e02 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.c\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..f870ac0e8c0676 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\tdo_trace_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..6c6600938a4760\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 do_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 do_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..70d07a462da1dc 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\tdo_trace_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..3bf1b1d390b8b3\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: return address of refcount\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 do_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..7e2746be6d169e 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 TRACEPOINTS\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..466647772ce172\n--- /dev/null\n+++ b/lib/ref_trace.c\n@@ -0,0 +1,13 @@\n+// SPDX-License-Identifier: GPL-2.0\n+#define CREATE_TRACE_POINTS\n+#include \u003ctrace/events/ref_trace.h\u003e\n+#include \u003clinux/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_call__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/refcount.c b/lib/refcount.c\nindex a207a8f22b3ca3..cd7e32df391903 100644\n--- a/lib/refcount.c\n+++ b/lib/refcount.c\n@@ -7,6 +7,7 @@\n #include \u003clinux/refcount.h\u003e\n #include \u003clinux/spinlock.h\u003e\n #include \u003clinux/bug.h\u003e\n+#include \u003clinux/ref_trace.h\u003e\n \n #define REFCOUNT_WARN(str)\tWARN_ONCE(1, \"refcount_t: \" str \".\\n\")\n \n@@ -56,7 +57,12 @@ bool refcount_dec_if_one(refcount_t *r)\n {\n \tint val = 1;\n \n-\treturn atomic_try_cmpxchg_release(\u0026r-\u003erefs, \u0026val, 0);\n+\tbool ret = atomic_try_cmpxchg_release(\u0026r-\u003erefs, \u0026val, 0);\n+\n+\tif (ret)\n+\t\tdo_trace_ref_final_put(r);\n+\n+\treturn ret;\n }\n EXPORT_SYMBOL(refcount_dec_if_one);\n \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..8f896adc96d12e\n--- /dev/null\n+++ b/lib/tests/ref_trace_kunit.c\n@@ -0,0 +1,141 @@\n+// SPDX-License-Identifier: GPL-2.0\n+#include \u003clinux/kernel.h\u003e\n+#include \u003ckunit/test.h\u003e\n+#include \u003clinux/compiler_attributes.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 \u003clinux/types.h\u003e\n+#include \u003clinux/atomic.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+\tatomic_t count;\n+};\n+\n+struct data capture;\n+\n+const void *chk_obj;\n+\n+#define test_init()\t\t\t\t\t\t\t\t\\\n+\tdo {\t\t\t\t\t\t\t\t\t\\\n+\t\tKUNIT_EXPECT_FALSE(\t\t\t\t\t\t\\\n+\t\t\ttest, register_trace_ref_trace_final_put(probe, NULL));\t\\\n+\t\t\t\t\t\t\t\t\t\t\\\n+\t\tatomic_set_release(\u0026capture.count, 0);\t\t\t\t\\\n+\t\t\t\t\t\t\t\t\t\t\\\n+\t\tchk_obj = \u0026obj;\t\t\t\t\t\t\t\\\n+\t} while (0)\n+\n+\n+#define test_exit(func_name)\t\t\t\t\t\t\t\\\n+\tdo {\t\t\t\t\t\t\t\t\t\\\n+\t\t/* wait for probe completion */\t\t\t\t\t\\\n+\t\tint notimeout = wait_var_event_timeout(\t\t\t\t\\\n+\t\t\t\u0026capture.count,\t\t\t\t\t\t\\\n+\t\t\tatomic_read_acquire(\u0026capture.count),\t\t\t\\\n+\t\t\t10\t\t\t\t\t\t\t\\\n+\t\t);\t\t\t\t\t\t\t\t\\\n+\t\t\t\t\t\t\t\t\t\t\\\n+\t\tKUNIT_ASSERT_TRUE(test, notimeout);\t\t\t\t\\\n+\t\t\t\t\t\t\t\t\t\t\\\n+\t\tunregister_trace_ref_trace_final_put(probe, NULL);\t\t\\\n+\t\ttracepoint_synchronize_unregister();\t\t\t\t\\\n+\t\t\t\t\t\t\t\t\t\t\\\n+\t\tKUNIT_EXPECT_EQ(test, atomic_read_acquire(\u0026capture.count), 1);\t\\\n+\t\t/*\t\t\t\t\t\t\t\t\\\n+\t\t * caller testing may be flaky\t\t\t\t\t\\\n+\t\t * due to compile optimisations so omit\t\t\t\t\\\n+\t\t */\t\t\t\t\t\t\t\t\\\n+\t\tKUNIT_EXPECT_STREQ(test, capture.fn, #func_name);\t\t\\\n+\t\tKUNIT_EXPECT_PTR_EQ(test, capture.obj, \u0026obj);\t\t\t\\\n+\t} while (0)\n+\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+\t//prevent non test func final_puts from changing captured values\n+\tif (chk_obj != obj)\n+\t\treturn;\n+\n+\tcapture.caller = caller;\n+\tcapture.fn = fn;\n+\tcapture.obj = obj;\n+\n+\tatomic_inc_return_release(\u0026capture.count); //increase count\n+}\n+\n+static void test_refcount_sub_and_test(struct kunit *test)\n+{\n+\trefcount_t obj;\n+\n+\ttest_init();\n+\trefcount_set(\u0026obj, 2);\n+\n+\tKUNIT_EXPECT_FALSE(test, refcount_dec_and_test(\u0026obj));\n+\tKUNIT_EXPECT_TRUE(test, refcount_dec_and_test(\u0026obj));\n+\n+\ttest_exit(__refcount_sub_and_test);\n+}\n+\n+static void test_refcount_dec_if_one(struct kunit *test)\n+{\n+\trefcount_t obj;\n+\n+\ttest_init();\n+\trefcount_set(\u0026obj, 2);\n+\n+\tKUNIT_EXPECT_FALSE(test, refcount_dec_and_test(\u0026obj));\n+\tKUNIT_EXPECT_TRUE(test, refcount_dec_if_one(\u0026obj));\n+\n+\ttest_exit(refcount_dec_if_one);\n+}\n+static void dummy_release(struct percpu_ref *ref) {}\n+\n+static void test_percpu_ref_put_many(struct kunit *test)\n+{\n+\tstruct percpu_ref obj;\n+\n+\ttest_init();\n+\n+\tKUNIT_ASSERT_FALSE(test, percpu_ref_init(\u0026obj, dummy_release, 0, GFP_KERNEL));\n+\n+\tpercpu_ref_get(\u0026obj);\n+\tpercpu_ref_get(\u0026obj);\n+\n+\tpercpu_ref_put(\u0026obj);\n+\tpercpu_ref_put(\u0026obj);\n+\n+\tpercpu_ref_switch_to_atomic_sync(\u0026obj);\n+\n+\tpercpu_ref_put(\u0026obj);\n+\n+\ttest_exit(percpu_ref_put_many);\n+\tpercpu_ref_exit(\u0026obj);\n+}\n+\n+static struct kunit_case __refdata ref_trace_test_cases[] = {\n+\tKUNIT_CASE(test_refcount_sub_and_test),\n+\tKUNIT_CASE(test_refcount_dec_if_one),\n+\tKUNIT_CASE(test_percpu_ref_put_many),\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/11 23:08 | agent | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch only adds a tracepoint for reference counting (`ref_trace_final_put`) and a corresponding KUnit test. It does not introduce functional changes to the kernel logic that 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 b61cbf4b0e0864de8d2bd2e1e38d024707fb7544
Author: syz-cluster <triage@syzkaller.com>
Date: Sat Jul 11 23:07:58 2026 +0000
syz-cluster: applied patch under review
diff --git a/MAINTAINERS b/MAINTAINERS
index 10e8253181d321..2dbb7441906e02 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.c
+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..f870ac0e8c0676 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))) {
+ do_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..6c6600938a4760
--- /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 do_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 do_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..70d07a462da1dc 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();
+ do_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..3bf1b1d390b8b3
--- /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: return address of refcount
+ * 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 do_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..7e2746be6d169e 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 && TRACEPOINTS
+ 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..466647772ce172
--- /dev/null
+++ b/lib/ref_trace.c
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0
+#define CREATE_TRACE_POINTS
+#include <trace/events/ref_trace.h>
+#include <linux/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_call__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/refcount.c b/lib/refcount.c
index a207a8f22b3ca3..cd7e32df391903 100644
--- a/lib/refcount.c
+++ b/lib/refcount.c
@@ -7,6 +7,7 @@
#include <linux/refcount.h>
#include <linux/spinlock.h>
#include <linux/bug.h>
+#include <linux/ref_trace.h>
#define REFCOUNT_WARN(str) WARN_ONCE(1, "refcount_t: " str ".\n")
@@ -56,7 +57,12 @@ bool refcount_dec_if_one(refcount_t *r)
{
int val = 1;
- return atomic_try_cmpxchg_release(&r->refs, &val, 0);
+ bool ret = atomic_try_cmpxchg_release(&r->refs, &val, 0);
+
+ if (ret)
+ do_trace_ref_final_put(r);
+
+ return ret;
}
EXPORT_SYMBOL(refcount_dec_if_one);
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..8f896adc96d12e
--- /dev/null
+++ b/lib/tests/ref_trace_kunit.c
@@ -0,0 +1,141 @@
+// 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 */ \
+ int notimeout = wait_var_event_timeout( \
+ &capture.count, \
+ atomic_read_acquire(&capture.count), \
+ 10 \
+ ); \
+ \
+ KUNIT_ASSERT_TRUE(test, notimeout); \
+ \
+ unregister_trace_ref_trace_final_put(probe, NULL); \
+ tracepoint_synchronize_unregister(); \
+ \
+ 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 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 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 void test_percpu_ref_put_many(struct kunit *test)
+{
+ struct percpu_ref obj;
+
+ test_init();
+
+ KUNIT_ASSERT_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");
|
| 3/2 | 2026/07/11 23:08 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 6053 output: 72 thoughts: 779 Thoughts: **WorthFuzzing Evaluation** Okay, so I've got this patch adding a `ref_trace_final_put` tracepoint to `refcount` and `percpu-refcount`. It also includes a KUnit test for this tracepoint. I need to determine if this patch warrants fuzzing. Looking at the code modifications, it touches quite a few files: `include/linux/percpu-refcount.h`, `include/linux/ref_trace.h`, `include/linux/refcount.h`, `include/trace/events/ref_trace.h`, `lib/Kconfig`, `lib/Makefile`, `lib/ref_trace.c`, `lib/refcount.c`, `lib/tests/Makefile`, and `lib/tests/ref_trace_kunit.c`. But as far as I can tell, the modifications are solely focused on introducing this new tracepoint and its associated test. No functional logic is being modified. According to the instructions, I need to set `WorthFuzzing=false` if the patch only includes: "Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints" and KUnit tests are not fuzzed. Therefore, because this patch *only* introduces a tracepoint and a KUnit test for it, and because tracepoints are considered non-functional, it should absolutely be `WorthFuzzing=false`. The purpose of a tracepoint is purely for observability, not to alter the behavior of the system, and KUnit tests are not fuzzed. I've just double-checked the changes in `include/linux/percpu-refcount.h`, `include/linux/refcount.h`, and `lib/refcount.c` and can confirm that all the changes simply add `do_trace_ref_final_put`, which is just the tracepoint itself. The rest of the files are just defining the tracepoint and adding the test, as I expected. So, in conclusion: `WorthFuzzing=false`. The reasoning is that the patch *only* adds a tracepoint for reference counting and its corresponding KUnit test. It does *not* introduce any changes to the core kernel logic which would necessitate fuzzing. |
| 4/2 | 2026/07/11 23:08 | tool | set-results |
0mArgs:{
"EnableConfigs": [],
"FocusSymbols": [],
"Reasoning": "The patch only adds a tracepoint for reference counting (`ref_trace_final_put`) and a corresponding KUnit test. It does not introduce functional changes to the kernel logic that require fuzzing.",
"WorthFuzzing": false
}Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch only adds a tracepoint for reference counting (`ref_trace_final_put`) and a corresponding KUnit test. It does not introduce functional changes to the kernel logic that require fuzzing.",
"WorthFuzzing": false
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|