Commit 09c0796a authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull tracing updates from Steven Rostedt:
 "The major update to this release is that there's a new arch config
  option called CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS.

  Currently, only x86_64 enables it. All the ftrace callbacks now take a
  struct ftrace_regs instead of a struct pt_regs. If the architecture
  has HAVE_DYNAMIC_FTRACE_WITH_ARGS enabled, then the ftrace_regs will
  have enough information to read the arguments of the function being
  traced, as well as access to the stack pointer.

  This way, if a user (like live kernel patching) only cares about the
  arguments, then it can avoid using the heavier weight "regs" callback,
  that puts in enough information in the struct ftrace_regs to simulate
  a breakpoint exception (needed for kprobes).

  A new config option that audits the timestamps of the ftrace ring
  buffer at most every event recorded.

  Ftrace recursion protection has been cleaned up to move the protection
  to the callback itself (this saves on an extra function call for those
  callbacks).

  Perf now handles its own RCU protection and does not depend on ftrace
  to do it for it (saving on that extra function call).

  New debug option to add "recursed_functions" file to tracefs that
  lists all the places that triggered the recursion protection of the
  function tracer. This will show where things need to be fixed as
  recursion slows down the function tracer.

  The eval enum mapping updates done at boot up are now offloaded to a
  work queue, as it caused a noticeable pause on slow embedded boards.

  Various clean ups and last minute fixes"

* tag 'trace-v5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace: (33 commits)
  tracing: Offload eval map updates to a work queue
  Revert: "ring-buffer: Remove HAVE_64BIT_ALIGNED_ACCESS"
  ring-buffer: Add rb_check_bpage in __rb_allocate_pages
  ring-buffer: Fix two typos in comments
  tracing: Drop unneeded assignment in ring_buffer_resize()
  tracing: Disable ftrace selftests when any tracer is running
  seq_buf: Avoid type mismatch for seq_buf_init
  ring-buffer: Fix a typo in function description
  ring-buffer: Remove obsolete rb_event_is_commit()
  ring-buffer: Add test to validate the time stamp deltas
  ftrace/documentation: Fix RST C code blocks
  tracing: Clean up after filter logic rewriting
  tracing: Remove the useless value assignment in test_create_synth_event()
  livepatch: Use the default ftrace_ops instead of REGS when ARGS is available
  ftrace/x86: Allow for arguments to be passed in to ftrace_regs by default
  ftrace: Have the callbacks receive a struct ftrace_regs instead of pt_regs
  MAINTAINERS: assign ./fs/tracefs to TRACING
  tracing: Fix some typos in comments
  ftrace: Remove unused varible 'ret'
  ring-buffer: Add recording of ring buffer recursion into recursed_functions
  ...
parents 312dcaf9 f6a69466
Loading
Loading
Loading
Loading
+68 −22
Original line number Diff line number Diff line
@@ -30,8 +30,8 @@ The ftrace context
  This requires extra care to what can be done inside a callback. A callback
  can be called outside the protective scope of RCU.

The ftrace infrastructure has some protections against recursions and RCU
but one must still be very careful how they use the callbacks.
There are helper functions to help against recursion, and making sure
RCU is watching. These are explained below.


The ftrace_ops structure
@@ -108,6 +108,58 @@ The prototype of the callback function is as follows (as of v4.14):
	at the start of the function where ftrace was tracing. Otherwise it
	either contains garbage, or NULL.

Protect your callback
=====================

As functions can be called from anywhere, and it is possible that a function
called by a callback may also be traced, and call that same callback,
recursion protection must be used. There are two helper functions that
can help in this regard. If you start your code with:

.. code-block:: c

	int bit;

	bit = ftrace_test_recursion_trylock(ip, parent_ip);
	if (bit < 0)
		return;

and end it with:

.. code-block:: c

	ftrace_test_recursion_unlock(bit);

The code in between will be safe to use, even if it ends up calling a
function that the callback is tracing. Note, on success,
ftrace_test_recursion_trylock() will disable preemption, and the
ftrace_test_recursion_unlock() will enable it again (if it was previously
enabled). The instruction pointer (ip) and its parent (parent_ip) is passed to
ftrace_test_recursion_trylock() to record where the recursion happened
(if CONFIG_FTRACE_RECORD_RECURSION is set).

Alternatively, if the FTRACE_OPS_FL_RECURSION flag is set on the ftrace_ops
(as explained below), then a helper trampoline will be used to test
for recursion for the callback and no recursion test needs to be done.
But this is at the expense of a slightly more overhead from an extra
function call.

If your callback accesses any data or critical section that requires RCU
protection, it is best to make sure that RCU is "watching", otherwise
that data or critical section will not be protected as expected. In this
case add:

.. code-block:: c

	if (!rcu_is_watching())
		return;

Alternatively, if the FTRACE_OPS_FL_RCU flag is set on the ftrace_ops
(as explained below), then a helper trampoline will be used to test
for rcu_is_watching for the callback and no other test needs to be done.
But this is at the expense of a slightly more overhead from an extra
function call.


The ftrace FLAGS
================
@@ -128,26 +180,20 @@ FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED
	will not fail with this flag set. But the callback must check if
	regs is NULL or not to determine if the architecture supports it.

