sched: Add wrapper for get_wchan() to keep task blocked
authorKees Cook <keescook@chromium.org>
Wed, 29 Sep 2021 22:02:14 +0000 (15:02 -0700)
committerPeter Zijlstra <peterz@infradead.org>
Fri, 15 Oct 2021 09:25:14 +0000 (11:25 +0200)
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
50 files changed:
arch/alpha/include/asm/processor.h
arch/alpha/kernel/process.c
arch/arc/include/asm/processor.h
arch/arc/kernel/stacktrace.c
arch/arm/include/asm/processor.h
arch/arm/kernel/process.c
arch/arm64/include/asm/processor.h
arch/arm64/kernel/process.c
arch/csky/include/asm/processor.h
arch/csky/kernel/stacktrace.c
arch/h8300/include/asm/processor.h
arch/h8300/kernel/process.c
arch/hexagon/include/asm/processor.h
arch/hexagon/kernel/process.c
arch/ia64/include/asm/processor.h
arch/ia64/kernel/process.c
arch/m68k/include/asm/processor.h
arch/m68k/kernel/process.c
arch/microblaze/include/asm/processor.h
arch/microblaze/kernel/process.c
arch/mips/include/asm/processor.h
arch/mips/kernel/process.c
arch/nds32/include/asm/processor.h
arch/nds32/kernel/process.c
arch/nios2/include/asm/processor.h
arch/nios2/kernel/process.c
arch/openrisc/include/asm/processor.h
arch/openrisc/kernel/process.c
arch/parisc/include/asm/processor.h
arch/parisc/kernel/process.c
arch/powerpc/include/asm/processor.h
arch/powerpc/kernel/process.c
arch/riscv/include/asm/processor.h
arch/riscv/kernel/stacktrace.c
arch/s390/include/asm/processor.h
arch/s390/kernel/process.c
arch/sh/include/asm/processor_32.h
arch/sh/kernel/process_32.c
arch/sparc/include/asm/processor_32.h
arch/sparc/include/asm/processor_64.h
arch/sparc/kernel/process_32.c
arch/sparc/kernel/process_64.c
arch/um/include/asm/processor-generic.h
arch/um/kernel/process.c
arch/x86/include/asm/processor.h
arch/x86/kernel/process.c
arch/xtensa/include/asm/processor.h
arch/xtensa/kernel/process.c
include/linux/sched.h
kernel/sched/core.c

index 6100431da07a3bfaf4c822d7af7ad02cb2994854..090499c99c1c1e7c4716494bd140f9308dbc7db9 100644 (file)
@@ -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)
 
index a5123ea426ce58ed230d0fde4e8dfbb0c4155d84..5f8527081da92fc69d12b77be04f706475c21239 100644 (file)
@@ -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
index f28afcf5c6d10f941b94994adbf76034bb9729de..54db9d7bb562d3f9acb697a89610568076b9b4f9 100644 (file)
@@ -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__ */
 
index c376ff3147e7b5f73345bd69e3de0434b7f1c8fd..5372dc04e784789291f0f7a8ee38e624c4fb30b8 100644 (file)
@@ -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);
 }
index 9e6b9728630773f445a094e7f9a837d2127a5ce1..6af68edfa53abc7a72789f23eb7f90efb8a6b0b5 100644 (file)
@@ -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)
index 0e2d3051741ed52df555644ebd38792cf5ee10d9..96f577e59595fb3ff8dbbf9e8a6f4aa48c221c46 100644 (file)
@@ -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);
index ee2bdc1b9f5bb5028d90f64d57ee3af9a1d62fcc..55ca034238eaead27611d710967181a60f753954 100644 (file)
@@ -257,7 +257,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);
 
