From bf6d3e63f9fae49b40596ce91549ec45d1f62522 Mon Sep 17 00:00:00 2001 From: Prakash Gupta Date: Thu, 7 Sep 2017 10:25:35 +1000 Subject: [PATCH 1/2] mm, page_owner: skip unnecessary stack_trace entries The page_owner stacktrace always begin as follows: [] save_stack+0x40/0xc8 [] __set_page_owner+0x3c/0x6c These two entries do not provide any useful information and limits the available stacktrace depth. The page_owner stacktrace was skipping caller function from stack entries but this was missed with commit f2ca0b557107 ("mm/page_owner: use stackdepot to store stacktrace") Example page_owner entry after the patch: Page allocated via order 0, mask 0x8(ffffff80085fb714) PFN 654411 type Movable Block 639 type CMA Flags 0x0(ffffffbe5c7f12c0) [] post_alloc_hook+0x70/0x80 ... [] msm_comm_try_state+0x5f8/0x14f4 [] msm_vidc_open+0x5e4/0x7d0 [] msm_v4l2_open+0xa8/0x224 Change-Id: Ia34fc127d691c2858d991bb631aad9ebc703bcee Link: http://lkml.kernel.org/r/1504078343-28754-2-git-send-email-guptap@codeaurora.org Fixes: f2ca0b557107 ("mm/page_owner: use stackdepot to store stacktrace") Acked-by: Vlastimil Babka Cc: Catalin Marinas Cc: Joonsoo Kim Cc: Michal Hocko Cc: Russell King Cc: Will Deacon Signed-off-by: Andrew Morton Signed-off-by: Stephen Rothwell Git-commit: 665bb76dd71bc061c5f730226dc1881d151983c8 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git Signed-off-by: Prakash Gupta --- mm/page_owner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/page_owner.c b/mm/page_owner.c index 3a9a358e7c63..10b7f196b005 100644 --- a/mm/page_owner.c +++ b/mm/page_owner.c @@ -129,7 +129,7 @@ static noinline depot_stack_handle_t save_stack(gfp_t flags) .nr_entries = 0, .entries = entries, .max_entries = PAGE_OWNER_STACK_DEPTH, - .skip = 0 + .skip = 2 }; depot_stack_handle_t handle; From d6bb6d333cc9bb030d27f459c2e6ce1e4a2d0043 Mon Sep 17 00:00:00 2001 From: Prakash Gupta Date: Thu, 7 Sep 2017 10:25:35 +1000 Subject: [PATCH 2/2] arm64: stacktrace: avoid listing stacktrace functions in stacktrace The stacktraces always begin as follows: [] save_stack_trace_tsk+0x0/0x98 [] save_stack_trace+0x24/0x28 ... This is because the stack trace code includes the stack frames for itself. This is incorrect behaviour, and also leads to "skip" doing the wrong thing (which is the number of stack frames to avoid recording.) Perversely, it does the right thing when passed a non-current thread. Fix this by ensuring that we have a known constant number of frames above the main stack trace function, and always skip these. This was fixed for arch arm by 3683f44c42e9 ("ARM: stacktrace: avoid listing stacktrace functions in stacktrace") Change-Id: I1a65ee011f022227204b406bb0288828a7beb0b8 Link: http://lkml.kernel.org/r/1504078343-28754-1-git-send-email-guptap@codeaurora.org Cc: Russell King Cc: Michal Hocko Cc: Vlastimil Babka Cc: Will Deacon Cc: Catalin Marinas Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Stephen Rothwell Git-commit: 457b9ab50babff7100fe7902d195069561bc1db7 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git [guptap@codeaurora.org: resolve trivial merge conflicts] Signed-off-by: Prakash Gupta --- arch/arm64/kernel/stacktrace.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index 1fd1a9a6596f..770d64547a6a 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -157,24 +157,26 @@ static int save_trace(struct stackframe *frame, void *d) return trace->nr_entries >= trace->max_entries; } -void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) +static noinline void __save_stack_trace(struct task_struct *tsk, + struct stack_trace *trace, unsigned int nosched) { struct stack_trace_data data; struct stackframe frame; data.trace = trace; data.skip = trace->skip; + data.no_sched_functions = nosched; if (tsk != current) { - data.no_sched_functions = 1; frame.fp = thread_saved_fp(tsk); frame.sp = thread_saved_sp(tsk); frame.pc = thread_saved_pc(tsk); } else { - data.no_sched_functions = 0; + /* We don't want this function nor the caller */ + data.skip += 2; frame.fp = (unsigned long)__builtin_frame_address(0); frame.sp = current_stack_pointer; - frame.pc = (unsigned long)save_stack_trace_tsk; + frame.pc = (unsigned long)__save_stack_trace; } #ifdef CONFIG_FUNCTION_GRAPH_TRACER frame.graph = tsk->curr_ret_stack; @@ -186,9 +188,15 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) } EXPORT_SYMBOL(save_stack_trace_tsk); +void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) +{ + __save_stack_trace(tsk, trace, 1); +} + void save_stack_trace(struct stack_trace *trace) { - save_stack_trace_tsk(current, trace); + __save_stack_trace(current, trace, 0); } + EXPORT_SYMBOL_GPL(save_stack_trace); #endif