Skip to contentSkip to conversation

tracing: Updates for 7.2

PATCH In review Steven Rostedt 4 participants 23 messages May 22 – Jul 1

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

cover tracing: Updates for 7.2

git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git
trace/for-next

Head SHA1: 292c8197e3685aa7ea5a3803ca240b2210fcd021

Ao Sun (1):
tracing: Fix README path for synthetic_events

David Carlier (1):
tracepoint: Add lockdep rcu_is_watching() check to trace_##name##_enabled()

Martin Kaiser (1):
tracefs: Fix typo in a comment of eventfs_callback() kerneldoc

Pengpeng Hou (1):
tracing: Bound synthetic-field strings with seq_buf

Qian-Yu Lin (1):
tracing: Remove local variable for argument detection from trace_printk()

Rosen Penev (1):
tracing: Simplify pages allocation for tracing_map logic

Shuvam Pandey (1):
seq_buf: Export seq_buf_putmem_hex() and add KUnit tests

Steven Rostedt (2):
tracing: Allow perf to read synthetic events
tracing: Move trace_iterator_increment() into trace_find_next_entry_inc()

Vineeth Pillai (2):
cpufreq: amd-pstate: Use trace_call__##name() at guarded tracepoint call site
HID: Use trace_call__##name() at guarded tracepoint call sites

Yash Suthar (2):
tracing: Remove redundant IS_ERR() check in trace_pipe_open()
tracing: Switch trace_recursion_record.c code over to use guard()

Yu Peng (2):
tracing/branch: Use pr_warn() instead of printk(KERN_WARNING)
tracing: Use krealloc_array() for trace option array growth

----

 drivers/cpufreq/amd-pstate.c            |   3 +-
 drivers/hid/intel-ish-hid/ipc/pci-ish.c |   2 +-
 include/linux/trace_printk.h            |   3 +-
 include/linux/tracefs.h                 |   2 +-
 include/linux/tracepoint.h              |   4 ++
 kernel/trace/trace.c                    |  25 +++----
 kernel/trace/trace_branch.c             |   9 +--
 kernel/trace/trace_events_hist.c        |  41 +++++++----
 kernel/trace/trace_events_synth.c       | 121 +++++++++++++++++++++++++-------
 kernel/trace/trace_recursion_record.c   |   8 +--
 kernel/trace/trace_remote.c             |   2 +-
 kernel/trace/tracing_map.c              |  30 +++-----
 kernel/trace/tracing_map.h              |   2 +-
 lib/seq_buf.c                           |   1 +
 lib/tests/seq_buf_kunit.c               |  34 +++++++++
 15 files changed, 197 insertions(+), 90 deletions(-)
#1 lore raw

PATCH 1/15 tracing: Remove redundant IS_ERR() check in trace_pipe_open()

From: Yash Suthar <[email protected]>

in trace_pipe_open() already check the IS_ERR(iter) and return early on error,so iter after will be valid and it is safe to return 0 at end.

---
 kernel/trace/trace_remote.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/trace_remote.c +1 -1
index d6c3f94d67cd..2a6cc000ec98 100644
@@ -602,7 +602,7 @@ static int trace_pipe_open(struct inode *inode, struct file *filp)
 
 	filp->private_data = iter;
 
-	return IS_ERR(iter) ? PTR_ERR(iter) : 0;
+	return 0;
 }
 
 static int trace_pipe_release(struct inode *inode, struct file *filp)
Signature · 1 line
2.53.0
#2 lore raw

PATCH 2/15 seq_buf: Export seq_buf_putmem_hex() and add KUnit tests

In reply to Steven Rostedt

From: Shuvam Pandey <[email protected]>

The seq_buf KUnit suite does not exercise seq_buf_putmem_hex().

Add one test for the len > 8 chunking path and one overflow test where a later chunk no longer fits in the buffer.

Export seq_buf_putmem_hex() as well so SEQ_BUF_KUNIT_TEST=m links cleanly. Without the export, modpost reports seq_buf_putmem_hex as undefined when seq_buf_kunit is built as a module.

---
 lib/seq_buf.c             |  1 +
 lib/tests/seq_buf_kunit.c | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+)
lib/seq_buf.c +1 -0
index f3f3436d60a9..b59488fa8135 100644
@@ -298,6 +298,7 @@ int seq_buf_putmem_hex(struct seq_buf *s, const void *mem,
 	}
 	return 0;
 }
+EXPORT_SYMBOL_GPL(seq_buf_putmem_hex);
 
 /**
  * seq_buf_path - copy a path into the sequence buffer
lib/tests/seq_buf_kunit.c +34 -0
index 8a01579a978e..eb466386bbef 100644
@@ -184,6 +184,38 @@ static void seq_buf_get_buf_commit_test(struct kunit *test)
 	KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s));
 }
 
+static void seq_buf_putmem_hex_test(struct kunit *test)
+{
+	DECLARE_SEQ_BUF(s, 24);
+	const u8 data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+#ifdef __BIG_ENDIAN
+	const char *expected = "0001020304050607 0809 ";
+#else
+	const char *expected = "0706050403020100 0908 ";
+#endif
+
+	KUNIT_EXPECT_EQ(test, seq_buf_putmem_hex(&s, data, sizeof(data)), 0);
+	KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s));
+	KUNIT_EXPECT_EQ(test, seq_buf_used(&s), strlen(expected));
+	KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), expected);
+}
+
+static void seq_buf_putmem_hex_overflow_test(struct kunit *test)
+{
+	DECLARE_SEQ_BUF(s, 20);
+	const u8 data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+#ifdef __BIG_ENDIAN
+	const char *expected = "0001020304050607 ";
+#else
+	const char *expected = "0706050403020100 ";
+#endif
+
+	KUNIT_EXPECT_EQ(test, seq_buf_putmem_hex(&s, data, sizeof(data)), -1);
+	KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s));
+	KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 20);
+	KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), expected);
+}
+
 static struct kunit_case seq_buf_test_cases[] = {
 	KUNIT_CASE(seq_buf_init_test),
 	KUNIT_CASE(seq_buf_declare_test),
@@ -194,6 +226,8 @@ static struct kunit_case seq_buf_test_cases[] = {
 	KUNIT_CASE(seq_buf_printf_test),
 	KUNIT_CASE(seq_buf_printf_overflow_test),
 	KUNIT_CASE(seq_buf_get_buf_commit_test),
+	KUNIT_CASE(seq_buf_putmem_hex_test),
+	KUNIT_CASE(seq_buf_putmem_hex_overflow_test),
 	{}
 };
 
Signature · 1 line
2.53.0
#3 lore raw

PATCH 3/15 tracing: Bound synthetic-field strings with seq_buf

In reply to Steven Rostedt

From: Pengpeng Hou <[email protected]>

The synthetic field helpers build a prefixed synthetic variable name and a generated hist command in fixed MAX_FILTER_STR_VAL buffers. The current code appends those strings with raw strcat(), so long key lists, field names, or saved filters can run past the end of the staging buffers.

Build both strings with seq_buf and propagate -E2BIG if either the synthetic variable name or the generated command exceeds MAX_FILTER_STR_VAL. This keeps the existing tracing-side limit while using the helper intended for bounded command construction.

Cc Mathieu Desnoyers <[email protected]>
Cc Tom Zanussi <[email protected]>
Fixes 02205a6752f2 ("tracing: Add support for 'field variables'")
[ sdr: Moved struct seq_buf *s for upside-down x-mas tree formatting ]
---
 kernel/trace/trace_events_hist.c | 41 ++++++++++++++++++++++----------
 1 file changed, 29 insertions(+), 12 deletions(-)
kernel/trace/trace_events_hist.c +29 -12
index eb2c2bc8bc3d..9701650c89b2 100644
@@ -8,6 +8,7 @@
 #include <linux/module.h>
 #include <linux/kallsyms.h>
 #include <linux/security.h>
+#include <linux/seq_buf.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/stacktrace.h>
@@ -2967,13 +2968,22 @@ find_synthetic_field_var(struct hist_trigger_data *target_hist_data,
 {
 	struct hist_field *event_var;
 	char *synthetic_name;
+	struct seq_buf s;
 
 	synthetic_name = kzalloc(MAX_FILTER_STR_VAL, GFP_KERNEL);
 	if (!synthetic_name)
 		return ERR_PTR(-ENOMEM);
 
-	strcpy(synthetic_name, "synthetic_");
-	strcat(synthetic_name, field_name);
+	seq_buf_init(&s, synthetic_name, MAX_FILTER_STR_VAL);
+	seq_buf_printf(&s, "synthetic_%s", field_name);
+
+	/* Terminate synthetic_name with a NUL. */
+	seq_buf_str(&s);
+
+	if (seq_buf_has_overflowed(&s)) {
+		kfree(synthetic_name);
+		return ERR_PTR(-E2BIG);
+	}
 
 	event_var = find_event_var(target_hist_data, system, event_name, synthetic_name);
 
