Linux Trace Kernel
 help / color / mirror / Atom feed
* Re: [PATCH] tracing: Have hist_debug show what function a field uses
From: Masami Hiramatsu @ 2026-01-28  8:20 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: LKML, Linux Trace Kernel, Masami Hiramatsu, Mathieu Desnoyers,
	Tom Zanussi
In-Reply-To: <20260122203822.58df4d80@gandalf.local.home>

On Thu, 22 Jan 2026 20:38:22 -0500
Steven Rostedt <rostedt@goodmis.org> wrote:

> From: Steven Rostedt <rostedt@goodmis.org>
> 
> When CONFIG_HIST_TRIGGERS_DEBUG is enabled, each trace event has a
> "hist_debug" file that explains the histogram internal data. This is very
> useful for debugging histograms.
> 
> One bit of data that was missing from this file was what function a
> histogram field uses to process its data. The hist_field structure now has
> a fn_num that is used by a switch statement in hist_fn_call() to call a
> function directly (to avoid spectre mitigations).
> 
> Instead of displaying that number, create a string array that maps to the
> histogram function enums so that the function for a field may be
> displayed:
> 
>  ~# cat /sys/kernel/tracing/events/sched/sched_switch/hist_debug
> [..]
> hist_data: 0000000043d62762
> 
>   n_vals: 2
>   n_keys: 1
>   n_fields: 3
> 
>   val fields:
> 
>     hist_data->fields[0]:
>       flags:
>         VAL: HIST_FIELD_FL_HITCOUNT
>       type: u64
>       size: 8
>       is_signed: 0
>       function: hist_field_counter()
> 
>     hist_data->fields[1]:
>       flags:
>         HIST_FIELD_FL_VAR
>       var.name: __arg_3921_2
>       var.idx (into tracing_map_elt.vars[]): 0
>       type: unsigned long[]
>       size: 128
>       is_signed: 0
>       function: hist_field_nop()
> 
>   key fields:
> 
>     hist_data->fields[2]:
>       flags:
>         HIST_FIELD_FL_KEY
>       ftrace_event_field name: prev_pid
>       type: pid_t
>       size: 8
>       is_signed: 1
>       function: hist_field_s32()
> 
> The "function:" field above is added.

Looks good to me.

Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>

Thanks,


> 
> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
> ---
>  kernel/trace/trace_events_hist.c | 75 +++++++++++++++++++-------------
>  1 file changed, 44 insertions(+), 31 deletions(-)
> 
> diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
> index 4a7f945e368d..24441b30a1a4 100644
> --- a/kernel/trace/trace_events_hist.c
> +++ b/kernel/trace/trace_events_hist.c
> @@ -105,38 +105,44 @@ enum field_op_id {
>  	FIELD_OP_MULT,
>  };
>  
> +#define FIELD_FUNCS					\
> +	C(NOP,			"nop"),			\
> +	C(VAR_REF,		"var_ref"),		\
> +	C(COUNTER,		"counter"),		\
> +	C(CONST,		"const"),		\
> +	C(LOG2,			"log2"),		\
> +	C(BUCKET,		"bucket"),		\
> +	C(TIMESTAMP,		"timestamp"),		\
> +	C(CPU,			"cpu"),			\
> +	C(COMM,			"comm"),		\
> +	C(STRING,		"string"),		\
> +	C(DYNSTRING,		"dynstring"),		\
> +	C(RELDYNSTRING,		"reldynstring"),	\
> +	C(PSTRING,		"pstring"),		\
> +	C(S64,			"s64"),			\
> +	C(U64,			"u64"),			\
> +	C(S32,			"s32"),			\
> +	C(U32,			"u32"),			\
> +	C(S16,			"s16"),			\
> +	C(U16,			"u16"),			\
> +	C(S8,			"s8"),			\
> +	C(U8,			"u8"),			\
> +	C(UMINUS,		"uminus"),		\
> +	C(MINUS,		"minus"),		\
> +	C(PLUS,			"plus"),		\
> +	C(DIV,			"div"),			\
> +	C(MULT,			"mult"),		\
> +	C(DIV_POWER2,		"div_power2"),		\
> +	C(DIV_NOT_POWER2,	"div_not_power2"),	\
> +	C(DIV_MULT_SHIFT,	"div_mult_shift"),	\
> +	C(EXECNAME,		"execname"),		\
> +	C(STACK,		"stack"),
> +
> +#undef C
> +#define C(a, b)		HIST_FIELD_FN_##a
> +
>  enum hist_field_fn {
> -	HIST_FIELD_FN_NOP,
> -	HIST_FIELD_FN_VAR_REF,
> -	HIST_FIELD_FN_COUNTER,
> -	HIST_FIELD_FN_CONST,
> -	HIST_FIELD_FN_LOG2,
> -	HIST_FIELD_FN_BUCKET,
> -	HIST_FIELD_FN_TIMESTAMP,
> -	HIST_FIELD_FN_CPU,
> -	HIST_FIELD_FN_COMM,
> -	HIST_FIELD_FN_STRING,
> -	HIST_FIELD_FN_DYNSTRING,
> -	HIST_FIELD_FN_RELDYNSTRING,
> -	HIST_FIELD_FN_PSTRING,
> -	HIST_FIELD_FN_S64,
> -	HIST_FIELD_FN_U64,
> -	HIST_FIELD_FN_S32,
> -	HIST_FIELD_FN_U32,
> -	HIST_FIELD_FN_S16,
> -	HIST_FIELD_FN_U16,
> -	HIST_FIELD_FN_S8,
> -	HIST_FIELD_FN_U8,
> -	HIST_FIELD_FN_UMINUS,
> -	HIST_FIELD_FN_MINUS,
> -	HIST_FIELD_FN_PLUS,
> -	HIST_FIELD_FN_DIV,
> -	HIST_FIELD_FN_MULT,
> -	HIST_FIELD_FN_DIV_POWER2,
> -	HIST_FIELD_FN_DIV_NOT_POWER2,
> -	HIST_FIELD_FN_DIV_MULT_SHIFT,
> -	HIST_FIELD_FN_EXECNAME,
> -	HIST_FIELD_FN_STACK,
> +	FIELD_FUNCS
>  };
>  
>  /*
> @@ -5845,6 +5851,12 @@ const struct file_operations event_hist_fops = {
>  };
>  
>  #ifdef CONFIG_HIST_TRIGGERS_DEBUG
> +
> +#undef C
> +#define C(a, b)		b
> +
> +static const char * const field_funcs[] = { FIELD_FUNCS };
> +
>  static void hist_field_debug_show_flags(struct seq_file *m,
>  					unsigned long flags)
>  {
> @@ -5909,6 +5921,7 @@ static int hist_field_debug_show(struct seq_file *m,
>  	seq_printf(m, "      type: %s\n", field->type);
>  	seq_printf(m, "      size: %u\n", field->size);
>  	seq_printf(m, "      is_signed: %u\n", field->is_signed);
> +	seq_printf(m, "      function: hist_field_%s()\n", field_funcs[field->fn_num]);
>  
>  	return 0;
>  }
> -- 
> 2.51.0
> 


-- 
Masami Hiramatsu (Google) <mhiramat@kernel.org>

^ permalink raw reply

* Re: [PATCH] tracing: trace_mmap.h: fix a kernel-doc warning
From: Masami Hiramatsu @ 2026-01-28  7:54 UTC (permalink / raw)
  To: Randy Dunlap
  Cc: linux-kernel, Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
	linux-trace-kernel
In-Reply-To: <20260128062522.403456-1-rdunlap@infradead.org>

On Tue, 27 Jan 2026 22:25:22 -0800
Randy Dunlap <rdunlap@infradead.org> wrote:

> Add a description of struct reader to resolve a kernel-doc warning:
> 
> Warning: include/uapi/linux/trace_mmap.h:43 struct member 'reader' not described in 'trace_buffer_meta'
> 

Looks good to me.

Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>

Thanks!

> Signed-off-by: Randy Dunlap <rdunlap@infradead.org>
> ---
> Cc: Steven Rostedt <rostedt@goodmis.org>
> Cc: Masami Hiramatsu <mhiramat@kernel.org>
> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
> Cc: linux-trace-kernel@vger.kernel.org
> 
>  include/uapi/linux/trace_mmap.h |    1 +
>  1 file changed, 1 insertion(+)
> 
> --- linux-next-20260126.orig/include/uapi/linux/trace_mmap.h
> +++ linux-next-20260126/include/uapi/linux/trace_mmap.h
> @@ -13,6 +13,7 @@
>   * @reader.lost_events:	Number of events lost at the time of the reader swap.
>   * @reader.id:		subbuf ID of the current reader. ID range [0 : @nr_subbufs - 1]
>   * @reader.read:	Number of bytes read on the reader subbuf.
> + * @reader:		The reader composite info structure
>   * @flags:		Placeholder for now, 0 until new features are supported.
>   * @entries:		Number of entries in the ring-buffer.
>   * @overrun:		Number of entries lost in the ring-buffer.
Masami Hiramatsu (Google) <mhiramat@kernel.org>

-- 
Masami Hiramatsu (Google) <mhiramat@kernel.org>

^ permalink raw reply

* Re: [PATCH v3 2/3] tracing/kprobes: Make setup_boot_kprobe_events() asynchronous
From: Masami Hiramatsu @ 2026-01-28  7:53 UTC (permalink / raw)
  To: Yaxiong Tian
  Cc: rostedt, axboe, mathieu.desnoyers, linux-block, linux-kernel,
	linux-trace-kernel
In-Reply-To: <6ab04276-8897-4d5e-a86c-e656cf1f6f91@kylinos.cn>

On Wed, 28 Jan 2026 15:24:15 +0800
Yaxiong Tian <tianyaxiong@kylinos.cn> wrote:

> 
> 在 2026/1/28 12:49, Masami Hiramatsu (Google) 写道:
> > On Tue, 27 Jan 2026 09:23:12 +0800
> > Yaxiong Tian <tianyaxiong@kylinos.cn> wrote:
> >
> >> During kernel boot, the setup_boot_kprobe_events() function causes
> >> significant delays, increasing overall startup time.
> >>
> >> The root cause is a lock contention chain: its child function
> >> enable_boot_kprobe_events() requires the event_mutex, which is
> >> already held by early_event_add_tracer(). early_event_add_tracer()
> >> itself is blocked waiting for the trace_event_sem  read-write lock,
> >> which is held for an extended period by trace_event_update_all().
> >>
> >> To resolve this, we have moved the execution of
> >> setup_boot_kprobe_events() to the trace_init_wq  workqueue, allowing
> >> it to run asynchronously.
> >>
> >> Signed-off-by: Yaxiong Tian <tianyaxiong@kylinos.cn>
> >> ---
> >>   kernel/trace/trace_kprobe.c | 14 +++++++++++++-
> >>   1 file changed, 13 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
> >> index 9953506370a5..4c6621f02696 100644
> >> --- a/kernel/trace/trace_kprobe.c
> >> +++ b/kernel/trace/trace_kprobe.c
> >> @@ -2031,6 +2031,13 @@ static __init int init_kprobe_trace_early(void)
> >>   }
> >>   core_initcall(init_kprobe_trace_early);
> >>   
> >> +static struct work_struct kprobe_trace_work __initdata;
> >> +
> >> +static void __init kprobe_trace_works_func(struct work_struct *work)
> >> +{
> >> +	setup_boot_kprobe_events();
> >> +}
> >> +
> >>   /* Make a tracefs interface for controlling probe points */
> >>   static __init int init_kprobe_trace(void)
> >>   {
> >> @@ -2048,7 +2055,12 @@ static __init int init_kprobe_trace(void)
> >>   	trace_create_file("kprobe_profile", TRACE_MODE_READ,
> >>   			  NULL, NULL, &kprobe_profile_ops);
> >>   
> >> -	setup_boot_kprobe_events();
> >> +	if (trace_init_wq) {
> >> +		INIT_WORK(&kprobe_trace_work, kprobe_trace_works_func);
> >> +		queue_work(trace_init_wq, &kprobe_trace_work);
> > Hmm, this queue_work is not required if kprobe_boot_events_buf[] is
> > empty. We should check it because most of the time we don't need it.
> Yes, I will improve it in the next version.
> > Also, deferring initialization makes it indeterminate when this
> > tracing will begin.
> Indeed, While most scenarios don't need boot-time tracing, and users 
> prioritize boot speed, we must balance the need for deterministic traces 
> with faster startup.

I just wonder why don't you define kprobe events after boot (e.g.
from init script) instead of kernel cmdline. Using cmdline means
it will be used for tracing kernel boot.

- tracing kernel boot -> use kernel cmdline (synchronous)
- tracing user boot -> use tracefs (asynchronous)

> > For kprobe event use case, I think setup_boot_kprobe_events() should
> > check the kprobe_boot_events_buf is empty at first. But I think Yaxiong
> > use case happens when you are using kprobe events via cmdline, is that
> > correct?
> The issue was identified without enabling kprobe events via the cmdline. 

Interesting. So is it fixed by another patch [1]?

[1] https://lore.kernel.org/all/20260127053848.108473-1-sunliming@linux.dev/

> The core finding is that asynchronous initialization can drastically cut 
> boot time under different workloads. As blocking occurs elsewhere in the 
> tracing infrastructure beyond just kprobe events, adopting async is a 
> broadly applicable strategy for boot time optimization.

Yes, but it is also possible to set it up from user space, because that
user process can work asynchronously.
We can make the ftrace initialization async to accelerate boot time, but
that means it is not useful for tracing kernel boot.

> >
> > I think introducing "async" cmdline option is more preferable.
> 
> Agreed, this works. Users focused on boot speed over early-boot tracing 
> can opt for this parameter to gain a startup performance boost.

Yeah, that is an option. Anyway, basically, users have another option to
setup ftrace after boot user space asynchronously. That is my
recommendation for such use case.

> 
> >
> > BTW, I found that the kprobe events from kernel cmdline will be made
> > after boot-time tracing from bootconfig. Maybe it should be run this
> > earlier timing too.
> 
> Yes. Additionally, this optimization does not conflict with the current 
> patch series at all.
> 
> I'll submit the updated patch for the next version promptly.

OK.

Thank you,

> 
> > Thank you,
> >
> >
> >> +	} else {
> >> +		setup_boot_kprobe_events();
> >> +	}
> >>   
> >>   	return 0;
> >>   }
> >> -- 
> >> 2.25.1
> >>
> >