index 40adb8cdbf5af667d595abe5908cb81723d89722..aacf2f5559a8bda4ed609a6170def696f7a20306 100644 (file)
@@ -528,13 +528,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)
index 9e933021fe8e08335ebfb26dd4a902e2588c2e78..817dd60ff152dca9c0abd7a6cce2baa76d35415f 100644 (file)
@@ -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)
index 1b280ef0800452bc8cf4e2e7ddeab29847cd3ae8..9f78f5d2151172460d3effa09358b9a814a903df 100644 (file)
@@ -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;
 }
 
index a060b41b2d31ca74f79aecfb50cbcef35ebb8b39..141a23eb62b747edd15ee4b27178eca2639a7e5f 100644 (file)
@@ -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)   \
        ({                       \
index 2ac27e4248a4623468d1171b930f5764b1cea80e..8833fa4f5d51640126a5e0c36a00b0164222ceae 100644 (file)
@@ -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 {
index 9f0cc99420bee39f8e97139da5f0c6a9844f6ba4..615f7e49968e619626f423b10af853f2a80ddbf1 100644 (file)
@@ -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.  */
 
index 6a6835fb42425a6e69b86e9951751fb28d4d658c..232dfd8956aa22bba4adb9b36292f782ceca8710 100644 (file)
@@ -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;
index 2d8bcdc27d7f85251483cb85cd9eee1176087e75..45365c2ef59833a5bffd3f9ee1755302ca0f37b8 100644 (file)
@@ -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)                                  \
index e56d63f4abf9decb151c1b6333062bf4c9657680..834df24a88f12cd0514770f51dccd2cea04f773f 100644 (file)
@@ -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
index f4d82c619a5c48ec7b3a87df334089c0e44873e6..ffeda9aa526a54206ad85129b33e2d3b19982bd8 100644 (file)
@@ -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)   \
     ({                 \
index 1ab692b952cd6235db7418cdb7b4cf6a83155f4e..a6030dbaa0891675735c418ac8041ddaf455a543 100644 (file)
@@ -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;
index 06c6e493590a23b2833b25b29326399ad380c121..7e9e92670df3340f2acd27f8563f3f6493a5de39 100644 (file)
@@ -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
index 62aa237180b6724a121e2399bbd12b738d532839..5e2b91c1e8ced0f9eeb1ed04eaa34ea3639bce49 100644 (file)
@@ -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;
index 0c3550c82b726863ad98f4f13bf23d17d7c50f20..252ed38ce8c5af53f8f9c11e584fbbbcff3244b9 100644 (file)
@@ -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))
index 95aa86fa6077858181b386b794a3cd17527820fd..cbff1b974f882ee9431c831ad68a2d490e5157c7 100644 (file)
@@ -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;
 
index b82369c7659d4dedeeec151859654bad0a789749..e6bfc74972bb3bdfd7d9946bc039f18b11f0eaa5 100644 (file)
@@ -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()
 
index 391895b54d13cb5ace1a174104385ff4278e8c04..49fab9e39cbffb6d9fbfda8e31bbe6901fad4389 100644 (file)
@@ -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);
index 94bcb86f679f5e7ee542eb10d841fddf9ffeada0..b8125dfbcad2d6cbe42239aeb3b2afa77bf6a79b 100644 (file)
@@ -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)
index 9ff37ba2bb6032184fcf3d284b00f42f5b3b8ff5..f8ea522a15880c4018588b01b6b4bcd6fa550a5f 100644 (file)
@@ -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 {
index ad53b318488597fbabc7618f94d908616fd960fa..aa1699c18add85ee7ec81918ba0f4b0129b2ce1a 100644 (file)
@@ -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()
 
index b0698d9ce14faf9dd389f9d28740caa04a8e6e1c..3c0c91bcdcbaa135feaf0c3e2cb23344425852cd 100644 (file)
@@ -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 */
 
index eeb7da06428916b46f7989c5b67cf8fc54ef302d..85a2dbfe527876d4cf668553afa7003cf99ccd1c 100644 (file)
@@ -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])
index 38ec4ae812396c737aed58714faf8b287984018f..4f562dee65a2c5d06fab1553907b6321f852e4b4 100644 (file)
@@ -240,15 +240,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..
         */
