Skip to content

Commit

Permalink
sched: Add wrapper for get_wchan() to keep task blocked
Browse files Browse the repository at this point in the history
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
  • Loading branch information
kees authored and Peter Zijlstra committed Oct 15, 2021
1 parent bc9bbb8 commit 42a20f8
Show file tree
Hide file tree
Showing 50 changed files with 80 additions and 112 deletions.
2 changes: 1 addition & 1 deletion arch/alpha/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
5 changes: 2 additions & 3 deletions arch/alpha/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion arch/arc/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__ */

Expand Down
4 changes: 2 additions & 2 deletions arch/arc/kernel/stacktrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion arch/arm/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 1 addition & 3 deletions arch/arm/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
4 changes: 1 addition & 3 deletions arch/arm64/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion arch/csky/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 2 additions & 3 deletions arch/csky/kernel/stacktrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
2 changes: 1 addition & 1 deletion arch/h8300/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
({ \
Expand Down
5 changes: 1 addition & 4 deletions arch/h8300/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion arch/hexagon/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. */

Expand Down
4 changes: 1 addition & 3 deletions arch/hexagon/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion arch/ia64/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down
5 changes: 1 addition & 4 deletions arch/ia64/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion arch/m68k/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
({ \
Expand Down
4 changes: 1 addition & 3 deletions arch/m68k/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion arch/microblaze/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion arch/microblaze/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion arch/mips/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
8 changes: 3 additions & 5 deletions arch/mips/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -652,18 +652,16 @@ 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
unsigned long sp;
unsigned long ra = 0;
#endif

if (!task || task == current || task_is_running(task))
goto out;
if (!task_stack_page(task))
goto out;

Expand Down
2 changes: 1 addition & 1 deletion arch/nds32/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
7 changes: 1 addition & 6 deletions arch/nds32/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -258,5 +255,3 @@ unsigned long get_wchan(struct task_struct *p)
}
return 0;
}

EXPORT_SYMBOL(get_wchan);
2 changes: 1 addition & 1 deletion arch/nios2/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 1 addition & 4 deletions arch/nios2/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion arch/openrisc/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
2 changes: 1 addition & 1 deletion arch/openrisc/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down
2 changes: 1 addition & 1 deletion arch/parisc/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down
5 changes: 1 addition & 4 deletions arch/parisc/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -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..
*/
Expand Down
2 changes: 1 addition & 1 deletion arch/powerpc/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading

0 comments on commit 42a20f8

Please sign in to comment.