@@ -3019,6 +3029,7 @@ create_field_var_hist(struct hist_trigger_data *target_hist_data,
 	struct hist_field *key_field;
 	struct hist_field *event_var;
 	char *saved_filter;
+	struct seq_buf s;
 	char *cmd;
 	int ret;
 
@@ -3063,28 +3074,34 @@ create_field_var_hist(struct hist_trigger_data *target_hist_data,
 		return ERR_PTR(-ENOMEM);
 	}
 
+	seq_buf_init(&s, cmd, MAX_FILTER_STR_VAL);
+
 	/* Use the same keys as the compatible histogram */
-	strcat(cmd, "keys=");
+	seq_buf_puts(&s, "keys=");
 
 	for_each_hist_key_field(i, hist_data) {
 		key_field = hist_data->fields[i];
 		if (!first)
-			strcat(cmd, ",");
-		strcat(cmd, key_field->field->name);
+			seq_buf_putc(&s, ',');
+		seq_buf_puts(&s, key_field->field->name);
 		first = false;
 	}
 
 	/* Create the synthetic field variable specification */
-	strcat(cmd, ":synthetic_");
-	strcat(cmd, field_name);
-	strcat(cmd, "=");
-	strcat(cmd, field_name);
+	seq_buf_printf(&s, ":synthetic_%s=%s", field_name, field_name);
 
 	/* Use the same filter as the compatible histogram */
 	saved_filter = find_trigger_filter(hist_data, file);
-	if (saved_filter) {
-		strcat(cmd, " if ");
-		strcat(cmd, saved_filter);
+	if (saved_filter)
+		seq_buf_printf(&s, " if %s", saved_filter);
+
+	/* Terminate cmd with a NUL. */
+	seq_buf_str(&s);
+
+	if (seq_buf_has_overflowed(&s)) {
+		kfree(cmd);
+		kfree(var_hist);
+		return ERR_PTR(-E2BIG);
 	}
 
 	var_hist->cmd = kstrdup(cmd, GFP_KERNEL);
Signature · 1 line
2.53.0
#4 lore raw

PATCH 4/15 tracepoint: Add lockdep rcu_is_watching() check to trace_##name##_enabled()

In reply to Steven Rostedt

From: David Carlier <[email protected]>

The trace_##name##_enabled() static call branch is used when work needs to be done for a tracepoint. It allows that work to be skipped when the tracepoint is not active and still uses the static_branch() of the tracepoint to keep performance.

Tracepoints themselves require being called in "RCU watching" locations otherwise races can occur that corrupts things. In order to make sure lockdep triggers at tracepoint locations, the lockdep checks are added to the tracepoint calling location and trigger even if the tracepoint is not enabled. This is done because a poorly placed tracepoint may never be detected if it is never enabled when lockdep is enabled.

As trace_##name##_enabled() also prevents the lockdep checks when the tracepoint is disabled add lockdep checks to that as well so that if one is placed in a location that RCU is not watching, it will trigger a lockdep splat even when the tracepoint is not enabled.

Cc Vineeth Pillai (Google) <[email protected]>
Cc Mathieu Desnoyers <[email protected]>
Cc Masami Hiramatsu <[email protected]>
Cc Peter Zijlstra <[email protected]>
[ Updated the change log ]
---
 include/linux/tracepoint.h | 4 ++++
 1 file changed, 4 insertions(+)
include/linux/tracepoint.h +4 -0
index 763eea4d80d8..c29fc57392bb 100644
@@ -293,6 +293,10 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
 	static inline bool						\
 	trace_##name##_enabled(void)					\
 	{								\
+		if (IS_ENABLED(CONFIG_LOCKDEP)) {			\
+			WARN_ONCE(!rcu_is_watching(),			\
+				  "RCU not watching for tracepoint");	\
+		}							\
 		return static_branch_unlikely(&__tracepoint_##name.key);\
 	}
 
Signature · 1 line
2.53.0
#5 lore raw

Re: [for-next][PATCH 04/15] tracepoint: Add lockdep rcu_is_watching() check to trace_##name##_enabled()

Hi Steven, David,

Quoted 19 lines · Steven Rostedt

From: David Carlier <[email protected]>

The trace_##name##_enabled() static call branch is used when work needs to be done for a tracepoint. It allows that work to be skipped when the tracepoint is not active and still uses the static_branch() of the tracepoint to keep performance.

Tracepoints themselves require being called in "RCU watching" locations otherwise races can occur that corrupts things. In order to make sure lockdep triggers at tracepoint locations, the lockdep checks are added to the tracepoint calling location and trigger even if the tracepoint is not enabled. This is done because a poorly placed tracepoint may never be detected if it is never enabled when lockdep is enabled.

As trace_##name##_enabled() also prevents the lockdep checks when the tracepoint is disabled add lockdep checks to that as well so that if one is placed in a location that RCU is not watching, it will trigger a lockdep splat even when the tracepoint is not enabled.

Quoted 8 lines
Cc Vineeth Pillai (Google) <[email protected]>
Cc Mathieu Desnoyers <[email protected]>
Cc Masami Hiramatsu <[email protected]>
Cc Peter Zijlstra <[email protected]>
[ Updated the change log ]

Thanks for your patch, which is now commit 9764e731ef6abacd ("tracepoint: Add lockdep rcu_is_watching() check to trace_##name##_enabled()") in v7.2-rc1.

This is causing multiple warnings during system suspend on Renesas SH-Mobile AG5, R-Car H1. and R-Car M2-W:

PM: suspend entry (deep)
-Filesystems sync: 0.018 seconds
+Filesystems sync: 0.027 seconds
Freezing user space processes
Freezing user space processes completed (elapsed 0.001 seconds) OOM killer disabled.
Freezing remaining freezable tasks
Freezing remaining freezable tasks completed (elapsed 0.001 seconds)
-PM: suspend devices took 0.110 seconds
+------------[ cut here ]------------
+WARNING: include/trace/events/preemptirq.h:36 at

trace_irq_disable_enabled+0x3c/0x64, CPU#0: swapper/0/0
    +------------[ cut here ]------------
    +RCU not watching for tracepoint
    +Modules linked in:
    +WARNING: include/trace/events/preemptirq.h:40 at
trace_irq_enable_enabled+0x3c/0x64, CPU#1: swapper/1/0
    +
    +RCU not watching for tracepoint
    +CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted

7.1.0-rc4-koelsch-00006-g9764e731ef6a #2337 VOLUNTARY
+Hardware name: Generic R-Car Gen2 (Flattened Device Tree) +Call trace:
+ unwind_backtrace from show_stack+0x10/0x14
+ show_stack from dump_stack_lvl+0x7c/0xb0
+ dump_stack_lvl from __warn+0x98/0x27c
+ __warn from warn_slowpath_fmt+0xc0/0x124
+ warn_slowpath_fmt from trace_irq_disable_enabled+0x3c/0x64
+ trace_irq_disable_enabled from trace_hardirqs_off+0x6c/0xb0
+ trace_hardirqs_off from __irq_svc+0x48/0xac +Exception stack(0xc1401f20 to 0xc1401f68)
+1f20: c027a764 effb0e88 00000000 00000001 c140b080 c027a764
c140801c c140b080

    +1f40: c1407fe0 00000000 c140801c 00000000 fffffff8 c1401f70

c0b35980 c0b359d8
+1f60: 20000113 ffffffff
+ __irq_svc from cpu_idle_poll+0x114/0x130
+ cpu_idle_poll from do_idle+0xb8/0x268
+ do_idle from cpu_startup_entry+0x28/0x2c
+ cpu_startup_entry from rest_init+0x150/0x178
+ rest_init from start_kernel+0x634/0x6d8 +irq event stamp: 19112
+Modules linked in:
+hardirqs last enabled at (19111): [<c0b35adc>]

default_idle_call+0xe8/0x104
    +
    +hardirqs last disabled at (19112): [<c0200b88>] __irq_svc+0x48/0xac
    +CPU: 1 UID: 0 PID: 0 Comm: swapper/1 Not tainted

7.1.0-rc4-koelsch-00006-g9764e731ef6a #2337 VOLUNTARY
+Hardware name: Generic R-Car Gen2 (Flattened Device Tree) +Call trace:
+ unwind_backtrace from show_stack+0x10/0x14
+ show_stack from dump_stack_lvl+0x7c/0xb0
+ dump_stack_lvl from __warn+0x98/0x27c
+ __warn from warn_slowpath_fmt+0xc0/0x124
+ warn_slowpath_fmt from trace_irq_enable_enabled+0x3c/0x64
+ trace_irq_enable_enabled from trace_hardirqs_on+0x40/0xbc
+ trace_hardirqs_on from __irq_svc+0x94/0xac +Exception stack(0xf0865f48 to 0xf0865f90)
+5f40: c027a764 effc2e88 00000000 00000001
c227cec0 c027a764

    +5f60: c140801c c227cec0 c1407fe0 413fc0f2 c140801c 00000000
fffffff8 f0865f98
    +5f80: c0b35980 c0b35988 20000013 ffffffff
    + __irq_svc from cpu_idle_poll+0xc4/0x130
    + cpu_idle_poll from do_idle+0xb8/0x268
    + do_idle from cpu_startup_entry+0x28/0x2c
    + cpu_startup_entry from secondary_start_kernel+0xdc/0xf0
    + secondary_start_kernel from 0x4020f094
    +irq event stamp: 27461
    +softirqs last  enabled at (19008): [<c02341ec>] handle_softirqs+0x174/0x3e4
    +hardirqs last  enabled at (27461): [<c027a7d0>] do_idle+0x124/0x268
    +softirqs last disabled at (18991): [<c0234a84>] __irq_exit_rcu+0xf0/0x194
    +hardirqs last disabled at (27460): [<c027a734>] do_idle+0x88/0x268
    +---[ end trace 0000000000000000 ]---
    +softirqs last  enabled at (27438): [<c02341ec>] handle_softirqs+0x174/0x3e4
    +softirqs last disabled at (27425): [<c0234a84>] __irq_exit_rcu+0xf0/0x194
    +---[ end trace 0000000000000000 ]---
    +PM: suspend devices took 0.380 seconds
     Disabling non-boot CPUs ...

Other Renesas ARM32 platforms I tried (R-Mobile A1, RZ/A1H, RZ/A2M) are unafffected, perhaps because they are not SMP?
All Renesas ARM64 platforms I tried (R-Car Gen3/4) are also unaffected.

Reverting the commit fixes the issue.

Do you have a clue?
Thanks!

include/linux/tracepoint.h static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p) · line 301

Quoted 12 lines
include/linux/tracepoint.h +4 -0
@@ -293,6 +293,10 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
        static inline bool                                              \
        trace_##name##_enabled(void)                                    \
        {                                                               \
+               if (IS_ENABLED(CONFIG_LOCKDEP)) {                       \
+                       WARN_ONCE(!rcu_is_watching(),                   \
+                                 "RCU not watching for tracepoint");   \
+               }                                                       \
                return static_branch_unlikely(&__tracepoint_##name.key);\
        }

Gr{oetje,eeting}s,

Geert

Signature · 5 lines
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
#6 lore raw

Re: [for-next][PATCH 04/15] tracepoint: Add lockdep rcu_is_watching() check to trace_##name##_enabled()

Quoted 7 lines · On Tue, 30 Jun 2026 19:39:02 +0200 Geert Uytterhoeven <[email protected]>…

Other Renesas ARM32 platforms I tried (R-Mobile A1, RZ/A1H, RZ/A2M) are unafffected, perhaps because they are not SMP?
All Renesas ARM64 platforms I tried (R-Car Gen3/4) are also unaffected.

Reverting the commit fixes the issue.

Do you have a clue?

Yes, it means the code was buggy before the commit. The commit will trigger warnings in places that have issues. Before the commit, the buggy code was never caught.

It's like enabling KASAN and finding code that has use-after-free. Disabling KASAN is not the fix.

Tracepoints are managed by using RCU. There's places that RCU is turned off, meaning a tracepoint in one of those locations can be triggered when RCU is not active which may have a use-after-free semantic when the tracepoint is enabled.

Tracepoints hidden by trace_#tracepoint#_enabled() are not caught when RCU is disabled and the tracepoint is not active. This commit makes these locations trigger even when the tracepoint is not active.

One way to find out if this is an existing bug or not, could you enable the preemptirq tracepoints and run the tests again with the commit reverted?

echo 1 > /sys/kernel/tracing/events/preemptirq/enable

This will enable the events that are hidden without the commit. If it triggers when enabled, it shows the commit found a bug.

If you get the same errors, the bug isn't with the commit in question, it's with the tracepoints being called during suspend/resume. We will need to fix that if that's the case.

-- Steve

#7 lore raw

Re: [for-next][PATCH 04/15] tracepoint: Add lockdep rcu_is_watching() check to trace_##name##_enabled()

Hi Steven,

Quoted 17 lines · Steven Rostedt
Quoted 7 lines · On Tue, 30 Jun 2026 19:39:02 +0200 Geert Uytterhoeven <[email protected]>…

Other Renesas ARM32 platforms I tried (R-Mobile A1, RZ/A1H, RZ/A2M) are unafffected, perhaps because they are not SMP?
All Renesas ARM64 platforms I tried (R-Car Gen3/4) are also unaffected.

Reverting the commit fixes the issue.

Do you have a clue?

Yes, it means the code was buggy before the commit. The commit will trigger warnings in places that have issues. Before the commit, the buggy code was never caught.

It's like enabling KASAN and finding code that has use-after-free. Disabling KASAN is not the fix.

Quoted 8 lines

Tracepoints are managed by using RCU. There's places that RCU is turned off, meaning a tracepoint in one of those locations can be triggered when RCU is not active which may have a use-after-free semantic when the tracepoint is enabled.

Tracepoints hidden by trace_#tracepoint#_enabled() are not caught when RCU is disabled and the tracepoint is not active. This commit makes these locations trigger even when the tracepoint is not active.

Sorry, my wording could indeed be better: this commit probably does not "cause" the issue, but merely exposes it.

Quoted 11 lines

One way to find out if this is an existing bug or not, could you enable the preemptirq tracepoints and run the tests again with the commit reverted?

echo 1 > /sys/kernel/tracing/events/preemptirq/enable

This will enable the events that are hidden without the commit. If it triggers when enabled, it shows the commit found a bug.

If you get the same errors, the bug isn't with the commit in question, it's with the tracepoints being called during suspend/resume. We will need to fix that if that's the case.

Thanks, it does not trigger with the commit reverted and the "echo 1 > ...".

Gr{oetje,eeting}s,

Geert

Signature · 5 lines
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
#8 lore raw

Re: [for-next][PATCH 04/15] tracepoint: Add lockdep rcu_is_watching() check to trace_##name##_enabled()

Quoted 1 line · On Wed, 1 Jul 2026 11:24:31 +0200 Geert Uytterhoeven <[email protected]>…

Thanks, it does not trigger with the commit reverted and the "echo 1 > ...".

Ah found the issue;

#define trace(point, args)                                      \
        do {                                                    \
                if (trace_##point##_enabled()) {                \
                        bool exit_rcu = false;                  \
                        if (in_nmi())                           \
                                break;                          \
                        if (!IS_ENABLED(CONFIG_TINY_RCU) &&     \
                            is_idle_task(current)) {            \
                                ct_irq_enter();                 \
                                exit_rcu = true;                \
                        }                                       \
                        trace_##point(args);                    \
                        if (exit_rcu)                           \
                                ct_irq_exit();                  \
                }                                               \
        } while (0)

#endif

The code within the enabled() call checks if RCU is watching, and if not, it makes it watch. So yeah, this is a special case.

The following patch should fix the issue:

include/linux/tracepoint.h +11 -1
index 4a0c36f40fe2..e0d838c9ce93 100644
@@ -292,13 +292,18 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
 	{								\
 	}								\
 	static inline bool						\
+	__trace_##name##_enabled(void)					\
+	{								\
+		return static_branch_unlikely(&__tracepoint_##name.key);\
+	}								\
+	static inline bool						\
 	trace_##name##_enabled(void)					\
 	{								\
 		if (IS_ENABLED(CONFIG_LOCKDEP)) {			\
 			WARN_ONCE(!rcu_is_watching(),			\
 				  "RCU not watching for tracepoint");	\
 		}							\
-		return static_branch_unlikely(&__tracepoint_##name.key);\
+		return __trace_##name##_enabled();			\
 	}
 
 #define __DECLARE_TRACE(name, proto, args, cond, data_proto)			\
@@ -457,6 +462,11 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
 	{								\
 	}								\
 	static inline bool						\
+	__trace_##name##_enabled(void)					\
+	{								\
+		return false;						\
+	}								\
+	static inline bool						\
 	trace_##name##_enabled(void)					\
 	{								\
 		return false;						\
kernel/trace/trace_preemptirq.c +1 -1
index 0c42b15c3800..b63e3558948f 100644
@@ -30,7 +30,7 @@
 #else
 #define trace(point, args)					\
 	do {							\
-		if (trace_##point##_enabled()) {		\
+		if (__trace_##point##_enabled()) {		\
 			bool exit_rcu = false;			\
 			if (in_nmi())				\
 				break;				\
#9 lore raw

PATCH 5/15 tracing: Remove local variable for argument detection from trace_printk()

In reply to Steven Rostedt

From: Qian-Yu Lin <[email protected]>

The trace_printk() macro uses a local variable _______STR to detect whether variadic arguments are present. This name can shadow outer variables.

Replace the local variable with sizeof applied directly to the stringified arguments:

if (sizeof __stringify((__VA_ARGS__)) > 3)

This eliminates the shadowing risk entirely without introducing any additional includes or local variables.

Verified with objdump on samples/trace_printk that all four cases branch correctly: __trace_bputs, __trace_puts, __trace_bprintk, and __trace_printk.

---
 include/linux/trace_printk.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
include/linux/trace_printk.h +1 -2
index 2670ec7f4262..3d54f440dccf 100644
@@ -86,8 +86,7 @@ do {									\
 
 #define trace_printk(fmt, ...)				\
 do {							\
-	char _______STR[] = __stringify((__VA_ARGS__));	\
-	if (sizeof(_______STR) > 3)			\
+	if (sizeof __stringify((__VA_ARGS__)) > 3)		\
 		do_trace_printk(fmt, ##__VA_ARGS__);	\
 	else						\
 		trace_puts(fmt);			\
Signature · 1 line
2.53.0
#10 lore raw

PATCH 6/15 tracing: Switch trace_recursion_record.c code over to use guard()

In reply to Steven Rostedt

From: Yash Suthar <[email protected]>

Switch mutex_lock()/mutex_unlock() to guard(). also drop the ret local variable and return directly.

---
 kernel/trace/trace_recursion_record.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)
kernel/trace/trace_recursion_record.c +3 -5
index 784fe1fbb866..bac4bc844ccd 100644
@@ -180,9 +180,8 @@ static const struct seq_operations recursed_function_seq_ops = {
 
 static int recursed_function_open(struct inode *inode, struct file *file)
 {
-	int ret = 0;
+	guard(mutex)(&recursed_function_lock);
 
-	mutex_lock(&recursed_function_lock);
 	/* If this file was opened for write, then erase contents */
 	if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) {
 		/* disable updating records */
@@ -194,10 +193,9 @@ static int recursed_function_open(struct inode *inode, struct file *file)
 		atomic_set(&nr_records, 0);
 	}
 	if (file->f_mode & FMODE_READ)
-		ret = seq_open(file, &recursed_function_seq_ops);
-	mutex_unlock(&recursed_function_lock);
+		return seq_open(file, &recursed_function_seq_ops);
 
-	return ret;
+	return 0;
 }
 
 static ssize_t recursed_function_write(struct file *file,
Signature · 1 line
2.53.0
#11 lore raw

PATCH 7/15 tracefs: Fix typo in a comment of eventfs_callback() kerneldoc

In reply to Steven Rostedt

From: Martin Kaiser <[email protected]>

Fix a typo "evetnfs files" to "eventfs files" in a comment.

---
 include/linux/tracefs.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
include/linux/tracefs.h +1 -1
index d03f74658716..bc354d340046 100644
@@ -30,7 +30,7 @@ struct eventfs_file;
  * @data: data to pass to the created file ops
  * @fops: the file operations of the created file
  *
- * The evetnfs files are dynamically created. The struct eventfs_entry array
+ * The eventfs files are dynamically created. The struct eventfs_entry array
  * is passed to eventfs_create_dir() or eventfs_create_events_dir() that will
  * be used to create the files within those directories. When a lookup
  * or access to a file within the directory is made, the struct eventfs_entry
Signature · 1 line
2.53.0
#12 lore raw

PATCH 8/15 cpufreq: amd-pstate: Use trace_call__##name() at guarded tracepoint call site

In reply to Steven Rostedt

From: Vineeth Pillai <[email protected]>

Replace trace_foo() with the new trace_call__foo() at sites already guarded by trace_foo_enabled(), avoiding a redundant static_branch_unlikely() re-evaluation inside the tracepoint. trace_call__foo() calls the tracepoint callbacks directly without utilizing the static branch again.

---
 drivers/cpufreq/amd-pstate.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/cpufreq/amd-pstate.c +2 -1
index 453084c67327..4722de25149b 100644
@@ -368,7 +368,8 @@ static int amd_pstate_set_floor_perf(struct cpufreq_policy *policy, u8 perf)
 
 out_trace:
 	if (trace_amd_pstate_cppc_req2_enabled())
-		trace_amd_pstate_cppc_req2(cpudata->cpu, perf, changed, ret);
+		trace_call__amd_pstate_cppc_req2(cpudata->cpu, perf, changed,
+						 ret);
 	return ret;
 }
 
Signature · 1 line
2.53.0
#13 lore raw

PATCH 9/15 HID: Use trace_call__##name() at guarded tracepoint call sites

In reply to Steven Rostedt

From: Vineeth Pillai <[email protected]>

Replace trace_foo() with the new trace_call__foo() at sites already guarded by trace_foo_enabled(), avoiding a redundant static_branch_unlikely() re-evaluation inside the tracepoint. trace_call__foo() calls the tracepoint callbacks directly without utilizing the static branch again.

Original v2 series:
https://lore.kernel.org/linux-trace-kernel/[email protected]/

Parts of the original v2 series have already been merged in mainline. This patch is being reposted as a follow-up cleanup for the remaining unmerged pieces.

---
 drivers/hid/intel-ish-hid/ipc/pci-ish.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hid/intel-ish-hid/ipc/pci-ish.c +1 -1
index ed3405c05e73..8d36ae96a3ee 100644
@@ -110,7 +110,7 @@ void ish_event_tracer(struct ishtp_device *dev, const char *format, ...)
 		vsnprintf(tmp_buf, sizeof(tmp_buf), format, args);
 		va_end(args);
 
-		trace_ishtp_dump(tmp_buf);
+		trace_call__ishtp_dump(tmp_buf);
 	}
 }
 
Signature · 1 line
2.53.0
#14 lore raw

PATCH 10/15 tracing: Allow perf to read synthetic events

In reply to Steven Rostedt

From: Steven Rostedt <[email protected]>

Currently, perf can not enable synthetic events. When it does, it either causes a warning in the kernel or errors with "no such device".

Add the necessary code to allow perf to also attach to synthetic events.

---
 kernel/trace/trace_events_synth.c | 121 +++++++++++++++++++++++-------
 1 file changed, 94 insertions(+), 27 deletions(-)
kernel/trace/trace_events_synth.c +94 -27
index 39ac4eba0702..e6871230bde9 100644
@@ -499,28 +499,19 @@ static unsigned int trace_stack(struct synth_trace_event *entry,
 	return len;
 }
 
-static void trace_event_raw_event_synth(void *__data,
-					u64 *var_ref_vals,
-					unsigned int *var_ref_idx)
+static __always_inline int get_field_size(struct synth_event *event,
+					  u64 *var_ref_vals,
+					  unsigned int *var_ref_idx)
 {
-	unsigned int i, n_u64, val_idx, len, data_size = 0;
-	struct trace_event_file *trace_file = __data;
-	struct synth_trace_event *entry;
-	struct trace_event_buffer fbuffer;
-	struct trace_buffer *buffer;
-	struct synth_event *event;
-	int fields_size = 0;
-
-	event = trace_file->event_call->data;
-
-	if (trace_trigger_soft_disabled(trace_file))
-		return;
+	int fields_size;
 
 	fields_size = event->n_u64 * sizeof(u64);
 
-	for (i = 0; i < event->n_dynamic_fields; i++) {
+	for (int i = 0; i < event->n_dynamic_fields; i++) {
 		unsigned int field_pos = event->dynamic_fields[i]->field_pos;
 		char *str_val;
+		int val_idx;
+		int len;
 
 		val_idx = var_ref_idx[field_pos];
 		str_val = (char *)(long)var_ref_vals[val_idx];
@@ -535,18 +526,18 @@ static void trace_event_raw_event_synth(void *__data,
 
 		fields_size += len;
 	}
+	return fields_size;
+}
 
-	/*
-	 * Avoid ring buffer recursion detection, as this event
-	 * is being performed within another event.
-	 */
-	buffer = trace_file->tr->array_buffer.buffer;
-	guard(ring_buffer_nest)(buffer);
-
-	entry = trace_event_buffer_reserve(&fbuffer, trace_file,
-					   sizeof(*entry) + fields_size);
-	if (!entry)
-		return;
+static __always_inline void write_synth_entry(struct synth_event *event,
+					      struct synth_trace_event *entry,
+					      u64 *var_ref_vals,
+					      unsigned int *var_ref_idx)
+{
+	int data_size = 0;
+	int i, n_u64;
+	int val_idx;
+	int len;
 
 	for (i = 0, n_u64 = 0; i < event->n_fields; i++) {
 		val_idx = var_ref_idx[i];
@@ -587,10 +578,83 @@ static void trace_event_raw_event_synth(void *__data,
 			n_u64++;
 		}
 	}
+}
+
+static void trace_event_raw_event_synth(void *__data,
+					u64 *var_ref_vals,
+					unsigned int *var_ref_idx)
+{
+	struct trace_event_file *trace_file = __data;
+	struct synth_trace_event *entry;
+	struct trace_event_buffer fbuffer;
+	struct trace_buffer *buffer;
+	struct synth_event *event;
+	int fields_size;
+
+	event = trace_file->event_call->data;
+
+	if (trace_trigger_soft_disabled(trace_file))
+		return;
+
+	fields_size = get_field_size(event, var_ref_vals, var_ref_idx);
+
+	/*
+	 * Avoid ring buffer recursion detection, as this event
+	 * is being performed within another event.
+	 */
+	buffer = trace_file->tr->array_buffer.buffer;
+	guard(ring_buffer_nest)(buffer);
+
+	entry = trace_event_buffer_reserve(&fbuffer, trace_file,
+					   sizeof(*entry) + fields_size);
+	if (!entry)
+		return;
+
+	write_synth_entry(event, entry, var_ref_vals, var_ref_idx);
 
 	trace_event_buffer_commit(&fbuffer);
 }
 
+#ifdef CONFIG_PERF_EVENTS
+static void perf_event_raw_event_synth(void *__data,
+				       u64 *var_ref_vals,
+				       unsigned int *var_ref_idx)
+{
+	struct trace_event_call *call = __data;
+	struct synth_trace_event *entry;
+	struct hlist_head *perf_head;
+	struct synth_event *event;
+	struct pt_regs *regs;
+	int fields_size;
+	size_t size;
+	int context;
+
+	event = call->data;
+
+	perf_head = this_cpu_ptr(call->perf_events);
+
+	if (!perf_head || hlist_empty(perf_head))
+		return;
+
+	fields_size = get_field_size(event, var_ref_vals, var_ref_idx);
+
+	size = ALIGN(sizeof(*entry) + fields_size, 8);
+
+	entry = perf_trace_buf_alloc(size, &regs, &context);
+
+	if (unlikely(!entry))
+		return;
+
+	write_synth_entry(event, entry, var_ref_vals, var_ref_idx);
+
+	perf_fetch_caller_regs(regs);
+
+	perf_trace_buf_submit(entry, size, context,
+			      call->event.type, 1, regs,
+			      perf_head, NULL);
+}
+#endif
+
 static void free_synth_event_print_fmt(struct trace_event_call *call)
 {
 	if (call) {
@@ -917,6 +981,9 @@ static int register_synth_event(struct synth_event *event)
 	call->flags = TRACE_EVENT_FL_TRACEPOINT;
 	call->class->reg = synth_event_reg;
 	call->class->probe = trace_event_raw_event_synth;
+#ifdef CONFIG_PERF_EVENTS
+	call->class->perf_probe = perf_event_raw_event_synth;
+#endif
 	call->data = event;
 	call->tp = event->tp;
 
Signature · 1 line
2.53.0
#15 lore raw

Re: [for-next][PATCH 10/15] tracing: Allow perf to read synthetic events

Quoted 7 lines · Steven Rostedt

From: Steven Rostedt <[email protected]>

Currently, perf can not enable synthetic events. When it does, it either causes a warning in the kernel or errors with "no such device".

Add the necessary code to allow perf to also attach to synthetic events.

Thanks so much for doing this work! I hoped to spend some time testing it, but there's never enough time. For the synthetic event I was wondering what values end up in the perf sample like 'period'? I can imagine this being the case and that, if you are doing something like a futex wait duration, having to interpret the raw data rather than just getting aggregation for free in perf report via the period. That's not wrong but I was just curious.

Thanks again,
Ian

Quoted 181 lines
---
 kernel/trace/trace_events_synth.c | 121 +++++++++++++++++++++++-------
 1 file changed, 94 insertions(+), 27 deletions(-)
kernel/trace/trace_events_synth.c +94 -28
index 39ac4eba0702..e6871230bde9 100644
@@ -499,28 +499,19 @@ static unsigned int trace_stack(struct synth_trace_event *entry,
        return len;
 }
 
-static void trace_event_raw_event_synth(void *__data,
-                                       u64 *var_ref_vals,
-                                       unsigned int *var_ref_idx)
+static __always_inline int get_field_size(struct synth_event *event,
+                                         u64 *var_ref_vals,
+                                         unsigned int *var_ref_idx)
 {
-       unsigned int i, n_u64, val_idx, len, data_size = 0;
-       struct trace_event_file *trace_file = __data;
-       struct synth_trace_event *entry;
-       struct trace_event_buffer fbuffer;
-       struct trace_buffer *buffer;
-       struct synth_event *event;
-       int fields_size = 0;
-
-       event = trace_file->event_call->data;
-
-       if (trace_trigger_soft_disabled(trace_file))
-               return;
+       int fields_size;
 
        fields_size = event->n_u64 * sizeof(u64);
 
-       for (i = 0; i < event->n_dynamic_fields; i++) {
+       for (int i = 0; i < event->n_dynamic_fields; i++) {
                unsigned int field_pos = event->dynamic_fields[i]->field_pos;
                char *str_val;
+               int val_idx;
+               int len;
 
                val_idx = var_ref_idx[field_pos];
                str_val = (char *)(long)var_ref_vals[val_idx];
@@ -535,18 +526,18 @@ static void trace_event_raw_event_synth(void *__data,
 
                fields_size += len;
        }
+       return fields_size;
+}
 
-       /*
-        * Avoid ring buffer recursion detection, as this event
-        * is being performed within another event.
-        */
-       buffer = trace_file->tr->array_buffer.buffer;
-       guard(ring_buffer_nest)(buffer);
-
-       entry = trace_event_buffer_reserve(&fbuffer, trace_file,
-                                          sizeof(*entry) + fields_size);
-       if (!entry)
-               return;
+static __always_inline void write_synth_entry(struct synth_event *event,
+                                             struct synth_trace_event *entry,
+                                             u64 *var_ref_vals,
+                                             unsigned int *var_ref_idx)
+{
+       int data_size = 0;
+       int i, n_u64;
+       int val_idx;
+       int len;
 
        for (i = 0, n_u64 = 0; i < event->n_fields; i++) {
                val_idx = var_ref_idx[i];
@@ -587,10 +578,83 @@ static void trace_event_raw_event_synth(void *__data,
                        n_u64++;
                }
        }
+}
+
+static void trace_event_raw_event_synth(void *__data,
+                                       u64 *var_ref_vals,
+                                       unsigned int *var_ref_idx)
+{
+       struct trace_event_file *trace_file = __data;
+       struct synth_trace_event *entry;
+       struct trace_event_buffer fbuffer;
+       struct trace_buffer *buffer;
+       struct synth_event *event;
+       int fields_size;
+
+       event = trace_file->event_call->data;
+
+       if (trace_trigger_soft_disabled(trace_file))
+               return;
+
+       fields_size = get_field_size(event, var_ref_vals, var_ref_idx);
+
+       /*
+        * Avoid ring buffer recursion detection, as this event
+        * is being performed within another event.
+        */
+       buffer = trace_file->tr->array_buffer.buffer;
+       guard(ring_buffer_nest)(buffer);
+
+       entry = trace_event_buffer_reserve(&fbuffer, trace_file,
+                                          sizeof(*entry) + fields_size);
+       if (!entry)
+               return;
+
+       write_synth_entry(event, entry, var_ref_vals, var_ref_idx);
 
        trace_event_buffer_commit(&fbuffer);
 }
 
+#ifdef CONFIG_PERF_EVENTS
+static void perf_event_raw_event_synth(void *__data,
+                                      u64 *var_ref_vals,
+                                      unsigned int *var_ref_idx)
+{
+       struct trace_event_call *call = __data;
+       struct synth_trace_event *entry;
+       struct hlist_head *perf_head;
+       struct synth_event *event;
+       struct pt_regs *regs;
+       int fields_size;
+       size_t size;
+       int context;
+
+       event = call->data;
+
+       perf_head = this_cpu_ptr(call->perf_events);
+
+       if (!perf_head || hlist_empty(perf_head))
+               return;
+
+       fields_size = get_field_size(event, var_ref_vals, var_ref_idx);
+
+       size = ALIGN(sizeof(*entry) + fields_size, 8);
+
+       entry = perf_trace_buf_alloc(size, &regs, &context);
+
+       if (unlikely(!entry))
+               return;
+
+       write_synth_entry(event, entry, var_ref_vals, var_ref_idx);
+
+       perf_fetch_caller_regs(regs);
+
+       perf_trace_buf_submit(entry, size, context,
+                             call->event.type, 1, regs,
+                             perf_head, NULL);
+}
+#endif
+
 static void free_synth_event_print_fmt(struct trace_event_call *call)
 {
        if (call) {
@@ -917,6 +981,9 @@ static int register_synth_event(struct synth_event *event)
        call->flags = TRACE_EVENT_FL_TRACEPOINT;
        call->class->reg = synth_event_reg;
        call->class->probe = trace_event_raw_event_synth;
+#ifdef CONFIG_PERF_EVENTS
+       call->class->perf_probe = perf_event_raw_event_synth;
+#endif
        call->data = event;
        call->tp = event->tp;
 
--

2.53.0

#16 lore raw

Re: [for-next][PATCH 10/15] tracing: Allow perf to read synthetic events

Quoted 11 lines · On Fri, 22 May 2026 08:19:36 -0700 Ian Rogers <[email protected]> wrote:
Quoted 7 lines · Steven Rostedt

From: Steven Rostedt <[email protected]>

Currently, perf can not enable synthetic events. When it does, it either causes a warning in the kernel or errors with "no such device".

Add the necessary code to allow perf to also attach to synthetic events.

Thanks so much for doing this work! I hoped to spend some time testing it, but there's never enough time. For the synthetic event I was

I totally understand not having time. Heck, I'm currently unemployed and I'm still having a hard time finding time!

Quoted 1 line

wondering what values end up in the perf sample like 'period'? I can

You mean to poll on the event?

Quoted 4 lines

imagine this being the case and that, if you are doing something like a futex wait duration, having to interpret the raw data rather than just getting aggregation for free in perf report via the period. That's not wrong but I was just curious.

I guess I'm not quite sure what you mean by "the period". But then again, I don't use perf that much.

-- Steve

#17 lore raw

Re: [for-next][PATCH 10/15] tracing: Allow perf to read synthetic events

Hello,

Quoted 10 lines · Steven Rostedt
Quoted 7 lines · On Fri, 22 May 2026 08:19:36 -0700 Ian Rogers <[email protected]> wrote:
Quoted 6 lines · Steven Rostedt

From: Steven Rostedt <[email protected]>

Currently, perf can not enable synthetic events. When it does, it either causes a warning in the kernel or errors with "no such device".

Quoted 7 lines
Quoted 4 lines
Quoted 1 line

Add the necessary code to allow perf to also attach to synthetic events.

Thanks so much for doing this work! I hoped to spend some time testing it, but there's never enough time. For the synthetic event I was

I totally understand not having time. Heck, I'm currently unemployed and I'm still having a hard time finding time!

:)

Quoted 5 lines
Quoted 2 lines

wondering what values end up in the perf sample like 'period'? I can

You mean to poll on the event?

Quoted 7 lines
Quoted 4 lines

imagine this being the case and that, if you are doing something like a futex wait duration, having to interpret the raw data rather than just getting aggregation for free in perf report via the period. That's not wrong but I was just curious.

I guess I'm not quite sure what you mean by "the period". But then again, I don't use perf that much.

Oh, it's about the value of the event.

IIUC, the period of any tracepoints is the number of times it hits. Using a field of tracepoint instead needs interpretation of the event.

Thanks,
Namhyung

#18 lore raw

PATCH 11/15 tracing/branch: Use pr_warn() instead of printk(KERN_WARNING)

In reply to Steven Rostedt

From: Yu Peng <[email protected]>

Use pr_warn() instead of printk(KERN_WARNING ...) for the branch tracer warning messages.

Keep the message text unchanged. The change only removes the open-coded log level from these warnings.

---
 kernel/trace/trace_branch.c | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)
kernel/trace/trace_branch.c +3 -6
index d1564db95a8f..d8e97ad798f0 100644
@@ -181,8 +181,7 @@ __init static int init_branch_tracer(void)
 
 	ret = register_trace_event(&trace_branch_event);
 	if (!ret) {
-		printk(KERN_WARNING "Warning: could not register "
-				    "branch events\n");
+		pr_warn("Warning: could not register branch events\n");
 		return 1;
 	}
 	return register_tracer(&branch_trace);
@@ -374,8 +373,7 @@ __init static int init_annotated_branch_stats(void)
 
 	ret = register_stat_tracer(&annotated_branch_stats);
 	if (ret) {
-		printk(KERN_WARNING "Warning: could not register "
-				    "annotated branches stats\n");
+		pr_warn("Warning: could not register annotated branches stats\n");
 		return ret;
 	}
 	return 0;
@@ -439,8 +437,7 @@ __init static int all_annotated_branch_stats(void)
 
 	ret = register_stat_tracer(&all_branch_stats);
 	if (ret) {
-		printk(KERN_WARNING "Warning: could not register "
-				    "all branches stats\n");
+		pr_warn("Warning: could not register all branches stats\n");
 		return ret;
 	}
 	return 0;
Signature · 1 line
2.53.0
#19 lore raw

PATCH 12/15 tracing: Use krealloc_array() for trace option array growth

In reply to Steven Rostedt

From: Yu Peng <[email protected]>

Use krealloc_array() when growing tr->topts instead of open-coding the size calculation in krealloc().

This makes the resize path use the helper intended for array allocations and avoids manual multiplication of the element count and element size.

---
 kernel/trace/trace.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/trace/trace.c +2 -2
index 6eb4d3097a4d..aec3f31ed027 100644
@@ -7928,8 +7928,8 @@ create_trace_option_files(struct trace_array *tr, struct tracer *tracer,
 	if (!topts)
 		return 0;
 
-	tr_topts = krealloc(tr->topts, sizeof(*tr->topts) * (tr->nr_topts + 1),
-			    GFP_KERNEL);
+	tr_topts = krealloc_array(tr->topts, tr->nr_topts + 1, sizeof(*tr->topts),
+				  GFP_KERNEL);
 	if (!tr_topts) {
 		kfree(topts);
 		return -ENOMEM;
Signature · 1 line
2.53.0
#20 lore raw

PATCH 13/15 tracing: Fix README path for synthetic_events

In reply to Steven Rostedt

From: Ao Sun <[email protected]>

The events/ prefix should be removed, since synthetic_events is now directly under the tracing root directory.

---
 kernel/trace/trace.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/trace.c +1 -1
index aec3f31ed027..4218c174460b 100644
@@ -4474,7 +4474,7 @@ static const char readme_msg[] =
 	"\t        snapshot()                           - snapshot the trace buffer\n\n"
 #endif
 #ifdef CONFIG_SYNTH_EVENTS
-	"  events/synthetic_events\t- Create/append/remove/show synthetic events\n"
+	"  synthetic_events\t- Create/append/remove/show synthetic events\n"
 	"\t  Write into this file to define/undefine new synthetic events.\n"
 	"\t     example: echo 'myevent u64 lat; char name[]; long[] stack' >> synthetic_events\n"
 #endif
Signature · 1 line
2.53.0
#21 lore raw

PATCH 14/15 tracing: Simplify pages allocation for tracing_map logic

In reply to Steven Rostedt

From: Rosen Penev <[email protected]>

Change to a flexible array member to allocate together with the array struct.

Simplifies code slightly by removing no longer correct null checks for pages and removing kfrees.

---
 kernel/trace/tracing_map.c | 30 +++++++++++-------------------
 kernel/trace/tracing_map.h |  2 +-
 2 files changed, 12 insertions(+), 20 deletions(-)
kernel/trace/tracing_map.c +11 -19
index 0dd7927df22a..d7922f40dbe2 100644
@@ -288,9 +288,6 @@ static void tracing_map_array_clear(struct tracing_map_array *a)
 {
 	unsigned int i;
 
-	if (!a->pages)
-		return;
-
 	for (i = 0; i < a->n_pages; i++)
 		memset(a->pages[i], 0, PAGE_SIZE);
 }
@@ -302,9 +299,6 @@ static void tracing_map_array_free(struct tracing_map_array *a)
 	if (!a)
 		return;
 
-	if (!a->pages)
-		goto free;
-
 	for (i = 0; i < a->n_pages; i++) {
 		if (!a->pages[i])
 			break;
@@ -312,9 +306,6 @@ static void tracing_map_array_free(struct tracing_map_array *a)
 		free_page((unsigned long)a->pages[i]);
 	}
 
-	kfree(a->pages);
-
- free:
 	kfree(a);
 }
 
@@ -322,24 +313,25 @@ static struct tracing_map_array *tracing_map_array_alloc(unsigned int n_elts,
 						  unsigned int entry_size)
 {
 	struct tracing_map_array *a;
+	unsigned int entry_size_shift;
+	unsigned int entries_per_page;
+	unsigned int n_pages;
 	unsigned int i;
 
-	a = kzalloc_obj(*a);
+	entry_size_shift = fls(roundup_pow_of_two(entry_size) - 1);
+	entries_per_page = PAGE_SIZE / (1 << entry_size_shift);
+	n_pages = max(1, n_elts / entries_per_page);
+
+	a = kzalloc_flex(*a, pages, n_pages);
 	if (!a)
 		return NULL;
 
-	a->entry_size_shift = fls(roundup_pow_of_two(entry_size) - 1);
-	a->entries_per_page = PAGE_SIZE / (1 << a->entry_size_shift);
-	a->n_pages = n_elts / a->entries_per_page;
-	if (!a->n_pages)
-		a->n_pages = 1;
+	a->entry_size_shift = entry_size_shift;
+	a->entries_per_page = entries_per_page;
+	a->n_pages = n_pages;
 	a->entry_shift = fls(a->entries_per_page) - 1;
 	a->entry_mask = (1 << a->entry_shift) - 1;
 
-	a->pages = kcalloc(a->n_pages, sizeof(void *), GFP_KERNEL);
-	if (!a->pages)
-		goto free;
-
 	for (i = 0; i < a->n_pages; i++) {
 		a->pages[i] = (void *)get_zeroed_page(GFP_KERNEL);
 		if (!a->pages[i])
kernel/trace/tracing_map.h +1 -1
index 99c37eeebc16..18a02959d77b 100644
@@ -167,7 +167,7 @@ struct tracing_map_array {
 	unsigned int entry_shift;
 	unsigned int entry_mask;
 	unsigned int n_pages;
-	void **pages;
+	void *pages[] __counted_by(n_pages);
 };
 
 #define TRACING_MAP_ARRAY_ELT(array, idx)				\
Signature · 1 line
2.53.0
#22 lore raw

PATCH 15/15 tracing: Move trace_iterator_increment() into trace_find_next_entry_inc()

In reply to Steven Rostedt

From: Steven Rostedt <[email protected]>

trace_iterator_increment() is only called from trace_find_next_entry_inc(). It's a small enough function that really doesn't need to be separated.

Move the code from trace_iterator_increment() into trace_find_next_entry_inc() and remove trace_iterator_increment().

---
 kernel/trace/trace.c | 19 ++++++++-----------
 1 file changed, 8 insertions(+), 11 deletions(-)
kernel/trace/trace.c +8 -11
index 4218c174460b..ae527c419508 100644
@@ -2338,15 +2338,6 @@ void trace_last_func_repeats(struct trace_array *tr,
 	__buffer_unlock_commit(buffer, event);
 }
 
-static void trace_iterator_increment(struct trace_iterator *iter)
-{
-	struct ring_buffer_iter *buf_iter = trace_buffer_iter(iter, iter->cpu);
-
-	iter->idx++;
-	if (buf_iter)
-		ring_buffer_iter_advance(buf_iter);
-}
-
 static struct trace_entry *
 peek_next_entry(struct trace_iterator *iter, int cpu, u64 *ts,
 		unsigned long *lost_events)
@@ -2676,11 +2667,17 @@ struct trace_entry *trace_find_next_entry(struct trace_iterator *iter,
 /* Find the next real entry, and increment the iterator to the next entry */
 void *trace_find_next_entry_inc(struct trace_iterator *iter)
 {
+	struct ring_buffer_iter *buf_iter;
+
 	iter->ent = __find_next_entry(iter, &iter->cpu,
 				      &iter->lost_events, &iter->ts);
 
-	if (iter->ent)
-		trace_iterator_increment(iter);
+	if (iter->ent) {
+		iter->idx++;
+		buf_iter = trace_buffer_iter(iter, iter->cpu);
+		if (buf_iter)
+			ring_buffer_iter_advance(buf_iter);
+	}
 
 	return iter->ent ? iter : NULL;
 }
Signature · 1 line
2.53.0