| From bb3646c17c38264c734027ac50c4a37b7c1b1c83 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Wed, 24 Feb 2021 13:25:53 +0100 |
| Subject: ARM: 9066/1: ftrace: pause/unpause function graph tracer in |
| cpu_suspend() |
| |
| From: louis.wang <liang26812@gmail.com> |
| |
| [ Upstream commit 8252ca87c7a2111502ee13994956f8c309faad7f ] |
| |
| Enabling function_graph tracer on ARM causes kernel panic, because the |
| function graph tracer updates the "return address" of a function in order |
| to insert a trace callback on function exit, it saves the function's |
| original return address in a return trace stack, but cpu_suspend() may not |
| return through the normal return path. |
| |
| cpu_suspend() will resume directly via the cpu_resume path, but the return |
| trace stack has been set-up by the subfunctions of cpu_suspend(), which |
| makes the "return address" inconsistent with cpu_suspend(). |
| |
| This patch refers to Commit de818bd4522c40ea02a81b387d2fa86f989c9623 |
| ("arm64: kernel: pause/unpause function graph tracer in cpu_suspend()"), |
| |
| fixes the issue by pausing/resuming the function graph tracer on the thread |
| executing cpu_suspend(), so that the function graph tracer state is kept |
| consistent across functions that enter power down states and never return |
| by effectively disabling graph tracer while they are executing. |
| |
| Signed-off-by: louis.wang <liang26812@gmail.com> |
| Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| arch/arm/kernel/suspend.c | 19 ++++++++++++++++++- |
| 1 file changed, 18 insertions(+), 1 deletion(-) |
| |
| diff --git a/arch/arm/kernel/suspend.c b/arch/arm/kernel/suspend.c |
| index 24bd20564be7..43f0a3ebf390 100644 |
| --- a/arch/arm/kernel/suspend.c |
| +++ b/arch/arm/kernel/suspend.c |
| @@ -1,4 +1,5 @@ |
| // SPDX-License-Identifier: GPL-2.0 |
| +#include <linux/ftrace.h> |
| #include <linux/init.h> |
| #include <linux/slab.h> |
| #include <linux/mm_types.h> |
| @@ -25,6 +26,13 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) |
| if (!idmap_pgd) |
| return -EINVAL; |
| |
| + /* |
| + * Function graph tracer state gets incosistent when the kernel |
| + * calls functions that never return (aka suspend finishers) hence |
| + * disable graph tracing during their execution. |
| + */ |
| + pause_graph_tracing(); |
| + |
| /* |
| * Provide a temporary page table with an identity mapping for |
| * the MMU-enable code, required for resuming. On successful |
| @@ -32,6 +40,9 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) |
| * back to the correct page tables. |
| */ |
| ret = __cpu_suspend(arg, fn, __mpidr); |
| + |
| + unpause_graph_tracing(); |
| + |
| if (ret == 0) { |
| cpu_switch_mm(mm->pgd, mm); |
| local_flush_bp_all(); |
| @@ -45,7 +56,13 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) |
| int cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) |
| { |
| u32 __mpidr = cpu_logical_map(smp_processor_id()); |
| - return __cpu_suspend(arg, fn, __mpidr); |
| + int ret; |
| + |
| + pause_graph_tracing(); |
| + ret = __cpu_suspend(arg, fn, __mpidr); |
| + unpause_graph_tracing(); |
| + |
| + return ret; |
| } |
| #define idmap_pgd NULL |
| #endif |
| -- |
| 2.30.2 |
| |