diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-02-01 13:43:01 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-02-01 13:43:01 -0500 |
| commit | 935cc9323ac33bb9b6cb853815e5c86f77e50607 (patch) | |
| tree | 6b48024b35b2d166de592ab3238e80c3e763f46a | |
| parent | 4ca5ded2bdc09259ad89915bac2d218e72cda351 (diff) | |
| parent | 03688970347bfea32823953a7ce5886d1713205f (diff) | |
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
| -rw-r--r-- | Documentation/trace/ftrace-design.txt | 26 | ||||
| -rw-r--r-- | Documentation/trace/ftrace.txt | 2 | ||||
| -rw-r--r-- | kernel/trace/Kconfig | 4 | ||||
| -rw-r--r-- | kernel/trace/ring_buffer.c | 24 | ||||
| -rw-r--r-- | kernel/trace/trace.c | 5 |
5 files changed, 51 insertions, 10 deletions
diff --git a/Documentation/trace/ftrace-design.txt b/Documentation/trace/ftrace-design.txt index 239f14b2b55a..6a5a579126b0 100644 --- a/Documentation/trace/ftrace-design.txt +++ b/Documentation/trace/ftrace-design.txt | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | function tracer guts | 1 | function tracer guts |
| 2 | ==================== | 2 | ==================== |
| 3 | By Mike Frysinger | ||
| 3 | 4 | ||
| 4 | Introduction | 5 | Introduction |
| 5 | ------------ | 6 | ------------ |
| @@ -173,14 +174,16 @@ void ftrace_graph_caller(void) | |||
| 173 | 174 | ||
| 174 | unsigned long *frompc = &...; | 175 | unsigned long *frompc = &...; |
| 175 | unsigned long selfpc = <return address> - MCOUNT_INSN_SIZE; | 176 | unsigned long selfpc = <return address> - MCOUNT_INSN_SIZE; |
| 176 | prepare_ftrace_return(frompc, selfpc); | 177 | /* passing frame pointer up is optional -- see below */ |
| 178 | prepare_ftrace_return(frompc, selfpc, frame_pointer); | ||
| 177 | 179 | ||
| 178 | /* restore all state needed by the ABI */ | 180 | /* restore all state needed by the ABI */ |
| 179 | } | 181 | } |
| 180 | #endif | 182 | #endif |
| 181 | 183 | ||
| 182 | For information on how to implement prepare_ftrace_return(), simply look at | 184 | For information on how to implement prepare_ftrace_return(), simply look at the |
| 183 | the x86 version. The only architecture-specific piece in it is the setup of | 185 | x86 version (the frame pointer passing is optional; see the next section for |
| 186 | more information). The only architecture-specific piece in it is the setup of | ||
| 184 | the fault recovery table (the asm(...) code). The rest should be the same | 187 | the fault recovery table (the asm(...) code). The rest should be the same |
| 185 | across architectures. | 188 | across architectures. |
| 186 | 189 | ||
| @@ -205,6 +208,23 @@ void return_to_handler(void) | |||
| 205 | #endif | 208 | #endif |
| 206 | 209 | ||
| 207 | 210 | ||
| 211 | HAVE_FUNCTION_GRAPH_FP_TEST | ||
| 212 | --------------------------- | ||
| 213 | |||
| 214 | An arch may pass in a unique value (frame pointer) to both the entering and | ||
| 215 | exiting of a function. On exit, the value is compared and if it does not | ||
| 216 | match, then it will panic the kernel. This is largely a sanity check for bad | ||
| 217 | code generation with gcc. If gcc for your port sanely updates the frame | ||
| 218 | pointer under different opitmization levels, then ignore this option. | ||
| 219 | |||
| 220 | However, adding support for it isn't terribly difficult. In your assembly code | ||
| 221 | that calls prepare_ftrace_return(), pass the frame pointer as the 3rd argument. | ||
| 222 | Then in the C version of that function, do what the x86 port does and pass it | ||
| 223 | along to ftrace_push_return_trace() instead of a stub value of 0. | ||
| 224 | |||
| 225 | Similarly, when you call ftrace_return_to_handler(), pass it the frame pointer. | ||
| 226 | |||
| 227 | |||
| 208 | HAVE_FTRACE_NMI_ENTER | 228 | HAVE_FTRACE_NMI_ENTER |
| 209 | --------------------- | 229 | --------------------- |
| 210 | 230 | ||
diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt index 8179692fbb90..bab3040da548 100644 --- a/Documentation/trace/ftrace.txt +++ b/Documentation/trace/ftrace.txt | |||
| @@ -1625,7 +1625,7 @@ If I am only interested in sys_nanosleep and hrtimer_interrupt: | |||
| 1625 | 1625 | ||
| 1626 | # echo sys_nanosleep hrtimer_interrupt \ | 1626 | # echo sys_nanosleep hrtimer_interrupt \ |
| 1627 | > set_ftrace_filter | 1627 | > set_ftrace_filter |
| 1628 | # echo ftrace > current_tracer | 1628 | # echo function > current_tracer |
| 1629 | # echo 1 > tracing_enabled | 1629 | # echo 1 > tracing_enabled |
| 1630 | # usleep 1 | 1630 | # usleep 1 |
| 1631 | # echo 0 > tracing_enabled | 1631 | # echo 0 > tracing_enabled |
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index 6c22d8a2f289..60e2ce0181ee 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig | |||
| @@ -27,9 +27,7 @@ config HAVE_FUNCTION_GRAPH_TRACER | |||
| 27 | config HAVE_FUNCTION_GRAPH_FP_TEST | 27 | config HAVE_FUNCTION_GRAPH_FP_TEST |
| 28 | bool | 28 | bool |
| 29 | help | 29 | help |
| 30 | An arch may pass in a unique value (frame pointer) to both the | 30 | See Documentation/trace/ftrace-design.txt |
| 31 | entering and exiting of a function. On exit, the value is compared | ||
| 32 | and if it does not match, then it will panic the kernel. | ||
| 33 | 31 | ||
| 34 | config HAVE_FUNCTION_TRACE_MCOUNT_TEST | 32 | config HAVE_FUNCTION_TRACE_MCOUNT_TEST |
| 35 | bool | 33 | bool |
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index edefe3b2801b..8c1b2d290718 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c | |||
| @@ -464,6 +464,8 @@ struct ring_buffer_iter { | |||
| 464 | struct ring_buffer_per_cpu *cpu_buffer; | 464 | struct ring_buffer_per_cpu *cpu_buffer; |
| 465 | unsigned long head; | 465 | unsigned long head; |
| 466 | struct buffer_page *head_page; | 466 | struct buffer_page *head_page; |
| 467 | struct buffer_page *cache_reader_page; | ||
| 468 | unsigned long cache_read; | ||
| 467 | u64 read_stamp; | 469 | u64 read_stamp; |
| 468 | }; | 470 | }; |
| 469 | 471 | ||
| @@ -2716,6 +2718,8 @@ static void rb_iter_reset(struct ring_buffer_iter *iter) | |||
| 2716 | iter->read_stamp = cpu_buffer->read_stamp; | 2718 | iter->read_stamp = cpu_buffer->read_stamp; |
| 2717 | else | 2719 | else |
| 2718 | iter->read_stamp = iter->head_page->page->time_stamp; | 2720 | iter->read_stamp = iter->head_page->page->time_stamp; |
| 2721 | iter->cache_reader_page = cpu_buffer->reader_page; | ||
| 2722 | iter->cache_read = cpu_buffer->read; | ||
| 2719 | } | 2723 | } |
| 2720 | 2724 | ||
| 2721 | /** | 2725 | /** |
| @@ -3060,13 +3064,22 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts) | |||
| 3060 | struct ring_buffer_event *event; | 3064 | struct ring_buffer_event *event; |
| 3061 | int nr_loops = 0; | 3065 | int nr_loops = 0; |
| 3062 | 3066 | ||
| 3063 | if (ring_buffer_iter_empty(iter)) | ||
| 3064 | return NULL; | ||
| 3065 | |||
| 3066 | cpu_buffer = iter->cpu_buffer; | 3067 | cpu_buffer = iter->cpu_buffer; |
| 3067 | buffer = cpu_buffer->buffer; | 3068 | buffer = cpu_buffer->buffer; |
| 3068 | 3069 | ||
| 3070 | /* | ||
| 3071 | * Check if someone performed a consuming read to | ||
| 3072 | * the buffer. A consuming read invalidates the iterator | ||
| 3073 | * and we need to reset the iterator in this case. | ||
| 3074 | */ | ||
| 3075 | if (unlikely(iter->cache_read != cpu_buffer->read || | ||
| 3076 | iter->cache_reader_page != cpu_buffer->reader_page)) | ||
| 3077 | rb_iter_reset(iter); | ||
| 3078 | |||
| 3069 | again: | 3079 | again: |
| 3080 | if (ring_buffer_iter_empty(iter)) | ||
| 3081 | return NULL; | ||
| 3082 | |||
| 3070 | /* | 3083 | /* |
| 3071 | * We repeat when a timestamp is encountered. | 3084 | * We repeat when a timestamp is encountered. |
| 3072 | * We can get multiple timestamps by nested interrupts or also | 3085 | * 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 | if (rb_per_cpu_empty(cpu_buffer)) | 3094 | if (rb_per_cpu_empty(cpu_buffer)) |
| 3082 | return NULL; | 3095 | return NULL; |
| 3083 | 3096 | ||
| 3097 | if (iter->head >= local_read(&iter->head_page->page->commit)) { | ||
| 3098 | rb_inc_iter(iter); | ||
| 3099 | goto again; | ||
| 3100 | } | ||
| 3101 | |||
| 3084 | event = rb_iter_head_event(iter); | 3102 | event = rb_iter_head_event(iter); |
| 3085 | 3103 | ||
| 3086 | switch (event->type_len) { | 3104 | switch (event->type_len) { |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 0df1b0f2cb9e..eac6875cb990 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
| @@ -951,6 +951,11 @@ void trace_find_cmdline(int pid, char comm[]) | |||
| 951 | return; | 951 | return; |
| 952 | } | 952 | } |
| 953 | 953 | ||
| 954 | if (WARN_ON_ONCE(pid < 0)) { | ||
| 955 | strcpy(comm, "<XXX>"); | ||
| 956 | return; | ||
| 957 | } | ||
| 958 | |||
| 954 | if (pid > PID_MAX_DEFAULT) { | 959 | if (pid > PID_MAX_DEFAULT) { |
| 955 | strcpy(comm, "<...>"); | 960 | strcpy(comm, "<...>"); |
| 956 | return; | 961 | return; |