index f348e564f7dd5407737aad61e785fb023c2a51f8..e39bd0ff69f3a1ef2a5345886b1c2fc1d56abe71 100644 (file)
@@ -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)
index 50436b52c2133ee900250e49c0ad622d11948ab3..406d7ee9e3220c336d99a23337ba5171575aaf68 100644 (file)
@@ -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);
 
index 46b492c78cbbf1a6c031e07d51257b3d7d25f122..0749924d9e552dc26786a9b3be2d44d593d8fc07 100644 (file)
@@ -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)
index 315db3d0229bfbfcb14d6a765e179fd3ecdbba55..0fcdc0233faca3df8d1c5237f7d2f347737c33d4 100644 (file)
@@ -128,16 +128,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;
 }
 
index 879b8e3f609cd53abea5f44e211ed29e1d5b235c..f54c152bf2bf9a42ca6cbeb2c0c98394124bb0e2 100644 (file)
@@ -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)
index 350e94d0cac23a4645ca5fcb7b63b46e662f55c2..e5dd46b1bff8cbc3bd85c64799b14a07b20b4357 100644 (file)
@@ -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 (!p || p == current || task_is_running(p) || !task_stack_page(p))
+       if (!task_stack_page(p))
                return 0;
 
        if (!try_get_task_stack(p))
index aa92cc933889df791ee756400d348412cc070415..45240ec6b85a43de127afb13b786c1142fcdb178 100644 (file)
@@ -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])
index 717de05c81f49f175f528433445f531107cc84d2..1c28e3cddb60dfc63fcf2e5f162d29c23b2c64a5 100644 (file)
@@ -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 ...
         */
index b6242f7771e9e845ab9a24720e99f66a86c8ae51..647bf0ac7beb9445dbeb1730399a94038b394d22 100644 (file)
@@ -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)
index 5cf145f18f36b01f416f56084e213d697fae045e..ae851e8fce4c9298ed832eede6ecf8381bba6db6 100644 (file)
@@ -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)
index bbbe0cfef7465fa931656e3cb0c9217eba4241bc..2dc0bf9fe62eb66ac115f743f3fff7fdd2cbf465 100644 (file)
@@ -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? */
index d1cc410d2f647c964e01a8f93bf1033cd2bbd034..f5b2cac8669f9bc6308718dcc37b569b638ec129 100644 (file)
@@ -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;
index b5cf0ed116d9eafa3e4353bb9ffdd05b522530cd..579692a40a5560ffb6879a5376e909b6e4f76f27 100644 (file)
@@ -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
index 457a38db368b7d77ed4b13ccace09d0939a905f4..82107373ac7e9243ab2063b9828f5c3cddb13900 100644 (file)
@@ -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)
index 9ad2acaaae9b84be5bece5730bfb8e7c746cc892..e81177edc681ac565b63be147c9fdbfd4fbfbe1f 100644 (file)
@@ -589,7 +589,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
index e645925f9f027bda7a1f58b2dfdf6f59a92f922b..a69885a9d71133826d38b5e11ae698a749948aeb 100644 (file)
@@ -942,13 +942,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;
 }
index 7f63aca6a0d340632646ccceb9f31ae63b878402..ad15fbc572838c9f88692f2ce8fd0dc6a3961447 100644 (file)
@@ -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])
index 0601653406123f5e1006f582bdcb75040a740a50..47f933fed87005d794c0f50343bfc81720207e8c 100644 (file)
@@ -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);
 
index 343603f77f8b32d328913e0151218c7696c81126..5f8db54226af7945329bf88b997d7f3ad3d38b75 100644 (file)
@@ -2139,6 +2139,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
index 935c2da00339f1ab8e562d123afc56df22fcb9c7..f2611b9cf503abe8ed9aef9e2a95745010f3adc5 100644 (file)
@@ -1966,6 +1966,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))