-- 
Masami Hiramatsu (Google) <mhiramat@kernel.org>

^ permalink raw reply

* Re: [PATCH v3 2/3] tracing/kprobes: Make setup_boot_kprobe_events() asynchronous
From: Yaxiong Tian @ 2026-01-28  7:24 UTC (permalink / raw)
  To: Masami Hiramatsu (Google)
  Cc: rostedt, axboe, mathieu.desnoyers, linux-block, linux-kernel,
	linux-trace-kernel
In-Reply-To: <20260128134936.539782c2112073e55e7a0304@kernel.org>


在 2026/1/28 12:49, Masami Hiramatsu (Google) 写道:
> On Tue, 27 Jan 2026 09:23:12 +0800
> Yaxiong Tian <tianyaxiong@kylinos.cn> wrote:
>
>> During kernel boot, the setup_boot_kprobe_events() function causes
>> significant delays, increasing overall startup time.
>>
>> The root cause is a lock contention chain: its child function
>> enable_boot_kprobe_events() requires the event_mutex, which is
>> already held by early_event_add_tracer(). early_event_add_tracer()
>> itself is blocked waiting for the trace_event_sem  read-write lock,
>> which is held for an extended period by trace_event_update_all().
>>
>> To resolve this, we have moved the execution of
>> setup_boot_kprobe_events() to the trace_init_wq  workqueue, allowing
>> it to run asynchronously.
>>
>> Signed-off-by: Yaxiong Tian <tianyaxiong@kylinos.cn>
>> ---
>>   kernel/trace/trace_kprobe.c | 14 +++++++++++++-
>>   1 file changed, 13 insertions(+), 1 deletion(-)
>>
>> diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
>> index 9953506370a5..4c6621f02696 100644
>> --- a/kernel/trace/trace_kprobe.c
>> +++ b/kernel/trace/trace_kprobe.c
>> @@ -2031,6 +2031,13 @@ static __init int init_kprobe_trace_early(void)
>>   }
>>   core_initcall(init_kprobe_trace_early);
>>   
>> +static struct work_struct kprobe_trace_work __initdata;
>> +
>> +static void __init kprobe_trace_works_func(struct work_struct *work)
>> +{
>> +	setup_boot_kprobe_events();
>> +}
>> +
>>   /* Make a tracefs interface for controlling probe points */
>>   static __init int init_kprobe_trace(void)
>>   {
>> @@ -2048,7 +2055,12 @@ static __init int init_kprobe_trace(void)
>>   	trace_create_file("kprobe_profile", TRACE_MODE_READ,
>>   			  NULL, NULL, &kprobe_profile_ops);
>>   
>> -	setup_boot_kprobe_events();
>> +	if (trace_init_wq) {
>> +		INIT_WORK(&kprobe_trace_work, kprobe_trace_works_func);
>> +		queue_work(trace_init_wq, &kprobe_trace_work);
> Hmm, this queue_work is not required if kprobe_boot_events_buf[] is
> empty. We should check it because most of the time we don't need it.
Yes, I will improve it in the next version.
> Also, deferring initialization makes it indeterminate when this
> tracing will begin.
Indeed, While most scenarios don't need boot-time tracing, and users 
prioritize boot speed, we must balance the need for deterministic traces 
with faster startup.

>
> For kprobe event use case, I think setup_boot_kprobe_events() should
> check the kprobe_boot_events_buf is empty at first. But I think Yaxiong
> use case happens when you are using kprobe events via cmdline, is that
> correct?
The issue was identified without enabling kprobe events via the cmdline. 
The core finding is that asynchronous initialization can drastically cut 
boot time under different workloads. As blocking occurs elsewhere in the 
tracing infrastructure beyond just kprobe events, adopting async is a 
broadly applicable strategy for boot time optimization.
>
> I think introducing "async" cmdline option is more preferable.

Agreed, this works. Users focused on boot speed over early-boot tracing 
can opt for this parameter to gain a startup performance boost.

>
> BTW, I found that the kprobe events from kernel cmdline will be made
> after boot-time tracing from bootconfig. Maybe it should be run this
> earlier timing too.

Yes. Additionally, this optimization does not conflict with the current 
patch series at all.

I'll submit the updated patch for the next version promptly.

> Thank you,
>
>
>> +	} else {
>> +		setup_boot_kprobe_events();
>> +	}
>>   
>>   	return 0;
>>   }
>> -- 
>> 2.25.1
>>
>

^ permalink raw reply

* [PATCH] tracing: trace_mmap.h: fix a kernel-doc warning
From: Randy Dunlap @ 2026-01-28  6:25 UTC (permalink / raw)
  To: linux-kernel
  Cc: Randy Dunlap, Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
	linux-trace-kernel

Add a description of struct reader to resolve a kernel-doc warning:

Warning: include/uapi/linux/trace_mmap.h:43 struct member 'reader' not described in 'trace_buffer_meta'

Signed-off-by: Randy Dunlap <rdunlap@infradead.org>
---
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: linux-trace-kernel@vger.kernel.org

 include/uapi/linux/trace_mmap.h |    1 +
 1 file changed, 1 insertion(+)

--- linux-next-20260126.orig/include/uapi/linux/trace_mmap.h
+++ linux-next-20260126/include/uapi/linux/trace_mmap.h
@@ -13,6 +13,7 @@
  * @reader.lost_events:	Number of events lost at the time of the reader swap.
  * @reader.id:		subbuf ID of the current reader. ID range [0 : @nr_subbufs - 1]
  * @reader.read:	Number of bytes read on the reader subbuf.
+ * @reader:		The reader composite info structure
  * @flags:		Placeholder for now, 0 until new features are supported.
  * @entries:		Number of entries in the ring-buffer.
  * @overrun:		Number of entries lost in the ring-buffer.

^ permalink raw reply

* Re: [PATCH v3 2/3] tracing/kprobes: Make setup_boot_kprobe_events() asynchronous
From: Masami Hiramatsu @ 2026-01-28  4:49 UTC (permalink / raw)
  To: Yaxiong Tian
  Cc: rostedt, axboe, mathieu.desnoyers, linux-block, linux-kernel,
	linux-trace-kernel
In-Reply-To: <20260127012312.84659-1-tianyaxiong@kylinos.cn>

On Tue, 27 Jan 2026 09:23:12 +0800
Yaxiong Tian <tianyaxiong@kylinos.cn> wrote:

> During kernel boot, the setup_boot_kprobe_events() function causes
> significant delays, increasing overall startup time.
> 
> The root cause is a lock contention chain: its child function
> enable_boot_kprobe_events() requires the event_mutex, which is
> already held by early_event_add_tracer(). early_event_add_tracer()
> itself is blocked waiting for the trace_event_sem  read-write lock,
> which is held for an extended period by trace_event_update_all().
> 
> To resolve this, we have moved the execution of
> setup_boot_kprobe_events() to the trace_init_wq  workqueue, allowing
> it to run asynchronously.
> 
> Signed-off-by: Yaxiong Tian <tianyaxiong@kylinos.cn>
> ---
>  kernel/trace/trace_kprobe.c | 14 +++++++++++++-
>  1 file changed, 13 insertions(+), 1 deletion(-)
> 
> diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
> index 9953506370a5..4c6621f02696 100644
> --- a/kernel/trace/trace_kprobe.c
> +++ b/kernel/trace/trace_kprobe.c
> @@ -2031,6 +2031,13 @@ static __init int init_kprobe_trace_early(void)
>  }
>  core_initcall(init_kprobe_trace_early);
>  
> +static struct work_struct kprobe_trace_work __initdata;
> +
> +static void __init kprobe_trace_works_func(struct work_struct *work)
> +{
> +	setup_boot_kprobe_events();
> +}
> +
>  /* Make a tracefs interface for controlling probe points */
>  static __init int init_kprobe_trace(void)
>  {
> @@ -2048,7 +2055,12 @@ static __init int init_kprobe_trace(void)
>  	trace_create_file("kprobe_profile", TRACE_MODE_READ,
>  			  NULL, NULL, &kprobe_profile_ops);
>  
> -	setup_boot_kprobe_events();
> +	if (trace_init_wq) {
> +		INIT_WORK(&kprobe_trace_work, kprobe_trace_works_func);
> +		queue_work(trace_init_wq, &kprobe_trace_work);

Hmm, this queue_work is not required if kprobe_boot_events_buf[] is
empty. We should check it because most of the time we don't need it.
Also, deferring initialization makes it indeterminate when this
tracing will begin.

For kprobe event use case, I think setup_boot_kprobe_events() should
check the kprobe_boot_events_buf is empty at first. But I think Yaxiong
use case happens when you are using kprobe events via cmdline, is that
correct?

I think introducing "async" cmdline option is more preferable.

BTW, I found that the kprobe events from kernel cmdline will be made
after boot-time tracing from bootconfig. Maybe it should be run this
earlier timing too.

Thank you,


> +	} else {
> +		setup_boot_kprobe_events();
> +	}
>  
>  	return 0;
>  }
> -- 
> 2.25.1
> 


-- 
Masami Hiramatsu (Google) <mhiramat@kernel.org>

^ permalink raw reply

* Re: [PATCH v2] tracing: kprobe-event: Return directly when trace kprobes is empty
From: Masami Hiramatsu @ 2026-01-28  2:59 UTC (permalink / raw)
  To: sunliming
  Cc: rostedt, mathieu.desnoyers, linux-kernel, linux-trace-kernel,
	sunliming
In-Reply-To: <20260127053848.108473-1-sunliming@linux.dev>

On Tue, 27 Jan 2026 13:38:48 +0800
sunliming@linux.dev wrote:

> From: sunliming <sunliming@kylinos.cn>
> 
> In enable_boot_kprobe_events(), it returns directly when trace kprobes is
> empty, thereby reducing the function's execution time. This function may
> otherwise wait for the event_mutex lock for tens of milliseconds on certain
> machines, which is unnecessary when trace kprobes is empty.
> 
> Signed-off-by: sunliming <sunliming@kylinos.cn>

Looks good to me. Let me pick it.

Thanks, 