FTRACE_OPS_FL_RECURSION_SAFE
	By default, a wrapper is added around the callback to
	make sure that recursion of the function does not occur. That is,
	if a function that is called as a result of the callback's execution
	is also traced, ftrace will prevent the callback from being called
	again. But this wrapper adds some overhead, and if the callback is
	safe from recursion, it can set this flag to disable the ftrace
	protection.

	Note, if this flag is set, and recursion does occur, it could cause
	the system to crash, and possibly reboot via a triple fault.

	It is OK if another callback traces a function that is called by a
	callback that is marked recursion safe. Recursion safe callbacks
	must never trace any function that are called by the callback
	itself or any nested functions that those functions call.

	If this flag is set, it is possible that the callback will also
	be called with preemption enabled (when CONFIG_PREEMPTION is set),
	but this is not guaranteed.
FTRACE_OPS_FL_RECURSION
	By default, it is expected that the callback can handle recursion.
	But if the callback is not that worried about overehead, then
	setting this bit will add the recursion protection around the
	callback by calling a helper function that will do the recursion
	protection and only call the callback if it did not recurse.

	Note, if this flag is not set, and recursion does occur, it could
	cause the system to crash, and possibly reboot via a triple fault.

	Not, if this flag is set, then the callback will always be called
	with preemption disabled. If it is not set, then it is possible
	(but not guaranteed) that the callback will be called in
	preemptable context.

FTRACE_OPS_FL_IPMODIFY
	Requires FTRACE_OPS_FL_SAVE_REGS set. If the callback is to "hijack"
+1 −0
Original line number Diff line number Diff line
@@ -17983,6 +17983,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git perf/core
F:	Documentation/trace/ftrace.rst
F:	arch/*/*/*/ftrace.h
F:	arch/*/kernel/ftrace.c
F:	fs/tracefs/
F:	include/*/ftrace.h
F:	include/linux/trace*.h
F:	include/trace/
+16 −0
Original line number Diff line number Diff line
@@ -143,6 +143,22 @@ config UPROBES
	    managed by the kernel and kept transparent to the probed
	    application. )

config HAVE_64BIT_ALIGNED_ACCESS
	def_bool 64BIT && !HAVE_EFFICIENT_UNALIGNED_ACCESS
	help
	  Some architectures require 64 bit accesses to be 64 bit
	  aligned, which also requires structs containing 64 bit values
	  to be 64 bit aligned too. This includes some 32 bit
	  architectures which can do 64 bit accesses, as well as 64 bit
	  architectures without unaligned access.

	  This symbol should be selected by an architecture if 64 bit
	  accesses are required to be 64 bit aligned in this way even
	  though it is not a 64 bit architecture.

	  See Documentation/unaligned-memory-access.txt for more
	  information on the topic of unaligned memory accesses.

config HAVE_EFFICIENT_UNALIGNED_ACCESS
	bool
	help
+13 −3
Original line number Diff line number Diff line
@@ -11,18 +11,25 @@ int arch_check_ftrace_location(struct kprobe *p)

/* Ftrace callback handler for kprobes -- called under preepmt disabed */
void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
			   struct ftrace_ops *ops, struct pt_regs *regs)
			   struct ftrace_ops *ops, struct ftrace_regs *fregs)
{
	int bit;
	bool lr_saver = false;
	struct kprobe *p;
	struct kprobe_ctlblk *kcb;
	struct pt_regs *regs;

	/* Preempt is disabled by ftrace */
	bit = ftrace_test_recursion_trylock(ip, parent_ip);
	if (bit < 0)
		return;

	regs = ftrace_get_regs(fregs);
	preempt_disable_notrace();
	p = get_kprobe((kprobe_opcode_t *)ip);
	if (!p) {
		p = get_kprobe((kprobe_opcode_t *)(ip - MCOUNT_INSN_SIZE));
		if (unlikely(!p) || kprobe_disabled(p))
			return;
			goto out;
		lr_saver = true;
	}

@@ -56,6 +63,9 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
		 */
		__this_cpu_write(current_kprobe, NULL);
	}
out:
	preempt_enable_notrace();
	ftrace_test_recursion_unlock(bit);
}
NOKPROBE_SYMBOL(kprobe_ftrace_handler);

+2 −2
Original line number Diff line number Diff line
@@ -10,7 +10,7 @@ extern void (*ftrace_trace_function)(unsigned long, unsigned long,
extern void ftrace_graph_caller(void);

noinline void __naked ftrace_stub(unsigned long ip, unsigned long parent_ip,
				  struct ftrace_ops *op, struct pt_regs *regs)
				  struct ftrace_ops *op, struct ftrace_regs *fregs)
{
	__asm__ ("");  /* avoid to optimize as pure function */
}
@@ -38,7 +38,7 @@ EXPORT_SYMBOL(_mcount);
#else /* CONFIG_DYNAMIC_FTRACE */

noinline void __naked ftrace_stub(unsigned long ip, unsigned long parent_ip,
				  struct ftrace_ops *op, struct pt_regs *regs)
				  struct ftrace_ops *op, struct ftrace_regs *fregs)
{
	__asm__ ("");  /* avoid to optimize as pure function */
}
Loading