Commit 42a20f86 authored by Kees Cook's avatar Kees Cook Committed by Peter Zijlstra

sched: Add wrapper for get_wchan() to keep task blocked

Having a stable wchan means the process must be blocked and for it to
stay that way while performing stack unwinding.
Suggested-by: default avatarPeter Zijlstra <peterz@infradead.org>
Signed-off-by: default avatarKees Cook <keescook@chromium.org>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: default avatarGeert 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
parent bc9bbb81
...@@ -42,7 +42,7 @@ extern void start_thread(struct pt_regs *, unsigned long, unsigned long); ...@@ -42,7 +42,7 @@ extern void start_thread(struct pt_regs *, unsigned long, unsigned long);
struct task_struct; struct task_struct;
extern void release_thread(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) #define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc)
......
...@@ -376,12 +376,11 @@ thread_saved_pc(struct task_struct *t) ...@@ -376,12 +376,11 @@ thread_saved_pc(struct task_struct *t)
} }
unsigned long unsigned long
get_wchan(struct task_struct *p) __get_wchan(struct task_struct *p)
{ {
unsigned long schedule_frame; unsigned long schedule_frame;
unsigned long pc; unsigned long pc;
if (!p || p == current || task_is_running(p))
return 0;
/* /*
* This one depends on the frame size of schedule(). Do a * This one depends on the frame size of schedule(). Do a
* "disass schedule" in gdb to find the frame size. Also, the * "disass schedule" in gdb to find the frame size. Also, the
......
...@@ -70,7 +70,7 @@ struct task_struct; ...@@ -70,7 +70,7 @@ struct task_struct;
extern void start_thread(struct pt_regs * regs, unsigned long pc, extern void start_thread(struct pt_regs * regs, unsigned long pc,
unsigned long usp); unsigned long usp);
extern unsigned int get_wchan(struct task_struct *p); extern unsigned int __get_wchan(struct task_struct *p);
#endif /* !__ASSEMBLY__ */ #endif /* !__ASSEMBLY__ */
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* = specifics of data structs where trace is saved(CONFIG_STACKTRACE etc) * = specifics of data structs where trace is saved(CONFIG_STACKTRACE etc)
* *
* vineetg: March 2009 * 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 * rajeshwarr: 2008
* -Initial implementation * -Initial implementation
...@@ -248,7 +248,7 @@ void show_stack(struct task_struct *tsk, unsigned long *sp, const char *loglvl) ...@@ -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 * Of course just returning schedule( ) would be pointless so unwind until
* the function is not in schedular code * 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); return arc_unwind_core(tsk, NULL, __get_first_nonsched, NULL);
} }
......
...@@ -84,7 +84,7 @@ struct task_struct; ...@@ -84,7 +84,7 @@ struct task_struct;
/* Free all resources held by a thread. */ /* Free all resources held by a thread. */
extern void release_thread(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 task_pt_regs(p) \ #define task_pt_regs(p) \
((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1) ((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1)
......
...@@ -276,13 +276,11 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start, ...@@ -276,13 +276,11 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
return 0; return 0;
} }
unsigned long get_wchan(struct task_struct *p) unsigned long __get_wchan(struct task_struct *p)
{ {
struct stackframe frame; struct stackframe frame;
unsigned long stack_page; unsigned long stack_page;
int count = 0; int count = 0;
if (!p || p == current || task_is_running(p))
return 0;
frame.fp = thread_saved_fp(p); frame.fp = thread_saved_fp(p);
frame.sp = thread_saved_sp(p); frame.sp = thread_saved_sp(p);
......
...@@ -257,7 +257,7 @@ struct task_struct; ...@@ -257,7 +257,7 @@ struct task_struct;
/* Free all resources held by a thread. */ /* Free all resources held by a thread. */
extern void release_thread(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);
void update_sctlr_el1(u64 sctlr); void update_sctlr_el1(u64 sctlr);
......
...@@ -528,13 +528,11 @@ __notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev, ...@@ -528,13 +528,11 @@ __notrace_funcgraph struct task_struct *__switch_to(struct task_struct *prev,
return last; return last;
} }
unsigned long get_wchan(struct task_struct *p) unsigned long __get_wchan(struct task_struct *p)
{ {
struct stackframe frame; struct stackframe frame;
unsigned long stack_page, ret = 0; unsigned long stack_page, ret = 0;
int count = 0; int count = 0;
if (!p || p == current || task_is_running(p))
return 0;
stack_page = (unsigned long)try_get_task_stack(p); stack_page = (unsigned long)try_get_task_stack(p);
if (!stack_page) if (!stack_page)
......
...@@ -81,7 +81,7 @@ static inline void release_thread(struct task_struct *dead_task) ...@@ -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); 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_EIP(tsk) (task_pt_regs(tsk)->pc)
#define KSTK_ESP(tsk) (task_pt_regs(tsk)->usp) #define KSTK_ESP(tsk) (task_pt_regs(tsk)->usp)
......
...@@ -111,12 +111,11 @@ static bool save_wchan(unsigned long pc, void *arg) ...@@ -111,12 +111,11 @@ static bool save_wchan(unsigned long pc, void *arg)
return false; return false;
} }
unsigned long get_wchan(struct task_struct *task) unsigned long __get_wchan(struct task_struct *task)
{ {
unsigned long pc = 0; 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; return pc;
} }
......
...@@ -105,7 +105,7 @@ static inline void release_thread(struct task_struct *dead_task) ...@@ -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) \ #define KSTK_EIP(tsk) \
({ \ ({ \
......
...@@ -128,15 +128,12 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, ...@@ -128,15 +128,12 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
return 0; return 0;
} }
unsigned long get_wchan(struct task_struct *p) unsigned long __get_wchan(struct task_struct *p)
{ {
unsigned long fp, pc; unsigned long fp, pc;
unsigned long stack_page; unsigned long stack_page;
int count = 0; int count = 0;
if (!p || p == current || task_is_running(p))
return 0;
stack_page = (unsigned long)p; stack_page = (unsigned long)p;
fp = ((struct pt_regs *)p->thread.ksp)->er6; fp = ((struct pt_regs *)p->thread.ksp)->er6;
do { do {
......
...@@ -64,7 +64,7 @@ struct thread_struct { ...@@ -64,7 +64,7 @@ struct thread_struct {
extern void release_thread(struct task_struct *dead_task); extern void release_thread(struct task_struct *dead_task);
/* Get wait channel for task P. */ /* 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. */ /* The following stuff is pretty HEXAGON specific. */
......
...@@ -130,13 +130,11 @@ void flush_thread(void) ...@@ -130,13 +130,11 @@ void flush_thread(void)
* is an identification of the point at which the scheduler * is an identification of the point at which the scheduler
* was invoked by a blocked thread. * 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 fp, pc;
unsigned long stack_page; unsigned long stack_page;
int count = 0; int count = 0;
if (!p || p == current || task_is_running(p))
return 0;
stack_page = (unsigned long)task_stack_page(p); stack_page = (unsigned long)task_stack_page(p);
fp = ((struct hexagon_switch_stack *)p->thread.switch_sp)->fp; fp = ((struct hexagon_switch_stack *)p->thread.switch_sp)->fp;
......
...@@ -330,7 +330,7 @@ struct task_struct; ...@@ -330,7 +330,7 @@ struct task_struct;
#define release_thread(dead_task) #define release_thread(dead_task)
/* Get wait channel for task P. */ /* 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. */ /* Return instruction pointer of blocked task TSK. */
#define KSTK_EIP(tsk) \ #define KSTK_EIP(tsk) \
......
...@@ -523,15 +523,12 @@ exit_thread (struct task_struct *tsk) ...@@ -523,15 +523,12 @@ exit_thread (struct task_struct *tsk)
} }
unsigned long unsigned long
get_wchan (struct task_struct *p) __get_wchan (struct task_struct *p)
{ {
struct unw_frame_info info; struct unw_frame_info info;
unsigned long ip; unsigned long ip;
int count = 0; 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 * Note: p may not be a blocked task (it could be current or
* another process running on some other CPU. Rather than * another process running on some other CPU. Rather than
......
...@@ -150,7 +150,7 @@ static inline void release_thread(struct task_struct *dead_task) ...@@ -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) \ #define KSTK_EIP(tsk) \
({ \ ({ \
......
...@@ -263,13 +263,11 @@ int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu) ...@@ -263,13 +263,11 @@ int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
} }
EXPORT_SYMBOL(dump_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 fp, pc;
unsigned long stack_page; unsigned long stack_page;
int count = 0; int count = 0;
if (!p || p == current || task_is_running(p))
return 0;
stack_page = (unsigned long)task_stack_page(p); stack_page = (unsigned long)task_stack_page(p);
fp = ((struct switch_stack *)p->thread.ksp)->a6; fp = ((struct switch_stack *)p->thread.ksp)->a6;
......
...@@ -68,7 +68,7 @@ static inline void release_thread(struct task_struct *dead_task) ...@@ -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! */ /* The size allocated for kernel stacks. This _must_ be a power of two! */
# define KERNEL_STACK_SIZE 0x2000 # define KERNEL_STACK_SIZE 0x2000
......
...@@ -112,7 +112,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg, ...@@ -112,7 +112,7 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg,
return 0; return 0;
} }
unsigned long get_wchan(struct task_struct *p) unsigned long __get_wchan(struct task_struct *p)
{ {
/* TBD (used by procfs) */ /* TBD (used by procfs) */
return 0; return 0;
......
...@@ -369,7 +369,7 @@ static inline void flush_thread(void) ...@@ -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) + \ #define __KSTK_TOS(tsk) ((unsigned long)task_stack_page(tsk) + \
THREAD_SIZE - 32 - sizeof(struct pt_regs)) THREAD_SIZE - 32 - sizeof(struct pt_regs))
......
...@@ -511,7 +511,7 @@ static int __init frame_info_init(void) ...@@ -511,7 +511,7 @@ static int __init frame_info_init(void)
/* /*
* Without schedule() frame info, result given by * 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) if (schedule_mfi.pc_offset < 0)
printk("Can't analyze schedule() prologue at %p\n", schedule); 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, ...@@ -652,9 +652,9 @@ unsigned long unwind_stack(struct task_struct *task, unsigned long *sp,
#endif #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; unsigned long pc = 0;
#ifdef CONFIG_KALLSYMS #ifdef CONFIG_KALLSYMS
...@@ -662,8 +662,6 @@ unsigned long get_wchan(struct task_struct *task) ...@@ -662,8 +662,6 @@ unsigned long get_wchan(struct task_struct *task)
unsigned long ra = 0; unsigned long ra = 0;
#endif #endif
if (!task || task == current || task_is_running(task))
goto out;
if (!task_stack_page(task)) if (!task_stack_page(task))
goto out; goto out;
......
...@@ -83,7 +83,7 @@ extern struct task_struct *last_task_used_math; ...@@ -83,7 +83,7 @@ extern struct task_struct *last_task_used_math;
/* Prepare to copy thread state - unlazy all lazy status */ /* Prepare to copy thread state - unlazy all lazy status */
#define prepare_to_copy(tsk) do { } while (0) #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() #define cpu_relax() barrier()
......
...@@ -233,15 +233,12 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpu) ...@@ -233,15 +233,12 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpu)
EXPORT_SYMBOL(dump_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 fp, lr;
unsigned long stack_start, stack_end; unsigned long stack_start, stack_end;
int count = 0; int count = 0;
if (!p || p == current || task_is_running(p))
return 0;
if (IS_ENABLED(CONFIG_FRAME_POINTER)) { if (IS_ENABLED(CONFIG_FRAME_POINTER)) {
stack_start = (unsigned long)end_of_stack(p); stack_start = (unsigned long)end_of_stack(p);
stack_end = (unsigned long)task_stack_page(p) + THREAD_SIZE; stack_end = (unsigned long)task_stack_page(p) + THREAD_SIZE;
...@@ -258,5 +255,3 @@ unsigned long get_wchan(struct task_struct *p) ...@@ -258,5 +255,3 @@ unsigned long get_wchan(struct task_struct *p)
} }
return 0; return 0;
} }
EXPORT_SYMBOL(get_wchan);
...@@ -69,7 +69,7 @@ static inline void release_thread(struct task_struct *dead_task) ...@@ -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) \ #define task_pt_regs(p) \
((struct pt_regs *)(THREAD_SIZE + task_stack_page(p)) - 1) ((struct pt_regs *)(THREAD_SIZE + task_stack_page(p)) - 1)
......
...@@ -217,15 +217,12 @@ void dump(struct pt_regs *fp) ...@@ -217,15 +217,12 @@ void dump(struct pt_regs *fp)
pr_emerg("\n\n"); 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 fp, pc;
unsigned long stack_page; unsigned long stack_page;
int count = 0; int count = 0;
if (!p || p == current || task_is_running(p))
return 0;
stack_page = (unsigned long)p; stack_page = (unsigned long)p;
fp = ((struct switch_stack *)p->thread.ksp)->fp; /* ;dgt2 */ fp = ((struct switch_stack *)p->thread.ksp)->fp; /* ;dgt2 */
do { do {
......
...@@ -73,7 +73,7 @@ struct thread_struct { ...@@ -73,7 +73,7 @@ struct thread_struct {
void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp); void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp);
void release_thread(struct task_struct *); 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() #define cpu_relax() barrier()
......
...@@ -263,7 +263,7 @@ void dump_elf_thread(elf_greg_t *dest, struct pt_regs* regs) ...@@ -263,7 +263,7 @@ void dump_elf_thread(elf_greg_t *dest, struct pt_regs* regs)
dest[35] = 0; dest[35] = 0;
} }
unsigned long get_wchan(struct task_struct *p) unsigned long __get_wchan(struct task_struct *p)
{ {
/* TODO */ /* TODO */
......
...@@ -273,7 +273,7 @@ struct mm_struct; ...@@ -273,7 +273,7 @@ struct mm_struct;
/* Free all resources held by a thread. */ /* Free all resources held by a thread. */
extern void release_thread(struct task_struct *); 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_EIP(tsk) ((tsk)->thread.regs.iaoq[0])
#define KSTK_ESP(tsk) ((tsk)->thread.regs.gr[30]) #define KSTK_ESP(tsk) ((tsk)->thread.regs.gr[30])
......
...@@ -240,15 +240,12 @@ copy_thread(unsigned long clone_flags, unsigned long usp, ...@@ -240,15 +240,12 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
} }
unsigned long unsigned long
get_wchan(struct task_struct *p) __get_wchan(struct task_struct *p)
{ {
struct unwind_frame_info info; struct unwind_frame_info info;
unsigned long ip; unsigned long ip;
int count = 0; int count = 0;
if (!p || p == current || task_is_running(p))
return 0;
/* /*
* These bracket the sleeping functions.. * These bracket the sleeping functions..
*/ */
......
...@@ -300,7 +300,7 @@ struct thread_struct { ...@@ -300,7 +300,7 @@ struct thread_struct {
#define task_pt_regs(tsk) ((tsk)->thread.regs) #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_EIP(tsk) ((tsk)->thread.regs? (tsk)->thread.regs->nip: 0)
#define KSTK_ESP(tsk) ((tsk)->thread.regs? (tsk)->thread.regs->gpr[1]: 0) #define KSTK_ESP(tsk) ((tsk)->thread.regs? (tsk)->thread.regs->gpr[1]: 0)
......
...@@ -2111,14 +2111,11 @@ int validate_sp(unsigned long sp, struct task_struct *p, ...@@ -2111,14 +2111,11 @@ int validate_sp(unsigned long sp, struct task_struct *p,
EXPORT_SYMBOL(validate_sp); 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; unsigned long ip, sp;
int count = 0; int count = 0;
if (!p || p == current || task_is_running(p))
return 0;
sp = p->thread.ksp; sp = p->thread.ksp;
if (!validate_sp(sp, p, STACK_FRAME_OVERHEAD)) if (!validate_sp(sp, p, STACK_FRAME_OVERHEAD))
return 0; return 0;
...@@ -2137,14 +2134,14 @@ static unsigned long __get_wchan(struct task_struct *p) ...@@ -2137,14 +2134,14 @@ static unsigned long __get_wchan(struct task_struct *p)
return 0; return 0;
} }
unsigned long get_wchan(struct task_struct *p) unsigned long __get_wchan(struct task_struct *p)
{ {
unsigned long ret; unsigned long ret;
if (!try_get_task_stack(p)) if (!try_get_task_stack(p))
return 0; return 0;
ret = __get_wchan(p); ret = ___get_wchan(p);
put_task_stack(p); put_task_stack(p);
......
...@@ -66,7 +66,7 @@ static inline void release_thread(struct task_struct *dead_task) ...@@ -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) static inline void wait_for_interrupt(void)
......
...@@ -128,16 +128,14 @@ static bool save_wchan(void *arg, unsigned long pc) ...@@ -128,16 +128,14 @@ static bool save_wchan(void *arg, unsigned long pc)
return true; return true;
} }
unsigned long get_wchan(struct task_struct *task) unsigned long __get_wchan(struct task_struct *task)
{ {
unsigned long pc = 0; unsigned long pc = 0;
if (likely(task && task != current && !task_is_running(task))) { if (!try_get_task_stack(task))
if (!try_get_task_stack(task)) return 0;
return 0; walk_stackframe(task, NULL, save_wchan, &pc);
walk_stackframe(task, NULL, save_wchan, &pc); put_task_stack(task);
put_task_stack(task);
}
return pc; return pc;
} }
......
...@@ -192,7 +192,7 @@ static inline void release_thread(struct task_struct *tsk) { } ...@@ -192,7 +192,7 @@ static inline void release_thread(struct task_struct *tsk) { }
void guarded_storage_release(struct task_struct *tsk); void guarded_storage_release(struct task_struct *tsk);
void gs_load_bc_cb(struct pt_regs *regs); 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 *) \ #define task_pt_regs(tsk) ((struct pt_regs *) \
(task_stack_page(tsk) + THREAD_SIZE) - 1) (task_stack_page(tsk) + THREAD_SIZE) - 1)
#define KSTK_EIP(tsk) (task_pt_regs(tsk)->psw.addr) #define KSTK_EIP(tsk) (task_pt_regs(tsk)->psw.addr)
......
...@@ -181,12 +181,12 @@ void execve_tail(void) ...@@ -181,12 +181,12 @@ void execve_tail(void)
asm volatile("sfpc %0" : : "d" (0)); 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; struct unwind_state state;
unsigned long ip = 0; unsigned long ip = 0;
if (!p || p == current || task_is_running(p) || !task_stack_page(p)) if (!task_stack_page(p))
return 0; return 0;
if (!try_get_task_stack(p)) if (!try_get_task_stack(p))
......
...@@ -180,7 +180,7 @@ static inline void show_code(struct pt_regs *regs) ...@@ -180,7 +180,7 @@ static inline void show_code(struct pt_regs *regs)
} }
#endif #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_EIP(tsk) (task_pt_regs(tsk)->pc)
#define KSTK_ESP(tsk) (task_pt_regs(tsk)->regs[15]) #define KSTK_ESP(tsk) (task_pt_regs(tsk)->regs[15])
......
...@@ -182,13 +182,10 @@ __switch_to(struct task_struct *prev, struct task_struct *next) ...@@ -182,13 +182,10 @@ __switch_to(struct task_struct *prev, struct task_struct *next)
return prev; return prev;
} }
unsigned long get_wchan(struct task_struct *p) unsigned long __get_wchan(struct task_struct *p)
{ {
unsigned long pc; unsigned long pc;
if (!p || p == current || task_is_running(p))
return 0;
/* /*
* The same comment as on the Alpha applies here, too ... * The same comment as on the Alpha applies here, too ...
*/ */
......
...@@ -89,7 +89,7 @@ static inline void start_thread(struct pt_regs * regs, unsigned long pc, ...@@ -89,7 +89,7 @@ static inline void start_thread(struct pt_regs * regs, unsigned long pc,
/* Free all resources held by a thread. */ /* Free all resources held by a thread. */
#define release_thread(tsk) do { } while(0) #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 task_pt_regs(tsk) ((tsk)->thread.kregs)
#define KSTK_EIP(tsk) ((tsk)->thread.kregs->pc) #define KSTK_EIP(tsk) ((tsk)->thread.kregs->pc)
......
...@@ -183,7 +183,7 @@ do { \ ...@@ -183,7 +183,7 @@ do { \
/* Free all resources held by a thread. */ /* Free all resources held by a thread. */
#define release_thread(tsk) do { } while (0) #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 task_pt_regs(tsk) (task_thread_info(tsk)->kregs)
#define KSTK_EIP(tsk) (task_pt_regs(tsk)->tpc) #define KSTK_EIP(tsk) (task_pt_regs(tsk)->tpc)
......
...@@ -365,7 +365,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg, ...@@ -365,7 +365,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg,
return 0; 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 pc, fp, bias = 0;
unsigned long task_base = (unsigned long) task; unsigned long task_base = (unsigned long) task;
...@@ -373,9 +373,6 @@ unsigned long get_wchan(struct task_struct *task) ...@@ -373,9 +373,6 @@ unsigned long get_wchan(struct task_struct *task)
struct reg_window32 *rw; struct reg_window32 *rw;
int count = 0; int count = 0;
if (!task || task == current || task_is_running(task))
goto out;
fp = task_thread_info(task)->ksp + bias; fp = task_thread_info(task)->ksp + bias;
do { do {
/* Bogus frame pointer? */ /* Bogus frame pointer? */
......
...@@ -663,7 +663,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) ...@@ -663,7 +663,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
return 0; 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 pc, fp, bias = 0;
struct thread_info *tp; struct thread_info *tp;
...@@ -671,9 +671,6 @@ unsigned long get_wchan(struct task_struct *task) ...@@ -671,9 +671,6 @@ unsigned long get_wchan(struct task_struct *task)
unsigned long ret = 0; unsigned long ret = 0;
int count = 0; int count = 0;
if (!task || task == current || task_is_running(task))
goto out;
tp = task_thread_info(task); tp = task_thread_info(task);
bias = STACK_BIAS; bias = STACK_BIAS;
fp = task_thread_info(task)->ksp + bias; fp = task_thread_info(task)->ksp + bias;
......
...@@ -106,6 +106,6 @@ extern struct cpuinfo_um boot_cpu_data; ...@@ -106,6 +106,6 @@ extern struct cpuinfo_um boot_cpu_data;
#define cache_line_size() (boot_cpu_data.cache_alignment) #define cache_line_size() (boot_cpu_data.cache_alignment)
#define KSTK_REG(tsk, reg) get_thread_reg(reg, &tsk->thread.switch_buf) #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 #endif
...@@ -364,14 +364,11 @@ unsigned long arch_align_stack(unsigned long sp) ...@@ -364,14 +364,11 @@ unsigned long arch_align_stack(unsigned long sp)
} }
#endif #endif
unsigned long get_wchan(struct task_struct *p) unsigned long __get_wchan(struct task_struct *p)
{ {
unsigned long stack_page, sp, ip; unsigned long stack_page, sp, ip;
bool seen_sched = 0; bool seen_sched = 0;
if ((p == NULL) || (p == current) || task_is_running(p))
return 0;
stack_page = (unsigned long) task_stack_page(p); stack_page = (unsigned long) task_stack_page(p);
/* Bail if the process has no kernel stack for some reason */ /* Bail if the process has no kernel stack for some reason */
if (stack_page == 0) if (stack_page == 0)
......
...@@ -589,7 +589,7 @@ static inline void load_sp0(unsigned long sp0) ...@@ -589,7 +589,7 @@ static inline void load_sp0(unsigned long sp0)
/* Free all resources held by a thread. */ /* Free all resources held by a thread. */
extern void release_thread(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);
/* /*
* Generic CPUID function * Generic CPUID function
......
...@@ -942,13 +942,10 @@ unsigned long arch_randomize_brk(struct mm_struct *mm) ...@@ -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 * because the task might wake up and we might look at a stack
* changing under us. * changing under us.
*/ */
unsigned long get_wchan(struct task_struct *p) unsigned long __get_wchan(struct task_struct *p)
{ {
unsigned long entry = 0; unsigned long entry = 0;
if (p == current || task_is_running(p))
return 0;
stack_trace_save_tsk(p, &entry, 1, 0); stack_trace_save_tsk(p, &entry, 1, 0);
return entry; return entry;
} }
......
...@@ -215,7 +215,7 @@ struct mm_struct; ...@@ -215,7 +215,7 @@ struct mm_struct;
/* Free all resources held by a thread. */ /* Free all resources held by a thread. */
#define release_thread(thread) do { } while(0) #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_EIP(tsk) (task_pt_regs(tsk)->pc)
#define KSTK_ESP(tsk) (task_pt_regs(tsk)->areg[1]) #define KSTK_ESP(tsk) (task_pt_regs(tsk)->areg[1])
......
...@@ -298,15 +298,12 @@ int copy_thread(unsigned long clone_flags, unsigned long usp_thread_fn, ...@@ -298,15 +298,12 @@ int copy_thread(unsigned long clone_flags, unsigned long usp_thread_fn,
* These bracket the sleeping functions.. * 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 sp, pc;
unsigned long stack_page = (unsigned long) task_stack_page(p); unsigned long stack_page = (unsigned long) task_stack_page(p);
int count = 0; int count = 0;
if (!p || p == current || task_is_running(p))
return 0;
sp = p->thread.sp; sp = p->thread.sp;
pc = MAKE_PC_FROM_RA(p->thread.ra, p->thread.sp); pc = MAKE_PC_FROM_RA(p->thread.ra, p->thread.sp);
......
...@@ -2139,6 +2139,7 @@ static inline void set_task_cpu(struct task_struct *p, unsigned int cpu) ...@@ -2139,6 +2139,7 @@ static inline void set_task_cpu(struct task_struct *p, unsigned int cpu)
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
extern bool sched_task_on_rq(struct task_struct *p); 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 * In order to reduce various lock holder preemption latencies provide an
......
...@@ -1966,6 +1966,25 @@ bool sched_task_on_rq(struct task_struct *p) ...@@ -1966,6 +1966,25 @@ bool sched_task_on_rq(struct task_struct *p)
return task_on_rq_queued(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) static inline void enqueue_task(struct rq *rq, struct task_struct *p, int flags)
{ {
if (!(flags & ENQUEUE_NOCLOCK)) if (!(flags & ENQUEUE_NOCLOCK))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment