Commit 8252ca87 authored by louis.wang's avatar louis.wang Committed by Russell King
Browse files

ARM: 9066/1: ftrace: pause/unpause function graph tracer in cpu_suspend()



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 de818bd4
("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: default avatarlouis.wang <liang26812@gmail.com>
Signed-off-by: default avatarRussell King <rmk+kernel@armlinux.org.uk>
parent a506bd57
Loading
Loading
Loading
Loading
+18 −1
Original line number Diff line number Diff line
// 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