Linux Trace Kernel
 help / color / mirror / Atom feed
* [PATCH] tracing: Up the hist stacktrace size from 16 to 31
From: Steven Rostedt @ 2026-01-23 15:54 UTC (permalink / raw)
  To: LKML, Linux Trace Kernel; +Cc: Masami Hiramatsu, Mathieu Desnoyers, Tom Zanussi

From: Steven Rostedt <rostedt@goodmis.org>

Recording stacktraces is very useful, but the size of 16 deep is very
restrictive. For example, in seeing where tasks schedule out in a non
running state, the following can be used:

 ~# cd /sys/kernel/tracing
 ~# echo 'hist:keys=common_stacktrace:vals=hitcount if prev_state & 3' > events/sched/sched_switch/trigger
 ~# cat events/sched/sched_switch/hist
[..]
{ common_stacktrace:
         __schedule+0xdc0/0x1860
         schedule+0x27/0xd0
         schedule_timeout+0xb5/0x100
         wait_for_completion+0x8a/0x140
         xfs_buf_iowait+0x20/0xd0 [xfs]
         xfs_buf_read_map+0x103/0x250 [xfs]
         xfs_trans_read_buf_map+0x161/0x310 [xfs]
         xfs_btree_read_buf_block+0xa0/0x120 [xfs]
         xfs_btree_lookup_get_block+0xa3/0x1e0 [xfs]
         xfs_btree_lookup+0xea/0x530 [xfs]
         xfs_alloc_fixup_trees+0x72/0x570 [xfs]
         xfs_alloc_ag_vextent_size+0x67f/0x800 [xfs]
         xfs_alloc_vextent_iterate_ags.constprop.0+0x52/0x230 [xfs]
         xfs_alloc_vextent_start_ag+0x9d/0x1b0 [xfs]
         xfs_bmap_btalloc+0x2af/0x680 [xfs]
         xfs_bmapi_allocate+0xdb/0x2c0 [xfs]
} hitcount:          1
[..]

The above stops at 16 functions where knowing more would be useful. As the
allocated storage for stacks is the same for strings, and that size is 256
bytes, there is a lot of space not being used for stacktraces.

 16 * 8 = 128

