Skip to content

Commit 357eda2

Browse files
committed
unwind deferred: Use SRCU unwind_deferred_task_work()
Instead of using the callback_mutex to protect the link list of callbacks in unwind_deferred_task_work(), use SRCU instead. This gets called every time a task exits that has to record a stack trace that was requested. This can happen for many tasks on several CPUs at the same time. A mutex is a bottleneck and can cause a bit of contention and slow down performance. As the callbacks themselves are allowed to sleep, regular RCU cannot be used to protect the list. Instead use SRCU, as that still allows the callbacks to sleep and the list can be read without needing to hold the callback_mutex. Link: https://lore.kernel.org/all/[email protected]/ Cc: "Paul E. McKenney" <[email protected]> Cc: Masami Hiramatsu <[email protected]> Cc: Josh Poimboeuf <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Arnaldo Carvalho de Melo <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Andrii Nakryiko <[email protected]> Cc: Indu Bhagat <[email protected]> Cc: "Jose E. Marchesi" <[email protected]> Cc: Beau Belgrave <[email protected]> Cc: Jens Remus <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Andrew Morton <[email protected]> Cc: Jens Axboe <[email protected]> Cc: Florian Weimer <[email protected]> Cc: Sam James <[email protected]> Link: https://lore.kernel.org/[email protected] Suggested-by: Mathieu Desnoyers <[email protected]> Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent 858fa8a commit 357eda2

File tree

1 file changed

+21
-6
lines changed

1 file changed

+21
-6
lines changed

kernel/unwind/deferred.c

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,15 @@ static inline bool try_assign_cnt(struct unwind_task_info *info, u32 cnt)
4141
#define UNWIND_MAX_ENTRIES \
4242
((SZ_4K - sizeof(struct unwind_cache)) / sizeof(long))
4343

44-
/* Guards adding to and reading the list of callbacks */
44+
/* Guards adding to or removing from the list of callbacks */
4545
static DEFINE_MUTEX(callback_mutex);
4646
static LIST_HEAD(callbacks);
4747

4848
#define RESERVED_BITS (UNWIND_PENDING | UNWIND_USED)
4949

5050
/* Zero'd bits are available for assigning callback users */
5151
static unsigned long unwind_mask = RESERVED_BITS;
52+
DEFINE_STATIC_SRCU(unwind_srcu);
5253

5354
static inline bool unwind_pending(struct unwind_task_info *info)
5455
{
@@ -174,8 +175,9 @@ static void unwind_deferred_task_work(struct callback_head *head)
174175

175176
cookie = info->id.id;
176177

177-
guard(mutex)(&callback_mutex);
178-
list_for_each_entry(work, &callbacks, list) {
178+
guard(srcu)(&unwind_srcu);
179+
list_for_each_entry_srcu(work, &callbacks, list,
180+
srcu_read_lock_held(&unwind_srcu)) {
179181
if (test_bit(work->bit, &bits)) {
180182
work->func(work, &trace, cookie);
181183
if (info->cache)
@@ -213,7 +215,7 @@ int unwind_deferred_request(struct unwind_work *work, u64 *cookie)
213215
{
214216
struct unwind_task_info *info = &current->unwind_info;
215217
unsigned long old, bits;
216-
unsigned long bit = BIT(work->bit);
218+
unsigned long bit;
217219
int ret;
218220

219221
*cookie = 0;
@@ -230,6 +232,14 @@ int unwind_deferred_request(struct unwind_work *work, u64 *cookie)
230232
if (WARN_ON_ONCE(!CAN_USE_IN_NMI && in_nmi()))
231233
return -EINVAL;
232234

235+
/* Do not allow cancelled works to request again */
236+
bit = READ_ONCE(work->bit);
237+
if (WARN_ON_ONCE(bit < 0))
238+
return -EINVAL;
239+
240+
/* Only need the mask now */
241+
bit = BIT(bit);
242+
233243
guard(irqsave)();
234244

235245
*cookie = get_cookie(info);
@@ -281,10 +291,15 @@ void unwind_deferred_cancel(struct unwind_work *work)
281291
return;
282292

283293
guard(mutex)(&callback_mutex);
284-
list_del(&work->list);
294+
list_del_rcu(&work->list);
295+
296+
/* Do not allow any more requests and prevent callbacks */
297+
work->bit = -1;
285298

286299
__clear_bit(bit, &unwind_mask);
287300

301+
synchronize_srcu(&unwind_srcu);
302+
288303
guard(rcu)();
289304
/* Clear this bit from all threads */
290305
for_each_process_thread(g, t) {
@@ -307,7 +322,7 @@ int unwind_deferred_init(struct unwind_work *work, unwind_callback_t func)
307322
work->bit = ffz(unwind_mask);
308323
__set_bit(work->bit, &unwind_mask);
309324

310-
list_add(&work->list, &callbacks);
325+
list_add_rcu(&work->list, &callbacks);
311326
work->func = func;
312327
return 0;
313328
}

0 commit comments

Comments
 (0)