From: Greg Kroah-Hartman Date: Thu, 18 Nov 2021 12:15:48 +0000 (+0100) Subject: Revert "sched: Add wrapper for get_wchan() to keep task blocked" X-Git-Tag: v5.14.20~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=961913f45ff64ee68b689ae8070e1ab42108d02b;p=thirdparty%2Fkernel%2Fstable.git Revert "sched: Add wrapper for get_wchan() to keep task blocked" This reverts commit e9ede14c116f1a6246eee89d320d60a90a86b5d5 which is commit 42a20f86dc19f9282d974df0ba4d226c865ab9dd upstream. It has been reported to be causing problems, and is being reworked upstream and has been dropped from the current 5.15.y stable queue until it gets resolved. Reported-by: Chris Rankin Reported-by: Thorsten Leemhuis Link: https://lore.kernel.org/r/ed000478-2a60-0066-c337-a04bffc112b1@leemhuis.info Cc: Stephen Rothwell Cc: Peter Zijlstra (Intel) Cc: Kees Cook Cc: Geert Uytterhoeven Cc: Russell King (Oracle) Cc: Mark Rutland Cc: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- diff --git a/arch/alpha/include/asm/processor.h b/arch/alpha/include/asm/processor.h index 090499c99c1c1..6100431da07a3 100644 --- a/arch/alpha/include/asm/processor.h +++ b/arch/alpha/include/asm/processor.h @@ -42,7 +42,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 5f8527081da92..a5123ea426ce5 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -376,11 +376,12 @@ 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 04a5268e592b9..e4031ecd3c8c1 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 db96cc8783891..1b9576d21e244 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 6af68edfa53ab..9e6b972863077 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 261be96fa0c30..fc9e8b37eaa84 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -283,11 +283,13 @@ 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 922355eb7eefa..b6517fd03d7b6 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -251,7 +251,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 set_task_sctlr_el1(u64 sctlr); diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 46995c972ff5f..c858b857c1ecf 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -544,11 +544,13 @@ __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 817dd60ff152d..9e933021fe8e0 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 9f78f5d215117..1b280ef080045 100644 --- a/arch/csky/kernel/stacktrace.c +++ b/arch/csky/kernel/stacktrace.c @@ -111,11 +111,12 @@ 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; - walk_stackframe(task, NULL, save_wchan, &pc); + if (likely(task && task != current && !task_is_running(task))) + 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 141a23eb62b74..a060b41b2d31c 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 8833fa4f5d516..2ac27e4248a46 100644 --- a/arch/h8300/kernel/process.c +++ b/arch/h8300/kernel/process.c @@ -128,12 +128,15 @@ 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 615f7e49968e6..9f0cc99420bee 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 232dfd8956aa2..6a6835fb42425 100644 --- a/arch/hexagon/kernel/process.c +++ b/arch/hexagon/kernel/process.c @@ -130,11 +130,13 @@ 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 45365c2ef5983..2d8bcdc27d7f8 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 834df24a88f12..e56d63f4abf9d 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -523,12 +523,15 @@ 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 bacec548cb3c6..3750819ac5a13 100644 --- a/arch/m68k/include/asm/processor.h +++ b/arch/m68k/include/asm/processor.h @@ -125,7 +125,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 d2357cba09abe..db49f90917112 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -263,11 +263,13 @@ 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 7e9e92670df33..06c6e493590a2 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 5e2b91c1e8ced..62aa237180b67 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 252ed38ce8c5a..0c3550c82b726 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 637e6207e3500..73c8e7990a973 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,6 +662,8 @@ 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 e6bfc74972bb3..b82369c7659d4 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 49fab9e39cbff..391895b54d13c 100644 --- a/arch/nds32/kernel/process.c +++ b/arch/nds32/kernel/process.c @@ -233,12 +233,15 @@ 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; @@ -255,3 +258,5 @@ 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 b8125dfbcad2d..94bcb86f679f5 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 f8ea522a15880..9ff37ba2bb603 100644 --- a/arch/nios2/kernel/process.c +++ b/arch/nios2/kernel/process.c @@ -217,12 +217,15 @@ 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 aa1699c18add8..ad53b31848859 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 eeea6d54b198c..eb62429681fc8 100644 --- a/arch/openrisc/kernel/process.c +++ b/arch/openrisc/kernel/process.c @@ -265,7 +265,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 5e5ceb5b9631f..b5fbcd2c17808 100644 --- a/arch/parisc/include/asm/processor.h +++ b/arch/parisc/include/asm/processor.h @@ -277,7 +277,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 05e89d4fa911a..184ec3c1eae44 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -243,12 +243,15 @@ 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 e39bd0ff69f3a..f348e564f7dd5 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 247ef0b9bfa4e..185beb2905801 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -2111,11 +2111,14 @@ 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; @@ -2134,14 +2137,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 086821b44def1..021ed64ee608f 100644 --- a/arch/riscv/include/asm/processor.h +++ b/arch/riscv/include/asm/processor.h @@ -58,7 +58,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 0fcdc0233faca..315db3d0229bf 100644 --- a/arch/riscv/kernel/stacktrace.c +++ b/arch/riscv/kernel/stacktrace.c @@ -128,14 +128,16 @@ 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 (!try_get_task_stack(task)) - return 0; - walk_stackframe(task, NULL, save_wchan, &pc); - put_task_stack(task); + 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); + } return pc; } diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index f54c152bf2bf9..879b8e3f609cd 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 e5dd46b1bff8c..350e94d0cac23 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -181,12 +181,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 (!task_stack_page(p)) + if (!p || p == current || task_is_running(p) || !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 45240ec6b85a4..aa92cc933889d 100644 --- a/arch/sh/include/asm/processor_32.h +++ b/arch/sh/include/asm/processor_32.h @@ -180,7 +180,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 1c28e3cddb60d..717de05c81f49 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c @@ -182,10 +182,13 @@ __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 647bf0ac7beb9..b6242f7771e9e 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 ae851e8fce4c9..5cf145f18f36b 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 29a2f396f8601..93983d6d431de 100644 --- a/arch/sparc/kernel/process_32.c +++ b/arch/sparc/kernel/process_32.c @@ -368,7 +368,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; @@ -376,6 +376,9 @@ 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 fa8db86e561c7..d33c58a58d4ff 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c @@ -666,7 +666,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; @@ -674,6 +674,9 @@ 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 579692a40a556..b5cf0ed116d9e 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 82107373ac7e9..457a38db368b7 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -364,11 +364,14 @@ 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 6f9ed2e800f21..d2c11378c7832 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -588,7 +588,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 266962547b58c..cd426c3283ee1 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -943,10 +943,13 @@ 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 ad15fbc572838..7f63aca6a0d34 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 47f933fed8700..0601653406123 100644 --- a/arch/xtensa/kernel/process.c +++ b/arch/xtensa/kernel/process.c @@ -298,12 +298,15 @@ 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 4ee118cf06971..8e10c7accdbcc 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2030,7 +2030,6 @@ 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 5ea5b6d8b2a94..9289da7f0ac4a 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -1960,25 +1960,6 @@ 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))