From: Steven Rostedt <rostedt@goodmis.org>
To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org,
bpf@vger.kernel.org, x86@kernel.org
Cc: Masami Hiramatsu <mhiramat@kernel.org>,
Mathieu Desnoyers <mathieu.desnoyers@efficios.com>,
Josh Poimboeuf <jpoimboe@kernel.org>,
Peter Zijlstra <peterz@infradead.org>,
Ingo Molnar <mingo@kernel.org>, Jiri Olsa <jolsa@kernel.org>,
Namhyung Kim <namhyung@kernel.org>,
Thomas Gleixner <tglx@linutronix.de>,
Andrii Nakryiko <andrii@kernel.org>,
Indu Bhagat <indu.bhagat@oracle.com>,
"Jose E. Marchesi" <jemarch@gnu.org>,
Beau Belgrave <beaub@linux.microsoft.com>,
Jens Remus <jremus@linux.ibm.com>,
Linus Torvalds <torvalds@linux-foundation.org>,
Andrew Morton <akpm@linux-foundation.org>,
Jens Axboe <axboe@kernel.dk>
Subject: [PATCH v11 08/14] unwind deferred: Use bitmask to determine which callbacks to call
Date: Wed, 25 Jun 2025 18:56:08 -0400 [thread overview]
Message-ID: <20250625225716.174989731@goodmis.org> (raw)
In-Reply-To: 20250625225600.555017347@goodmis.org
From: Steven Rostedt <rostedt@goodmis.org>
In order to know which registered callback requested a stacktrace for when
the task goes back to user space, add a bitmask to keep track of all
registered tracers. The bitmask is the size of long, which means that on a
32 bit machine, it can have at most 32 registered tracers, and on 64 bit,
it can have at most 64 registered tracers. This should not be an issue as
there should not be more than 10 (unless BPF can abuse this?).
When a tracer registers with unwind_deferred_init() it will get a bit
number assigned to it. When a tracer requests a stacktrace, it will have
its bit set within the task_struct. When the task returns back to user
space, it will call the callbacks for all the registered tracers where
their bits are set in the task's mask.
When a tracer is removed by the unwind_deferred_cancel() all current tasks
will clear the associated bit, just in case another tracer gets registered
immediately afterward and then gets their callback called unexpectedly.
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
Changes since v10: https://lore.kernel.org/20250611010429.105907436@goodmis.org
- Use __clear_bit() and __set_bit() consistently with the global variable
unwind_mask. (Peter Zijlstra)
- Use clear_bit() and set_bit() consistently with the task unwind_mask,
as it can race with NMIs.
include/linux/unwind_deferred.h | 1 +
include/linux/unwind_deferred_types.h | 1 +
kernel/unwind/deferred.c | 36 ++++++++++++++++++++++++---
3 files changed, 34 insertions(+), 4 deletions(-)
diff --git a/include/linux/unwind_deferred.h b/include/linux/unwind_deferred.h
index 718637777649..00656e903375 100644
--- a/include/linux/unwind_deferred.h
+++ b/include/linux/unwind_deferred.h
@@ -13,6 +13,7 @@ typedef void (*unwind_callback_t)(struct unwind_work *work, struct unwind_stackt
struct unwind_work {
struct list_head list;
unwind_callback_t func;
+ int bit;
};
#ifdef CONFIG_UNWIND_USER
diff --git a/include/linux/unwind_deferred_types.h b/include/linux/unwind_deferred_types.h
index 0d722e877473..5863bf4eb436 100644
--- a/include/linux/unwind_deferred_types.h
+++ b/include/linux/unwind_deferred_types.h
@@ -13,6 +13,7 @@ struct unwind_cache {
struct unwind_task_info {
struct unwind_cache *cache;
struct callback_head work;
+ unsigned long unwind_mask;
local64_t timestamp;
local_t pending;
};
diff --git a/kernel/unwind/deferred.c b/kernel/unwind/deferred.c
index dd36e58c8cad..6c558d00ff41 100644
--- a/kernel/unwind/deferred.c
+++ b/kernel/unwind/deferred.c
@@ -48,6 +48,7 @@ static inline u64 assign_timestamp(struct unwind_task_info *info,
/* Guards adding to and reading the list of callbacks */
static DEFINE_MUTEX(callback_mutex);
static LIST_HEAD(callbacks);
+static unsigned long unwind_mask;
/*
* Read the task context timestamp, if this is the first caller then
@@ -153,7 +154,10 @@ static void unwind_deferred_task_work(struct callback_head *head)
guard(mutex)(&callback_mutex);
list_for_each_entry(work, &callbacks, list) {
- work->func(work, &trace, timestamp);
+ if (test_bit(work->bit, &info->unwind_mask)) {
+ work->func(work, &trace, timestamp);
+ clear_bit(work->bit, &info->unwind_mask);
+ }
}
}
@@ -205,15 +209,19 @@ int unwind_deferred_request(struct unwind_work *work, u64 *timestamp)
*timestamp = get_timestamp(info);
+ /* This is already queued */
+ if (test_bit(work->bit, &info->unwind_mask))
+ return 1;
+
/* callback already pending? */
pending = local_read(&info->pending);
if (pending)
- return 1;
+ goto out;
if (CAN_USE_IN_NMI) {
/* Claim the work unless an NMI just now swooped in to do so. */
if (!local_try_cmpxchg(&info->pending, &pending, 1))
- return 1;
+ goto out;
} else {
local_set(&info->pending, 1);
}
@@ -225,16 +233,27 @@ int unwind_deferred_request(struct unwind_work *work, u64 *timestamp)
return ret;
}
- return 0;
+ out:
+ return test_and_set_bit(work->bit, &info->unwind_mask);
}
void unwind_deferred_cancel(struct unwind_work *work)
{
+ struct task_struct *g, *t;
+
if (!work)
return;
guard(mutex)(&callback_mutex);
list_del(&work->list);
+
+ __clear_bit(work->bit, &unwind_mask);
+
+ guard(rcu)();
+ /* Clear this bit from all threads */
+ for_each_process_thread(g, t) {
+ clear_bit(work->bit, &t->unwind_info.unwind_mask);
+ }
}
int unwind_deferred_init(struct unwind_work *work, unwind_callback_t func)
@@ -242,6 +261,14 @@ int unwind_deferred_init(struct unwind_work *work, unwind_callback_t func)
memset(work, 0, sizeof(*work));
guard(mutex)(&callback_mutex);
+
+ /* See if there's a bit in the mask available */
+ if (unwind_mask == ~0UL)
+ return -EBUSY;
+
+ work->bit = ffz(unwind_mask);
+ __set_bit(work->bit, &unwind_mask);
+
list_add(&work->list, &callbacks);
work->func = func;
return 0;
@@ -253,6 +280,7 @@ void unwind_task_init(struct task_struct *task)
memset(info, 0, sizeof(*info));
init_task_work(&info->work, unwind_deferred_task_work);
+ info->unwind_mask = 0;
}
void unwind_task_free(struct task_struct *task)
--
2.47.2
next prev parent reply other threads:[~2025-06-25 22:57 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-25 22:56 [PATCH v11 00/14] unwind_user: x86: Deferred unwinding infrastructure Steven Rostedt
2025-06-25 22:56 ` [PATCH v11 01/14] unwind_user: Add user space unwinding API Steven Rostedt
2025-06-25 22:56 ` [PATCH v11 02/14] unwind_user: Add frame pointer support Steven Rostedt
2025-06-25 22:56 ` [PATCH v11 03/14] unwind_user: Add compat mode " Steven Rostedt
2025-06-25 22:56 ` [PATCH v11 04/14] unwind_user/deferred: Add unwind_user_faultable() Steven Rostedt
2025-06-25 22:56 ` [PATCH v11 05/14] unwind_user/deferred: Add unwind cache Steven Rostedt
2025-06-25 22:56 ` [PATCH v11 06/14] unwind_user/deferred: Add deferred unwinding interface Steven Rostedt
2025-06-26 16:48 ` Steven Rostedt
2025-06-26 20:34 ` Steven Rostedt
2025-06-25 22:56 ` [PATCH v11 07/14] unwind_user/deferred: Make unwind deferral requests NMI-safe Steven Rostedt
2025-06-25 22:56 ` Steven Rostedt [this message]
2025-06-25 22:56 ` [PATCH v11 09/14] unwind deferred: Use SRCU unwind_deferred_task_work() Steven Rostedt
2025-06-25 22:56 ` [PATCH v11 10/14] unwind: Clear unwind_mask on exit back to user space Steven Rostedt
2025-06-25 22:56 ` [PATCH v11 11/14] unwind: Finish up unwind when a task exits Steven Rostedt
2025-06-25 22:56 ` [PATCH v11 12/14] unwind_user/x86: Enable frame pointer unwinding on x86 Steven Rostedt
2025-06-25 22:56 ` [PATCH v11 13/14] perf/x86: Rename and move get_segment_base() and make it global Steven Rostedt
2025-06-26 8:44 ` Ingo Molnar
2025-06-26 12:13 ` Steven Rostedt
2025-06-26 13:07 ` Peter Zijlstra
2025-06-26 15:13 ` Steven Rostedt
2025-06-25 22:56 ` [PATCH v11 14/14] unwind_user/x86: Enable compat mode frame pointer unwinding on x86 Steven Rostedt
2025-06-26 8:33 ` Ingo Molnar
2025-06-26 12:12 ` Steven Rostedt
2025-06-27 14:01 ` Steven Rostedt
2025-06-27 16:23 ` Linus Torvalds
2025-06-30 12:50 ` [PATCH v11 00/14] unwind_user: x86: Deferred unwinding infrastructure Florian Weimer
2025-06-30 16:35 ` Namhyung Kim
2025-06-30 17:30 ` Steven Rostedt
2025-07-02 11:44 ` Sam James
2025-07-02 16:15 ` Steven Rostedt
2025-07-02 17:14 ` Namhyung Kim
2025-07-03 4:01 ` Sam James
2025-07-02 17:10 ` Namhyung Kim
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=20250625225716.174989731@goodmis.org \
--to=rostedt@goodmis.org \
--cc=akpm@linux-foundation.org \
--cc=andrii@kernel.org \
--cc=axboe@kernel.dk \
--cc=beaub@linux.microsoft.com \
--cc=bpf@vger.kernel.org \
--cc=indu.bhagat@oracle.com \
--cc=jemarch@gnu.org \
--cc=jolsa@kernel.org \
--cc=jpoimboe@kernel.org \
--cc=jremus@linux.ibm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=mathieu.desnoyers@efficios.com \
--cc=mhiramat@kernel.org \
--cc=mingo@kernel.org \
--cc=namhyung@kernel.org \
--cc=peterz@infradead.org \
--cc=tglx@linutronix.de \
--cc=torvalds@linux-foundation.org \
--cc=x86@kernel.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;
as well as URLs for NNTP newsgroup(s).