From: Andrea Parri <parri.andrea@gmail.com>
To: Steven Rostedt <rostedt@goodmis.org>,
Masami Hiramatsu <mhiramat@kernel.org>,
Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org,
Andrea Parri <parri.andrea@gmail.com>
Subject: [RFC PATCH] ftrace: Fix lost recursion records in ftrace_record_recursion()
Date: Thu, 17 Sep 2026 11:02:17 +0200 [thread overview]
Message-ID: <20260917090217.6738-1-parri.andrea@gmail.com> (raw)
cached_function is set to the current ip before the cmpxchg() that
claims a slot in recursed_functions[]. When that cmpxchg() loses a
race for the same slot, the code bumps index and retries via "goto
again", but the retry immediately matches its own cached_function
write and returns without ever reaching the bumped-index cmpxchg().
Concretely, for two writers racing on the same index:
CPU 0 (ip = A) CPU 1 (ip = B)
-------------- --------------
cmpxchg(&recursed_functions[index].ip,
0, B); // succeeds
cached_function = A;
cmpxchg(&recursed_functions[index].ip,
0, A);
// fails, old == B
index++;
goto again;
if (A == cached_function) // true: matches A's own store
return; // A is dropped, not retried
Once dropped this way, cached_function stays set to A, so every later
recursion of A also hits the fast path and returns before reaching the
retry, until some unrelated ip overwrites the cache.
Only set cached_function once the record is confirmed present, either
because a concurrent writer already added it or because this writer
just claimed the slot. The retry path leaves it untouched, so it no
longer matches against a value it just wrote for itself.
Fixes: 773c16705058e ("ftrace: Add recording of functions that caused recursion")
Assisted-by: LLM
Signed-off-by: Andrea Parri <parri.andrea@gmail.com>
---
Can't claim to fully understand the logic behind ftrace_record_recursion().
Notably, its smp_mb__after_atomic() calls and the lack of barrier comments
both look suspicious to my LKMM-trained eyes. ;) Hence the RFC.
---
kernel/trace/trace_recursion_record.c | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/kernel/trace/trace_recursion_record.c b/kernel/trace/trace_recursion_record.c
index bac4bc844ccd8..f42089c30f53c 100644
--- a/kernel/trace/trace_recursion_record.c
+++ b/kernel/trace/trace_recursion_record.c
@@ -17,8 +17,8 @@ static struct recursed_functions recursed_functions[CONFIG_FTRACE_RECORD_RECURSI
static atomic_t nr_records;
/*
- * Cache the last found function. Yes, updates to this is racey, but
- * so is memory cache ;-)
+ * Cache the last function confirmed present in recursed_functions[].
+ * Updates to this are racy, but this is only a best-effort cache.
*/
static unsigned long cached_function;
@@ -67,24 +67,27 @@ void ftrace_record_recursion(unsigned long ip, unsigned long parent_ip)
}
}
- cached_function = ip;
-
/*
* We only want to add a function if it hasn't been added before.
- * Add to the current location before incrementing the count.
- * If it fails to add, then increment the index (save in i)
- * and try again.
+ * Claim the current slot before incrementing the count. If the slot
+ * is occupied by another function, advance to the next slot and retry.
+ *
+ * Do not update cached_function until ip is known to be present;
+ * otherwise the retry would match its own cache update.
*/
old = cmpxchg(&recursed_functions[index].ip, 0, ip);
if (old != 0) {
/* Did something else already added this for us? */
- if (old == ip)
+ if (old == ip) {
+ cached_function = ip;
return;
+ }
/* Try the next location (use i for the next index) */
index++;
goto again;
}
+ cached_function = ip;
recursed_functions[index].parent_ip = parent_ip;
/*
--
2.53.0
reply other threads:[~2026-09-17 9:02 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260917090217.6738-1-parri.andrea@gmail.com \
--to=parri.andrea@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=mathieu.desnoyers@efficios.com \
--cc=mhiramat@kernel.org \
--cc=rostedt@goodmis.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®