Commit 935cc932 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'tracing-fixes-for-linus' of...

Merge branch 'tracing-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'tracing-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  tracing/documentation: Cover new frame pointer semantics
  tracing/documentation: Fix a typo in ftrace.txt
  ring-buffer: Check for end of page in iterator
  ring-buffer: Check if ring buffer iterator has stale data
  tracing: Prevent kernel oops with corrupted buffer
parents 4ca5ded2 03688970
function tracer guts function tracer guts
==================== ====================
By Mike Frysinger
Introduction Introduction
------------ ------------
...@@ -173,14 +174,16 @@ void ftrace_graph_caller(void) ...@@ -173,14 +174,16 @@ void ftrace_graph_caller(void)
unsigned long *frompc = &...; unsigned long *frompc = &...;
unsigned long selfpc = <return address> - MCOUNT_INSN_SIZE; unsigned long selfpc = <return address> - MCOUNT_INSN_SIZE;
prepare_ftrace_return(frompc, selfpc); /* passing frame pointer up is optional -- see below */
prepare_ftrace_return(frompc, selfpc, frame_pointer);
/* restore all state needed by the ABI */ /* restore all state needed by the ABI */
} }
#endif #endif
For information on how to implement prepare_ftrace_return(), simply look at For information on how to implement prepare_ftrace_return(), simply look at the
the x86 version. The only architecture-specific piece in it is the setup of x86 version (the frame pointer passing is optional; see the next section for
more information). The only architecture-specific piece in it is the setup of
the fault recovery table (the asm(...) code). The rest should be the same the fault recovery table (the asm(...) code). The rest should be the same
across architectures. across architectures.
...@@ -205,6 +208,23 @@ void return_to_handler(void) ...@@ -205,6 +208,23 @@ void return_to_handler(void)
#endif #endif
HAVE_FUNCTION_GRAPH_FP_TEST
---------------------------
An arch may pass in a unique value (frame pointer) to both the entering and
exiting of a function. On exit, the value is compared and if it does not
match, then it will panic the kernel. This is largely a sanity check for bad
code generation with gcc. If gcc for your port sanely updates the frame
pointer under different opitmization levels, then ignore this option.
However, adding support for it isn't terribly difficult. In your assembly code
that calls prepare_ftrace_return(), pass the frame pointer as the 3rd argument.
Then in the C version of that function, do what the x86 port does and pass it
along to ftrace_push_return_trace() instead of a stub value of 0.
Similarly, when you call ftrace_return_to_handler(), pass it the frame pointer.
HAVE_FTRACE_NMI_ENTER HAVE_FTRACE_NMI_ENTER
--------------------- ---------------------
......
...@@ -1625,7 +1625,7 @@ If I am only interested in sys_nanosleep and hrtimer_interrupt: ...@@ -1625,7 +1625,7 @@ If I am only interested in sys_nanosleep and hrtimer_interrupt:
# echo sys_nanosleep hrtimer_interrupt \ # echo sys_nanosleep hrtimer_interrupt \
> set_ftrace_filter > set_ftrace_filter
# echo ftrace > current_tracer # echo function > current_tracer
# echo 1 > tracing_enabled # echo 1 > tracing_enabled
# usleep 1 # usleep 1
# echo 0 > tracing_enabled # echo 0 > tracing_enabled
......
...@@ -27,9 +27,7 @@ config HAVE_FUNCTION_GRAPH_TRACER ...@@ -27,9 +27,7 @@ config HAVE_FUNCTION_GRAPH_TRACER
config HAVE_FUNCTION_GRAPH_FP_TEST config HAVE_FUNCTION_GRAPH_FP_TEST
bool bool
help help
An arch may pass in a unique value (frame pointer) to both the See Documentation/trace/ftrace-design.txt
entering and exiting of a function. On exit, the value is compared
and if it does not match, then it will panic the kernel.
config HAVE_FUNCTION_TRACE_MCOUNT_TEST config HAVE_FUNCTION_TRACE_MCOUNT_TEST
bool bool
......
...@@ -464,6 +464,8 @@ struct ring_buffer_iter { ...@@ -464,6 +464,8 @@ struct ring_buffer_iter {
struct ring_buffer_per_cpu *cpu_buffer; struct ring_buffer_per_cpu *cpu_buffer;
unsigned long head; unsigned long head;
struct buffer_page *head_page; struct buffer_page *head_page;
struct buffer_page *cache_reader_page;
unsigned long cache_read;
u64 read_stamp; u64 read_stamp;
}; };
...@@ -2716,6 +2718,8 @@ static void rb_iter_reset(struct ring_buffer_iter *iter) ...@@ -2716,6 +2718,8 @@ static void rb_iter_reset(struct ring_buffer_iter *iter)
iter->read_stamp = cpu_buffer->read_stamp; iter->read_stamp = cpu_buffer->read_stamp;
else else
iter->read_stamp = iter->head_page->page->time_stamp; iter->read_stamp = iter->head_page->page->time_stamp;
iter->cache_reader_page = cpu_buffer->reader_page;
iter->cache_read = cpu_buffer->read;
} }
/** /**
...@@ -3060,13 +3064,22 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts) ...@@ -3060,13 +3064,22 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts)
struct ring_buffer_event *event; struct ring_buffer_event *event;
int nr_loops = 0; int nr_loops = 0;
if (ring_buffer_iter_empty(iter))
return NULL;
cpu_buffer = iter->cpu_buffer; cpu_buffer = iter->cpu_buffer;
buffer = cpu_buffer->buffer; buffer = cpu_buffer->buffer;
/*
* Check if someone performed a consuming read to
* the buffer. A consuming read invalidates the iterator
* and we need to reset the iterator in this case.
*/
if (unlikely(iter->cache_read != cpu_buffer->read ||
iter->cache_reader_page != cpu_buffer->reader_page))
rb_iter_reset(iter);
again: again:
if (ring_buffer_iter_empty(iter))
return NULL;
/* /*
* We repeat when a timestamp is encountered. * We repeat when a timestamp is encountered.
* We can get multiple timestamps by nested interrupts or also * We can get multiple timestamps by nested interrupts or also
...@@ -3081,6 +3094,11 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts) ...@@ -3081,6 +3094,11 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts)
if (rb_per_cpu_empty(cpu_buffer)) if (rb_per_cpu_empty(cpu_buffer))
return NULL; return NULL;
if (iter->head >= local_read(&iter->head_page->page->commit)) {
rb_inc_iter(iter);
goto again;
}
event = rb_iter_head_event(iter); event = rb_iter_head_event(iter);
switch (event->type_len) { switch (event->type_len) {
......
...@@ -951,6 +951,11 @@ void trace_find_cmdline(int pid, char comm[]) ...@@ -951,6 +951,11 @@ void trace_find_cmdline(int pid, char comm[])
return; return;
} }
if (WARN_ON_ONCE(pid < 0)) {
strcpy(comm, "<XXX>");
return;
}
if (pid > PID_MAX_DEFAULT) { if (pid > PID_MAX_DEFAULT) {
strcpy(comm, "<...>"); strcpy(comm, "<...>");
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment