* [PATCH v5 2/3] docs: tracing/fprobe: Document list filters and :entry/:exit
From: Seokwoo Chung (Ryan) @ 2026-01-14 22:13 UTC (permalink / raw)
To: rostedt, mhiramat, corbet, shuah
Cc: mathieu.desnoyers, linux-kernel, linux-trace-kernel, linux-doc,
linux-kselftest, Seokwoo Chung (Ryan)
In-Reply-To: <20260114221341.128038-1-seokwoo.chung130@gmail.com>
Signed-off-by: Seokwoo Chung (Ryan) <seokwoo.chung130@gmail.com>
---
Documentation/trace/fprobetrace.rst | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/Documentation/trace/fprobetrace.rst b/Documentation/trace/fprobetrace.rst
index b4c2ca3d02c1..5efd9c374365 100644
--- a/Documentation/trace/fprobetrace.rst
+++ b/Documentation/trace/fprobetrace.rst
@@ -25,14 +25,19 @@ Synopsis of fprobe-events
-------------------------
::
- f[:[GRP1/][EVENT1]] SYM [FETCHARGS] : Probe on function entry
- f[MAXACTIVE][:[GRP1/][EVENT1]] SYM%return [FETCHARGS] : Probe on function exit
+ f[:[GRP1/][EVENT1]] SYM [FETCHARGS] : Probe on function entry
+ f[MAXACTIVE][:[GRP1/][EVENT1]] SYM%return [FETCHARGS] : Probe on function exit
+ f[:[GRP1/][EVENT1] SYM[,[!]SYM[,...][:entry|:exit] [FETCHARGS] : Probe on
+ list/wildcard
t[:[GRP2/][EVENT2]] TRACEPOINT [FETCHARGS] : Probe on tracepoint
GRP1 : Group name for fprobe. If omitted, use "fprobes" for it.
GRP2 : Group name for tprobe. If omitted, use "tracepoints" for it.
EVENT1 : Event name for fprobe. If omitted, the event name is
- "SYM__entry" or "SYM__exit".
+ - For a single literal symbol, the event name is
+ "SYM__entry" or "SYM__exit".
+ - For a *list or any wildcard*, an explicit [GRP1/][EVENT1] is
+ required.
EVENT2 : Event name for tprobe. If omitted, the event name is
the same as "TRACEPOINT", but if the "TRACEPOINT" starts
with a digit character, "_TRACEPOINT" is used.
@@ -40,6 +45,13 @@ Synopsis of fprobe-events
can be probed simultaneously, or 0 for the default value
as defined in Documentation/trace/fprobe.rst
+ SYM : Function name or comma-separated list of symbols.
+ - SYM prefixed with "!" are exclusions.
+ - ":entry" suffix means it probes entry of given symbols
+ (default)
+ - ":exit" suffix means it probes exit of given symbols.
+ - "%return" suffix means it probes exit of SYM (single
+ symbol).
FETCHARGS : Arguments. Each probe can have up to 128 args.
ARG : Fetch "ARG" function argument using BTF (only for function
entry or tracepoint.) (\*1)
--
2.43.0
^ permalink raw reply related
* [PATCH v5 0/3] tracing/fprobe: Support comma-separated symbols and :entry/:exit
From: Seokwoo Chung (Ryan) @ 2026-01-14 22:13 UTC (permalink / raw)
To: rostedt, mhiramat, corbet, shuah
Cc: mathieu.desnoyers, linux-kernel, linux-trace-kernel, linux-doc,
linux-kselftest, Seokwoo Chung (Ryan)
In-Reply-To: <20251126184110.72241-1-seokwoo.chung130@gmail.com>
This series extends fprobe dynamic events to accept a comma-separated list of
symbols and explicit/suffixes.
Currently, fprobe only supports a single symbol (or wildcard) per event. This
series allow users to specify a comma-separated list of symbols, including
exclusions, and to select entry/exit explicitly using /
Examples:
- f:[GRP/][EVENT] func1,func2,func3
- f:[GRP/][EVENT] func1,!func2,func3 (exclude with '!')
Logic changes:
- Refactor parsing logic into parse_fprobe_spec()
- Support comma-separated lists and '!' exclusions
- Add / suffixes for explicit entry/exit selection
- Preserve legacy single-symbol behavior (single symbols still accept %return)
- Disable BTF-based signature lookup when list/wildcard is used, since one
function signature cannot apply to multiple functions
- Reject mixed legacy/new syntax where applicable (e.g. list + %return)
- Update tracefs/README and fprobe documentation
- Add ftrace selftests covering accepted list syntax cases
*Patch order is adjusted: code first, then docs, then selftest
Changes in v5:
- Reordered patches (code->docs->selftests) as suggested
- Addressed review feedback on README help text to show both legacy and list
syntaxes
- Added missing traceprobe error IDs used by the new validation and fixed
parsing/bracing issues found by automated builds
- Removed the dedicated list_mode field and infer list behavior from presence of
filter/nofilter and keep struct trace_probe as the last member
- Link to v4: https://lore.kernel.org/linux-trace-kernel/20251127151218.4763b25c751bb2aac4b1ee36@kernel.org/
I am not fully confident the runtime testing coverage that I did is sufficient
across configs/architectures, so additional verification would be appreciated.
Best regards,
Ryan Chung
Seokwoo Chung (Ryan) (3):
tracing/fprobe: Support comma-separated symbols and :entry/:exit
docs: tracing/fprobe: Document list filters and :entry/:exit
selftests/ftrace: Add accept cases for fprobe list syntax
Documentation/trace/fprobetrace.rst | 18 +++++--
kernel/trace/trace.c | 4 +-
kernel/trace/trace_fprobe.c | 49 ++++++++++---------
kernel/trace/trace_probe.h | 2 +
.../ftrace/test.d/dynevent/fprobe_list.tc | 2 +-
5 files changed, 47 insertions(+), 28 deletions(-)
base-commit: f0c13b210e4366e03bd9e8967347b06b227e20a4
--
2.43.0
^ permalink raw reply
* [PATCH v5 1/3] tracing/fprobe: Support comma-separated symbols and :entry/:exit
From: Seokwoo Chung (Ryan) @ 2026-01-14 22:13 UTC (permalink / raw)
To: rostedt, mhiramat, corbet, shuah
Cc: mathieu.desnoyers, linux-kernel, linux-trace-kernel, linux-doc,
linux-kselftest, Seokwoo Chung (Ryan)
In-Reply-To: <20260114221341.128038-1-seokwoo.chung130@gmail.com>
Signed-off-by: Seokwoo Chung (Ryan) <seokwoo.chung130@gmail.com>
---
kernel/trace/trace.c | 4 +--
kernel/trace/trace_fprobe.c | 49 ++++++++++++++++++++-----------------
kernel/trace/trace_probe.h | 2 ++
3 files changed, 31 insertions(+), 24 deletions(-)
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 10cdcc7b194e..73b59d47dfe7 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -5578,8 +5578,8 @@ static const char readme_msg[] =
"\t r[maxactive][:[<group>/][<event>]] <place> [<args>]\n"
#endif
#ifdef CONFIG_FPROBE_EVENTS
- "\t f[:[<group>/][<event>]] <func-name>[:entry|:exit] [<args>]\n"
- "\t (single symbols still accept %return)\n"
+ "\t f[:[<group>/][<event>]] <func-name>[%return] [<args>]\n"
+ "\t f[:[<group>/][<event>]] <func-list>[:entry|:exit] [<args>]\n"
"\t t[:[<group>/][<event>]] <tracepoint> [<args>]\n"
#endif
#ifdef CONFIG_HIST_TRIGGERS
diff --git a/kernel/trace/trace_fprobe.c b/kernel/trace/trace_fprobe.c
index 5a2a41eea603..1663c341ddb4 100644
--- a/kernel/trace/trace_fprobe.c
+++ b/kernel/trace/trace_fprobe.c
@@ -187,16 +187,23 @@ DEFINE_FREE(tuser_put, struct tracepoint_user *,
*/
struct trace_fprobe {
struct dyn_event devent;
- char *filter;
+
struct fprobe fp;
- bool list_mode;
- char *nofilter;
const char *symbol;
- struct trace_probe tp;
+ char *filter;
+ char *nofilter;
+
bool tprobe;
struct tracepoint_user *tuser;
+
+ struct trace_probe tp;
};
+static inline bool trace_fprobe_has_list(const struct trace_fprobe *tf)
+{
+ return tf->filter || tf->nofilter;
+}
+
static bool is_trace_fprobe(struct dyn_event *ev)
{
return ev->ops == &trace_fprobe_ops;
@@ -847,7 +854,7 @@ static int __register_trace_fprobe(struct trace_fprobe *tf)
* - list_mode: pass filter/nofilter
* - single: pass symbol only (legacy)
*/
- if (tf->list_mode)
+ if (trace_fprobe_has_list(tf))
return register_fprobe(&tf->fp, tf->filter, tf->nofilter);
return register_fprobe(&tf->fp, tf->symbol, NULL);
}
@@ -1188,11 +1195,18 @@ static int parse_fprobe_spec(const char *in, bool is_tracepoint,
*base = NULL; *filter = NULL; *nofilter = NULL;
*is_return = false; *list_mode = false;
- if (is_tracepoint) {
+ if (is_tracepoint)
+ {
if (strchr(in, ',') || strchr(in, ':'))
+ {
+ trace_probe_log_err(0, BAD_TP_NAME);
return -EINVAL;
+ }
if (strstr(in, "%return"))
+ {
+ trace_probe_log_err(p - in, BAD_TP_NAME);
return -EINVAL;
+ }
for (p = in; *p; p++)
if (!isalnum(*p) && *p != '_')
return -EINVAL;
@@ -1225,6 +1239,7 @@ static int parse_fprobe_spec(const char *in, bool is_tracepoint,
} else if (!strcmp(p, ":entry")) {
*(char *)p = '\0';
} else {
+ trace_probe_log_err(p - work, BAD_LIST_SUFFIX);
return -EINVAL;
}
}
@@ -1233,6 +1248,7 @@ static int parse_fprobe_spec(const char *in, bool is_tracepoint,
list = !!strchr(work, ',');
if (list && legacy_ret) {
+ trace_probe_log_err(p - work, BAD_LEGACY_RET);
return -EINVAL;
}
@@ -1245,12 +1261,9 @@ static int parse_fprobe_spec(const char *in, bool is_tracepoint,
if (list) {
char *tmp = b, *tok;
- size_t fsz, nfsz;
- fsz = nfsz = strlen(b) + 1;
-
- f = kzalloc(fsz, GFP_KERNEL);
- nf = kzalloc(nfsz, GFP_KERNEL);
+ f = kzalloc(strlen(b) + 1, GFP_KERNEL);
+ nf = kzalloc(strlen(b) + 1, GFP_KERNEL);
if (!f || !nf)
return -ENOMEM;
@@ -1261,6 +1274,7 @@ static int parse_fprobe_spec(const char *in, bool is_tracepoint,
if (*tok == '\0') {
trace_probe_log_err(tmp - b - 1, BAD_TP_NAME);
return -EINVAL;
+ }
if (neg)
tok++;
@@ -1455,17 +1469,8 @@ static int trace_fprobe_create_internal(int argc, const char *argv[],
/* carry list parsing result into tf */
if (!is_tracepoint) {
- tf->list_mode = list_mode;
- if (parsed_filter) {
- tf->filter = kstrdup(parsed_filter, GFP_KERNEL);
- if (!tf->filter)
- return -ENOMEM;
- }
- if (parsed_nofilter) {
- tf->nofilter = kstrdup(parsed_nofilter, GFP_KERNEL);
- if (!tf->nofilter)
- return -ENOMEM;
- }
+ tf->filter = no_free_ptr(parsed_filter);
+ tf->nofilter = no_free_ptr(parsed_nofilter);
}
/* parse arguments */
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 9fc56c937130..b8b0544eb7cd 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -494,9 +494,11 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
C(BAD_PROBE_ADDR, "Invalid probed address or symbol"), \
C(NON_UNIQ_SYMBOL, "The symbol is not unique"), \
C(BAD_RETPROBE, "Retprobe address must be an function entry"), \
+ C(BAD_LEGACY_RET, "Legacy %return not allowed with list"), \
C(NO_TRACEPOINT, "Tracepoint is not found"), \
C(BAD_TP_NAME, "Invalid character in tracepoint name"),\
C(BAD_ADDR_SUFFIX, "Invalid probed address suffix"), \
+ C(BAD_LIST_SUFFIX, "Bad list suffix"), \
C(NO_GROUP_NAME, "Group name is not specified"), \
C(GROUP_TOO_LONG, "Group name is too long"), \
C(BAD_GROUP_NAME, "Group name must follow the same rules as C identifiers"), \
--
2.43.0
^ permalink raw reply related
* [PATCH v5 3/3] selftests/ftrace: Add accept cases for fprobe list syntax
From: Seokwoo Chung (Ryan) @ 2026-01-14 22:13 UTC (permalink / raw)
To: rostedt, mhiramat, corbet, shuah
Cc: mathieu.desnoyers, linux-kernel, linux-trace-kernel, linux-doc,
linux-kselftest, Seokwoo Chung (Ryan)
In-Reply-To: <20260114221341.128038-1-seokwoo.chung130@gmail.com>
Signed-off-by: Seokwoo Chung (Ryan) <seokwoo.chung130@gmail.com>
---
tools/testing/selftests/ftrace/test.d/dynevent/fprobe_list.tc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/testing/selftests/ftrace/test.d/dynevent/fprobe_list.tc b/tools/testing/selftests/ftrace/test.d/dynevent/fprobe_list.tc
index 45e57c6f487d..79392e268929 100644
--- a/tools/testing/selftests/ftrace/test.d/dynevent/fprobe_list.tc
+++ b/tools/testing/selftests/ftrace/test.d/dynevent/fprobe_list.tc
@@ -1,7 +1,7 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# description: Fprobe event list syntax and :entry/:exit suffixes
-# requires: dynamic_events "f[:[<group>/][<event>]] <func-name>[:entry|:exit] [<args>]":README
+# requires: dynamic_events "f[:[<group>/][<event>]] <func-list>[:entry|:exit] [<args>]":README
# Setup symbols to test. These are common kernel functions.
PLACE=vfs_read
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v2 1/1] mm: Fix OOM killer inaccuracy on large many-core systems
From: Baolin Wang @ 2026-01-15 1:40 UTC (permalink / raw)
To: Mathieu Desnoyers, Andrew Morton
Cc: linux-kernel, Michal Hocko, Paul E. McKenney, Steven Rostedt,
Masami Hiramatsu, Dennis Zhou, Tejun Heo, Christoph Lameter,
Martin Liu, David Rientjes, christian.koenig, Shakeel Butt,
SeongJae Park, Johannes Weiner, Sweet Tea Dorminy,
Lorenzo Stoakes, Liam R . Howlett, Mike Rapoport,
Suren Baghdasaryan, Vlastimil Babka, Christian Brauner, Wei Yang,
David Hildenbrand, Miaohe Lin, Al Viro, linux-mm, stable,
linux-trace-kernel, Yu Zhao, Roman Gushchin, Mateusz Guzik,
Matthew Wilcox, Aboorva Devarajan
In-Reply-To: <20260114143642.47333-1-mathieu.desnoyers@efficios.com>
On 1/14/26 10:36 PM, Mathieu Desnoyers wrote:
> Use the precise, albeit slower, precise RSS counter sums for the OOM
> killer task selection and console dumps. The approximated value is
> too imprecise on large many-core systems.
>
> The following rss tracking issues were noted by Sweet Tea Dorminy [1],
> which lead to picking wrong tasks as OOM kill target:
>
> Recently, several internal services had an RSS usage regression as part of a
> kernel upgrade. Previously, they were on a pre-6.2 kernel and were able to
> read RSS statistics in a backup watchdog process to monitor and decide if
> they'd overrun their memory budget. Now, however, a representative service
> with five threads, expected to use about a hundred MB of memory, on a 250-cpu
> machine had memory usage tens of megabytes different from the expected amount
> -- this constituted a significant percentage of inaccuracy, causing the
> watchdog to act.
>
> This was a result of commit f1a7941243c1 ("mm: convert mm's rss stats
> into percpu_counter") [1]. Previously, the memory error was bounded by
> 64*nr_threads pages, a very livable megabyte. Now, however, as a result of
> scheduler decisions moving the threads around the CPUs, the memory error could
> be as large as a gigabyte.
>
> This is a really tremendous inaccuracy for any few-threaded program on a
> large machine and impedes monitoring significantly. These stat counters are
> also used to make OOM killing decisions, so this additional inaccuracy could
> make a big difference in OOM situations -- either resulting in the wrong
> process being killed, or in less memory being returned from an OOM-kill than
> expected.
>
> Here is a (possibly incomplete) list of the prior approaches that were
> used or proposed, along with their downside:
>
> 1) Per-thread rss tracking: large error on many-thread processes.
>
> 2) Per-CPU counters: up to 12% slower for short-lived processes and 9%
> increased system time in make test workloads [1]. Moreover, the
> inaccuracy increases with O(n^2) with the number of CPUs.
>
> 3) Per-NUMA-node counters: requires atomics on fast-path (overhead),
> error is high with systems that have lots of NUMA nodes (32 times
> the number of NUMA nodes).
>
> commit 82241a83cd15 ("mm: fix the inaccurate memory statistics issue for
> users") introduced get_mm_counter_sum() for precise proc memory status
> queries for some proc files.
>
> The simple fix proposed here is to do the precise per-cpu counters sum
> every time a counter value needs to be read. This applies to the OOM
> killer task selection, oom task console dumps (printk).
>
> This change increases the latency introduced when the OOM killer
> executes in favor of doing a more precise OOM target task selection.
> Effectively, the OOM killer iterates on all tasks, for all relevant page
> types, for which the precise sum iterates on all possible CPUs.
>
> As a reference, here is the execution time of the OOM killer
> before/after the change:
>
> AMD EPYC 9654 96-Core (2 sockets)
> Within a KVM, configured with 256 logical cpus.
>
> | before | after |
> ----------------------------------|----------|----------|
> nr_processes=40 | 0.3 ms | 0.5 ms |
> nr_processes=10000 | 3.0 ms | 80.0 ms |
>
> Suggested-by: Michal Hocko <mhocko@suse.com>
> Fixes: f1a7941243c1 ("mm: convert mm's rss stats into percpu_counter")
> Link: https://lore.kernel.org/lkml/20250331223516.7810-2-sweettea-kernel@dorminy.me/ # [1]
> Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: "Paul E. McKenney" <paulmck@kernel.org>
> Cc: Steven Rostedt <rostedt@goodmis.org>
> Cc: Masami Hiramatsu <mhiramat@kernel.org>
> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
> Cc: Dennis Zhou <dennis@kernel.org>
> Cc: Tejun Heo <tj@kernel.org>
> Cc: Christoph Lameter <cl@linux.com>
> Cc: Martin Liu <liumartin@google.com>
> Cc: David Rientjes <rientjes@google.com>
> Cc: christian.koenig@amd.com
> Cc: Shakeel Butt <shakeel.butt@linux.dev>
> Cc: SeongJae Park <sj@kernel.org>
> Cc: Michal Hocko <mhocko@suse.com>
> Cc: Johannes Weiner <hannes@cmpxchg.org>
> Cc: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
> Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
> Cc: "Liam R . Howlett" <liam.howlett@oracle.com>
> Cc: Mike Rapoport <rppt@kernel.org>
> Cc: Suren Baghdasaryan <surenb@google.com>
> Cc: Vlastimil Babka <vbabka@suse.cz>
> Cc: Christian Brauner <brauner@kernel.org>
> Cc: Wei Yang <richard.weiyang@gmail.com>
> Cc: David Hildenbrand <david@redhat.com>
> Cc: Miaohe Lin <linmiaohe@huawei.com>
> Cc: Al Viro <viro@zeniv.linux.org.uk>
> Cc: linux-mm@kvack.org
> Cc: stable@vger.kernel.org
> Cc: linux-trace-kernel@vger.kernel.org
> Cc: Yu Zhao <yuzhao@google.com>
> Cc: Roman Gushchin <roman.gushchin@linux.dev>
> Cc: Mateusz Guzik <mjguzik@gmail.com>
> Cc: Matthew Wilcox <willy@infradead.org>
> Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
> Cc: Aboorva Devarajan <aboorvad@linux.ibm.com>
> ---
> This patch replaces v1. It's aimed at mm-new.
>
> Changes since v1:
> - Only change the oom killer RSS values from approximated to precise
> sums. Do not change other RSS values users.
> ---
LGTM.
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
^ permalink raw reply
* [PATCH v3 0/1]
From: hongao @ 2026-01-15 2:38 UTC (permalink / raw)
To: mhiramat
Cc: hongao, naveen, anil.s.keshavamurthy, davem, linux-kernel,
linux-trace-kernel
In-Reply-To: <20260105135800.1f9f05ab5635e2ab85a2f2bd@kernel.org>
Hi Masami,
Thanks for the review and clarification.
As suggested, I dropped the reopt_unblocked_probes flag and simply retry
optimize_kprobe() from do_free_cleaned_kprobes() after the aggregator is
fully reverted. The stale comment in __disarm_kprobe() is also removed.
No new state is added to struct optimized_kprobe.
Changes since v2:
- reoptimize the sibling directly in do_free_cleaned_kprobes()
- no new fields in struct optimized_kprobe
- remove the obsolete TODO in __disarm_kprobe()
- Link to v2: https://lore.kernel.org/all/C5E6295166D4EDE9+20251210033321.2895692-1-hongao@uniontech.com/
Thanks,
Hongao
---
Hongao (1):
kprobes: retry blocked optprobe in do_free_cleaned_kprobes
kernel/kprobes.c | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
--
2.50.1
^ permalink raw reply
* [PATCH v3 1/1] kprobes: retry blocked optprobe in do_free_cleaned_kprobes
From: hongao @ 2026-01-15 2:38 UTC (permalink / raw)
To: mhiramat
Cc: hongao, naveen, anil.s.keshavamurthy, davem, linux-kernel,
linux-trace-kernel
In-Reply-To: <20260115023804.3951960-1-hongao@uniontech.com>
Once the aggrprobe is fully reverted in do_free_cleaned_kprobes(), retry
optimize_kprobe() on that sibling so it can return to OPTIMIZED.
Also remove the stale comment in __disarm_kprobe().
Signed-off-by: hongao <hongao@uniontech.com>
---
kernel/kprobes.c | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index ab8f9fc1f0d1..1bd84d3b4817 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -516,6 +516,7 @@ static LIST_HEAD(freeing_list);
static void kprobe_optimizer(struct work_struct *work);
static DECLARE_DELAYED_WORK(optimizing_work, kprobe_optimizer);
+static void optimize_kprobe(struct kprobe *p);
#define OPTIMIZE_DELAY 5
/*
@@ -593,6 +594,17 @@ static void do_free_cleaned_kprobes(void)
*/
continue;
}
+
+ /*
+ * The aggregator was holding back another probe while it sat on the
+ * unoptimizing/freeing lists. Now that the aggregator has been fully
+ * reverted we can safely retry the optimization of that sibling.
+ */
+
+ struct kprobe *_p = get_optimized_kprobe(op->kp.addr);
+ if (unlikely(_p))
+ optimize_kprobe(_p);
+
free_aggr_kprobe(&op->kp);
}
}
@@ -1002,12 +1014,6 @@ static void __disarm_kprobe(struct kprobe *p, bool reopt)
if (unlikely(_p) && reopt)
optimize_kprobe(_p);
}
- /*
- * TODO: Since unoptimization and real disarming will be done by
- * the worker thread, we can not check whether another probe are
- * unoptimized because of this probe here. It should be re-optimized
- * by the worker thread.
- */
}
#else /* !CONFIG_OPTPROBES */
--
2.50.1
^ permalink raw reply related
* Re: [PATCH v4 2/3] tracing/fprobe: Support comma-separated symbols and :entry/:exit
From: kernel test robot @ 2026-01-15 11:07 UTC (permalink / raw)
To: Seokwoo Chung (Ryan), rostedt, mhiramat, corbet, shuah
Cc: oe-kbuild-all, mathieu.desnoyers, linux-kernel,
linux-trace-kernel, linux-doc, linux-kselftest,
Seokwoo Chung (Ryan)
In-Reply-To: <20251126184110.72241-3-seokwoo.chung130@gmail.com>
Hi Seokwoo,
kernel test robot noticed the following build errors:
[auto build test ERROR on trace/for-next]
[also build test ERROR on linus/master v6.19-rc5 next-20260115]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Seokwoo-Chung-Ryan/docs-tracing-fprobe-Document-list-filters-and-entry-exit/20260115-101521
base: https://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace for-next
patch link: https://lore.kernel.org/r/20251126184110.72241-3-seokwoo.chung130%40gmail.com
patch subject: [PATCH v4 2/3] tracing/fprobe: Support comma-separated symbols and :entry/:exit
config: x86_64-rhel-9.4-ltp (https://download.01.org/0day-ci/archive/20260115/202601151839.tQFpt1nW-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260115/202601151839.tQFpt1nW-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202601151839.tQFpt1nW-lkp@intel.com/
All error/warnings (new ones prefixed by >>):
kernel/trace/trace_fprobe.c: In function 'parse_fprobe_spec':
>> kernel/trace/trace_fprobe.c:1282:12: error: invalid storage class for function 'trace_fprobe_create_internal'
1282 | static int trace_fprobe_create_internal(int argc, const char *argv[],
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> kernel/trace/trace_fprobe.c:1513:12: error: invalid storage class for function 'trace_fprobe_create_cb'
1513 | static int trace_fprobe_create_cb(int argc, const char *argv[])
| ^~~~~~~~~~~~~~~~~~~~~~
>> kernel/trace/trace_fprobe.c:1530:12: error: invalid storage class for function 'trace_fprobe_create'
1530 | static int trace_fprobe_create(const char *raw_command)
| ^~~~~~~~~~~~~~~~~~~
>> kernel/trace/trace_fprobe.c:1535:12: error: invalid storage class for function 'trace_fprobe_release'
1535 | static int trace_fprobe_release(struct dyn_event *ev)
| ^~~~~~~~~~~~~~~~~~~~
>> kernel/trace/trace_fprobe.c:1545:12: error: invalid storage class for function 'trace_fprobe_show'
1545 | static int trace_fprobe_show(struct seq_file *m, struct dyn_event *ev)
| ^~~~~~~~~~~~~~~~~
>> kernel/trace/trace_fprobe.c:1572:12: error: invalid storage class for function 'enable_trace_fprobe'
1572 | static int enable_trace_fprobe(struct trace_event_call *call,
| ^~~~~~~~~~~~~~~~~~~
>> kernel/trace/trace_fprobe.c:1608:12: error: invalid storage class for function 'disable_trace_fprobe'
1608 | static int disable_trace_fprobe(struct trace_event_call *call,
| ^~~~~~~~~~~~~~~~~~~~
>> kernel/trace/trace_fprobe.c:1653:12: error: invalid storage class for function 'fprobe_register'
1653 | static int fprobe_register(struct trace_event_call *event,
| ^~~~~~~~~~~~~~~
>> kernel/trace/trace_fprobe.c:1683:19: error: invalid storage class for function 'init_fprobe_trace_early'
1683 | static __init int init_fprobe_trace_early(void)
| ^~~~~~~~~~~~~~~~~~~~~~~
In file included from include/linux/fprobe.h:6,
from kernel/trace/trace_fprobe.c:8:
include/linux/compiler.h:284:51: error: initializer element is not constant
284 | __UNIQUE_ID(__PASTE(addressable_, sym)) = (void *)(uintptr_t)&sym;
| ^
include/linux/compiler.h:287:9: note: in expansion of macro '___ADDRESSABLE'
287 | ___ADDRESSABLE(sym, __section(".discard.addressable"))
| ^~~~~~~~~~~~~~
include/linux/init.h:251:9: note: in expansion of macro '__ADDRESSABLE'
251 | __ADDRESSABLE(fn)
| ^~~~~~~~~~~~~
include/linux/init.h:256:9: note: in expansion of macro '__define_initcall_stub'
256 | __define_initcall_stub(__stub, fn) \
| ^~~~~~~~~~~~~~~~~~~~~~
include/linux/init.h:269:9: note: in expansion of macro '____define_initcall'
269 | ____define_initcall(fn, \
| ^~~~~~~~~~~~~~~~~~~
include/linux/init.h:275:9: note: in expansion of macro '__unique_initcall'
275 | __unique_initcall(fn, id, __sec, __initcall_id(fn))
| ^~~~~~~~~~~~~~~~~
include/linux/init.h:277:35: note: in expansion of macro '___define_initcall'
277 | #define __define_initcall(fn, id) ___define_initcall(fn, id, .initcall##id)
| ^~~~~~~~~~~~~~~~~~
include/linux/init.h:295:41: note: in expansion of macro '__define_initcall'
295 | #define core_initcall(fn) __define_initcall(fn, 1)
| ^~~~~~~~~~~~~~~~~
kernel/trace/trace_fprobe.c:1702:1: note: in expansion of macro 'core_initcall'
1702 | core_initcall(init_fprobe_trace_early);
| ^~~~~~~~~~~~~
>> kernel/trace/trace_fprobe.c:1702:1: error: expected declaration or statement at end of input
kernel/trace/trace_fprobe.c: At top level:
>> kernel/trace/trace_fprobe.c:28:12: warning: 'trace_fprobe_create' used but never defined
28 | static int trace_fprobe_create(const char *raw_command);
| ^~~~~~~~~~~~~~~~~~~
>> kernel/trace/trace_fprobe.c:29:12: warning: 'trace_fprobe_show' used but never defined
29 | static int trace_fprobe_show(struct seq_file *m, struct dyn_event *ev);
| ^~~~~~~~~~~~~~~~~
>> kernel/trace/trace_fprobe.c:30:12: warning: 'trace_fprobe_release' used but never defined
30 | static int trace_fprobe_release(struct dyn_event *ev);
| ^~~~~~~~~~~~~~~~~~~~
>> kernel/trace/trace_fprobe.c:741:12: warning: 'fprobe_register' used but never defined
741 | static int fprobe_register(struct trace_event_call *event,
| ^~~~~~~~~~~~~~~
>> kernel/trace/trace_fprobe.c:1653:12: warning: 'fprobe_register' defined but not used [-Wunused-function]
1653 | static int fprobe_register(struct trace_event_call *event,
| ^~~~~~~~~~~~~~~
>> kernel/trace/trace_fprobe.c:1545:12: warning: 'trace_fprobe_show' defined but not used [-Wunused-function]
1545 | static int trace_fprobe_show(struct seq_file *m, struct dyn_event *ev)
| ^~~~~~~~~~~~~~~~~
>> kernel/trace/trace_fprobe.c:1535:12: warning: 'trace_fprobe_release' defined but not used [-Wunused-function]
1535 | static int trace_fprobe_release(struct dyn_event *ev)
| ^~~~~~~~~~~~~~~~~~~~
>> kernel/trace/trace_fprobe.c:1530:12: warning: 'trace_fprobe_create' defined but not used [-Wunused-function]
1530 | static int trace_fprobe_create(const char *raw_command)
| ^~~~~~~~~~~~~~~~~~~
vim +/trace_fprobe_create_internal +1282 kernel/trace/trace_fprobe.c
08c9306fc2e32b0 Masami Hiramatsu (Google 2023-08-23 1281)
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 @1282) static int trace_fprobe_create_internal(int argc, const char *argv[],
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1283) struct traceprobe_parse_context *ctx)
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1284) {
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1285) /*
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1286) * Argument syntax:
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1287) * - Add fentry probe:
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1288) * f[:[GRP/][EVENT]] [MOD:]KSYM [FETCHARGS]
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1289) * - Add fexit probe:
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1290) * f[N][:[GRP/][EVENT]] [MOD:]KSYM%return [FETCHARGS]
e2d0d7b2f42dcaf Masami Hiramatsu (Google 2023-06-06 1291) * - Add tracepoint probe:
e2d0d7b2f42dcaf Masami Hiramatsu (Google 2023-06-06 1292) * t[:[GRP/][EVENT]] TRACEPOINT [FETCHARGS]
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1293) *
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1294) * Fetch args:
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1295) * $retval : fetch return value
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1296) * $stack : fetch stack address
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1297) * $stackN : fetch Nth entry of stack (N:0-)
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1298) * $argN : fetch Nth argument (N:1-)
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1299) * $comm : fetch current task comm
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1300) * @ADDR : fetch memory at ADDR (ADDR should be in kernel)
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1301) * @SYM[+|-offs] : fetch memory at SYM +|- offs (SYM is a data symbol)
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1302) * Dereferencing memory fetch:
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1303) * +|-offs(ARG) : fetch memory at ARG +|- offs address.
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1304) * Alias name of args:
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1305) * NAME=FETCHARG : set NAME as alias of FETCHARG.
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1306) * Type of args:
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1307) * FETCHARG:TYPE : use TYPE instead of unsigned long.
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1308) */
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1309) struct trace_fprobe *tf __free(free_trace_fprobe) = NULL;
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1310) const char *event = NULL, *group = FPROBE_EVENT_SYSTEM;
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1311) struct module *mod __free(module_put) = NULL;
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1312) const char **new_argv __free(kfree) = NULL;
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1313) char *parsed_nofilter __free(kfree) = NULL;
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1314) char *parsed_filter __free(kfree) = NULL;
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1315) char *symbol __free(kfree) = NULL;
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1316) char *ebuf __free(kfree) = NULL;
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1317) char *gbuf __free(kfree) = NULL;
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1318) char *sbuf __free(kfree) = NULL;
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1319) char *abuf __free(kfree) = NULL;
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1320) char *dbuf __free(kfree) = NULL;
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1321) int i, new_argc = 0, ret = 0;
e2d0d7b2f42dcaf Masami Hiramatsu (Google 2023-06-06 1322) bool is_tracepoint = false;
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1323) bool list_mode = false;
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1324) bool is_return = false;
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1325)
e2d0d7b2f42dcaf Masami Hiramatsu (Google 2023-06-06 1326) if ((argv[0][0] != 'f' && argv[0][0] != 't') || argc < 2)
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1327) return -ECANCELED;
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1328)
e2d0d7b2f42dcaf Masami Hiramatsu (Google 2023-06-06 1329) if (argv[0][0] == 't') {
e2d0d7b2f42dcaf Masami Hiramatsu (Google 2023-06-06 1330) is_tracepoint = true;
e2d0d7b2f42dcaf Masami Hiramatsu (Google 2023-06-06 1331) group = TRACEPOINT_EVENT_SYSTEM;
e2d0d7b2f42dcaf Masami Hiramatsu (Google 2023-06-06 1332) }
e2d0d7b2f42dcaf Masami Hiramatsu (Google 2023-06-06 1333)
a2224559cbba1db Masami Hiramatsu (Google 2024-12-26 1334) if (argv[0][1] != '\0') {
a2224559cbba1db Masami Hiramatsu (Google 2024-12-26 1335) if (argv[0][1] != ':') {
a2224559cbba1db Masami Hiramatsu (Google 2024-12-26 1336) trace_probe_log_set_index(0);
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1337) trace_probe_log_err(1, BAD_MAXACT);
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1338) return -EINVAL;
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1339) }
a2224559cbba1db Masami Hiramatsu (Google 2024-12-26 1340) event = &argv[0][2];
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1341) }
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1342)
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1343) trace_probe_log_set_index(1);
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1344)
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1345) /* Parse spec early (single vs list, suffix, base symbol) */
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1346) ret = parse_fprobe_spec(argv[1], is_tracepoint, &symbol, &is_return,
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1347) &list_mode, &parsed_filter, &parsed_nofilter);
08c9306fc2e32b0 Masami Hiramatsu (Google 2023-08-23 1348) if (ret < 0)
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1349) return -EINVAL;
08c9306fc2e32b0 Masami Hiramatsu (Google 2023-08-23 1350)
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1351) for (i = 2; i < argc; i++) {
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1352) char *tmp = strstr(argv[i], "$retval");
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1353)
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1354) if (tmp && !isalnum(tmp[7]) && tmp[7] != '_') {
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1355) if (is_tracepoint) {
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1356) trace_probe_log_set_index(i);
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1357) trace_probe_log_err(tmp - argv[i], RETVAL_ON_PROBE);
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1358) return -EINVAL;
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1359) }
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1360) is_return = true;
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1361) break;
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1362) }
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1363) }
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1364)
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1365) trace_probe_log_set_index(0);
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1366) if (event) {
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1367) gbuf = kmalloc(MAX_EVENT_NAME_LEN, GFP_KERNEL);
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1368) if (!gbuf)
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1369) return -ENOMEM;
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1370) ret = traceprobe_parse_event_name(&event, &group, gbuf,
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1371) event - argv[0]);
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1372) if (ret)
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1373) return -EINVAL;
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1374) }
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1375)
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1376) if (!event) {
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1377) /*
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1378) * Event name rules:
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1379) * - For list/wildcard: require explicit [GROUP/]EVENT
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1380) * - For single literal: autogenerate symbol__entry/symbol__exit
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1381) */
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1382) if (list_mode || has_wildcard(symbol)) {
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1383) trace_probe_log_err(0, NO_GROUP_NAME);
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1384) return -EINVAL;
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1385) }
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1386) ebuf = kmalloc(MAX_EVENT_NAME_LEN, GFP_KERNEL);
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1387) if (!ebuf)
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1388) return -ENOMEM;
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1389) /* Make a new event name */
e2d0d7b2f42dcaf Masami Hiramatsu (Google 2023-06-06 1390) if (is_tracepoint)
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1391) snprintf(ebuf, MAX_EVENT_NAME_LEN, "%s%s",
b576e09701c7d04 Masami Hiramatsu (Google 2023-06-06 1392) isdigit(*symbol) ? "_" : "", symbol);
e2d0d7b2f42dcaf Masami Hiramatsu (Google 2023-06-06 1393) else
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1394) snprintf(ebuf, MAX_EVENT_NAME_LEN, "%s__%s", symbol,
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1395) is_return ? "exit" : "entry");
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1396) sanitize_event_name(ebuf);
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1397) event = ebuf;
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1398) }
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1399)
b576e09701c7d04 Masami Hiramatsu (Google 2023-06-06 1400) if (is_return)
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1401) ctx->flags |= TPARG_FL_RETURN;
b576e09701c7d04 Masami Hiramatsu (Google 2023-06-06 1402) else
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1403) ctx->flags |= TPARG_FL_FENTRY;
b576e09701c7d04 Masami Hiramatsu (Google 2023-06-06 1404)
2867495dea86324 Masami Hiramatsu (Google 2025-04-01 1405) ctx->funcname = NULL;
b576e09701c7d04 Masami Hiramatsu (Google 2023-06-06 1406) if (is_tracepoint) {
2867495dea86324 Masami Hiramatsu (Google 2025-04-01 1407) /* Get tracepoint and lock its module until the end of the registration. */
2867495dea86324 Masami Hiramatsu (Google 2025-04-01 1408) struct tracepoint *tpoint;
2867495dea86324 Masami Hiramatsu (Google 2025-04-01 1409)
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1410) ctx->flags |= TPARG_FL_TPOINT;
2867495dea86324 Masami Hiramatsu (Google 2025-04-01 1411) mod = NULL;
2867495dea86324 Masami Hiramatsu (Google 2025-04-01 1412) tpoint = find_tracepoint(symbol, &mod);
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1413) if (tpoint) {
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1414) sbuf = kmalloc(KSYM_NAME_LEN, GFP_KERNEL);
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1415) if (!sbuf)
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1416) return -ENOMEM;
2867495dea86324 Masami Hiramatsu (Google 2025-04-01 1417) ctx->funcname = kallsyms_lookup((unsigned long)tpoint->probestub,
2867495dea86324 Masami Hiramatsu (Google 2025-04-01 1418) NULL, NULL, NULL, sbuf);
b576e09701c7d04 Masami Hiramatsu (Google 2023-06-06 1419) }
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1420) }
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1421)
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1422) if (!list_mode && !has_wildcard(symbol) && !is_tracepoint)
e3d6e1b9a34c745 Masami Hiramatsu (Google 2025-04-01 1423) ctx->funcname = symbol;
b576e09701c7d04 Masami Hiramatsu (Google 2023-06-06 1424)
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1425) abuf = kmalloc(MAX_BTF_ARGS_LEN, GFP_KERNEL);
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1426) if (!abuf)
d643eaa7082dc3d Masami Hiramatsu (Google 2025-07-23 1427) return -ENOMEM;
18b1e870a496717 Masami Hiramatsu (Google 2023-06-06 1428) argc -= 2; argv += 2;
18b1e870a496717 Masami Hiramatsu (Google 2023-06-06 1429) new_argv = traceprobe_expand_meta_args(argc, argv, &new_argc,
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1430) abuf, MAX_BTF_ARGS_LEN, ctx);
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1431) if (IS_ERR(new_argv))
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1432) return PTR_ERR(new_argv);
18b1e870a496717 Masami Hiramatsu (Google 2023-06-06 1433) if (new_argv) {
18b1e870a496717 Masami Hiramatsu (Google 2023-06-06 1434) argc = new_argc;
18b1e870a496717 Masami Hiramatsu (Google 2023-06-06 1435) argv = new_argv;
18b1e870a496717 Masami Hiramatsu (Google 2023-06-06 1436) }
57faaa04804ccbf Masami Hiramatsu (Google 2025-03-27 1437) if (argc > MAX_TRACE_ARGS) {
57faaa04804ccbf Masami Hiramatsu (Google 2025-03-27 1438) trace_probe_log_set_index(2);
57faaa04804ccbf Masami Hiramatsu (Google 2025-03-27 1439) trace_probe_log_err(0, TOO_MANY_ARGS);
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1440) return -E2BIG;
57faaa04804ccbf Masami Hiramatsu (Google 2025-03-27 1441) }
18b1e870a496717 Masami Hiramatsu (Google 2023-06-06 1442)
d9b15224dd8ff83 Ye Bin 2024-03-22 1443 ret = traceprobe_expand_dentry_args(argc, argv, &dbuf);
d9b15224dd8ff83 Ye Bin 2024-03-22 1444 if (ret)
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1445) return ret;
d9b15224dd8ff83 Ye Bin 2024-03-22 1446
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1447) /* setup a probe */
2867495dea86324 Masami Hiramatsu (Google 2025-04-01 1448) tf = alloc_trace_fprobe(group, event, symbol, argc, is_return, is_tracepoint);
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1449) if (IS_ERR(tf)) {
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1450) ret = PTR_ERR(tf);
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1451) /* This must return -ENOMEM, else there is a bug */
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1452) WARN_ON_ONCE(ret != -ENOMEM);
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1453) return ret;
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1454) }
e2d0d7b2f42dcaf Masami Hiramatsu (Google 2023-06-06 1455)
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1456) /* carry list parsing result into tf */
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1457) if (!is_tracepoint) {
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1458) tf->list_mode = list_mode;
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1459) if (parsed_filter) {
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1460) tf->filter = kstrdup(parsed_filter, GFP_KERNEL);
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1461) if (!tf->filter)
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1462) return -ENOMEM;
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1463) }
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1464) if (parsed_nofilter) {
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1465) tf->nofilter = kstrdup(parsed_nofilter, GFP_KERNEL);
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1466) if (!tf->nofilter)
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1467) return -ENOMEM;
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1468) }
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1469) }
6589e7661d349c0 Seokwoo Chung (Ryan 2025-11-26 1470)
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1471) /* parse arguments */
73f35080477e893 Mikel Rychliski 2024-09-30 1472 for (i = 0; i < argc; i++) {
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1473) trace_probe_log_set_index(i + 2);
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1474) ctx->offset = 0;
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1475) ret = traceprobe_parse_probe_arg(&tf->tp, i, argv[i], ctx);
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1476) if (ret)
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1477) return ret; /* This can be -ENOMEM */
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1478) }
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1479)
25f00e40ce7953d Masami Hiramatsu (Google 2024-03-04 1480) if (is_return && tf->tp.entry_arg) {
25f00e40ce7953d Masami Hiramatsu (Google 2024-03-04 1481) tf->fp.entry_handler = trace_fprobe_entry_handler;
25f00e40ce7953d Masami Hiramatsu (Google 2024-03-04 1482) tf->fp.entry_data_size = traceprobe_get_entry_data_size(&tf->tp);
db5e228611b118c Masami Hiramatsu (Google 2025-02-26 1483) if (ALIGN(tf->fp.entry_data_size, sizeof(long)) > MAX_FPROBE_DATA_SIZE) {
db5e228611b118c Masami Hiramatsu (Google 2025-02-26 1484) trace_probe_log_set_index(2);
db5e228611b118c Masami Hiramatsu (Google 2025-02-26 1485) trace_probe_log_err(0, TOO_MANY_EARGS);
db5e228611b118c Masami Hiramatsu (Google 2025-02-26 1486) return -E2BIG;
db5e228611b118c Masami Hiramatsu (Google 2025-02-26 1487) }
25f00e40ce7953d Masami Hiramatsu (Google 2024-03-04 1488) }
25f00e40ce7953d Masami Hiramatsu (Google 2024-03-04 1489)
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1490) ret = traceprobe_set_print_fmt(&tf->tp,
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1491) is_return ? PROBE_PRINT_RETURN : PROBE_PRINT_NORMAL);
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1492) if (ret < 0)
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1493) return ret;
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1494)
2db832ec9090d3b Masami Hiramatsu (Google 2025-04-01 1495) ret = register_trace_fprobe_event(tf);
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1496) if (ret) {
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1497) trace_probe_log_set_index(1);
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1498) if (ret == -EILSEQ)
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1499) trace_probe_log_err(0, BAD_INSN_BNDRY);
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1500) else if (ret == -ENOENT)
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1501) trace_probe_log_err(0, BAD_PROBE_ADDR);
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1502) else if (ret != -ENOMEM && ret != -EEXIST)
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1503) trace_probe_log_err(0, FAIL_REG_PROBE);
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1504) return -EINVAL;
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1505) }
334e5519c375701 Masami Hiramatsu (Google 2023-06-06 1506)
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1507) /* 'tf' is successfully registered. To avoid freeing, assign NULL. */
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1508) tf = NULL;
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1509)
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1510) return 0;
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1511) }
8275637215bd3d4 Masami Hiramatsu (Google 2025-01-17 1512)
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [RFC PATCH v1 05/37] KVM: guest_memfd: Wire up kvm_get_memory_attributes() to per-gmem attributes
From: Alexey Kardashevskiy @ 2026-01-15 11:08 UTC (permalink / raw)
To: Ackerley Tng, cgroups, kvm, linux-doc, linux-fsdevel,
linux-kernel, linux-kselftest, linux-mm, linux-trace-kernel, x86
Cc: akpm, binbin.wu, bp, brauner, chao.p.peng, chenhuacai, corbet,
dave.hansen, dave.hansen, david, dmatlack, erdemaktas, fan.du,
fvdl, haibo1.xu, hannes, hch, hpa, hughd, ira.weiny,
isaku.yamahata, jack, james.morse, jarkko, jgg, jgowans, jhubbard,
jroedel, jthoughton, jun.miao, kai.huang, keirf, kent.overstreet,
liam.merwick, maciej.wieczor-retman, mail, maobibo,
mathieu.desnoyers, maz, mhiramat, mhocko, mic, michael.roth,
mingo, mlevitsk, mpe, muchun.song, nikunj, nsaenz, oliver.upton,
palmer, pankaj.gupta, paul.walmsley, pbonzini, peterx, pgonda,
prsampat, pvorel, qperret, richard.weiyang, rick.p.edgecombe,
rientjes, rostedt, roypat, rppt, seanjc, shakeel.butt, shuah,
steven.price, steven.sistare, suzuki.poulose, tabba, tglx,
thomas.lendacky, vannapurve, vbabka, viro, vkuznets, wei.w.wang,
will, willy, wyihan, xiaoyao.li, yan.y.zhao, yilun.xu, yuzenghui,
zhiquan1.li
In-Reply-To: <071a3c6603809186e914fe5fed939edee4e11988.1760731772.git.ackerleytng@google.com>
On 18/10/25 07:11, Ackerley Tng wrote:
> From: Sean Christopherson <seanjc@google.com>
>
> Implement kvm_gmem_get_memory_attributes() for guest_memfd to allow the KVM
> core and architecture code to query per-GFN memory attributes.
>
> kvm_gmem_get_memory_attributes() finds the memory slot for a given GFN and
> queries the guest_memfd file's to determine if the page is marked as
> private.
>
> If vm_memory_attributes is not enabled, there is no shared/private tracking
> at the VM level. Install the guest_memfd implementation as long as
> guest_memfd is enabled to give guest_memfd a chance to respond on
> attributes.
>
> guest_memfd should look up attributes regardless of whether this memslot is
> gmem-only since attributes are now tracked by gmem regardless of whether
> mmap() is enabled.
>
> Signed-off-by: Sean Christopherson <seanjc@google.com>
> Co-developed-by: Ackerley Tng <ackerleytng@google.com>
> Signed-off-by: Ackerley Tng <ackerleytng@google.com>
> ---
> include/linux/kvm_host.h | 2 ++
> virt/kvm/guest_memfd.c | 29 +++++++++++++++++++++++++++++
> virt/kvm/kvm_main.c | 3 +++
> 3 files changed, 34 insertions(+)
>
> diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
> index 512febf47c265..b8418cc5851f1 100644
> --- a/include/linux/kvm_host.h
> +++ b/include/linux/kvm_host.h
> @@ -2543,6 +2543,8 @@ bool kvm_arch_post_set_memory_attributes(struct kvm *kvm,
> struct kvm_gfn_range *range);
> #endif /* CONFIG_KVM_VM_MEMORY_ATTRIBUTES */
>
> +unsigned long kvm_gmem_get_memory_attributes(struct kvm *kvm, gfn_t gfn);
> +
> #ifdef CONFIG_KVM_GUEST_MEMFD
> int kvm_gmem_get_pfn(struct kvm *kvm, struct kvm_memory_slot *slot,
> gfn_t gfn, kvm_pfn_t *pfn, struct page **page,
> diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c
> index 26cec833766c3..f62facc3ab776 100644
> --- a/virt/kvm/guest_memfd.c
> +++ b/virt/kvm/guest_memfd.c
> @@ -518,6 +518,35 @@ static int kvm_gmem_mmap(struct file *file, struct vm_area_struct *vma)
> return 0;
> }
>
> +unsigned long kvm_gmem_get_memory_attributes(struct kvm *kvm, gfn_t gfn)
> +{
> + struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn);
> +
> + /*
> + * If this gfn has no associated memslot, there's no chance of the gfn
> + * being backed by private memory, since guest_memfd must be used for
> + * private memory, and guest_memfd must be associated with some memslot.
> + */
> + if (!slot)
> + return 0;
> +
> + CLASS(gmem_get_file, file)(slot);
> + if (!file)
> + return false;
> +
> + /*
> + * Don't take the filemap invalidation lock, as temporarily acquiring
> + * that lock wouldn't provide any meaningful protection. The caller
> + * _must_ protect consumption of private vs. shared by checking
> + * mmu_invalidate_retry_gfn() under mmu_lock.
> + */
> + guard(rcu)();
> +
> + return kvm_gmem_get_attributes(file_inode(file),
> + kvm_gmem_get_index(slot, gfn));
> +}
> +EXPORT_SYMBOL_GPL(kvm_gmem_get_memory_attributes);
> +
> static struct file_operations kvm_gmem_fops = {
> .mmap = kvm_gmem_mmap,
> .open = generic_file_open,
> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> index 6c29770dfa7c8..c73ebdb73070e 100644
> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
> @@ -2660,6 +2660,9 @@ static void kvm_init_memory_attributes(void)
> if (vm_memory_attributes)
> static_call_update(__kvm_get_memory_attributes,
> kvm_get_vm_memory_attributes);
> + else if (IS_ENABLED(CONFIG_KVM_GUEST_MEMFD))
> + static_call_update(__kvm_get_memory_attributes,
> + kvm_gmem_get_memory_attributes);
> else
> static_call_update(__kvm_get_memory_attributes,
> (void *)__static_call_return0);
I am trying to make it work with TEE-IO where fd of VFIO MMIO is a dmabuf fd while the rest (guest RAM) is gmemfd. The above suggests that if there is gmemfd - then the memory attributes are handled by gmemfd which is... expected?
The problem at hand is that kvm_mmu_faultin_pfn() fails at "if (fault->is_private != kvm_mem_is_private(kvm, fault->gfn))" and marking MMIO as private using kvm_vm_ioctl_set_mem_attributes() does not work as kvm_gmem_get_memory_attributes() fails on dmabuf fds.
I worked around this like below but wonder what is the proper way? Thanks,
@@ -768,13 +768,13 @@ unsigned long kvm_gmem_get_memory_attributes(struct kvm *kvm, gfn_t gfn)
*/
if (!slot)
return 0;
CLASS(gmem_get_file, file)(slot);
if (!file)
- return false;
+ return kvm_get_vm_memory_attributes(kvm, gfn);
/*
* Don't take the filemap invalidation lock, as temporarily acquiring
* that lock wouldn't provide any meaningful protection. The caller
* _must_ protect consumption of private vs. shared by checking
* mmu_invalidate_retry_gfn() under mmu_lock.
--
Alexey
^ permalink raw reply
* Re: [PATCH v4 2/3] tracing/fprobe: Support comma-separated symbols and :entry/:exit
From: kernel test robot @ 2026-01-15 11:17 UTC (permalink / raw)
To: Seokwoo Chung (Ryan), rostedt, mhiramat, corbet, shuah
Cc: llvm, oe-kbuild-all, mathieu.desnoyers, linux-kernel,
linux-trace-kernel, linux-doc, linux-kselftest,
Seokwoo Chung (Ryan)
In-Reply-To: <20251126184110.72241-3-seokwoo.chung130@gmail.com>
Hi Seokwoo,
kernel test robot noticed the following build errors:
[auto build test ERROR on trace/for-next]
[also build test ERROR on linus/master v6.19-rc5 next-20260115]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Seokwoo-Chung-Ryan/docs-tracing-fprobe-Document-list-filters-and-entry-exit/20260115-101521
base: https://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace for-next
patch link: https://lore.kernel.org/r/20251126184110.72241-3-seokwoo.chung130%40gmail.com
patch subject: [PATCH v4 2/3] tracing/fprobe: Support comma-separated symbols and :entry/:exit
config: x86_64-rhel-9.4-rust (https://download.01.org/0day-ci/archive/20260115/202601151807.J0B7Qsch-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
rustc: rustc 1.88.0 (6b00bc388 2025-06-23)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260115/202601151807.J0B7Qsch-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202601151807.J0B7Qsch-lkp@intel.com/
All errors (new ones prefixed by >>):
>> kernel/trace/trace_fprobe.c:1284:1: error: function definition is not allowed here
1284 | {
| ^
kernel/trace/trace_fprobe.c:1514:1: error: function definition is not allowed here
1514 | {
| ^
kernel/trace/trace_fprobe.c:1531:1: error: function definition is not allowed here
1531 | {
| ^
kernel/trace/trace_fprobe.c:1536:1: error: function definition is not allowed here
1536 | {
| ^
kernel/trace/trace_fprobe.c:1546:1: error: function definition is not allowed here
1546 | {
| ^
kernel/trace/trace_fprobe.c:1574:1: error: function definition is not allowed here
1574 | {
| ^
kernel/trace/trace_fprobe.c:1610:1: error: function definition is not allowed here
1610 | {
| ^
kernel/trace/trace_fprobe.c:1655:1: error: function definition is not allowed here
1655 | {
| ^
kernel/trace/trace_fprobe.c:1684:1: error: function definition is not allowed here
1684 | {
| ^
>> kernel/trace/trace_fprobe.c:1702:15: error: use of undeclared identifier 'init_fprobe_trace_early'
1702 | core_initcall(init_fprobe_trace_early);
| ^
>> kernel/trace/trace_fprobe.c:1702:15: error: use of undeclared identifier 'init_fprobe_trace_early'
>> kernel/trace/trace_fprobe.c:1702:40: error: expected '}'
1702 | core_initcall(init_fprobe_trace_early);
| ^
kernel/trace/trace_fprobe.c:1175:1: note: to match this '{'
1175 | {
| ^
12 errors generated.
vim +1284 kernel/trace/trace_fprobe.c
08c9306fc2e32b Masami Hiramatsu (Google 2023-08-23 1281)
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1282) static int trace_fprobe_create_internal(int argc, const char *argv[],
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1283) struct traceprobe_parse_context *ctx)
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 @1284) {
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1285) /*
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1286) * Argument syntax:
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1287) * - Add fentry probe:
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1288) * f[:[GRP/][EVENT]] [MOD:]KSYM [FETCHARGS]
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1289) * - Add fexit probe:
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1290) * f[N][:[GRP/][EVENT]] [MOD:]KSYM%return [FETCHARGS]
e2d0d7b2f42dca Masami Hiramatsu (Google 2023-06-06 1291) * - Add tracepoint probe:
e2d0d7b2f42dca Masami Hiramatsu (Google 2023-06-06 1292) * t[:[GRP/][EVENT]] TRACEPOINT [FETCHARGS]
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1293) *
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1294) * Fetch args:
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1295) * $retval : fetch return value
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1296) * $stack : fetch stack address
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1297) * $stackN : fetch Nth entry of stack (N:0-)
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1298) * $argN : fetch Nth argument (N:1-)
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1299) * $comm : fetch current task comm
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1300) * @ADDR : fetch memory at ADDR (ADDR should be in kernel)
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1301) * @SYM[+|-offs] : fetch memory at SYM +|- offs (SYM is a data symbol)
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1302) * Dereferencing memory fetch:
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1303) * +|-offs(ARG) : fetch memory at ARG +|- offs address.
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1304) * Alias name of args:
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1305) * NAME=FETCHARG : set NAME as alias of FETCHARG.
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1306) * Type of args:
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1307) * FETCHARG:TYPE : use TYPE instead of unsigned long.
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1308) */
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1309) struct trace_fprobe *tf __free(free_trace_fprobe) = NULL;
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1310) const char *event = NULL, *group = FPROBE_EVENT_SYSTEM;
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1311) struct module *mod __free(module_put) = NULL;
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1312) const char **new_argv __free(kfree) = NULL;
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1313) char *parsed_nofilter __free(kfree) = NULL;
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1314) char *parsed_filter __free(kfree) = NULL;
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1315) char *symbol __free(kfree) = NULL;
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1316) char *ebuf __free(kfree) = NULL;
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1317) char *gbuf __free(kfree) = NULL;
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1318) char *sbuf __free(kfree) = NULL;
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1319) char *abuf __free(kfree) = NULL;
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1320) char *dbuf __free(kfree) = NULL;
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1321) int i, new_argc = 0, ret = 0;
e2d0d7b2f42dca Masami Hiramatsu (Google 2023-06-06 1322) bool is_tracepoint = false;
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1323) bool list_mode = false;
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1324) bool is_return = false;
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1325)
e2d0d7b2f42dca Masami Hiramatsu (Google 2023-06-06 1326) if ((argv[0][0] != 'f' && argv[0][0] != 't') || argc < 2)
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1327) return -ECANCELED;
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1328)
e2d0d7b2f42dca Masami Hiramatsu (Google 2023-06-06 1329) if (argv[0][0] == 't') {
e2d0d7b2f42dca Masami Hiramatsu (Google 2023-06-06 1330) is_tracepoint = true;
e2d0d7b2f42dca Masami Hiramatsu (Google 2023-06-06 1331) group = TRACEPOINT_EVENT_SYSTEM;
e2d0d7b2f42dca Masami Hiramatsu (Google 2023-06-06 1332) }
e2d0d7b2f42dca Masami Hiramatsu (Google 2023-06-06 1333)
a2224559cbba1d Masami Hiramatsu (Google 2024-12-26 1334) if (argv[0][1] != '\0') {
a2224559cbba1d Masami Hiramatsu (Google 2024-12-26 1335) if (argv[0][1] != ':') {
a2224559cbba1d Masami Hiramatsu (Google 2024-12-26 1336) trace_probe_log_set_index(0);
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1337) trace_probe_log_err(1, BAD_MAXACT);
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1338) return -EINVAL;
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1339) }
a2224559cbba1d Masami Hiramatsu (Google 2024-12-26 1340) event = &argv[0][2];
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1341) }
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1342)
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1343) trace_probe_log_set_index(1);
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1344)
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1345) /* Parse spec early (single vs list, suffix, base symbol) */
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1346) ret = parse_fprobe_spec(argv[1], is_tracepoint, &symbol, &is_return,
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1347) &list_mode, &parsed_filter, &parsed_nofilter);
08c9306fc2e32b Masami Hiramatsu (Google 2023-08-23 1348) if (ret < 0)
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1349) return -EINVAL;
08c9306fc2e32b Masami Hiramatsu (Google 2023-08-23 1350)
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1351) for (i = 2; i < argc; i++) {
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1352) char *tmp = strstr(argv[i], "$retval");
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1353)
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1354) if (tmp && !isalnum(tmp[7]) && tmp[7] != '_') {
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1355) if (is_tracepoint) {
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1356) trace_probe_log_set_index(i);
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1357) trace_probe_log_err(tmp - argv[i], RETVAL_ON_PROBE);
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1358) return -EINVAL;
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1359) }
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1360) is_return = true;
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1361) break;
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1362) }
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1363) }
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1364)
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1365) trace_probe_log_set_index(0);
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1366) if (event) {
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1367) gbuf = kmalloc(MAX_EVENT_NAME_LEN, GFP_KERNEL);
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1368) if (!gbuf)
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1369) return -ENOMEM;
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1370) ret = traceprobe_parse_event_name(&event, &group, gbuf,
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1371) event - argv[0]);
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1372) if (ret)
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1373) return -EINVAL;
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1374) }
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1375)
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1376) if (!event) {
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1377) /*
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1378) * Event name rules:
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1379) * - For list/wildcard: require explicit [GROUP/]EVENT
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1380) * - For single literal: autogenerate symbol__entry/symbol__exit
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1381) */
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1382) if (list_mode || has_wildcard(symbol)) {
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1383) trace_probe_log_err(0, NO_GROUP_NAME);
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1384) return -EINVAL;
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1385) }
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1386) ebuf = kmalloc(MAX_EVENT_NAME_LEN, GFP_KERNEL);
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1387) if (!ebuf)
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1388) return -ENOMEM;
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1389) /* Make a new event name */
e2d0d7b2f42dca Masami Hiramatsu (Google 2023-06-06 1390) if (is_tracepoint)
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1391) snprintf(ebuf, MAX_EVENT_NAME_LEN, "%s%s",
b576e09701c7d0 Masami Hiramatsu (Google 2023-06-06 1392) isdigit(*symbol) ? "_" : "", symbol);
e2d0d7b2f42dca Masami Hiramatsu (Google 2023-06-06 1393) else
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1394) snprintf(ebuf, MAX_EVENT_NAME_LEN, "%s__%s", symbol,
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1395) is_return ? "exit" : "entry");
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1396) sanitize_event_name(ebuf);
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1397) event = ebuf;
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1398) }
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1399)
b576e09701c7d0 Masami Hiramatsu (Google 2023-06-06 1400) if (is_return)
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1401) ctx->flags |= TPARG_FL_RETURN;
b576e09701c7d0 Masami Hiramatsu (Google 2023-06-06 1402) else
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1403) ctx->flags |= TPARG_FL_FENTRY;
b576e09701c7d0 Masami Hiramatsu (Google 2023-06-06 1404)
2867495dea8632 Masami Hiramatsu (Google 2025-04-01 1405) ctx->funcname = NULL;
b576e09701c7d0 Masami Hiramatsu (Google 2023-06-06 1406) if (is_tracepoint) {
2867495dea8632 Masami Hiramatsu (Google 2025-04-01 1407) /* Get tracepoint and lock its module until the end of the registration. */
2867495dea8632 Masami Hiramatsu (Google 2025-04-01 1408) struct tracepoint *tpoint;
2867495dea8632 Masami Hiramatsu (Google 2025-04-01 1409)
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1410) ctx->flags |= TPARG_FL_TPOINT;
2867495dea8632 Masami Hiramatsu (Google 2025-04-01 1411) mod = NULL;
2867495dea8632 Masami Hiramatsu (Google 2025-04-01 1412) tpoint = find_tracepoint(symbol, &mod);
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1413) if (tpoint) {
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1414) sbuf = kmalloc(KSYM_NAME_LEN, GFP_KERNEL);
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1415) if (!sbuf)
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1416) return -ENOMEM;
2867495dea8632 Masami Hiramatsu (Google 2025-04-01 1417) ctx->funcname = kallsyms_lookup((unsigned long)tpoint->probestub,
2867495dea8632 Masami Hiramatsu (Google 2025-04-01 1418) NULL, NULL, NULL, sbuf);
b576e09701c7d0 Masami Hiramatsu (Google 2023-06-06 1419) }
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1420) }
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1421)
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1422) if (!list_mode && !has_wildcard(symbol) && !is_tracepoint)
e3d6e1b9a34c74 Masami Hiramatsu (Google 2025-04-01 1423) ctx->funcname = symbol;
b576e09701c7d0 Masami Hiramatsu (Google 2023-06-06 1424)
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1425) abuf = kmalloc(MAX_BTF_ARGS_LEN, GFP_KERNEL);
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1426) if (!abuf)
d643eaa7082dc3 Masami Hiramatsu (Google 2025-07-23 1427) return -ENOMEM;
18b1e870a49671 Masami Hiramatsu (Google 2023-06-06 1428) argc -= 2; argv += 2;
18b1e870a49671 Masami Hiramatsu (Google 2023-06-06 1429) new_argv = traceprobe_expand_meta_args(argc, argv, &new_argc,
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1430) abuf, MAX_BTF_ARGS_LEN, ctx);
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1431) if (IS_ERR(new_argv))
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1432) return PTR_ERR(new_argv);
18b1e870a49671 Masami Hiramatsu (Google 2023-06-06 1433) if (new_argv) {
18b1e870a49671 Masami Hiramatsu (Google 2023-06-06 1434) argc = new_argc;
18b1e870a49671 Masami Hiramatsu (Google 2023-06-06 1435) argv = new_argv;
18b1e870a49671 Masami Hiramatsu (Google 2023-06-06 1436) }
57faaa04804ccb Masami Hiramatsu (Google 2025-03-27 1437) if (argc > MAX_TRACE_ARGS) {
57faaa04804ccb Masami Hiramatsu (Google 2025-03-27 1438) trace_probe_log_set_index(2);
57faaa04804ccb Masami Hiramatsu (Google 2025-03-27 1439) trace_probe_log_err(0, TOO_MANY_ARGS);
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1440) return -E2BIG;
57faaa04804ccb Masami Hiramatsu (Google 2025-03-27 1441) }
18b1e870a49671 Masami Hiramatsu (Google 2023-06-06 1442)
d9b15224dd8ff8 Ye Bin 2024-03-22 1443 ret = traceprobe_expand_dentry_args(argc, argv, &dbuf);
d9b15224dd8ff8 Ye Bin 2024-03-22 1444 if (ret)
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1445) return ret;
d9b15224dd8ff8 Ye Bin 2024-03-22 1446
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1447) /* setup a probe */
2867495dea8632 Masami Hiramatsu (Google 2025-04-01 1448) tf = alloc_trace_fprobe(group, event, symbol, argc, is_return, is_tracepoint);
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1449) if (IS_ERR(tf)) {
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1450) ret = PTR_ERR(tf);
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1451) /* This must return -ENOMEM, else there is a bug */
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1452) WARN_ON_ONCE(ret != -ENOMEM);
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1453) return ret;
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1454) }
e2d0d7b2f42dca Masami Hiramatsu (Google 2023-06-06 1455)
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1456) /* carry list parsing result into tf */
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1457) if (!is_tracepoint) {
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1458) tf->list_mode = list_mode;
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1459) if (parsed_filter) {
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1460) tf->filter = kstrdup(parsed_filter, GFP_KERNEL);
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1461) if (!tf->filter)
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1462) return -ENOMEM;
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1463) }
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1464) if (parsed_nofilter) {
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1465) tf->nofilter = kstrdup(parsed_nofilter, GFP_KERNEL);
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1466) if (!tf->nofilter)
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1467) return -ENOMEM;
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1468) }
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1469) }
6589e7661d349c Seokwoo Chung (Ryan 2025-11-26 1470)
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1471) /* parse arguments */
73f35080477e89 Mikel Rychliski 2024-09-30 1472 for (i = 0; i < argc; i++) {
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1473) trace_probe_log_set_index(i + 2);
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1474) ctx->offset = 0;
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1475) ret = traceprobe_parse_probe_arg(&tf->tp, i, argv[i], ctx);
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1476) if (ret)
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1477) return ret; /* This can be -ENOMEM */
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1478) }
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1479)
25f00e40ce7953 Masami Hiramatsu (Google 2024-03-04 1480) if (is_return && tf->tp.entry_arg) {
25f00e40ce7953 Masami Hiramatsu (Google 2024-03-04 1481) tf->fp.entry_handler = trace_fprobe_entry_handler;
25f00e40ce7953 Masami Hiramatsu (Google 2024-03-04 1482) tf->fp.entry_data_size = traceprobe_get_entry_data_size(&tf->tp);
db5e228611b118 Masami Hiramatsu (Google 2025-02-26 1483) if (ALIGN(tf->fp.entry_data_size, sizeof(long)) > MAX_FPROBE_DATA_SIZE) {
db5e228611b118 Masami Hiramatsu (Google 2025-02-26 1484) trace_probe_log_set_index(2);
db5e228611b118 Masami Hiramatsu (Google 2025-02-26 1485) trace_probe_log_err(0, TOO_MANY_EARGS);
db5e228611b118 Masami Hiramatsu (Google 2025-02-26 1486) return -E2BIG;
db5e228611b118 Masami Hiramatsu (Google 2025-02-26 1487) }
25f00e40ce7953 Masami Hiramatsu (Google 2024-03-04 1488) }
25f00e40ce7953 Masami Hiramatsu (Google 2024-03-04 1489)
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1490) ret = traceprobe_set_print_fmt(&tf->tp,
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1491) is_return ? PROBE_PRINT_RETURN : PROBE_PRINT_NORMAL);
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1492) if (ret < 0)
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1493) return ret;
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1494)
2db832ec9090d3 Masami Hiramatsu (Google 2025-04-01 1495) ret = register_trace_fprobe_event(tf);
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1496) if (ret) {
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1497) trace_probe_log_set_index(1);
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1498) if (ret == -EILSEQ)
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1499) trace_probe_log_err(0, BAD_INSN_BNDRY);
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1500) else if (ret == -ENOENT)
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1501) trace_probe_log_err(0, BAD_PROBE_ADDR);
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1502) else if (ret != -ENOMEM && ret != -EEXIST)
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1503) trace_probe_log_err(0, FAIL_REG_PROBE);
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1504) return -EINVAL;
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1505) }
334e5519c37570 Masami Hiramatsu (Google 2023-06-06 1506)
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1507) /* 'tf' is successfully registered. To avoid freeing, assign NULL. */
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1508) tf = NULL;
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1509)
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1510) return 0;
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1511) }
8275637215bd3d Masami Hiramatsu (Google 2025-01-17 1512)
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* [PATCH v4 0/3] mm: vmscan: add PID and cgroup ID to vmscan tracepoints
From: Thomas Ballasi @ 2026-01-15 12:38 UTC (permalink / raw)
To: tballasi; +Cc: akpm, linux-mm, linux-trace-kernel, mhiramat, rostedt
In-Reply-To: <20260105160423.23708-1-tballasi@linux.microsoft.com>
Changes in v4:
- added Steven's patch for __even_in_*irq() calls
- moved back to mem_cgroup_id() following Shakeel's changes
- passed cgroup ID through trace calls for slab_* tracepoints
instead of in vmscan.h directly
- changed memcg_id instances types from unsigned short to u64 and
updated struct entries accordingly
Link to v3:
https://lore.kernel.org/linux-trace-kernel/20260105160423.23708-1-tballasi@linux.microsoft.com/
Signed-off-by: Thomas Ballasi <tballasi@linux.microsoft.com>
Steven Rostedt (1):
tracing: Add __event_in_*irq() helpers
Thomas Ballasi (2):
mm: vmscan: add cgroup IDs to vmscan tracepoints
mm: vmscan: add PIDs to vmscan tracepoints
include/trace/events/vmscan.h | 104 +++++++++++++--------
include/trace/stages/stage3_trace_output.h | 8 ++
include/trace/stages/stage7_class_define.h | 19 ++++
mm/shrinker.c | 6 +-
mm/vmscan.c | 17 ++--
5 files changed, 106 insertions(+), 48 deletions(-)
--
2.33.8
^ permalink raw reply
* [PATCH v4 1/3] tracing: Add __event_in_*irq() helpers
From: Thomas Ballasi @ 2026-01-15 12:38 UTC (permalink / raw)
To: tballasi; +Cc: akpm, linux-mm, linux-trace-kernel, mhiramat, rostedt
In-Reply-To: <20260115123809.2257-1-tballasi@linux.microsoft.com>
From: Steven Rostedt <rostedt@goodmis.org>
Some trace events want to expose in their output if they were triggered in
an interrupt or softirq context. Instead of recording this in the event
structure itself, as this information is stored in the flags portion of
the event header, add helper macros that can be used in the print format:
TP_printk("val=%d %s", __entry->val, __entry_in_irq() ? "(in-irq)" : "")
This will output "(in-irq)" for the event in the trace data if the event
was triggered in hard or soft interrupt context.
Link: https://lore.kernel.org/all/20251229132942.31a2b583@gandalf.local.home/
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
include/trace/stages/stage3_trace_output.h | 8 ++++++++
include/trace/stages/stage7_class_define.h | 19 +++++++++++++++++++
2 files changed, 27 insertions(+)
diff --git a/include/trace/stages/stage3_trace_output.h b/include/trace/stages/stage3_trace_output.h
index 1e7b0bef95f52..53a23988a3b8a 100644
--- a/include/trace/stages/stage3_trace_output.h
+++ b/include/trace/stages/stage3_trace_output.h
@@ -150,3 +150,11 @@
#undef __get_buf
#define __get_buf(len) trace_seq_acquire(p, (len))
+
+#undef __event_in_hardirq
+#undef __event_in_softirq
+#undef __event_in_irq
+
+#define __event_in_hardirq() (__entry->ent.flags & TRACE_FLAG_HARDIRQ)
+#define __event_in_softirq() (__entry->ent.flags & TRACE_FLAG_SOFTIRQ)
+#define __event_in_irq() (__entry->ent.flags & (TRACE_FLAG_HARDIRQ | TRACE_FLAG_SOFTIRQ))
diff --git a/include/trace/stages/stage7_class_define.h b/include/trace/stages/stage7_class_define.h
index fcd564a590f43..47008897a7956 100644
--- a/include/trace/stages/stage7_class_define.h
+++ b/include/trace/stages/stage7_class_define.h
@@ -26,6 +26,25 @@
#undef __print_hex_dump
#undef __get_buf
+#undef __event_in_hardirq
+#undef __event_in_softirq
+#undef __event_in_irq
+
+/*
+ * The TRACE_FLAG_* are enums. Instead of using TRACE_DEFINE_ENUM(),
+ * use their hardcoded values. These values are parsed by user space
+ * tooling elsewhere so they will never change.
+ *
+ * See "enum trace_flag_type" in linux/trace_events.h:
+ * TRACE_FLAG_HARDIRQ
+ * TRACE_FLAG_SOFTIRQ
+ */
+
+/* This is what is displayed in the format files */
+#define __event_in_hardirq() (REC->common_flags & 0x8)
+#define __event_in_softirq() (REC->common_flags & 0x10)
+#define __event_in_irq() (REC->common_flags & 0x18)
+
/*
* The below is not executed in the kernel. It is only what is
* displayed in the print format for userspace to parse.
--
2.33.8
^ permalink raw reply related
* [PATCH v4 2/3] mm: vmscan: add cgroup IDs to vmscan tracepoints
From: Thomas Ballasi @ 2026-01-15 12:38 UTC (permalink / raw)
To: tballasi; +Cc: akpm, linux-mm, linux-trace-kernel, mhiramat, rostedt
In-Reply-To: <20260115123809.2257-1-tballasi@linux.microsoft.com>
Memory reclaim events are currently difficult to attribute to
specific cgroups, making debugging memory pressure issues
challenging. This patch adds memory cgroup ID (memcg_id) to key
vmscan tracepoints to enable better correlation and analysis.
For operations not associated with a specific cgroup, the field
is defaulted to 0.
Signed-off-by: Thomas Ballasi <tballasi@linux.microsoft.com>
---
include/trace/events/vmscan.h | 83 ++++++++++++++++++++---------------
mm/shrinker.c | 6 ++-
mm/vmscan.c | 17 +++----
3 files changed, 61 insertions(+), 45 deletions(-)
diff --git a/include/trace/events/vmscan.h b/include/trace/events/vmscan.h
index 490958fa10dee..20160e79eb0d7 100644
--- a/include/trace/events/vmscan.h
+++ b/include/trace/events/vmscan.h
@@ -114,85 +114,92 @@ TRACE_EVENT(mm_vmscan_wakeup_kswapd,
DECLARE_EVENT_CLASS(mm_vmscan_direct_reclaim_begin_template,
- TP_PROTO(int order, gfp_t gfp_flags),
+ TP_PROTO(gfp_t gfp_flags, int order, u64 memcg_id),
- TP_ARGS(order, gfp_flags),
+ TP_ARGS(gfp_flags, order, memcg_id),
TP_STRUCT__entry(
- __field( int, order )
__field( unsigned long, gfp_flags )
+ __field( u64, memcg_id )
+ __field( int, order )
),
TP_fast_assign(
- __entry->order = order;
__entry->gfp_flags = (__force unsigned long)gfp_flags;
+ __entry->order = order;
+ __entry->memcg_id = memcg_id;
),
- TP_printk("order=%d gfp_flags=%s",
+ TP_printk("order=%d gfp_flags=%s memcg_id=%llu",
__entry->order,
- show_gfp_flags(__entry->gfp_flags))
+ show_gfp_flags(__entry->gfp_flags),
+ __entry->memcg_id)
);
DEFINE_EVENT(mm_vmscan_direct_reclaim_begin_template, mm_vmscan_direct_reclaim_begin,
- TP_PROTO(int order, gfp_t gfp_flags),
+ TP_PROTO(gfp_t gfp_flags, int order, u64 memcg_id),
- TP_ARGS(order, gfp_flags)
+ TP_ARGS(gfp_flags, order, memcg_id)
);
#ifdef CONFIG_MEMCG
DEFINE_EVENT(mm_vmscan_direct_reclaim_begin_template, mm_vmscan_memcg_reclaim_begin,
- TP_PROTO(int order, gfp_t gfp_flags),
+ TP_PROTO(gfp_t gfp_flags, int order, u64 memcg_id),
- TP_ARGS(order, gfp_flags)
+ TP_ARGS(gfp_flags, order, memcg_id)
);
DEFINE_EVENT(mm_vmscan_direct_reclaim_begin_template, mm_vmscan_memcg_softlimit_reclaim_begin,
- TP_PROTO(int order, gfp_t gfp_flags),
+ TP_PROTO(gfp_t gfp_flags, int order, u64 memcg_id),
- TP_ARGS(order, gfp_flags)
+ TP_ARGS(gfp_flags, order, memcg_id)
);
#endif /* CONFIG_MEMCG */
DECLARE_EVENT_CLASS(mm_vmscan_direct_reclaim_end_template,
- TP_PROTO(unsigned long nr_reclaimed),
+ TP_PROTO(unsigned long nr_reclaimed, u64 memcg_id),
- TP_ARGS(nr_reclaimed),
+ TP_ARGS(nr_reclaimed, memcg_id),
TP_STRUCT__entry(
__field( unsigned long, nr_reclaimed )
+ __field( u64, memcg_id )
),
TP_fast_assign(
__entry->nr_reclaimed = nr_reclaimed;
+ __entry->memcg_id = memcg_id;
),
- TP_printk("nr_reclaimed=%lu", __entry->nr_reclaimed)
+ TP_printk("nr_reclaimed=%lu memcg_id=%llu",
+ __entry->nr_reclaimed,
+ __entry->memcg_id)
);
DEFINE_EVENT(mm_vmscan_direct_reclaim_end_template, mm_vmscan_direct_reclaim_end,
- TP_PROTO(unsigned long nr_reclaimed),
+ TP_PROTO(unsigned long nr_reclaimed, u64 memcg_id),
- TP_ARGS(nr_reclaimed)
+ TP_ARGS(nr_reclaimed, memcg_id)
);
#ifdef CONFIG_MEMCG
DEFINE_EVENT(mm_vmscan_direct_reclaim_end_template, mm_vmscan_memcg_reclaim_end,
- TP_PROTO(unsigned long nr_reclaimed),
+ TP_PROTO(unsigned long nr_reclaimed, u64 memcg_id),
- TP_ARGS(nr_reclaimed)
+ TP_ARGS(nr_reclaimed, memcg_id)
);
DEFINE_EVENT(mm_vmscan_direct_reclaim_end_template, mm_vmscan_memcg_softlimit_reclaim_end,
- TP_PROTO(unsigned long nr_reclaimed),
+ TP_PROTO(unsigned long nr_reclaimed, u64 memcg_id),
- TP_ARGS(nr_reclaimed)
+ TP_ARGS(nr_reclaimed, memcg_id)
);
#endif /* CONFIG_MEMCG */
@@ -200,39 +207,42 @@ TRACE_EVENT(mm_shrink_slab_start,
TP_PROTO(struct shrinker *shr, struct shrink_control *sc,
long nr_objects_to_shrink, unsigned long cache_items,
unsigned long long delta, unsigned long total_scan,
- int priority),
+ int priority, u64 memcg_id),
TP_ARGS(shr, sc, nr_objects_to_shrink, cache_items, delta, total_scan,
- priority),
+ priority, memcg_id),
TP_STRUCT__entry(
__field(struct shrinker *, shr)
__field(void *, shrink)
- __field(int, nid)
__field(long, nr_objects_to_shrink)
__field(unsigned long, gfp_flags)
__field(unsigned long, cache_items)
__field(unsigned long long, delta)
__field(unsigned long, total_scan)
__field(int, priority)
+ __field(int, nid)
+ __field(u64, memcg_id)
),
TP_fast_assign(
__entry->shr = shr;
__entry->shrink = shr->scan_objects;
- __entry->nid = sc->nid;
__entry->nr_objects_to_shrink = nr_objects_to_shrink;
__entry->gfp_flags = (__force unsigned long)sc->gfp_mask;
__entry->cache_items = cache_items;
__entry->delta = delta;
__entry->total_scan = total_scan;
__entry->priority = priority;
+ __entry->nid = sc->nid;
+ __entry->memcg_id = memcg_id;
),
- TP_printk("%pS %p: nid: %d objects to shrink %ld gfp_flags %s cache items %ld delta %lld total_scan %ld priority %d",
+ TP_printk("%pS %p: nid: %d memcg_id: %llu objects to shrink %ld gfp_flags %s cache items %ld delta %lld total_scan %ld priority %d",
__entry->shrink,
__entry->shr,
__entry->nid,
+ __entry->memcg_id,
__entry->nr_objects_to_shrink,
show_gfp_flags(__entry->gfp_flags),
__entry->cache_items,
@@ -243,35 +253,38 @@ TRACE_EVENT(mm_shrink_slab_start,
TRACE_EVENT(mm_shrink_slab_end,
TP_PROTO(struct shrinker *shr, int nid, int shrinker_retval,
- long unused_scan_cnt, long new_scan_cnt, long total_scan),
+ long unused_scan_cnt, long new_scan_cnt, long total_scan, u64 memcg_id),
TP_ARGS(shr, nid, shrinker_retval, unused_scan_cnt, new_scan_cnt,
- total_scan),
+ total_scan, memcg_id),
TP_STRUCT__entry(
__field(struct shrinker *, shr)
- __field(int, nid)
__field(void *, shrink)
__field(long, unused_scan)
__field(long, new_scan)
- __field(int, retval)
__field(long, total_scan)
+ __field(int, nid)
+ __field(int, retval)
+ __field(u64, memcg_id)
),
TP_fast_assign(
__entry->shr = shr;
- __entry->nid = nid;
__entry->shrink = shr->scan_objects;
__entry->unused_scan = unused_scan_cnt;
__entry->new_scan = new_scan_cnt;
- __entry->retval = shrinker_retval;
__entry->total_scan = total_scan;
+ __entry->nid = nid;
+ __entry->retval = shrinker_retval;
+ __entry->memcg_id = memcg_id;
),
- TP_printk("%pS %p: nid: %d unused scan count %ld new scan count %ld total_scan %ld last shrinker return val %d",
+ TP_printk("%pS %p: nid: %d memcg_id: %llu unused scan count %ld new scan count %ld total_scan %ld last shrinker return val %d",
__entry->shrink,
__entry->shr,
__entry->nid,
+ __entry->memcg_id,
__entry->unused_scan,
__entry->new_scan,
__entry->total_scan,
@@ -504,9 +517,9 @@ TRACE_EVENT(mm_vmscan_node_reclaim_begin,
DEFINE_EVENT(mm_vmscan_direct_reclaim_end_template, mm_vmscan_node_reclaim_end,
- TP_PROTO(unsigned long nr_reclaimed),
+ TP_PROTO(unsigned long nr_reclaimed, u64 memcg_id),
- TP_ARGS(nr_reclaimed)
+ TP_ARGS(nr_reclaimed, memcg_id)
);
TRACE_EVENT(mm_vmscan_throttled,
diff --git a/mm/shrinker.c b/mm/shrinker.c
index 4a93fd433689a..ccfbe3fb3b378 100644
--- a/mm/shrinker.c
+++ b/mm/shrinker.c
@@ -410,7 +410,8 @@ static unsigned long do_shrink_slab(struct shrink_control *shrinkctl,
total_scan = min(total_scan, (2 * freeable));
trace_mm_shrink_slab_start(shrinker, shrinkctl, nr,
- freeable, delta, total_scan, priority);
+ freeable, delta, total_scan, priority,
+ mem_cgroup_id(shrinkctl->memcg));
/*
* Normally, we should not scan less than batch_size objects in one
@@ -461,7 +462,8 @@ static unsigned long do_shrink_slab(struct shrink_control *shrinkctl,
*/
new_nr = add_nr_deferred(next_deferred, shrinker, shrinkctl);
- trace_mm_shrink_slab_end(shrinker, shrinkctl->nid, freed, nr, new_nr, total_scan);
+ trace_mm_shrink_slab_end(shrinker, shrinkctl->nid, freed, nr, new_nr, total_scan,
+ mem_cgroup_id(shrinkctl->memcg));
return freed;
}
diff --git a/mm/vmscan.c b/mm/vmscan.c
index b2fc8b626d3df..9a3cd975a9f30 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -6642,11 +6642,11 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
return 1;
set_task_reclaim_state(current, &sc.reclaim_state);
- trace_mm_vmscan_direct_reclaim_begin(order, sc.gfp_mask);
+ trace_mm_vmscan_direct_reclaim_begin(sc.gfp_mask, order, 0);
nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
- trace_mm_vmscan_direct_reclaim_end(nr_reclaimed);
+ trace_mm_vmscan_direct_reclaim_end(nr_reclaimed, 0);
set_task_reclaim_state(current, NULL);
return nr_reclaimed;
@@ -6675,8 +6675,9 @@ unsigned long mem_cgroup_shrink_node(struct mem_cgroup *memcg,
sc.gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
(GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK);
- trace_mm_vmscan_memcg_softlimit_reclaim_begin(sc.order,
- sc.gfp_mask);
+ trace_mm_vmscan_memcg_softlimit_reclaim_begin(sc.gfp_mask,
+ sc.order,
+ mem_cgroup_id(memcg));
/*
* NOTE: Although we can get the priority field, using it
@@ -6687,7 +6688,7 @@ unsigned long mem_cgroup_shrink_node(struct mem_cgroup *memcg,
*/
shrink_lruvec(lruvec, &sc);
- trace_mm_vmscan_memcg_softlimit_reclaim_end(sc.nr_reclaimed);
+ trace_mm_vmscan_memcg_softlimit_reclaim_end(sc.nr_reclaimed, mem_cgroup_id(memcg));
*nr_scanned = sc.nr_scanned;
@@ -6723,13 +6724,13 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg,
struct zonelist *zonelist = node_zonelist(numa_node_id(), sc.gfp_mask);
set_task_reclaim_state(current, &sc.reclaim_state);
- trace_mm_vmscan_memcg_reclaim_begin(0, sc.gfp_mask);
+ trace_mm_vmscan_memcg_reclaim_begin(sc.gfp_mask, 0, mem_cgroup_id(memcg));
noreclaim_flag = memalloc_noreclaim_save();
nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
memalloc_noreclaim_restore(noreclaim_flag);
- trace_mm_vmscan_memcg_reclaim_end(nr_reclaimed);
+ trace_mm_vmscan_memcg_reclaim_end(nr_reclaimed, mem_cgroup_id(memcg));
set_task_reclaim_state(current, NULL);
return nr_reclaimed;
@@ -7675,7 +7676,7 @@ static unsigned long __node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask,
delayacct_freepages_end();
psi_memstall_leave(&pflags);
- trace_mm_vmscan_node_reclaim_end(sc->nr_reclaimed);
+ trace_mm_vmscan_node_reclaim_end(sc->nr_reclaimed, 0);
return sc->nr_reclaimed;
}
--
2.33.8
^ permalink raw reply related
* [PATCH v4 3/3] mm: vmscan: add PIDs to vmscan tracepoints
From: Thomas Ballasi @ 2026-01-15 12:38 UTC (permalink / raw)
To: tballasi; +Cc: akpm, linux-mm, linux-trace-kernel, mhiramat, rostedt
In-Reply-To: <20260115123809.2257-1-tballasi@linux.microsoft.com>
The changes aims at adding additionnal tracepoints variables to help
debuggers attribute them to specific processes.
The PID field uses in_task() to reliably detect when we're in process
context and can safely access current->pid. When not in process
context (such as in interrupt or in an asynchronous RCU context), the
field is set to -1 as a sentinel value.
Signed-off-by: Thomas Ballasi <tballasi@linux.microsoft.com>
---
include/trace/events/vmscan.h | 35 +++++++++++++++++++++++++----------
1 file changed, 25 insertions(+), 10 deletions(-)
diff --git a/include/trace/events/vmscan.h b/include/trace/events/vmscan.h
index 20160e79eb0d7..288589e3364b0 100644
--- a/include/trace/events/vmscan.h
+++ b/include/trace/events/vmscan.h
@@ -122,18 +122,22 @@ DECLARE_EVENT_CLASS(mm_vmscan_direct_reclaim_begin_template,
__field( unsigned long, gfp_flags )
__field( u64, memcg_id )
__field( int, order )
+ __field( int, pid )
),
TP_fast_assign(
__entry->gfp_flags = (__force unsigned long)gfp_flags;
__entry->order = order;
+ __entry->pid = current->pid;
__entry->memcg_id = memcg_id;
),
- TP_printk("order=%d gfp_flags=%s memcg_id=%llu",
+ TP_printk("order=%d gfp_flags=%s pid=%d memcg_id=%llu %s",
__entry->order,
show_gfp_flags(__entry->gfp_flags),
- __entry->memcg_id)
+ __entry->pid,
+ __entry->memcg_id,
++ __event_in_irq() ? "(in-irq)" : "")
);
DEFINE_EVENT(mm_vmscan_direct_reclaim_begin_template, mm_vmscan_direct_reclaim_begin,
@@ -168,16 +172,20 @@ DECLARE_EVENT_CLASS(mm_vmscan_direct_reclaim_end_template,
TP_STRUCT__entry(
__field( unsigned long, nr_reclaimed )
__field( u64, memcg_id )
+ __field( int, pid )
),
TP_fast_assign(
__entry->nr_reclaimed = nr_reclaimed;
__entry->memcg_id = memcg_id;
+ __entry->pid = current->pid;
),
- TP_printk("nr_reclaimed=%lu memcg_id=%llu",
+ TP_printk("nr_reclaimed=%lu pid=%d memcg_id=%llu %s",
__entry->nr_reclaimed,
- __entry->memcg_id)
+ __entry->pid,
+ __entry->memcg_id,
+ __event_in_irq() ? "(in-irq)" : "")
);
DEFINE_EVENT(mm_vmscan_direct_reclaim_end_template, mm_vmscan_direct_reclaim_end,
@@ -220,9 +228,10 @@ TRACE_EVENT(mm_shrink_slab_start,
__field(unsigned long, cache_items)
__field(unsigned long long, delta)
__field(unsigned long, total_scan)
+ __field(u64, memcg_id)
__field(int, priority)
__field(int, nid)
- __field(u64, memcg_id)
+ __field(int, pid)
),
TP_fast_assign(
@@ -236,19 +245,22 @@ TRACE_EVENT(mm_shrink_slab_start,
__entry->priority = priority;
__entry->nid = sc->nid;
__entry->memcg_id = memcg_id;
+ __entry->pid = current->pid;
),
- TP_printk("%pS %p: nid: %d memcg_id: %llu objects to shrink %ld gfp_flags %s cache items %ld delta %lld total_scan %ld priority %d",
+ TP_printk("%pS %p: nid: %d pid: %d memcg_id: %llu objects to shrink %ld gfp_flags %s cache items %ld delta %lld total_scan %ld priority %d %s",
__entry->shrink,
__entry->shr,
__entry->nid,
+ __entry->pid,
__entry->memcg_id,
__entry->nr_objects_to_shrink,
show_gfp_flags(__entry->gfp_flags),
__entry->cache_items,
__entry->delta,
__entry->total_scan,
- __entry->priority)
+ __entry->priority,
++ __event_in_irq() ? "(in-irq)" : "")
);
TRACE_EVENT(mm_shrink_slab_end,
@@ -266,29 +278,32 @@ TRACE_EVENT(mm_shrink_slab_end,
__field(long, total_scan)
__field(int, nid)
__field(int, retval)
+ __field(int, pid)
__field(u64, memcg_id)
),
TP_fast_assign(
__entry->shr = shr;
- __entry->shrink = shr->scan_objects;
__entry->unused_scan = unused_scan_cnt;
__entry->new_scan = new_scan_cnt;
__entry->total_scan = total_scan;
__entry->nid = nid;
__entry->retval = shrinker_retval;
+ __entry->pid = current->pid;
__entry->memcg_id = memcg_id;
),
- TP_printk("%pS %p: nid: %d memcg_id: %llu unused scan count %ld new scan count %ld total_scan %ld last shrinker return val %d",
+ TP_printk("%pS %p: nid: %d pid: %d memcg_id: %llu unused scan count %ld new scan count %ld total_scan %ld last shrinker return val %d %s",
__entry->shrink,
__entry->shr,
__entry->nid,
+ __entry->pid,
__entry->memcg_id,
__entry->unused_scan,
__entry->new_scan,
__entry->total_scan,
- __entry->retval)
+ __entry->retval,
++ __event_in_irq() ? "(in-irq)" : "")
);
TRACE_EVENT(mm_vmscan_lru_isolate,
--
2.33.8
^ permalink raw reply related
* Re: [PATCH] tracing/osnoise: Fix OSN_WORKLOAD-related crash
From: Tomas Glozar @ 2026-01-15 13:32 UTC (permalink / raw)
To: Crystal Wood
Cc: Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers, John Kacur,
Luis Goncalves, LKML, Linux Trace Kernel
In-Reply-To: <bbb834f13cb1480b2517497481a1b3e0137d089a.camel@redhat.com>
st 14. 1. 2026 v 20:49 odesílatel Crystal Wood <crwood@redhat.com> napsal:
> >
> > The kernel first displays several WARN traces with the following pattern:
> >
> > WARNING: CPU: 1 PID: 1822 at kernel/trace/trace_osnoise.c:1959 stop_kthread+0xb7/0xc0
>
> The line number doesn't match up for me; is this the first or second
> WARN_ON in that function?
The first one [1], sorry for the confusion, I used a log from an old
CentOS Stream 10 kernel for the commit description.
[1] https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-10/-/blob/7482e1508860dc8009827f87970b2f48fca251d4/kernel/trace/trace_osnoise.c#L1959
> > and finally a null pointer reference BUG:
> >
> > BUG: kernel NULL pointer dereference, address: 0000000000000030
> > ...
> > CPU: 1 UID: 0 PID: 2155 Comm: timerlatu/1
> > ...
> > Call Trace:
> > ...
> > ? timerlat_fd_read+0xf2/0x370
> > ? timerlat_fd_read+0xee/0x370
> > vfs_read+0xe8/0x370
> > ksys_read+0x6d/0xf0
> > do_syscall_64+0x7d/0x160
> > ...
> > entry_SYSCALL_64_after_hwframe+0x76/0x7e
>
> What's the actual fault location? And those ? lines in the call trace
> are "considered to be additional clues" rather than actual unwound
> frames; what was in the ... above them?
Ah I dropped one line more than I wanted, the fault is in timerlat_fd_read:
[ 513.050331] BUG: kernel NULL pointer dereference, address: 0000000000000030
[ 513.050345] #PF: supervisor read access in kernel mode
[ 513.050350] #PF: error_code(0x0000) - not-present page
[ 513.050354] PGD 0 P4D 0
[ 513.050358] Oops: Oops: 0000 [#1] PREEMPT SMP NOPTI
[ 513.050364] CPU: 1 UID: 0 PID: 2155 Comm: timerlatu/1 Kdump: loaded
Tainted: G W ------- --- 6.12.0-35.el10.x86_64 #1
[ 513.050375] Tainted: [W]=WARN
[ 513.050378] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009),
BIOS 1.16.3-3.fc41 04/01/2014
[ 513.050385] RIP: 0010:timerlat_fd_read+0xf2/0x370
[ 513.050392] Code: f7 53 e3 a5 9b c4 20 48 89 e8 48 c1 e8 03 48 f7
e2 48 c1 ea 04 48 39 ca 0f 83 8c 01 00 00 48 89 df e8 a2 f9 ff ff 48
8b 43 38 <48> 8b 40 30 ff d0 0f 1f 00 48 2b 43 50 48 89 c5 78 49 48 8b
43 60
[ 513.050406] RSP: 0018:ffffadd181227df8 EFLAGS: 00010246
[ 513.050411] RAX: 0000000000000000 RBX: ffff93739fd2e680 RCX: 0000000000000000
[ 513.050417] RDX: ffff937365b21560 RSI: ffff93734106b180 RDI: ffff9373422b4280
[ 513.050422] RBP: 000000000000b38b R08: 0000000000000000 R09: 0000000000000001
[ 513.050427] R10: 0000000080170010 R11: ffff93734106b180 R12: ffff937342c186c0
[ 513.050433] R13: 0000000000000001 R14: 00007f6e618dca90 R15: ffffadd181227ed0
[ 513.050547] FS: 00007f6e618dd6c0(0000) GS:ffff93739fd00000(0000)
knlGS:0000000000000000
[ 513.050659] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 513.050766] CR2: 0000000000000030 CR3: 000000000354e006 CR4: 0000000000772ef0
[ 513.050888] PKRU: 55555554
[ 513.051006] Call Trace:
[ 513.051134] <TASK>
[ 513.051249] ? show_trace_log_lvl+0x1b0/0x2f0
[ 513.051363] ? show_trace_log_lvl+0x1b0/0x2f0
[ 513.051476] ? vfs_read+0xe8/0x370
[ 513.051591] ? __die_body.cold+0x8/0x12
[ 513.051706] ? page_fault_oops+0x146/0x160
[ 513.051823] ? exc_page_fault+0x73/0x160
[ 513.051941] ? asm_exc_page_fault+0x26/0x30
[ 513.052060] ? timerlat_fd_read+0xf2/0x370
[ 513.052187] ? timerlat_fd_read+0xee/0x370
[ 513.052300] vfs_read+0xe8/0x370
[ 513.052410] ksys_read+0x6d/0xf0
[ 513.052519] do_syscall_64+0x7d/0x160
[ 513.052630] ? clear_bhb_loop+0x25/0x80
[ 513.052742] ? clear_bhb_loop+0x25/0x80
[ 513.052853] ? clear_bhb_loop+0x25/0x80
[ 513.052963] entry_SYSCALL_64_after_hwframe+0x76/0x7e
[ 513.053081] RIP: 0033:0x7f6e619d7bbc
[ 513.053217] Code: ec 28 48 89 54 24 18 48 89 74 24 10 89 7c 24 08
e8 b9 8f f9 ff 48 8b 54 24 18 48 8b 74 24 10 41 89 c0 8b 7c 24 08 31
c0 0f 05 <48> 3d 00 f0 ff ff 77 34 44 89 c7 48 89 44 24 08 e8 0f 90 f9
ff 48
[ 513.053470] RSP: 002b:00007f6e618dc910 EFLAGS: 00000246 ORIG_RAX:
0000000000000000
[ 513.053599] RAX: ffffffffffffffda RBX: 00007f6e618dca90 RCX: 00007f6e619d7bbc
[ 513.053731] RDX: 0000000000000400 RSI: 00007f6e618dca90 RDI: 0000000000000003
[ 513.053863] RBP: 00007f6e618dced0 R08: 0000000000000000 R09: 00007f6e5c000b90
[ 513.053998] R10: 00007f6e5c0008e0 R11: 0000000000000246 R12: 0000000000000001
[ 513.054145] R13: 0000000000000003 R14: 0000000000000000 R15: 0000000000000001
[ 513.054288] </TASK>
I didn't look deeply into the mechanism of the crash, I just thought
that this is not a valid state to be setting OSNOISE_WORKLOAD in the
first place, so I can just disallow it and I don't have to dig deeper.
> > static int osnoise_options_open(struct inode *inode, struct file *file)
> > {
> > return seq_open(file, &osnoise_options_seq_ops);
> > @@ -2229,6 +2254,10 @@ static ssize_t osnoise_options_write(struct file *filp, const char __user *ubuf,
> > if (option < 0)
> > return -EINVAL;
> >
> > + retval = osnoise_validate_option(option, enable);
> > + if (retval != 0)
> > + return retval;
> > +
> > /*
> > * trace_types_lock is taken to avoid concurrency on start/stop.
> > */
>
> Shouldn't this be done under interface_lock to avoid concurrent
> timerlat_fd_open()? FWIW, your test script doesn't appear to cover the
> case of option setting racing with timerlat starting (due to the 2
> second delay).
My patch only takes into account the sequential case, which is already
rare to trigger - I don't know about any cases where this happened
during normal use. I would normally put the code behind the
interface_lock, if there weren't the stop_per_cpu_kthreads() thing in
between.
> Of course, this is complicated by stop_per_cpu_kthreads() happening
> before interface_lock is acquired. Do we know why that happens outside
> the lock? That might even be the actual cause of this bug.
Before commit b484a02c9c ("tracing/timerlat: Drop interface_lock in
stop_kthread()"), stop_kthread() took interface_lock, so
stop_per_cpu_kthreads() couldn't be called while holding
interface_lock. As that is no longer the case, the position of taking
interface_lock in osnoise_options_write() could be re-evaluated
(comment in 5bfbcd1ee57b says interface_lock cannot be taken at the
same time as cpu_read_lock).
I don't think it's directly related to this bug. All operations in the
reproducer are expected to be executed in sequence, so the lock should
have no effect on it.
> Though even in the non-race case, we might still want to return -EBUSY
> rather than just killing the thread (which might still have races since
> we don't wait for the user thread to die).
Yes, if we want to change the semantics to kill the user threads and
restart kernel threads on setting OSNOISE_WORKLOAD, we have to take
into account that the user threads might take an indefinite amount of
time to exit. The idea of my patch is to let the user dispose of the
user threads rather than the tracer, that will also avoid possible
deadlocks.
Tomas
^ permalink raw reply
* Re: [PATCH] tracing/osnoise: Fix OSN_WORKLOAD-related crash
From: Steven Rostedt @ 2026-01-15 15:52 UTC (permalink / raw)
To: Tomas Glozar
Cc: Crystal Wood, Masami Hiramatsu, Mathieu Desnoyers, John Kacur,
Luis Goncalves, LKML, Linux Trace Kernel
In-Reply-To: <CAP4=nvQeBnAtbQFjAdKhQUP1_Xi2uEH0i+kZC6TZwu7GZJYu3w@mail.gmail.com>
On Thu, 15 Jan 2026 14:32:27 +0100
Tomas Glozar <tglozar@redhat.com> wrote:
> > Of course, this is complicated by stop_per_cpu_kthreads() happening
> > before interface_lock is acquired. Do we know why that happens outside
> > the lock? That might even be the actual cause of this bug.
>
> Before commit b484a02c9c ("tracing/timerlat: Drop interface_lock in
> stop_kthread()"), stop_kthread() took interface_lock, so
> stop_per_cpu_kthreads() couldn't be called while holding
> interface_lock. As that is no longer the case, the position of taking
> interface_lock in osnoise_options_write() could be re-evaluated
> (comment in 5bfbcd1ee57b says interface_lock cannot be taken at the
> same time as cpu_read_lock).
Right. Also take a look at commit 177e1cc2f4123 ("tracing/osnoise: Use
a cpumask to know what threads are kthreads"). I don't remember the
details but there was a lot of issues with lock ordering between the
interface_lock and the cpu_read_lock. Whatever changes you make, make
sure to run lockdep while doing your tests.
-- Steve
^ permalink raw reply
* Re: [PATCH v2 1/1] mm: Fix OOM killer inaccuracy on large many-core systems
From: Vlastimil Babka @ 2026-01-15 17:21 UTC (permalink / raw)
To: Mathieu Desnoyers, Andrew Morton
Cc: linux-kernel, Michal Hocko, Paul E. McKenney, Steven Rostedt,
Masami Hiramatsu, Dennis Zhou, Tejun Heo, Christoph Lameter,
Martin Liu, David Rientjes, christian.koenig, Shakeel Butt,
SeongJae Park, Johannes Weiner, Sweet Tea Dorminy,
Lorenzo Stoakes, Liam R . Howlett, Mike Rapoport,
Suren Baghdasaryan, Christian Brauner, Wei Yang,
David Hildenbrand, Miaohe Lin, Al Viro, linux-mm, stable,
linux-trace-kernel, Yu Zhao, Roman Gushchin, Mateusz Guzik,
Matthew Wilcox, Baolin Wang, Aboorva Devarajan
In-Reply-To: <20260114143642.47333-1-mathieu.desnoyers@efficios.com>
On 1/14/26 15:36, Mathieu Desnoyers wrote:
> Use the precise, albeit slower, precise RSS counter sums for the OOM
> killer task selection and console dumps. The approximated value is
> too imprecise on large many-core systems.
>
> The following rss tracking issues were noted by Sweet Tea Dorminy [1],
> which lead to picking wrong tasks as OOM kill target:
>
> Recently, several internal services had an RSS usage regression as part of a
> kernel upgrade. Previously, they were on a pre-6.2 kernel and were able to
> read RSS statistics in a backup watchdog process to monitor and decide if
> they'd overrun their memory budget. Now, however, a representative service
> with five threads, expected to use about a hundred MB of memory, on a 250-cpu
> machine had memory usage tens of megabytes different from the expected amount
> -- this constituted a significant percentage of inaccuracy, causing the
> watchdog to act.
>
> This was a result of commit f1a7941243c1 ("mm: convert mm's rss stats
> into percpu_counter") [1]. Previously, the memory error was bounded by
> 64*nr_threads pages, a very livable megabyte. Now, however, as a result of
> scheduler decisions moving the threads around the CPUs, the memory error could
> be as large as a gigabyte.
>
> This is a really tremendous inaccuracy for any few-threaded program on a
> large machine and impedes monitoring significantly. These stat counters are
> also used to make OOM killing decisions, so this additional inaccuracy could
> make a big difference in OOM situations -- either resulting in the wrong
> process being killed, or in less memory being returned from an OOM-kill than
> expected.
>
> Here is a (possibly incomplete) list of the prior approaches that were
> used or proposed, along with their downside:
>
> 1) Per-thread rss tracking: large error on many-thread processes.
>
> 2) Per-CPU counters: up to 12% slower for short-lived processes and 9%
> increased system time in make test workloads [1]. Moreover, the
> inaccuracy increases with O(n^2) with the number of CPUs.
>
> 3) Per-NUMA-node counters: requires atomics on fast-path (overhead),
> error is high with systems that have lots of NUMA nodes (32 times
> the number of NUMA nodes).
>
> commit 82241a83cd15 ("mm: fix the inaccurate memory statistics issue for
> users") introduced get_mm_counter_sum() for precise proc memory status
> queries for some proc files.
>
> The simple fix proposed here is to do the precise per-cpu counters sum
> every time a counter value needs to be read. This applies to the OOM
> killer task selection, oom task console dumps (printk).
>
> This change increases the latency introduced when the OOM killer
> executes in favor of doing a more precise OOM target task selection.
> Effectively, the OOM killer iterates on all tasks, for all relevant page
> types, for which the precise sum iterates on all possible CPUs.
>
> As a reference, here is the execution time of the OOM killer
> before/after the change:
>
> AMD EPYC 9654 96-Core (2 sockets)
> Within a KVM, configured with 256 logical cpus.
>
> | before | after |
> ----------------------------------|----------|----------|
> nr_processes=40 | 0.3 ms | 0.5 ms |
> nr_processes=10000 | 3.0 ms | 80.0 ms |
>
> Suggested-by: Michal Hocko <mhocko@suse.com>
> Fixes: f1a7941243c1 ("mm: convert mm's rss stats into percpu_counter")
> Link: https://lore.kernel.org/lkml/20250331223516.7810-2-sweettea-kernel@dorminy.me/ # [1]
> Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: "Paul E. McKenney" <paulmck@kernel.org>
> Cc: Steven Rostedt <rostedt@goodmis.org>
> Cc: Masami Hiramatsu <mhiramat@kernel.org>
> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
> Cc: Dennis Zhou <dennis@kernel.org>
> Cc: Tejun Heo <tj@kernel.org>
> Cc: Christoph Lameter <cl@linux.com>
> Cc: Martin Liu <liumartin@google.com>
> Cc: David Rientjes <rientjes@google.com>
> Cc: christian.koenig@amd.com
> Cc: Shakeel Butt <shakeel.butt@linux.dev>
> Cc: SeongJae Park <sj@kernel.org>
> Cc: Michal Hocko <mhocko@suse.com>
> Cc: Johannes Weiner <hannes@cmpxchg.org>
> Cc: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
> Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
> Cc: "Liam R . Howlett" <liam.howlett@oracle.com>
> Cc: Mike Rapoport <rppt@kernel.org>
> Cc: Suren Baghdasaryan <surenb@google.com>
> Cc: Vlastimil Babka <vbabka@suse.cz>
> Cc: Christian Brauner <brauner@kernel.org>
> Cc: Wei Yang <richard.weiyang@gmail.com>
> Cc: David Hildenbrand <david@redhat.com>
> Cc: Miaohe Lin <linmiaohe@huawei.com>
> Cc: Al Viro <viro@zeniv.linux.org.uk>
> Cc: linux-mm@kvack.org
> Cc: stable@vger.kernel.org
> Cc: linux-trace-kernel@vger.kernel.org
> Cc: Yu Zhao <yuzhao@google.com>
> Cc: Roman Gushchin <roman.gushchin@linux.dev>
> Cc: Mateusz Guzik <mjguzik@gmail.com>
> Cc: Matthew Wilcox <willy@infradead.org>
> Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
> Cc: Aboorva Devarajan <aboorvad@linux.ibm.com>
> ---
> This patch replaces v1. It's aimed at mm-new.
>
> Changes since v1:
> - Only change the oom killer RSS values from approximated to precise
> sums. Do not change other RSS values users.
> ---
> include/linux/mm.h | 7 +++++++
> mm/oom_kill.c | 22 +++++++++++-----------
> 2 files changed, 18 insertions(+), 11 deletions(-)
>
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 6f959d8ca4b4..bfa1307264df 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -2901,6 +2901,13 @@ static inline unsigned long get_mm_rss(struct mm_struct *mm)
> get_mm_counter(mm, MM_SHMEMPAGES);
> }
>
> +static inline unsigned long get_mm_rss_sum(struct mm_struct *mm)
> +{
> + return get_mm_counter_sum(mm, MM_FILEPAGES) +
> + get_mm_counter_sum(mm, MM_ANONPAGES) +
> + get_mm_counter_sum(mm, MM_SHMEMPAGES);
> +}
> +
> static inline unsigned long get_mm_hiwater_rss(struct mm_struct *mm)
> {
> return max(mm->hiwater_rss, get_mm_rss(mm));
> diff --git a/mm/oom_kill.c b/mm/oom_kill.c
> index 5eb11fbba704..214cb8cb939b 100644
> --- a/mm/oom_kill.c
> +++ b/mm/oom_kill.c
> @@ -228,7 +228,7 @@ long oom_badness(struct task_struct *p, unsigned long totalpages)
> * The baseline for the badness score is the proportion of RAM that each
> * task's rss, pagetable and swap space use.
> */
> - points = get_mm_rss(p->mm) + get_mm_counter(p->mm, MM_SWAPENTS) +
> + points = get_mm_rss_sum(p->mm) + get_mm_counter_sum(p->mm, MM_SWAPENTS) +
> mm_pgtables_bytes(p->mm) / PAGE_SIZE;
> task_unlock(p);
>
> @@ -402,10 +402,10 @@ static int dump_task(struct task_struct *p, void *arg)
>
> pr_info("[%7d] %5d %5d %8lu %8lu %8lu %8lu %9lu %8ld %8lu %5hd %s\n",
> task->pid, from_kuid(&init_user_ns, task_uid(task)),
> - task->tgid, task->mm->total_vm, get_mm_rss(task->mm),
> - get_mm_counter(task->mm, MM_ANONPAGES), get_mm_counter(task->mm, MM_FILEPAGES),
> - get_mm_counter(task->mm, MM_SHMEMPAGES), mm_pgtables_bytes(task->mm),
> - get_mm_counter(task->mm, MM_SWAPENTS),
> + task->tgid, task->mm->total_vm, get_mm_rss_sum(task->mm),
> + get_mm_counter_sum(task->mm, MM_ANONPAGES), get_mm_counter_sum(task->mm, MM_FILEPAGES),
> + get_mm_counter_sum(task->mm, MM_SHMEMPAGES), mm_pgtables_bytes(task->mm),
> + get_mm_counter_sum(task->mm, MM_SWAPENTS),
> task->signal->oom_score_adj, task->comm);
> task_unlock(task);
>
> @@ -604,9 +604,9 @@ static bool oom_reap_task_mm(struct task_struct *tsk, struct mm_struct *mm)
>
> pr_info("oom_reaper: reaped process %d (%s), now anon-rss:%lukB, file-rss:%lukB, shmem-rss:%lukB\n",
> task_pid_nr(tsk), tsk->comm,
> - K(get_mm_counter(mm, MM_ANONPAGES)),
> - K(get_mm_counter(mm, MM_FILEPAGES)),
> - K(get_mm_counter(mm, MM_SHMEMPAGES)));
> + K(get_mm_counter_sum(mm, MM_ANONPAGES)),
> + K(get_mm_counter_sum(mm, MM_FILEPAGES)),
> + K(get_mm_counter_sum(mm, MM_SHMEMPAGES)));
> out_finish:
> trace_finish_task_reaping(tsk->pid);
> out_unlock:
> @@ -960,9 +960,9 @@ static void __oom_kill_process(struct task_struct *victim, const char *message)
> mark_oom_victim(victim);
> pr_err("%s: Killed process %d (%s) total-vm:%lukB, anon-rss:%lukB, file-rss:%lukB, shmem-rss:%lukB, UID:%u pgtables:%lukB oom_score_adj:%hd\n",
> message, task_pid_nr(victim), victim->comm, K(mm->total_vm),
> - K(get_mm_counter(mm, MM_ANONPAGES)),
> - K(get_mm_counter(mm, MM_FILEPAGES)),
> - K(get_mm_counter(mm, MM_SHMEMPAGES)),
> + K(get_mm_counter_sum(mm, MM_ANONPAGES)),
> + K(get_mm_counter_sum(mm, MM_FILEPAGES)),
> + K(get_mm_counter_sum(mm, MM_SHMEMPAGES)),
> from_kuid(&init_user_ns, task_uid(victim)),
> mm_pgtables_bytes(mm) >> 10, victim->signal->oom_score_adj);
> task_unlock(victim);
^ permalink raw reply
* [PATCH v3 00/18] rtla: Robustness and code quality improvements
From: Wander Lairson Costa @ 2026-01-15 16:31 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Crystal Wood,
Ivan Pravdin, Costa Shulyupin, John Kacur, Tiezhu Yang,
Daniel Wagner, Daniel Bristot de Oliveira,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
This series addresses multiple issues in the rtla codebase related to
error handling, string manipulation safety, and code maintainability.
The changes improve the tool's reliability and bring the code more in
line with kernel coding practices.
The series can be broadly divided into three categories:
Bug fixes address several correctness issues: a resource leak where
opendir() was not paired with closedir() on success paths, I/O loops
that failed to handle EINTR and partial writes correctly, a missing
bounds check when indexing the softirq_name array with kernel-provided
data, improper handling of pthread_create() failures, and a loop
condition that checked a pointer instead of the character it points to.
String handling improvements replace unsafe patterns throughout the
codebase. The strncpy() function is replaced with a new strscpy()
implementation that guarantees NUL-termination and provides truncation
detection. A str_has_prefix() helper replaces verbose strncmp/strlen
patterns for prefix matching. String comparisons are tightened to use
exact matching where appropriate, preventing silent acceptance of
malformed input like "100nsx" being parsed as "100ns".
Code quality improvements reduce duplication and improve readability.
A common_threshold_handler() consolidates repeated threshold action
logic. The extract_arg() macro simplifies key=value parsing. Magic
numbers are replaced with named constants (MAX_PATH, ARRAY_SIZE), and
redundant strlen() calls are cached in local variables.
All changes have been tested with the existing rtla test suite.
Changes:
v3:
- Address v2 feedback:
- Rename common_restart() to common_threshold_handler() to better
reflect its purpose (Tomas Glozar).
- Implement a proper strscpy() for safer string handling instead of
manual buffer sizing (Steven Rostedt).
- Remove restart_result enum in favor of simpler, direct return
values (Tomas Glozar).
- Add several new bug fixes, including a softirq vector bounds check,
pthread_create() failure handling, robust I/O handling for
EINTR/partial writes, and a resource leak fix.
- Introduce str_has_prefix() helper to replace verbose strncmp/strlen
patterns.
- Tighten string parsing to enforce exact matching and reject invalid
suffixes (e.g., "100nsx").
- Drop patches already merged via RTLA v6.20 pull request.
v2:
- exit on memory allocation failure
- remove redundant strlen() calls
- fix possible race on condition on stop_tracing variable access
- ensure null termination on read() calls
- fix checkpatch reports
- make extract_args() an inline function
- add the usage of common_restart() in more places
Wander Lairson Costa (18):
rtla: Exit on memory allocation failures during initialization
rtla: Use strdup() to simplify code
rtla: Simplify argument parsing
rtla: Introduce common_threshold_handler() helper
rtla: Replace magic number with MAX_PATH
rtla: Simplify code by caching string lengths
rtla: Add strscpy() and replace strncpy() calls
rtla/timerlat: Add bounds check for softirq vector
rtla: Handle pthread_create() failure properly
rtla: Add str_has_prefix() helper function
rtla: Use str_has_prefix() for prefix checks
rtla: Enforce exact match for time unit suffixes
rtla: Use str_has_prefix() for option prefix check
rtla/timerlat: Simplify RTLA_NO_BPF environment variable check
rtla/trace: Fix write loop in trace_event_save_hist()
rtla/trace: Fix I/O handling in save_trace_to_file()
rtla/utils: Fix resource leak in set_comm_sched_attr()
rtla/utils: Fix loop condition in PID validation
tools/tracing/rtla/src/actions.c | 103 ++++++++++++++----------
tools/tracing/rtla/src/actions.h | 8 +-
tools/tracing/rtla/src/common.c | 65 +++++++++++-----
tools/tracing/rtla/src/common.h | 18 +++++
tools/tracing/rtla/src/osnoise.c | 28 +++----
tools/tracing/rtla/src/osnoise_hist.c | 22 ++----
tools/tracing/rtla/src/osnoise_top.c | 22 ++----
tools/tracing/rtla/src/timerlat.c | 5 +-
tools/tracing/rtla/src/timerlat_aa.c | 10 +--
tools/tracing/rtla/src/timerlat_hist.c | 41 ++++------
tools/tracing/rtla/src/timerlat_top.c | 54 ++++++-------
tools/tracing/rtla/src/timerlat_u.c | 4 +-
tools/tracing/rtla/src/trace.c | 101 +++++++++++++-----------
tools/tracing/rtla/src/trace.h | 4 +-
tools/tracing/rtla/src/utils.c | 104 ++++++++++++++++++++-----
tools/tracing/rtla/src/utils.h | 31 +++++++-
16 files changed, 374 insertions(+), 246 deletions(-)
--
2.52.0
^ permalink raw reply
* [PATCH v3 01/18] rtla: Exit on memory allocation failures during initialization
From: Wander Lairson Costa @ 2026-01-15 16:31 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Crystal Wood,
Ivan Pravdin, Costa Shulyupin, John Kacur, Haiyong Sun,
Tiezhu Yang, Daniel Wagner, Daniel Bristot de Oliveira,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
In-Reply-To: <20260115163650.118910-1-wander@redhat.com>
Most memory allocations in rtla happen during early initialization
before any resources are acquired that would require cleanup. In these
cases, propagating allocation errors just adds complexity without any
benefit. There's nothing to clean up, and the program must exit anyway.
This patch introduces fatal allocation wrappers (calloc_fatal,
reallocarray_fatal, strdup_fatal) that call fatal() on allocation
failure. These wrappers simplify the code by eliminating unnecessary
error propagation paths.
The patch converts early allocations to use these wrappers in
actions_init() and related action functions, osnoise_context_alloc()
and osnoise_init_tool(), trace_instance_init() and trace event
functions, and parameter structure allocations in main functions.
This simplifies the code while maintaining the same behavior: immediate
exit on allocation failure during initialization. Allocations that
require cleanup, such as those in histogram allocation functions with
goto cleanup paths, are left unchanged and continue to return errors.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/actions.c | 50 ++++++++++++--------------
tools/tracing/rtla/src/actions.h | 8 ++---
tools/tracing/rtla/src/osnoise.c | 22 ++++--------
tools/tracing/rtla/src/osnoise_hist.c | 22 ++++--------
tools/tracing/rtla/src/osnoise_top.c | 22 ++++--------
tools/tracing/rtla/src/timerlat_hist.c | 22 ++++--------
tools/tracing/rtla/src/timerlat_top.c | 22 ++++--------
tools/tracing/rtla/src/trace.c | 30 ++++------------
tools/tracing/rtla/src/trace.h | 4 +--
tools/tracing/rtla/src/utils.c | 35 ++++++++++++++++++
tools/tracing/rtla/src/utils.h | 3 ++
11 files changed, 108 insertions(+), 132 deletions(-)
diff --git a/tools/tracing/rtla/src/actions.c b/tools/tracing/rtla/src/actions.c
index a42615011962d..22b8283a183f3 100644
--- a/tools/tracing/rtla/src/actions.c
+++ b/tools/tracing/rtla/src/actions.c
@@ -15,7 +15,7 @@ void
actions_init(struct actions *self)
{
self->size = action_default_size;
- self->list = calloc(self->size, sizeof(struct action));
+ self->list = calloc_fatal(self->size, sizeof(struct action));
self->len = 0;
self->continue_flag = false;
@@ -50,8 +50,10 @@ static struct action *
actions_new(struct actions *self)
{
if (self->len >= self->size) {
- self->size *= 2;
- self->list = realloc(self->list, self->size * sizeof(struct action));
+ const size_t new_size = self->size * 2;
+
+ self->list = reallocarray_fatal(self->list, new_size, sizeof(struct action));
+ self->size = new_size;
}
return &self->list[self->len++];
@@ -60,25 +62,21 @@ actions_new(struct actions *self)
/*
* actions_add_trace_output - add an action to output trace
*/
-int
+void
actions_add_trace_output(struct actions *self, const char *trace_output)
{
struct action *action = actions_new(self);
self->present[ACTION_TRACE_OUTPUT] = true;
action->type = ACTION_TRACE_OUTPUT;
- action->trace_output = calloc(strlen(trace_output) + 1, sizeof(char));
- if (!action->trace_output)
- return -1;
+ action->trace_output = calloc_fatal(strlen(trace_output) + 1, sizeof(char));
strcpy(action->trace_output, trace_output);
-
- return 0;
}
/*
* actions_add_trace_output - add an action to send signal to a process
*/
-int
+void
actions_add_signal(struct actions *self, int signal, int pid)
{
struct action *action = actions_new(self);
@@ -87,40 +85,32 @@ actions_add_signal(struct actions *self, int signal, int pid)
action->type = ACTION_SIGNAL;
action->signal = signal;
action->pid = pid;
-
- return 0;
}
/*
* actions_add_shell - add an action to execute a shell command
*/
-int
+void
actions_add_shell(struct actions *self, const char *command)
{
struct action *action = actions_new(self);
self->present[ACTION_SHELL] = true;
action->type = ACTION_SHELL;
- action->command = calloc(strlen(command) + 1, sizeof(char));
- if (!action->command)
- return -1;
+ action->command = calloc_fatal(strlen(command) + 1, sizeof(char));
strcpy(action->command, command);
-
- return 0;
}
/*
* actions_add_continue - add an action to resume measurement
*/
-int
+void
actions_add_continue(struct actions *self)
{
struct action *action = actions_new(self);
self->present[ACTION_CONTINUE] = true;
action->type = ACTION_CONTINUE;
-
- return 0;
}
/*
@@ -176,7 +166,8 @@ actions_parse(struct actions *self, const char *trigger, const char *tracefn)
/* Only one argument allowed */
return -1;
}
- return actions_add_trace_output(self, trace_output);
+ actions_add_trace_output(self, trace_output);
+ break;
case ACTION_SIGNAL:
/* Takes two arguments, num (signal) and pid */
while (token != NULL) {
@@ -200,21 +191,26 @@ actions_parse(struct actions *self, const char *trigger, const char *tracefn)
/* Missing argument */
return -1;
- return actions_add_signal(self, signal, pid);
+ actions_add_signal(self, signal, pid);
+ break;
case ACTION_SHELL:
if (token == NULL)
return -1;
- if (strlen(token) > 8 && strncmp(token, "command=", 8) == 0)
- return actions_add_shell(self, token + 8);
- return -1;
+ if (strlen(token) > 8 && strncmp(token, "command=", 8))
+ return -1;
+ actions_add_shell(self, token + 8);
+ break;
case ACTION_CONTINUE:
/* Takes no argument */
if (token != NULL)
return -1;
- return actions_add_continue(self);
+ actions_add_continue(self);
+ break;
default:
return -1;
}
+
+ return 0;
}
/*
diff --git a/tools/tracing/rtla/src/actions.h b/tools/tracing/rtla/src/actions.h
index fb77069c972ba..034048682fefb 100644
--- a/tools/tracing/rtla/src/actions.h
+++ b/tools/tracing/rtla/src/actions.h
@@ -49,9 +49,9 @@ struct actions {
void actions_init(struct actions *self);
void actions_destroy(struct actions *self);
-int actions_add_trace_output(struct actions *self, const char *trace_output);
-int actions_add_signal(struct actions *self, int signal, int pid);
-int actions_add_shell(struct actions *self, const char *command);
-int actions_add_continue(struct actions *self);
+void actions_add_trace_output(struct actions *self, const char *trace_output);
+void actions_add_signal(struct actions *self, int signal, int pid);
+void actions_add_shell(struct actions *self, const char *command);
+void actions_add_continue(struct actions *self);
int actions_parse(struct actions *self, const char *trigger, const char *tracefn);
int actions_perform(struct actions *self);
diff --git a/tools/tracing/rtla/src/osnoise.c b/tools/tracing/rtla/src/osnoise.c
index 945eb61efc465..ec074cd53dd84 100644
--- a/tools/tracing/rtla/src/osnoise.c
+++ b/tools/tracing/rtla/src/osnoise.c
@@ -938,9 +938,7 @@ struct osnoise_context *osnoise_context_alloc(void)
{
struct osnoise_context *context;
- context = calloc(1, sizeof(*context));
- if (!context)
- return NULL;
+ context = calloc_fatal(1, sizeof(*context));
context->orig_stop_us = OSNOISE_OPTION_INIT_VAL;
context->stop_us = OSNOISE_OPTION_INIT_VAL;
@@ -1017,24 +1015,16 @@ void osnoise_destroy_tool(struct osnoise_tool *top)
struct osnoise_tool *osnoise_init_tool(char *tool_name)
{
struct osnoise_tool *top;
- int retval;
-
- top = calloc(1, sizeof(*top));
- if (!top)
- return NULL;
+ top = calloc_fatal(1, sizeof(*top));
top->context = osnoise_context_alloc();
- if (!top->context)
- goto out_err;
- retval = trace_instance_init(&top->trace, tool_name);
- if (retval)
- goto out_err;
+ if (trace_instance_init(&top->trace, tool_name)) {
+ osnoise_destroy_tool(top);
+ return NULL;
+ }
return top;
-out_err:
- osnoise_destroy_tool(top);
- return NULL;
}
/*
diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c
index 9d70ea34807ff..efbd2e834cf0e 100644
--- a/tools/tracing/rtla/src/osnoise_hist.c
+++ b/tools/tracing/rtla/src/osnoise_hist.c
@@ -466,9 +466,7 @@ static struct common_params
int c;
char *trace_output = NULL;
- params = calloc(1, sizeof(*params));
- if (!params)
- exit(1);
+ params = calloc_fatal(1, sizeof(*params));
actions_init(¶ms->common.threshold_actions);
actions_init(¶ms->common.end_actions);
@@ -579,22 +577,16 @@ static struct common_params
params->common.hist.with_zeros = 1;
break;
case '4': /* trigger */
- if (params->common.events) {
- retval = trace_event_add_trigger(params->common.events, optarg);
- if (retval)
- fatal("Error adding trigger %s", optarg);
- } else {
+ if (params->common.events)
+ trace_event_add_trigger(params->common.events, optarg);
+ else
fatal("--trigger requires a previous -e");
- }
break;
case '5': /* filter */
- if (params->common.events) {
- retval = trace_event_add_filter(params->common.events, optarg);
- if (retval)
- fatal("Error adding filter %s", optarg);
- } else {
+ if (params->common.events)
+ trace_event_add_filter(params->common.events, optarg);
+ else
fatal("--filter requires a previous -e");
- }
break;
case '6':
params->common.warmup = get_llong_from_str(optarg);
diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c
index d54d47947fb44..d2b4ac64e77b4 100644
--- a/tools/tracing/rtla/src/osnoise_top.c
+++ b/tools/tracing/rtla/src/osnoise_top.c
@@ -319,9 +319,7 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv)
int c;
char *trace_output = NULL;
- params = calloc(1, sizeof(*params));
- if (!params)
- exit(1);
+ params = calloc_fatal(1, sizeof(*params));
actions_init(¶ms->common.threshold_actions);
actions_init(¶ms->common.end_actions);
@@ -410,22 +408,16 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv)
params->threshold = get_llong_from_str(optarg);
break;
case '0': /* trigger */
- if (params->common.events) {
- retval = trace_event_add_trigger(params->common.events, optarg);
- if (retval)
- fatal("Error adding trigger %s", optarg);
- } else {
+ if (params->common.events)
+ trace_event_add_trigger(params->common.events, optarg);
+ else
fatal("--trigger requires a previous -e");
- }
break;
case '1': /* filter */
- if (params->common.events) {
- retval = trace_event_add_filter(params->common.events, optarg);
- if (retval)
- fatal("Error adding filter %s", optarg);
- } else {
+ if (params->common.events)
+ trace_event_add_filter(params->common.events, optarg);
+ else
fatal("--filter requires a previous -e");
- }
break;
case '2':
params->common.warmup = get_llong_from_str(optarg);
diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c
index 4e8c38a61197c..6ea397421f1c9 100644
--- a/tools/tracing/rtla/src/timerlat_hist.c
+++ b/tools/tracing/rtla/src/timerlat_hist.c
@@ -766,9 +766,7 @@ static struct common_params
int c;
char *trace_output = NULL;
- params = calloc(1, sizeof(*params));
- if (!params)
- exit(1);
+ params = calloc_fatal(1, sizeof(*params));
actions_init(¶ms->common.threshold_actions);
actions_init(¶ms->common.end_actions);
@@ -914,22 +912,16 @@ static struct common_params
params->common.hist.with_zeros = 1;
break;
case '6': /* trigger */
- if (params->common.events) {
- retval = trace_event_add_trigger(params->common.events, optarg);
- if (retval)
- fatal("Error adding trigger %s", optarg);
- } else {
+ if (params->common.events)
+ trace_event_add_trigger(params->common.events, optarg);
+ else
fatal("--trigger requires a previous -e");
- }
break;
case '7': /* filter */
- if (params->common.events) {
- retval = trace_event_add_filter(params->common.events, optarg);
- if (retval)
- fatal("Error adding filter %s", optarg);
- } else {
+ if (params->common.events)
+ trace_event_add_filter(params->common.events, optarg);
+ else
fatal("--filter requires a previous -e");
- }
break;
case '8':
params->dma_latency = get_llong_from_str(optarg);
diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c
index 284b74773c2b5..dd727cb48b551 100644
--- a/tools/tracing/rtla/src/timerlat_top.c
+++ b/tools/tracing/rtla/src/timerlat_top.c
@@ -537,9 +537,7 @@ static struct common_params
int c;
char *trace_output = NULL;
- params = calloc(1, sizeof(*params));
- if (!params)
- exit(1);
+ params = calloc_fatal(1, sizeof(*params));
actions_init(¶ms->common.threshold_actions);
actions_init(¶ms->common.end_actions);
@@ -664,22 +662,16 @@ static struct common_params
params->common.user_data = true;
break;
case '0': /* trigger */
- if (params->common.events) {
- retval = trace_event_add_trigger(params->common.events, optarg);
- if (retval)
- fatal("Error adding trigger %s", optarg);
- } else {
+ if (params->common.events)
+ trace_event_add_trigger(params->common.events, optarg);
+ else
fatal("--trigger requires a previous -e");
- }
break;
case '1': /* filter */
- if (params->common.events) {
- retval = trace_event_add_filter(params->common.events, optarg);
- if (retval)
- fatal("Error adding filter %s", optarg);
- } else {
+ if (params->common.events)
+ trace_event_add_filter(params->common.events, optarg);
+ else
fatal("--filter requires a previous -e");
- }
break;
case '2': /* dma-latency */
params->dma_latency = get_llong_from_str(optarg);
diff --git a/tools/tracing/rtla/src/trace.c b/tools/tracing/rtla/src/trace.c
index b8be3e28680ee..211ca54b15b0e 100644
--- a/tools/tracing/rtla/src/trace.c
+++ b/tools/tracing/rtla/src/trace.c
@@ -191,9 +191,7 @@ void trace_instance_destroy(struct trace_instance *trace)
*/
int trace_instance_init(struct trace_instance *trace, char *tool_name)
{
- trace->seq = calloc(1, sizeof(*trace->seq));
- if (!trace->seq)
- goto out_err;
+ trace->seq = calloc_fatal(1, sizeof(*trace->seq));
trace_seq_init(trace->seq);
@@ -274,15 +272,9 @@ struct trace_events *trace_event_alloc(const char *event_string)
{
struct trace_events *tevent;
- tevent = calloc(1, sizeof(*tevent));
- if (!tevent)
- return NULL;
+ tevent = calloc_fatal(1, sizeof(*tevent));
- tevent->system = strdup(event_string);
- if (!tevent->system) {
- free(tevent);
- return NULL;
- }
+ tevent->system = strdup_fatal(event_string);
tevent->event = strstr(tevent->system, ":");
if (tevent->event) {
@@ -296,31 +288,23 @@ struct trace_events *trace_event_alloc(const char *event_string)
/*
* trace_event_add_filter - record an event filter
*/
-int trace_event_add_filter(struct trace_events *event, char *filter)
+void trace_event_add_filter(struct trace_events *event, char *filter)
{
if (event->filter)
free(event->filter);
- event->filter = strdup(filter);
- if (!event->filter)
- return 1;
-
- return 0;
+ event->filter = strdup_fatal(filter);
}
/*
* trace_event_add_trigger - record an event trigger action
*/
-int trace_event_add_trigger(struct trace_events *event, char *trigger)
+void trace_event_add_trigger(struct trace_events *event, char *trigger)
{
if (event->trigger)
free(event->trigger);
- event->trigger = strdup(trigger);
- if (!event->trigger)
- return 1;
-
- return 0;
+ event->trigger = strdup_fatal(trigger);
}
/*
diff --git a/tools/tracing/rtla/src/trace.h b/tools/tracing/rtla/src/trace.h
index 1e5aee4b828dd..95b911a2228b2 100644
--- a/tools/tracing/rtla/src/trace.h
+++ b/tools/tracing/rtla/src/trace.h
@@ -45,6 +45,6 @@ void trace_events_destroy(struct trace_instance *instance,
int trace_events_enable(struct trace_instance *instance,
struct trace_events *events);
-int trace_event_add_filter(struct trace_events *event, char *filter);
-int trace_event_add_trigger(struct trace_events *event, char *trigger);
+void trace_event_add_filter(struct trace_events *event, char *filter);
+void trace_event_add_trigger(struct trace_events *event, char *trigger);
int trace_set_buffer_size(struct trace_instance *trace, int size);
diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c
index 18986a5aed3c1..75cdcc63d5a15 100644
--- a/tools/tracing/rtla/src/utils.c
+++ b/tools/tracing/rtla/src/utils.c
@@ -1032,3 +1032,38 @@ int strtoi(const char *s, int *res)
*res = (int) lres;
return 0;
}
+
+static inline void fatal_alloc(void)
+{
+ fatal("Error allocating memory\n");
+}
+
+void *calloc_fatal(size_t n, size_t size)
+{
+ void *p = calloc(n, size);
+
+ if (!p)
+ fatal_alloc();
+
+ return p;
+}
+
+void *reallocarray_fatal(void *p, size_t n, size_t size)
+{
+ p = reallocarray(p, n, size);
+
+ if (!p)
+ fatal_alloc();
+
+ return p;
+}
+
+char *strdup_fatal(const char *s)
+{
+ char *p = strdup(s);
+
+ if (!p)
+ fatal_alloc();
+
+ return p;
+}
diff --git a/tools/tracing/rtla/src/utils.h b/tools/tracing/rtla/src/utils.h
index f7c2a52a0ab54..e29c2eb5d569d 100644
--- a/tools/tracing/rtla/src/utils.h
+++ b/tools/tracing/rtla/src/utils.h
@@ -69,6 +69,9 @@ int set_comm_sched_attr(const char *comm_prefix, struct sched_attr *attr);
int set_comm_cgroup(const char *comm_prefix, const char *cgroup);
int set_pid_cgroup(pid_t pid, const char *cgroup);
int set_cpu_dma_latency(int32_t latency);
+void *calloc_fatal(size_t n, size_t size);
+void *reallocarray_fatal(void *p, size_t n, size_t size);
+char *strdup_fatal(const char *s);
#ifdef HAVE_LIBCPUPOWER_SUPPORT
int save_cpu_idle_disable_state(unsigned int cpu);
int restore_cpu_idle_disable_state(unsigned int cpu);
--
2.52.0
^ permalink raw reply related
* [PATCH v3 02/18] rtla: Use strdup() to simplify code
From: Wander Lairson Costa @ 2026-01-15 16:31 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Crystal Wood,
Ivan Pravdin, Costa Shulyupin, John Kacur, Tiezhu Yang,
Daniel Wagner, Daniel Bristot de Oliveira,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
In-Reply-To: <20260115163650.118910-1-wander@redhat.com>
The actions_add_trace_output() and actions_add_shell() functions were
using calloc() followed by strcpy() to allocate and copy a string.
This can be simplified by using strdup(), which allocates memory and
copies the string in a single step.
Replace the calloc() and strcpy() calls with strdup(), making the
code more concise and readable.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/actions.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/tools/tracing/rtla/src/actions.c b/tools/tracing/rtla/src/actions.c
index 22b8283a183f3..0ac42ffd734a3 100644
--- a/tools/tracing/rtla/src/actions.c
+++ b/tools/tracing/rtla/src/actions.c
@@ -69,8 +69,7 @@ actions_add_trace_output(struct actions *self, const char *trace_output)
self->present[ACTION_TRACE_OUTPUT] = true;
action->type = ACTION_TRACE_OUTPUT;
- action->trace_output = calloc_fatal(strlen(trace_output) + 1, sizeof(char));
- strcpy(action->trace_output, trace_output);
+ action->trace_output = strdup_fatal(trace_output);
}
/*
@@ -97,8 +96,7 @@ actions_add_shell(struct actions *self, const char *command)
self->present[ACTION_SHELL] = true;
action->type = ACTION_SHELL;
- action->command = calloc_fatal(strlen(command) + 1, sizeof(char));
- strcpy(action->command, command);
+ action->command = strdup_fatal(command);
}
/*
--
2.52.0
^ permalink raw reply related
* [PATCH v3 03/18] rtla: Simplify argument parsing
From: Wander Lairson Costa @ 2026-01-15 16:31 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Crystal Wood,
Ivan Pravdin, Costa Shulyupin, John Kacur, Haiyong Sun,
Tiezhu Yang, Daniel Wagner, Daniel Bristot de Oliveira,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
In-Reply-To: <20260115163650.118910-1-wander@redhat.com>
The actions_parse() function uses open-coded logic to extract arguments
from a string. This includes manual length checks and strncmp() calls,
which can be verbose and error-prone.
To simplify and improve the robustness of argument parsing, introduce a
new extract_arg() helper macro. This macro extracts the value from a
"key=value" pair, making the code more concise and readable.
Also, introduce STRING_LENGTH() and strncmp_static() macros to
perform compile-time calculations of string lengths and safer string
comparisons.
Refactor actions_parse() to use these new helpers, resulting in
cleaner and more maintainable code.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/actions.c | 57 +++++++++++++++++++++++---------
tools/tracing/rtla/src/utils.h | 14 ++++++--
2 files changed, 54 insertions(+), 17 deletions(-)
diff --git a/tools/tracing/rtla/src/actions.c b/tools/tracing/rtla/src/actions.c
index 0ac42ffd734a3..b0d68b5de08db 100644
--- a/tools/tracing/rtla/src/actions.c
+++ b/tools/tracing/rtla/src/actions.c
@@ -111,6 +111,29 @@ actions_add_continue(struct actions *self)
action->type = ACTION_CONTINUE;
}
+static inline const char *__extract_arg(const char *token, const char *opt, size_t opt_len)
+{
+ const size_t tok_len = strlen(token);
+
+ if (tok_len <= opt_len)
+ return NULL;
+
+ if (strncmp(token, opt, opt_len))
+ return NULL;
+
+ return token + opt_len;
+}
+
+/*
+ * extract_arg - extract argument value from option token
+ * @token: option token (e.g., "file=trace.txt")
+ * @opt: option name to match (e.g., "file")
+ *
+ * Returns pointer to argument value after "=" if token matches "opt=",
+ * otherwise returns NULL.
+ */
+#define extract_arg(token, opt) __extract_arg(token, opt "=", STRING_LENGTH(opt "="))
+
/*
* actions_parse - add an action based on text specification
*/
@@ -120,6 +143,7 @@ actions_parse(struct actions *self, const char *trigger, const char *tracefn)
enum action_type type = ACTION_NONE;
const char *token;
char trigger_c[strlen(trigger) + 1];
+ const char *arg_value;
/* For ACTION_SIGNAL */
int signal = 0, pid = 0;
@@ -152,12 +176,10 @@ actions_parse(struct actions *self, const char *trigger, const char *tracefn)
if (token == NULL)
trace_output = tracefn;
else {
- if (strlen(token) > 5 && strncmp(token, "file=", 5) == 0) {
- trace_output = token + 5;
- } else {
+ trace_output = extract_arg(token, "file");
+ if (!trace_output)
/* Invalid argument */
return -1;
- }
token = strtok(NULL, ",");
if (token != NULL)
@@ -169,17 +191,21 @@ actions_parse(struct actions *self, const char *trigger, const char *tracefn)
case ACTION_SIGNAL:
/* Takes two arguments, num (signal) and pid */
while (token != NULL) {
- if (strlen(token) > 4 && strncmp(token, "num=", 4) == 0) {
- if (strtoi(token + 4, &signal))
- return -1;
- } else if (strlen(token) > 4 && strncmp(token, "pid=", 4) == 0) {
- if (strncmp(token + 4, "parent", 7) == 0)
- pid = -1;
- else if (strtoi(token + 4, &pid))
+ arg_value = extract_arg(token, "num");
+ if (arg_value) {
+ if (strtoi(arg_value, &signal))
return -1;
} else {
- /* Invalid argument */
- return -1;
+ arg_value = extract_arg(token, "pid");
+ if (arg_value) {
+ if (strncmp_static(arg_value, "parent") == 0)
+ pid = -1;
+ else if (strtoi(arg_value, &pid))
+ return -1;
+ } else {
+ /* Invalid argument */
+ return -1;
+ }
}
token = strtok(NULL, ",");
@@ -194,9 +220,10 @@ actions_parse(struct actions *self, const char *trigger, const char *tracefn)
case ACTION_SHELL:
if (token == NULL)
return -1;
- if (strlen(token) > 8 && strncmp(token, "command=", 8))
+ arg_value = extract_arg(token, "command");
+ if (!arg_value)
return -1;
- actions_add_shell(self, token + 8);
+ actions_add_shell(self, arg_value);
break;
case ACTION_CONTINUE:
/* Takes no argument */
diff --git a/tools/tracing/rtla/src/utils.h b/tools/tracing/rtla/src/utils.h
index e29c2eb5d569d..8323c999260c2 100644
--- a/tools/tracing/rtla/src/utils.h
+++ b/tools/tracing/rtla/src/utils.h
@@ -14,8 +14,18 @@
#define MAX_NICE 20
#define MIN_NICE -19
-#define container_of(ptr, type, member)({ \
- const typeof(((type *)0)->member) *__mptr = (ptr); \
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+#endif
+
+/* Calculate string length at compile time (excluding null terminator) */
+#define STRING_LENGTH(s) (ARRAY_SIZE(s) - sizeof(*(s)))
+
+/* Compare string with static string, length determined at compile time */
+#define strncmp_static(s1, s2) strncmp(s1, s2, ARRAY_SIZE(s2))
+
+#define container_of(ptr, type, member)({ \
+ const typeof(((type *)0)->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)) ; })
extern int config_debug;
--
2.52.0
^ permalink raw reply related
* [PATCH v3 04/18] rtla: Introduce common_threshold_handler() helper
From: Wander Lairson Costa @ 2026-01-15 16:31 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Ivan Pravdin,
Crystal Wood, Costa Shulyupin, John Kacur, Tiezhu Yang,
Daniel Wagner, Daniel Bristot de Oliveira,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
In-Reply-To: <20260115163650.118910-1-wander@redhat.com>
Several functions duplicate the logic for handling threshold actions.
When a threshold is reached, these functions stop the trace, perform
configured actions, and restart the trace if --on-threshold continue
is set.
Create common_threshold_handler() to centralize this shared logic and
avoid code duplication. The function executes the configured threshold
actions and restarts the necessary trace instances when appropriate.
Also add should_continue_tracing() helper to encapsulate the check
for whether tracing should continue after a threshold event, improving
code readability at call sites.
In timerlat_top_bpf_main_loop(), use common_params directly instead
of casting through timerlat_params when only common fields are needed.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/common.c | 61 ++++++++++++++++++--------
tools/tracing/rtla/src/common.h | 18 ++++++++
tools/tracing/rtla/src/timerlat_hist.c | 19 ++++----
tools/tracing/rtla/src/timerlat_top.c | 32 +++++++-------
4 files changed, 86 insertions(+), 44 deletions(-)
diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c
index ceff76a62a30b..cbc207fa58707 100644
--- a/tools/tracing/rtla/src/common.c
+++ b/tools/tracing/rtla/src/common.c
@@ -175,6 +175,38 @@ common_apply_config(struct osnoise_tool *tool, struct common_params *params)
}
+/**
+ * common_threshold_handler - handle latency threshold overflow
+ * @tool: pointer to the osnoise_tool instance containing trace contexts
+ *
+ * Executes the configured threshold actions (e.g., saving trace, printing,
+ * sending signals). If the continue flag is set (--on-threshold continue),
+ * restarts the auxiliary trace instances to continue monitoring.
+ *
+ * Return: 0 for success, -1 for error.
+ */
+int
+common_threshold_handler(const struct osnoise_tool *tool)
+{
+ actions_perform(&tool->params->threshold_actions);
+
+ if (!should_continue_tracing(tool->params))
+ /* continue flag not set, break */
+ return 0;
+
+ /* continue action reached, re-enable tracing */
+ if (tool->record && trace_instance_start(&tool->record->trace))
+ goto err;
+ if (tool->aa && trace_instance_start(&tool->aa->trace))
+ goto err;
+
+ return 0;
+
+err:
+ err_msg("Error restarting trace\n");
+ return -1;
+}
+
int run_tool(struct tool_ops *ops, int argc, char *argv[])
{
struct common_params *params;
@@ -352,17 +384,14 @@ int top_main_loop(struct osnoise_tool *tool)
/* stop tracing requested, do not perform actions */
return 0;
- actions_perform(¶ms->threshold_actions);
+ retval = common_threshold_handler(tool);
+ if (retval)
+ return retval;
+
- if (!params->threshold_actions.continue_flag)
- /* continue flag not set, break */
+ if (!should_continue_tracing(params))
return 0;
- /* continue action reached, re-enable tracing */
- if (record)
- trace_instance_start(&record->trace);
- if (tool->aa)
- trace_instance_start(&tool->aa->trace);
trace_instance_start(trace);
}
@@ -403,18 +432,14 @@ int hist_main_loop(struct osnoise_tool *tool)
/* stop tracing requested, do not perform actions */
break;
- actions_perform(¶ms->threshold_actions);
+ retval = common_threshold_handler(tool);
+ if (retval)
+ return retval;
- if (!params->threshold_actions.continue_flag)
- /* continue flag not set, break */
- break;
+ if (!should_continue_tracing(params))
+ return 0;
- /* continue action reached, re-enable tracing */
- if (tool->record)
- trace_instance_start(&tool->record->trace);
- if (tool->aa)
- trace_instance_start(&tool->aa->trace);
- trace_instance_start(&tool->trace);
+ trace_instance_start(trace);
}
/* is there still any user-threads ? */
diff --git a/tools/tracing/rtla/src/common.h b/tools/tracing/rtla/src/common.h
index 7602c5593ef5d..c548decd3c40f 100644
--- a/tools/tracing/rtla/src/common.h
+++ b/tools/tracing/rtla/src/common.h
@@ -143,6 +143,24 @@ struct tool_ops {
void (*free)(struct osnoise_tool *tool);
};
+/**
+ * should_continue_tracing - check if tracing should continue after threshold
+ * @params: pointer to the common parameters structure
+ *
+ * Returns true if the continue action was configured (--on-threshold continue),
+ * indicating that tracing should be restarted after handling the threshold event.
+ *
+ * Return: 1 if tracing should continue, 0 otherwise.
+ */
+static inline int
+should_continue_tracing(const struct common_params *params)
+{
+ return params->threshold_actions.continue_flag;
+}
+
+int
+common_threshold_handler(const struct osnoise_tool *tool);
+
int osnoise_set_cpus(struct osnoise_context *context, char *cpus);
void osnoise_restore_cpus(struct osnoise_context *context);
diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c
index 6ea397421f1c9..6b8eaef8a3a09 100644
--- a/tools/tracing/rtla/src/timerlat_hist.c
+++ b/tools/tracing/rtla/src/timerlat_hist.c
@@ -17,6 +17,7 @@
#include "timerlat.h"
#include "timerlat_aa.h"
#include "timerlat_bpf.h"
+#include "common.h"
struct timerlat_hist_cpu {
int *irq;
@@ -1048,7 +1049,6 @@ static struct osnoise_tool
static int timerlat_hist_bpf_main_loop(struct osnoise_tool *tool)
{
- struct timerlat_params *params = to_timerlat_params(tool->params);
int retval;
while (!stop_tracing) {
@@ -1056,18 +1056,17 @@ static int timerlat_hist_bpf_main_loop(struct osnoise_tool *tool)
if (!stop_tracing) {
/* Threshold overflow, perform actions on threshold */
- actions_perform(¶ms->common.threshold_actions);
+ retval = common_threshold_handler(tool);
+ if (retval)
+ return retval;
- if (!params->common.threshold_actions.continue_flag)
- /* continue flag not set, break */
+ if (!should_continue_tracing(tool->params))
break;
- /* continue action reached, re-enable tracing */
- if (tool->record)
- trace_instance_start(&tool->record->trace);
- if (tool->aa)
- trace_instance_start(&tool->aa->trace);
- timerlat_bpf_restart_tracing();
+ if (timerlat_bpf_restart_tracing()) {
+ err_msg("Error restarting BPF trace\n");
+ return -1;
+ }
}
}
timerlat_bpf_detach();
diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c
index dd727cb48b551..c6f6757c3fb6b 100644
--- a/tools/tracing/rtla/src/timerlat_top.c
+++ b/tools/tracing/rtla/src/timerlat_top.c
@@ -17,6 +17,7 @@
#include "timerlat.h"
#include "timerlat_aa.h"
#include "timerlat_bpf.h"
+#include "common.h"
struct timerlat_top_cpu {
unsigned long long irq_count;
@@ -801,10 +802,10 @@ static struct osnoise_tool
static int
timerlat_top_bpf_main_loop(struct osnoise_tool *tool)
{
- struct timerlat_params *params = to_timerlat_params(tool->params);
+ const struct common_params *params = tool->params;
int retval, wait_retval;
- if (params->common.aa_only) {
+ if (params->aa_only) {
/* Auto-analysis only, just wait for stop tracing */
timerlat_bpf_wait(-1);
return 0;
@@ -812,8 +813,8 @@ timerlat_top_bpf_main_loop(struct osnoise_tool *tool)
/* Pull and display data in a loop */
while (!stop_tracing) {
- wait_retval = timerlat_bpf_wait(params->common.quiet ? -1 :
- params->common.sleep_time);
+ wait_retval = timerlat_bpf_wait(params->quiet ? -1 :
+ params->sleep_time);
retval = timerlat_top_bpf_pull_data(tool);
if (retval) {
@@ -821,28 +822,27 @@ timerlat_top_bpf_main_loop(struct osnoise_tool *tool)
return retval;
}
- if (!params->common.quiet)
+ if (!params->quiet)
timerlat_print_stats(tool);
if (wait_retval != 0) {
/* Stopping requested by tracer */
- actions_perform(¶ms->common.threshold_actions);
+ retval = common_threshold_handler(tool);
+ if (retval)
+ return retval;
- if (!params->common.threshold_actions.continue_flag)
- /* continue flag not set, break */
+ if (!should_continue_tracing(tool->params))
break;
- /* continue action reached, re-enable tracing */
- if (tool->record)
- trace_instance_start(&tool->record->trace);
- if (tool->aa)
- trace_instance_start(&tool->aa->trace);
- timerlat_bpf_restart_tracing();
+ if (timerlat_bpf_restart_tracing()) {
+ err_msg("Error restarting BPF trace\n");
+ return -1;
+ }
}
/* is there still any user-threads ? */
- if (params->common.user_workload) {
- if (params->common.user.stopped_running) {
+ if (params->user_workload) {
+ if (params->user.stopped_running) {
debug_msg("timerlat user space threads stopped!\n");
break;
}
--
2.52.0
^ permalink raw reply related
* [PATCH v3 05/18] rtla: Replace magic number with MAX_PATH
From: Wander Lairson Costa @ 2026-01-15 16:31 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Ivan Pravdin,
Crystal Wood, Costa Shulyupin, John Kacur, Tiezhu Yang,
Daniel Wagner, Daniel Bristot de Oliveira,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
In-Reply-To: <20260115163650.118910-1-wander@redhat.com>
The trace functions use a buffer to manipulate strings that will be
written to tracefs files. These buffers are defined with a magic number
of 1024, which is a common source of vulnerabilities.
Replace the magic number 1024 with the MAX_PATH macro to make the code
safer and more readable. While at it, replace other instances of the
magic number with ARRAY_SIZE() when the buffer is locally defined.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/osnoise.c | 4 ++--
tools/tracing/rtla/src/timerlat_u.c | 4 ++--
tools/tracing/rtla/src/trace.c | 20 ++++++++++----------
3 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/tools/tracing/rtla/src/osnoise.c b/tools/tracing/rtla/src/osnoise.c
index ec074cd53dd84..4890a9a9d6466 100644
--- a/tools/tracing/rtla/src/osnoise.c
+++ b/tools/tracing/rtla/src/osnoise.c
@@ -52,7 +52,7 @@ char *osnoise_get_cpus(struct osnoise_context *context)
int osnoise_set_cpus(struct osnoise_context *context, char *cpus)
{
char *orig_cpus = osnoise_get_cpus(context);
- char buffer[1024];
+ char buffer[MAX_PATH];
int retval;
if (!orig_cpus)
@@ -62,7 +62,7 @@ int osnoise_set_cpus(struct osnoise_context *context, char *cpus)
if (!context->curr_cpus)
return -1;
- snprintf(buffer, 1024, "%s\n", cpus);
+ snprintf(buffer, ARRAY_SIZE(buffer), "%s\n", cpus);
debug_msg("setting cpus to %s from %s", cpus, context->orig_cpus);
diff --git a/tools/tracing/rtla/src/timerlat_u.c b/tools/tracing/rtla/src/timerlat_u.c
index ce68e39d25fde..efe2f72686486 100644
--- a/tools/tracing/rtla/src/timerlat_u.c
+++ b/tools/tracing/rtla/src/timerlat_u.c
@@ -32,7 +32,7 @@
static int timerlat_u_main(int cpu, struct timerlat_u_params *params)
{
struct sched_param sp = { .sched_priority = 95 };
- char buffer[1024];
+ char buffer[MAX_PATH];
int timerlat_fd;
cpu_set_t set;
int retval;
@@ -83,7 +83,7 @@ static int timerlat_u_main(int cpu, struct timerlat_u_params *params)
/* add should continue with a signal handler */
while (true) {
- retval = read(timerlat_fd, buffer, 1024);
+ retval = read(timerlat_fd, buffer, ARRAY_SIZE(buffer));
if (retval < 0)
break;
}
diff --git a/tools/tracing/rtla/src/trace.c b/tools/tracing/rtla/src/trace.c
index 211ca54b15b0e..e1af54f9531b8 100644
--- a/tools/tracing/rtla/src/trace.c
+++ b/tools/tracing/rtla/src/trace.c
@@ -313,7 +313,7 @@ void trace_event_add_trigger(struct trace_events *event, char *trigger)
static void trace_event_disable_filter(struct trace_instance *instance,
struct trace_events *tevent)
{
- char filter[1024];
+ char filter[MAX_PATH];
int retval;
if (!tevent->filter)
@@ -325,7 +325,7 @@ static void trace_event_disable_filter(struct trace_instance *instance,
debug_msg("Disabling %s:%s filter %s\n", tevent->system,
tevent->event ? : "*", tevent->filter);
- snprintf(filter, 1024, "!%s\n", tevent->filter);
+ snprintf(filter, ARRAY_SIZE(filter), "!%s\n", tevent->filter);
retval = tracefs_event_file_write(instance->inst, tevent->system,
tevent->event, "filter", filter);
@@ -344,7 +344,7 @@ static void trace_event_save_hist(struct trace_instance *instance,
{
int retval, index, out_fd;
mode_t mode = 0644;
- char path[1024];
+ char path[MAX_PATH];
char *hist;
if (!tevent)
@@ -359,7 +359,7 @@ static void trace_event_save_hist(struct trace_instance *instance,
if (retval)
return;
- snprintf(path, 1024, "%s_%s_hist.txt", tevent->system, tevent->event);
+ snprintf(path, ARRAY_SIZE(path), "%s_%s_hist.txt", tevent->system, tevent->event);
printf(" Saving event %s:%s hist to %s\n", tevent->system, tevent->event, path);
@@ -391,7 +391,7 @@ static void trace_event_save_hist(struct trace_instance *instance,
static void trace_event_disable_trigger(struct trace_instance *instance,
struct trace_events *tevent)
{
- char trigger[1024];
+ char trigger[MAX_PATH];
int retval;
if (!tevent->trigger)
@@ -405,7 +405,7 @@ static void trace_event_disable_trigger(struct trace_instance *instance,
trace_event_save_hist(instance, tevent);
- snprintf(trigger, 1024, "!%s\n", tevent->trigger);
+ snprintf(trigger, ARRAY_SIZE(trigger), "!%s\n", tevent->trigger);
retval = tracefs_event_file_write(instance->inst, tevent->system,
tevent->event, "trigger", trigger);
@@ -444,7 +444,7 @@ void trace_events_disable(struct trace_instance *instance,
static int trace_event_enable_filter(struct trace_instance *instance,
struct trace_events *tevent)
{
- char filter[1024];
+ char filter[MAX_PATH];
int retval;
if (!tevent->filter)
@@ -456,7 +456,7 @@ static int trace_event_enable_filter(struct trace_instance *instance,
return 1;
}
- snprintf(filter, 1024, "%s\n", tevent->filter);
+ snprintf(filter, ARRAY_SIZE(filter), "%s\n", tevent->filter);
debug_msg("Enabling %s:%s filter %s\n", tevent->system,
tevent->event ? : "*", tevent->filter);
@@ -479,7 +479,7 @@ static int trace_event_enable_filter(struct trace_instance *instance,
static int trace_event_enable_trigger(struct trace_instance *instance,
struct trace_events *tevent)
{
- char trigger[1024];
+ char trigger[MAX_PATH];
int retval;
if (!tevent->trigger)
@@ -491,7 +491,7 @@ static int trace_event_enable_trigger(struct trace_instance *instance,
return 1;
}
- snprintf(trigger, 1024, "%s\n", tevent->trigger);
+ snprintf(trigger, ARRAY_SIZE(trigger), "%s\n", tevent->trigger);
debug_msg("Enabling %s:%s trigger %s\n", tevent->system,
tevent->event ? : "*", tevent->trigger);
--
2.52.0
^ permalink raw reply related
* [PATCH v3 06/18] rtla: Simplify code by caching string lengths
From: Wander Lairson Costa @ 2026-01-15 16:31 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Ivan Pravdin,
Crystal Wood, Costa Shulyupin, John Kacur, Tiezhu Yang,
Daniel Wagner, Daniel Bristot de Oliveira,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
In-Reply-To: <20260115163650.118910-1-wander@redhat.com>
Simplify trace_event_save_hist() and set_comm_cgroup() by computing
string lengths once and storing them in local variables, rather than
calling strlen() multiple times on the same unchanged strings. This
makes the code clearer by eliminating redundant function calls and
improving readability.
In trace_event_save_hist(), the write loop previously called strlen()
on the hist buffer twice per iteration for both the size calculation
and loop condition. Store the length in hist_len before entering the
loop. In set_comm_cgroup(), strlen() was called on cgroup_path up to
three times in succession. Store the result in cg_path_len to use in
both the offset calculation and size parameter for subsequent append
operations.
This simplification makes the code easier to read and maintain without
changing program behavior.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/trace.c | 6 ++++--
tools/tracing/rtla/src/utils.c | 11 +++++++----
2 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/tools/tracing/rtla/src/trace.c b/tools/tracing/rtla/src/trace.c
index e1af54f9531b8..2f529aaf8deef 100644
--- a/tools/tracing/rtla/src/trace.c
+++ b/tools/tracing/rtla/src/trace.c
@@ -346,6 +346,7 @@ static void trace_event_save_hist(struct trace_instance *instance,
mode_t mode = 0644;
char path[MAX_PATH];
char *hist;
+ size_t hist_len;
if (!tevent)
return;
@@ -376,9 +377,10 @@ static void trace_event_save_hist(struct trace_instance *instance,
}
index = 0;
+ hist_len = strlen(hist);
do {
- index += write(out_fd, &hist[index], strlen(hist) - index);
- } while (index < strlen(hist));
+ index += write(out_fd, &hist[index], hist_len - index);
+ } while (index < hist_len);
free(hist);
out_close:
diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c
index 75cdcc63d5a15..b5a6007b108d2 100644
--- a/tools/tracing/rtla/src/utils.c
+++ b/tools/tracing/rtla/src/utils.c
@@ -811,6 +811,7 @@ static int open_cgroup_procs(const char *cgroup)
char cgroup_procs[MAX_PATH];
int retval;
int cg_fd;
+ size_t cg_path_len;
retval = find_mount("cgroup2", cgroup_path, sizeof(cgroup_path));
if (!retval) {
@@ -818,16 +819,18 @@ static int open_cgroup_procs(const char *cgroup)
return -1;
}
+ cg_path_len = strlen(cgroup_path);
+
if (!cgroup) {
- retval = get_self_cgroup(&cgroup_path[strlen(cgroup_path)],
- sizeof(cgroup_path) - strlen(cgroup_path));
+ retval = get_self_cgroup(&cgroup_path[cg_path_len],
+ sizeof(cgroup_path) - cg_path_len);
if (!retval) {
err_msg("Did not find self cgroup\n");
return -1;
}
} else {
- snprintf(&cgroup_path[strlen(cgroup_path)],
- sizeof(cgroup_path) - strlen(cgroup_path), "%s/", cgroup);
+ snprintf(&cgroup_path[cg_path_len],
+ sizeof(cgroup_path) - cg_path_len, "%s/", cgroup);
}
snprintf(cgroup_procs, MAX_PATH, "%s/cgroup.procs", cgroup_path);
--
2.52.0
^ permalink raw reply related
* [PATCH v3 07/18] rtla: Add strscpy() and replace strncpy() calls
From: Wander Lairson Costa @ 2026-01-15 16:31 UTC (permalink / raw)
To: Steven Rostedt, Tomas Glozar, Wander Lairson Costa, Crystal Wood,
Ivan Pravdin, Costa Shulyupin, John Kacur, Tiezhu Yang,
Haiyong Sun, Daniel Wagner, Daniel Bristot de Oliveira,
open list:Real-time Linux Analysis (RTLA) tools,
open list:Real-time Linux Analysis (RTLA) tools,
open list:BPF [MISC]:Keyword:(?:b|_)bpf(?:b|_)
In-Reply-To: <20260115163650.118910-1-wander@redhat.com>
Introduce a userspace strscpy() implementation that matches the Linux
kernel's strscpy() semantics. The function is built on top of glibc's
strlcpy() and provides guaranteed NUL-termination along with proper
truncation detection through its return value.
The previous strncpy() calls had potential issues: strncpy() does not
guarantee NUL-termination when the source string length equals or
exceeds the destination buffer size. This required defensive patterns
like pre-zeroing buffers or manually setting the last byte to NUL.
The new strscpy() function always NUL-terminates the destination buffer
unless the size is zero, and returns -E2BIG on truncation, making error
handling cleaner and more consistent with kernel code.
Note that unlike the kernel's strscpy(), this implementation uses
strlcpy() internally, which reads the entire source string to determine
its length. The kernel avoids this to prevent potential DoS attacks from
extremely long untrusted strings. This is harmless for a userspace CLI
tool like rtla where input sources are bounded and trusted.
Replace all strncpy() calls in rtla with strscpy(), using sizeof() for
buffer sizes instead of magic constants to ensure the sizes stay in
sync with the actual buffer declarations. Also remove a now-redundant
memset() call that was previously needed to work around strncpy()
behavior.
Signed-off-by: Wander Lairson Costa <wander@redhat.com>
---
tools/tracing/rtla/src/timerlat_aa.c | 6 ++---
tools/tracing/rtla/src/utils.c | 34 ++++++++++++++++++++++++++--
tools/tracing/rtla/src/utils.h | 1 +
3 files changed, 36 insertions(+), 5 deletions(-)
diff --git a/tools/tracing/rtla/src/timerlat_aa.c b/tools/tracing/rtla/src/timerlat_aa.c
index 31e66ea2b144c..30ef56d644f9c 100644
--- a/tools/tracing/rtla/src/timerlat_aa.c
+++ b/tools/tracing/rtla/src/timerlat_aa.c
@@ -455,9 +455,9 @@ static int timerlat_aa_thread_handler(struct trace_seq *s, struct tep_record *re
taa_data->thread_blocking_duration = duration;
if (comm)
- strncpy(taa_data->run_thread_comm, comm, MAX_COMM);
+ strscpy(taa_data->run_thread_comm, comm, sizeof(taa_data->run_thread_comm));
else
- sprintf(taa_data->run_thread_comm, "<...>");
+ strscpy(taa_data->run_thread_comm, "<...>", sizeof(taa_data->run_thread_comm));
} else {
taa_data->thread_thread_sum += duration;
@@ -519,7 +519,7 @@ static int timerlat_aa_sched_switch_handler(struct trace_seq *s, struct tep_reco
tep_get_field_val(s, event, "next_pid", record, &taa_data->current_pid, 1);
comm = tep_get_field_raw(s, event, "next_comm", record, &val, 1);
- strncpy(taa_data->current_comm, comm, MAX_COMM);
+ strscpy(taa_data->current_comm, comm, sizeof(taa_data->current_comm));
/*
* If this was a kworker, clean the last kworkers that ran.
diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c
index b5a6007b108d2..e98288e55db15 100644
--- a/tools/tracing/rtla/src/utils.c
+++ b/tools/tracing/rtla/src/utils.c
@@ -722,8 +722,7 @@ static const int find_mount(const char *fs, char *mp, int sizeof_mp)
if (!found)
return 0;
- memset(mp, 0, sizeof_mp);
- strncpy(mp, mount_point, sizeof_mp - 1);
+ strscpy(mp, mount_point, sizeof_mp);
debug_msg("Fs %s found at %s\n", fs, mp);
return 1;
@@ -1036,6 +1035,37 @@ int strtoi(const char *s, int *res)
return 0;
}
+/**
+ * strscpy - Copy a C-string into a sized buffer
+ * @dst: Where to copy the string to
+ * @src: Where to copy the string from
+ * @count: Size of destination buffer
+ *
+ * Copy the source string @src, or as much of it as fits, into the destination
+ * @dst buffer. The destination @dst buffer is always NUL-terminated, unless
+ * it's zero-sized.
+ *
+ * This is a userspace implementation matching the kernel's strscpy() semantics,
+ * built on top of glibc's strlcpy().
+ *
+ * Returns the number of characters copied (not including the trailing NUL)
+ * or -E2BIG if @count is 0 or the copy was truncated.
+ */
+ssize_t strscpy(char *dst, const char *src, size_t count)
+{
+ size_t len;
+
+ if (count == 0)
+ return -E2BIG;
+
+ len = strlcpy(dst, src, count);
+
+ if (len >= count)
+ return -E2BIG;
+
+ return (ssize_t) len;
+}
+
static inline void fatal_alloc(void)
{
fatal("Error allocating memory\n");
diff --git a/tools/tracing/rtla/src/utils.h b/tools/tracing/rtla/src/utils.h
index 8323c999260c2..25b08fc5e199a 100644
--- a/tools/tracing/rtla/src/utils.h
+++ b/tools/tracing/rtla/src/utils.h
@@ -97,6 +97,7 @@ static inline int have_libcpupower_support(void) { return 0; }
#endif /* HAVE_LIBCPUPOWER_SUPPORT */
int auto_house_keeping(cpu_set_t *monitored_cpus);
__attribute__((__warn_unused_result__)) int strtoi(const char *s, int *res);
+ssize_t strscpy(char *dst, const char *src, size_t count);
#define ns_to_usf(x) (((double)x/1000))
#define ns_to_per(total, part) ((part * 100) / (double)total)
--
2.52.0
^ permalink raw reply related
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