Skip to content

Commit

Permalink
tracing/perf: disable preemption in syscall probe
Browse files Browse the repository at this point in the history
In preparation for allowing system call enter/exit instrumentation to
handle page faults, make sure that perf can handle this change by
explicitly disabling preemption within the perf system call tracepoint
probes to respect the current expectations within perf ring buffer code.

This change does not yet allow perf to take page faults per se within
its probe, but allows its existing probes to adapt to the upcoming
change.

Cc: Michael Jeanson <[email protected]>
Cc: Masami Hiramatsu <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Alexei Starovoitov <[email protected]>
Cc: Yonghong Song <[email protected]>
Cc: Paul E. McKenney <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Mark Rutland <[email protected]>
Cc: Alexander Shishkin <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Andrii Nakryiko <[email protected]>
Cc: [email protected]
Cc: Joel Fernandes <[email protected]>
Link: https://lore.kernel.org/[email protected]
Signed-off-by: Mathieu Desnoyers <[email protected]>
Signed-off-by: Steven Rostedt (Google) <[email protected]>
  • Loading branch information
compudj authored and rostedt committed Oct 9, 2024
1 parent 13d750c commit 65e7462
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 4 deletions.
42 changes: 38 additions & 4 deletions include/trace/perf.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
#undef __perf_task
#define __perf_task(t) (__task = (t))

#undef DECLARE_EVENT_CLASS
#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
#undef __DECLARE_EVENT_CLASS
#define __DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
static notrace void \
perf_trace_##call(void *__data, proto) \
do_perf_trace_##call(void *__data, proto) \
{ \
struct trace_event_call *event_call = __data; \
struct trace_event_data_offsets_##call __maybe_unused __data_offsets;\
Expand Down Expand Up @@ -55,8 +55,39 @@ perf_trace_##call(void *__data, proto) \
head, __task); \
}

/*
* Define unused __count and __task variables to use @args to pass
* arguments to do_perf_trace_##call. This is needed because the
* macros __perf_count and __perf_task introduce the side-effect to
* store copies into those local variables.
*/
#undef DECLARE_EVENT_CLASS
#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
__DECLARE_EVENT_CLASS(call, PARAMS(proto), PARAMS(args), PARAMS(tstruct), \
PARAMS(assign), PARAMS(print)) \
static notrace void \
perf_trace_##call(void *__data, proto) \
{ \
u64 __count __attribute__((unused)); \
struct task_struct *__task __attribute__((unused)); \
\
do_perf_trace_##call(__data, args); \
}

#undef DECLARE_EVENT_SYSCALL_CLASS
#define DECLARE_EVENT_SYSCALL_CLASS DECLARE_EVENT_CLASS
#define DECLARE_EVENT_SYSCALL_CLASS(call, proto, args, tstruct, assign, print) \
__DECLARE_EVENT_CLASS(call, PARAMS(proto), PARAMS(args), PARAMS(tstruct), \
PARAMS(assign), PARAMS(print)) \
static notrace void \
perf_trace_##call(void *__data, proto) \
{ \
u64 __count __attribute__((unused)); \
struct task_struct *__task __attribute__((unused)); \
\
preempt_disable_notrace(); \
do_perf_trace_##call(__data, args); \
preempt_enable_notrace(); \
}

/*
* This part is compiled out, it is only here as a build time check
Expand All @@ -76,4 +107,7 @@ static inline void perf_test_probe_##call(void) \
DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args))

#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)

#undef __DECLARE_EVENT_CLASS

#endif /* CONFIG_PERF_EVENTS */
12 changes: 12 additions & 0 deletions kernel/trace/trace_syscalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,12 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id)
int rctx;
int size;

/*
* Syscall probe called with preemption enabled, but the ring
* buffer and per-cpu data require preemption to be disabled.
*/
guard(preempt_notrace)();

syscall_nr = trace_get_syscall_nr(current, regs);
if (syscall_nr < 0 || syscall_nr >= NR_syscalls)
return;
Expand Down Expand Up @@ -698,6 +704,12 @@ static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
int rctx;
int size;

/*
* Syscall probe called with preemption enabled, but the ring
* buffer and per-cpu data require preemption to be disabled.
*/
guard(preempt_notrace)();

syscall_nr = trace_get_syscall_nr(current, regs);
if (syscall_nr < 0 || syscall_nr >= NR_syscalls)
return;
Expand Down

0 comments on commit 65e7462

Please sign in to comment.