Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

unwind_user/deferred: Add unwind_user_faultable()

Add a new API to retrieve a user space callstack called
unwind_user_faultable(). The difference between this user space stack
tracer from the current user space stack tracer is that this must be
called from faultable context as it may use routines to access user space
data that needs to be faulted in.

It can be safely called from entering or exiting a system call as the code
can still be faulted in there.

This code is based on work by Josh Poimboeuf's deferred unwinding code:

Link: https://lore.kernel.org/all/6052e8487746603bdb29b65f4033e739092d9925.1737511963.git.jpoimboe@kernel.org/

Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Josh Poimboeuf <jpoimboe@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Andrii Nakryiko <andrii@kernel.org>
Cc: Indu Bhagat <indu.bhagat@oracle.com>
Cc: "Jose E. Marchesi" <jemarch@gnu.org>
Cc: Beau Belgrave <beaub@linux.microsoft.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Florian Weimer <fweimer@redhat.com>
Cc: Sam James <sam@gentoo.org>
Link: https://lore.kernel.org/20250729182405.147896868@kernel.org
Reviewed-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>

+103 -1
+5
include/linux/sched.h
··· 46 46 #include <linux/rv.h> 47 47 #include <linux/uidgid_types.h> 48 48 #include <linux/tracepoint-defs.h> 49 + #include <linux/unwind_deferred_types.h> 49 50 #include <asm/kmap_size.h> 50 51 51 52 /* task_struct member predeclarations (sorted alphabetically): */ ··· 1653 1652 1654 1653 #ifdef CONFIG_USER_EVENTS 1655 1654 struct user_event_mm *user_event_mm; 1655 + #endif 1656 + 1657 + #ifdef CONFIG_UNWIND_USER 1658 + struct unwind_task_info unwind_info; 1656 1659 #endif 1657 1660 1658 1661 /* CPU-specific state of this task: */
+24
include/linux/unwind_deferred.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef _LINUX_UNWIND_USER_DEFERRED_H 3 + #define _LINUX_UNWIND_USER_DEFERRED_H 4 + 5 + #include <linux/unwind_user.h> 6 + #include <linux/unwind_deferred_types.h> 7 + 8 + #ifdef CONFIG_UNWIND_USER 9 + 10 + void unwind_task_init(struct task_struct *task); 11 + void unwind_task_free(struct task_struct *task); 12 + 13 + int unwind_user_faultable(struct unwind_stacktrace *trace); 14 + 15 + #else /* !CONFIG_UNWIND_USER */ 16 + 17 + static inline void unwind_task_init(struct task_struct *task) {} 18 + static inline void unwind_task_free(struct task_struct *task) {} 19 + 20 + static inline int unwind_user_faultable(struct unwind_stacktrace *trace) { return -ENOSYS; } 21 + 22 + #endif /* !CONFIG_UNWIND_USER */ 23 + 24 + #endif /* _LINUX_UNWIND_USER_DEFERRED_H */
+9
include/linux/unwind_deferred_types.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef _LINUX_UNWIND_USER_DEFERRED_TYPES_H 3 + #define _LINUX_UNWIND_USER_DEFERRED_TYPES_H 4 + 5 + struct unwind_task_info { 6 + unsigned long *entries; 7 + }; 8 + 9 + #endif /* _LINUX_UNWIND_USER_DEFERRED_TYPES_H */
+4
kernel/fork.c
··· 105 105 #include <uapi/linux/pidfd.h> 106 106 #include <linux/pidfs.h> 107 107 #include <linux/tick.h> 108 + #include <linux/unwind_deferred.h> 108 109 109 110 #include <asm/pgalloc.h> 110 111 #include <linux/uaccess.h> ··· 733 732 WARN_ON(refcount_read(&tsk->usage)); 734 733 WARN_ON(tsk == current); 735 734 735 + unwind_task_free(tsk); 736 736 sched_ext_free(tsk); 737 737 io_uring_free(tsk); 738 738 cgroup_free(tsk); ··· 2136 2134 RCU_INIT_POINTER(p->bpf_storage, NULL); 2137 2135 p->bpf_ctx = NULL; 2138 2136 #endif 2137 + 2138 + unwind_task_init(p); 2139 2139 2140 2140 /* Perform scheduler related setup. Assign this task to a CPU. */ 2141 2141 retval = sched_fork(clone_flags, p);
+1 -1
kernel/unwind/Makefile
··· 1 - obj-$(CONFIG_UNWIND_USER) += user.o 1 + obj-$(CONFIG_UNWIND_USER) += user.o deferred.o
+60
kernel/unwind/deferred.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Deferred user space unwinding 4 + */ 5 + #include <linux/kernel.h> 6 + #include <linux/sched.h> 7 + #include <linux/slab.h> 8 + #include <linux/unwind_deferred.h> 9 + 10 + #define UNWIND_MAX_ENTRIES 512 11 + 12 + /** 13 + * unwind_user_faultable - Produce a user stacktrace in faultable context 14 + * @trace: The descriptor that will store the user stacktrace 15 + * 16 + * This must be called in a known faultable context (usually when entering 17 + * or exiting user space). Depending on the available implementations 18 + * the @trace will be loaded with the addresses of the user space stacktrace 19 + * if it can be found. 20 + * 21 + * Return: 0 on success and negative on error 22 + * On success @trace will contain the user space stacktrace 23 + */ 24 + int unwind_user_faultable(struct unwind_stacktrace *trace) 25 + { 26 + struct unwind_task_info *info = &current->unwind_info; 27 + 28 + /* Should always be called from faultable context */ 29 + might_fault(); 30 + 31 + if (current->flags & PF_EXITING) 32 + return -EINVAL; 33 + 34 + if (!info->entries) { 35 + info->entries = kmalloc_array(UNWIND_MAX_ENTRIES, sizeof(long), 36 + GFP_KERNEL); 37 + if (!info->entries) 38 + return -ENOMEM; 39 + } 40 + 41 + trace->nr = 0; 42 + trace->entries = info->entries; 43 + unwind_user(trace, UNWIND_MAX_ENTRIES); 44 + 45 + return 0; 46 + } 47 + 48 + void unwind_task_init(struct task_struct *task) 49 + { 50 + struct unwind_task_info *info = &task->unwind_info; 51 + 52 + memset(info, 0, sizeof(*info)); 53 + } 54 + 55 + void unwind_task_free(struct task_struct *task) 56 + { 57 + struct unwind_task_info *info = &task->unwind_info; 58 + 59 + kfree(info->entries); 60 + }