> ---
> v2:
> - wrap the the null check for the dyn_event_list with macro trace_kprobe_list_empty
> ---
>  kernel/trace/trace_kprobe.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
> index 9953506370a5..95f2c42603d5 100644
> --- a/kernel/trace/trace_kprobe.c
> +++ b/kernel/trace/trace_kprobe.c
> @@ -82,6 +82,7 @@ static struct trace_kprobe *to_trace_kprobe(struct dyn_event *ev)
>  #define for_each_trace_kprobe(pos, dpos)	\
>  	for_each_dyn_event(dpos)		\
>  		if (is_trace_kprobe(dpos) && (pos = to_trace_kprobe(dpos)))
> +#define trace_kprobe_list_empty() list_empty(&dyn_event_list)
>  
>  static nokprobe_inline bool trace_kprobe_is_return(struct trace_kprobe *tk)
>  {
> @@ -1982,6 +1983,9 @@ static __init void enable_boot_kprobe_events(void)
>  	struct trace_kprobe *tk;
>  	struct dyn_event *pos;
>  
> +	if (trace_kprobe_list_empty())
> +		return;
> +
>  	guard(mutex)(&event_mutex);
>  	for_each_trace_kprobe(tk, pos) {
>  		list_for_each_entry(file, &tr->events, list)
> -- 
> 2.25.1
> 


-- 
Masami Hiramatsu (Google) <mhiramat@kernel.org>

^ permalink raw reply

* [PATCH v5 4/4] tracing/Documentation: Add a section about backup instance
From: Masami Hiramatsu (Google) @ 2026-01-28  0:10 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Mathieu Desnoyers, linux-kernel,
	linux-trace-kernel
In-Reply-To: <176955897718.2786091.11948759407196200082.stgit@mhiramat.tok.corp.google.com>

From: Masami Hiramatsu (Google) <mhiramat@kernel.org>

Add a section about backup instance to the debugging.rst.

Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
 Documentation/trace/debugging.rst |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/Documentation/trace/debugging.rst b/Documentation/trace/debugging.rst
index 4d88c346fc38..73e2154bcf98 100644
--- a/Documentation/trace/debugging.rst
+++ b/Documentation/trace/debugging.rst
@@ -159,3 +159,22 @@ If setting it from the kernel command line, it is recommended to also
 disable tracing with the "traceoff" flag, and enable tracing after boot up.
 Otherwise the trace from the most recent boot will be mixed with the trace
 from the previous boot, and may make it confusing to read.
+
+Using a backup instance for keeping previous boot data
+------------------------------------------------------
+
+It is also possible to record trace data at system boot time by specifying
+events with the persistent ring buffer, but in this case the data before the
+reboot will be lost before it can be read. This problem can be solved by a
+backup instance. From the kernel command line::
+
+  reserve_mem=12M:4096:trace trace_instance=boot_map@trace,sched,irq trace_instance=backup=boot_map
+
+When the boot up, the previous data in the`boot_map` is copied to "backup"
+instance, and the "sched:*" and "irq:*" events for current boot are traced on
+"boot_map". Thus user can read the previous boot data from the "backup" instance
+without stopping trace.
+
+Note that this "backup" instance is readonly, and will be removed automatically
+if you clear the trace data or read out all trace data from "trace_pipe" or
+"trace_pipe_raw" files.
\ No newline at end of file


^ permalink raw reply related

* [PATCH v5 3/4] tracing: Remove the backup instance automatically after read
From: Masami Hiramatsu (Google) @ 2026-01-28  0:10 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Mathieu Desnoyers, linux-kernel,
	linux-trace-kernel
In-Reply-To: <176955897718.2786091.11948759407196200082.stgit@mhiramat.tok.corp.google.com>

From: Masami Hiramatsu (Google) <mhiramat@kernel.org>

Since the backup instance is readonly, after reading all data
via pipe, no data is left on the instance. Thus it can be
removed safely after closing all files.
This also removes it if user resets the ring buffer manually
via 'trace' file.

Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
 Changes in v4:
   - Update description.
---
 kernel/trace/trace.c |   64 +++++++++++++++++++++++++++++++++++++++++++++++++-
 kernel/trace/trace.h |    6 +++++
 2 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index d39f6509c12a..7d615a74f915 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -590,6 +590,55 @@ void trace_set_ring_buffer_expanded(struct trace_array *tr)
 	tr->ring_buffer_expanded = true;
 }
 
+static int __remove_instance(struct trace_array *tr);
+
+static void trace_array_autoremove(struct work_struct *work)
+{
+	struct trace_array *tr = container_of(work, struct trace_array, autoremove_work);
+
+	guard(mutex)(&event_mutex);
+	guard(mutex)(&trace_types_lock);
+
+	/*
+	 * This can be fail if someone gets @tr before starting this
+	 * function, but in that case, this will be kicked again when
+	 * putting it. So we don't care the result.
+	 */
+	__remove_instance(tr);
+}
+
+static struct workqueue_struct *autoremove_wq;
+
+static void trace_array_init_autoremove(struct trace_array *tr)
+{
+	INIT_WORK(&tr->autoremove_work, trace_array_autoremove);
+}
+
+static void trace_array_kick_autoremove(struct trace_array *tr)
+{
+	if (!work_pending(&tr->autoremove_work) && autoremove_wq)
+		queue_work(autoremove_wq, &tr->autoremove_work);
+}
+
+static void trace_array_cancel_autoremove(struct trace_array *tr)
+{
+	if (work_pending(&tr->autoremove_work))
+		cancel_work(&tr->autoremove_work);
+}
+
+__init static int trace_array_init_autoremove_wq(void)
+{
+	autoremove_wq = alloc_workqueue("tr_autoremove_wq",
+					WQ_UNBOUND | WQ_HIGHPRI, 0);
+	if (!autoremove_wq) {
+		pr_err("Unable to allocate tr_autoremove_wq\n");
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+late_initcall_sync(trace_array_init_autoremove_wq);
+
 LIST_HEAD(ftrace_trace_arrays);
 
 int trace_array_get(struct trace_array *this_tr)
@@ -598,7 +647,7 @@ int trace_array_get(struct trace_array *this_tr)
 
 	guard(mutex)(&trace_types_lock);
 	list_for_each_entry(tr, &ftrace_trace_arrays, list) {
-		if (tr == this_tr) {
+		if (tr == this_tr && !tr->free_on_close) {
 			tr->ref++;
 			return 0;
 		}
@@ -611,6 +660,12 @@ static void __trace_array_put(struct trace_array *this_tr)
 {
 	WARN_ON(!this_tr->ref);
 	this_tr->ref--;
+	/*
+	 * When free_on_close is set, prepare removing the array
+	 * when the last reference is released.
+	 */
+	if (this_tr->ref == 1 && this_tr->free_on_close)
+		trace_array_kick_autoremove(this_tr);
 }
 
 /**
@@ -6237,6 +6292,10 @@ static void update_last_data(struct trace_array *tr)
 	/* Only if the buffer has previous boot data clear and update it. */
 	tr->flags &= ~TRACE_ARRAY_FL_LAST_BOOT;
 
+	/* If this is a backup instance, mark it for autoremove. */
+	if (tr->flags & TRACE_ARRAY_FL_VMALLOC)
+		tr->free_on_close = true;
+
 	/* Reset the module list and reload them */
 	if (tr->scratch) {
 		struct trace_scratch *tscratch = tr->scratch;
@@ -10418,6 +10477,8 @@ trace_array_create_systems(const char *name, const char *systems,
 	if (ftrace_allocate_ftrace_ops(tr) < 0)
 		goto out_free_tr;
 
+	trace_array_init_autoremove(tr);
+
 	ftrace_init_trace_array(tr);
 
 	init_trace_flags_index(tr);
@@ -10566,6 +10627,7 @@ static int __remove_instance(struct trace_array *tr)
 	if (update_marker_trace(tr, 0))
 		synchronize_rcu();
 
+	trace_array_cancel_autoremove(tr);
 	tracing_set_nop(tr);
 	clear_ftrace_function_probes(tr);
 	event_trace_del_tracer(tr);
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 0adc644084bf..d9d45dd3c0f3 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -447,6 +447,12 @@ struct trace_array {
 	 * we do not waste memory on systems that are not using tracing.
 	 */
 	bool ring_buffer_expanded;
+	/*
+	 * If the ring buffer is a read only backup instance, it will be
+	 * removed after dumping all data via pipe, because no readable data.
+	 */
+	bool free_on_close;
+	struct work_struct	autoremove_work;
 };
 
 enum {


^ permalink raw reply related

* [PATCH v5 2/4] tracing: Make the backup instance non-reusable
From: Masami Hiramatsu (Google) @ 2026-01-28  0:09 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Mathieu Desnoyers, linux-kernel,
	linux-trace-kernel
In-Reply-To: <176955897718.2786091.11948759407196200082.stgit@mhiramat.tok.corp.google.com>

From: Masami Hiramatsu (Google) <mhiramat@kernel.org>

Since there is no reason to reuse the backup instance, make it
readonly (but erasable).
Note that only backup instances are readonly, because
other trace instances will be empty unless it is writable.
Only backup instances have copy entries from the original.

With this change, most of the trace control files are removed
from the backup instance, including eventfs enable/filter etc.

 # find /sys/kernel/tracing/instances/backup/events/ | wc -l
 4093
 # find /sys/kernel/tracing/instances/boot_map/events/ | wc -l
 9573

Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
 Changes in v5:
   - Rebased on the latest for-next (and hide show_event_filters/triggers
     if the instance is readonly.
 Changes in v4:
  - Make trace data erasable. (not reusable)
 Changes in v3:
  - Resuse the beginning part of event_entries for readonly files.
  - Remove readonly file_operations and checking readonly flag in
    each write operation.
 Changes in v2:
  - Use readonly file_operations to prohibit writing instead of
    checking flags in write() callbacks.
  - Remove writable files from eventfs.
---
 kernel/trace/trace.c        |   93 ++++++++++++++++++++++++++++++-------------
 kernel/trace/trace.h        |    8 +++-
 kernel/trace/trace_boot.c   |    5 +-
 kernel/trace/trace_events.c |   80 ++++++++++++++++++++++++-------------
 4 files changed, 126 insertions(+), 60 deletions(-)

diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 5c3e4a554143..d39f6509c12a 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -5052,6 +5052,11 @@ static ssize_t
 tracing_write_stub(struct file *filp, const char __user *ubuf,
 		   size_t count, loff_t *ppos)
 {
+	struct trace_array *tr = file_inode(filp)->i_private;
+
+	if (trace_array_is_readonly(tr))
+		return -EPERM;
+
 	return count;
 }
 
@@ -5152,6 +5157,9 @@ tracing_cpumask_write(struct file *filp, const char __user *ubuf,
 	cpumask_var_t tracing_cpumask_new;
 	int err;
 
+	if (trace_array_is_readonly(tr))
+		return -EPERM;
+
 	if (count == 0 || count > KMALLOC_MAX_SIZE)
 		return -EINVAL;
 
@@ -6436,6 +6444,9 @@ tracing_set_trace_write(struct file *filp, const char __user *ubuf,
 	size_t ret;
 	int err;
 
+	if (trace_array_is_readonly(tr))
+		return -EPERM;
+
 	ret = cnt;
 
 	if (cnt > MAX_TRACER_SIZE)
@@ -7070,6 +7081,9 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,
 	unsigned long val;
 	int ret;
 
+	if (trace_array_is_readonly(tr))
+		return -EPERM;
+
 	ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
 	if (ret)
 		return ret;
@@ -7824,6 +7838,9 @@ static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf,
 	const char *clockstr;
 	int ret;
 
+	if (trace_array_is_readonly(tr))
+		return -EPERM;
+
 	if (cnt >= sizeof(buf))
 		return -EINVAL;
 
@@ -9388,12 +9405,16 @@ static void
 tracing_init_tracefs_percpu(struct trace_array *tr, long cpu)
 {
 	struct dentry *d_percpu = tracing_dentry_percpu(tr, cpu);
+	umode_t writable_mode = TRACE_MODE_WRITE;
 	struct dentry *d_cpu;
 	char cpu_dir[30]; /* 30 characters should be more than enough */
 
 	if (!d_percpu)
 		return;
 
+	if (trace_array_is_readonly(tr))
+		writable_mode = TRACE_MODE_READ;
+
 	snprintf(cpu_dir, 30, "cpu%ld", cpu);
 	d_cpu = tracefs_create_dir(cpu_dir, d_percpu);
 	if (!d_cpu) {
@@ -9616,7 +9637,6 @@ struct dentry *trace_create_file(const char *name,
 	return ret;
 }
 
-
 static struct dentry *trace_options_init_dentry(struct trace_array *tr)
 {
 	struct dentry *d_tracer;
@@ -9846,6 +9866,9 @@ rb_simple_write(struct file *filp, const char __user *ubuf,
 	unsigned long val;
 	int ret;
 
+	if (trace_array_is_readonly(tr))
+		return -EPERM;
+
 	ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
 	if (ret)
 		return ret;
@@ -9952,6 +9975,9 @@ buffer_subbuf_size_write(struct file *filp, const char __user *ubuf,
 	int pages;
 	int ret;
 
+	if (trace_array_is_readonly(tr))
+		return -EPERM;
+
 	ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
 	if (ret)
 		return ret;
@@ -10632,17 +10658,23 @@ static __init void create_trace_instances(struct dentry *d_tracer)
 static void
 init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer)
 {
+	umode_t writable_mode = TRACE_MODE_WRITE;
+	bool readonly = trace_array_is_readonly(tr);
 	int cpu;
 
+	if (readonly)
+		writable_mode = TRACE_MODE_READ;
+
 	trace_create_file("available_tracers", TRACE_MODE_READ, d_tracer,
-			tr, &show_traces_fops);
+			  tr, &show_traces_fops);
 
-	trace_create_file("current_tracer", TRACE_MODE_WRITE, d_tracer,
-			tr, &set_tracer_fops);
+	trace_create_file("current_tracer", writable_mode, d_tracer,
+			  tr, &set_tracer_fops);
 
-	trace_create_file("tracing_cpumask", TRACE_MODE_WRITE, d_tracer,
+	trace_create_file("tracing_cpumask", writable_mode, d_tracer,
 			  tr, &tracing_cpumask_fops);
 
+	/* Options are used for changing print-format even for readonly instance. */
 	trace_create_file("trace_options", TRACE_MODE_WRITE, d_tracer,
 			  tr, &tracing_iter_fops);
 
@@ -10652,27 +10684,35 @@ init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer)
 	trace_create_file("trace_pipe", TRACE_MODE_READ, d_tracer,
 			  tr, &tracing_pipe_fops);
 
-	trace_create_file("buffer_size_kb", TRACE_MODE_WRITE, d_tracer,
+	trace_create_file("buffer_size_kb", writable_mode, d_tracer,
 			  tr, &tracing_entries_fops);
 
 	trace_create_file("buffer_total_size_kb", TRACE_MODE_READ, d_tracer,
 			  tr, &tracing_total_entries_fops);
 
-	trace_create_file("free_buffer", 0200, d_tracer,
-			  tr, &tracing_free_buffer_fops);
+	if (!readonly) {
+		trace_create_file("free_buffer", 0200, d_tracer,
+				tr, &tracing_free_buffer_fops);
 
-	trace_create_file("trace_marker", 0220, d_tracer,
-			  tr, &tracing_mark_fops);
+		trace_create_file("trace_marker", 0220, d_tracer,
+				tr, &tracing_mark_fops);
 
-	tr->trace_marker_file = __find_event_file(tr, "ftrace", "print");
+		tr->trace_marker_file = __find_event_file(tr, "ftrace", "print");
 
-	trace_create_file("trace_marker_raw", 0220, d_tracer,
-			  tr, &tracing_mark_raw_fops);
+		trace_create_file("trace_marker_raw", 0220, d_tracer,
+				tr, &tracing_mark_raw_fops);
 
-	trace_create_file("trace_clock", TRACE_MODE_WRITE, d_tracer, tr,
+		trace_create_file("buffer_percent", TRACE_MODE_WRITE, d_tracer,
+				tr, &buffer_percent_fops);
+
+		trace_create_file("syscall_user_buf_size", TRACE_MODE_WRITE, d_tracer,
+				tr, &tracing_syscall_buf_fops);
+	}
+
+	trace_create_file("trace_clock", writable_mode, d_tracer, tr,
 			  &trace_clock_fops);
 
-	trace_create_file("tracing_on", TRACE_MODE_WRITE, d_tracer,
+	trace_create_file("tracing_on", writable_mode, d_tracer,
 			  tr, &rb_simple_fops);
 
 	trace_create_file("timestamp_mode", TRACE_MODE_READ, d_tracer, tr,
@@ -10680,41 +10720,38 @@ init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer)
 
 	tr->buffer_percent = 50;
 
-	trace_create_file("buffer_percent", TRACE_MODE_WRITE, d_tracer,
-			tr, &buffer_percent_fops);
-
-	trace_create_file("buffer_subbuf_size_kb", TRACE_MODE_WRITE, d_tracer,
+	trace_create_file("buffer_subbuf_size_kb", writable_mode, d_tracer,
 			  tr, &buffer_subbuf_size_fops);
 
-	trace_create_file("syscall_user_buf_size", TRACE_MODE_WRITE, d_tracer,
-			 tr, &tracing_syscall_buf_fops);
-
 	create_trace_options_dir(tr);
 
 #ifdef CONFIG_TRACER_MAX_TRACE
-	trace_create_maxlat_file(tr, d_tracer);
+	if (!readonly)
+		trace_create_maxlat_file(tr, d_tracer);
 #endif
 
-	if (ftrace_create_function_files(tr, d_tracer))
+	if (!readonly && ftrace_create_function_files(tr, d_tracer))
 		MEM_FAIL(1, "Could not allocate function filter files");
 
 	if (tr->range_addr_start) {
 		trace_create_file("last_boot_info", TRACE_MODE_READ, d_tracer,
 				  tr, &last_boot_fops);
 #ifdef CONFIG_TRACER_SNAPSHOT
-	} else {
+	} else if (!readonly) {
 		trace_create_file("snapshot", TRACE_MODE_WRITE, d_tracer,
 				  tr, &snapshot_fops);
 #endif
 	}
 
-	trace_create_file("error_log", TRACE_MODE_WRITE, d_tracer,
-			  tr, &tracing_err_log_fops);
+	if (!readonly)
+		trace_create_file("error_log", TRACE_MODE_WRITE, d_tracer,
+				  tr, &tracing_err_log_fops);
 
 	for_each_tracing_cpu(cpu)
 		tracing_init_tracefs_percpu(tr, cpu);
 
-	ftrace_init_tracefs(tr, d_tracer);
+	if (!readonly)
+		ftrace_init_tracefs(tr, d_tracer);
 }
 
 #ifdef CONFIG_TRACEFS_AUTOMOUNT_DEPRECATED
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 69e7defba6c6..0adc644084bf 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -33,6 +33,7 @@
 
 #define TRACE_MODE_WRITE	0640
 #define TRACE_MODE_READ		0440
+#define TRACE_MODE_WRITE_MASK	(TRACE_MODE_WRITE & ~TRACE_MODE_READ)
 
 enum trace_type {
 	__TRACE_FIRST_TYPE = 0,
@@ -483,6 +484,12 @@ extern bool trace_clock_in_ns(struct trace_array *tr);
 
 extern unsigned long trace_adjust_address(struct trace_array *tr, unsigned long addr);
 
+static inline bool trace_array_is_readonly(struct trace_array *tr)
+{
+	/* backup instance is read only. */
+	return tr->flags & TRACE_ARRAY_FL_VMALLOC;
+}
+
 /*
  * The global tracer (top) should be the first trace array added,
  * but we check the flag anyway.
@@ -681,7 +688,6 @@ struct dentry *trace_create_file(const char *name,
 				 void *data,
 				 const struct file_operations *fops);
 
-
 /**
  * tracer_tracing_is_on_cpu - show real state of ring buffer enabled on for a cpu
  * @tr : the trace array to know if ring buffer is enabled
diff --git a/kernel/trace/trace_boot.c b/kernel/trace/trace_boot.c
index dbe29b4c6a7a..2ca2541c8a58 100644
--- a/kernel/trace/trace_boot.c
+++ b/kernel/trace/trace_boot.c
@@ -61,7 +61,8 @@ trace_boot_set_instance_options(struct trace_array *tr, struct xbc_node *node)
 		v = memparse(p, NULL);
 		if (v < PAGE_SIZE)
 			pr_err("Buffer size is too small: %s\n", p);
-		if (tracing_resize_ring_buffer(tr, v, RING_BUFFER_ALL_CPUS) < 0)
+		if (trace_array_is_readonly(tr) ||
+		    tracing_resize_ring_buffer(tr, v, RING_BUFFER_ALL_CPUS) < 0)
 			pr_err("Failed to resize trace buffer to %s\n", p);
 	}
 
@@ -597,7 +598,7 @@ trace_boot_enable_tracer(struct trace_array *tr, struct xbc_node *node)
 
 	p = xbc_node_find_value(node, "tracer", NULL);
 	if (p && *p != '\0') {
-		if (tracing_set_tracer(tr, p) < 0)
+		if (trace_array_is_readonly(tr) || tracing_set_tracer(tr, p) < 0)
 			pr_err("Failed to set given tracer: %s\n", p);
 	}
 
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 4972e1a2b5f3..2e0db93be557 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -1380,6 +1380,9 @@ static int __ftrace_set_clr_event(struct trace_array *tr, const char *match,
 {
 	int ret;
 
+	if (trace_array_is_readonly(tr))
+		return -EPERM;
+
 	mutex_lock(&event_mutex);
 	ret = __ftrace_set_clr_event_nolock(tr, match, sub, event, set, mod);
 	mutex_unlock(&event_mutex);
@@ -2952,8 +2955,8 @@ event_subsystem_dir(struct trace_array *tr, const char *name,
 	} else
 		__get_system(system);
 
-	/* ftrace only has directories no files */
-	if (strcmp(name, "ftrace") == 0)
+	/* ftrace only has directories no files, readonly instance too. */
+	if (strcmp(name, "ftrace") == 0 || trace_array_is_readonly(tr))
 		nr_entries = 0;
 	else
 		nr_entries = ARRAY_SIZE(system_entries);
@@ -3118,28 +3121,30 @@ event_create_dir(struct eventfs_inode *parent, struct trace_event_file *file)
 	int ret;
 	static struct eventfs_entry event_entries[] = {
 		{
-			.name		= "enable",
+			.name		= "format",
 			.callback	= event_callback,
-			.release	= event_release,
 		},
+#ifdef CONFIG_PERF_EVENTS
 		{
-			.name		= "filter",
+			.name		= "id",
 			.callback	= event_callback,
 		},
+#endif
+#define NR_RO_EVENT_ENTRIES	(1 + IS_ENABLED(CONFIG_PERF_EVENTS))
+/* Readonly files must be above this line and counted by NR_RO_EVENT_ENTRIES. */
 		{
-			.name		= "trigger",
+			.name		= "enable",
 			.callback	= event_callback,
+			.release	= event_release,
 		},
 		{
-			.name		= "format",
+			.name		= "filter",
 			.callback	= event_callback,
 		},
-#ifdef CONFIG_PERF_EVENTS
 		{
-			.name		= "id",
+			.name		= "trigger",
 			.callback	= event_callback,
 		},
-#endif
 #ifdef CONFIG_HIST_TRIGGERS
 		{
 			.name		= "hist",
@@ -3172,9 +3177,13 @@ event_create_dir(struct eventfs_inode *parent, struct trace_event_file *file)
 	if (!e_events)
 		return -ENOMEM;
 
-	nr_entries = ARRAY_SIZE(event_entries);
+	if (trace_array_is_readonly(tr))
+		nr_entries = NR_RO_EVENT_ENTRIES;
+	else
+		nr_entries = ARRAY_SIZE(event_entries);
 
 	name = trace_event_name(call);
+
 	ei = eventfs_create_dir(name, e_events, event_entries, nr_entries, file);
 	if (IS_ERR(ei)) {
 		pr_warn("Could not create tracefs '%s' directory\n", name);
@@ -4511,31 +4520,37 @@ create_event_toplevel_files(struct dentry *parent, struct trace_array *tr)
 	int nr_entries;
 	static struct eventfs_entry events_entries[] = {
 		{
-			.name		= "enable",
+			.name		= "header_page",
 			.callback	= events_callback,
 		},
 		{
-			.name		= "header_page",
+			.name		= "header_event",
 			.callback	= events_callback,
 		},
+#define NR_RO_TOP_ENTRIES	2
+/* Readonly files must be above this line and counted by NR_RO_TOP_ENTRIES. */
 		{
-			.name		= "header_event",
+			.name		= "enable",
 			.callback	= events_callback,
 		},
 	};
 
-	entry = trace_create_file("set_event", TRACE_MODE_WRITE, parent,
-				  tr, &ftrace_set_event_fops);
-	if (!entry)
-		return -ENOMEM;
+	if (!trace_array_is_readonly(tr)) {
+		entry = trace_create_file("set_event", TRACE_MODE_WRITE, parent,
+					tr, &ftrace_set_event_fops);
+		if (!entry)
+			return -ENOMEM;
 
-	trace_create_file("show_event_filters", TRACE_MODE_READ, parent, tr,
-			  &ftrace_show_event_filters_fops);
+		trace_create_file("show_event_filters", TRACE_MODE_READ, parent, tr,
+				&ftrace_show_event_filters_fops);
 
-	trace_create_file("show_event_triggers", TRACE_MODE_READ, parent, tr,
-			  &ftrace_show_event_triggers_fops);
+		trace_create_file("show_event_triggers", TRACE_MODE_READ, parent, tr,
+				&ftrace_show_event_triggers_fops);
 
-	nr_entries = ARRAY_SIZE(events_entries);
+		nr_entries = ARRAY_SIZE(events_entries);
+	} else {
+		nr_entries = NR_RO_TOP_ENTRIES;
+	}
 
 	e_events = eventfs_create_events_dir("events", parent, events_entries,
 					     nr_entries, tr);
@@ -4544,15 +4559,22 @@ create_event_toplevel_files(struct dentry *parent, struct trace_array *tr)
 		return -ENOMEM;
 	}
 
-	/* There are not as crucial, just warn if they are not created */
+	if (!trace_array_is_readonly(tr)) {
+
+		entry = trace_create_file("set_event", TRACE_MODE_WRITE, parent,
+					tr, &ftrace_set_event_fops);
+		if (!entry)
+			return -ENOMEM;
 
-	trace_create_file("set_event_pid", TRACE_MODE_WRITE, parent,
-			  tr, &ftrace_set_event_pid_fops);
+		/* There are not as crucial, just warn if they are not created */
 
-	trace_create_file("set_event_notrace_pid",
-			  TRACE_MODE_WRITE, parent, tr,
-			  &ftrace_set_event_notrace_pid_fops);
+		trace_create_file("set_event_pid", TRACE_MODE_WRITE, parent,
+				tr, &ftrace_set_event_pid_fops);
 
+		trace_create_file("set_event_notrace_pid",
+				TRACE_MODE_WRITE, parent, tr,
+				&ftrace_set_event_notrace_pid_fops);
+	}
 	tr->event_dir = e_events;
 
 	return 0;


^ permalink raw reply related

* [PATCH v5 1/4] tracing: Reset last_boot_info if ring buffer is reset
From: Masami Hiramatsu (Google) @ 2026-01-28  0:09 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Mathieu Desnoyers, linux-kernel,
	linux-trace-kernel
In-Reply-To: <176955897718.2786091.11948759407196200082.stgit@mhiramat.tok.corp.google.com>

From: Masami Hiramatsu (Google) <mhiramat@kernel.org>

Commit 32dc0042528d ("tracing: Reset last-boot buffers when reading
out all cpu buffers") resets the last_boot_info when user read out
all data via trace_pipe* files. But it is not reset when user
resets the buffer from other files. (e.g. write `trace` file)

Reset it when the corresponding ring buffer is reset too.

Fixes: 32dc0042528d ("tracing: Reset last-boot buffers when reading out all cpu buffers")
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
 kernel/trace/trace.c |    7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 396d59202438..5c3e4a554143 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4891,6 +4891,8 @@ static int tracing_single_release_tr(struct inode *inode, struct file *file)
 	return single_release(inode, file);
 }
 
+static bool update_last_data_if_empty(struct trace_array *tr);
+
 static int tracing_open(struct inode *inode, struct file *file)
 {
 	struct trace_array *tr = inode->i_private;
@@ -4915,6 +4917,8 @@ static int tracing_open(struct inode *inode, struct file *file)
 			tracing_reset_online_cpus(trace_buf);
 		else
 			tracing_reset_cpu(trace_buf, cpu);
+
+		update_last_data_if_empty(tr);
 	}
 
 	if (file->f_mode & FMODE_READ) {
@@ -5981,6 +5985,7 @@ tracing_set_trace_read(struct file *filp, char __user *ubuf,
 int tracer_init(struct tracer *t, struct trace_array *tr)
 {
 	tracing_reset_online_cpus(&tr->array_buffer);
+	update_last_data_if_empty(tr);
 	return t->init(tr);
 }
 
@@ -7799,6 +7804,7 @@ int tracing_set_clock(struct trace_array *tr, const char *clockstr)
 		ring_buffer_set_clock(tr->max_buffer.buffer, trace_clocks[i].func);
 	tracing_reset_online_cpus(&tr->max_buffer);
 #endif
+	update_last_data_if_empty(tr);
 
 	if (tr->scratch && !(tr->flags & TRACE_ARRAY_FL_LAST_BOOT)) {
 		struct trace_scratch *tscratch = tr->scratch;
@@ -8036,6 +8042,7 @@ tracing_snapshot_write(struct file *filp, const char __user *ubuf, size_t cnt,
 				tracing_reset_online_cpus(&tr->max_buffer);
 			else
 				tracing_reset_cpu(&tr->max_buffer, iter->cpu_file);
+			update_last_data_if_empty(tr);
 		}
 		break;
 	}


^ permalink raw reply related

* [PATCH v5 0/4] tracing: Remove backup instance after read all
From: Masami Hiramatsu (Google) @ 2026-01-28  0:09 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Mathieu Desnoyers, linux-kernel,
	linux-trace-kernel

Hi,

Here is the v5 of the series to improve backup instances of
the persistent ring buffer. The previous version is here:

https://lore.kernel.org/all/176887135615.578403.6988045330349053692.stgit@mhiramat.tok.corp.google.com/

This is just rebased on top of the latest linux-trace/trace/for-next.

Since backup instances are a kind of snapshot of the persistent
ring buffer, it should be readonly. And if it is readonly
there is no reason to keep it after reading all data via trace_pipe
because the data has been consumed. But user should be able to remove
the readonly instance by rmdir or truncating `trace` file.

Thus, [2/4] makes backup instances readonly (not able to write any
events, cleanup trace, change buffer size). Also, [3/4] removes the
backup instance after consuming all data via trace_pipe.
With this improvements, even if we makes a backup instance (using
the same amount of memory of the persistent ring buffer), it will
be removed after reading the data automatically.

---

Masami Hiramatsu (Google) (4):
      tracing: Reset last_boot_info if ring buffer is reset
      tracing: Make the backup instance non-reusable
      tracing: Remove the backup instance automatically after read
      tracing/Documentation: Add a section about backup instance


 Documentation/trace/debugging.rst |   19 ++++
 kernel/trace/trace.c              |  164 ++++++++++++++++++++++++++++++-------
 kernel/trace/trace.h              |   14 +++
 kernel/trace/trace_boot.c         |    5 +
 kernel/trace/trace_events.c       |   80 ++++++++++++------
 5 files changed, 221 insertions(+), 61 deletions(-)

--
Masami Hiramatsu (Google) <mhiramat@kernel.org>

^ permalink raw reply

* Re: [RFC PATCH v1 09/37] KVM: guest_memfd: Skip LRU for guest_memfd folios
From: Ackerley Tng @ 2026-01-27 23:46 UTC (permalink / raw)
  To: Vlastimil Babka, cgroups, kvm, linux-doc, linux-fsdevel,
	linux-kernel, linux-kselftest, linux-mm, linux-trace-kernel, x86
  Cc: akpm, binbin.wu, bp, brauner, chao.p.peng, chenhuacai, corbet,
	dave.hansen, dave.hansen, david, dmatlack, erdemaktas, fan.du,
	fvdl, haibo1.xu, hannes, hch, hpa, hughd, ira.weiny,
	isaku.yamahata, jack, james.morse, jarkko, jgg, jgowans, jhubbard,
	jroedel, jthoughton, jun.miao, kai.huang, keirf, kent.overstreet,
	liam.merwick, maciej.wieczor-retman, mail, maobibo,
	mathieu.desnoyers, maz, mhiramat, mhocko, mic, michael.roth,
	mingo, mlevitsk, mpe, muchun.song, nikunj, nsaenz, oliver.upton,
	palmer, pankaj.gupta, paul.walmsley, pbonzini, peterx, pgonda,
	prsampat, pvorel, qperret, richard.weiyang, rick.p.edgecombe,
	rientjes, rostedt, roypat, rppt, seanjc, shakeel.butt, shuah,
	steven.price, steven.sistare, suzuki.poulose, tabba, tglx,
	thomas.lendacky, vannapurve, viro, vkuznets, wei.w.wang, will,
	willy, wyihan, xiaoyao.li, yan.y.zhao, yilun.xu, yuzenghui,
	zhiquan1.li
In-Reply-To: <ce78da49-2525-44af-9cb8-301bf6a4658a@suse.cz>

Vlastimil Babka <vbabka@suse.cz> writes:

> On 10/17/25 22:11, Ackerley Tng wrote:
>> filemap_add_folio(), called from filemap_grab_folio(), adds folios to
>> an LRU list. This is unnecessary for guest_memfd, which does not
>> participate in swapping.
>
> IIRC guest_memfd mappings are unevictable. That should mean they are not
> ultimately added to a list (see lruvec_add_folio()).
>
>> In addition, the LRU list takes a reference count on the folio. With
>
> IIUC the refcount is temporary while being on the percpu
> &cpu_fbatches.lru_add, added by __folio_batch_add_and_move().

Thanks for pointing this out. You're right about this, I misunderstood
this refcounting earlier.

> When flushed
> via folio_batch_move_lru(), the refcount is removed and there's only the LRU
> folio flag that remains. The fbatch flushing can be triggered if you see an
> unexpected refcount increase.

The new plan is, to update kvm_gmem_is_safe_for_conversion() to drain
the fbatch if it some elevated refcount is found:

static bool kvm_gmem_is_safe_for_conversion(struct inode *inode,
					    pgoff_t start, size_t nr_pages,
					    pgoff_t *err_index)
{
	struct address_space *mapping = inode->i_mapping;
	const int filemap_get_folios_refcount = 1;
	pgoff_t last = start + nr_pages - 1;
	struct folio_batch fbatch;
	bool lru_drained = false;
	bool safe = true;
	int i;

	folio_batch_init(&fbatch);
	while (safe && filemap_get_folios(mapping, &start, last, &fbatch)) {

		for (i = 0; i < folio_batch_count(&fbatch);) {
			struct folio *folio = fbatch.folios[i];

			safe = (folio_ref_count(folio) ==
				folio_nr_pages(folio) +
				filemap_get_folios_refcount);

			if (safe) {
				++i;
			} else if (!lru_drained) {
				lru_add_drain_all();
				lru_drained = true;
			} else {
				*err_index = folio->index;
				break;
			}
		}

		folio_batch_release(&fbatch);
	}

	return safe;
}

I hope this is what you meant!

> So it might be feasible to do without this
> patch (maybe it was already tried and there were substantial issues, in
> which case should be mentioned).
>

The patch "KVM: guest_memfd: Skip LRU for guest_memfd folios" will be
dropped from the next revision, and "KVM: guest_memfd: Don't set
FGP_ACCESSED when getting folios" is no longer a requirement for this
patch series.

>> shared-to-private memory conversions for KVM guests dependent on folio
>> refcounts, this extra reference can cause conversions to fail due to
>> unexpected refcounts.
>>
>>
>> [...snip...]
>>

^ permalink raw reply

* Re: [PATCH v5 2/3] mm: vmscan: add cgroup IDs to vmscan tracepoints
From: Shakeel Butt @ 2026-01-27 23:43 UTC (permalink / raw)
  To: Thomas Ballasi; +Cc: akpm, linux-mm, linux-trace-kernel, mhiramat, rostedt
In-Reply-To: <20260122182510.2126-3-tballasi@linux.microsoft.com>

On Thu, Jan 22, 2026 at 10:25:09AM -0800, Thomas Ballasi wrote:
> Memory reclaim events are currently difficult to attribute to
> specific cgroups, making debugging memory pressure issues
> challenging.  This patch adds memory cgroup ID (memcg_id) to key
> vmscan tracepoints to enable better correlation and analysis.
> 
> For operations not associated with a specific cgroup, the field
> is defaulted to 0.
> 
> Signed-off-by: Thomas Ballasi <tballasi@linux.microsoft.com>
> ---
>  include/trace/events/vmscan.h | 83 ++++++++++++++++++++---------------
>  mm/shrinker.c                 |  6 ++-
>  mm/vmscan.c                   | 17 +++----
>  3 files changed, 61 insertions(+), 45 deletions(-)
> 
> diff --git a/include/trace/events/vmscan.h b/include/trace/events/vmscan.h
> index 490958fa10dee..20160e79eb0d7 100644
> --- a/include/trace/events/vmscan.h
> +++ b/include/trace/events/vmscan.h
> @@ -114,85 +114,92 @@ TRACE_EVENT(mm_vmscan_wakeup_kswapd,
>  
>  DECLARE_EVENT_CLASS(mm_vmscan_direct_reclaim_begin_template,
>  
> -	TP_PROTO(int order, gfp_t gfp_flags),
> +	TP_PROTO(gfp_t gfp_flags, int order, u64 memcg_id),
>  
> -	TP_ARGS(order, gfp_flags),
> +	TP_ARGS(gfp_flags, order, memcg_id),
>  
>  	TP_STRUCT__entry(
> -		__field(	int,	order		)
>  		__field(	unsigned long,	gfp_flags	)
> +		__field(	u64,	memcg_id	)
> +		__field(	int,	order		)
>  	),
>  
>  	TP_fast_assign(
> -		__entry->order		= order;
>  		__entry->gfp_flags	= (__force unsigned long)gfp_flags;
> +		__entry->order		= order;
> +		__entry->memcg_id	= memcg_id;

Please pass memcg pointer to tracepoints and call mem_cgroup_id(memcg)
here.


^ permalink raw reply

* Re: [PATCH v6 0/3] tracing: Guard __DECLARE_TRACE() use of __DO_TRACE_CALL() with SRCU-fast
From: Paul E. McKenney @ 2026-01-27 23:18 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, linux-trace-kernel, bpf, Masami Hiramatsu,
	Mark Rutland, Mathieu Desnoyers, Andrew Morton,
	Sebastian Andrzej Siewior, Alexei Starovoitov
In-Reply-To: <20260126213922.0a91bfac@robin>

On Mon, Jan 26, 2026 at 09:39:22PM -0500, Steven Rostedt wrote:
> On Mon, 26 Jan 2026 18:11:45 -0500
> Steven Rostedt <rostedt@kernel.org> wrote:
> 
> > The current use of guard(preempt_notrace)() within __DECLARE_TRACE()
> > to protect invocation of __DO_TRACE_CALL() means that BPF programs
> > attached to tracepoints are non-preemptible.  This is unhelpful in
> > real-time systems, whose users apparently wish to use BPF while also
> > achieving low latencies.
> > 
> > Change the protection of tracepoints to use fast_srcu() instead.
> > This will allow the callbacks to be able to be preempted. This also
> > means that the callbacks themselves need to be able to handle this
> > new found preemption ability.
> > 
> > For perf, add a guard(preempt) inside its handler too keep the old behavior
> > of perf events being called with preemption disabled.
> > 
> > For BPF, add a migrate_disable() to its handler. Actually, just replace
> > the rcu_read_lock() with rcu_read_lock_dont_migrate() and make it
> > cover more of the BPF callback handler.
> 
> My tests just triggered this, so I'm removing them from my queue for now.

Huh.  "Works for me."

Ah, I get it.  I think.  NMIs, right?

In your source tree, line 792 of kernel/rcu/srcutree.c is this line of
code, correct?

	WARN_ON_ONCE((read_flavor != SRCU_READ_FLAVOR_NMI) && in_nmi());

If so, could you please try this test with the patch shown at the end
of this email?

> -- Steve
> 
> 
> [  204.194772] ------------[ cut here ]------------
> [  204.194789] WARNING: kernel/rcu/srcutree.c:792 at __srcu_check_read_flavor+0x5c/0xb0, CPU#1: swapper/1/0
> [  204.194800] Modules linked in:
> [  204.194817] CPU: 1 UID: 0 PID: 0 Comm: swapper/1 Not tainted 6.19.0-rc7-test-00018-g2c774d6ad074-dirty #32 PREEMPT(voluntary) 
> [  204.194821] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.17.0-debian-1.17.0-1 04/01/2014
> [  204.194824] RIP: 0010:__srcu_check_read_flavor+0x5c/0xb0
> [  204.194829] Code: 84 c9 74 19 39 f1 74 45 0f 0b 85 c0 74 2e 39 c1 74 45 0f 0b 39 f0 75 3f c3 cc cc cc cc 85 c0 74 16 83 fe 04 75 ee 0f 0b eb ea <0f> 0b 8d 46 ff 85 f0 74 ba 0f 0b eb b6 83
>  fe 04 74 3a 31 c0 f0 0f
> [  204.194832] RSP: 0018:fffffe4c48325b50 EFLAGS: 00010002
> [  204.194835] RAX: 0000000000000001 RBX: ffffffff8791e5a0 RCX: 0000000000000000
> [  204.194836] RDX: 00000000ffffffff RSI: 0000000000000004 RDI: ffffffff879f1180
> [  204.194838] RBP: ffff8e6453fd2000 R08: 0000000000000001 R09: 0000000000000000
> [  204.194839] R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000001
> [  204.194840] R13: fffffe4c48325ef8 R14: ffffffff85eeae93 R15: ffff8e6453906900
> [  204.194842] FS:  0000000000000000(0000) GS:ffff8e6533593000(0000) knlGS:0000000000000000
> [  204.194844] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [  204.194845] CR2: 000055d1e7cf8cc0 CR3: 000000010b0cc004 CR4: 0000000000172ef0
> [  204.194850] Call Trace:
> [  204.194866]  <NMI>
> [  204.194868]  lock_release+0x215/0x320
> [  204.194886]  ? arch_perf_update_userpage+0x6c/0xf0
> [  204.195214]  perf_event_update_userpage+0x158/0x2e0
> [  204.195538]  x86_perf_event_set_period+0xc1/0x180
> [  204.195811]  handle_pmi_common+0x1ac/0x450
> [  204.198605]  ? __get_next_timer_interrupt+0x185/0x370
> [  204.198914]  intel_pmu_handle_irq+0x10e/0x510
> [  204.199032]  ? nmi_handle.part.0+0x30/0x270
> [  204.199197]  ? __get_next_timer_interrupt+0x185/0x370
> [  204.199404]  perf_event_nmi_handler+0x34/0x60
> [  204.199523]  nmi_handle.part.0+0xc9/0x270

------------------------------------------------------------------------

diff --git a/kernel/rcu/srcutree.c b/kernel/rcu/srcutree.c
index c469c708fdd6a..66ba6a2f83d3a 100644
--- a/kernel/rcu/srcutree.c
+++ b/kernel/rcu/srcutree.c
@@ -789,7 +789,8 @@ void __srcu_check_read_flavor(struct srcu_struct *ssp, int read_flavor)
 	struct srcu_data *sdp;
 
 	/* NMI-unsafe use in NMI is a bad sign, as is multi-bit read_flavor values. */
-	WARN_ON_ONCE((read_flavor != SRCU_READ_FLAVOR_NMI) && in_nmi());
+	WARN_ON_ONCE(read_flavor != SRCU_READ_FLAVOR_NMI &&
+		     read_flavor != SRCU_READ_FLAVOR_FAST && in_nmi());
 	WARN_ON_ONCE(read_flavor & (read_flavor - 1));
 
 	sdp = raw_cpu_ptr(ssp->sda);

^ permalink raw reply related

* Re: [RESEND][PATCH 3/5] perf: Use current->flags & PF_KTHREAD|PF_USER_WORKER instead of current->mm == NULL
From: Guenter Roeck @ 2026-01-27 20:31 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, linux-trace-kernel, linux-perf-users,
	Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers, Andrew Morton,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Namhyung Kim, Alexander Shishkin, Jiri Olsa, Ian Rogers,
	Adrian Hunter, Thomas Gleixner
In-Reply-To: <20260127102234.755d8c4e@gandalf.local.home>

On 1/27/26 07:22, Steven Rostedt wrote:
> On Mon, 26 Jan 2026 17:32:35 -0800
> Guenter Roeck <linux@roeck-us.net> wrote:
> 
>> Still crashing, though not as often and with a slightly different backtrace.
>> I added the backtrace to the bug report @ Google.
> 
> I figured there would be other locations. A while ago I had a patch to wrap
> the checks in a "is_user_thread()" helper function[1], but Ingo had issues
> with it. It seems now it's biting us in the butt and let's see if it would
> help now. I modified it slightly.
> 
> [1] https://lore.kernel.org/linux-trace-kernel/20250425204313.616425861@goodmis.org/
> 
> If the below fixes it, I'll resend it, but now as a real bug fix.
> 

All attempts to reproduce the problem after applying the patch below failed,
so feel free to go ahead and add

Tested-by: Guenter Roeck <linux@roeck-us.net>

to the patch.

Thanks,
Guenter

> -- Steve
> 
> diff --git a/include/linux/sched.h b/include/linux/sched.h
> index da0133524d08..5f00b5ed0f3b 100644
> --- a/include/linux/sched.h
> +++ b/include/linux/sched.h
> @@ -1776,6 +1776,11 @@ static __always_inline bool is_percpu_thread(void)
>   		(current->nr_cpus_allowed  == 1);
>   }
>   
> +static __always_inline bool is_user_task(struct task_struct *task)
> +{
> +	return task->mm && !(task->flags & (PF_KTHREAD | PF_USER_WORKER));
> +}
> +
>   /* Per-process atomic flags. */
>   #define PFA_NO_NEW_PRIVS		0	/* May not gain new privileges. */
>   #define PFA_SPREAD_PAGE			1	/* Spread page cache over cpuset */
> diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c
> index 1f6589578703..9d24b6e0c91f 100644
> --- a/kernel/events/callchain.c
> +++ b/kernel/events/callchain.c
> @@ -246,7 +246,7 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user,
>   
>   	if (user && !crosstask) {
>   		if (!user_mode(regs)) {
> -			if (current->flags & (PF_KTHREAD | PF_USER_WORKER))
> +			if (!is_user_task(current))
>   				goto exit_put;
>   			regs = task_pt_regs(current);
>   		}
> diff --git a/kernel/events/core.c b/kernel/events/core.c
> index a0fa488bce84..8cca80094624 100644
> --- a/kernel/events/core.c
> +++ b/kernel/events/core.c
> @@ -7460,7 +7460,7 @@ static void perf_sample_regs_user(struct perf_regs *regs_user,
>   	if (user_mode(regs)) {
>   		regs_user->abi = perf_reg_abi(current);
>   		regs_user->regs = regs;
> -	} else if (!(current->flags & (PF_KTHREAD | PF_USER_WORKER))) {
> +	} else if (is_user_task(current)) {
>   		perf_get_regs_user(regs_user, regs);
>   	} else {
>   		regs_user->abi = PERF_SAMPLE_REGS_ABI_NONE;
> @@ -8100,7 +8100,7 @@ static u64 perf_virt_to_phys(u64 virt)
>   		 * Try IRQ-safe get_user_page_fast_only first.
>   		 * If failed, leave phys_addr as 0.
>   		 */
> -		if (!(current->flags & (PF_KTHREAD | PF_USER_WORKER))) {
> +		if (is_user_task(current)) {
>   			struct page *p;
>   
>   			pagefault_disable();
> @@ -8215,7 +8215,7 @@ perf_callchain(struct perf_event *event, struct pt_regs *regs)
>   {
>   	bool kernel = !event->attr.exclude_callchain_kernel;
>   	bool user   = !event->attr.exclude_callchain_user &&
> -		!(current->flags & (PF_KTHREAD | PF_USER_WORKER));
> +		is_user_task(current);
>   	/* Disallow cross-task user callchains. */
>   	bool crosstask = event->ctx->task && event->ctx->task != current;
>   	bool defer_user = IS_ENABLED(CONFIG_UNWIND_USER) && user &&


^ permalink raw reply

* Re: [RESEND][PATCH 3/5] perf: Use current->flags & PF_KTHREAD|PF_USER_WORKER instead of current->mm == NULL
From: Steven Rostedt @ 2026-01-27 21:36 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: linux-kernel, linux-trace-kernel, linux-perf-users,
	Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers, Andrew Morton,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Namhyung Kim, Alexander Shishkin, Jiri Olsa, Ian Rogers,
	Adrian Hunter, Thomas Gleixner
In-Reply-To: <402e0322-bc2d-441f-8969-fc643dfaff06@roeck-us.net>

On Tue, 27 Jan 2026 11:07:05 -0800
Guenter Roeck <linux@roeck-us.net> wrote:

> Trying. So far I can no longer reproduce the problem with the patch below applied.
> Obviously that doesn't mean that the problem is fixed, only that I can no longer
> reproduce it. I'll keep trying with different platforms.

Well, the revert of the patch just replaces the flags test with a test for
current->mm being NULL. This patch simply makes all those locations test
both the flags and for current->mm being NULL.

I can't see how it doesn't fix it.

Anyway, I'll start making this into a legitimate patch.

Thanks,

-- Steve

^ permalink raw reply

* Re: [RESEND][PATCH 3/5] perf: Use current->flags & PF_KTHREAD|PF_USER_WORKER instead of current->mm == NULL
From: Guenter Roeck @ 2026-01-27 19:07 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, linux-trace-kernel, linux-perf-users,
	Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers, Andrew Morton,
	Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
	Namhyung Kim, Alexander Shishkin, Jiri Olsa, Ian Rogers,
	Adrian Hunter, Thomas Gleixner
In-Reply-To: <20260127102234.755d8c4e@gandalf.local.home>

Hi Steven,

On 1/27/26 07:22, Steven Rostedt wrote:
> On Mon, 26 Jan 2026 17:32:35 -0800
> Guenter Roeck <linux@roeck-us.net> wrote:
> 
>> Still crashing, though not as often and with a slightly different backtrace.
>> I added the backtrace to the bug report @ Google.
> 
> I figured there would be other locations. A while ago I had a patch to wrap
> the checks in a "is_user_thread()" helper function[1], but Ingo had issues
> with it. It seems now it's biting us in the butt and let's see if it would
> help now. I modified it slightly.
> 
> [1] https://lore.kernel.org/linux-trace-kernel/20250425204313.616425861@goodmis.org/
> 
> If the below fixes it, I'll resend it, but now as a real bug fix.
> 

Trying. So far I can no longer reproduce the problem with the patch below applied.
Obviously that doesn't mean that the problem is fixed, only that I can no longer
reproduce it. I'll keep trying with different platforms.

Guenter

> -- Steve
> 
> diff --git a/include/linux/sched.h b/include/linux/sched.h
> index da0133524d08..5f00b5ed0f3b 100644
> --- a/include/linux/sched.h
> +++ b/include/linux/sched.h
> @@ -1776,6 +1776,11 @@ static __always_inline bool is_percpu_thread(void)
>   		(current->nr_cpus_allowed  == 1);
>   }
>   
> +static __always_inline bool is_user_task(struct task_struct *task)
> +{
> +	return task->mm && !(task->flags & (PF_KTHREAD | PF_USER_WORKER));
> +}
> +
>   /* Per-process atomic flags. */
>   #define PFA_NO_NEW_PRIVS		0	/* May not gain new privileges. */
>   #define PFA_SPREAD_PAGE			1	/* Spread page cache over cpuset */
> diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c
> index 1f6589578703..9d24b6e0c91f 100644
> --- a/kernel/events/callchain.c
> +++ b/kernel/events/callchain.c
> @@ -246,7 +246,7 @@ get_perf_callchain(struct pt_regs *regs, bool kernel, bool user,
>   
>   	if (user && !crosstask) {
>   		if (!user_mode(regs)) {
> -			if (current->flags & (PF_KTHREAD | PF_USER_WORKER))
> +			if (!is_user_task(current))
>   				goto exit_put;
>   			regs = task_pt_regs(current);
>   		}
> diff --git a/kernel/events/core.c b/kernel/events/core.c
> index a0fa488bce84..8cca80094624 100644
> --- a/kernel/events/core.c
> +++ b/kernel/events/core.c
> @@ -7460,7 +7460,7 @@ static void perf_sample_regs_user(struct perf_regs *regs_user,
>   	if (user_mode(regs)) {
>   		regs_user->abi = perf_reg_abi(current);
>   		regs_user->regs = regs;
> -	} else if (!(current->flags & (PF_KTHREAD | PF_USER_WORKER))) {
> +	} else if (is_user_task(current)) {
>   		perf_get_regs_user(regs_user, regs);
>   	} else {
>   		regs_user->abi = PERF_SAMPLE_REGS_ABI_NONE;
> @@ -8100,7 +8100,7 @@ static u64 perf_virt_to_phys(u64 virt)
>   		 * Try IRQ-safe get_user_page_fast_only first.
>   		 * If failed, leave phys_addr as 0.
>   		 */
> -		if (!(current->flags & (PF_KTHREAD | PF_USER_WORKER))) {
> +		if (is_user_task(current)) {
>   			struct page *p;
>   
>   			pagefault_disable();
> @@ -8215,7 +8215,7 @@ perf_callchain(struct perf_event *event, struct pt_regs *regs)
>   {
>   	bool kernel = !event->attr.exclude_callchain_kernel;
>   	bool user   = !event->attr.exclude_callchain_user &&
> -		!(current->flags & (PF_KTHREAD | PF_USER_WORKER));
> +		is_user_task(current);
>   	/* Disallow cross-task user callchains. */
>   	bool crosstask = event->ctx->task && event->ctx->task != current;
>   	bool defer_user = IS_ENABLED(CONFIG_UNWIND_USER) && user &&


^ permalink raw reply

* Re: [PATCH 2/2] rust_binder: add binder_transaction tracepoint
From: Carlos Llamas @ 2026-01-27 18:31 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: Greg Kroah-Hartman, Steven Rostedt, Masami Hiramatsu,
	Mathieu Desnoyers, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Trevor Gross, Danilo Krummrich, Arve Hjønnevåg,
	Todd Kjos, Martijn Coenen, Joel Fernandes, Christian Brauner,
	Suren Baghdasaryan, rust-for-linux, linux-trace-kernel,
	linux-kernel
In-Reply-To: <20251203-binder-trace1-v1-2-22d3ffddb44e@google.com>

On Wed, Dec 03, 2025 at 02:48:09PM +0000, Alice Ryhl wrote:
> This patch adds the binder_transaction tracepoint to Rust Binder. This
> was chosen as the next tracepoint to add as it is the most complex
> tracepoint. (And it's also an important tracepoint known to perfetto.)
> 
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> ---

This approach seems to work well considering the limitations. I wonder
though if it would be more practical to simply pass the individual
primitive values used by TP_prinkt() from the start? I suppose the
downside would be the extra overhead with the tracepoints disabled.
However, this might be neglectable and the solution much simpler?

> +static inline rust_binder_node rust_binder_transaction_target_node(rust_binder_transaction t)
> +{
> +	void *p = *(void **) (t + RUST_BINDER_LAYOUT.t.target_node);
> +
> +	if (p)
> +		p = p + RUST_BINDER_LAYOUT.n.arc_offset;
> +	return NULL;

It looks like this should have 'return p' right? Sorry for the late
review this has been picked up so we might need a fixes for this.

--
Carlos Llamas

^ permalink raw reply

* [RFC PATCH v1 1/5] unwind_user: Enable arch-specific signal frame unwinders
From: Jens Remus @ 2026-01-27 15:33 UTC (permalink / raw)
  To: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
	Steven Rostedt
  Cc: Jens Remus, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
	Josh Poimboeuf, Masami Hiramatsu, Mathieu Desnoyers,
	Peter Zijlstra, Ingo Molnar, Jiri Olsa, Arnaldo Carvalho de Melo,
	Namhyung Kim, Thomas Gleixner, Andrii Nakryiko, Indu Bhagat,
	Jose E. Marchesi, Beau Belgrave, Linus Torvalds, Andrew Morton,
	Florian Weimer, Kees Cook, Carlos O'Donell, Sam James,
	Dylan Hatch
In-Reply-To: <20260127153331.2902504-1-jremus@linux.ibm.com>

Add a signal flag to struct unwind_user_frame, which indicates whether
the frame is a signal frame.  If set unwind_user_common_next() uses an
architecture-specific unwind_user_signal_next() implementation to
unwind the frame.

user unwind sframe will make use of the signal flag in a subsequent
commit.

Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
 arch/x86/include/asm/unwind_user.h | 6 ++++--
 include/linux/unwind_user.h        | 9 +++++++++
 include/linux/unwind_user_types.h  | 1 +
 kernel/unwind/user.c               | 4 ++++
 4 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/unwind_user.h b/arch/x86/include/asm/unwind_user.h
index f5e9fbcdae28..21cb9eeb2503 100644
--- a/arch/x86/include/asm/unwind_user.h
+++ b/arch/x86/include/asm/unwind_user.h
@@ -67,7 +67,8 @@ static inline int unwind_user_get_reg(unsigned long *val, unsigned int regnum)
 		.offset		= -2*(ws),		\
 			},				\
 	.sp_off		= 0,				\
-	.outermost	= false,
+	.outermost	= false,			\
+	.signal		= false,
 
 #define ARCH_INIT_USER_FP_ENTRY_FRAME(ws)		\
 	.cfa		= {				\
@@ -82,7 +83,8 @@ static inline int unwind_user_get_reg(unsigned long *val, unsigned int regnum)
 		.rule		= UNWIND_USER_RULE_RETAIN,\
 			},				\
 	.sp_off		= 0,				\
-	.outermost	= false,
+	.outermost	= false,			\
+	.signal		= false,
 
 static inline int unwind_user_fp_get_frame(struct unwind_user_state *state,
 					   struct unwind_user_frame *frame)
diff --git a/include/linux/unwind_user.h b/include/linux/unwind_user.h
index f65b0573b3a5..eb5de4cb5bd6 100644
--- a/include/linux/unwind_user.h
+++ b/include/linux/unwind_user.h
@@ -34,6 +34,15 @@ static inline int unwind_user_get_reg(unsigned long *val, unsigned int regnum)
 #define unwind_user_get_reg unwind_user_get_reg
 #endif
 
+#ifndef unwind_user_signal_next
+static inline int unwind_user_signal_next(struct unwind_user_state *state)
+{
+	WARN_ON_ONCE(1);
+	return -EINVAL;
+}
+#define unwind_user_signal_next unwind_user_signal_next
+#endif
+
 int unwind_user(struct unwind_stacktrace *trace, unsigned int max_entries);
 
 #endif /* _LINUX_UNWIND_USER_H */
diff --git a/include/linux/unwind_user_types.h b/include/linux/unwind_user_types.h
index fac8f470b597..3985706d7851 100644
--- a/include/linux/unwind_user_types.h
+++ b/include/linux/unwind_user_types.h
@@ -68,6 +68,7 @@ struct unwind_user_frame {
 	struct unwind_user_rule_data fp;
 	s32 sp_off;
 	bool outermost;
+	bool signal;
 };
 
 struct unwind_user_state {
diff --git a/kernel/unwind/user.c b/kernel/unwind/user.c
index a64ceb4a2bf6..b9a3b59e8282 100644
--- a/kernel/unwind/user.c
+++ b/kernel/unwind/user.c
@@ -32,6 +32,10 @@ static int unwind_user_next_common(struct unwind_user_state *state,
 {
 	unsigned long cfa, sp, fp, ra;
 
+	/* Use signal frame unwinder for signal frames. */
+	if (frame->signal)
+		return unwind_user_signal_next(state);
+
 	/* Stop unwinding when reaching an outermost frame. */
 	if (frame->outermost) {
 		state->done = true;
-- 
2.51.0


^ permalink raw reply related

* [RFC PATCH v1 2/5] unwind_user/sframe: Add support for signal frame indication
From: Jens Remus @ 2026-01-27 15:33 UTC (permalink / raw)
  To: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
	Steven Rostedt
  Cc: Jens Remus, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
	Josh Poimboeuf, Masami Hiramatsu, Mathieu Desnoyers,
	Peter Zijlstra, Ingo Molnar, Jiri Olsa, Arnaldo Carvalho de Melo,
	Namhyung Kim, Thomas Gleixner, Andrii Nakryiko, Indu Bhagat,
	Jose E. Marchesi, Beau Belgrave, Linus Torvalds, Andrew Morton,
	Florian Weimer, Kees Cook, Carlos O'Donell, Sam James,
	Dylan Hatch
In-Reply-To: <20260127153331.2902504-1-jremus@linux.ibm.com>

SFrame V3 represents the assembler directive .cfi_signal_frame using
a SFrame FDE flag.  Note that a SFrame FDE with this particular flag set
may have no SFrame FREs.

Introduce a SFRAME_V3_FDE_SIGNAL_P() helper macro.  Use it in
__find_fre() to populate the signal flag in struct unwind_user_frame,
even if there are no FREs.

Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
 kernel/unwind/sframe.c | 8 +++++++-
 kernel/unwind/sframe.h | 1 +
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/kernel/unwind/sframe.c b/kernel/unwind/sframe.c
index 21283e3bda42..9fd2fc1572cc 100644
--- a/kernel/unwind/sframe.c
+++ b/kernel/unwind/sframe.c
@@ -446,6 +446,7 @@ static __always_inline int __find_fre(struct sframe_section *sec,
 				      struct unwind_user_frame *frame)
 {
 	unsigned char fde_pctype = SFRAME_V3_FDE_PCTYPE(fde->info);
+	bool signal = SFRAME_V3_FDE_SIGNAL_P(fde->info);
 	struct sframe_fre_internal *fre, *prev_fre = NULL;
 	struct sframe_fre_internal fres[2];
 	unsigned long fre_addr;
@@ -486,8 +487,11 @@ static __always_inline int __find_fre(struct sframe_section *sec,
 		prev_fre = fre;
 	}
 
-	if (!prev_fre)
+	if (!prev_fre) {
+		if (signal)
+			goto signal;
 		return -EINVAL;
+	}
 	fre = prev_fre;
 
 	ret = __read_fre_datawords(sec, fde, fre);
@@ -500,6 +504,8 @@ static __always_inline int __find_fre(struct sframe_section *sec,
 	sframe_init_rule_data(&frame->fp, fre->fp_ctl, fre->fp_off);
 	frame->sp_off  = SFRAME_SP_OFFSET;
 	frame->outermost = SFRAME_V3_FRE_RA_UNDEFINED_P(fre->info);
+signal:
+	frame->signal = signal;
 
 	return 0;
 }
diff --git a/kernel/unwind/sframe.h b/kernel/unwind/sframe.h
index 8a5322e95403..78432857f84c 100644
--- a/kernel/unwind/sframe.h
+++ b/kernel/unwind/sframe.h
@@ -65,6 +65,7 @@ struct sframe_fda_v3 {
 #define SFRAME_V3_FDE_FRE_TYPE(info)		((info) & 0xf)
 #define SFRAME_V3_FDE_PCTYPE(info)		(((info) >> 4) & 0x1)
 #define SFRAME_V3_AARCH64_FDE_PAUTH_KEY(info)	(((info) >> 5) & 0x1)
+#define SFRAME_V3_FDE_SIGNAL_P(info)		(((info) >> 7) & 0x1)
 
 #define SFRAME_FDE_TYPE_REGULAR			0
 #define SFRAME_FDE_TYPE_FLEXIBLE		1
-- 
2.51.0


^ permalink raw reply related

* [RFC PATCH v1 4/5] s390/signal: Move struct [rt_]sigframe to asm/sigframe.h
From: Jens Remus @ 2026-01-27 15:33 UTC (permalink / raw)
  To: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
	Steven Rostedt
  Cc: Jens Remus, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
	Josh Poimboeuf, Masami Hiramatsu, Mathieu Desnoyers,
	Peter Zijlstra, Ingo Molnar, Jiri Olsa, Arnaldo Carvalho de Melo,
	Namhyung Kim, Thomas Gleixner, Andrii Nakryiko, Indu Bhagat,
	Jose E. Marchesi, Beau Belgrave, Linus Torvalds, Andrew Morton,
	Florian Weimer, Kees Cook, Carlos O'Donell, Sam James,
	Dylan Hatch
In-Reply-To: <20260127153331.2902504-1-jremus@linux.ibm.com>

This enables use of struct sigframe and struct rt_sigframe elsewhere,
such as unwind user.

Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
 arch/s390/include/asm/sigframe.h | 78 ++++++++++++++++++++++++++++++++
 arch/s390/kernel/signal.c        | 71 +----------------------------
 2 files changed, 79 insertions(+), 70 deletions(-)
 create mode 100644 arch/s390/include/asm/sigframe.h

diff --git a/arch/s390/include/asm/sigframe.h b/arch/s390/include/asm/sigframe.h
new file mode 100644
index 000000000000..7539fd802675
--- /dev/null
+++ b/arch/s390/include/asm/sigframe.h
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0
+#ifndef _ASM_S390_SIGFRAME_H
+#define _ASM_S390_SIGFRAME_H
+
+#include <uapi/asm/sigcontext.h>
+#include <asm/ucontext.h>
+
+/*
+ * Layout of an old-style signal-frame:
+ *	-----------------------------------------
+ *	| save area (_SIGNAL_FRAMESIZE)		|
+ *	-----------------------------------------
+ *	| struct sigcontext			|
+ *	|	oldmask				|
+ *	|	_sigregs *			|
+ *	-----------------------------------------
+ *	| _sigregs with				|
+ *	|	_s390_regs_common		|
+ *	|	_s390_fp_regs			|
+ *	-----------------------------------------
+ *	| int signo				|
+ *	-----------------------------------------
+ *	| _sigregs_ext with			|
+ *	|	gprs_high 64 byte (opt)		|
+ *	|	vxrs_low 128 byte (opt)		|
+ *	|	vxrs_high 256 byte (opt)	|
+ *	|	reserved 128 byte (opt)		|
+ *	-----------------------------------------
+ *	| __u16 svc_insn			|
+ *	-----------------------------------------
+ * The svc_insn entry with the sigreturn system call opcode does not
+ * have a fixed position and moves if gprs_high or vxrs exist.
+ * Future extensions will be added to _sigregs_ext.
+ */
+struct sigframe
+{
+	__u8 callee_used_stack[__SIGNAL_FRAMESIZE];
+	struct sigcontext sc;
+	_sigregs sregs;
+	int signo;
+	_sigregs_ext sregs_ext;
+	__u16 svc_insn;		/* Offset of svc_insn is NOT fixed! */
+};
+
+/*
+ * Layout of an rt signal-frame:
+ *	-----------------------------------------
+ *	| save area (_SIGNAL_FRAMESIZE)		|
+ *	-----------------------------------------
+ *	| svc __NR_rt_sigreturn 2 byte		|
+ *	-----------------------------------------
+ *	| struct siginfo			|
+ *	-----------------------------------------
+ *	| struct ucontext_extended with		|
+ *	|	unsigned long uc_flags		|
+ *	|	struct ucontext *uc_link	|
+ *	|	stack_t uc_stack		|
+ *	|	_sigregs uc_mcontext with	|
+ *	|		_s390_regs_common	|
+ *	|		_s390_fp_regs		|
+ *	|	sigset_t uc_sigmask		|
+ *	|	_sigregs_ext uc_mcontext_ext	|
+ *	|		gprs_high 64 byte (opt)	|
+ *	|		vxrs_low 128 byte (opt)	|
+ *	|		vxrs_high 256 byte (opt)|
+ *	|		reserved 128 byte (opt)	|
+ *	-----------------------------------------
+ * Future extensions will be added to _sigregs_ext.
+ */
+struct rt_sigframe
+{
+	__u8 callee_used_stack[__SIGNAL_FRAMESIZE];
+	__u16 svc_insn;
+	struct siginfo info;
+	struct ucontext_extended uc;
+};
+
+#endif /* _ASM_S390_SIGFRAME_H */
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index 4874de5edea0..42675066399f 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -32,78 +32,9 @@
 #include <asm/vdso-symbols.h>
 #include <asm/access-regs.h>
 #include <asm/lowcore.h>
+#include <asm/sigframe.h>
 #include "entry.h"
 
-/*
- * Layout of an old-style signal-frame:
- *	-----------------------------------------
- *	| save area (_SIGNAL_FRAMESIZE)		|
- *	-----------------------------------------
- *	| struct sigcontext			|
- *	|	oldmask				|
- *	|	_sigregs *			|
- *	-----------------------------------------
- *	| _sigregs with				|
- *	|	_s390_regs_common		|
- *	|	_s390_fp_regs			|
- *	-----------------------------------------
- *	| int signo				|
- *	-----------------------------------------
- *	| _sigregs_ext with			|
- *	|	gprs_high 64 byte (opt)		|
- *	|	vxrs_low 128 byte (opt)		|
- *	|	vxrs_high 256 byte (opt)	|
- *	|	reserved 128 byte (opt)		|
- *	-----------------------------------------
- *	| __u16 svc_insn			|
- *	-----------------------------------------
- * The svc_insn entry with the sigreturn system call opcode does not
- * have a fixed position and moves if gprs_high or vxrs exist.
- * Future extensions will be added to _sigregs_ext.
- */
-struct sigframe
-{
-	__u8 callee_used_stack[__SIGNAL_FRAMESIZE];
-	struct sigcontext sc;
-	_sigregs sregs;
-	int signo;
-	_sigregs_ext sregs_ext;
-	__u16 svc_insn;		/* Offset of svc_insn is NOT fixed! */
-};
-
-/*
- * Layout of an rt signal-frame:
- *	-----------------------------------------
- *	| save area (_SIGNAL_FRAMESIZE)		|
- *	-----------------------------------------
- *	| svc __NR_rt_sigreturn 2 byte		|
- *	-----------------------------------------
- *	| struct siginfo			|
- *	-----------------------------------------
- *	| struct ucontext_extended with		|
- *	|	unsigned long uc_flags		|
- *	|	struct ucontext *uc_link	|
- *	|	stack_t uc_stack		|
- *	|	_sigregs uc_mcontext with	|
- *	|		_s390_regs_common	|
- *	|		_s390_fp_regs		|
- *	|	sigset_t uc_sigmask		|
- *	|	_sigregs_ext uc_mcontext_ext	|
- *	|		gprs_high 64 byte (opt)	|
- *	|		vxrs_low 128 byte (opt)	|
- *	|		vxrs_high 256 byte (opt)|
- *	|		reserved 128 byte (opt)	|
- *	-----------------------------------------
- * Future extensions will be added to _sigregs_ext.
- */
-struct rt_sigframe
-{
-	__u8 callee_used_stack[__SIGNAL_FRAMESIZE];
-	__u16 svc_insn;
-	struct siginfo info;
-	struct ucontext_extended uc;
-};
-
 /* Store registers needed to create the signal frame */
 static void store_sigregs(void)
 {
-- 
2.51.0


^ permalink raw reply related

* [RFC PATCH v1 5/5] s390/unwind_user: Enable signal frame unwinding of user space
From: Jens Remus @ 2026-01-27 15:33 UTC (permalink / raw)
  To: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
	Steven Rostedt
  Cc: Jens Remus, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
	Josh Poimboeuf, Masami Hiramatsu, Mathieu Desnoyers,
	Peter Zijlstra, Ingo Molnar, Jiri Olsa, Arnaldo Carvalho de Melo,
	Namhyung Kim, Thomas Gleixner, Andrii Nakryiko, Indu Bhagat,
	Jose E. Marchesi, Beau Belgrave, Linus Torvalds, Andrew Morton,
	Florian Weimer, Kees Cook, Carlos O'Donell, Sam James,
	Dylan Hatch
In-Reply-To: <20260127153331.2902504-1-jremus@linux.ibm.com>

Provide a s390-specific implementation of unwind_user_signal_next(),
that unwinds from a (RT) signal frame.

Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
 arch/s390/include/asm/unwind_user.h | 57 +++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/arch/s390/include/asm/unwind_user.h b/arch/s390/include/asm/unwind_user.h
index a7b97ea01c26..8f5524a24ae1 100644
--- a/arch/s390/include/asm/unwind_user.h
+++ b/arch/s390/include/asm/unwind_user.h
@@ -7,6 +7,7 @@
 #include <linux/types.h>
 #include <asm/asm-offsets.h>
 #include <asm/fpu.h>
+#include <asm/sigframe.h>
 #include <asm/stacktrace.h>
 #include <linux/unwind_user_types.h>
 
@@ -67,6 +68,62 @@ static inline int arch_unwind_user_get_reg(unsigned long *val,
 }
 #define unwind_user_get_reg arch_unwind_user_get_reg
 
+#define SVC_OPCODE		0x0a
+#define INSN_SVC_SIGRETURN	((SVC_OPCODE << 8) | __NR_sigreturn)
+#define INSN_SVC_RT_SIGRETURN	((SVC_OPCODE << 8) | __NR_rt_sigreturn)
+
+static inline int unwind_user_signal_next(struct unwind_user_state *state)
+{
+	unsigned short insn;
+	const _sigregs __user *sr;
+	unsigned long sp, fp, ra;
+
+	/* ABI requires IP to be 2-byte aligned. */
+	if (state->ip & 1)
+		return -EINVAL;
+
+	if (__get_user(insn, (unsigned short __user *)state->ip))
+		return -EINVAL;
+
+	/*
+	 * A signal frame has the instruction pointer pointing to
+	 * svc $__NR_sigreturn or svc $__NR_rt_sigreturn
+	 */
+	switch (insn) {
+	case INSN_SVC_SIGRETURN:
+		/* New-style non-RT frame.  */
+		const struct sigframe __user *sf;
+
+		sf = (struct sigframe __user *)state->sp;
+		if (__get_user(sr, (_sigregs __user **)&sf->sc.sregs))
+			return -EINVAL;
+		break;
+	case INSN_SVC_RT_SIGRETURN:
+		/* New-style RT frame.  */
+		const struct rt_sigframe __user *rt_sf;
+
+		rt_sf = (struct rt_sigframe __user *)state->sp;
+		sr = (_sigregs __user *)&rt_sf->uc.uc_mcontext;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (__get_user(sp, (unsigned long __user *)&sr->regs.gprs[15]))
+		return -EINVAL;
+	if (__get_user(fp, (unsigned long __user *)&sr->regs.gprs[11]))
+		return -EINVAL;
+	if (__get_user(ra, (unsigned long __user *)&sr->regs.psw.addr))
+		return -EINVAL;
+
+	state->ip = ra;
+	state->sp = sp;
+	state->fp = fp;
+	state->topmost = false;
+	return 0;
+}
+#define unwind_user_signal_next unwind_user_signal_next
+
 #endif /* CONFIG_UNWIND_USER */
 
 #ifdef CONFIG_HAVE_UNWIND_USER_FP
-- 
2.51.0


^ permalink raw reply related

* [RFC PATCH v1 0/5] s390: Signal frame user space unwinding
From: Jens Remus @ 2026-01-27 15:33 UTC (permalink / raw)
  To: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
	Steven Rostedt
  Cc: Jens Remus, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
	Josh Poimboeuf, Masami Hiramatsu, Mathieu Desnoyers,
	Peter Zijlstra, Ingo Molnar, Jiri Olsa, Arnaldo Carvalho de Melo,
	Namhyung Kim, Thomas Gleixner, Andrii Nakryiko, Indu Bhagat,
	Jose E. Marchesi, Beau Belgrave, Linus Torvalds, Andrew Morton,
	Florian Weimer, Kees Cook, Carlos O'Donell, Sam James,
	Dylan Hatch

This RFC series adds s390 support for unwinding of signal frames in user
space using SFrame V3's indication of signal frames.


Prerequirements:

This series applies on top of the latest unwind user sframe s390 series
"[PATCH v4 00/12] s390: SFrame user space unwinding":
https://lore.kernel.org/all/20260127151926.2805123-1-jremus@linux.ibm.com/

on top of the latest unwind user sframe series
"[PATCH v13 00/18] unwind_deferred: Implement sframe handling":
https://lore.kernel.org/all/20260127150554.2760964-1-jremus@linux.ibm.com/

Like above series it depends on the upcoming binutils 2.46 release to
be used to build executables and libraries (e.g. vDSO) with SFrame V3
on s390 (using the assembler option --gsframe-3).


Overview:

Patches 1 and 2 enables the common unwind user (sframe) frameworks to
support signal frames:

- Patch 1 enables unwind user to resort to an architecture-specific
  signal frame unwinder, if a frame is a signal frame.

- Patch 2 adds support to unwind user sframe to provide the signal
  frame indication represented in SFrame V3.

Patch 3 annotates the s390 vDSO functions __kernel_[rt_]sigreturn()
as signal frames.

Patch 4 moves the s390 struct [rt_]sigframe to asm/sigframe.h so that
it can be used in unwind user.

Patch 5 enables signal frame unwinding in user space on s390.

Regards,
Jens


Jens Remus (5):
  unwind_user: Enable arch-specific signal frame unwinders
  unwind_user/sframe: Add support for signal frame indication
  s390/vdso: Annotate __kernel_[rt_]sigreturn as signal frames
  s390/signal: Move struct [rt_]sigframe to asm/sigframe.h
  s390/unwind_user: Enable signal frame unwinding of user space

 arch/s390/include/asm/dwarf.h             |  3 +
 arch/s390/include/asm/sigframe.h          | 78 +++++++++++++++++++++++
 arch/s390/include/asm/unwind_user.h       | 57 +++++++++++++++++
 arch/s390/kernel/signal.c                 | 71 +--------------------
 arch/s390/kernel/vdso/vdso_user_wrapper.S | 15 ++++-
 arch/x86/include/asm/unwind_user.h        |  6 +-
 include/linux/unwind_user.h               |  9 +++
 include/linux/unwind_user_types.h         |  1 +
 kernel/unwind/sframe.c                    |  8 ++-
 kernel/unwind/sframe.h                    |  1 +
 kernel/unwind/user.c                      |  4 ++
 11 files changed, 178 insertions(+), 75 deletions(-)
 create mode 100644 arch/s390/include/asm/sigframe.h

-- 
2.51.0


^ permalink raw reply

* [RFC PATCH v1 3/5] s390/vdso: Annotate __kernel_[rt_]sigreturn as signal frames
From: Jens Remus @ 2026-01-27 15:33 UTC (permalink / raw)
  To: linux-kernel, linux-trace-kernel, linux-s390, bpf, x86,
	Steven Rostedt
  Cc: Jens Remus, Heiko Carstens, Vasily Gorbik, Ilya Leoshkevich,
	Josh Poimboeuf, Masami Hiramatsu, Mathieu Desnoyers,
	Peter Zijlstra, Ingo Molnar, Jiri Olsa, Arnaldo Carvalho de Melo,
	Namhyung Kim, Thomas Gleixner, Andrii Nakryiko, Indu Bhagat,
	Jose E. Marchesi, Beau Belgrave, Linus Torvalds, Andrew Morton,
	Florian Weimer, Kees Cook, Carlos O'Donell, Sam James,
	Dylan Hatch
In-Reply-To: <20260127153331.2902504-1-jremus@linux.ibm.com>

The GNU assembler supports CFI directive .cfi_signal_frame with
binutils 2.17+.  Use it to annotate the vDSO functions
__kernel_sigreturn() and __kernel_rt_sigreturn() as signal
frames.

This enables generation of SFrame stack trace information for the
vDSO to likewise annotate these functions for use in stack tracers,
such as the kernel unwind user sframe.

Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
 arch/s390/include/asm/dwarf.h             |  3 +++
 arch/s390/kernel/vdso/vdso_user_wrapper.S | 15 +++++++++++++--
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/arch/s390/include/asm/dwarf.h b/arch/s390/include/asm/dwarf.h
index 2f148b15fd7d..e5663d6b11db 100644
--- a/arch/s390/include/asm/dwarf.h
+++ b/arch/s390/include/asm/dwarf.h
@@ -35,6 +35,8 @@
 #define CFI_VAL_OFFSET		nocfi
 #endif
 
+#define CFI_SIGNAL_FRAME	.cfi_signal_frame
+
 #else /* !BUILD_VDSO */
 
 /*
@@ -49,6 +51,7 @@
 #define CFI_RESTORE		nocfi
 #define CFI_REL_OFFSET		nocfi
 #define CFI_VAL_OFFSET		nocfi
+#define CFI_SIGNAL_FRAME	nocfi
 
 #endif /* !BUILD_VDSO */
 
diff --git a/arch/s390/kernel/vdso/vdso_user_wrapper.S b/arch/s390/kernel/vdso/vdso_user_wrapper.S
index aa06c85bcbd3..757503929ab0 100644
--- a/arch/s390/kernel/vdso/vdso_user_wrapper.S
+++ b/arch/s390/kernel/vdso/vdso_user_wrapper.S
@@ -47,6 +47,17 @@ SYM_FUNC_START(__kernel_\func)
 SYM_FUNC_END(__kernel_\func)
 .endm
 
+.macro vdso_syscall_sf func,syscall
+SYM_FUNC_START(__kernel_\func)
+	CFI_STARTPROC simple
+	CFI_SIGNAL_FRAME
+	svc	\syscall
+	/* Trap, if syscall returns, which shouldn't happen */
+	.insn e,0x0000
+	CFI_ENDPROC
+SYM_FUNC_END(__kernel_\func)
+.endm
+
 vdso_syscall restart_syscall,__NR_restart_syscall
-vdso_syscall sigreturn,__NR_sigreturn
-vdso_syscall rt_sigreturn,__NR_rt_sigreturn
+vdso_syscall_sf sigreturn,__NR_sigreturn
+vdso_syscall_sf rt_sigreturn,__NR_rt_sigreturn
-- 
2.51.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox