[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20211022152104.487919043@infradead.org>
Date: Fri, 22 Oct 2021 17:09:39 +0200
From: Peter Zijlstra <peterz@...radead.org>
To: keescook@...omium.org, x86@...nel.org
Cc: linux-kernel@...r.kernel.org, peterz@...radead.org,
juri.lelli@...hat.com, vincent.guittot@...aro.org,
dietmar.eggemann@....com, rostedt@...dmis.org, bsegall@...gle.com,
mgorman@...e.de, bristot@...hat.com, akpm@...ux-foundation.org,
mark.rutland@....com, zhengqi.arch@...edance.com,
linux@...linux.org.uk, catalin.marinas@....com, will@...nel.org,
mpe@...erman.id.au, paul.walmsley@...ive.com, palmer@...belt.com,
hca@...ux.ibm.com, gor@...ux.ibm.com, borntraeger@...ibm.com,
linux-arch@...r.kernel.org, ardb@...nel.org
Subject: [PATCH 6/7] arch: __get_wchan() || ARCH_STACKWALK
Use ARCH_STACKWALK to implement a generic __get_wchan().
STACKTRACE should be possible, but the various implementations of
stack_trace_save_tsk() are not consistent enough for this to work.
ARCH_STACKWALK is a smaller set of architectures with a better defined
interface.
Since get_wchan() pins the task in a blocked state, it is not
necessary to take a reference on the task stack, the task isn't going
anywhere.
Signed-off-by: Peter Zijlstra (Intel) <peterz@...radead.org>
---
arch/arm/include/asm/processor.h | 2 -
arch/arm/kernel/process.c | 22 --------------------
arch/arm64/include/asm/processor.h | 2 -
arch/arm64/kernel/process.c | 26 ------------------------
arch/powerpc/include/asm/processor.h | 2 -
arch/powerpc/kernel/process.c | 37 -----------------------------------
arch/riscv/include/asm/processor.h | 3 --
arch/riscv/kernel/stacktrace.c | 21 -------------------
arch/s390/include/asm/processor.h | 1
arch/s390/kernel/process.c | 29 ---------------------------
arch/x86/include/asm/processor.h | 2 -
arch/x86/kernel/process.c | 25 -----------------------
kernel/sched/core.c | 24 ++++++++++++++++++++++
13 files changed, 24 insertions(+), 172 deletions(-)
--- a/arch/arm/include/asm/processor.h
+++ b/arch/arm/include/asm/processor.h
@@ -84,8 +84,6 @@ 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);
-
#define task_pt_regs(p) \
((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1)
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -276,28 +276,6 @@ int copy_thread(unsigned long clone_flag
return 0;
}
-unsigned long __get_wchan(struct task_struct *p)
-{
- struct stackframe frame;
- unsigned long stack_page;
- int count = 0;
-
- frame.fp = thread_saved_fp(p);
- frame.sp = thread_saved_sp(p);
- frame.lr = 0; /* recovered from the stack */
- frame.pc = thread_saved_pc(p);
- stack_page = (unsigned long)task_stack_page(p);
- do {
- if (frame.sp < stack_page ||
- frame.sp >= stack_page + THREAD_SIZE ||
- unwind_frame(&frame) < 0)
- return 0;
- if (!in_sched_functions(frame.pc))
- return frame.pc;
- } while (count ++ < 16);
- return 0;
-}
-
#ifdef CONFIG_MMU
#ifdef CONFIG_KUSER_HELPERS
/*
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -257,8 +257,6 @@ 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);
-
void update_sctlr_el1(u64 sctlr);
/* Thread switching */
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -528,32 +528,6 @@ struct task_struct *__switch_to(struct t
return last;
}
-unsigned long __get_wchan(struct task_struct *p)
-{
- struct stackframe frame;
- unsigned long stack_page, ret = 0;
- int count = 0;
-
- stack_page = (unsigned long)try_get_task_stack(p);
- if (!stack_page)
- return 0;
-
- start_backtrace(&frame, thread_saved_fp(p), thread_saved_pc(p));
-
- do {
- if (unwind_frame(p, &frame))
- goto out;
- if (!in_sched_functions(frame.pc)) {
- ret = frame.pc;
- goto out;
- }
- } while (count++ < 16);
-
-out:
- put_task_stack(p);
- return ret;
-}
-
unsigned long arch_align_stack(unsigned long sp)
{
if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -300,8 +300,6 @@ struct thread_struct {
#define task_pt_regs(tsk) ((tsk)->thread.regs)
-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)
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -2111,43 +2111,6 @@ int validate_sp(unsigned long sp, struct
EXPORT_SYMBOL(validate_sp);
-static unsigned long ___get_wchan(struct task_struct *p)
-{
- unsigned long ip, sp;
- int count = 0;
-
- sp = p->thread.ksp;
- if (!validate_sp(sp, p, STACK_FRAME_OVERHEAD))
- return 0;
-
- do {
- sp = *(unsigned long *)sp;
- if (!validate_sp(sp, p, STACK_FRAME_OVERHEAD) ||
- task_is_running(p))
- return 0;
- if (count > 0) {
- ip = ((unsigned long *)sp)[STACK_FRAME_LR_SAVE];
- if (!in_sched_functions(ip))
- return ip;
- }
- } while (count++ < 16);
- return 0;
-}
-
-unsigned long __get_wchan(struct task_struct *p)
-{
- unsigned long ret;
-
- if (!try_get_task_stack(p))
- return 0;
-
- ret = ___get_wchan(p);
-
- put_task_stack(p);
-
- return ret;
-}
-
static int kstack_depth_to_print = CONFIG_PRINT_STACK_DEPTH;
void __no_sanitize_address show_stack(struct task_struct *tsk,
--- a/arch/riscv/include/asm/processor.h
+++ b/arch/riscv/include/asm/processor.h
@@ -66,9 +66,6 @@ static inline void release_thread(struct
{
}
-extern unsigned long __get_wchan(struct task_struct *p);
-
-
static inline void wait_for_interrupt(void)
{
__asm__ __volatile__ ("wfi");
--- a/arch/riscv/kernel/stacktrace.c
+++ b/arch/riscv/kernel/stacktrace.c
@@ -118,27 +118,6 @@ void show_stack(struct task_struct *task
dump_backtrace(NULL, task, loglvl);
}
-static bool save_wchan(void *arg, unsigned long pc)
-{
- if (!in_sched_functions(pc)) {
- unsigned long *p = arg;
- *p = pc;
- return false;
- }
- return true;
-}
-
-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);
- return pc;
-}
-
noinline void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
struct task_struct *task, struct pt_regs *regs)
{
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -192,7 +192,6 @@ static inline void release_thread(struct
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);
#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)
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -181,35 +181,6 @@ void execve_tail(void)
asm volatile("sfpc %0" : : "d" (0));
}
-unsigned long __get_wchan(struct task_struct *p)
-{
- struct unwind_state state;
- unsigned long ip = 0;
-
- if (!task_stack_page(p))
- return 0;
-
- if (!try_get_task_stack(p))
- return 0;
-
- unwind_for_each_frame(&state, p, NULL, 0) {
- if (state.stack_info.type != STACK_TYPE_TASK) {
- ip = 0;
- break;
- }
-
- ip = unwind_get_return_address(&state);
- if (!ip)
- break;
-
- if (!in_sched_functions(ip))
- break;
- }
-
- put_task_stack(p);
- return ip;
-}
-
unsigned long arch_align_stack(unsigned long sp)
{
if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -588,8 +588,6 @@ static inline void load_sp0(unsigned lon
/* Free all resources held by a thread. */
extern void release_thread(struct task_struct *);
-unsigned long __get_wchan(struct task_struct *p);
-
/*
* Generic CPUID function
* clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -43,7 +43,6 @@
#include <asm/io_bitmap.h>
#include <asm/proto.h>
#include <asm/frame.h>
-#include <asm/unwind.h>
#include "process.h"
@@ -942,30 +941,6 @@ unsigned long arch_randomize_brk(struct
return randomize_page(mm->brk, 0x02000000);
}
-/*
- * Called from fs/proc with a reference on @p to find the function
- * which called into schedule(). This needs to be done carefully
- * because the task might wake up and we might look at a stack
- * changing under us.
- */
-unsigned long __get_wchan(struct task_struct *p)
-{
- struct unwind_state state;
- unsigned long addr = 0;
-
- for (unwind_start(&state, p, NULL, NULL); !unwind_done(&state);
- unwind_next_frame(&state)) {
- addr = unwind_get_return_address(&state);
- if (!addr)
- break;
- if (in_sched_functions(addr))
- continue;
- break;
- }
-
- return addr;
-}
-
long do_arch_prctl_common(struct task_struct *task, int option,
unsigned long cpuid_enabled)
{
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -1966,6 +1966,30 @@ bool sched_task_on_rq(struct task_struct
return task_on_rq_queued(p);
}
+#ifdef CONFIG_ARCH_STACKWALK
+
+static bool consume_wchan(void *cookie, unsigned long addr)
+{
+ unsigned long *wchan = cookie;
+
+ if (in_sched_functions(addr))
+ return true;
+
+ *wchan = addr;
+ return false;
+}
+
+static unsigned long __get_wchan(struct task_struct *p)
+{
+ unsigned long wchan = 0;
+
+ arch_stack_walk(consume_wchan, &wchan, p, NULL);
+
+ return wchan;
+}
+
+#endif /* CONFIG_ARCH_STACKWALK */
+
static int try_get_wchan(struct task_struct *p, void *arg)
{
unsigned long *wchan = arg;
Powered by blists - more mailing lists