Up the size to 31 (it requires the last slot to be zero, so it can't be 32).

Also change the BUILD_BUG_ON() to allow the size of the stacktrace storage
to be equal to the max size. It already accounts for the empty slot via
a "+ 1":

  BUILD_BUG_ON((HIST_STACKTRACE_DEPTH + 1) * sizeof(long) >= STR_VAR_LEN_MAX);

Change that from ">=" to just ">", as now they are equal.

Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
 kernel/trace/trace.h             | 2 +-
 kernel/trace/trace_events_hist.c | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 8888fc9335b6..69e7defba6c6 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -128,7 +128,7 @@ enum trace_type {
 
 #define FAULT_STRING "(fault)"
 
-#define HIST_STACKTRACE_DEPTH	16
+#define HIST_STACKTRACE_DEPTH	31
 #define HIST_STACKTRACE_SIZE	(HIST_STACKTRACE_DEPTH * sizeof(unsigned long))
 #define HIST_STACKTRACE_SKIP	5
 
diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
index 24441b30a1a4..dfb7c4754bf8 100644
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -3154,7 +3154,7 @@ static inline void __update_field_vars(struct tracing_map_elt *elt,
 	u64 var_val;
 
 	/* Make sure stacktrace can fit in the string variable length */
-	BUILD_BUG_ON((HIST_STACKTRACE_DEPTH + 1) * sizeof(long) >= STR_VAR_LEN_MAX);
+	BUILD_BUG_ON((HIST_STACKTRACE_DEPTH + 1) * sizeof(long) > STR_VAR_LEN_MAX);
 
 	for (i = 0, j = field_var_str_start; i < n_field_vars; i++) {
 		struct field_var *field_var = field_vars[i];
-- 
2.51.0


^ permalink raw reply related

* [RFC PATCH 3/3] rtla/timerlat: Attach BPF program before tracers
From: Tomas Glozar @ 2026-01-23 15:25 UTC (permalink / raw)
  To: Steven Rostedt, Masami Hiramatsu
  Cc: Mathieu Desnoyers, Crystal Wood, John Kacur, Luis Goncalves, LKML,
	Linux Trace Kernel, Tomas Glozar
In-Reply-To: <20260123152534.1036533-1-tglozar@redhat.com>

If osnoise:timerlat_sample has instance count fields, attach the BPF program
before starting trace instances in BPF/mixed mode.

This ensures that what is seen by BPF sample collection is exactly what
is seen by the last enabled tracefs instance.

Signed-off-by: Tomas Glozar <tglozar@redhat.com>
---
 tools/tracing/rtla/src/timerlat.c | 25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/tools/tracing/rtla/src/timerlat.c b/tools/tracing/rtla/src/timerlat.c
index 069f916100e7..da2e2d003ec9 100644
--- a/tools/tracing/rtla/src/timerlat.c
+++ b/tools/tracing/rtla/src/timerlat.c
@@ -170,6 +170,21 @@ int timerlat_enable(struct osnoise_tool *tool)
 			return -1;
 	}
 
+	if (params->mode != TRACING_MODE_TRACEFS && params->has_instance_count_fields) {
+		/*
+		 * If the timerlat tracer has instance count fields, it is safe
+		 * to attach the BPF program before starting the trace instances.
+		 *
+		 * The BPF program will ignore any samples that arrive before
+		 * the trace instances are started.
+		 */
+		retval = timerlat_bpf_attach();
+		if (retval) {
+			err_msg("Error attaching BPF program\n");
+			return retval;
+		}
+	}
+
 	/*
 	 * Start the tracers here, after having set all instances.
 	 *
@@ -183,7 +198,15 @@ int timerlat_enable(struct osnoise_tool *tool)
 		trace_instance_start(&tool->aa->trace);
 	if (params->mode == TRACING_MODE_TRACEFS) {
 		trace_instance_start(&tool->trace);
-	} else {
+	} else if (!params->has_instance_count_fields) {
+		/*
+		 * Without instance count fields, play safe and attach the BPF program
+		 * after starting the trace instances.
+		 *
+		 * This might lead to samples being seen only by trace output and
+		 * auto analysis, but it is better than RTLA reporting results over
+		 * threshold that cannot be analyzed further.
+		 */
 		retval = timerlat_bpf_attach();
 		if (retval) {
 			err_msg("Error attaching BPF program\n");
-- 
2.52.0


^ permalink raw reply related

* [RFC PATCH 0/3] rtla: Synchronize sample collection methods
From: Tomas Glozar @ 2026-01-23 15:25 UTC (permalink / raw)
  To: Steven Rostedt, Masami Hiramatsu
  Cc: Mathieu Desnoyers, Crystal Wood, John Kacur, Luis Goncalves, LKML,
	Linux Trace Kernel, Tomas Glozar

This is a proposal to synchronize the start of sample collection throughout
all places where samples are collected in RTLA, using a lockless method of
tracking the count of active tracefs instances set to the timerlat tracer.

There are three different places where timerlat samples are collected in RTLA:
two tracefs instances (auto-analysis and record), and a BPF program attached
to the osnoise:timerlat_sample tracepoint.

The BPF program collects all samples and generates the main statistics from
them in either top or hist mode, while the auto-analysis and record instances
are used as ring buffers with the intention of capturing the tail of both
timerlat samples and additional tracepoints.

In instances where BPF support is not available, the BPF program is replaced
by a third tracefs instance, called the "main instance".

One problem with this approach is each of these sample collectors is
turned on [1] separately, in the present state of RTLA, in the following order:

- record instance
- auto-analysis instance
- BPF program / main instance

[1] By "turned on", I mean toggling tracing on (for tracefs instances) or
attachment (for the BPF program). Note that timerlat starts measurement
on tracer registration, even if tracing is off by default. This might have
been originally unintentional - considering that explicitly turning off
tracing stops the measurement threads - but is now relied upon in RTLA.

This leads to some samples being seen only by tracers that are enabled
earlier, leading to confusing results. For example, auto-analysis might
show spikes that are not seen in the histogram, and trace output (record)
might show samples that are not seen by either the histogram or
auto-analysis.

To enable RTLA to analyze samples consistently, the first patch adds two fields
to the osnoise:timerlat_sample tracepoint: instances_registered and
instances_on. During the recording of a timerlat sample, timerlat counts
how many instances are registered and how many are on, and attaches
the information to the osnoise:timerlat_sample trace event, which is moved
to occur after the samples are recorded.

The second patch makes RTLA count how many tracefs instances are to be enabled
in total, passes this number to the BPF program, and makes it drop any samples
that arrive before the instances are turned on. This ensures all samples
recorded in the main statistics (e.g. histogram) are seen by all active tracefs
instances, that is, auto-analysis and trace output (record).

The third patch then moves the attachment of the BPF program before the enabling
of the tracefs instances, provided that the kernel supports instance counting
introduced in the first patch. The second patch enforces that all samples
recorded by the program are seen by the last enabled tracefs instance.

Synchronization between different tracefs instances, that is, auto-analysis and
trace output, and the main instance in non-BPF mode, is possible by looking at
the osnoise:timerlat_sample record that comes after each sample, but is not yet
implemented in the current version of the patchset.

Tomas Glozar (3):
  tracing/osnoise: Record timerlat instance counts
  rtla/timerlat_bpf: Filter samples unseen by tracer
  rtla/timerlat: Attach BPF program before tracers

 include/trace/events/osnoise.h        | 14 ++++++---
 kernel/trace/trace_osnoise.c          | 10 +++++--
 tools/tracing/rtla/src/timerlat.bpf.c |  9 ++++++
 tools/tracing/rtla/src/timerlat.c     | 43 +++++++++++++++++++++++++--
 tools/tracing/rtla/src/timerlat.h     |  2 ++
 tools/tracing/rtla/src/timerlat_bpf.c |  8 +++++
 6 files changed, 78 insertions(+), 8 deletions(-)

-- 
2.52.0


^ permalink raw reply

* [RFC PATCH 2/3] rtla/timerlat_bpf: Filter samples unseen by tracer
From: Tomas Glozar @ 2026-01-23 15:25 UTC (permalink / raw)
  To: Steven Rostedt, Masami Hiramatsu
  Cc: Mathieu Desnoyers, Crystal Wood, John Kacur, Luis Goncalves, LKML,
	Linux Trace Kernel, Tomas Glozar
In-Reply-To: <20260123152534.1036533-1-tglozar@redhat.com>

If both BPF and tracefs sample collection are used (mixed mode), drop
samples seen by BPF program when the count of timerlat instances that
are both registered and have tracing on does not match the expected value.

This ensures that there are no samples seen by BPF that are not included
in auto-analysis or trace output.

Signed-off-by: Tomas Glozar <tglozar@redhat.com>
---
 tools/tracing/rtla/src/timerlat.bpf.c |  9 +++++++++
 tools/tracing/rtla/src/timerlat.c     | 18 +++++++++++++++++-
 tools/tracing/rtla/src/timerlat.h     |  2 ++
 tools/tracing/rtla/src/timerlat_bpf.c |  8 ++++++++
 4 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/tools/tracing/rtla/src/timerlat.bpf.c b/tools/tracing/rtla/src/timerlat.bpf.c
index 549d2d2191d2..2724a9bfea4e 100644
--- a/tools/tracing/rtla/src/timerlat.bpf.c
+++ b/tools/tracing/rtla/src/timerlat.bpf.c
@@ -12,6 +12,8 @@ char LICENSE[] SEC("license") = "GPL";
 struct trace_event_raw_timerlat_sample {
 	unsigned long long timer_latency;
 	int context;
+	int instances_registered;
+	int instances_on;
 } __attribute__((preserve_access_index));
 
 struct {
@@ -58,6 +60,8 @@ const volatile int entries = 256;
 const volatile int irq_threshold;
 const volatile int thread_threshold;
 const volatile bool aa_only;
+const volatile int instances_registered = -1;
+const volatile int instances_on = -1;
 
 nosubprog unsigned long long map_get(void *map,
 				     unsigned int key)
@@ -143,6 +147,11 @@ int handle_timerlat_sample(struct trace_event_raw_timerlat_sample *tp_args)
 	unsigned long long latency, latency_us;
 	int bucket;
 
+	if ((instances_registered != -1 && tp_args->instances_registered != instances_registered)
+		|| (instances_on != -1 && tp_args->instances_on != instances_on))
+		/* This sample is not seen by all trace instances, filter it out */
+		return 0;
+
 	if (map_get(&stop_tracing, 0))
 		return 0;
 
diff --git a/tools/tracing/rtla/src/timerlat.c b/tools/tracing/rtla/src/timerlat.c
index 8f8811f7a13b..069f916100e7 100644
--- a/tools/tracing/rtla/src/timerlat.c
+++ b/tools/tracing/rtla/src/timerlat.c
@@ -28,6 +28,7 @@ int
 timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params)
 {
 	int retval;
+	struct tep_event *event = NULL;
 
 	/*
 	 * Try to enable BPF, unless disabled explicitly.
@@ -36,10 +37,25 @@ timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params)
 	if (getenv("RTLA_NO_BPF") && strncmp(getenv("RTLA_NO_BPF"), "1", 2) == 0) {
 		debug_msg("RTLA_NO_BPF set, disabling BPF\n");
 		params->mode = TRACING_MODE_TRACEFS;
-	} else if (!tep_find_event_by_name(tool->trace.tep, "osnoise", "timerlat_sample")) {
+	} else if (!(event = tep_find_event_by_name(tool->trace.tep, "osnoise", "timerlat_sample"))) {
 		debug_msg("osnoise:timerlat_sample missing, disabling BPF\n");
 		params->mode = TRACING_MODE_TRACEFS;
+	}
+
+	if (event && tep_find_field(event, "instances_registered") &&
+	    tep_find_field(event, "instances_on")) {
+		params->has_instance_count_fields = true;
+
+		if (!params->no_aa)
+			params->instances_on++;
+		if (params->common.threshold_actions.present[ACTION_TRACE_OUTPUT] ||
+		    params->common.end_actions.present[ACTION_TRACE_OUTPUT])
+			params->instances_on++;
 	} else {
+		params->has_instance_count_fields = false;
+	}
+
+	if (params->mode != TRACING_MODE_TRACEFS) {
 		retval = timerlat_bpf_init(params);
 		if (retval) {
 			debug_msg("Could not enable BPF\n");
diff --git a/tools/tracing/rtla/src/timerlat.h b/tools/tracing/rtla/src/timerlat.h
index 8dd5d134ce08..ef97e545c7ff 100644
--- a/tools/tracing/rtla/src/timerlat.h
+++ b/tools/tracing/rtla/src/timerlat.h
@@ -28,6 +28,8 @@ struct timerlat_params {
 	int			deepest_idle_state;
 	enum timerlat_tracing_mode mode;
 	const char		*bpf_action_program;
+	bool			has_instance_count_fields;
+	int			instances_on;
 };
 
 #define to_timerlat_params(ptr) container_of(ptr, struct timerlat_params, common)
diff --git a/tools/tracing/rtla/src/timerlat_bpf.c b/tools/tracing/rtla/src/timerlat_bpf.c
index 05adf18303df..80801796bbf0 100644
--- a/tools/tracing/rtla/src/timerlat_bpf.c
+++ b/tools/tracing/rtla/src/timerlat_bpf.c
@@ -53,6 +53,14 @@ int timerlat_bpf_init(struct timerlat_params *params)
 		bpf_map__set_autocreate(bpf->maps.summary_user, false);
 	}
 
+	if (params->mode == TRACING_MODE_MIXED && params->has_instance_count_fields) {
+		bpf->rodata->instances_on = params->instances_on;
+		bpf->rodata->instances_registered = params->instances_on + 1; /* +1 for the main instance */
+	} else {
+		bpf->rodata->instances_registered = -1;
+		bpf->rodata->instances_on = -1;
+	}
+
 	/* Load and verify BPF program */
 	err = timerlat_bpf__load(bpf);
 	if (err) {
-- 
2.52.0


^ permalink raw reply related

* [RFC PATCH 1/3] tracing/osnoise: Record timerlat instance counts
From: Tomas Glozar @ 2026-01-23 15:25 UTC (permalink / raw)
  To: Steven Rostedt, Masami Hiramatsu
  Cc: Mathieu Desnoyers, Crystal Wood, John Kacur, Luis Goncalves, LKML,
	Linux Trace Kernel, Tomas Glozar
In-Reply-To: <20260123152534.1036533-1-tglozar@redhat.com>

While recording a timerlat sample, track how many timerlat instances are
registered at the moment and how many instances have tracing on.

This enables a user of the timerlat_sample threshold to synchronize with
any users of the timerlat tracer instance buffer.

Note that this also reverses the order in which the trace buffer record
and the tracepoint are processed: the tracepoint now fires after the
trace buffer entries are recorded.

Signed-off-by: Tomas Glozar <tglozar@redhat.com>
---
 include/trace/events/osnoise.h | 14 ++++++++++----
 kernel/trace/trace_osnoise.c   | 10 ++++++++--
 2 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/include/trace/events/osnoise.h b/include/trace/events/osnoise.h
index 3f4273623801..50beaf8fbb52 100644
--- a/include/trace/events/osnoise.h
+++ b/include/trace/events/osnoise.h
@@ -79,26 +79,32 @@ TRACE_EVENT(osnoise_sample,
 #ifdef CONFIG_TIMERLAT_TRACER
 TRACE_EVENT(timerlat_sample,
 
-	TP_PROTO(struct timerlat_sample *s),
+	TP_PROTO(struct timerlat_sample *s, int instances_registered, int instances_on),
 
-	TP_ARGS(s),
+	TP_ARGS(s, instances_registered, instances_on),
 
 	TP_STRUCT__entry(
 		__field(	u64,		timer_latency	)
 		__field(	unsigned int,	seqnum		)
 		__field(	int,		context		)
+		__field(	int,		instances_registered	)
+		__field(	int,		instances_on		)
 	),
 
 	TP_fast_assign(
 		__entry->timer_latency = s->timer_latency;
 		__entry->seqnum = s->seqnum;
 		__entry->context = s->context;
+		__entry->instances_registered = instances_registered;
+		__entry->instances_on = instances_on;
 	),
 
-	TP_printk("timer_latency=%llu seqnum=%u context=%d",
+	TP_printk("timer_latency=%llu seqnum=%u context=%d instances_registered=%d instances_on=%d",
 		  __entry->timer_latency,
 		  __entry->seqnum,
-		  __entry->context)
+		  __entry->context,
+		  __entry->instances_registered,
+		  __entry->instances_on)
 );
 #endif // CONFIG_TIMERLAT_TRACER
 
diff --git a/kernel/trace/trace_osnoise.c b/kernel/trace/trace_osnoise.c
index 827104d00bc0..65ddc1f49c19 100644
--- a/kernel/trace/trace_osnoise.c
+++ b/kernel/trace/trace_osnoise.c
@@ -574,15 +574,21 @@ static void record_timerlat_sample(struct timerlat_sample *sample)
 {
 	struct osnoise_instance *inst;
 	struct trace_buffer *buffer;
-
-	trace_timerlat_sample(sample);
+	int instances_registered = 0;
+	int instances_on = 0;
 
 	rcu_read_lock();
 	list_for_each_entry_rcu(inst, &osnoise_instances, list) {
+		if (tracer_tracing_is_on(inst->tr))
+			instances_on++;
+		instances_registered++;
+
 		buffer = inst->tr->array_buffer.buffer;
 		__record_timerlat_sample(sample, buffer);
 	}
 	rcu_read_unlock();
+
+	trace_timerlat_sample(sample, instances_registered, instances_on);
 }
 
 #ifdef CONFIG_STACKTRACE
-- 
2.52.0


^ permalink raw reply related

* Re: [PATCH 18/26] rv/rvgen: add fill_tracepoint_args_skel stub to ltl2k
From: Wander Lairson Costa @ 2026-01-23 14:04 UTC (permalink / raw)
  To: Gabriele Monaco
  Cc: Steven Rostedt, Nam Cao, open list,
	open list:RUNTIME VERIFICATION (RV)
In-Reply-To: <c866db81d6213862baf4a4d3d9f2f013b7ef058b.camel@redhat.com>

On Fri, Jan 23, 2026 at 01:26:45PM +0100, Gabriele Monaco wrote:
> On Fri, 2026-01-23 at 09:19 -0300, Wander Lairson Costa wrote:
> > On Thu, Jan 22, 2026 at 02:49:59PM +0100, Gabriele Monaco wrote:
> > > Why fill_tracepoint_args_skel() is not required by LTL is an implementation
> > > detail, so that stub could even stay, in case future monitors are going to
> > > need
> > > the entire thing.
> > > Though I still find it cleaner to move that away too until there's a need
> > > for it
> > > shared in Monitor.
> > 
> > I didn't catch what is included in "that"...
> 
> Right, it ended up quite cryptic, I meant fill_tracepoint_args_skel() could stay
> in Monitor although not all Monitors need it, though I honestly prefer to move
> it away and not rely on the stub. 
> 
> > > What do you think?
> > 
> > I agreed. fill_tracepoint_args_skel() makes sense in the Monitor class.
> > If a derived class doesn't need it, it is an implementation detail.
> > 
> 
> But I get your stance and agree with that too, where fill_tracepoint_args_skel()
> goes is just nitpicking at this point.
> 

I will go with your early suggestion and drop all this related work in
v2 and submitting a separate patch series addressing these interface
issues. Python has some good tools [1,2] to handle that. I intend to
make use of them.

[1] https://docs.python.org/3/library/abc.html
[2] https://typing.python.org/en/latest/spec/protocol.html

> Thanks,
> Gabriele
> 


^ permalink raw reply

* Re: [PATCH v5 15/15] rv: Add dl_server specific monitors
From: Juri Lelli @ 2026-01-23 13:04 UTC (permalink / raw)
  To: Gabriele Monaco
  Cc: linux-kernel, Steven Rostedt, Nam Cao, Juri Lelli,
	Jonathan Corbet, Masami Hiramatsu, linux-trace-kernel, linux-doc,
	Peter Zijlstra, Tomas Glozar, Clark Williams, John Kacur
In-Reply-To: <20260122155500.362683-16-gmonaco@redhat.com>

Hello,

On 22/01/26 16:55, Gabriele Monaco wrote:
> Add monitors to validate the behaviour of the deadline server.
> 
> The currently implemented monitors are:
> * boost
>     fair tasks run either independently or boosted
> * laxity
>     deferrable servers wait for zero-laxity and run
> 
> Cc: Peter Zijlstra <peterz@infradead.org>
> Reviewed-by: Nam Cao <namcao@linutronix.de>
> Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
> ---

And these as well look alright.

Reviewed-by: Juri Lelli <juri.lelli@redhat.com>

Thanks,
Juri


^ permalink raw reply

* Re: [PATCH v5 14/15] rv: Add deadline monitors
From: Juri Lelli @ 2026-01-23 13:03 UTC (permalink / raw)
  To: Gabriele Monaco
  Cc: linux-kernel, Steven Rostedt, Nam Cao, Juri Lelli,
	Jonathan Corbet, Masami Hiramatsu, linux-trace-kernel, linux-doc,
	Peter Zijlstra, Tomas Glozar, Clark Williams, John Kacur
In-Reply-To: <20260122155500.362683-15-gmonaco@redhat.com>

Hello,

On 22/01/26 16:54, Gabriele Monaco wrote:
> Add the deadline monitors collection to validate the deadline scheduler,
> both for deadline tasks and servers.
> 
> The currently implemented monitors are:
> * throttle:
>     validate dl entities are throttled when they use up their runtime
> * nomiss:
>     validate dl entities run to completion before their deadiline
> 
> Cc: Peter Zijlstra <peterz@infradead.org>
> Reviewed-by: Nam Cao <namcao@linutronix.de>
> Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
> ---

Looks good to me!

Reviewed-by: Juri Lelli <juri.lelli@redhat.com>

Thanks,
Juri


^ permalink raw reply

* Re: [PATCH v5 13/15] sched/deadline: Move some utility functions to deadline.h
From: Juri Lelli @ 2026-01-23 13:00 UTC (permalink / raw)
  To: Gabriele Monaco
  Cc: linux-kernel, Steven Rostedt, Nam Cao, Juri Lelli, Ingo Molnar,
	Peter Zijlstra, Tomas Glozar, Clark Williams, John Kacur,
	linux-trace-kernel
In-Reply-To: <20260122155500.362683-14-gmonaco@redhat.com>

Hello,

On 22/01/26 16:54, Gabriele Monaco wrote:
> Some utility functions on sched_dl_entity can be useful outside of
> deadline.c , for instance for modelling, without relying on raw
> structure fields.
> 
> Move functions like dl_task_of and dl_is_implicit to deadline.h to make
> them available outside.
> 
> Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
> ---

Acked-by: Juri Lelli <juri.lelli@redhat.com>

Thanks,
Juri


^ permalink raw reply

* Re: [PATCH v9 29/30] KVM: arm64: Add selftest event support to nVHE/pKVM hyp
From: Marc Zyngier @ 2026-01-23 12:47 UTC (permalink / raw)
  To: Vincent Donnefort
  Cc: rostedt, mhiramat, mathieu.desnoyers, linux-trace-kernel,
	oliver.upton, joey.gouly, suzuki.poulose, yuzenghui, kvmarm,
	linux-arm-kernel, jstultz, qperret, will, aneesh.kumar,
	kernel-team, linux-kernel
In-Reply-To: <aXNnsJqqsskXyJu7@google.com>

On Fri, 23 Jan 2026 12:21:04 +0000,
Vincent Donnefort <vdonnefort@google.com> wrote:
> 
> On Fri, Jan 23, 2026 at 12:14:34PM +0000, Vincent Donnefort wrote:
> > On Wed, Jan 07, 2026 at 03:40:22PM +0000, Marc Zyngier wrote:
> > > On Tue, 02 Dec 2025 09:36:22 +0000,
> > > Vincent Donnefort <vdonnefort@google.com> wrote:
> > > > 
> > > > Add a selftest event that can be triggered from a `write_event` tracefs
> > > > file. This intends to be used by trace remote selftests.
> > > > 
> > > > Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
> > > > 
> > > > diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
> > > > index 37c015b54ff6..e2de7ad64938 100644
> > > > --- a/arch/arm64/include/asm/kvm_asm.h
> > > > +++ b/arch/arm64/include/asm/kvm_asm.h
> > > > @@ -96,6 +96,7 @@ enum __kvm_host_smccc_func {
> > > >  	__KVM_HOST_SMCCC_FUNC___tracing_update_clock,
> > > >  	__KVM_HOST_SMCCC_FUNC___tracing_reset,
> > > >  	__KVM_HOST_SMCCC_FUNC___tracing_enable_event,
> > > > +	__KVM_HOST_SMCCC_FUNC___tracing_write_event,
> > > >  };
> > > >  
> > > >  #define DECLARE_KVM_VHE_SYM(sym)	extern char sym[]
> > > > diff --git a/arch/arm64/include/asm/kvm_hypevents.h b/arch/arm64/include/asm/kvm_hypevents.h
> > > > index 268b3cd7a1b2..c276fd28e0bf 100644
> > > > --- a/arch/arm64/include/asm/kvm_hypevents.h
> > > > +++ b/arch/arm64/include/asm/kvm_hypevents.h
> > > > @@ -42,4 +42,15 @@ HYP_EVENT(hyp_exit,
> > > >  	),
> > > >  	HE_PRINTK("reason=%s", __hyp_enter_exit_reason_str(__entry->reason))
> > > >  );
> > > > +
> > > > +HYP_EVENT(selftest,
> > > > +	HE_PROTO(u64 id),
> > > > +	HE_STRUCT(
> > > > +		he_field(u64, id)
> > > > +	),
> > > > +	HE_ASSIGN(
> > > > +		__entry->id = id;
> > > > +	),
> > > > +	RE_PRINTK("id=%llu", __entry->id)
> > > 
> > > Not strictly related to this patch, but I find that the trace itself
> > > lacks context. For example:
> > > 
> > > [001]	  323.847422: hyp_enter reason=hvc
> > > [001]	  323.847423: hyp_exit reason=eret_host
> > > [001]	  323.847688: hyp_enter reason=hvc
> > > [001]	  323.847688: hyp_exit reason=eret_host
> > > [001]	  323.847706: hyp_enter reason=hvc
> > > [001]	  323.847707: hyp_exit reason=eret_host
> > > [001]	  323.847722: hyp_enter reason=hvc
> > > [001]	  323.847723: hyp_exit reason=eret_host
> > > 
> > > That's all fine as long as I'm dealing with a single guest, or even
> > > with a single vcpu. Trying to trace multiple guests, or even multiple
> > > vcpus makes the whole thing completely unusable, because I have no
> > > idea what I'm looking at.
> > > 
> > > To make this useful, having some context provided by the host really
> > > is required.
> > 
> > I could add to the event header the VM pid related to the currently loaded vCPU
> > (if any). I can access it easily with host_kvm->userspace_pid. WDYS?
> 
> Or actually directly kvm_vcpu->pid?

More like it indeed.

	M.

-- 
Without deviation from the norm, progress is not possible.

^ permalink raw reply

* Re: [PATCH v9 29/30] KVM: arm64: Add selftest event support to nVHE/pKVM hyp
From: Marc Zyngier @ 2026-01-23 12:47 UTC (permalink / raw)
  To: Vincent Donnefort
  Cc: rostedt, mhiramat, mathieu.desnoyers, linux-trace-kernel,
	oliver.upton, joey.gouly, suzuki.poulose, yuzenghui, kvmarm,
	linux-arm-kernel, jstultz, qperret, will, aneesh.kumar,
	kernel-team, linux-kernel
In-Reply-To: <aXNmKpHqVw93BegX@google.com>

On Fri, 23 Jan 2026 12:14:34 +0000,
Vincent Donnefort <vdonnefort@google.com> wrote:
> 
> On Wed, Jan 07, 2026 at 03:40:22PM +0000, Marc Zyngier wrote:
> > On Tue, 02 Dec 2025 09:36:22 +0000,
> > Vincent Donnefort <vdonnefort@google.com> wrote:
> > > 
> > Not strictly related to this patch, but I find that the trace itself
> > lacks context. For example:
> > 
> > [001]	  323.847422: hyp_enter reason=hvc
> > [001]	  323.847423: hyp_exit reason=eret_host
> > [001]	  323.847688: hyp_enter reason=hvc
> > [001]	  323.847688: hyp_exit reason=eret_host
> > [001]	  323.847706: hyp_enter reason=hvc
> > [001]	  323.847707: hyp_exit reason=eret_host
> > [001]	  323.847722: hyp_enter reason=hvc
> > [001]	  323.847723: hyp_exit reason=eret_host
> > 
> > That's all fine as long as I'm dealing with a single guest, or even
> > with a single vcpu. Trying to trace multiple guests, or even multiple
> > vcpus makes the whole thing completely unusable, because I have no
> > idea what I'm looking at.
> > 
> > To make this useful, having some context provided by the host really
> > is required.
> 
> I could add to the event header the VM pid related to the currently loaded vCPU
> (if any). I can access it easily with host_kvm->userspace_pid. WDYS?

It really should be the thread name, just like we already have for the
kernel tracing. For example:

vgic_irq-2007    [005] ..... 180926.476735: kvm_sys_access: PC: 4119e4 SYS_ICC_DIR_EL1 (3,0,12,11,1) write
vgic_irq-2010    [005] ..... 180926.534771: kvm_sys_access: PC: 40254c SYS_CNTV_CVAL_EL0 (3,3,14,3,2) write
vgic_irq-2010    [005] ..... 180926.534777: kvm_sys_access: PC: 402554 SYS_CNTV_CTL_EL0 (3,3,14,3,1) write
vgic_irq-2010    [005] ..... 180926.534789: kvm_sys_access: PC: 4025b8 SYS_CNTV_CTL_EL0 (3,3,14,3,1) write
vgic_irq-2011    [010] ..... 180926.534790: kvm_sys_access: PC: 40254c SYS_CNTV_CVAL_EL0 (3,3,14,3,2) write
vgic_irq-2010    [005] ..... 180926.534793: kvm_sys_access: PC: 4119e4 SYS_ICC_DIR_EL1 (3,0,12,11,1) write

This is a single guest, with concurrent vcpus. I'd like to be able to
correlate that with what the hypervisor tracing outputs. At the very
least the thread's PID. But the VM itself is pretty much irrelevant.

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.

^ permalink raw reply

* Re: [PATCH 18/26] rv/rvgen: add fill_tracepoint_args_skel stub to ltl2k
From: Gabriele Monaco @ 2026-01-23 12:26 UTC (permalink / raw)
  To: Wander Lairson Costa
  Cc: Steven Rostedt, Nam Cao, open list,
	open list:RUNTIME VERIFICATION (RV)
In-Reply-To: <aXNkusXPp9MyRX9y@fedora>

On Fri, 2026-01-23 at 09:19 -0300, Wander Lairson Costa wrote:
> On Thu, Jan 22, 2026 at 02:49:59PM +0100, Gabriele Monaco wrote:
> > Why fill_tracepoint_args_skel() is not required by LTL is an implementation
> > detail, so that stub could even stay, in case future monitors are going to
> > need
> > the entire thing.
> > Though I still find it cleaner to move that away too until there's a need
> > for it
> > shared in Monitor.
> 
> I didn't catch what is included in "that"...

Right, it ended up quite cryptic, I meant fill_tracepoint_args_skel() could stay
in Monitor although not all Monitors need it, though I honestly prefer to move
it away and not rely on the stub. 

> > What do you think?
> 
> I agreed. fill_tracepoint_args_skel() makes sense in the Monitor class.
> If a derived class doesn't need it, it is an implementation detail.
> 

But I get your stance and agree with that too, where fill_tracepoint_args_skel()
goes is just nitpicking at this point.

Thanks,
Gabriele


^ permalink raw reply

* Re: [PATCH v9 29/30] KVM: arm64: Add selftest event support to nVHE/pKVM hyp
From: Vincent Donnefort @ 2026-01-23 12:21 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: rostedt, mhiramat, mathieu.desnoyers, linux-trace-kernel,
	oliver.upton, joey.gouly, suzuki.poulose, yuzenghui, kvmarm,
	linux-arm-kernel, jstultz, qperret, will, aneesh.kumar,
	kernel-team, linux-kernel
In-Reply-To: <aXNmKpHqVw93BegX@google.com>

On Fri, Jan 23, 2026 at 12:14:34PM +0000, Vincent Donnefort wrote:
> On Wed, Jan 07, 2026 at 03:40:22PM +0000, Marc Zyngier wrote:
> > On Tue, 02 Dec 2025 09:36:22 +0000,
> > Vincent Donnefort <vdonnefort@google.com> wrote:
> > > 
> > > Add a selftest event that can be triggered from a `write_event` tracefs
> > > file. This intends to be used by trace remote selftests.
> > > 
> > > Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
> > > 
> > > diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
> > > index 37c015b54ff6..e2de7ad64938 100644
> > > --- a/arch/arm64/include/asm/kvm_asm.h
> > > +++ b/arch/arm64/include/asm/kvm_asm.h
> > > @@ -96,6 +96,7 @@ enum __kvm_host_smccc_func {
> > >  	__KVM_HOST_SMCCC_FUNC___tracing_update_clock,
> > >  	__KVM_HOST_SMCCC_FUNC___tracing_reset,
> > >  	__KVM_HOST_SMCCC_FUNC___tracing_enable_event,
> > > +	__KVM_HOST_SMCCC_FUNC___tracing_write_event,
> > >  };
> > >  
> > >  #define DECLARE_KVM_VHE_SYM(sym)	extern char sym[]
> > > diff --git a/arch/arm64/include/asm/kvm_hypevents.h b/arch/arm64/include/asm/kvm_hypevents.h
> > > index 268b3cd7a1b2..c276fd28e0bf 100644
> > > --- a/arch/arm64/include/asm/kvm_hypevents.h
> > > +++ b/arch/arm64/include/asm/kvm_hypevents.h
> > > @@ -42,4 +42,15 @@ HYP_EVENT(hyp_exit,
> > >  	),
> > >  	HE_PRINTK("reason=%s", __hyp_enter_exit_reason_str(__entry->reason))
> > >  );
> > > +
> > > +HYP_EVENT(selftest,
> > > +	HE_PROTO(u64 id),
> > > +	HE_STRUCT(
> > > +		he_field(u64, id)
> > > +	),
> > > +	HE_ASSIGN(
> > > +		__entry->id = id;
> > > +	),
> > > +	RE_PRINTK("id=%llu", __entry->id)
> > 
> > Not strictly related to this patch, but I find that the trace itself
> > lacks context. For example:
> > 
> > [001]	  323.847422: hyp_enter reason=hvc
> > [001]	  323.847423: hyp_exit reason=eret_host
> > [001]	  323.847688: hyp_enter reason=hvc
> > [001]	  323.847688: hyp_exit reason=eret_host
> > [001]	  323.847706: hyp_enter reason=hvc
> > [001]	  323.847707: hyp_exit reason=eret_host
> > [001]	  323.847722: hyp_enter reason=hvc
> > [001]	  323.847723: hyp_exit reason=eret_host
> > 
> > That's all fine as long as I'm dealing with a single guest, or even
> > with a single vcpu. Trying to trace multiple guests, or even multiple
> > vcpus makes the whole thing completely unusable, because I have no
> > idea what I'm looking at.
> > 
> > To make this useful, having some context provided by the host really
> > is required.
> 
> I could add to the event header the VM pid related to the currently loaded vCPU
> (if any). I can access it easily with host_kvm->userspace_pid. WDYS?

Or actually directly kvm_vcpu->pid?

> 
> > 
> > Thanks,
> > 
> > 	M.
> > 
> > -- 
> > Without deviation from the norm, progress is not possible.

^ permalink raw reply

* Re: [PATCH 18/26] rv/rvgen: add fill_tracepoint_args_skel stub to ltl2k
From: Wander Lairson Costa @ 2026-01-23 12:19 UTC (permalink / raw)
  To: Gabriele Monaco
  Cc: Steven Rostedt, Nam Cao, open list,
	open list:RUNTIME VERIFICATION (RV)
In-Reply-To: <ed5ffb1045a5d0734947019ad31b9bf46bdca3ab.camel@redhat.com>

On Thu, Jan 22, 2026 at 02:49:59PM +0100, Gabriele Monaco wrote:
> On Thu, 2026-01-22 at 10:10 -0300, Wander Lairson Costa wrote:
> > On Wed, Jan 21, 2026 at 02:53:03PM -0300, Wander Lairson Costa wrote:
> > > On Wed, Jan 21, 2026 at 02:57:02PM +0100, Gabriele Monaco wrote:
> > > > Mmh, this is a bit fishy though.
> > > > We the patch using the decorator seems fine, but highlights how this
> > > > method
> > > > isn't meant to be in Monitor if not all monitors use it..
> > > > Adding a stub here is just sweeping dust under the carpet.
> > > > 
> > > > Here should probably keep the common part of fill_trace_h() in Monitor
> > > > (e.g.
> > > > replacing MODEL_NAME and other common things) and create specific
> > > > implementations in dot2k and ltl2k for what is not common while calling
> > > > the
> > > > super() counterpart for the rest.
> > > > 
> > > > Does it make sense to you?
> > > 
> > > Yes, that is exactly my idea. Since the patch series were getting too
> > > long and my brain too rot, I thought would be better addressing this in
> > > a following up patch series. But I can work in the next version if you
> > > are not ok with that approach.
> 
> Good point, that can be a separate series so that we don't mix too many things,
> but I'd also separate the initial patch introducing the @not_implemented .
> 
> > I gave more thought on this matter yesterday before bed. Maybe this
> > isn't a issue on the design. Some methods on Monitor might just have a
> > harmless default behavior. I look into it more closely for next the
> > round.
> 
> Well, I believe that if a bunch of methods from the parent class don't need to
> be called and we have to create stubs just to avoid errors, those methods
> probably shouldn't be there in the first place.
> 
> That's particularly valid for the Container class, that won't ever need to fill
> tracepoints and other stuff.
> 
> Why fill_tracepoint_args_skel() is not required by LTL is an implementation
> detail, so that stub could even stay, in case future monitors are going to need
> the entire thing.
> Though I still find it cleaner to move that away too until there's a need for it
> shared in Monitor.
> 

I didn't catch what is included in "that"...

> What do you think?
> 

I agreed. fill_tracepoint_args_skel() makes sense in the Monitor class.
If a derived class doesn't need it, it is an implementation detail.

> Thanks,
> Gabriele
> 


^ permalink raw reply

* Re: [PATCH v9 29/30] KVM: arm64: Add selftest event support to nVHE/pKVM hyp
From: Vincent Donnefort @ 2026-01-23 12:14 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: rostedt, mhiramat, mathieu.desnoyers, linux-trace-kernel,
	oliver.upton, joey.gouly, suzuki.poulose, yuzenghui, kvmarm,
	linux-arm-kernel, jstultz, qperret, will, aneesh.kumar,
	kernel-team, linux-kernel
In-Reply-To: <868qe9mnx5.wl-maz@kernel.org>

On Wed, Jan 07, 2026 at 03:40:22PM +0000, Marc Zyngier wrote:
> On Tue, 02 Dec 2025 09:36:22 +0000,
> Vincent Donnefort <vdonnefort@google.com> wrote:
> > 
> > Add a selftest event that can be triggered from a `write_event` tracefs
> > file. This intends to be used by trace remote selftests.
> > 
> > Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
> > 
> > diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
> > index 37c015b54ff6..e2de7ad64938 100644
> > --- a/arch/arm64/include/asm/kvm_asm.h
> > +++ b/arch/arm64/include/asm/kvm_asm.h
> > @@ -96,6 +96,7 @@ enum __kvm_host_smccc_func {
> >  	__KVM_HOST_SMCCC_FUNC___tracing_update_clock,
> >  	__KVM_HOST_SMCCC_FUNC___tracing_reset,
> >  	__KVM_HOST_SMCCC_FUNC___tracing_enable_event,
> > +	__KVM_HOST_SMCCC_FUNC___tracing_write_event,
> >  };
> >  
> >  #define DECLARE_KVM_VHE_SYM(sym)	extern char sym[]
> > diff --git a/arch/arm64/include/asm/kvm_hypevents.h b/arch/arm64/include/asm/kvm_hypevents.h
> > index 268b3cd7a1b2..c276fd28e0bf 100644
> > --- a/arch/arm64/include/asm/kvm_hypevents.h
> > +++ b/arch/arm64/include/asm/kvm_hypevents.h
> > @@ -42,4 +42,15 @@ HYP_EVENT(hyp_exit,
> >  	),
> >  	HE_PRINTK("reason=%s", __hyp_enter_exit_reason_str(__entry->reason))
> >  );
> > +
> > +HYP_EVENT(selftest,
> > +	HE_PROTO(u64 id),
> > +	HE_STRUCT(
> > +		he_field(u64, id)
> > +	),
> > +	HE_ASSIGN(
> > +		__entry->id = id;
> > +	),
> > +	RE_PRINTK("id=%llu", __entry->id)
> 
> Not strictly related to this patch, but I find that the trace itself
> lacks context. For example:
> 
> [001]	  323.847422: hyp_enter reason=hvc
> [001]	  323.847423: hyp_exit reason=eret_host
> [001]	  323.847688: hyp_enter reason=hvc
> [001]	  323.847688: hyp_exit reason=eret_host
> [001]	  323.847706: hyp_enter reason=hvc
> [001]	  323.847707: hyp_exit reason=eret_host
> [001]	  323.847722: hyp_enter reason=hvc
> [001]	  323.847723: hyp_exit reason=eret_host
> 
> That's all fine as long as I'm dealing with a single guest, or even
> with a single vcpu. Trying to trace multiple guests, or even multiple
> vcpus makes the whole thing completely unusable, because I have no
> idea what I'm looking at.
> 
> To make this useful, having some context provided by the host really
> is required.

I could add to the event header the VM pid related to the currently loaded vCPU
(if any). I can access it easily with host_kvm->userspace_pid. WDYS?

> 
> Thanks,
> 
> 	M.
> 
> -- 
> Without deviation from the norm, progress is not possible.

^ permalink raw reply

* Re: [PATCH v9 25/30] KVM: arm64: Sync boot clock with the nVHE/pKVM hyp
From: Vincent Donnefort @ 2026-01-23 12:12 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: rostedt, mhiramat, mathieu.desnoyers, linux-trace-kernel,
	oliver.upton, joey.gouly, suzuki.poulose, yuzenghui, kvmarm,
	linux-arm-kernel, jstultz, qperret, will, aneesh.kumar,
	kernel-team, linux-kernel, Thomas Gleixner, Stephen Boyd,
	Christopher S. Hall, Richard Cochran
In-Reply-To: <86bjj5mrhn.wl-maz@kernel.org>

On Wed, Jan 07, 2026 at 02:23:16PM +0000, Marc Zyngier wrote:
> On Tue, 02 Dec 2025 09:36:18 +0000,
> Vincent Donnefort <vdonnefort@google.com> wrote:
> > 
> > Configure the hypervisor tracing clock with the kernel boot clock. For
> > tracing purposes, the boot clock is interesting: it doesn't stop on
> > suspend. However, it is corrected on a regular basis, which implies the
> > need to re-evaluate it every once in a while.
> > 
> > Cc: John Stultz <jstultz@google.com>
> > Cc: Thomas Gleixner <tglx@linutronix.de>
> > Cc: Stephen Boyd <sboyd@kernel.org>
> > Cc: Christopher S. Hall <christopher.s.hall@intel.com>
> > Cc: Richard Cochran <richardcochran@gmail.com>
> > Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
> > 
> > diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
> > index f83650a7aad9..375607c67285 100644
> > --- a/arch/arm64/include/asm/kvm_asm.h
> > +++ b/arch/arm64/include/asm/kvm_asm.h
> > @@ -93,6 +93,7 @@ enum __kvm_host_smccc_func {
> >  	__KVM_HOST_SMCCC_FUNC___tracing_unload,
> >  	__KVM_HOST_SMCCC_FUNC___tracing_enable,
> >  	__KVM_HOST_SMCCC_FUNC___tracing_swap_reader,
> > +	__KVM_HOST_SMCCC_FUNC___tracing_update_clock,
> >  };
> >  
> >  #define DECLARE_KVM_VHE_SYM(sym)	extern char sym[]
> > diff --git a/arch/arm64/kvm/hyp/include/nvhe/trace.h b/arch/arm64/kvm/hyp/include/nvhe/trace.h
> > index 7da8788ce527..fd641e1b1c23 100644
> > --- a/arch/arm64/kvm/hyp/include/nvhe/trace.h
> > +++ b/arch/arm64/kvm/hyp/include/nvhe/trace.h
> > @@ -11,6 +11,7 @@ int __tracing_load(unsigned long desc_va, size_t desc_size);
> >  void __tracing_unload(void);
> >  int __tracing_enable(bool enable);
> >  int __tracing_swap_reader(unsigned int cpu);
> > +void __tracing_update_clock(u32 mult, u32 shift, u64 epoch_ns, u64 epoch_cyc);
> >  #else
> >  static inline void *tracing_reserve_entry(unsigned long length) { return NULL; }
> >  static inline void tracing_commit_entry(void) { }
> > @@ -19,5 +20,6 @@ static inline int __tracing_load(unsigned long desc_va, size_t desc_size) { retu
> >  static inline void __tracing_unload(void) { }
> >  static inline int __tracing_enable(bool enable) { return -ENODEV; }
> >  static inline int __tracing_swap_reader(unsigned int cpu) { return -ENODEV; }
> > +static inline void __tracing_update_clock(u32 mult, u32 shift, u64 epoch_ns, u64 epoch_cyc) { }
> >  #endif
> >  #endif
> > diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > index 8b78b29c2069..45b8f70828de 100644
> > --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > @@ -613,6 +613,18 @@ static void handle___tracing_swap_reader(struct kvm_cpu_context *host_ctxt)
> >  	cpu_reg(host_ctxt, 1) = __tracing_swap_reader(cpu);
> >  }
> >  
> > +static void handle___tracing_update_clock(struct kvm_cpu_context *host_ctxt)
> > +{
> > +	DECLARE_REG(u32, mult, host_ctxt, 1);
> > +	DECLARE_REG(u32, shift, host_ctxt, 2);
> > +	DECLARE_REG(u64, epoch_ns, host_ctxt, 3);
> > +	DECLARE_REG(u64, epoch_cyc, host_ctxt, 4);
> > +
> > +	__tracing_update_clock(mult, shift, epoch_ns, epoch_cyc);
> > +
> > +	cpu_reg(host_ctxt, 1) = 0;
> 
> What's the purpose of setting X1 to 0? This is a call returning void,
> so I don't immediately see the need for this.

Hum, nope nothing. And actually the same applies to __tracing_write_event() and
__tracing_unload()

> 
> > +}
> > +
> >  typedef void (*hcall_t)(struct kvm_cpu_context *);
> >  
> >  #define HANDLE_FUNC(x)	[__KVM_HOST_SMCCC_FUNC_##x] = (hcall_t)handle_##x
> > @@ -658,6 +670,7 @@ static const hcall_t host_hcall[] = {
> >  	HANDLE_FUNC(__tracing_unload),
> >  	HANDLE_FUNC(__tracing_enable),
> >  	HANDLE_FUNC(__tracing_swap_reader),
> > +	HANDLE_FUNC(__tracing_update_clock),
> >  };
> >  
> >  static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
> > diff --git a/arch/arm64/kvm/hyp/nvhe/trace.c b/arch/arm64/kvm/hyp/nvhe/trace.c
> > index df9d66fcb3c9..97e9f6c1a52c 100644
> > --- a/arch/arm64/kvm/hyp/nvhe/trace.c
> > +++ b/arch/arm64/kvm/hyp/nvhe/trace.c
> > @@ -271,3 +271,19 @@ int __tracing_swap_reader(unsigned int cpu)
> >  
> >  	return ret;
> >  }
> > +
> > +void __tracing_update_clock(u32 mult, u32 shift, u64 epoch_ns, u64 epoch_cyc)
> > +{
> > +	int cpu;
> > +
> > +	/* After this loop, all CPUs are observing the new bank... */
> > +	for (cpu = 0; cpu < hyp_nr_cpus; cpu++) {
> > +		struct simple_rb_per_cpu *simple_rb = per_cpu_ptr(trace_buffer.simple_rbs, cpu);
> > +
> > +		while (READ_ONCE(simple_rb->status) == SIMPLE_RB_WRITING)
> > +			;
> > +	}
> > +
> > +	/* ...we can now override the old one and swap. */
> > +	trace_clock_update(mult, shift, epoch_ns, epoch_cyc);
> > +}
> > diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c
> > index 2866effe28ec..1e5fc27f0e9d 100644
> > --- a/arch/arm64/kvm/hyp_trace.c
> > +++ b/arch/arm64/kvm/hyp_trace.c
> > @@ -4,15 +4,133 @@
> >   * Author: Vincent Donnefort <vdonnefort@google.com>
> >   */
> >  
> > +#include <linux/cpumask.h>
> >  #include <linux/trace_remote.h>
> > +#include <linux/tracefs.h>
> >  #include <linux/simple_ring_buffer.h>
> >  
> > +#include <asm/arch_timer.h>
> >  #include <asm/kvm_host.h>
> >  #include <asm/kvm_hyptrace.h>
> >  #include <asm/kvm_mmu.h>
> >  
> >  #include "hyp_trace.h"
> >  
> > +/* Same 10min used by clocksource when width is more than 32-bits */
> > +#define CLOCK_MAX_CONVERSION_S	600
> > +/*
> > + * Time to give for the clock init. Long enough to get a good mult/shift
> > + * estimation. Short enough to not delay the tracing start too much.
> > + */
> > +#define CLOCK_INIT_MS		100
> > +/*
> > + * Time between clock checks. Must be small enough to catch clock deviation when
> > + * it is still tiny.
> > + */
> > +#define CLOCK_UPDATE_MS		500
> 
> If these definitions are common, can't we reuse the existing ones?
> Specially given that this isn't EL2 code.

Only the first is reused but it doesn't exist any definition for it.

> 
> Thanks,
> 
> 	M.
> 
> -- 
> Without deviation from the norm, progress is not possible.

^ permalink raw reply

* Re: [PATCH mm-unstable v14 03/16] introduce collapse_single_pmd to unify khugepaged and madvise_collapse
From: Baolin Wang @ 2026-01-23  9:31 UTC (permalink / raw)
  To: Lance Yang, Nico Pache
  Cc: akpm, david, lorenzo.stoakes, ziy, Liam.Howlett, ryan.roberts,
	dev.jain, baohua, vbabka, rppt, surenb, mhocko,
	linux-trace-kernel, linux-doc, corbet, rostedt, mhiramat,
	mathieu.desnoyers, linux-kernel, matthew.brost, joshua.hahnjy,
	rakie.kim, byungchul, gourry, ying.huang, apopple, jannh,
	pfalcato, jackmanb, hannes, willy, peterx, wangkefeng.wang,
	usamaarif642, sunnanyong, vishal.moola, thomas.hellstrom, yang,
	kas, aarcange, raquini, anshuman.khandual, catalin.marinas, tiwai,
	will, dave.hansen, jack, cl, jglisse, zokeefe, rientjes, rdunlap,
	hughd, richard.weiyang, David Hildenbrand, linux-mm
In-Reply-To: <65dcf7ab-1299-411f-9cbc-438ae72ff757@linux.dev>



On 1/23/26 1:07 PM, Lance Yang wrote:
> 
> 
> On 2026/1/23 03:28, Nico Pache wrote:
>> The khugepaged daemon and madvise_collapse have two different
>> implementations that do almost the same thing.
>>
>> Create collapse_single_pmd to increase code reuse and create an entry
>> point to these two users.
>>
>> Refactor madvise_collapse and collapse_scan_mm_slot to use the new
>> collapse_single_pmd function. This introduces a minor behavioral change
>> that is most likely an undiscovered bug. The current implementation of
>> khugepaged tests collapse_test_exit_or_disable before calling
>> collapse_pte_mapped_thp, but we weren't doing it in the madvise_collapse
>> case. By unifying these two callers madvise_collapse now also performs
>> this check. We also modify the return value to be SCAN_ANY_PROCESS which
>> properly indicates that this process is no longer valid to operate on.
>>
>> We also guard the khugepaged_pages_collapsed variable to ensure its only
>> incremented for khugepaged.
>>
>> Reviewed-by: Wei Yang <richard.weiyang@gmail.com>
>> Reviewed-by: Lance Yang <lance.yang@linux.dev>
>> Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
>> Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
>> Reviewed-by: Zi Yan <ziy@nvidia.com>
>> Acked-by: David Hildenbrand <david@redhat.com>
>> Signed-off-by: Nico Pache <npache@redhat.com>
>> ---
> 
> I think this patch introduces some functional changes compared to previous
> version[1] ...
> 
> Maybe we should drop the r-b tags and let folks take another look?
> 
> There might be an issue with the vma access in madvise_collapse(). See 
> below:
> 
> [1] https://lore.kernel.org/linux-mm/20251201174627.23295-3- 
> npache@redhat.com/
> 
>>   mm/khugepaged.c | 106 +++++++++++++++++++++++++++---------------------
>>   1 file changed, 60 insertions(+), 46 deletions(-)
>>
>> diff --git a/mm/khugepaged.c b/mm/khugepaged.c
>> index fefcbdca4510..59e5a5588d85 100644
>> --- a/mm/khugepaged.c
>> +++ b/mm/khugepaged.c
>> @@ -2394,6 +2394,54 @@ static enum scan_result 
>> collapse_scan_file(struct mm_struct *mm, unsigned long a
>>       return result;
>>   }
>> +/*
>> + * Try to collapse a single PMD starting at a PMD aligned addr, and 
>> return
>> + * the results.
>> + */
>> +static enum scan_result collapse_single_pmd(unsigned long addr,
>> +        struct vm_area_struct *vma, bool *mmap_locked,
>> +        struct collapse_control *cc)
>> +{
>> +    struct mm_struct *mm = vma->vm_mm;
>> +    enum scan_result result;
>> +    struct file *file;
>> +    pgoff_t pgoff;
>> +
>> +    if (vma_is_anonymous(vma)) {
>> +        result = collapse_scan_pmd(mm, vma, addr, mmap_locked, cc);
>> +        goto end;
>> +    }
>> +
>> +    file = get_file(vma->vm_file);
>> +    pgoff = linear_page_index(vma, addr);
>> +
>> +    mmap_read_unlock(mm);
>> +    *mmap_locked = false;
>> +    result = collapse_scan_file(mm, addr, file, pgoff, cc);
>> +    fput(file);
>> +
>> +    if (result != SCAN_PTE_MAPPED_HUGEPAGE)
>> +        goto end;
>> +
>> +    mmap_read_lock(mm);
>> +    *mmap_locked = true;
>> +    if (collapse_test_exit_or_disable(mm)) {
>> +        mmap_read_unlock(mm);
>> +        *mmap_locked = false;
>> +        return SCAN_ANY_PROCESS;
>> +    }
>> +    result = try_collapse_pte_mapped_thp(mm, addr, !cc->is_khugepaged);
>> +    if (result == SCAN_PMD_MAPPED)
>> +        result = SCAN_SUCCEED;
>> +    mmap_read_unlock(mm);
>> +    *mmap_locked = false;
>> +
>> +end:
>> +    if (cc->is_khugepaged && result == SCAN_SUCCEED)
>> +        ++khugepaged_pages_collapsed;
>> +    return result;
>> +}
>> +
>>   static unsigned int collapse_scan_mm_slot(unsigned int pages, enum 
>> scan_result *result,
>>                           struct collapse_control *cc)
>>       __releases(&khugepaged_mm_lock)
>> @@ -2466,34 +2514,9 @@ static unsigned int 
>> collapse_scan_mm_slot(unsigned int pages, enum scan_result *
>>               VM_BUG_ON(khugepaged_scan.address < hstart ||
>>                     khugepaged_scan.address + HPAGE_PMD_SIZE >
>>                     hend);
>> -            if (!vma_is_anonymous(vma)) {
>> -                struct file *file = get_file(vma->vm_file);
>> -                pgoff_t pgoff = linear_page_index(vma,
>> -                        khugepaged_scan.address);
>> -
>> -                mmap_read_unlock(mm);
>> -                mmap_locked = false;
>> -                *result = collapse_scan_file(mm,
>> -                    khugepaged_scan.address, file, pgoff, cc);
>> -                fput(file);
>> -                if (*result == SCAN_PTE_MAPPED_HUGEPAGE) {
>> -                    mmap_read_lock(mm);
>> -                    if (collapse_test_exit_or_disable(mm))
>> -                        goto breakouterloop;
>> -                    *result = try_collapse_pte_mapped_thp(mm,
>> -                        khugepaged_scan.address, false);
>> -                    if (*result == SCAN_PMD_MAPPED)
>> -                        *result = SCAN_SUCCEED;
>> -                    mmap_read_unlock(mm);
>> -                }
>> -            } else {
>> -                *result = collapse_scan_pmd(mm, vma,
>> -                    khugepaged_scan.address, &mmap_locked, cc);
>> -            }
>> -
>> -            if (*result == SCAN_SUCCEED)
>> -                ++khugepaged_pages_collapsed;
>> +            *result = collapse_single_pmd(khugepaged_scan.address,
>> +                              vma, &mmap_locked, cc);
>>               /* move to next address */
>>               khugepaged_scan.address += HPAGE_PMD_SIZE;
>>               progress += HPAGE_PMD_NR;
>> @@ -2799,6 +2822,7 @@ int madvise_collapse(struct vm_area_struct *vma, 
>> unsigned long start,
>>               cond_resched();
>>               mmap_read_lock(mm);
>>               mmap_locked = true;
>> +            *lock_dropped = true;
>>               result = hugepage_vma_revalidate(mm, addr, false, &vma,
>>                                cc);
>>               if (result  != SCAN_SUCCEED) {
>> @@ -2809,17 +2833,17 @@ int madvise_collapse(struct vm_area_struct 
>> *vma, unsigned long start,
>>               hend = min(hend, vma->vm_end & HPAGE_PMD_MASK);
>>           }
>>           mmap_assert_locked(mm);
>> -        if (!vma_is_anonymous(vma)) {
>> -            struct file *file = get_file(vma->vm_file);
>> -            pgoff_t pgoff = linear_page_index(vma, addr);
>> -            mmap_read_unlock(mm);
>> -            mmap_locked = false;
>> +        result = collapse_single_pmd(addr, vma, &mmap_locked, cc);
>> +
>> +        if (!mmap_locked)
>>               *lock_dropped = true;
>> -            result = collapse_scan_file(mm, addr, file, pgoff, cc);
>> -            if (result == SCAN_PAGE_DIRTY_OR_WRITEBACK && ! 
>> triggered_wb &&
>> -                mapping_can_writeback(file->f_mapping)) {
>> +        if (result == SCAN_PAGE_DIRTY_OR_WRITEBACK && !triggered_wb) {
>> +            struct file *file = get_file(vma->vm_file);
>> +            pgoff_t pgoff = linear_page_index(vma, addr);
> 
> 
> After collapse_single_pmd() returns, mmap_lock might have been released. 
> Between
> that unlock and here, another thread could unmap/remap the VMA, making 
> the vma
> pointer stale when we access vma->vm_file?
> 
> Would it be safer to get the file reference before calling 
> collapse_single_pmd()?
> Or we need to revalidate the VMA after getting the lock back?
Good catch. I think we can move the filemap_write_and_wait_range() 
related logic into collapse_single_pmd(), after we get a file reference.

^ permalink raw reply

* Re: [PATCH mm-unstable v14 03/16] introduce collapse_single_pmd to unify khugepaged and madvise_collapse
From: Lance Yang @ 2026-01-23  5:07 UTC (permalink / raw)
  To: Nico Pache
  Cc: akpm, david, lorenzo.stoakes, ziy, baolin.wang, Liam.Howlett,
	ryan.roberts, dev.jain, baohua, vbabka, rppt, surenb, mhocko,
	linux-trace-kernel, linux-doc, corbet, rostedt, mhiramat,
	mathieu.desnoyers, linux-kernel, matthew.brost, joshua.hahnjy,
	rakie.kim, byungchul, gourry, ying.huang, apopple, jannh,
	pfalcato, jackmanb, hannes, willy, peterx, wangkefeng.wang,
	usamaarif642, sunnanyong, vishal.moola, thomas.hellstrom, yang,
	kas, aarcange, raquini, anshuman.khandual, catalin.marinas, tiwai,
	will, dave.hansen, jack, cl, jglisse, zokeefe, rientjes, rdunlap,
	hughd, richard.weiyang, David Hildenbrand, linux-mm
In-Reply-To: <20260122192841.128719-4-npache@redhat.com>



On 2026/1/23 03:28, Nico Pache wrote:
> The khugepaged daemon and madvise_collapse have two different
> implementations that do almost the same thing.
> 
> Create collapse_single_pmd to increase code reuse and create an entry
> point to these two users.
> 
> Refactor madvise_collapse and collapse_scan_mm_slot to use the new
> collapse_single_pmd function. This introduces a minor behavioral change
> that is most likely an undiscovered bug. The current implementation of
> khugepaged tests collapse_test_exit_or_disable before calling
> collapse_pte_mapped_thp, but we weren't doing it in the madvise_collapse
> case. By unifying these two callers madvise_collapse now also performs
> this check. We also modify the return value to be SCAN_ANY_PROCESS which
> properly indicates that this process is no longer valid to operate on.
> 
> We also guard the khugepaged_pages_collapsed variable to ensure its only
> incremented for khugepaged.
> 
> Reviewed-by: Wei Yang <richard.weiyang@gmail.com>
> Reviewed-by: Lance Yang <lance.yang@linux.dev>
> Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
> Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
> Reviewed-by: Zi Yan <ziy@nvidia.com>
> Acked-by: David Hildenbrand <david@redhat.com>
> Signed-off-by: Nico Pache <npache@redhat.com>
> ---

I think this patch introduces some functional changes compared to previous
version[1] ...

Maybe we should drop the r-b tags and let folks take another look?

There might be an issue with the vma access in madvise_collapse(). See 
below:

[1] 
https://lore.kernel.org/linux-mm/20251201174627.23295-3-npache@redhat.com/

>   mm/khugepaged.c | 106 +++++++++++++++++++++++++++---------------------
>   1 file changed, 60 insertions(+), 46 deletions(-)
> 
> diff --git a/mm/khugepaged.c b/mm/khugepaged.c
> index fefcbdca4510..59e5a5588d85 100644
> --- a/mm/khugepaged.c
> +++ b/mm/khugepaged.c
> @@ -2394,6 +2394,54 @@ static enum scan_result collapse_scan_file(struct mm_struct *mm, unsigned long a
>   	return result;
>   }
>   
> +/*
> + * Try to collapse a single PMD starting at a PMD aligned addr, and return
> + * the results.
> + */
> +static enum scan_result collapse_single_pmd(unsigned long addr,
> +		struct vm_area_struct *vma, bool *mmap_locked,
> +		struct collapse_control *cc)
> +{
> +	struct mm_struct *mm = vma->vm_mm;
> +	enum scan_result result;
> +	struct file *file;
> +	pgoff_t pgoff;
> +
> +	if (vma_is_anonymous(vma)) {
> +		result = collapse_scan_pmd(mm, vma, addr, mmap_locked, cc);
> +		goto end;
> +	}
> +
> +	file = get_file(vma->vm_file);
> +	pgoff = linear_page_index(vma, addr);
> +
> +	mmap_read_unlock(mm);
> +	*mmap_locked = false;
> +	result = collapse_scan_file(mm, addr, file, pgoff, cc);
> +	fput(file);
> +
> +	if (result != SCAN_PTE_MAPPED_HUGEPAGE)
> +		goto end;
> +
> +	mmap_read_lock(mm);
> +	*mmap_locked = true;
> +	if (collapse_test_exit_or_disable(mm)) {
> +		mmap_read_unlock(mm);
> +		*mmap_locked = false;
> +		return SCAN_ANY_PROCESS;
> +	}
> +	result = try_collapse_pte_mapped_thp(mm, addr, !cc->is_khugepaged);
> +	if (result == SCAN_PMD_MAPPED)
> +		result = SCAN_SUCCEED;
> +	mmap_read_unlock(mm);
> +	*mmap_locked = false;
> +
> +end:
> +	if (cc->is_khugepaged && result == SCAN_SUCCEED)
> +		++khugepaged_pages_collapsed;
> +	return result;
> +}
> +
>   static unsigned int collapse_scan_mm_slot(unsigned int pages, enum scan_result *result,
>   					    struct collapse_control *cc)
>   	__releases(&khugepaged_mm_lock)
> @@ -2466,34 +2514,9 @@ static unsigned int collapse_scan_mm_slot(unsigned int pages, enum scan_result *
>   			VM_BUG_ON(khugepaged_scan.address < hstart ||
>   				  khugepaged_scan.address + HPAGE_PMD_SIZE >
>   				  hend);
> -			if (!vma_is_anonymous(vma)) {
> -				struct file *file = get_file(vma->vm_file);
> -				pgoff_t pgoff = linear_page_index(vma,
> -						khugepaged_scan.address);
> -
> -				mmap_read_unlock(mm);
> -				mmap_locked = false;
> -				*result = collapse_scan_file(mm,
> -					khugepaged_scan.address, file, pgoff, cc);
> -				fput(file);
> -				if (*result == SCAN_PTE_MAPPED_HUGEPAGE) {
> -					mmap_read_lock(mm);
> -					if (collapse_test_exit_or_disable(mm))
> -						goto breakouterloop;
> -					*result = try_collapse_pte_mapped_thp(mm,
> -						khugepaged_scan.address, false);
> -					if (*result == SCAN_PMD_MAPPED)
> -						*result = SCAN_SUCCEED;
> -					mmap_read_unlock(mm);
> -				}
> -			} else {
> -				*result = collapse_scan_pmd(mm, vma,
> -					khugepaged_scan.address, &mmap_locked, cc);
> -			}
> -
> -			if (*result == SCAN_SUCCEED)
> -				++khugepaged_pages_collapsed;
>   
> +			*result = collapse_single_pmd(khugepaged_scan.address,
> +						      vma, &mmap_locked, cc);
>   			/* move to next address */
>   			khugepaged_scan.address += HPAGE_PMD_SIZE;
>   			progress += HPAGE_PMD_NR;
> @@ -2799,6 +2822,7 @@ int madvise_collapse(struct vm_area_struct *vma, unsigned long start,
>   			cond_resched();
>   			mmap_read_lock(mm);
>   			mmap_locked = true;
> +			*lock_dropped = true;
>   			result = hugepage_vma_revalidate(mm, addr, false, &vma,
>   							 cc);
>   			if (result  != SCAN_SUCCEED) {
> @@ -2809,17 +2833,17 @@ int madvise_collapse(struct vm_area_struct *vma, unsigned long start,
>   			hend = min(hend, vma->vm_end & HPAGE_PMD_MASK);
>   		}
>   		mmap_assert_locked(mm);
> -		if (!vma_is_anonymous(vma)) {
> -			struct file *file = get_file(vma->vm_file);
> -			pgoff_t pgoff = linear_page_index(vma, addr);
>   
> -			mmap_read_unlock(mm);
> -			mmap_locked = false;
> +		result = collapse_single_pmd(addr, vma, &mmap_locked, cc);
> +
> +		if (!mmap_locked)
>   			*lock_dropped = true;
> -			result = collapse_scan_file(mm, addr, file, pgoff, cc);
>   
> -			if (result == SCAN_PAGE_DIRTY_OR_WRITEBACK && !triggered_wb &&
> -			    mapping_can_writeback(file->f_mapping)) {
> +		if (result == SCAN_PAGE_DIRTY_OR_WRITEBACK && !triggered_wb) {
> +			struct file *file = get_file(vma->vm_file);
> +			pgoff_t pgoff = linear_page_index(vma, addr);


After collapse_single_pmd() returns, mmap_lock might have been released. 
Between
that unlock and here, another thread could unmap/remap the VMA, making 
the vma
pointer stale when we access vma->vm_file?

Would it be safer to get the file reference before calling 
collapse_single_pmd()?
Or we need to revalidate the VMA after getting the lock back?


Thanks,
Lance

> +
> +			if (mapping_can_writeback(file->f_mapping)) {
>   				loff_t lstart = (loff_t)pgoff << PAGE_SHIFT;
>   				loff_t lend = lstart + HPAGE_PMD_SIZE - 1;
>   
> @@ -2829,26 +2853,16 @@ int madvise_collapse(struct vm_area_struct *vma, unsigned long start,
>   				goto retry;
>   			}
>   			fput(file);
> -		} else {
> -			result = collapse_scan_pmd(mm, vma, addr, &mmap_locked, cc);
>   		}
> -		if (!mmap_locked)
> -			*lock_dropped = true;
>   
> -handle_result:
>   		switch (result) {
>   		case SCAN_SUCCEED:
>   		case SCAN_PMD_MAPPED:
>   			++thps;
>   			break;
> -		case SCAN_PTE_MAPPED_HUGEPAGE:
> -			BUG_ON(mmap_locked);
> -			mmap_read_lock(mm);
> -			result = try_collapse_pte_mapped_thp(mm, addr, true);
> -			mmap_read_unlock(mm);
> -			goto handle_result;
>   		/* Whitelisted set of results where continuing OK */
>   		case SCAN_NO_PTE_TABLE:
> +		case SCAN_PTE_MAPPED_HUGEPAGE:
>   		case SCAN_PTE_NON_PRESENT:
>   		case SCAN_PTE_UFFD_WP:
>   		case SCAN_LACK_REFERENCED_PAGE:


^ permalink raw reply

* [PATCH] tracing: Remove notrace from trace_event_raw_event_synth()
From: Steven Rostedt @ 2026-01-23  1:45 UTC (permalink / raw)
  To: LKML, Linux Trace Kernel; +Cc: Masami Hiramatsu, Mathieu Desnoyers, Tom Zanussi

From: Steven Rostedt <rostedt@goodmis.org>

When debugging the synthetic events, being able to function trace its
functions is very useful (now that CONFIG_FUNCTION_SELF_TRACING is
available). For some reason trace_event_raw_event_synth() was marked as
"notrace", which was totally unnecessary as all of the tracing directory
had function tracing disabled until the recent FUNCTION_SELF_TRACING was
added.

Remove the notrace annotation from trace_event_raw_event_synth() as
there's no reason to not trace it when tracing synthetic event functions.

Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
 kernel/trace/trace_events_synth.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/kernel/trace/trace_events_synth.c b/kernel/trace/trace_events_synth.c
index 4554c458b78c..79a506fc2856 100644
--- a/kernel/trace/trace_events_synth.c
+++ b/kernel/trace/trace_events_synth.c
@@ -493,9 +493,9 @@ static unsigned int trace_stack(struct synth_trace_event *entry,
 	return len;
 }
 
-static notrace void trace_event_raw_event_synth(void *__data,
-						u64 *var_ref_vals,
-						unsigned int *var_ref_idx)
+static void trace_event_raw_event_synth(void *__data,
+					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;
-- 
2.51.0


^ permalink raw reply related

* [PATCH] tracing: Have hist_debug show what function a field uses
From: Steven Rostedt @ 2026-01-23  1:38 UTC (permalink / raw)
  To: LKML, Linux Trace Kernel; +Cc: Masami Hiramatsu, Mathieu Desnoyers, Tom Zanussi

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.

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


^ permalink raw reply related

* [PATCH] tracing: kprobe-event: Return directly when dyn_event_list is empty
From: sunliming @ 2026-01-23  1:36 UTC (permalink / raw)
  To: rostedt, mhiramat
  Cc: mathieu.desnoyers, linux-kernel, linux-trace-kernel, sunliming

From: sunliming <sunliming@kylinos.cn>

In enable_boot_kprobe_events(), it returns directly when dyn_event_list 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 dyn_event_list is empty.

Signed-off-by: sunliming <sunliming@kylinos.cn>
---
 kernel/trace/trace_kprobe.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 9953506370a5..d89a403c99d4 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -1982,6 +1982,9 @@ static __init void enable_boot_kprobe_events(void)
 	struct trace_kprobe *tk;
 	struct dyn_event *pos;
 
+	if (list_empty(&dyn_event_list))
+		return;
+
 	guard(mutex)(&event_mutex);
 	for_each_trace_kprobe(tk, pos) {
 		list_for_each_entry(file, &tr->events, list)
-- 
2.25.1


^ permalink raw reply related

* [PATCH] tracing: Fix crash on synthetic stacktrace field usage
From: Steven Rostedt @ 2026-01-23  0:48 UTC (permalink / raw)
  To: LKML, Linux Trace Kernel; +Cc: Masami Hiramatsu, Mathieu Desnoyers, Tom Zanussi

From: Steven Rostedt <rostedt@goodmis.org>

When creating a synthetic event based on an existing synthetic event that
had a stacktrace field and the new synthetic event used that field a
kernel crash occurred:

 ~# cd /sys/kernel/tracing
 ~# echo 's:stack unsigned long stack[];' > dynamic_events
 ~# echo 'hist:keys=prev_pid:s0=common_stacktrace if prev_state & 3' >> events/sched/sched_switch/trigger
 ~# echo 'hist:keys=next_pid:s1=$s0:onmatch(sched.sched_switch).trace(stack,$s1)' >> events/sched/sched_switch/trigger

The above creates a synthetic event that takes a stacktrace when a task
schedules out in a non-running state and passes that stacktrace to the
sched_switch event when that task schedules back in. It triggers the
"stack" synthetic event that has a stacktrace as its field (called "stack").

 ~# echo 's:syscall_stack s64 id; unsigned long stack[];' >> dynamic_events
 ~# echo 'hist:keys=common_pid:s2=stack' >> events/synthetic/stack/trigger
 ~# echo 'hist:keys=common_pid:s3=$s2,i0=id:onmatch(synthetic.stack).trace(syscall_stack,$i0,$s3)' >> events/raw_syscalls/sys_exit/trigger

The above makes another synthetic event called "syscall_stack" that
attaches the first synthetic event (stack) to the sys_exit trace event and
records the stacktrace from the stack event with the id of the system call
that is exiting.

When enabling this event (or using it in a historgram):

 ~# echo 1 > events/synthetic/syscall_stack/enable

Produces a kernel crash!

 BUG: unable to handle page fault for address: 0000000000400010
 #PF: supervisor read access in kernel mode
 #PF: error_code(0x0000) - not-present page
 PGD 0 P4D 0
 Oops: Oops: 0000 [#1] SMP PTI
 CPU: 6 UID: 0 PID: 1257 Comm: bash Not tainted 6.16.3+deb14-amd64 #1 PREEMPT(lazy)  Debian 6.16.3-1
 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.17.0-debian-1.17.0-1 04/01/2014
 RIP: 0010:trace_event_raw_event_synth+0x90/0x380
 Code: c5 00 00 00 00 85 d2 0f 84 e1 00 00 00 31 db eb 34 0f 1f 00 66 66 2e 0f 1f 84 00 00 00 00 00 66 66 2e 0f 1f 84 00 00 00 00 00 <49> 8b 04 24 48 83 c3 01 8d 0c c5 08 00 00 00 01 cd 41 3b 5d 40 0f
 RSP: 0018:ffffd2670388f958 EFLAGS: 00010202
 RAX: ffff8ba1065cc100 RBX: 0000000000000000 RCX: 0000000000000000
 RDX: 0000000000000001 RSI: fffff266ffda7b90 RDI: ffffd2670388f9b0
 RBP: 0000000000000010 R08: ffff8ba104e76000 R09: ffffd2670388fa50
 R10: ffff8ba102dd42e0 R11: ffffffff9a908970 R12: 0000000000400010
 R13: ffff8ba10a246400 R14: ffff8ba10a710220 R15: fffff266ffda7b90
 FS:  00007fa3bc63f740(0000) GS:ffff8ba2e0f48000(0000) knlGS:0000000000000000
 CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
 CR2: 0000000000400010 CR3: 0000000107f9e003 CR4: 0000000000172ef0
 Call Trace:
  <TASK>
  ? __tracing_map_insert+0x208/0x3a0
  action_trace+0x67/0x70
  event_hist_trigger+0x633/0x6d0
  event_triggers_call+0x82/0x130
  trace_event_buffer_commit+0x19d/0x250
  trace_event_raw_event_sys_exit+0x62/0xb0
  syscall_exit_work+0x9d/0x140
  do_syscall_64+0x20a/0x2f0
  ? trace_event_raw_event_sched_switch+0x12b/0x170
  ? save_fpregs_to_fpstate+0x3e/0x90
  ? _raw_spin_unlock+0xe/0x30
  ? finish_task_switch.isra.0+0x97/0x2c0
  ? __rseq_handle_notify_resume+0xad/0x4c0
  ? __schedule+0x4b8/0xd00
  ? restore_fpregs_from_fpstate+0x3c/0x90
  ? switch_fpu_return+0x5b/0xe0
  ? do_syscall_64+0x1ef/0x2f0
  ? do_fault+0x2e9/0x540
  ? __handle_mm_fault+0x7d1/0xf70
  ? count_memcg_events+0x167/0x1d0
  ? handle_mm_fault+0x1d7/0x2e0
  ? do_user_addr_fault+0x2c3/0x7f0
  entry_SYSCALL_64_after_hwframe+0x76/0x7e

The reason is that the stacktrace field is not labeled as such, and is
treated as a normal field and not as a dynamic event that it is.

In trace_event_raw_event_synth() the event is field is still treated as a
dynamic array, but the retrieval of the data is considered a normal field,
and the reference is just the meta data:

// Meta data is retrieved instead of a dynamic array
  str_val = (char *)(long)var_ref_vals[val_idx];

// Then when it tries to process it:
  len = *((unsigned long *)str_val) + 1;

It triggers a kernel page fault.

To fix this, first when defining the fields of the first synthetic event,
set the filter type to FILTER_STACKTRACE. This is used later by the second
synthetic event to know that this field is a stacktrace. When creating
the field of the new synthetic event, have it use this FILTER_STACKTRACE
to know to create a stacktrace field to copy the stacktrace into.

Cc: stable@vger.kernel.org
Fixes: 00cf3d672a9d ("tracing: Allow synthetic events to pass around stacktraces")
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
 kernel/trace/trace_events_hist.c  | 9 +++++++++
 kernel/trace/trace_events_synth.c | 8 +++++++-
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
index 5e6e70540eef..c97bb2fda5c0 100644
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -2057,6 +2057,15 @@ static struct hist_field *create_hist_field(struct hist_trigger_data *hist_data,
 			hist_field->fn_num = HIST_FIELD_FN_RELDYNSTRING;
 		else
 			hist_field->fn_num = HIST_FIELD_FN_PSTRING;
+	} else if (field->filter_type == FILTER_STACKTRACE) {
+		flags |= HIST_FIELD_FL_STACKTRACE;
+
+		hist_field->size = MAX_FILTER_STR_VAL;
+		hist_field->type = kstrdup_const(field->type, GFP_KERNEL);
+		if (!hist_field->type)
+			goto free;
+
+		hist_field->fn_num = HIST_FIELD_FN_STACK;
 	} else {
 		hist_field->size = field->size;
 		hist_field->is_signed = field->is_signed;
diff --git a/kernel/trace/trace_events_synth.c b/kernel/trace/trace_events_synth.c
index 4554c458b78c..45c187e77e21 100644
--- a/kernel/trace/trace_events_synth.c
+++ b/kernel/trace/trace_events_synth.c
@@ -130,7 +130,9 @@ static int synth_event_define_fields(struct trace_event_call *call)
 	struct synth_event *event = call->data;
 	unsigned int i, size, n_u64;
 	char *name, *type;
+	int filter_type;
 	bool is_signed;
+	bool is_stack;
 	int ret = 0;
 
 	for (i = 0, n_u64 = 0; i < event->n_fields; i++) {
@@ -138,8 +140,12 @@ static int synth_event_define_fields(struct trace_event_call *call)
 		is_signed = event->fields[i]->is_signed;
 		type = event->fields[i]->type;
 		name = event->fields[i]->name;
+		is_stack = event->fields[i]->is_stack;
+
+		filter_type = is_stack ? FILTER_STACKTRACE : FILTER_OTHER;
+
 		ret = trace_define_field(call, type, name, offset, size,
-					 is_signed, FILTER_OTHER);
+					 is_signed, filter_type);
 		if (ret)
 			break;
 
-- 
2.51.0


^ permalink raw reply related

* Re: [PATCH V5 2/2] mm/khugepaged: retry with sync writeback for MADV_COLLAPSE
From: David Hildenbrand (Red Hat) @ 2026-01-22 22:34 UTC (permalink / raw)
  To: Dev Jain, Shivank Garg, Andrew Morton, Lorenzo Stoakes
  Cc: Zi Yan, Baolin Wang, Liam R . Howlett, Nico Pache, Ryan Roberts,
	Barry Song, Lance Yang, Masami Hiramatsu, Steven Rostedt,
	linux-trace-kernel, Mathieu Desnoyers, Zach O'Keefe, linux-mm,
	linux-kernel, Stephen Rothwell, Branden Moore
In-Reply-To: <3aaa3e5d-7f66-40fc-a5b0-ea6a384a88a8@arm.com>

On 1/22/26 12:07, Dev Jain wrote:
> 
> On 19/01/26 12:39 am, Shivank Garg wrote:
>> When MADV_COLLAPSE is called on file-backed mappings (e.g., executable
>> text sections), the pages may still be dirty from recent writes.
>> collapse_file() will trigger async writeback and fail with
>> SCAN_PAGE_DIRTY_OR_WRITEBACK (-EAGAIN).
>>
>> MADV_COLLAPSE is a synchronous operation where userspace expects
>> immediate results. If the collapse fails due to dirty pages, perform
>> synchronous writeback on the specific range and retry once.
>>
>> This avoids spurious failures for freshly written executables while
>> avoiding unnecessary synchronous I/O for mappings that are already clean.
>>
>> Reported-by: Branden Moore <Branden.Moore@amd.com>
>> Closes: https://lore.kernel.org/all/4e26fe5e-7374-467c-a333-9dd48f85d7cc@amd.com
>> Fixes: 34488399fa08 ("mm/madvise: add file and shmem support to MADV_COLLAPSE")
>> Suggested-by: David Hildenbrand <david@kernel.org>
>> Tested-by: Lance Yang <lance.yang@linux.dev>
>> Signed-off-by: Shivank Garg <shivankg@amd.com>
>> ---
>>   mm/khugepaged.c | 15 +++++++++++++++
>>   1 file changed, 15 insertions(+)
>>
>> diff --git a/mm/khugepaged.c b/mm/khugepaged.c
>> index 219dfa2e523c..16582bdcb6ff 100644
>> --- a/mm/khugepaged.c
>> +++ b/mm/khugepaged.c
>> @@ -22,6 +22,7 @@
>>   #include <linux/dax.h>
>>   #include <linux/ksm.h>
>>   #include <linux/pgalloc.h>
>> +#include <linux/backing-dev.h>
>>   
>>   #include <asm/tlb.h>
>>   #include "internal.h"
>> @@ -2788,7 +2789,9 @@ int madvise_collapse(struct vm_area_struct *vma, unsigned long start,
>>   
>>   	for (addr = hstart; addr < hend; addr += HPAGE_PMD_SIZE) {
>>   		int result = SCAN_FAIL;
>> +		bool triggered_wb = false;
>>   
>> +retry:
>>   		if (!mmap_locked) {
>>   			cond_resched();
>>   			mmap_read_lock(mm);
>> @@ -2809,8 +2812,20 @@ int madvise_collapse(struct vm_area_struct *vma, unsigned long start,
>>   
>>   			mmap_read_unlock(mm);
>>   			mmap_locked = false;
>> +			*lock_dropped = true;
>>   			result = hpage_collapse_scan_file(mm, addr, file, pgoff,
>>   							  cc);
>> +
>> +			if (result == SCAN_PAGE_DIRTY_OR_WRITEBACK && !triggered_wb &&
>> +			    mapping_can_writeback(file->f_mapping)) {
>> +				loff_t lstart = (loff_t)pgoff << PAGE_SHIFT;
>> +				loff_t lend = lstart + HPAGE_PMD_SIZE - 1;
>> +
>> +				filemap_write_and_wait_range(file->f_mapping, lstart, lend);
> 
> So we don't care about the return value here because this is best-effort.
> I really wish we had in our coding-style.rst to typecast such things to (void),
> so we know explicitly that we are ignoring the return value, and not that the
> function itself returns void.

That makes functions like bitmap_and() hard (and ugly) to use that just 
return some value for the caller's convenience.

For functions where we really want callers to think about this, we can 
enforce such checks through __must_check.

Here, it's rather obvious that we don't care about the result as we only 
retry once to then give up.

-- 
Cheers

David

^ permalink raw reply

* [syzbot] Monthly trace report (Jan 2026)
From: syzbot @ 2026-01-22 21:23 UTC (permalink / raw)
  To: linux-kernel, linux-trace-kernel, syzkaller-bugs

Hello trace maintainers/developers,

This is a 31-day syzbot report for the trace subsystem.
All related reports/information can be found at:
https://syzkaller.appspot.com/upstream/s/trace

During the period, 1 new issues were detected and 0 were fixed.
In total, 11 issues are still open and 62 have already been fixed.

Some of the still happening issues:

Ref Crashes Repro Title
<1> 101     Yes   WARNING in blk_register_tracepoints
                  https://syzkaller.appspot.com/bug?extid=c54ded83396afee31eb1
<2> 96      Yes   WARNING in tracepoint_probe_unregister (3)
                  https://syzkaller.appspot.com/bug?extid=a1d25e53cd4a10f7f2d3
<3> 71      Yes   INFO: task hung in blk_trace_ioctl (4)
                  https://syzkaller.appspot.com/bug?extid=ed812ed461471ab17a0c
<4> 63      Yes   INFO: task hung in blk_trace_remove (2)
                  https://syzkaller.appspot.com/bug?extid=2373f6be3e6de4f92562
<5> 26      Yes   INFO: task hung in relay_open (2)
                  https://syzkaller.appspot.com/bug?extid=16ea22f26882d7e46f35
<6> 22      Yes   WARNING in get_probe_ref
                  https://syzkaller.appspot.com/bug?extid=8672dcb9d10011c0a160
<7> 14      No    WARNING in ring_buffer_map_get_reader (2)
                  https://syzkaller.appspot.com/bug?extid=c7143161d8215214a993

---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.

To disable reminders for individual bugs, reply with the following command:
#syz set <Ref> no-reminders

To change bug's subsystems, reply with:
#syz set <Ref> subsystems: new-subsystem

You may send multiple commands in a single email message.

^ permalink raw reply

* [PATCH mm-unstable v14 16/16] Documentation: mm: update the admin guide for mTHP collapse
From: Nico Pache @ 2026-01-22 19:28 UTC (permalink / raw)
  To: linux-mm, linux-doc, linux-kernel, linux-trace-kernel
  Cc: npache, akpm, david, lorenzo.stoakes, ziy, baolin.wang,
	Liam.Howlett, ryan.roberts, dev.jain, baohua, lance.yang, vbabka,
	rppt, surenb, mhocko, corbet, rostedt, mhiramat,
	mathieu.desnoyers, matthew.brost, joshua.hahnjy, rakie.kim,
	byungchul, gourry, ying.huang, apopple, jannh, pfalcato, jackmanb,
	hannes, willy, peterx, wangkefeng.wang, usamaarif642, sunnanyong,
	vishal.moola, thomas.hellstrom, yang, kas, aarcange, raquini,
	anshuman.khandual, catalin.marinas, tiwai, will, dave.hansen,
	jack, cl, jglisse, zokeefe, rientjes, rdunlap, hughd,
	richard.weiyang, Bagas Sanjaya
In-Reply-To: <20260122192841.128719-1-npache@redhat.com>

Now that we can collapse to mTHPs lets update the admin guide to
reflect these changes and provide proper guidance on how to utilize it.

Reviewed-by: Bagas Sanjaya <bagasdotme@gmail.com>
Signed-off-by: Nico Pache <npache@redhat.com>
---
 Documentation/admin-guide/mm/transhuge.rst | 48 +++++++++++++---------
 1 file changed, 28 insertions(+), 20 deletions(-)

diff --git a/Documentation/admin-guide/mm/transhuge.rst b/Documentation/admin-guide/mm/transhuge.rst
index eebb1f6bbc6c..67836c683e8d 100644
--- a/Documentation/admin-guide/mm/transhuge.rst
+++ b/Documentation/admin-guide/mm/transhuge.rst
@@ -63,7 +63,8 @@ often.
 THP can be enabled system wide or restricted to certain tasks or even
 memory ranges inside task's address space. Unless THP is completely
 disabled, there is ``khugepaged`` daemon that scans memory and
-collapses sequences of basic pages into PMD-sized huge pages.
+collapses sequences of basic pages into huge pages of either PMD size
+or mTHP sizes, if the system is configured to do so.
 
 The THP behaviour is controlled via :ref:`sysfs <thp_sysfs>`
 interface and using madvise(2) and prctl(2) system calls.
@@ -219,10 +220,10 @@ this behaviour by writing 0 to shrink_underused, and enable it by writing
 	echo 0 > /sys/kernel/mm/transparent_hugepage/shrink_underused
 	echo 1 > /sys/kernel/mm/transparent_hugepage/shrink_underused
 
-khugepaged will be automatically started when PMD-sized THP is enabled
+khugepaged will be automatically started when any THP size is enabled
 (either of the per-size anon control or the top-level control are set
 to "always" or "madvise"), and it'll be automatically shutdown when
-PMD-sized THP is disabled (when both the per-size anon control and the
+all THP sizes are disabled (when both the per-size anon control and the
 top-level control are "never")
 
 process THP controls
@@ -264,11 +265,6 @@ support the following arguments::
 Khugepaged controls
 -------------------
 
-.. note::
-   khugepaged currently only searches for opportunities to collapse to
-   PMD-sized THP and no attempt is made to collapse to other THP
-   sizes.
-
 khugepaged runs usually at low frequency so while one may not want to
 invoke defrag algorithms synchronously during the page faults, it
 should be worth invoking defrag at least in khugepaged. However it's
@@ -296,11 +292,11 @@ allocation failure to throttle the next allocation attempt::
 The khugepaged progress can be seen in the number of pages collapsed (note
 that this counter may not be an exact count of the number of pages
 collapsed, since "collapsed" could mean multiple things: (1) A PTE mapping
-being replaced by a PMD mapping, or (2) All 4K physical pages replaced by
-one 2M hugepage. Each may happen independently, or together, depending on
-the type of memory and the failures that occur. As such, this value should
-be interpreted roughly as a sign of progress, and counters in /proc/vmstat
-consulted for more accurate accounting)::
+being replaced by a PMD mapping, or (2) physical pages replaced by one
+hugepage of various sizes (PMD-sized or mTHP). Each may happen independently,
+or together, depending on the type of memory and the failures that occur.
+As such, this value should be interpreted roughly as a sign of progress,
+and counters in /proc/vmstat consulted for more accurate accounting)::
 
 	/sys/kernel/mm/transparent_hugepage/khugepaged/pages_collapsed
 
@@ -308,16 +304,19 @@ for each pass::
 
 	/sys/kernel/mm/transparent_hugepage/khugepaged/full_scans
 
-``max_ptes_none`` specifies how many extra small pages (that are
-not already mapped) can be allocated when collapsing a group
-of small pages into one large page::
+``max_ptes_none`` specifies how many empty (none/zero) pages are allowed
+when collapsing a group of small pages into one large page::
 
 	/sys/kernel/mm/transparent_hugepage/khugepaged/max_ptes_none
 
-A higher value leads to use additional memory for programs.
-A lower value leads to gain less thp performance. Value of
-max_ptes_none can waste cpu time very little, you can
-ignore it.
+For PMD-sized THP collapse, this directly limits the number of empty pages
+allowed in the 2MB region. For mTHP collapse, only 0 or (HPAGE_PMD_NR - 1)
+are supported. Any other value will emit a warning and no mTHP collapse
+will be attempted.
+
+A higher value allows more empty pages, potentially leading to more memory
+usage but better THP performance. A lower value is more conservative and
+may result in fewer THP collapses.
 
 ``max_ptes_swap`` specifies how many pages can be brought in from
 swap when collapsing a group of pages into a transparent huge page::
@@ -337,6 +336,15 @@ that THP is shared. Exceeding the number would block the collapse::
 
 A higher value may increase memory footprint for some workloads.
 
+.. note::
+   For mTHP collapse, khugepaged does not support collapsing regions that
+   contain shared or swapped out pages, as this could lead to continuous
+   promotion to higher orders. The collapse will fail if any shared or
+   swapped PTEs are encountered during the scan.
+
+   Currently, madvise_collapse only supports collapsing to PMD-sized THPs
+   and does not attempt mTHP collapses.
+
 Boot parameters
 ===============
 
-- 
2.52.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