* Re: [PATCH v6 3/4] mm/memory-failure: add panic option for unrecoverable pages
From: Breno Leitao @ 2026-05-12 13:05 UTC (permalink / raw)
To: David Hildenbrand (Arm)
Cc: Miaohe Lin, Naoya Horiguchi, Andrew Morton, Jonathan Corbet,
Shuah Khan, Lorenzo Stoakes, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Shuah Khan, Steven Rostedt,
Masami Hiramatsu, Mathieu Desnoyers, Liam R. Howlett, linux-mm,
linux-kernel, linux-doc, linux-kselftest, linux-trace-kernel,
kernel-team
In-Reply-To: <8d4940bc-d8c4-4e7f-a35d-979e6a781966@kernel.org>
On Tue, May 12, 2026 at 10:22:38AM +0200, David Hildenbrand (Arm) wrote:
>
> > @@ -1281,6 +1292,18 @@ static void update_per_node_mf_stats(unsigned long pfn,
> > ++mf_stats->total;
> > }
> >
> > +static bool panic_on_unrecoverable_mf(enum mf_action_page_type type,
> > + enum mf_result result)
> > +{
> > + if (!sysctl_panic_on_unrecoverable_mf || result != MF_IGNORED)
> > + return false;
> > +
> > + if (type == MF_MSG_KERNEL)
> > + return true;
> > +
> > + return false;
>
> return type == MF_MSG_KERNEL;
>
> might be simpler.
Ack, I will update once we decide about the other pendencies.
^ permalink raw reply
* Re: [RFC PATCH v2 06/10] rvgen: support reset() on the __init arrow for global-window HA clocks
From: Gabriele Monaco @ 2026-05-12 13:25 UTC (permalink / raw)
To: wen.yang; +Cc: linux-trace-kernel, linux-kernel, Steven Rostedt
In-Reply-To: <aa156a1c7696e054f8db57c48a26fa6ec1e17395.1778522945.git.wen.yang@linux.dev>
On Tue, 2026-05-12 at 02:24 +0800, wen.yang@linux.dev wrote:
> From: Wen Yang <wen.yang@linux.dev>
>
> rvgen rejects a state invariant when its env is never reset on any
> state-transition edge. This prevents expressing monitors where a clock
> tracks the full monitoring window — reset once at object creation,
> active in all states.
>
> Allow reset() annotations on the __init_STATE -> STATE arrow.
> automata.py adds listed envs to the new env_init_started set (and to
> env_stored so the HA framework allocates per-object storage). dot2k.py
> uses env_init_started for three purposes:
>
> - Generate a handle_monitor_start() skeleton that resets the env and
> arms the timer after the caller sets up DA storage and initial state.
>
> - Guard ha_inv_to_guard calls with !ha_monitor_env_invalid() for these
> envs: a concurrent DA event between da_handle_start_event() and
> ha_reset_env() would otherwise store U64_MAX - BUDGET as the guard
> anchor, silently disabling enforcement.
>
> - Always generate ha_verify_guards() for monitors with invariants,
> providing a stable extension point for future per-event guards.
>
> Models without __init resets (e.g. stall.dot) are unaffected.
>
> Signed-off-by: Wen Yang <wen.yang@linux.dev>
Mmh, I see that's an issue, but technically the init arrow isn't a real state
transition. In your case, you have a start condition that you labelled
"switch_in_tlob" although it isn't a switch in.
Why don't you make it a separate event (e.g. "start_tlob"), it seems to me you
cannot really have that occur multiple times, so doing the following wouldn't
harm and you wouldn't need to change how HA monitors work:
|
|
v
+-----------------------------+ start;reset(clk)
| running | -------------------+
switch_in | clk < BUDGET_NS() | |
+---------> | | <------------------+
| +-----------------------------+
| | |
| | sleep |
| v |
| |
| sleeping |
| clk < BUDGET_NS() |
| | preempt
| | |
| | wakeup |
| v |
| |
| waiting |
+---------- clk < BUDGET_NS() <+
Then you also wouldn't need to call reset() and start_timer() manually.
Isn't that feasible?
Thanks,
Gabriele
> ---
> tools/verification/rvgen/rvgen/automata.py | 26 ++++++
> tools/verification/rvgen/rvgen/dot2k.py | 100 +++++++++++++++++++--
> 2 files changed, 119 insertions(+), 7 deletions(-)
>
> diff --git a/tools/verification/rvgen/rvgen/automata.py
> b/tools/verification/rvgen/rvgen/automata.py
> index b9f8149f7118..178a1a4ffd8a 100644
> --- a/tools/verification/rvgen/rvgen/automata.py
> +++ b/tools/verification/rvgen/rvgen/automata.py
> @@ -69,15 +69,41 @@ class Automata:
> self.states, self.initial_state, self.final_states =
> self.__get_state_variables()
> self.env_types = {}
> self.env_stored = set()
> + self.env_init_started = set()
> self.constraint_vars = set()
> self.self_loop_reset_events = set()
> self.events, self.envs = self.__get_event_variables()
> + self.__parse_init_resets()
> self.function, self.constraints = self.__create_matrix()
> self.events_start, self.events_start_run = self.__store_init_events()
> self.env_stored = sorted(self.env_stored)
> + self.env_init_started = sorted(self.env_init_started)
> self.constraint_vars = sorted(self.constraint_vars)
> self.self_loop_reset_events = sorted(self.self_loop_reset_events)
>
> + def __parse_init_resets(self) -> None:
> + """Parse reset() annotations on the __init_STATE -> STATE arrow.
> +
> + Adds each listed env to env_stored (HA framework allocates per-object
> + storage) and env_init_started (ha2k generates
> handle_monitor_start()).
> + """
> + init_prefix = f'"{self.init_marker}'
> + for line in map(str.lstrip, self.__dot_lines):
> + if not line.startswith(init_prefix):
> + continue
> + split_line = line.split()
> + if len(split_line) < 3 or split_line[1] != "->":
> + continue
> + if "label" not in line:
> + continue
> + label = "".join(split_line[split_line.index("label") + 2:-
> 1]).replace('"', '')
> + for part in label.split(";"):
> + reset_m = self.constraint_reset.search(part.strip())
> + if reset_m:
> + env = reset_m["env"]
> + self.env_stored.add(env)
> + self.env_init_started.add(env)
> +
> def __get_model_name(self) -> str:
> basename = ntpath.basename(self.__dot_path)
> if not basename.endswith(".dot") and not basename.endswith(".gv"):
> diff --git a/tools/verification/rvgen/rvgen/dot2k.py
> b/tools/verification/rvgen/rvgen/dot2k.py
> index e6f476b903b0..e8066260c0af 100644
> --- a/tools/verification/rvgen/rvgen/dot2k.py
> +++ b/tools/verification/rvgen/rvgen/dot2k.py
> @@ -366,7 +366,18 @@ f"""static inline void ha_convert_inv_guard(struct
> ha_monitor *ha_mon,
> conf_g = [e for s, e in conflict_guards if s == state]
> if not conf_i and not conf_g:
> continue
> - buff.append(f"\t{_else}if (curr_state ==
> {self.states[state]}{self.enum_suffix})")
> +
> + state_name = f"{self.states[state]}{self.enum_suffix}"
> + env_full = self.__get_constraint_env(constr)
> + env_bare = env_full[:-len(self.enum_suffix)]
> + if env_bare in self.env_init_started:
> + # env_store is ENV_INVALID_VALUE until
> handle_monitor_start();
> + # skip ha_inv_to_guard during the init race window.
> + cont = "\t\t " if _else else "\t "
> + buff.append(f"\t{_else}if (curr_state == {state_name} &&")
> + buff.append(f"{cont}!ha_monitor_env_invalid(ha_mon,
> {env_full}))")
> + else:
> + buff.append(f"\t{_else}if (curr_state == {state_name})")
>
> buff.append(f"\t\t{self.__start_to_conv(constr)};")
> _else = "else "
> @@ -376,16 +387,22 @@ f"""static inline void ha_convert_inv_guard(struct
> ha_monitor *ha_mon,
>
> def __fill_verify_guards_func(self) -> list[str]:
> buff = []
> - if not self.guards:
> + # Always generate for monitors with invariants: stable extension
> + # point for future guard conditions.
> + if not self.guards and not self.invariants:
> return []
>
> buff.append(
> f"""static inline bool ha_verify_guards(struct ha_monitor *ha_mon,
> \t\t\t\t enum {self.enum_states_def} curr_state, enum
> {self.enum_events_def} event,
> \t\t\t\t enum {self.enum_states_def} next_state, u64 time_ns)
> -{{
> -\tbool res = true;
> -""")
> +{{""")
> +
> + if not self.guards:
> + buff.append("\treturn true;\n}\n")
> + return buff
> +
> + buff.append("\tbool res = true;\n")
>
> _else = ""
> for edge, constr in sorted(self.guards.items()):
> @@ -522,7 +539,7 @@ f"""static bool ha_verify_constraint(struct ha_monitor
> *ha_mon,
> buff.append("\tha_convert_inv_guard(ha_mon, curr_state, event, "
> "next_state, time_ns);\n")
>
> - if self.guards:
> + if self.guards or self.invariants:
> buff.append("\tif (!ha_verify_guards(ha_mon, curr_state, event, "
> "next_state, time_ns))\n\t\treturn false;\n")
>
> @@ -599,8 +616,77 @@ f"""static bool ha_verify_constraint(struct ha_monitor
> *ha_mon,
> buff.append("}\n")
> return buff
>
> + def __fill_init_start_helper(self) -> list[str]:
> + """Generate handle_monitor_start() for envs reset on the __init
> arrow.
> +
> + env_store is invalid inside da_handle_start_event(); this helper must
> + be called after DA storage is allocated and initial state is set.
> + """
> + if not self.env_init_started:
> + return []
> +
> + # Collect the ha_start_timer call for each init-started env from the
> + # first state invariant that references it.
> + timer_calls: dict[str, str] = {}
> + for env in self.env_init_started:
> + env_full = f"{env}{self.enum_suffix}"
> + for constr in self.invariants.values():
> + if env_full in constr:
> + timer_calls[env] = constr
> + break
> +
> + buff = []
> + buff.append(
> +"""/*
> + * handle_monitor_start - reset per-object clock(s) and arm the timer.
> + *
> + * env_store is invalid inside da_handle_start_event(); call this helper
> + * after allocating DA storage and setting the initial DA state.
> + *
> + * XXX: replace the placeholders with the actual logic for your monitor.
> + */""")
> +
> + if self.monitor_type == "per_obj":
> + buff.append("static int handle_monitor_start(int id,
> monitor_target t)")
> + buff.append("{")
> + buff.append("\tstruct ha_monitor *ha_mon;")
> + buff.append("\tu64 time_ns = ktime_get_ns();\n")
> + buff.append("\t/* XXX: allocate DA storage, e.g.
> da_create_or_get(id, t) */")
> + buff.append("\t/* XXX: set initial DA state, e.g.
> da_handle_start_event(id, t, <event>) */")
> + buff.append("\tha_mon = /* XXX: retrieve ha_monitor for (id, t)
> */;")
> + elif self.monitor_type == "per_task":
> + buff.append("static int handle_monitor_start(struct task_struct
> *p)")
> + buff.append("{")
> + buff.append("\tstruct ha_monitor *ha_mon;")
> + buff.append("\tu64 time_ns = ktime_get_ns();\n")
> + buff.append("\t/* XXX: allocate DA storage, e.g.
> da_create_or_get(p->pid, p) */")
> + buff.append("\t/* XXX: set initial DA state, e.g.
> da_handle_start_event(p->pid, p, <event>) */")
> + buff.append("\tha_mon = /* XXX: retrieve ha_monitor for p */;")
> + else:
> + buff.append("static int handle_monitor_start(void)")
> + buff.append("{")
> + buff.append("\tstruct ha_monitor *ha_mon;")
> + buff.append("\tu64 time_ns = ktime_get_ns();\n")
> + buff.append("\tha_mon = /* XXX: retrieve global ha_monitor */;")
> +
> + buff.append("\tif (!ha_mon)")
> + buff.append("\t\treturn -ENOENT;")
> +
> + for env in self.env_init_started:
> + buff.append(f"\tha_reset_env(ha_mon, {env}{self.enum_suffix},
> time_ns);")
> + if env in timer_calls:
> + buff.append(f"\t{timer_calls[env]};")
> + else:
> + buff.append(f"\t/* XXX: arm timer for {env} */")
> +
> + buff.append("\treturn 0;")
> + buff.append("}\n")
> + return buff
> +
> def _fill_hybrid_definitions(self) -> list[str]:
> - return self.__fill_hybrid_get_reset_functions() +
> self.__fill_constr_func()
> + return (self.__fill_hybrid_get_reset_functions() +
> + self.__fill_init_start_helper() +
> + self.__fill_constr_func())
>
> def _fill_timer_type(self) -> list:
> if self.invariants:
^ permalink raw reply
* Re: [PATCH v6 2/4] mm/memory-failure: classify get_any_page() failures by reason
From: Breno Leitao @ 2026-05-12 13:33 UTC (permalink / raw)
To: David Hildenbrand (Arm)
Cc: Miaohe Lin, Naoya Horiguchi, Andrew Morton, Jonathan Corbet,
Shuah Khan, Lorenzo Stoakes, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Shuah Khan, Steven Rostedt,
Masami Hiramatsu, Mathieu Desnoyers, Liam R. Howlett, linux-mm,
linux-kernel, linux-doc, linux-kselftest, linux-trace-kernel,
kernel-team, Lance Yang
In-Reply-To: <28b01c14-3d87-4cab-b695-5b9015578785@kernel.org>
On Tue, May 12, 2026 at 10:21:50AM +0200, David Hildenbrand (Arm) wrote:
>
> > }
> > goto unlock_mutex;
> > } else if (res < 0) {
> > - if (is_reserved)
> > + /*
> > + * Promote a stable unhandlable kernel page diagnosed by
> > + * get_hwpoison_page() to MF_MSG_KERNEL alongside reserved
> > + * pages; transient lifecycle races stay as MF_MSG_GET_HWPOISON.
> > + */
> > + if (is_reserved || gp_status == MF_GET_PAGE_UNHANDLABLE)
> > res = action_result(pfn, MF_MSG_KERNEL, MF_IGNORED);
>
>
> It's all a bit of a mess. get_hwpoison_page() should just indicate that a page
> is unhandable if it is PG_reserved?
Are you saying that we should identify if the page is PG_reserved in
get_hwpoison_page() instead of in memory_failure(), as done in the
previous patch ("mm/memory-failure: report MF_MSG_KERNEL for reserved
pages") ?
> Why can't we just return a special error code from get_hwpoison_page()? We ahve
> plenty of errno values to chose from.
Something like:
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 866c4428ac7ef..0a6d83575833e 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -878,7 +878,7 @@ static const char *action_name[] = {
};
static const char * const action_page_types[] = {
- [MF_MSG_KERNEL] = "reserved kernel page",
+ [MF_MSG_KERNEL] = "unrecoverable kernel page",
[MF_MSG_KERNEL_HIGH_ORDER] = "high-order kernel page",
[MF_MSG_HUGE] = "huge page",
[MF_MSG_FREE_HUGE] = "free huge page",
@@ -1394,6 +1394,21 @@ static int get_any_page(struct page *p, unsigned long flags)
int ret = 0, pass = 0;
bool count_increased = false;
+ if (PageReserved(p)) {
+ ret = -ENOTRECOVERABLE;
+ goto out;
+ }
+
if (flags & MF_COUNT_INCREASED)
count_increased = true;
@@ -1422,7 +1437,7 @@ static int get_any_page(struct page *p, unsigned long flags)
shake_page(p);
goto try_again;
}
- ret = -EIO;
+ ret = -ENOTRECOVERABLE;
goto out;
}
}
@@ -1441,10 +1456,10 @@ static int get_any_page(struct page *p, unsigned long flags)
goto try_again;
}
put_page(p);
- ret = -EIO;
+ ret = -ENOTRECOVERABLE;
}
out:
- if (ret == -EIO)
+ if (ret == -EIO || ret == -ENOTRECOVERABLE)
pr_err("%#lx: unhandlable page.\n", page_to_pfn(p));
return ret;
@@ -2431,6 +2448,9 @@ int memory_failure(unsigned long pfn, int flags)
res = action_result(pfn, MF_MSG_KERNEL_HIGH_ORDER, MF_IGNORED);
}
goto unlock_mutex;
+ } else if (res == -ENOTRECOVERABLE) {
+ res = action_result(pfn, MF_MSG_KERNEL, MF_IGNORED);
+ goto unlock_mutex;
} else if (res < 0) {
res = action_result(pfn, MF_MSG_GET_HWPOISON, MF_IGNORED);
goto unlock_mutex;
If that is what you are suggestion, maybe we can create another
MF_MSG_RESERVED? and another return value for get_any_page() to track
the reserve pages ?
Thanks for the review and suggestions,
--breno
^ permalink raw reply related
* Re: [PATCH] rtla: Stop the record trace on interrupt
From: Tomas Glozar @ 2026-05-12 13:50 UTC (permalink / raw)
To: Crystal Wood
Cc: Steven Rostedt, linux-trace-kernel, John Kacur, Costa Shulyupin,
Wander Lairson Costa
In-Reply-To: <20260511223509.1483323-1-crwood@redhat.com>
út 12. 5. 2026 v 0:35 odesílatel Crystal Wood <crwood@redhat.com> napsal:
>
> Before, when rtla gets a signal, it stopped the main trace but not the
> record trace. save_trace_to_file() could also fail to keep up on a debug
> kernel -- and in any case, it adds post-stoppage noise to the trace file.
>
This affects only the "new" (since 6.19) --on-end trace option, right?
The regular --trace/--on-threshold trace should already disable the
instance in-kernel, as timerlat disables all instances set to the
tracer on stop_tracing threshold.
If so, that should be reflected in the commit message.
> Signed-off-by: Crystal Wood <crwood@redhat.com>
> ---
> tools/tracing/rtla/src/common.c | 19 +++++++++++--------
> tools/tracing/rtla/src/common.h | 1 -
> tools/tracing/rtla/src/timerlat.c | 2 +-
> 3 files changed, 12 insertions(+), 10 deletions(-)
>
> diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c
> index 35e3d3aa922e..effad523e8cf 100644
> --- a/tools/tracing/rtla/src/common.c
> +++ b/tools/tracing/rtla/src/common.c
> @@ -10,7 +10,7 @@
>
> #include "common.h"
>
> -struct trace_instance *trace_inst;
> +struct osnoise_tool *trace_tool;
> volatile int stop_tracing;
> int nr_cpus;
>
> @@ -21,12 +21,16 @@ static void stop_trace(int sig)
> * Stop requested twice in a row; abort event processing and
> * exit immediately
> */
> - tracefs_iterate_stop(trace_inst->inst);
> + if (trace_tool)
> + tracefs_iterate_stop(trace_tool->trace.inst);
Can this condition be ever false? The signal should be attached after
trace_inst is initialized. Of course, it doesn't hurt to have it there
for safety, as long as we keep in mind that it does not protect from
the trace instance being freed (which should be fixed by commit
be8058f31b4e already).
> return;
> }
> stop_tracing = 1;
> - if (trace_inst)
> - trace_instance_stop(trace_inst);
> + if (trace_tool) {
> + trace_instance_stop(&trace_tool->trace);
> + if (trace_tool->record)
> + trace_instance_stop(&trace_tool->record->trace);
> + }
> }
>
Otherwise this makes sense. The reason for doing trace_instance_stop()
in stop_trace() and not waiting for cleanup is that in tracefs mode,
the loop would get struck in tracefs_iterate_raw_events() if it cannot
process the events faster than they are created (see commit
c73cab9dbed and a4dfce7559d respectively). But it can cause a
discrepancy in the trace output, as you point out.
> /*
> @@ -273,11 +277,10 @@ int run_tool(struct tool_ops *ops, int argc, char *argv[])
> tool->params = params;
>
> /*
> - * Save trace instance into global variable so that SIGINT can stop
> - * the timerlat tracer.
> + * Expose the tool to signal handlers so they can stop the trace.
> * Otherwise, rtla could loop indefinitely when overloaded.
> */
> - trace_inst = &tool->trace;
> + trace_tool = tool;
>
> retval = ops->apply_config(tool);
> if (retval) {
> @@ -285,7 +288,7 @@ int run_tool(struct tool_ops *ops, int argc, char *argv[])
> goto out_free;
> }
>
> - retval = enable_tracer_by_name(trace_inst->inst, ops->tracer);
> + retval = enable_tracer_by_name(tool->trace.inst, ops->tracer);
> if (retval) {
> err_msg("Failed to enable %s tracer\n", ops->tracer);
> goto out_free;
> diff --git a/tools/tracing/rtla/src/common.h b/tools/tracing/rtla/src/common.h
> index 51665db4ffce..eba40b6d9504 100644
> --- a/tools/tracing/rtla/src/common.h
> +++ b/tools/tracing/rtla/src/common.h
> @@ -54,7 +54,6 @@ struct osnoise_context {
> int opt_workload;
> };
>
> -extern struct trace_instance *trace_inst;
> extern volatile int stop_tracing;
>
This is removed as it is not needed now after the consolidation I
assume, since all users are now in common.c? That could also be
mentioned in the commit message.
> struct hist_params {
> diff --git a/tools/tracing/rtla/src/timerlat.c b/tools/tracing/rtla/src/timerlat.c
> index f8c057518d22..637f68d684f5 100644
> --- a/tools/tracing/rtla/src/timerlat.c
> +++ b/tools/tracing/rtla/src/timerlat.c
> @@ -202,7 +202,7 @@ void timerlat_analyze(struct osnoise_tool *tool, bool stopped)
> * If the trace did not stop with --aa-only, at least print
> * the max known latency.
> */
> - max_lat = tracefs_instance_file_read(trace_inst->inst, "tracing_max_latency", NULL);
> + max_lat = tracefs_instance_file_read(tool->trace.inst, "tracing_max_latency", NULL);
Not sure why this used trace_inst instead of tool which is right
there, maybe again refactoring of the code?
> if (max_lat) {
> printf(" Max latency was %s\n", max_lat);
> free(max_lat);
> --
> 2.54.0
>
Otherwise, LGTM. You can also add:
Fixes: c73cab9dbed0 ("rtla/timerlat_hist: Stop timerlat tracer on signal")
Fixes: a4dfce7559d7 ("rtla/timerlat_top: Stop timerlat tracer on signal")
Fixes: 3aadb65db5d6 ("rtla/timerlat: Add action on end feature")
as this fixes two bugs, one with the post-stoppage noise (that is
present since the trace_instance_stop() was added), one with the
save_trace_to_file() not keeping up (which should be since the
--on-end option was added).
Tomas
^ permalink raw reply
* Re: [PATCH] rtla: Stop the record trace on interrupt
From: Tomas Glozar @ 2026-05-12 13:51 UTC (permalink / raw)
To: Crystal Wood
Cc: Steven Rostedt, linux-trace-kernel, John Kacur, Costa Shulyupin,
Wander Lairson Costa
In-Reply-To: <CAP4=nvQEnCG2vabuA52p3bmGo7f1_-pZJ2b6rr5N=bKmaBuqxg@mail.gmail.com>
út 12. 5. 2026 v 15:50 odesílatel Tomas Glozar <tglozar@redhat.com> napsal:
>
> This affects only the "new" (since 6.19) --on-end trace option, right?
s/6.19/6.17/
^ permalink raw reply
* [PATCH v3] tracing: Fix nr_subbufs initialization in simple_ring_buffer_init_mm()
From: David Carlier @ 2026-05-12 13:54 UTC (permalink / raw)
To: catalin.marinas, will
Cc: rostedt, mhiramat, mathieu.desnoyers, vdonnefort, ryan.roberts,
maz, linux-arm-kernel, linux-trace-kernel, linux-kernel,
David Carlier
nr_subbufs in the ring buffer metadata is always initialized to zero
because it is assigned from cpu_buffer->nr_pages before the page
initialization loop has run. While nr_subbufs is not currently read
by the kernel, it should reflect the actual buffer geometry in the
meta page for correctness.
Move the assignment after the page loop so that cpu_buffer->nr_pages
holds the final count.
Fixes: 34e5b958bdad ("tracing: Introduce simple_ring_buffer")
Reviewed-by: Vincent Donnefort <vdonnefort@google.com>
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: David Carlier <devnexen@gmail.com>
---
kernel/trace/simple_ring_buffer.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/trace/simple_ring_buffer.c b/kernel/trace/simple_ring_buffer.c
index 02af2297ae5a..f731f14d0ff7 100644
--- a/kernel/trace/simple_ring_buffer.c
+++ b/kernel/trace/simple_ring_buffer.c
@@ -395,7 +395,6 @@ int simple_ring_buffer_init_mm(struct simple_rb_per_cpu *cpu_buffer,
memset(cpu_buffer->meta, 0, sizeof(*cpu_buffer->meta));
cpu_buffer->meta->meta_page_size = PAGE_SIZE;
- cpu_buffer->meta->nr_subbufs = cpu_buffer->nr_pages;
/* The reader page is not part of the ring initially */
page = load_page(desc->page_va[0]);
@@ -437,6 +436,7 @@ int simple_ring_buffer_init_mm(struct simple_rb_per_cpu *cpu_buffer,
return ret;
}
+ cpu_buffer->meta->nr_subbufs = cpu_buffer->nr_pages;
/* Close the ring */
bpage->link.next = &cpu_buffer->tail_page->link;
cpu_buffer->tail_page->link.prev = &bpage->link;
--
2.53.0
^ permalink raw reply related
* Re: [bug report] bootconfig: init: Allow admin to use bootconfig for kernel command line
From: Breno Leitao @ 2026-05-12 13:54 UTC (permalink / raw)
To: Masami Hiramatsu
Cc: Dan Carpenter, kernel-janitors, Linux Trace Kernel, linux-kernel
In-Reply-To: <20260512091638.8b95253ab022d7dabf473465@kernel.org>
On Tue, May 12, 2026 at 09:16:38AM +0900, Masami Hiramatsu wrote:
> Hi Dan,
>
> Thanks for reporting. A similar problem is pointed by Sashiko [1].
>
> [1] https://sashiko.dev/#/patchset/20260508-bootconfig_using_tools-v1-0-1132219aa773%40debian.org
>
> On Fri, 8 May 2026 20:07:25 +0300
> Dan Carpenter <error27@gmail.com> wrote:
>
> > Hello Masami Hiramatsu,
> >
> > Commit 51887d03aca1 ("bootconfig: init: Allow admin to use bootconfig
> > for kernel command line") from Jan 11, 2020 (linux-next), leads to
> > the following Smatch static checker warning:
> >
> > init/main.c:368 xbc_snprint_cmdline()
For your information, I am moving this function to lib/bootconfig.
https://lore.kernel.org/all/20260508-bootconfig_using_tools-v1-1-1132219aa773@debian.org/
I understand that no action is required on this report, correct?
Thanks,
--breno
^ permalink raw reply
* [PATCH 0/9] rv: Fixes on Deterministic and Hybrid Automata
From: Gabriele Monaco @ 2026-05-12 14:02 UTC (permalink / raw)
To: linux-kernel; +Cc: Gabriele Monaco, Nam Cao, Wen Yang, linux-trace-kernel
Fix issues that were reported by bots or visible only after integration:
* Make sure timers are always terminated and waited for when disabling
the monitor or when the target terminates
* Run per-cpu monitors with migration disabled since preemption is now
enabled from tracepoints
* Fix a wrong __user specifier in a helper function
* Other cleanup and concurrency issues
Cc: Nam Cao <namcao@linutronix.de>
Cc: Wen Yang <wen.yang@linux.dev>
Cc: linux-trace-kernel@vger.kernel.org
Gabriele Monaco (9):
rv: Fix __user specifier usage in extract_params()
rv: Fix read_lock scope in per-task DA cleanup
rv: Reset per-task DA monitors before releasing the slot
rv: Prevent task migration while handling per-CPU events
rv: Ensure all pending probes terminate on per-obj monitor destroy
rv: Ensure synchronous cleanup for HA monitors
rv: Do not rely on clean monitor when initialising HA
rv: Add automatic cleanup handlers for per-task HA monitors
rv: Mandate deallocation for per-obj monitors
include/rv/da_monitor.h | 66 ++++++++++---
include/rv/ha_monitor.h | 93 ++++++++++++++++++-
kernel/trace/rv/monitors/deadline/deadline.h | 8 +-
kernel/trace/rv/monitors/nomiss/nomiss.c | 4 +-
kernel/trace/rv/monitors/opid/opid.c | 4 +-
kernel/trace/rv/monitors/stall/stall.c | 4 +-
.../rvgen/rvgen/templates/dot2k/main.c | 4 +-
7 files changed, 157 insertions(+), 26 deletions(-)
base-commit: 6d35786de28116ecf78797a62b84e6bf3c45aa5a
--
2.54.0
^ permalink raw reply
* [PATCH 1/9] rv: Fix __user specifier usage in extract_params()
From: Gabriele Monaco @ 2026-05-12 14:02 UTC (permalink / raw)
To: linux-kernel, Steven Rostedt, Gabriele Monaco, Masami Hiramatsu,
Nam Cao, linux-trace-kernel
Cc: kernel test robot, Wen Yang
In-Reply-To: <20260512140250.262190-1-gmonaco@redhat.com>
The attributes variables extracted from syscalls in the helper are both
defined with the __user specifier although only the actual pointer to
user data should be marked.
Remove the __user specifier from attr.
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202604150820.Ny143u6X-lkp@intel.com
Fixes: b133207deb72 ("rv: Add nomiss deadline monitor")
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
---
kernel/trace/rv/monitors/deadline/deadline.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/kernel/trace/rv/monitors/deadline/deadline.h b/kernel/trace/rv/monitors/deadline/deadline.h
index 0bbfd2543329..78fca873d61e 100644
--- a/kernel/trace/rv/monitors/deadline/deadline.h
+++ b/kernel/trace/rv/monitors/deadline/deadline.h
@@ -95,7 +95,8 @@ static inline u8 get_server_type(struct task_struct *tsk)
static inline int extract_params(struct pt_regs *regs, long id, pid_t *pid_out)
{
size_t size = offsetofend(struct sched_attr, sched_flags);
- struct sched_attr __user *uattr, attr;
+ struct sched_attr __user *uattr;
+ struct sched_attr attr;
int new_policy = -1, ret;
unsigned long args[6];
--
2.54.0
^ permalink raw reply related
* [PATCH 2/9] rv: Fix read_lock scope in per-task DA cleanup
From: Gabriele Monaco @ 2026-05-12 14:02 UTC (permalink / raw)
To: linux-kernel, Steven Rostedt, Gabriele Monaco, Nam Cao,
linux-trace-kernel
Cc: Wen Yang
In-Reply-To: <20260512140250.262190-1-gmonaco@redhat.com>
The da_monitor_reset_all() function for per-task monitors takes
tasklist_lock while iterating over tasks, then keeps it also while
iterating over idle tasks (one per CPU). The latter is not necessary
since the lock needs to guard only for_each_process_thread().
Use a scoped_guard for more compact syntax and adjust the scope only
where the lock is necessary.
Fixes: 30984ccf31b7f ("rv: Refactor da_monitor to minimise macros")
Fixes: 8259cb14a7068 ("rv: Reset per-task monitors also for idle tasks")
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
---
include/rv/da_monitor.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/include/rv/da_monitor.h b/include/rv/da_monitor.h
index 39765ff6f098..250888812125 100644
--- a/include/rv/da_monitor.h
+++ b/include/rv/da_monitor.h
@@ -272,12 +272,12 @@ static void da_monitor_reset_all(void)
struct task_struct *g, *p;
int cpu;
- read_lock(&tasklist_lock);
- for_each_process_thread(g, p)
- da_monitor_reset(da_get_monitor(p));
+ scoped_guard(read_lock, &tasklist_lock) {
+ for_each_process_thread(g, p)
+ da_monitor_reset(da_get_monitor(p));
+ }
for_each_present_cpu(cpu)
da_monitor_reset(da_get_monitor(idle_task(cpu)));
- read_unlock(&tasklist_lock);
}
/*
--
2.54.0
^ permalink raw reply related
* [PATCH 3/9] rv: Reset per-task DA monitors before releasing the slot
From: Gabriele Monaco @ 2026-05-12 14:02 UTC (permalink / raw)
To: linux-kernel, Steven Rostedt, Gabriele Monaco, Nam Cao,
linux-trace-kernel
Cc: Wen Yang
In-Reply-To: <20260512140250.262190-1-gmonaco@redhat.com>
Per-task monitors use task_mon_slot to determine which slot in the array
to use for the monitor. During destruction, this slot is returned but
this is done before resetting the monitor. As a result, the monitor's
reset is in fact resetting a slot that is outside of the array
(RV_PER_TASK_MONITOR_INIT).
Release the slot only after the reset to avoid out-of-bound memory
access.
Fixes: 30984ccf31b7f ("rv: Refactor da_monitor to minimise macros")
Fixes: 792575348ff70 ("rv/include: Add deterministic automata monitor definition via C macros")
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
---
include/rv/da_monitor.h | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/include/rv/da_monitor.h b/include/rv/da_monitor.h
index 250888812125..0b7028df08fb 100644
--- a/include/rv/da_monitor.h
+++ b/include/rv/da_monitor.h
@@ -309,10 +309,11 @@ static inline void da_monitor_destroy(void)
WARN_ONCE(1, "Disabling a disabled monitor: " __stringify(MONITOR_NAME));
return;
}
- rv_put_task_monitor_slot(task_mon_slot);
- task_mon_slot = RV_PER_TASK_MONITOR_INIT;
da_monitor_reset_all();
+
+ rv_put_task_monitor_slot(task_mon_slot);
+ task_mon_slot = RV_PER_TASK_MONITOR_INIT;
}
#elif RV_MON_TYPE == RV_MON_PER_OBJ
--
2.54.0
^ permalink raw reply related
* [PATCH 4/9] rv: Prevent task migration while handling per-CPU events
From: Gabriele Monaco @ 2026-05-12 14:02 UTC (permalink / raw)
To: linux-kernel, Steven Rostedt, Gabriele Monaco, linux-trace-kernel
Cc: Nam Cao, Wen Yang
In-Reply-To: <20260512140250.262190-1-gmonaco@redhat.com>
Tracepoint handlers are now fully preemptible. When a per-CPU monitor
handles an event, it retrieves the monitor state using a per-CPU
pointer. If the event itself doesn't disable preemption, the task can
migrate to a different CPU and we risk updating the wrong monitor.
Mitigate this by explicitly disabling task migration before acquiring
the monitor pointer. This cannot guarantee the monitor runs on the
correct CPU but reduces the race condition window and prevents warnings.
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
---
include/rv/da_monitor.h | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/include/rv/da_monitor.h b/include/rv/da_monitor.h
index 0b7028df08fb..a9fd284195ee 100644
--- a/include/rv/da_monitor.h
+++ b/include/rv/da_monitor.h
@@ -181,6 +181,10 @@ static inline void da_monitor_destroy(void)
da_monitor_reset_all();
}
+#ifndef da_implicit_guard
+#define da_implicit_guard()
+#endif
+
#elif RV_MON_TYPE == RV_MON_PER_CPU
/*
* Functions to define, init and get a per-cpu monitor.
@@ -230,6 +234,10 @@ static inline void da_monitor_destroy(void)
da_monitor_reset_all();
}
+#ifndef da_implicit_guard
+#define da_implicit_guard() guard(migrate)()
+#endif
+
#elif RV_MON_TYPE == RV_MON_PER_TASK
/*
* Functions to define, init and get a per-task monitor.
@@ -677,6 +685,7 @@ static inline bool __da_handle_start_run_event(struct da_monitor *da_mon,
*/
static inline void da_handle_event(enum events event)
{
+ da_implicit_guard();
__da_handle_event(da_get_monitor(), event, 0);
}
@@ -692,6 +701,7 @@ static inline void da_handle_event(enum events event)
*/
static inline bool da_handle_start_event(enum events event)
{
+ da_implicit_guard();
return __da_handle_start_event(da_get_monitor(), event, 0);
}
@@ -703,6 +713,7 @@ static inline bool da_handle_start_event(enum events event)
*/
static inline bool da_handle_start_run_event(enum events event)
{
+ da_implicit_guard();
return __da_handle_start_run_event(da_get_monitor(), event, 0);
}
--
2.54.0
^ permalink raw reply related
* [PATCH 5/9] rv: Ensure all pending probes terminate on per-obj monitor destroy
From: Gabriele Monaco @ 2026-05-12 14:02 UTC (permalink / raw)
To: linux-kernel, Steven Rostedt, Gabriele Monaco, Nam Cao,
linux-trace-kernel
Cc: Wen Yang
In-Reply-To: <20260512140250.262190-1-gmonaco@redhat.com>
The monitor disable/destroy sequence detaches all probes and resets the
monitor's data, however it doesn't wait for pending probes. This is an
issue with per-object monitors, which free the monitor storage.
Call tracepoint_synchronize_unregister() to make sure to wait for all
pending probes before destroying the monitor storage.
Fixes: 4a24127bd6cb ("rv: Add support for per-object monitors in DA/HA")
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
---
include/rv/da_monitor.h | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/include/rv/da_monitor.h b/include/rv/da_monitor.h
index a9fd284195ee..a4a13b62d1a4 100644
--- a/include/rv/da_monitor.h
+++ b/include/rv/da_monitor.h
@@ -515,9 +515,10 @@ static inline void da_monitor_destroy(void)
struct hlist_node *tmp;
int bkt;
+ tracepoint_synchronize_unregister();
/*
- * This function is called after all probes are disabled, we need only
- * worry about concurrency against old events.
+ * This function is called after all probes are disabled and no longer
+ * pending, we can safely assume no concurrent user.
*/
synchronize_rcu();
hash_for_each_safe(da_monitor_ht, bkt, tmp, mon_storage, node) {
--
2.54.0
^ permalink raw reply related
* [PATCH 6/9] rv: Ensure synchronous cleanup for HA monitors
From: Gabriele Monaco @ 2026-05-12 14:02 UTC (permalink / raw)
To: linux-kernel, Steven Rostedt, Gabriele Monaco, Nam Cao,
linux-trace-kernel
Cc: Wen Yang
In-Reply-To: <20260512140250.262190-1-gmonaco@redhat.com>
HA monitors may start timers, all cleanup functions currently stop the
timers asynchronously to avoid sleeping in the wrong context.
Nothing makes sure running callbacks terminate on cleanup.
Run the entire HA timer callback in an RCU read-side critical section,
this way we can simply synchronize_rcu() with any pending timer and are
sure any cleanup using kfree_rcu() runs after callbacks terminated.
Additionally make sure any unlikely callback running late won't run any
code if the monitor is marked as disabled.
Fixes: f5587d1b6ec9 ("rv: Add Hybrid Automata monitor type")
Fixes: 4a24127bd6cb ("rv: Add support for per-object monitors in DA/HA")
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
---
include/rv/da_monitor.h | 23 +++++++++++++++++++----
include/rv/ha_monitor.h | 18 ++++++++++++++++--
2 files changed, 35 insertions(+), 6 deletions(-)
diff --git a/include/rv/da_monitor.h b/include/rv/da_monitor.h
index a4a13b62d1a4..402d3b935c08 100644
--- a/include/rv/da_monitor.h
+++ b/include/rv/da_monitor.h
@@ -57,6 +57,15 @@ static struct rv_monitor rv_this;
#define da_monitor_reset_hook(da_mon)
#endif
+/*
+ * Hook to allow the implementation of hybrid automata: define it with a
+ * function that waits for the termination of all monitors background
+ * activities (e.g. all timers). This hook can sleep.
+ */
+#ifndef da_monitor_sync_hook
+#define da_monitor_sync_hook()
+#endif
+
/*
* Type for the target id, default to int but can be overridden.
* A long type can work as hash table key (PER_OBJ) but will be downgraded to
@@ -179,6 +188,7 @@ static inline int da_monitor_init(void)
static inline void da_monitor_destroy(void)
{
da_monitor_reset_all();
+ da_monitor_sync_hook();
}
#ifndef da_implicit_guard
@@ -232,6 +242,7 @@ static inline int da_monitor_init(void)
static inline void da_monitor_destroy(void)
{
da_monitor_reset_all();
+ da_monitor_sync_hook();
}
#ifndef da_implicit_guard
@@ -319,6 +330,7 @@ static inline void da_monitor_destroy(void)
}
da_monitor_reset_all();
+ da_monitor_sync_hook();
rv_put_task_monitor_slot(task_mon_slot);
task_mon_slot = RV_PER_TASK_MONITOR_INIT;
@@ -497,10 +509,9 @@ static void da_monitor_reset_all(void)
struct da_monitor_storage *mon_storage;
int bkt;
- rcu_read_lock();
+ guard(rcu)();
hash_for_each_rcu(da_monitor_ht, bkt, mon_storage, node)
da_monitor_reset(&mon_storage->rv.da_mon);
- rcu_read_unlock();
}
static inline int da_monitor_init(void)
@@ -516,13 +527,17 @@ static inline void da_monitor_destroy(void)
int bkt;
tracepoint_synchronize_unregister();
+ scoped_guard(rcu) {
+ hash_for_each_rcu(da_monitor_ht, bkt, mon_storage, node) {
+ da_monitor_reset_hook(&mon_storage->rv.da_mon);
+ }
+ }
+ da_monitor_sync_hook();
/*
* This function is called after all probes are disabled and no longer
* pending, we can safely assume no concurrent user.
*/
- synchronize_rcu();
hash_for_each_safe(da_monitor_ht, bkt, tmp, mon_storage, node) {
- da_monitor_reset_hook(&mon_storage->rv.da_mon);
hash_del_rcu(&mon_storage->node);
kfree(mon_storage);
}
diff --git a/include/rv/ha_monitor.h b/include/rv/ha_monitor.h
index d59507e8cb30..47ff1a41febe 100644
--- a/include/rv/ha_monitor.h
+++ b/include/rv/ha_monitor.h
@@ -36,6 +36,7 @@ static bool ha_monitor_handle_constraint(struct da_monitor *da_mon,
#define da_monitor_event_hook ha_monitor_handle_constraint
#define da_monitor_init_hook ha_monitor_init_env
#define da_monitor_reset_hook ha_monitor_reset_env
+#define da_monitor_sync_hook() synchronize_rcu()
#include <rv/da_monitor.h>
#include <linux/seq_buf.h>
@@ -237,12 +238,25 @@ static bool ha_monitor_handle_constraint(struct da_monitor *da_mon,
return false;
}
+/*
+ * __ha_monitor_timer_callback - generic callback representation
+ *
+ * This callback runs in an RCU read-side critical section to allow the
+ * destruction sequence to easily synchronize_rcu() with all pending timer
+ * after asynchronously disabling them.
+ */
static inline void __ha_monitor_timer_callback(struct ha_monitor *ha_mon)
{
- enum states curr_state = READ_ONCE(ha_mon->da_mon.curr_state);
DECLARE_SEQ_BUF(env_string, ENV_BUFFER_SIZE);
- u64 time_ns = ha_get_ns();
+ enum states curr_state;
+ u64 time_ns;
+
+ if (unlikely(!da_monitor_handling_event(&ha_mon->da_mon)))
+ return;
+ guard(rcu)();
+ curr_state = READ_ONCE(ha_mon->da_mon.curr_state);
+ time_ns = ha_get_ns();
ha_get_env_string(&env_string, ha_mon, time_ns);
ha_react(curr_state, EVENT_NONE, env_string.buffer);
ha_trace_error_env(ha_mon, model_get_state_name(curr_state),
--
2.54.0
^ permalink raw reply related
* [PATCH 7/9] rv: Do not rely on clean monitor when initialising HA
From: Gabriele Monaco @ 2026-05-12 14:02 UTC (permalink / raw)
To: linux-kernel, Steven Rostedt, Gabriele Monaco, Masami Hiramatsu,
Nam Cao, linux-trace-kernel
Cc: Wen Yang
In-Reply-To: <20260512140250.262190-1-gmonaco@redhat.com>
Hybrid Automata monitors hook into the DA implementation when doing
da_monitor_reset(). This function is called both on initialisation and
teardown, HA monitors try to cancel a timer only when it's initialised
relying on the da_mon->monitoring flag. This flag could however be
corrupted during initialisation. This happens for instance on per-task
monitors that share the same storage with different type of monitors
like LTL or in case of races during a previous teardown.
Stop relying on the monitoring flag during initialisation, assume that
can have any value, so skip timer cancellation in any case when a local
flag is set. New monitors (e.g. new tasks) are always zero-initialised
so they are safe.
Reported-by: Wen Yang <wen.yang@linux.dev>
Closes: https://lore.kernel.org/lkml/d02c656aada7d071f083460a5c9a454363669b61.1778522945.git.wen.yang@linux.dev
Fixes: f5587d1b6ec9 ("rv: Add Hybrid Automata monitor type")
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
---
include/rv/ha_monitor.h | 31 ++++++++++++++++++-
kernel/trace/rv/monitors/nomiss/nomiss.c | 4 +--
kernel/trace/rv/monitors/opid/opid.c | 4 +--
kernel/trace/rv/monitors/stall/stall.c | 4 +--
.../rvgen/rvgen/templates/dot2k/main.c | 4 +--
5 files changed, 38 insertions(+), 9 deletions(-)
diff --git a/include/rv/ha_monitor.h b/include/rv/ha_monitor.h
index 47ff1a41febe..11ae85bad492 100644
--- a/include/rv/ha_monitor.h
+++ b/include/rv/ha_monitor.h
@@ -116,6 +116,35 @@ static enum hrtimer_restart ha_monitor_timer_callback(struct hrtimer *hrtimer);
#define ha_get_ns() 0
#endif /* HA_CLK_NS */
+static bool ha_mon_initializing;
+
+static int ha_monitor_init(void)
+{
+ int ret;
+
+ ha_mon_initializing = true;
+ ret = da_monitor_init();
+ ha_mon_initializing = false;
+ return ret;
+}
+
+static void ha_monitor_destroy(void)
+{
+ da_monitor_destroy();
+}
+
+/*
+ * ha_monitor_uninitialized - are fields like the timer initialized?
+ *
+ * On a clean monitor, we can assume an active monitor (monitoring) is
+ * initialized, however the monitoring field cannot be trusted during
+ * initialization.
+ */
+static inline bool ha_monitor_uninitialized(struct da_monitor *da_mon)
+{
+ return ha_mon_initializing || !da_monitoring(da_mon);
+}
+
/* Should be supplied by the monitor */
static u64 ha_get_env(struct ha_monitor *ha_mon, enum envs env, u64 time_ns);
static bool ha_verify_constraint(struct ha_monitor *ha_mon,
@@ -160,7 +189,7 @@ static inline void ha_monitor_reset_env(struct da_monitor *da_mon)
struct ha_monitor *ha_mon = to_ha_monitor(da_mon);
/* Initialisation resets the monitor before initialising the timer */
- if (likely(da_monitoring(da_mon)))
+ if (likely(!ha_monitor_uninitialized(da_mon)))
ha_cancel_timer(ha_mon);
}
diff --git a/kernel/trace/rv/monitors/nomiss/nomiss.c b/kernel/trace/rv/monitors/nomiss/nomiss.c
index 31f90f3638d8..8ead8783c29f 100644
--- a/kernel/trace/rv/monitors/nomiss/nomiss.c
+++ b/kernel/trace/rv/monitors/nomiss/nomiss.c
@@ -227,7 +227,7 @@ static int enable_nomiss(void)
{
int retval;
- retval = da_monitor_init();
+ retval = ha_monitor_init();
if (retval)
return retval;
@@ -263,7 +263,7 @@ static void disable_nomiss(void)
rv_detach_trace_probe("nomiss", sched_switch, handle_sched_switch);
rv_detach_trace_probe("nomiss", sched_wakeup, handle_sched_wakeup);
- da_monitor_destroy();
+ ha_monitor_destroy();
}
static struct rv_monitor rv_this = {
diff --git a/kernel/trace/rv/monitors/opid/opid.c b/kernel/trace/rv/monitors/opid/opid.c
index 4594c7c46601..2922318c6112 100644
--- a/kernel/trace/rv/monitors/opid/opid.c
+++ b/kernel/trace/rv/monitors/opid/opid.c
@@ -73,7 +73,7 @@ static int enable_opid(void)
{
int retval;
- retval = da_monitor_init();
+ retval = ha_monitor_init();
if (retval)
return retval;
@@ -90,7 +90,7 @@ static void disable_opid(void)
rv_detach_trace_probe("opid", sched_set_need_resched_tp, handle_sched_need_resched);
rv_detach_trace_probe("opid", sched_waking, handle_sched_waking);
- da_monitor_destroy();
+ ha_monitor_destroy();
}
/*
diff --git a/kernel/trace/rv/monitors/stall/stall.c b/kernel/trace/rv/monitors/stall/stall.c
index 9ccfda6b0e73..3c38fb1a0159 100644
--- a/kernel/trace/rv/monitors/stall/stall.c
+++ b/kernel/trace/rv/monitors/stall/stall.c
@@ -103,7 +103,7 @@ static int enable_stall(void)
{
int retval;
- retval = da_monitor_init();
+ retval = ha_monitor_init();
if (retval)
return retval;
@@ -120,7 +120,7 @@ static void disable_stall(void)
rv_detach_trace_probe("stall", sched_switch, handle_sched_switch);
rv_detach_trace_probe("stall", sched_wakeup, handle_sched_wakeup);
- da_monitor_destroy();
+ ha_monitor_destroy();
}
static struct rv_monitor rv_this = {
diff --git a/tools/verification/rvgen/rvgen/templates/dot2k/main.c b/tools/verification/rvgen/rvgen/templates/dot2k/main.c
index bf0999f6657a..889446760e3c 100644
--- a/tools/verification/rvgen/rvgen/templates/dot2k/main.c
+++ b/tools/verification/rvgen/rvgen/templates/dot2k/main.c
@@ -35,7 +35,7 @@ static int enable_%%MODEL_NAME%%(void)
{
int retval;
- retval = da_monitor_init();
+ retval = %%MONITOR_CLASS%%_monitor_init();
if (retval)
return retval;
@@ -50,7 +50,7 @@ static void disable_%%MODEL_NAME%%(void)
%%TRACEPOINT_DETACH%%
- da_monitor_destroy();
+ %%MONITOR_CLASS%%_monitor_destroy();
}
/*
--
2.54.0
^ permalink raw reply related
* [PATCH 8/9] rv: Add automatic cleanup handlers for per-task HA monitors
From: Gabriele Monaco @ 2026-05-12 14:02 UTC (permalink / raw)
To: linux-kernel, Steven Rostedt, Gabriele Monaco, Nam Cao,
linux-trace-kernel
Cc: Wen Yang
In-Reply-To: <20260512140250.262190-1-gmonaco@redhat.com>
Hybrid automata monitors may start timers, depending on the model, these
may remain active on an exiting task and cause false positives or even
access freed memory.
Add an enable/disable hook in the HA code, currently only populated by
the per-task handler for registration and deregistration.
This hooks to the sched_process_exit event and ensures the timer is
stopped for every exiting task. The handler is enabled automatically but
may be disabled, for instance if the monitor uses the event for another
purpose (but should still manually ensure timers are stopped).
Fixes: f5587d1b6ec9 ("rv: Add Hybrid Automata monitor type")
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
---
include/rv/ha_monitor.h | 44 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/include/rv/ha_monitor.h b/include/rv/ha_monitor.h
index 11ae85bad492..1bdf866e9c63 100644
--- a/include/rv/ha_monitor.h
+++ b/include/rv/ha_monitor.h
@@ -28,6 +28,7 @@ static inline void ha_monitor_init_env(struct da_monitor *da_mon);
static inline void ha_monitor_reset_env(struct da_monitor *da_mon);
static inline void ha_setup_timer(struct ha_monitor *ha_mon);
static inline bool ha_cancel_timer(struct ha_monitor *ha_mon);
+static inline void ha_cancel_timer_sync(struct ha_monitor *ha_mon);
static bool ha_monitor_handle_constraint(struct da_monitor *da_mon,
enum states curr_state,
enum events event,
@@ -38,6 +39,26 @@ static bool ha_monitor_handle_constraint(struct da_monitor *da_mon,
#define da_monitor_reset_hook ha_monitor_reset_env
#define da_monitor_sync_hook() synchronize_rcu()
+#if !defined(HA_SKIP_AUTO_CLEANUP) && RV_MON_TYPE == RV_MON_PER_TASK
+/*
+ * Automatic cleanup handlers for per-task HA monitors, only skip if you know
+ * what you are doing (e.g. you want to implement cleanup manually in another
+ * handler doing more things).
+ */
+static void ha_handle_sched_process_exit(void *data, struct task_struct *p,
+ bool group_dead);
+
+#define ha_monitor_enable_hook() \
+ rv_attach_trace_probe(__stringify(MONITOR_NAME), sched_process_exit, \
+ ha_handle_sched_process_exit)
+#define ha_monitor_disable_hook() \
+ rv_detach_trace_probe(__stringify(MONITOR_NAME), sched_process_exit, \
+ ha_handle_sched_process_exit)
+#else
+#define ha_monitor_enable_hook()
+#define ha_monitor_disable_hook()
+#endif
+
#include <rv/da_monitor.h>
#include <linux/seq_buf.h>
@@ -124,12 +145,14 @@ static int ha_monitor_init(void)
ha_mon_initializing = true;
ret = da_monitor_init();
+ ha_monitor_enable_hook();
ha_mon_initializing = false;
return ret;
}
static void ha_monitor_destroy(void)
{
+ ha_monitor_disable_hook();
da_monitor_destroy();
}
@@ -230,6 +253,18 @@ static inline void ha_trace_error_env(struct ha_monitor *ha_mon,
{
CONCATENATE(trace_error_env_, MONITOR_NAME)(id, curr_state, event, env);
}
+
+#if !defined(HA_SKIP_AUTO_CLEANUP) && RV_MON_TYPE == RV_MON_PER_TASK
+static void ha_handle_sched_process_exit(void *data, struct task_struct *p,
+ bool group_dead)
+{
+ struct da_monitor *da_mon = da_get_monitor(p);
+
+ if (likely(!ha_monitor_uninitialized(da_mon)))
+ ha_cancel_timer_sync(to_ha_monitor(da_mon));
+}
+#endif
+
#endif /* RV_MON_TYPE */
/*
@@ -455,6 +490,10 @@ static inline bool ha_cancel_timer(struct ha_monitor *ha_mon)
{
return timer_delete(&ha_mon->timer);
}
+static inline void ha_cancel_timer_sync(struct ha_monitor *ha_mon)
+{
+ timer_delete_sync(&ha_mon->timer);
+}
#elif HA_TIMER_TYPE == HA_TIMER_HRTIMER
/*
* Helper functions to handle the monitor timer.
@@ -506,6 +545,10 @@ static inline bool ha_cancel_timer(struct ha_monitor *ha_mon)
{
return hrtimer_try_to_cancel(&ha_mon->hrtimer) == 1;
}
+static inline void ha_cancel_timer_sync(struct ha_monitor *ha_mon)
+{
+ hrtimer_cancel(&ha_mon->hrtimer);
+}
#else /* HA_TIMER_NONE */
/*
* Start function is intentionally not defined, monitors using timers must
@@ -516,6 +559,7 @@ static inline bool ha_cancel_timer(struct ha_monitor *ha_mon)
{
return false;
}
+static inline void ha_cancel_timer_sync(struct ha_monitor *ha_mon) { }
#endif
#endif
--
2.54.0
^ permalink raw reply related
* [PATCH 9/9] rv: Mandate deallocation for per-obj monitors
From: Gabriele Monaco @ 2026-05-12 14:02 UTC (permalink / raw)
To: linux-kernel, Steven Rostedt, Gabriele Monaco, Masami Hiramatsu,
linux-trace-kernel
Cc: Nam Cao, Wen Yang
In-Reply-To: <20260512140250.262190-1-gmonaco@redhat.com>
The per-object monitors use a hash tables and dynamic allocation of the
monitor storage, functions to clean a monitor that is no longer needed
are provided but nothing ensures the monitor actually uses them.
Remove the inline specifier on the deallocation function to let the
compiler warn in case it isn't referenced. If the monitor really doesn't
need one (for instance because instances will never cease to exist
before disabling the monitor), the da_skip_deallocation() helper macro
can be used to silence the warning.
Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
---
include/rv/da_monitor.h | 14 +++++++++++++-
kernel/trace/rv/monitors/deadline/deadline.h | 5 ++++-
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/include/rv/da_monitor.h b/include/rv/da_monitor.h
index 402d3b935c08..378d23ab7dfb 100644
--- a/include/rv/da_monitor.h
+++ b/include/rv/da_monitor.h
@@ -489,8 +489,11 @@ static inline monitor_target da_get_target_by_id(da_id_type id)
* locks.
* This function includes an RCU read-side critical section to synchronise
* against da_monitor_destroy().
+ * NOTE: inline is omitted on purpose to let the compiler warn if this function
+ * is never referenced. For monitors that don't require a deallocation hook,
+ * da_skip_deallocation() can be used.
*/
-static inline void da_destroy_storage(da_id_type id)
+static void da_destroy_storage(da_id_type id)
{
struct da_monitor_storage *mon_storage;
@@ -504,6 +507,15 @@ static inline void da_destroy_storage(da_id_type id)
kfree_rcu(mon_storage, rcu);
}
+/*
+ * da_skip_deallocation - explicitly mark a deallocation function as not required
+ *
+ * Only use when you are absolutely sure the monitor doesn't require a
+ * deallocation hook (i.e. it's not possible for an object to finish existing
+ * when the monitor is still running).
+ */
+#define da_skip_deallocation(hook) ((void)hook)
+
static void da_monitor_reset_all(void)
{
struct da_monitor_storage *mon_storage;
diff --git a/kernel/trace/rv/monitors/deadline/deadline.h b/kernel/trace/rv/monitors/deadline/deadline.h
index 78fca873d61e..c39fd79148c2 100644
--- a/kernel/trace/rv/monitors/deadline/deadline.h
+++ b/kernel/trace/rv/monitors/deadline/deadline.h
@@ -194,7 +194,10 @@ static void __maybe_unused handle_newtask(void *data, struct task_struct *task,
da_create_storage(EXPAND_ID_TASK(task), NULL);
}
-static void __maybe_unused handle_exit(void *data, struct task_struct *p, bool group_dead)
+/*
+ * Deallocation hook, use da_skip_deallocation() when not necessary
+ */
+static void handle_exit(void *data, struct task_struct *p, bool group_dead)
{
if (p->policy == SCHED_DEADLINE)
da_destroy_storage(get_entity_id(&p->dl, DL_TASK, DL_TASK));
--
2.54.0
^ permalink raw reply related
* [PATCH] tracing: Fix unload_page for simple_ring_buffer init rollback
From: Vincent Donnefort @ 2026-05-12 14:16 UTC (permalink / raw)
To: rostedt, mhiramat, mathieu.desnoyers, linux-trace-kernel
Cc: kernel-team, linux-kernel, Vincent Donnefort
The unload_page callback expects the return value of load_page() as its
argument: ret = load_page(va); unload(ret). Fix the rollback code in
simple_ring_buffer_init_mm() where the descriptor's VA is used instead
of the loaded page address.
Fixes: 635923081c79 ("tracing: load/unload page callbacks for simple_ring_buffer")
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
diff --git a/kernel/trace/simple_ring_buffer.c b/kernel/trace/simple_ring_buffer.c
index 02af2297ae5a..38cf9abe0be8 100644
--- a/kernel/trace/simple_ring_buffer.c
+++ b/kernel/trace/simple_ring_buffer.c
@@ -431,7 +431,7 @@ int simple_ring_buffer_init_mm(struct simple_rb_per_cpu *cpu_buffer,
if (ret) {
for (i--; i >= 0; i--)
- unload_page((void *)desc->page_va[i]);
+ unload_page(bpages[i].page);
unload_page(cpu_buffer->meta);
return ret;
base-commit: 5d6919055dec134de3c40167a490f33c74c12581
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply related
* [RFC PATCH v2 00/28] mm/damon: introduce data attributes monitoring
From: SeongJae Park @ 2026-05-12 14:36 UTC (permalink / raw)
Cc: SeongJae Park, Liam R. Howlett, Andrew Morton, David Hildenbrand,
Jonathan Corbet, Lorenzo Stoakes, Masami Hiramatsu,
Mathieu Desnoyers, Michal Hocko, Mike Rapoport, Shuah Khan,
Shuah Khan, Steven Rostedt, Suren Baghdasaryan, Vlastimil Babka,
damon, linux-doc, linux-kernel, linux-kselftest, linux-mm,
linux-trace-kernel
TL; DR
======
Extend DAMON for monitoring general data attributes other than accesses.
The short term motivation is lightweight page type (e.g., belonging
cgroup) aware monitoring. In long term, this will help extending DAMON
for multiple access events capture primitives (e.g., page faults and
PMU) and eventually pivotting DAMON to a "Data Attributes Monitoring and
Operations eNgine" in long term.
Background: High Cost of Page Level Properties Monitoring
=========================================================
DAMON is initially introduced as a Data Access MONitor. It has been
extended for not only access monitoring but also data access-aware
system operations (DAMOS). But still the monitoring part is only for
data accesses.
Data access patterns is good information, but some users need more
holistic views. Particularly, users want to show the access pattern
information together with the types of the memory. For example, users
who work for making huge pages efficiently want to know how much of
DAMON-found hot/cold regions are backed by huge pages. Users who run
multiple workloads with different cgroups want to know how much of
DAMON-found hot/cold regions belong to specific cgroups.
For the user demand, we developed a DAMOS extension for page level
properties based monitoring [1], which has landed on 6.14. Using the
feature, users can inform the page level data properties that they are
interested in, in a flexible format that uses DAMOS filters. Then,
DAMON applies the filters to each folio of the entire DAMON region and
lets users know how many bytes of memory in each DAMON region passed the
given filters.
This gives page level detailed and deterministic information to users.
But, because the operation is done at page level, the overhead is
proportional to the memory size. It was useful for test or debugging
purposes on a small number of machines. But it was obviously too heavy
to be enabled always on all machines running the real user workloads.
For real world workloads, it was recommended to use the feature with
user-space controlled sampling approaches. For example, users could do
the page level monitoring only once per hour, on randomly selected one
percent of machines of their fleet. If the runtime and the size of the
fleet is long and big enough, it should provide statistically meaningful
data.
But users are too busy to implement such controls on their own.
Data Attributes Monitoring
==========================
Extend DAMON to monitor not only data accesses, but also general data
attributes. Do the extension while keeping the main promise of DAMON,
the bounded and best-effort minimum overhead.
Allow users to specify what data attributes in addition to the data
access they want to monitor. Users can install one 'data probe' per
data attribute of their interest for this purpose. The 'data probe'
should be able to be applied to any memory, and determine if the given
memory has the appropriate data attribute. E.g., if memory of physical
address 42 belongs to cgroup A. Each 'data probe' is configured with
filters that are very similar to the DAMOS filters.
When DAMON checks if each sampling address memory of each region is
accessed since the last check, it applies data probes if registered.
Same to the number of access check-positive samples accounting
(nr_accesses), it accounts the number of each data probe-positive
samples in another per-region counters array, namely 'probe_hits'. When
DAMON resets nr_accesses every aggregation interval, it resets
'probe_hits' together.
Users can read 'probe_hits' just before the values are reset. In this
way, users can know how many hot/cold memory regions have data
attributes of their interest. E.g., 30 percent of this system's hot
memory is belonging to cgroup A, and 80 percent of the cgroup
A-belonging hot memory is backed by huge pages.
Patches Sequence
================
First eight patches implement the core feature, interface and the
working support. Patch 1 introduces data probe data structure, namely
damon_probe. Patch 2 extends damon_ctx for installing data probes.
Patch 3 introduces another data structure for filters of each data
probe, namely damon_filter. Patch 4 updates damon_ctx commit function
to handle the probes. Patch 5 extends damon_region for the per-region
per-probe positive samples counter, namely probe_hits. Patch 6 extends
damon_operations for applying probes on the underlying DAMON operations
implementation. Patch 7 updates kdamond_fn() to invoke the probes
applying callback. Patch 8 finally implements the probes support on
paddr ops.
Ten changes for user interface (patches 9-18) come next. Patches 9-13
implements sysfs directories and files for setting data probes, namely
probes directory, probe directory, filters directory, filter directory
and filter directory internal files, respectively. Patch 14 connects
the user inputs that are made via the sysfs files to DAMON core.
Following three patches (patches 15-17) implement sysfs directories and
files for showing the probe_hits to users, namely probes directory,
probe directory and hits files, respectively. Patch 18 introduces a new
tracepoint for showing the probe_hits via tracefs.
Patch 19 adds a selftest for the sysfs files.
Patches 20 and 21 documents the design and usage of the new feature,
respectively.
Seven additional patches (patches 22-28) for monitoring belonging memory
cgroup follow. Depending on the feedback, this part might be separated
to another series in future. Patch 22 defines the DAMON filter type for
the new attribute, namely DAMON_FILTER_TYPE_MEMCG. Patch 23 add the
support on paddr ops. Patch 24 updates the sysfs interface for setup of
the target memcg. Patch 25 move code for easy reuse of the filter
target memcg setup. Patch 26 connects the user input to the core layer.
Finally, patches 27 and 28 update the design and usage documents for the
memcg attribute monitoring support.
Discussions
===========
This allows the page properties monitoring with overhead that is low
enough to be enabled always on real world workloads. Because the
sampling time for access check is reused for data attributes check, the
upper-bounded and best-effort minimum overhead of DAMON is kept.
Because the sampling memory for access check is reused for data
attributes check, additional overhead is minimum.
Still DAMOS-based page level properties monitoring should be useful,
because it provides a deterministic page level information. When in
doubt of the sampling based information, running DAMOS-based one
together and comparing the results would be useful, for debugging and
tuning.
Plan for Dropping RFC tag
=========================
I'm considering renaming the tracepoint for exposing probe_hits
(damon_aggregated_v2).
Making changes for feedback from myself, humans and Sashiko should be
the major remaining work.
I'm currently hoping to drop the RFC tag by 7.2-rc1.
Future Works: Mid Term
========================
This version of implementation is limiting the maximum number of data
probes to four. I will try to find a way to remove the limit in future.
I personally think it should be enough for common use cases, though, and
therefore not giving high priority at the moment.
Future Works: Long Term
=======================
There are user requests for extending DAMON with detailed access
information, for example, per-CPUs/threads/read/writes monitoring. For
that, I was working [2] on extending DAMON to use page fault events as
another access check primitives, and making the infrastructure flexible
for future use of yet another access check primitive. Actually there is
another ongoing work [3] for extending DAMON with PMU events. The
motivation of the work is reducing the overhead, though.
In my work [2], I was introducing a new interface for access sampling
primitives control. Now I think this data probe interface can be used
for that, too. That is, data access becomes just one type of data
attribute. Also, pg_idle-confirmed access, page fault-confirmed access,
and PMU event-confirmed access will be different types of data
attributes.
The regions adjustment mechanism is currently working based on the
access information. That's because DAMON is designed for data access
monitoring. That is, data access information is the primary interest,
and therefore DAMON adjusts regions in a way that can best-present the
information.
Once data access becomes just one of data attributes, there is no reason
to think data access that special. There might be some users not
interested in access at all but want to know the location of memory of
specific type. Data probes interface will allow doing that. Further,
we could extend the interface to let users set any data attribute as the
'primary' attribute. Then, DAMON will split and merge regions in a way
that can best-present the 'primary' attributes.
DAMOS will also be extended, to specify targets based on not only the
data access pattern, but all user-registered data attributes. From this
stage, we may be able to call DAMON as a "Data Attributes Monitoring and
Operations eNgine".
[1] https://lore.kernel.org/20250106193401.109161-1-sj@kernel.org
[2] https://lore.kernel.org/20251208062943.68824-1-sj@kernel.org/
[3] https://lore.kernel.org/20260423004211.7037-1-akinobu.mita@gmail.com
Changes from RFC
- rfc: https://lore.kernel.org/all/20260426205222.93895-1-sj@kernel.org/
- Support memcg DAMON filter.
- Use per-probe probe_hits sysfs file.
- Use dynamic_array for probe_hits tracing.
- Fix filter matching field.
- Fix folio leaking in damon_pa_filter_pass().
- Move nr_regions of damon_aggregated_v2 tracepoint after end.
- Rename DAMON_TEST_TYPE_ANON to DAMON_FILTER_TYPE_ANON.
SeongJae Park (28):
mm/damon/core: introduce struct damon_probe
mm/damon/core: embed damon_probe objects in damon_ctx
mm/damon/core: introduce damon_filter
mm/damon/core: commit probes
mm/damon/core: introduce damon_region->probe_hits
mm/damon/core: introduce damon_ops->apply_probes
mm/damon/core: do data attributes monitoring
mm/damon/paddr: support data attributes monitoring
mm/damon/sysfs: implement probes dir
mm/damon/sysfs: implement probe dir
mm/damon/sysfs: implement filters directory
mm/damon/sysfs: implement filter dir
mm/damon/sysfs: implement filter dir files
mm/damon/sysfs: setup probes on DAMON core API parameters
mm/damon/sysfs-schemes: implement tried_regions/<r>/probes/
mm/damon/sysfs-schemes: implement probe dir
mm/damon/sysfs-schemes: implement probe/hits file
mm/damon: trace probe_hits
selftests/damon/sysfs.sh: test probes dir
Docs/mm/damon/design: document data attributes monitoring
Docs/admin-guide/mm/damon/usage: document data attributes monitoring
mm/damon/core: introduce DAMON_FILTER_TYPE_MEMCG
mm/damon/paddr: support DAMON_FILTER_TYPE_MEMCG
mm/damon/sysfs: add filters/<F>/path file
mm/damon/sysfs-schemes: move memcg_path_to_id() to sysfs-common
mm/damon/sysfs: setup damon_filter->memcg_id from path
Docs/mm/damon/design: update for memcg damon filter
Docs/admin-guide/mm/damon/usage: update for memcg damon filter
Documentation/admin-guide/mm/damon/usage.rst | 48 +-
Documentation/mm/damon/design.rst | 39 ++
include/linux/damon.h | 67 +++
include/trace/events/damon.h | 36 ++
mm/damon/core.c | 195 +++++++
mm/damon/paddr.c | 76 +++
mm/damon/sysfs-common.c | 41 ++
mm/damon/sysfs-common.h | 2 +
mm/damon/sysfs-schemes.c | 222 ++++++--
mm/damon/sysfs.c | 557 +++++++++++++++++++
tools/testing/selftests/damon/sysfs.sh | 48 ++
11 files changed, 1280 insertions(+), 51 deletions(-)
base-commit: 610724cfd93c1c413faf9e5bb63926fe54849887
--
2.47.3
^ permalink raw reply
* [RFC PATCH v2 18/28] mm/damon: trace probe_hits
From: SeongJae Park @ 2026-05-12 14:36 UTC (permalink / raw)
Cc: SeongJae Park, Andrew Morton, Masami Hiramatsu, Mathieu Desnoyers,
Steven Rostedt, damon, linux-kernel, linux-mm, linux-trace-kernel
In-Reply-To: <20260512143645.113201-1-sj@kernel.org>
Introduce a new tracepoint for exposing the per-region per-probe
positive sample count via tracefs.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
include/trace/events/damon.h | 36 ++++++++++++++++++++++++++++++++++++
mm/damon/core.c | 7 +++++++
2 files changed, 43 insertions(+)
diff --git a/include/trace/events/damon.h b/include/trace/events/damon.h
index 7e25f4469b81b..d7b94c7640217 100644
--- a/include/trace/events/damon.h
+++ b/include/trace/events/damon.h
@@ -130,6 +130,42 @@ TRACE_EVENT(damon_monitor_intervals_tune,
TP_printk("sample_us=%lu", __entry->sample_us)
);
+TRACE_EVENT(damon_aggregated_v2,
+
+ TP_PROTO(unsigned int target_id, struct damon_region *r,
+ unsigned int nr_regions, unsigned int nr_probes),
+
+ TP_ARGS(target_id, r, nr_regions, nr_probes),
+
+ TP_STRUCT__entry(
+ __field(unsigned long, target_id)
+ __field(unsigned long, start)
+ __field(unsigned long, end)
+ __field(unsigned int, nr_regions)
+ __field(unsigned int, nr_accesses)
+ __field(unsigned int, age)
+ __dynamic_array(unsigned char, probe_hits, nr_probes)
+ ),
+
+ TP_fast_assign(
+ __entry->target_id = target_id;
+ __entry->start = r->ar.start;
+ __entry->end = r->ar.end;
+ __entry->nr_regions = nr_regions;
+ __entry->nr_accesses = r->nr_accesses;
+ __entry->age = r->age;
+ memcpy(__get_dynamic_array(probe_hits), r->probe_hits,
+ sizeof(*r->probe_hits) * nr_probes);
+ ),
+
+ TP_printk("target_id=%lu nr_regions=%u %lu-%lu: %u %u probe_hits=%s",
+ __entry->target_id, __entry->nr_regions,
+ __entry->start, __entry->end,
+ __entry->nr_accesses, __entry->age,
+ __print_hex(__get_dynamic_array(probe_hits),
+ __get_dynamic_array_len(probe_hits)))
+);
+
TRACE_EVENT(damon_aggregated,
TP_PROTO(unsigned int target_id, struct damon_region *r,
diff --git a/mm/damon/core.c b/mm/damon/core.c
index fe6c789f2cecb..14b15c9876516 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -1905,6 +1905,11 @@ static void kdamond_reset_aggregated(struct damon_ctx *c)
{
struct damon_target *t;
unsigned int ti = 0; /* target's index */
+ unsigned int nr_probes = 0;
+ struct damon_probe *probe;
+
+ damon_for_each_probe(probe, c)
+ nr_probes++;
damon_for_each_target(t, c) {
struct damon_region *r;
@@ -1913,6 +1918,8 @@ static void kdamond_reset_aggregated(struct damon_ctx *c)
int i;
trace_damon_aggregated(ti, r, damon_nr_regions(t));
+ trace_damon_aggregated_v2(ti, r, damon_nr_regions(t),
+ nr_probes);
damon_warn_fix_nr_accesses_corruption(r);
r->last_nr_accesses = r->nr_accesses;
r->nr_accesses = 0;
--
2.47.3
^ permalink raw reply related
* Re: [PATCH] tracing: Switch trace_recursion_record.c code over to use guard()
From: Yash Suthar @ 2026-05-12 14:41 UTC (permalink / raw)
To: rostedt
Cc: mhiramat, mathieu.desnoyers, linux-kernel, linux-trace-kernel,
skhan, me
In-Reply-To: <20260502174741.39636-1-yashsuthar983@gmail.com>
Gentle ping.
Sincerely,
Yash Suthar
On Sat, May 2, 2026 at 11:17 PM Yash Suthar <yashsuthar983@gmail.com> wrote:
>
> Switch mutex_lock()/mutex_unlock() to guard().
> also drop the ret local variable and return directly.
>
> Signed-off-by: Yash Suthar <yashsuthar983@gmail.com>
> ---
> kernel/trace/trace_recursion_record.c | 8 +++-----
> 1 file changed, 3 insertions(+), 5 deletions(-)
>
> diff --git a/kernel/trace/trace_recursion_record.c b/kernel/trace/trace_recursion_record.c
> index 784fe1fbb866..bac4bc844ccd 100644
> --- a/kernel/trace/trace_recursion_record.c
> +++ b/kernel/trace/trace_recursion_record.c
> @@ -180,9 +180,8 @@ static const struct seq_operations recursed_function_seq_ops = {
>
> static int recursed_function_open(struct inode *inode, struct file *file)
> {
> - int ret = 0;
> + guard(mutex)(&recursed_function_lock);
>
> - mutex_lock(&recursed_function_lock);
> /* If this file was opened for write, then erase contents */
> if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) {
> /* disable updating records */
> @@ -194,10 +193,9 @@ static int recursed_function_open(struct inode *inode, struct file *file)
> atomic_set(&nr_records, 0);
> }
> if (file->f_mode & FMODE_READ)
> - ret = seq_open(file, &recursed_function_seq_ops);
> - mutex_unlock(&recursed_function_lock);
> + return seq_open(file, &recursed_function_seq_ops);
>
> - return ret;
> + return 0;
> }
>
> static ssize_t recursed_function_write(struct file *file,
> --
> 2.43.0
>
^ permalink raw reply
* Re: [PATCHv2] uprobes: Use flexible array for xol_area bitmap
From: Masami Hiramatsu @ 2026-05-12 14:48 UTC (permalink / raw)
To: Oleg Nesterov
Cc: Rosen Penev, linux-kernel, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
James Clark, Masami Hiramatsu,
open list:PERFORMANCE EVENTS SUBSYSTEM, open list:UPROBES
In-Reply-To: <agMPMAnsCH2ZRhf5@redhat.com>
On Tue, 12 May 2026 13:29:52 +0200
Oleg Nesterov <oleg@redhat.com> wrote:
> On 05/11, Rosen Penev wrote:
> >
> > struct xol_area {
> > wait_queue_head_t wq; /* if all slots are busy */
> > - unsigned long *bitmap; /* 0 = free slot */
> >
> > struct page *page;
> > /*
> > @@ -117,6 +116,7 @@ struct xol_area {
> > * the vma go away, and we must handle that reasonably gracefully.
> > */
> > unsigned long vaddr; /* Page(s) of instruction slots */
> > + unsigned long bitmap[]; /* 0 = free slot */
> > };
> >
> > static void uprobe_warn(struct task_struct *t, const char *msg)
> > @@ -1755,18 +1755,13 @@ static struct xol_area *__create_xol_area(unsigned long vaddr)
> > struct xol_area *area;
> > void *insns;
> >
> > - area = kzalloc_obj(*area);
> > + area = kzalloc_flex(*area, bitmap, BITS_TO_LONGS(UINSNS_PER_PAGE));
>
> The downside is that kmalloc will use kmem_cache with ->object_size = PAGE_SIZE * 2,
> almost half of the allocated memory won't be used...
Hmm, is the bitmap so big?
#define UINSNS_PER_PAGE (PAGE_SIZE/UPROBE_XOL_SLOT_BYTES)
And even on arm64,
#define UPROBE_XOL_SLOT_BYTES AARCH64_INSN_SIZE
So if PAGE_SIZE is 4k, UINSNS_PER_PAGE is 1k, its BITS_TO_LONGS will
be 1024/64 = 16. So 128 bytes. So the object is allocated from
object_size = 256 ?
Thank you,
>
> But technically the patch looks correct so I won't argue.
>
> Oleg.
>
>
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
^ permalink raw reply
* Re: [PATCH mm-unstable v17 11/14] mm/khugepaged: Introduce mTHP collapse support
From: Wei Yang @ 2026-05-12 15:44 UTC (permalink / raw)
To: Nico Pache
Cc: linux-doc, linux-kernel, linux-mm, linux-trace-kernel, aarcange,
akpm, anshuman.khandual, apopple, baohua, baolin.wang, byungchul,
catalin.marinas, cl, corbet, dave.hansen, david, dev.jain, gourry,
hannes, hughd, jack, jackmanb, jannh, jglisse, joshua.hahnjy, kas,
lance.yang, liam, ljs, mathieu.desnoyers, matthew.brost, mhiramat,
mhocko, peterx, pfalcato, rakie.kim, raquini, rdunlap,
richard.weiyang, rientjes, rostedt, rppt, ryan.roberts, shivankg,
sunnanyong, surenb, thomas.hellstrom, tiwai, usamaarif642, vbabka,
vishal.moola, wangkefeng.wang, will, willy, yang, ying.huang, ziy,
zokeefe
In-Reply-To: <20260511185817.686831-12-npache@redhat.com>
On Mon, May 11, 2026 at 12:58:11PM -0600, Nico Pache wrote:
>Enable khugepaged to collapse to mTHP orders. This patch implements the
>main scanning logic using a bitmap to track occupied pages and a stack
>structure that allows us to find optimal collapse sizes.
>
>Previous to this patch, PMD collapse had 3 main phases, a light weight
>scanning phase (mmap_read_lock) that determines a potential PMD
>collapse, an alloc phase (mmap unlocked), then finally heavier collapse
>phase (mmap_write_lock).
>
>To enabled mTHP collapse we make the following changes:
>
>During PMD scan phase, track occupied pages in a bitmap. When mTHP
>orders are enabled, we remove the restriction of max_ptes_none during the
>scan phase to avoid missing potential mTHP collapse candidates. Once we
>have scanned the full PMD range and updated the bitmap to track occupied
>pages, we use the bitmap to find the optimal mTHP size.
>
>Implement collapse_scan_bitmap() to perform binary recursion on the bitmap
>and determine the best eligible order for the collapse. A stack structure
>is used instead of traditional recursion to manage the search. This also
>prevents a traditional recursive approach when the kernel stack struct is
>limited. The algorithm recursively splits the bitmap into smaller chunks to
>find the highest order mTHPs that satisfy the collapse criteria. We start
>by attempting the PMD order, then moved on the consecutively lower orders
>(mTHP collapse). The stack maintains a pair of variables (offset, order),
>indicating the number of PTEs from the start of the PMD, and the order of
>the potential collapse candidate.
>
>The algorithm for consuming the bitmap works as such:
> 1) push (0, HPAGE_PMD_ORDER) onto the stack
> 2) pop the stack
> 3) check if the number of set bits in that (offset,order) pair
> statisfy the max_ptes_none threshold for that order
> 4) if yes, attempt collapse
> 5) if no (or collapse fails), push two new stack items representing
> the left and right halves of the current bitmap range, at the
> next lower order
> 6) repeat at step (2) until stack is empty.
>
>Below is a diagram representing the algorithm and stack items:
>
> offset mid_offset
> | |
> | |
> v v
> ____________________________________
> | PTE Page Table |
> --------------------------------------
> <-------><------->
> order-1 order-1
>
>mTHP collapses reject regions containing swapped out or shared pages.
>This is because adding new entries can lead to new none pages, and these
>may lead to constant promotion into a higher order mTHP. A similar
>issue can occur with "max_ptes_none > HPAGE_PMD_NR/2" due to a collapse
>introducing at least 2x the number of pages, and on a future scan will
>satisfy the promotion condition once again. This issue is prevented via
>the collapse_max_ptes_none() function which imposes the max_ptes_none
>restrictions above.
>
>We currently only support mTHP collapse for max_ptes_none values of 0
>and HPAGE_PMD_NR - 1. resulting in the following behavior:
>
> - max_ptes_none=0: Never introduce new empty pages during collapse
> - max_ptes_none=HPAGE_PMD_NR-1: Always try collapse to the highest
> available mTHP order
>
>Any other max_ptes_none value will emit a warning and skip mTHP collapse
>attempts. There should be no behavior change for PMD collapse.
>
>Once we determine what mTHP sizes fits best in that PMD range a collapse
>is attempted. A minimum collapse order of 2 is used as this is the lowest
>order supported by anon memory as defined by THP_ORDERS_ALL_ANON.
>
>Currently madv_collapse is not supported and will only attempt PMD
>collapse.
>
>We can also remove the check for is_khugepaged inside the PMD scan as
>the collapse_max_ptes_none() function handles this logic now.
>
>Signed-off-by: Nico Pache <npache@redhat.com>
[...]
>+static int mthp_collapse(struct mm_struct *mm, unsigned long address,
>+ int referenced, int unmapped, struct collapse_control *cc,
>+ unsigned long enabled_orders)
>+{
>+ unsigned int nr_occupied_ptes, nr_ptes;
>+ int max_ptes_none, collapsed = 0, stack_size = 0;
>+ unsigned long collapse_address;
>+ struct mthp_range range;
>+ u16 offset;
>+ u8 order;
>+
>+ collapse_mthp_stack_push(cc, &stack_size, 0, HPAGE_PMD_ORDER);
>+
>+ while (stack_size) {
>+ range = collapse_mthp_stack_pop(cc, &stack_size);
>+ order = range.order;
>+ offset = range.offset;
>+ nr_ptes = 1UL << order;
>+
>+ if (!test_bit(order, &enabled_orders))
>+ goto next_order;
>+
>+ max_ptes_none = collapse_max_ptes_none(cc, NULL, order);
I am thinking whether there is a behavioral change for userfaultfd_armed(vma).
collapse_single_pmd()
collapse_scan_pmd
max_ptes_none = collapse_max_ptes_none(cc, vma)
max_ptes_none = KHUGEPAGED_MAX_PTES_LIMIT --- (1)
mthp_collapse
max_ptes_none = collapse_max_ptes_none(cc, NULL) --- (2)
collapse_huge_page(mm)
hugepage_vma_revalidate(&vma)
__collapse_huge_page_isolate(vma)
max_ptes_none = collapse_max_ptes_none(cc, vma)
Before mthp_collapse() introduced, userfaultfd_armed(vma) is skipped if there
is any pte_none_or_zero() in collapse_scan_pmd().
But now, max_ptes_none could be set to KHUGEPAGED_MAX_PTES_LIMIT at (1), so
that we can scan all the pte to get the bitmap. This means
userfaultfd_armed(vma) could continue even with pte_none_or_zero().
Then in mthp_collapse(), collapse_max_ptes_none() at (2) ignores
userfaultfd_armed(vma), which means it will continue to collapse a
userfaultfd_armed(vma) when there is pte_none_or_zero().
The good news is we will stop at __collapse_huge_page_isolate(), where we
get collapse_max_ptes_none() with vma. But we already did a lot of work.
Not sure if I missed something.
>+
>+ if (max_ptes_none < 0)
>+ return collapsed;
>+
>+ nr_occupied_ptes = collapse_mthp_count_present(cc, offset,
>+ nr_ptes);
>+
>+ if (nr_occupied_ptes >= nr_ptes - max_ptes_none) {
>+ int ret;
>+
>+ collapse_address = address + offset * PAGE_SIZE;
>+ ret = collapse_huge_page(mm, collapse_address, referenced,
>+ unmapped, cc, order);
>+ if (ret == SCAN_SUCCEED) {
>+ collapsed += nr_ptes;
>+ continue;
>+ }
>+ }
>+
>+next_order:
>+ if (order > KHUGEPAGED_MIN_MTHP_ORDER) {
>+ const u8 next_order = order - 1;
>+ const u16 mid_offset = offset + (nr_ptes / 2);
>+
>+ collapse_mthp_stack_push(cc, &stack_size, mid_offset,
>+ next_order);
>+ collapse_mthp_stack_push(cc, &stack_size, offset,
>+ next_order);
>+ }
>+ }
>+ return collapsed;
>+}
>+
> static enum scan_result collapse_scan_pmd(struct mm_struct *mm,
> struct vm_area_struct *vma, unsigned long start_addr,
> bool *lock_dropped, struct collapse_control *cc)
> {
>- const int max_ptes_none = collapse_max_ptes_none(cc, vma, HPAGE_PMD_ORDER);
>+ int max_ptes_none = collapse_max_ptes_none(cc, vma, HPAGE_PMD_ORDER);
> const unsigned int max_ptes_shared = collapse_max_ptes_shared(cc, HPAGE_PMD_ORDER);
> const unsigned int max_ptes_swap = collapse_max_ptes_swap(cc, HPAGE_PMD_ORDER);
>+ enum tva_type tva_flags = cc->is_khugepaged ? TVA_KHUGEPAGED : TVA_FORCED_COLLAPSE;
> pmd_t *pmd;
>- pte_t *pte, *_pte;
>- int none_or_zero = 0, shared = 0, referenced = 0;
>+ pte_t *pte, *_pte, pteval;
>+ int i;
>+ int none_or_zero = 0, shared = 0, nr_collapsed = 0, referenced = 0;
> enum scan_result result = SCAN_FAIL;
> struct page *page = NULL;
> struct folio *folio = NULL;
> unsigned long addr;
>+ unsigned long enabled_orders;
> spinlock_t *ptl;
> int node = NUMA_NO_NODE, unmapped = 0;
>
>@@ -1429,8 +1579,19 @@ static enum scan_result collapse_scan_pmd(struct mm_struct *mm,
> goto out;
> }
>
>+ bitmap_zero(cc->mthp_bitmap, MAX_PTRS_PER_PTE);
> memset(cc->node_load, 0, sizeof(cc->node_load));
> nodes_clear(cc->alloc_nmask);
>+
>+ enabled_orders = collapse_allowable_orders(vma, vma->vm_flags, tva_flags);
Would it be 0 at this point?
>+
>+ /*
>+ * If PMD is the only enabled order, enforce max_ptes_none, otherwise
>+ * scan all pages to populate the bitmap for mTHP collapse.
>+ */
>+ if (enabled_orders != BIT(HPAGE_PMD_ORDER))
>+ max_ptes_none = KHUGEPAGED_MAX_PTES_LIMIT;
>+
> pte = pte_offset_map_lock(mm, pmd, start_addr, &ptl);
> if (!pte) {
> cc->progress++;
>@@ -1438,11 +1599,13 @@ static enum scan_result collapse_scan_pmd(struct mm_struct *mm,
> goto out;
> }
>
>- for (addr = start_addr, _pte = pte; _pte < pte + HPAGE_PMD_NR;
>- _pte++, addr += PAGE_SIZE) {
>+ for (i = 0; i < HPAGE_PMD_NR; i++) {
>+ _pte = pte + i;
>+ addr = start_addr + i * PAGE_SIZE;
>+ pteval = ptep_get(_pte);
>+
> cc->progress++;
>
>- pte_t pteval = ptep_get(_pte);
> if (pte_none_or_zero(pteval)) {
> if (++none_or_zero > max_ptes_none) {
> result = SCAN_EXCEED_NONE_PTE;
>@@ -1522,6 +1685,8 @@ static enum scan_result collapse_scan_pmd(struct mm_struct *mm,
> }
> }
>
>+ /* Set bit for occupied pages */
>+ __set_bit(i, cc->mthp_bitmap);
> /*
> * Record which node the original page is from and save this
> * information to cc->node_load[].
>@@ -1580,10 +1745,11 @@ static enum scan_result collapse_scan_pmd(struct mm_struct *mm,
> if (result == SCAN_SUCCEED) {
> /* collapse_huge_page expects the lock to be dropped before calling */
> mmap_read_unlock(mm);
>- result = collapse_huge_page(mm, start_addr, referenced,
>- unmapped, cc, HPAGE_PMD_ORDER);
>+ nr_collapsed = mthp_collapse(mm, start_addr, referenced, unmapped,
>+ cc, enabled_orders);
> /* collapse_huge_page will return with the mmap_lock released */
collapse_huge_page will return with mmap_lock released, but mthp_collapse()
may not?
> *lock_dropped = true;
>+ result = nr_collapsed ? SCAN_SUCCEED : SCAN_FAIL;
> }
> out:
> trace_mm_khugepaged_scan_pmd(mm, folio, referenced,
>--
>2.54.0
--
Wei Yang
Help you, Help me
^ permalink raw reply
* Re: [PATCHv2] uprobes: Use flexible array for xol_area bitmap
From: Oleg Nesterov @ 2026-05-12 16:17 UTC (permalink / raw)
To: Masami Hiramatsu
Cc: Rosen Penev, linux-kernel, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
James Clark, open list:PERFORMANCE EVENTS SUBSYSTEM,
open list:UPROBES
In-Reply-To: <20260512234857.44e2b0fafa4961900fdb7246@kernel.org>
On 05/12, Masami Hiramatsu wrote:
>
> On Tue, 12 May 2026 13:29:52 +0200
> Oleg Nesterov <oleg@redhat.com> wrote:
>
> > >
> > > - area = kzalloc_obj(*area);
> > > + area = kzalloc_flex(*area, bitmap, BITS_TO_LONGS(UINSNS_PER_PAGE));
> >
> > The downside is that kmalloc will use kmem_cache with ->object_size = PAGE_SIZE * 2,
> > almost half of the allocated memory won't be used...
>
> Hmm, is the bitmap so big?
>
> #define UINSNS_PER_PAGE (PAGE_SIZE/UPROBE_XOL_SLOT_BYTES)
>
> And even on arm64,
>
> #define UPROBE_XOL_SLOT_BYTES AARCH64_INSN_SIZE
>
> So if PAGE_SIZE is 4k, UINSNS_PER_PAGE is 1k, its BITS_TO_LONGS will
> be 1024/64 = 16. So 128 bytes. So the object is allocated from
> object_size = 256 ?
Indeed you are right.
Sorry for the noise and thanks for correcting me! I can't even explain how can
I came to conclusion that object_size can be greater than PAGE_SIZE with this
change ;)
So I think the patch from Rosen is fine.
Thanks,
Oleg.
^ permalink raw reply
* Re: [RFC][PATCH] unwind: Add stacktrace_setup system call
From: Steven Rostedt @ 2026-05-12 16:47 UTC (permalink / raw)
To: Jens Remus
Cc: LKML, Linux Trace Kernel, Masami Hiramatsu, Mathieu Desnoyers,
Josh Poimboeuf, 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, Borislav Petkov,
Dave Hansen, David Hildenbrand, H. Peter Anvin, Liam R. Howlett,
Lorenzo Stoakes, Michal Hocko, Mike Rapoport, Suren Baghdasaryan,
Vlastimil Babka, Heiko Carstens, Vasily Gorbik
In-Reply-To: <43158d95-b4c2-44d2-a244-eb546fb2bfaa@linux.ibm.com>
On Fri, 8 May 2026 09:46:30 +0200
Jens Remus <jremus@linux.ibm.com> wrote:
> > STACKTRACE_REGISTER_SFRAME - This registers the sframe
> > STACKTRACE_UNREGISTER_SFRAME - This removes the sframe
> >
> > Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
>
> LGTM. Some comments/questions below.
Note, after talking with people at LSF/MM/BPF, I plan on completely
changing this system call into two distinct ones, and only for sframes.
I'll be sending that later this week.
>
> > diff --git a/include/uapi/linux/stacktrace.h b/include/uapi/linux/stacktrace.h
>
> > @@ -0,0 +1,10 @@
> > +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
> > +#ifndef _UAPI_LINUX_STACKTRACE_H
> > +#define _UAPI_LINUX_STACKTRACE_H
> > +
> > +enum stacktrace_setup_types {
> > + STACKTRACE_REGISTER_SFRAME = 1,
> > + STACKTRACE_UNREGISTER_SFRAME = 2,
> > +};
> > +
> > +#endif /* _UAPI_LINUX_STACKTRACE_H */
>
> > diff --git a/kernel/unwind/sframe.c b/kernel/unwind/sframe.c
>
> Having the syscall live in kernel/unwind/sframe.c means it is only
> available if config option HAVE_UNWIND_USER_SFRAME is selected (which
> triggers sframe.o to be built and linked into the kernel), which makes
> sense as long as it only implements sframe-specific functionality.
> I suppose it could be moved elsewhere if non-sframe use cases would
> arise in the future?
The new system calls will only be for sframes. Other unwinders will need to
implement their own system calls.
>
> Would Dylan need to guard it when introducing HAVE_UNWIND_KERNEL_SFRAME?
> Provided the syscall fails with -ENOSYS if not implemented (e.g. when
> HAVE_UNWIND_USER_SFRAME is not enabled) the dummy implementations of
> sframe_add_section() and sframe_remove_section() in linux/sframe.h also
> return -ENOSYS, so the user observable behavior would be the same and
> it would not matter. Do you agree?
I'll reply to that when Dylan's patches get closer to acceptance ;-)
>
> > @@ -12,8 +12,10 @@
> > #include <linux/mm.h>
> > #include <linux/string_helpers.h>
> > #include <linux/sframe.h>
> > +#include <linux/syscalls.h>
> > #include <asm/unwind_user_sframe.h>
> > #include <linux/unwind_user_types.h>
> > +#include <uapi/linux/stacktrace.h>
> >
> > #include "sframe.h"
> > #include "sframe_debug.h"
> > @@ -838,3 +840,38 @@ void sframe_free_mm(struct mm_struct *mm)
> >
> > mtree_destroy(&mm->sframe_mt);
> > }
> > +
> > +/**
> > + * sys_stacktrace_setup - register an address for user space stacktrace walking.
> > + * @op: Type of operation to perform
> > + * @addr_start: The virtual address of the stacktrace information
> > + * @addr_length: The length of the stacktrace information
> > + * @text_start: The virtual address of the text that @addr_start represents
> > + * @text_length: The length of teh text
> > + *
> > + * This system call is used by dynamic library utilities to inform the kernel
> > + * of meta data that it loaded that can be used by the kernel to know how
> > + * to stack walk the given text locations.
> > + *
> > + * Currently only sframes are supported, but in the future, this may be used
> > + * to tell the kernel about JIT code which will most likely have a different
> > + * format.
> > + *
> > + * The type command may be extended and parameters may be used for other
> > + * purposes.
> > + *
> > + * Return: 0 if successful, otherwise a negative error.
> > + */
> > +SYSCALL_DEFINE5(stacktrace_setup, int, op, unsigned long, addr_start,
> > + unsigned long, addr_length, unsigned long, text_start,
> > + unsigned long, text_length)
>
> Would it make sense to keep the parameters generic from start, similar
> to how it is done in prctl()? Or can this be changed later, if the need
> arises?
With discussions at LSF/MM/BPF I'll have the system call parameters be a
pointer to a structure, and a size of that structure. All the API will then
be part of the structure.
Thanks for reviewing,
-- Steve
>
> SYSCALL_DEFINE5(stacktrace_setup, int, op, unsigned long, arg2,
> unsigned long, arg3, unsigned long, arg4, unsigned long, arg5)
>
> > +{
> > + switch (op) {
> > + case STACKTRACE_REGISTER_SFRAME:
> > + return sframe_add_section(addr_start, addr_start + addr_length,
> > + text_start, text_start+text_length);
>
> Nit:
> text_start, text_start + text_length);
>
> > + case STACKTRACE_UNREGISTER_SFRAME:
> > + return sframe_remove_section(addr_start);
> > + }
> > + return -EINVAL;
> > +}
> Thanks and regards,
> Jens
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox