* [PATCH 5.15.y 0/4] Fix blank WHCAN value in 'ps' output
@ 2025-07-22 6:26 Siddhi Katage
2025-07-22 6:26 ` [PATCH 5.15.y 1/4] x86: Fix get_wchan() to support the ORC unwinder Siddhi Katage
` (4 more replies)
0 siblings, 5 replies; 12+ messages in thread
From: Siddhi Katage @ 2025-07-22 6:26 UTC (permalink / raw)
To: stable
The 'ps' output prints blank(hyphen) WHCAN value for all the tasks.
This patchset will help print the correct WCHAN value.
Kees Cook (1):
sched: Add wrapper for get_wchan() to keep task blocked
Peter Zijlstra (2):
x86: Fix __get_wchan() for !STACKTRACE
x86: Pin task-stack in __get_wchan()
Qi Zheng (1):
x86: Fix get_wchan() to support the ORC unwinder
arch/alpha/include/asm/processor.h | 2 +-
arch/alpha/kernel/process.c | 5 +-
arch/arc/include/asm/processor.h | 2 +-
arch/arc/kernel/stacktrace.c | 4 +-
arch/arm/include/asm/processor.h | 2 +-
arch/arm/kernel/process.c | 4 +-
arch/arm64/include/asm/processor.h | 2 +-
arch/arm64/kernel/process.c | 4 +-
arch/csky/include/asm/processor.h | 2 +-
arch/csky/kernel/stacktrace.c | 5 +-
arch/h8300/include/asm/processor.h | 2 +-
arch/h8300/kernel/process.c | 5 +-
arch/hexagon/include/asm/processor.h | 2 +-
arch/hexagon/kernel/process.c | 4 +-
arch/ia64/include/asm/processor.h | 2 +-
arch/ia64/kernel/process.c | 5 +-
arch/m68k/include/asm/processor.h | 2 +-
arch/m68k/kernel/process.c | 4 +-
arch/microblaze/include/asm/processor.h | 2 +-
arch/microblaze/kernel/process.c | 2 +-
arch/mips/include/asm/processor.h | 2 +-
arch/mips/kernel/process.c | 8 ++--
arch/nds32/include/asm/processor.h | 2 +-
arch/nds32/kernel/process.c | 7 +--
arch/nios2/include/asm/processor.h | 2 +-
arch/nios2/kernel/process.c | 5 +-
arch/openrisc/include/asm/processor.h | 2 +-
arch/openrisc/kernel/process.c | 2 +-
arch/parisc/include/asm/processor.h | 2 +-
arch/parisc/kernel/process.c | 5 +-
arch/powerpc/include/asm/processor.h | 2 +-
arch/powerpc/kernel/process.c | 9 ++--
arch/riscv/include/asm/processor.h | 2 +-
arch/riscv/kernel/stacktrace.c | 12 ++---
arch/s390/include/asm/processor.h | 2 +-
arch/s390/kernel/process.c | 4 +-
arch/sh/include/asm/processor_32.h | 2 +-
arch/sh/kernel/process_32.c | 5 +-
arch/sparc/include/asm/processor_32.h | 2 +-
arch/sparc/include/asm/processor_64.h | 2 +-
arch/sparc/kernel/process_32.c | 5 +-
arch/sparc/kernel/process_64.c | 5 +-
arch/um/include/asm/processor-generic.h | 2 +-
arch/um/kernel/process.c | 5 +-
arch/x86/include/asm/processor.h | 2 +-
arch/x86/kernel/process.c | 62 ++++++-------------------
arch/xtensa/include/asm/processor.h | 2 +-
arch/xtensa/kernel/process.c | 5 +-
include/linux/sched.h | 1 +
kernel/sched/core.c | 19 ++++++++
50 files changed, 94 insertions(+), 155 deletions(-)
--
2.47.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 5.15.y 1/4] x86: Fix get_wchan() to support the ORC unwinder
2025-07-22 6:26 [PATCH 5.15.y 0/4] Fix blank WHCAN value in 'ps' output Siddhi Katage
@ 2025-07-22 6:26 ` Siddhi Katage
2025-07-23 4:33 ` Sasha Levin
2025-07-22 6:26 ` [PATCH 5.15.y 2/4] sched: Add wrapper for get_wchan() to keep task blocked Siddhi Katage
` (3 subsequent siblings)
4 siblings, 1 reply; 12+ messages in thread
From: Siddhi Katage @ 2025-07-22 6:26 UTC (permalink / raw)
To: stable
From: Qi Zheng <zhengqi.arch@bytedance.com>
[ Upstream commit bc9bbb81730ea667c31c5b284f95ee312bab466f ]
Currently, the kernel CONFIG_UNWINDER_ORC option is enabled by default
on x86, but the implementation of get_wchan() is still based on the frame
pointer unwinder, so the /proc/<pid>/wchan usually returned 0 regardless
of whether the task <pid> is running.
Reimplement get_wchan() by calling stack_trace_save_tsk(), which is
adapted to the ORC and frame pointer unwinders.
Fixes: ee9f8fce9964 ("x86/unwind: Add the ORC unwinder")
Signed-off-by: Qi Zheng <zhengqi.arch@bytedance.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lkml.kernel.org/r/20211008111626.271115116@infradead.org
Signed-off-by: Siddhi Katage <siddhi.katage@oracle.com>
---
arch/x86/kernel/process.c | 51 +++------------------------------------
1 file changed, 3 insertions(+), 48 deletions(-)
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 5ce91d5dfab0..a4d437727345 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -971,58 +971,13 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
*/
unsigned long get_wchan(struct task_struct *p)
{
- unsigned long start, bottom, top, sp, fp, ip, ret = 0;
- int count = 0;
+ unsigned long entry = 0;
if (p == current || task_is_running(p))
return 0;
- if (!try_get_task_stack(p))
- return 0;
-
- start = (unsigned long)task_stack_page(p);
- if (!start)
- goto out;
-
- /*
- * Layout of the stack page:
- *
- * ----------- topmax = start + THREAD_SIZE - sizeof(unsigned long)
- * PADDING
- * ----------- top = topmax - TOP_OF_KERNEL_STACK_PADDING
- * stack
- * ----------- bottom = start
- *
- * The tasks stack pointer points at the location where the
- * framepointer is stored. The data on the stack is:
- * ... IP FP ... IP FP
- *
- * We need to read FP and IP, so we need to adjust the upper
- * bound by another unsigned long.
- */
- top = start + THREAD_SIZE - TOP_OF_KERNEL_STACK_PADDING;
- top -= 2 * sizeof(unsigned long);
- bottom = start;
-
- sp = READ_ONCE(p->thread.sp);
- if (sp < bottom || sp > top)
- goto out;
-
- fp = READ_ONCE_NOCHECK(((struct inactive_task_frame *)sp)->bp);
- do {
- if (fp < bottom || fp > top)
- goto out;
- ip = READ_ONCE_NOCHECK(*(unsigned long *)(fp + sizeof(unsigned long)));
- if (!in_sched_functions(ip)) {
- ret = ip;
- goto out;
- }
- fp = READ_ONCE_NOCHECK(*(unsigned long *)fp);
- } while (count++ < 16 && !task_is_running(p));
-
-out:
- put_task_stack(p);
- return ret;
+ stack_trace_save_tsk(p, &entry, 1, 0);
+ return entry;
}
long do_arch_prctl_common(struct task_struct *task, int option,
--
2.47.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 5.15.y 2/4] sched: Add wrapper for get_wchan() to keep task blocked
2025-07-22 6:26 [PATCH 5.15.y 0/4] Fix blank WHCAN value in 'ps' output Siddhi Katage
2025-07-22 6:26 ` [PATCH 5.15.y 1/4] x86: Fix get_wchan() to support the ORC unwinder Siddhi Katage
@ 2025-07-22 6:26 ` Siddhi Katage
2025-07-23 4:33 ` Sasha Levin
2025-07-22 6:26 ` [PATCH 5.15.y 3/4] x86: Fix __get_wchan() for !STACKTRACE Siddhi Katage
` (2 subsequent siblings)
4 siblings, 1 reply; 12+ messages in thread
From: Siddhi Katage @ 2025-07-22 6:26 UTC (permalink / raw)
To: stable
From: Kees Cook <keescook@chromium.org>
[ Upstream commit 42a20f86dc19f9282d974df0ba4d226c865ab9dd ]
Having a stable wchan means the process must be blocked and for it to
stay that way while performing stack unwinding.
Suggested-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
Acked-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> [arm]
Tested-by: Mark Rutland <mark.rutland@arm.com> [arm64]
Link: https://lkml.kernel.org/r/20211008111626.332092234@infradead.org
Signed-off-by: Siddhi Katage <siddhi.katage@oracle.com>
---
arch/alpha/include/asm/processor.h | 2 +-
arch/alpha/kernel/process.c | 5 ++---
arch/arc/include/asm/processor.h | 2 +-
arch/arc/kernel/stacktrace.c | 4 ++--
arch/arm/include/asm/processor.h | 2 +-
arch/arm/kernel/process.c | 4 +---
arch/arm64/include/asm/processor.h | 2 +-
arch/arm64/kernel/process.c | 4 +---
arch/csky/include/asm/processor.h | 2 +-
arch/csky/kernel/stacktrace.c | 5 ++---
arch/h8300/include/asm/processor.h | 2 +-
arch/h8300/kernel/process.c | 5 +----
arch/hexagon/include/asm/processor.h | 2 +-
arch/hexagon/kernel/process.c | 4 +---
arch/ia64/include/asm/processor.h | 2 +-
arch/ia64/kernel/process.c | 5 +----
arch/m68k/include/asm/processor.h | 2 +-
arch/m68k/kernel/process.c | 4 +---
arch/microblaze/include/asm/processor.h | 2 +-
arch/microblaze/kernel/process.c | 2 +-
arch/mips/include/asm/processor.h | 2 +-
arch/mips/kernel/process.c | 8 +++-----
arch/nds32/include/asm/processor.h | 2 +-
arch/nds32/kernel/process.c | 7 +------
arch/nios2/include/asm/processor.h | 2 +-
arch/nios2/kernel/process.c | 5 +----
arch/openrisc/include/asm/processor.h | 2 +-
arch/openrisc/kernel/process.c | 2 +-
arch/parisc/include/asm/processor.h | 2 +-
arch/parisc/kernel/process.c | 5 +----
arch/powerpc/include/asm/processor.h | 2 +-
arch/powerpc/kernel/process.c | 9 +++------
arch/riscv/include/asm/processor.h | 2 +-
arch/riscv/kernel/stacktrace.c | 12 +++++-------
arch/s390/include/asm/processor.h | 2 +-
arch/s390/kernel/process.c | 4 ++--
arch/sh/include/asm/processor_32.h | 2 +-
arch/sh/kernel/process_32.c | 5 +----
arch/sparc/include/asm/processor_32.h | 2 +-
arch/sparc/include/asm/processor_64.h | 2 +-
arch/sparc/kernel/process_32.c | 5 +----
arch/sparc/kernel/process_64.c | 5 +----
arch/um/include/asm/processor-generic.h | 2 +-
arch/um/kernel/process.c | 5 +----
arch/x86/include/asm/processor.h | 2 +-
arch/x86/kernel/process.c | 5 +----
arch/xtensa/include/asm/processor.h | 2 +-
arch/xtensa/kernel/process.c | 5 +----
include/linux/sched.h | 1 +
kernel/sched/core.c | 19 +++++++++++++++++++
50 files changed, 80 insertions(+), 112 deletions(-)
diff --git a/arch/alpha/include/asm/processor.h b/arch/alpha/include/asm/processor.h
index d27db62c3247..c2002a666515 100644
--- a/arch/alpha/include/asm/processor.h
+++ b/arch/alpha/include/asm/processor.h
@@ -38,7 +38,7 @@ extern void start_thread(struct pt_regs *, unsigned long, unsigned long);
struct task_struct;
extern void release_thread(struct task_struct *);
-unsigned long get_wchan(struct task_struct *p);
+unsigned long __get_wchan(struct task_struct *p);
#define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc)
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index a5123ea426ce..5f8527081da9 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -376,12 +376,11 @@ thread_saved_pc(struct task_struct *t)
}
unsigned long
-get_wchan(struct task_struct *p)
+__get_wchan(struct task_struct *p)
{
unsigned long schedule_frame;
unsigned long pc;
- if (!p || p == current || task_is_running(p))
- return 0;
+
/*
* This one depends on the frame size of schedule(). Do a
* "disass schedule" in gdb to find the frame size. Also, the
diff --git a/arch/arc/include/asm/processor.h b/arch/arc/include/asm/processor.h
index f28afcf5c6d1..54db9d7bb562 100644
--- a/arch/arc/include/asm/processor.h
+++ b/arch/arc/include/asm/processor.h
@@ -70,7 +70,7 @@ struct task_struct;
extern void start_thread(struct pt_regs * regs, unsigned long pc,
unsigned long usp);
-extern unsigned int get_wchan(struct task_struct *p);
+extern unsigned int __get_wchan(struct task_struct *p);
#endif /* !__ASSEMBLY__ */
diff --git a/arch/arc/kernel/stacktrace.c b/arch/arc/kernel/stacktrace.c
index c376ff3147e7..5372dc04e784 100644
--- a/arch/arc/kernel/stacktrace.c
+++ b/arch/arc/kernel/stacktrace.c
@@ -15,7 +15,7 @@
* = specifics of data structs where trace is saved(CONFIG_STACKTRACE etc)
*
* vineetg: March 2009
- * -Implemented correct versions of thread_saved_pc() and get_wchan()
+ * -Implemented correct versions of thread_saved_pc() and __get_wchan()
*
* rajeshwarr: 2008
* -Initial implementation
@@ -248,7 +248,7 @@ void show_stack(struct task_struct *tsk, unsigned long *sp, const char *loglvl)
* Of course just returning schedule( ) would be pointless so unwind until
* the function is not in schedular code
*/
-unsigned int get_wchan(struct task_struct *tsk)
+unsigned int __get_wchan(struct task_struct *tsk)
{
return arc_unwind_core(tsk, NULL, __get_first_nonsched, NULL);
}
diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h
index 8aeff55aebfa..bdc35c0e8dfb 100644
--- a/arch/arm/include/asm/processor.h
+++ b/arch/arm/include/asm/processor.h
@@ -84,7 +84,7 @@ struct task_struct;
/* Free all resources held by a thread. */
extern void release_thread(struct task_struct *);
-unsigned long get_wchan(struct task_struct *p);
+unsigned long __get_wchan(struct task_struct *p);
#define task_pt_regs(p) \
((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1)
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 0e2d3051741e..96f577e59595 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -276,13 +276,11 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
return 0;
}
-unsigned long get_wchan(struct task_struct *p)
+unsigned long __get_wchan(struct task_struct *p)
{
struct stackframe frame;
unsigned long stack_page;
int count = 0;
- if (!p || p == current || task_is_running(p))
- return 0;
frame.fp = thread_saved_fp(p);
frame.sp = thread_saved_sp(p);
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index 1da032444dac..f7077add7aa9 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -265,7 +265,7 @@ struct task_struct;
/* Free all resources held by a thread. */
extern void release_thread(struct task_struct *);
-unsigned long get_wchan(struct task_struct *p);
+unsigned long __get_wchan(struct task_struct *p);
void update_sctlr_el1(u64 sctlr);
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index a01f2288ee9a..2763b395e927 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -523,13 +523,11 @@ __notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev,
return last;
}
-unsigned long get_wchan(struct task_struct *p)
+unsigned long __get_wchan(struct task_struct *p)
{
struct stackframe frame;
unsigned long stack_page, ret = 0;
int count = 0;
- if (!p || p == current || task_is_running(p))
- return 0;
stack_page = (unsigned long)try_get_task_stack(p);
if (!stack_page)
diff --git a/arch/csky/include/asm/processor.h b/arch/csky/include/asm/processor.h
index 9e933021fe8e..817dd60ff152 100644
--- a/arch/csky/include/asm/processor.h
+++ b/arch/csky/include/asm/processor.h
@@ -81,7 +81,7 @@ static inline void release_thread(struct task_struct *dead_task)
extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-unsigned long get_wchan(struct task_struct *p);
+unsigned long __get_wchan(struct task_struct *p);
#define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc)
#define KSTK_ESP(tsk) (task_pt_regs(tsk)->usp)
diff --git a/arch/csky/kernel/stacktrace.c b/arch/csky/kernel/stacktrace.c
index 1b280ef08004..9f78f5d21511 100644
--- a/arch/csky/kernel/stacktrace.c
+++ b/arch/csky/kernel/stacktrace.c
@@ -111,12 +111,11 @@ static bool save_wchan(unsigned long pc, void *arg)
return false;
}
-unsigned long get_wchan(struct task_struct *task)
+unsigned long __get_wchan(struct task_struct *task)
{
unsigned long pc = 0;
- if (likely(task && task != current && !task_is_running(task)))
- walk_stackframe(task, NULL, save_wchan, &pc);
+ walk_stackframe(task, NULL, save_wchan, &pc);
return pc;
}
diff --git a/arch/h8300/include/asm/processor.h b/arch/h8300/include/asm/processor.h
index a060b41b2d31..141a23eb62b7 100644
--- a/arch/h8300/include/asm/processor.h
+++ b/arch/h8300/include/asm/processor.h
@@ -105,7 +105,7 @@ static inline void release_thread(struct task_struct *dead_task)
{
}
-unsigned long get_wchan(struct task_struct *p);
+unsigned long __get_wchan(struct task_struct *p);
#define KSTK_EIP(tsk) \
({ \
diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c
index 2ac27e4248a4..8833fa4f5d51 100644
--- a/arch/h8300/kernel/process.c
+++ b/arch/h8300/kernel/process.c
@@ -128,15 +128,12 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
return 0;
}
-unsigned long get_wchan(struct task_struct *p)
+unsigned long __get_wchan(struct task_struct *p)
{
unsigned long fp, pc;
unsigned long stack_page;
int count = 0;
- if (!p || p == current || task_is_running(p))
- return 0;
-
stack_page = (unsigned long)p;
fp = ((struct pt_regs *)p->thread.ksp)->er6;
do {
diff --git a/arch/hexagon/include/asm/processor.h b/arch/hexagon/include/asm/processor.h
index 9f0cc99420be..615f7e49968e 100644
--- a/arch/hexagon/include/asm/processor.h
+++ b/arch/hexagon/include/asm/processor.h
@@ -64,7 +64,7 @@ struct thread_struct {
extern void release_thread(struct task_struct *dead_task);
/* Get wait channel for task P. */
-extern unsigned long get_wchan(struct task_struct *p);
+extern unsigned long __get_wchan(struct task_struct *p);
/* The following stuff is pretty HEXAGON specific. */
diff --git a/arch/hexagon/kernel/process.c b/arch/hexagon/kernel/process.c
index 6a6835fb4242..232dfd8956aa 100644
--- a/arch/hexagon/kernel/process.c
+++ b/arch/hexagon/kernel/process.c
@@ -130,13 +130,11 @@ void flush_thread(void)
* is an identification of the point at which the scheduler
* was invoked by a blocked thread.
*/
-unsigned long get_wchan(struct task_struct *p)
+unsigned long __get_wchan(struct task_struct *p)
{
unsigned long fp, pc;
unsigned long stack_page;
int count = 0;
- if (!p || p == current || task_is_running(p))
- return 0;
stack_page = (unsigned long)task_stack_page(p);
fp = ((struct hexagon_switch_stack *)p->thread.switch_sp)->fp;
diff --git a/arch/ia64/include/asm/processor.h b/arch/ia64/include/asm/processor.h
index 05e7c9ad1a96..309bcbf88137 100644
--- a/arch/ia64/include/asm/processor.h
+++ b/arch/ia64/include/asm/processor.h
@@ -330,7 +330,7 @@ struct task_struct;
#define release_thread(dead_task)
/* Get wait channel for task P. */
-extern unsigned long get_wchan (struct task_struct *p);
+extern unsigned long __get_wchan (struct task_struct *p);
/* Return instruction pointer of blocked task TSK. */
#define KSTK_EIP(tsk) \
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index e56d63f4abf9..834df24a88f1 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -523,15 +523,12 @@ exit_thread (struct task_struct *tsk)
}
unsigned long
-get_wchan (struct task_struct *p)
+__get_wchan (struct task_struct *p)
{
struct unw_frame_info info;
unsigned long ip;
int count = 0;
- if (!p || p == current || task_is_running(p))
- return 0;
-
/*
* Note: p may not be a blocked task (it could be current or
* another process running on some other CPU. Rather than
diff --git a/arch/m68k/include/asm/processor.h b/arch/m68k/include/asm/processor.h
index f4d82c619a5c..ffeda9aa526a 100644
--- a/arch/m68k/include/asm/processor.h
+++ b/arch/m68k/include/asm/processor.h
@@ -150,7 +150,7 @@ static inline void release_thread(struct task_struct *dead_task)
{
}
-unsigned long get_wchan(struct task_struct *p);
+unsigned long __get_wchan(struct task_struct *p);
#define KSTK_EIP(tsk) \
({ \
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index 32427aa13166..e29d877e867d 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -263,13 +263,11 @@ int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
}
EXPORT_SYMBOL(dump_fpu);
-unsigned long get_wchan(struct task_struct *p)
+unsigned long __get_wchan(struct task_struct *p)
{
unsigned long fp, pc;
unsigned long stack_page;
int count = 0;
- if (!p || p == current || task_is_running(p))
- return 0;
stack_page = (unsigned long)task_stack_page(p);
fp = ((struct switch_stack *)p->thread.ksp)->a6;
diff --git a/arch/microblaze/include/asm/processor.h b/arch/microblaze/include/asm/processor.h
index 06c6e493590a..7e9e92670df3 100644
--- a/arch/microblaze/include/asm/processor.h
+++ b/arch/microblaze/include/asm/processor.h
@@ -68,7 +68,7 @@ static inline void release_thread(struct task_struct *dead_task)
{
}
-unsigned long get_wchan(struct task_struct *p);
+unsigned long __get_wchan(struct task_struct *p);
/* The size allocated for kernel stacks. This _must_ be a power of two! */
# define KERNEL_STACK_SIZE 0x2000
diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c
index 62aa237180b6..5e2b91c1e8ce 100644
--- a/arch/microblaze/kernel/process.c
+++ b/arch/microblaze/kernel/process.c
@@ -112,7 +112,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg,
return 0;
}
-unsigned long get_wchan(struct task_struct *p)
+unsigned long __get_wchan(struct task_struct *p)
{
/* TBD (used by procfs) */
return 0;
diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h
index 0c3550c82b72..252ed38ce8c5 100644
--- a/arch/mips/include/asm/processor.h
+++ b/arch/mips/include/asm/processor.h
@@ -369,7 +369,7 @@ static inline void flush_thread(void)
{
}
-unsigned long get_wchan(struct task_struct *p);
+unsigned long __get_wchan(struct task_struct *p);
#define __KSTK_TOS(tsk) ((unsigned long)task_stack_page(tsk) + \
THREAD_SIZE - 32 - sizeof(struct pt_regs))
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 95aa86fa6077..cbff1b974f88 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -511,7 +511,7 @@ static int __init frame_info_init(void)
/*
* Without schedule() frame info, result given by
- * thread_saved_pc() and get_wchan() are not reliable.
+ * thread_saved_pc() and __get_wchan() are not reliable.
*/
if (schedule_mfi.pc_offset < 0)
printk("Can't analyze schedule() prologue at %p\n", schedule);
@@ -652,9 +652,9 @@ unsigned long unwind_stack(struct task_struct *task, unsigned long *sp,
#endif
/*
- * get_wchan - a maintenance nightmare^W^Wpain in the ass ...
+ * __get_wchan - a maintenance nightmare^W^Wpain in the ass ...
*/
-unsigned long get_wchan(struct task_struct *task)
+unsigned long __get_wchan(struct task_struct *task)
{
unsigned long pc = 0;
#ifdef CONFIG_KALLSYMS
@@ -662,8 +662,6 @@ unsigned long get_wchan(struct task_struct *task)
unsigned long ra = 0;
#endif
- if (!task || task == current || task_is_running(task))
- goto out;
if (!task_stack_page(task))
goto out;
diff --git a/arch/nds32/include/asm/processor.h b/arch/nds32/include/asm/processor.h
index b82369c7659d..e6bfc74972bb 100644
--- a/arch/nds32/include/asm/processor.h
+++ b/arch/nds32/include/asm/processor.h
@@ -83,7 +83,7 @@ extern struct task_struct *last_task_used_math;
/* Prepare to copy thread state - unlazy all lazy status */
#define prepare_to_copy(tsk) do { } while (0)
-unsigned long get_wchan(struct task_struct *p);
+unsigned long __get_wchan(struct task_struct *p);
#define cpu_relax() barrier()
diff --git a/arch/nds32/kernel/process.c b/arch/nds32/kernel/process.c
index 391895b54d13..49fab9e39cbf 100644
--- a/arch/nds32/kernel/process.c
+++ b/arch/nds32/kernel/process.c
@@ -233,15 +233,12 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpu)
EXPORT_SYMBOL(dump_fpu);
-unsigned long get_wchan(struct task_struct *p)
+unsigned long __get_wchan(struct task_struct *p)
{
unsigned long fp, lr;
unsigned long stack_start, stack_end;
int count = 0;
- if (!p || p == current || task_is_running(p))
- return 0;
-
if (IS_ENABLED(CONFIG_FRAME_POINTER)) {
stack_start = (unsigned long)end_of_stack(p);
stack_end = (unsigned long)task_stack_page(p) + THREAD_SIZE;
@@ -258,5 +255,3 @@ unsigned long get_wchan(struct task_struct *p)
}
return 0;
}
-
-EXPORT_SYMBOL(get_wchan);
diff --git a/arch/nios2/include/asm/processor.h b/arch/nios2/include/asm/processor.h
index 94bcb86f679f..b8125dfbcad2 100644
--- a/arch/nios2/include/asm/processor.h
+++ b/arch/nios2/include/asm/processor.h
@@ -69,7 +69,7 @@ static inline void release_thread(struct task_struct *dead_task)
{
}
-extern unsigned long get_wchan(struct task_struct *p);
+extern unsigned long __get_wchan(struct task_struct *p);
#define task_pt_regs(p) \
((struct pt_regs *)(THREAD_SIZE + task_stack_page(p)) - 1)
diff --git a/arch/nios2/kernel/process.c b/arch/nios2/kernel/process.c
index 9ff37ba2bb60..f8ea522a1588 100644
--- a/arch/nios2/kernel/process.c
+++ b/arch/nios2/kernel/process.c
@@ -217,15 +217,12 @@ void dump(struct pt_regs *fp)
pr_emerg("\n\n");
}
-unsigned long get_wchan(struct task_struct *p)
+unsigned long __get_wchan(struct task_struct *p)
{
unsigned long fp, pc;
unsigned long stack_page;
int count = 0;
- if (!p || p == current || task_is_running(p))
- return 0;
-
stack_page = (unsigned long)p;
fp = ((struct switch_stack *)p->thread.ksp)->fp; /* ;dgt2 */
do {
diff --git a/arch/openrisc/include/asm/processor.h b/arch/openrisc/include/asm/processor.h
index ad53b3184885..aa1699c18add 100644
--- a/arch/openrisc/include/asm/processor.h
+++ b/arch/openrisc/include/asm/processor.h
@@ -73,7 +73,7 @@ struct thread_struct {
void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp);
void release_thread(struct task_struct *);
-unsigned long get_wchan(struct task_struct *p);
+unsigned long __get_wchan(struct task_struct *p);
#define cpu_relax() barrier()
diff --git a/arch/openrisc/kernel/process.c b/arch/openrisc/kernel/process.c
index b0698d9ce14f..3c0c91bcdcba 100644
--- a/arch/openrisc/kernel/process.c
+++ b/arch/openrisc/kernel/process.c
@@ -263,7 +263,7 @@ void dump_elf_thread(elf_greg_t *dest, struct pt_regs* regs)
dest[35] = 0;
}
-unsigned long get_wchan(struct task_struct *p)
+unsigned long __get_wchan(struct task_struct *p)
{
/* TODO */
diff --git a/arch/parisc/include/asm/processor.h b/arch/parisc/include/asm/processor.h
index eeb7da064289..85a2dbfe5278 100644
--- a/arch/parisc/include/asm/processor.h
+++ b/arch/parisc/include/asm/processor.h
@@ -273,7 +273,7 @@ struct mm_struct;
/* Free all resources held by a thread. */
extern void release_thread(struct task_struct *);
-extern unsigned long get_wchan(struct task_struct *p);
+extern unsigned long __get_wchan(struct task_struct *p);
#define KSTK_EIP(tsk) ((tsk)->thread.regs.iaoq[0])
#define KSTK_ESP(tsk) ((tsk)->thread.regs.gr[30])
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index 4f36c16aec86..f393d24e4b1c 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -245,15 +245,12 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
}
unsigned long
-get_wchan(struct task_struct *p)
+__get_wchan(struct task_struct *p)
{
struct unwind_frame_info info;
unsigned long ip;
int count = 0;
- if (!p || p == current || task_is_running(p))
- return 0;
-
/*
* These bracket the sleeping functions..
*/
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index f348e564f7dd..e39bd0ff69f3 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -300,7 +300,7 @@ struct thread_struct {
#define task_pt_regs(tsk) ((tsk)->thread.regs)
-unsigned long get_wchan(struct task_struct *p);
+unsigned long __get_wchan(struct task_struct *p);
#define KSTK_EIP(tsk) ((tsk)->thread.regs? (tsk)->thread.regs->nip: 0)
#define KSTK_ESP(tsk) ((tsk)->thread.regs? (tsk)->thread.regs->gpr[1]: 0)
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index c590e1219913..365e538ff2d7 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -2111,14 +2111,11 @@ int validate_sp(unsigned long sp, struct task_struct *p,
EXPORT_SYMBOL(validate_sp);
-static unsigned long __get_wchan(struct task_struct *p)
+static unsigned long ___get_wchan(struct task_struct *p)
{
unsigned long ip, sp;
int count = 0;
- if (!p || p == current || task_is_running(p))
- return 0;
-
sp = p->thread.ksp;
if (!validate_sp(sp, p, STACK_FRAME_OVERHEAD))
return 0;
@@ -2137,14 +2134,14 @@ static unsigned long __get_wchan(struct task_struct *p)
return 0;
}
-unsigned long get_wchan(struct task_struct *p)
+unsigned long __get_wchan(struct task_struct *p)
{
unsigned long ret;
if (!try_get_task_stack(p))
return 0;
- ret = __get_wchan(p);
+ ret = ___get_wchan(p);
put_task_stack(p);
diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
index 46b492c78cbb..0749924d9e55 100644
--- a/arch/riscv/include/asm/processor.h
+++ b/arch/riscv/include/asm/processor.h
@@ -66,7 +66,7 @@ static inline void release_thread(struct task_struct *dead_task)
{
}
-extern unsigned long get_wchan(struct task_struct *p);
+extern unsigned long __get_wchan(struct task_struct *p);
static inline void wait_for_interrupt(void)
diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c
index 95b4ad1b6708..7c35af666d42 100644
--- a/arch/riscv/kernel/stacktrace.c
+++ b/arch/riscv/kernel/stacktrace.c
@@ -148,16 +148,14 @@ static bool save_wchan(void *arg, unsigned long pc)
return true;
}
-unsigned long get_wchan(struct task_struct *task)
+unsigned long __get_wchan(struct task_struct *task)
{
unsigned long pc = 0;
- if (likely(task && task != current && !task_is_running(task))) {
- if (!try_get_task_stack(task))
- return 0;
- walk_stackframe(task, NULL, save_wchan, &pc);
- put_task_stack(task);
- }
+ if (!try_get_task_stack(task))
+ return 0;
+ walk_stackframe(task, NULL, save_wchan, &pc);
+ put_task_stack(task);
return pc;
}
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index 2ba16e67c96d..e273064382bd 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -192,7 +192,7 @@ static inline void release_thread(struct task_struct *tsk) { }
void guarded_storage_release(struct task_struct *tsk);
void gs_load_bc_cb(struct pt_regs *regs);
-unsigned long get_wchan(struct task_struct *p);
+unsigned long __get_wchan(struct task_struct *p);
#define task_pt_regs(tsk) ((struct pt_regs *) \
(task_stack_page(tsk) + THREAD_SIZE) - 1)
#define KSTK_EIP(tsk) (task_pt_regs(tsk)->psw.addr)
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index d015cb1027fa..1143e46d8683 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -191,12 +191,12 @@ void execve_tail(void)
asm volatile("sfpc %0" : : "d" (0));
}
-unsigned long get_wchan(struct task_struct *p)
+unsigned long __get_wchan(struct task_struct *p)
{
struct unwind_state state;
unsigned long ip = 0;
- if (!p || p == current || task_is_running(p) || !task_stack_page(p))
+ if (!task_stack_page(p))
return 0;
if (!try_get_task_stack(p))
diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h
index 6c7966e62775..48c5f014177d 100644
--- a/arch/sh/include/asm/processor_32.h
+++ b/arch/sh/include/asm/processor_32.h
@@ -181,7 +181,7 @@ static inline void show_code(struct pt_regs *regs)
}
#endif
-extern unsigned long get_wchan(struct task_struct *p);
+extern unsigned long __get_wchan(struct task_struct *p);
#define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc)
#define KSTK_ESP(tsk) (task_pt_regs(tsk)->regs[15])
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c
index 717de05c81f4..1c28e3cddb60 100644
--- a/arch/sh/kernel/process_32.c
+++ b/arch/sh/kernel/process_32.c
@@ -182,13 +182,10 @@ __switch_to(struct task_struct *prev, struct task_struct *next)
return prev;
}
-unsigned long get_wchan(struct task_struct *p)
+unsigned long __get_wchan(struct task_struct *p)
{
unsigned long pc;
- if (!p || p == current || task_is_running(p))
- return 0;
-
/*
* The same comment as on the Alpha applies here, too ...
*/
diff --git a/arch/sparc/include/asm/processor_32.h b/arch/sparc/include/asm/processor_32.h
index b6242f7771e9..647bf0ac7beb 100644
--- a/arch/sparc/include/asm/processor_32.h
+++ b/arch/sparc/include/asm/processor_32.h
@@ -89,7 +89,7 @@ static inline void start_thread(struct pt_regs * regs, unsigned long pc,
/* Free all resources held by a thread. */
#define release_thread(tsk) do { } while(0)
-unsigned long get_wchan(struct task_struct *);
+unsigned long __get_wchan(struct task_struct *);
#define task_pt_regs(tsk) ((tsk)->thread.kregs)
#define KSTK_EIP(tsk) ((tsk)->thread.kregs->pc)
diff --git a/arch/sparc/include/asm/processor_64.h b/arch/sparc/include/asm/processor_64.h
index 5cf145f18f36..ae851e8fce4c 100644
--- a/arch/sparc/include/asm/processor_64.h
+++ b/arch/sparc/include/asm/processor_64.h
@@ -183,7 +183,7 @@ do { \
/* Free all resources held by a thread. */
#define release_thread(tsk) do { } while (0)
-unsigned long get_wchan(struct task_struct *task);
+unsigned long __get_wchan(struct task_struct *task);
#define task_pt_regs(tsk) (task_thread_info(tsk)->kregs)
#define KSTK_EIP(tsk) (task_pt_regs(tsk)->tpc)
diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c
index bbbe0cfef746..2dc0bf9fe62e 100644
--- a/arch/sparc/kernel/process_32.c
+++ b/arch/sparc/kernel/process_32.c
@@ -365,7 +365,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg,
return 0;
}
-unsigned long get_wchan(struct task_struct *task)
+unsigned long __get_wchan(struct task_struct *task)
{
unsigned long pc, fp, bias = 0;
unsigned long task_base = (unsigned long) task;
@@ -373,9 +373,6 @@ unsigned long get_wchan(struct task_struct *task)
struct reg_window32 *rw;
int count = 0;
- if (!task || task == current || task_is_running(task))
- goto out;
-
fp = task_thread_info(task)->ksp + bias;
do {
/* Bogus frame pointer? */
diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c
index d1cc410d2f64..f5b2cac8669f 100644
--- a/arch/sparc/kernel/process_64.c
+++ b/arch/sparc/kernel/process_64.c
@@ -663,7 +663,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
return 0;
}
-unsigned long get_wchan(struct task_struct *task)
+unsigned long __get_wchan(struct task_struct *task)
{
unsigned long pc, fp, bias = 0;
struct thread_info *tp;
@@ -671,9 +671,6 @@ unsigned long get_wchan(struct task_struct *task)
unsigned long ret = 0;
int count = 0;
- if (!task || task == current || task_is_running(task))
- goto out;
-
tp = task_thread_info(task);
bias = STACK_BIAS;
fp = task_thread_info(task)->ksp + bias;
diff --git a/arch/um/include/asm/processor-generic.h b/arch/um/include/asm/processor-generic.h
index b5cf0ed116d9..579692a40a55 100644
--- a/arch/um/include/asm/processor-generic.h
+++ b/arch/um/include/asm/processor-generic.h
@@ -106,6 +106,6 @@ extern struct cpuinfo_um boot_cpu_data;
#define cache_line_size() (boot_cpu_data.cache_alignment)
#define KSTK_REG(tsk, reg) get_thread_reg(reg, &tsk->thread.switch_buf)
-extern unsigned long get_wchan(struct task_struct *p);
+extern unsigned long __get_wchan(struct task_struct *p);
#endif
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index 8d84684000b0..f6b2bdc9d78a 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -364,14 +364,11 @@ unsigned long arch_align_stack(unsigned long sp)
}
#endif
-unsigned long get_wchan(struct task_struct *p)
+unsigned long __get_wchan(struct task_struct *p)
{
unsigned long stack_page, sp, ip;
bool seen_sched = 0;
- if ((p == NULL) || (p == current) || task_is_running(p))
- return 0;
-
stack_page = (unsigned long) task_stack_page(p);
/* Bail if the process has no kernel stack for some reason */
if (stack_page == 0)
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 3401c9977baf..c4e9586441e8 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -591,7 +591,7 @@ static inline void load_sp0(unsigned long sp0)
/* Free all resources held by a thread. */
extern void release_thread(struct task_struct *);
-unsigned long get_wchan(struct task_struct *p);
+unsigned long __get_wchan(struct task_struct *p);
/*
* Generic CPUID function
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index a4d437727345..6d707226f4a3 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -969,13 +969,10 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
* because the task might wake up and we might look at a stack
* changing under us.
*/
-unsigned long get_wchan(struct task_struct *p)
+unsigned long __get_wchan(struct task_struct *p)
{
unsigned long entry = 0;
- if (p == current || task_is_running(p))
- return 0;
-
stack_trace_save_tsk(p, &entry, 1, 0);
return entry;
}
diff --git a/arch/xtensa/include/asm/processor.h b/arch/xtensa/include/asm/processor.h
index 9dd4efe1bf0b..f8fab2536493 100644
--- a/arch/xtensa/include/asm/processor.h
+++ b/arch/xtensa/include/asm/processor.h
@@ -215,7 +215,7 @@ struct mm_struct;
/* Free all resources held by a thread. */
#define release_thread(thread) do { } while(0)
-extern unsigned long get_wchan(struct task_struct *p);
+extern unsigned long __get_wchan(struct task_struct *p);
#define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc)
#define KSTK_ESP(tsk) (task_pt_regs(tsk)->areg[1])
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
index 060165340612..47f933fed870 100644
--- a/arch/xtensa/kernel/process.c
+++ b/arch/xtensa/kernel/process.c
@@ -298,15 +298,12 @@ int copy_thread(unsigned long clone_flags, unsigned long usp_thread_fn,
* These bracket the sleeping functions..
*/
-unsigned long get_wchan(struct task_struct *p)
+unsigned long __get_wchan(struct task_struct *p)
{
unsigned long sp, pc;
unsigned long stack_page = (unsigned long) task_stack_page(p);
int count = 0;
- if (!p || p == current || task_is_running(p))
- return 0;
-
sp = p->thread.sp;
pc = MAKE_PC_FROM_RA(p->thread.ra, p->thread.sp);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 5d0a44e4db4b..cbf69d0d6952 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -2141,6 +2141,7 @@ static inline void set_task_cpu(struct task_struct *p, unsigned int cpu)
#endif /* CONFIG_SMP */
extern bool sched_task_on_rq(struct task_struct *p);
+extern unsigned long get_wchan(struct task_struct *p);
/*
* In order to reduce various lock holder preemption latencies provide an
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 380938831b13..c1d219289872 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -1963,6 +1963,25 @@ bool sched_task_on_rq(struct task_struct *p)
return task_on_rq_queued(p);
}
+unsigned long get_wchan(struct task_struct *p)
+{
+ unsigned long ip = 0;
+ unsigned int state;
+
+ if (!p || p == current)
+ return 0;
+
+ /* Only get wchan if task is blocked and we can keep it that way. */
+ raw_spin_lock_irq(&p->pi_lock);
+ state = READ_ONCE(p->__state);
+ smp_rmb(); /* see try_to_wake_up() */
+ if (state != TASK_RUNNING && state != TASK_WAKING && !p->on_rq)
+ ip = __get_wchan(p);
+ raw_spin_unlock_irq(&p->pi_lock);
+
+ return ip;
+}
+
static inline void enqueue_task(struct rq *rq, struct task_struct *p, int flags)
{
if (!(flags & ENQUEUE_NOCLOCK))
--
2.47.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 5.15.y 3/4] x86: Fix __get_wchan() for !STACKTRACE
2025-07-22 6:26 [PATCH 5.15.y 0/4] Fix blank WHCAN value in 'ps' output Siddhi Katage
2025-07-22 6:26 ` [PATCH 5.15.y 1/4] x86: Fix get_wchan() to support the ORC unwinder Siddhi Katage
2025-07-22 6:26 ` [PATCH 5.15.y 2/4] sched: Add wrapper for get_wchan() to keep task blocked Siddhi Katage
@ 2025-07-22 6:26 ` Siddhi Katage
2025-07-23 4:34 ` Sasha Levin
2025-07-22 6:26 ` [PATCH 5.15.y 4/4] x86: Pin task-stack in __get_wchan() Siddhi Katage
2025-07-22 9:51 ` [PATCH 5.15.y 0/4] Fix blank WHCAN value in 'ps' output Greg KH
4 siblings, 1 reply; 12+ messages in thread
From: Siddhi Katage @ 2025-07-22 6:26 UTC (permalink / raw)
To: stable
From: Peter Zijlstra <peterz@infradead.org>
[ Upstream commit 5d1ceb3969b6b2e47e2df6d17790a7c5a20fcbb4 ]
Use asm/unwind.h to implement wchan, since we cannot always rely on
STACKTRACE=y.
Fixes: bc9bbb81730e ("x86: Fix get_wchan() to support the ORC unwinder")
Reported-by: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Link: https://lkml.kernel.org/r/20211022152104.137058575@infradead.org
Signed-off-by: Siddhi Katage <siddhi.katage@oracle.com>
---
arch/x86/kernel/process.c | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 6d707226f4a3..16d4c5a79d68 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -43,6 +43,7 @@
#include <asm/io_bitmap.h>
#include <asm/proto.h>
#include <asm/frame.h>
+#include <asm/unwind.h>
#include "process.h"
@@ -971,10 +972,20 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
*/
unsigned long __get_wchan(struct task_struct *p)
{
- unsigned long entry = 0;
+ struct unwind_state state;
+ unsigned long addr = 0;
- stack_trace_save_tsk(p, &entry, 1, 0);
- return entry;
+ for (unwind_start(&state, p, NULL, NULL); !unwind_done(&state);
+ unwind_next_frame(&state)) {
+ addr = unwind_get_return_address(&state);
+ if (!addr)
+ break;
+ if (in_sched_functions(addr))
+ continue;
+ break;
+ }
+
+ return addr;
}
long do_arch_prctl_common(struct task_struct *task, int option,
--
2.47.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 5.15.y 4/4] x86: Pin task-stack in __get_wchan()
2025-07-22 6:26 [PATCH 5.15.y 0/4] Fix blank WHCAN value in 'ps' output Siddhi Katage
` (2 preceding siblings ...)
2025-07-22 6:26 ` [PATCH 5.15.y 3/4] x86: Fix __get_wchan() for !STACKTRACE Siddhi Katage
@ 2025-07-22 6:26 ` Siddhi Katage
2025-07-23 4:34 ` Sasha Levin
2025-07-22 9:51 ` [PATCH 5.15.y 0/4] Fix blank WHCAN value in 'ps' output Greg KH
4 siblings, 1 reply; 12+ messages in thread
From: Siddhi Katage @ 2025-07-22 6:26 UTC (permalink / raw)
To: stable
From: Peter Zijlstra <peterz@infradead.org>
[ Upstream commit 0dc636b3b757a6b747a156de613275f9d74a4a66 ]
When commit 5d1ceb3969b6 ("x86: Fix __get_wchan() for !STACKTRACE")
moved from stacktrace to native unwind_*() usage, the
try_get_task_stack() got lost, leading to use-after-free issues for
dying tasks.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Fixes: 5d1ceb3969b6 ("x86: Fix __get_wchan() for !STACKTRACE")
Link: https://bugzilla.kernel.org/show_bug.cgi?id=215031
Link: https://lore.kernel.org/stable/YZV02RCRVHIa144u@fedora64.linuxtx.org/
Reported-by: Justin Forbes <jmforbes@linuxtx.org>
Reported-by: Holger Hoffstätte <holger@applied-asynchrony.com>
Cc: Qi Zheng <zhengqi.arch@bytedance.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Siddhi Katage <siddhi.katage@oracle.com>
---
arch/x86/kernel/process.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 16d4c5a79d68..2a4218deddd2 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -975,6 +975,9 @@ unsigned long __get_wchan(struct task_struct *p)
struct unwind_state state;
unsigned long addr = 0;
+ if (!try_get_task_stack(p))
+ return 0;
+
for (unwind_start(&state, p, NULL, NULL); !unwind_done(&state);
unwind_next_frame(&state)) {
addr = unwind_get_return_address(&state);
@@ -985,6 +988,8 @@ unsigned long __get_wchan(struct task_struct *p)
break;
}
+ put_task_stack(p);
+
return addr;
}
--
2.47.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 5.15.y 0/4] Fix blank WHCAN value in 'ps' output
2025-07-22 6:26 [PATCH 5.15.y 0/4] Fix blank WHCAN value in 'ps' output Siddhi Katage
` (3 preceding siblings ...)
2025-07-22 6:26 ` [PATCH 5.15.y 4/4] x86: Pin task-stack in __get_wchan() Siddhi Katage
@ 2025-07-22 9:51 ` Greg KH
2025-07-22 11:13 ` [External] : " Siddhi Katage
4 siblings, 1 reply; 12+ messages in thread
From: Greg KH @ 2025-07-22 9:51 UTC (permalink / raw)
To: Siddhi Katage; +Cc: stable
On Tue, Jul 22, 2025 at 06:26:38AM +0000, Siddhi Katage wrote:
> The 'ps' output prints blank(hyphen) WHCAN value for all the tasks.
> This patchset will help print the correct WCHAN value.
Did you forget to also backport commit b88f55389ad2 ("profiling: remove
profile=sleep support") for this series?
thanks,
greg k-h
^ permalink raw reply [flat|nested] 12+ messages in thread
* RE: [External] : Re: [PATCH 5.15.y 0/4] Fix blank WHCAN value in 'ps' output
2025-07-22 9:51 ` [PATCH 5.15.y 0/4] Fix blank WHCAN value in 'ps' output Greg KH
@ 2025-07-22 11:13 ` Siddhi Katage
2025-07-22 12:15 ` Greg KH
0 siblings, 1 reply; 12+ messages in thread
From: Siddhi Katage @ 2025-07-22 11:13 UTC (permalink / raw)
To: Greg KH; +Cc: stable@vger.kernel.org
Hi Greg,
This patch is already present in stable-5.15.y.
Thanks,
Siddhi.
-----Original Message-----
From: Greg KH <gregkh@linuxfoundation.org>
Sent: Tuesday, July 22, 2025 3:21 PM
To: Siddhi Katage <siddhi.katage@oracle.com>
Cc: stable@vger.kernel.org
Subject: [External] : Re: [PATCH 5.15.y 0/4] Fix blank WHCAN value in 'ps' output
On Tue, Jul 22, 2025 at 06:26:38AM +0000, Siddhi Katage wrote:
> The 'ps' output prints blank(hyphen) WHCAN value for all the tasks.
> This patchset will help print the correct WCHAN value.
Did you forget to also backport commit b88f55389ad2 ("profiling: remove profile=sleep support") for this series?
thanks,
greg k-h
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [External] : Re: [PATCH 5.15.y 0/4] Fix blank WHCAN value in 'ps' output
2025-07-22 11:13 ` [External] : " Siddhi Katage
@ 2025-07-22 12:15 ` Greg KH
0 siblings, 0 replies; 12+ messages in thread
From: Greg KH @ 2025-07-22 12:15 UTC (permalink / raw)
To: Siddhi Katage; +Cc: stable@vger.kernel.org
On Tue, Jul 22, 2025 at 11:13:08AM +0000, Siddhi Katage wrote:
> Hi Greg,
>
> This patch is already present in stable-5.15.y.
Ah, missed that, thanks!
greg k-h
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 5.15.y 2/4] sched: Add wrapper for get_wchan() to keep task blocked
2025-07-22 6:26 ` [PATCH 5.15.y 2/4] sched: Add wrapper for get_wchan() to keep task blocked Siddhi Katage
@ 2025-07-23 4:33 ` Sasha Levin
0 siblings, 0 replies; 12+ messages in thread
From: Sasha Levin @ 2025-07-23 4:33 UTC (permalink / raw)
To: stable, siddhi.katage; +Cc: Sasha Levin
[ Sasha's backport helper bot ]
Hi,
Summary of potential issues:
ℹ️ This is part 2/4 of a series
⚠️ Found follow-up fixes in mainline
The upstream commit SHA1 provided is correct: 42a20f86dc19f9282d974df0ba4d226c865ab9dd
WARNING: Author mismatch between patch and upstream commit:
Backport author: Siddhi Katage <siddhi.katage@oracle.com>
Commit author: Kees Cook <keescook@chromium.org>
Status in newer kernel trees:
6.15.y | Present (exact SHA1)
6.12.y | Present (exact SHA1)
6.6.y | Present (exact SHA1)
6.1.y | Present (exact SHA1)
Found fixes commits:
b88f55389ad2 profiling: remove profile=sleep support
Note: Could not generate a diff with upstream commit:
---
Note: Could not generate diff - patch failed to apply for comparison
---
NOTE: These results are for this patch alone. Full series testing will be
performed when all parts are received.
Results of testing on various branches:
| Branch | Patch Apply | Build Test |
|---------------------------|-------------|------------|
| 5.15 | Success | Success |
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 5.15.y 1/4] x86: Fix get_wchan() to support the ORC unwinder
2025-07-22 6:26 ` [PATCH 5.15.y 1/4] x86: Fix get_wchan() to support the ORC unwinder Siddhi Katage
@ 2025-07-23 4:33 ` Sasha Levin
0 siblings, 0 replies; 12+ messages in thread
From: Sasha Levin @ 2025-07-23 4:33 UTC (permalink / raw)
To: stable, siddhi.katage; +Cc: Sasha Levin
[ Sasha's backport helper bot ]
Hi,
Summary of potential issues:
⚠️ Found follow-up fixes in mainline
The upstream commit SHA1 provided is correct: bc9bbb81730ea667c31c5b284f95ee312bab466f
WARNING: Author mismatch between patch and upstream commit:
Backport author: Siddhi Katage <siddhi.katage@oracle.com>
Commit author: Qi Zheng <zhengqi.arch@bytedance.com>
Status in newer kernel trees:
6.15.y | Present (exact SHA1)
6.12.y | Present (exact SHA1)
6.6.y | Present (exact SHA1)
6.1.y | Present (exact SHA1)
Found fixes commits:
5d1ceb3969b6 x86: Fix __get_wchan() for !STACKTRACE
Note: The patch differs from the upstream commit:
---
1: bc9bbb81730e ! 1: 1f7a2f87bdde x86: Fix get_wchan() to support the ORC unwinder
@@ Metadata
## Commit message ##
x86: Fix get_wchan() to support the ORC unwinder
+ [ Upstream commit bc9bbb81730ea667c31c5b284f95ee312bab466f ]
+
Currently, the kernel CONFIG_UNWINDER_ORC option is enabled by default
on x86, but the implementation of get_wchan() is still based on the frame
pointer unwinder, so the /proc/<pid>/wchan usually returned 0 regardless
@@ Commit message
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lkml.kernel.org/r/20211008111626.271115116@infradead.org
+ Signed-off-by: Siddhi Katage <siddhi.katage@oracle.com>
## arch/x86/kernel/process.c ##
@@ arch/x86/kernel/process.c: unsigned long arch_randomize_brk(struct mm_struct *mm)
---
Results of testing on various branches:
| Branch | Patch Apply | Build Test |
|---------------------------|-------------|------------|
| 5.15 | Success | Success |
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 5.15.y 3/4] x86: Fix __get_wchan() for !STACKTRACE
2025-07-22 6:26 ` [PATCH 5.15.y 3/4] x86: Fix __get_wchan() for !STACKTRACE Siddhi Katage
@ 2025-07-23 4:34 ` Sasha Levin
0 siblings, 0 replies; 12+ messages in thread
From: Sasha Levin @ 2025-07-23 4:34 UTC (permalink / raw)
To: stable, siddhi.katage; +Cc: Sasha Levin
[ Sasha's backport helper bot ]
Hi,
Summary of potential issues:
ℹ️ This is part 3/4 of a series
⚠️ Found follow-up fixes in mainline
The upstream commit SHA1 provided is correct: 5d1ceb3969b6b2e47e2df6d17790a7c5a20fcbb4
WARNING: Author mismatch between patch and upstream commit:
Backport author: Siddhi Katage <siddhi.katage@oracle.com>
Commit author: Peter Zijlstra <peterz@infradead.org>
Status in newer kernel trees:
6.15.y | Present (exact SHA1)
6.12.y | Present (exact SHA1)
6.6.y | Present (exact SHA1)
6.1.y | Present (exact SHA1)
Found fixes commits:
0dc636b3b757 x86: Pin task-stack in __get_wchan()
Note: Could not generate a diff with upstream commit:
---
Note: Could not generate diff - patch failed to apply for comparison
---
NOTE: These results are for this patch alone. Full series testing will be
performed when all parts are received.
Results of testing on various branches:
| Branch | Patch Apply | Build Test |
|---------------------------|-------------|------------|
| 5.15 | Success | Success |
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 5.15.y 4/4] x86: Pin task-stack in __get_wchan()
2025-07-22 6:26 ` [PATCH 5.15.y 4/4] x86: Pin task-stack in __get_wchan() Siddhi Katage
@ 2025-07-23 4:34 ` Sasha Levin
0 siblings, 0 replies; 12+ messages in thread
From: Sasha Levin @ 2025-07-23 4:34 UTC (permalink / raw)
To: stable; +Cc: Sasha Levin
[ Sasha's backport helper bot ]
Hi,
✅ All tests passed successfully. No issues detected.
No action required from the submitter.
The upstream commit SHA1 provided is correct: 0dc636b3b757a6b747a156de613275f9d74a4a66
WARNING: Author mismatch between patch and upstream commit:
Backport author: Siddhi Katage <siddhi.katage@oracle.com>
Commit author: Peter Zijlstra <peterz@infradead.org>
Status in newer kernel trees:
6.15.y | Present (exact SHA1)
6.12.y | Present (exact SHA1)
6.6.y | Present (exact SHA1)
6.1.y | Present (exact SHA1)
Note: Could not generate a diff with upstream commit:
---
Note: Could not generate diff - patch failed to apply for comparison
---
Results of testing on various branches:
| Branch | Patch Apply | Build Test |
|---------------------------|-------------|------------|
| 5.15 | Success | Success |
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2025-07-23 4:34 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-22 6:26 [PATCH 5.15.y 0/4] Fix blank WHCAN value in 'ps' output Siddhi Katage
2025-07-22 6:26 ` [PATCH 5.15.y 1/4] x86: Fix get_wchan() to support the ORC unwinder Siddhi Katage
2025-07-23 4:33 ` Sasha Levin
2025-07-22 6:26 ` [PATCH 5.15.y 2/4] sched: Add wrapper for get_wchan() to keep task blocked Siddhi Katage
2025-07-23 4:33 ` Sasha Levin
2025-07-22 6:26 ` [PATCH 5.15.y 3/4] x86: Fix __get_wchan() for !STACKTRACE Siddhi Katage
2025-07-23 4:34 ` Sasha Levin
2025-07-22 6:26 ` [PATCH 5.15.y 4/4] x86: Pin task-stack in __get_wchan() Siddhi Katage
2025-07-23 4:34 ` Sasha Levin
2025-07-22 9:51 ` [PATCH 5.15.y 0/4] Fix blank WHCAN value in 'ps' output Greg KH
2025-07-22 11:13 ` [External] : " Siddhi Katage
2025-07-22 12:15 ` Greg KH
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).