diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-11 23:47:44 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-11 23:47:44 -0500 |
commit | df7147b3c37cb203f968119f3b6a1cd648c535a1 (patch) | |
tree | f5e0026cc8b1f711beef03338b087ff66cae92c4 | |
parent | 6f696eb17be741668810fe1f798135c7cf6733e2 (diff) | |
parent | 788d70dce0184eccc249ac6f05aa38b385b7497c (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: Remove comparing of NULL to va_list in trace_array_vprintk()
tracing: Fix function graph trace_pipe to properly display failed entries
tracing: Add full state to trace_seq
tracing: Buffer the output of seq_file in case of filled buffer
tracing: Only call pipe_close if pipe_close is defined
tracing: Add pipe_close interface
-rw-r--r-- | include/linux/ftrace_event.h | 1 | ||||
-rw-r--r-- | include/linux/trace_seq.h | 7 | ||||
-rw-r--r-- | kernel/trace/trace.c | 57 | ||||
-rw-r--r-- | kernel/trace/trace.h | 2 | ||||
-rw-r--r-- | kernel/trace/trace_functions_graph.c | 165 | ||||
-rw-r--r-- | kernel/trace/trace_output.c | 75 |
6 files changed, 248 insertions, 59 deletions
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 47bbdf9c38d0..38f8d6553831 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h | |||
@@ -57,6 +57,7 @@ struct trace_iterator { | |||
57 | /* The below is zeroed out in pipe_read */ | 57 | /* The below is zeroed out in pipe_read */ |
58 | struct trace_seq seq; | 58 | struct trace_seq seq; |
59 | struct trace_entry *ent; | 59 | struct trace_entry *ent; |
60 | int leftover; | ||
60 | int cpu; | 61 | int cpu; |
61 | u64 ts; | 62 | u64 ts; |
62 | 63 | ||
diff --git a/include/linux/trace_seq.h b/include/linux/trace_seq.h index 09077f6ed128..5cf397ceb726 100644 --- a/include/linux/trace_seq.h +++ b/include/linux/trace_seq.h | |||
@@ -14,6 +14,7 @@ struct trace_seq { | |||
14 | unsigned char buffer[PAGE_SIZE]; | 14 | unsigned char buffer[PAGE_SIZE]; |
15 | unsigned int len; | 15 | unsigned int len; |
16 | unsigned int readpos; | 16 | unsigned int readpos; |
17 | int full; | ||
17 | }; | 18 | }; |
18 | 19 | ||
19 | static inline void | 20 | static inline void |
@@ -21,6 +22,7 @@ trace_seq_init(struct trace_seq *s) | |||
21 | { | 22 | { |
22 | s->len = 0; | 23 | s->len = 0; |
23 | s->readpos = 0; | 24 | s->readpos = 0; |
25 | s->full = 0; | ||
24 | } | 26 | } |
25 | 27 | ||
26 | /* | 28 | /* |
@@ -33,7 +35,7 @@ extern int trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args) | |||
33 | __attribute__ ((format (printf, 2, 0))); | 35 | __attribute__ ((format (printf, 2, 0))); |
34 | extern int | 36 | extern int |
35 | trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary); | 37 | trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary); |
36 | extern void trace_print_seq(struct seq_file *m, struct trace_seq *s); | 38 | extern int trace_print_seq(struct seq_file *m, struct trace_seq *s); |
37 | extern ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf, | 39 | extern ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf, |
38 | size_t cnt); | 40 | size_t cnt); |
39 | extern int trace_seq_puts(struct trace_seq *s, const char *str); | 41 | extern int trace_seq_puts(struct trace_seq *s, const char *str); |
@@ -55,8 +57,9 @@ trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary) | |||
55 | return 0; | 57 | return 0; |
56 | } | 58 | } |
57 | 59 | ||
58 | static inline void trace_print_seq(struct seq_file *m, struct trace_seq *s) | 60 | static inline int trace_print_seq(struct seq_file *m, struct trace_seq *s) |
59 | { | 61 | { |
62 | return 0; | ||
60 | } | 63 | } |
61 | static inline ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf, | 64 | static inline ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf, |
62 | size_t cnt) | 65 | size_t cnt) |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 874f2893cff0..88bd9ae2a9ed 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -1361,11 +1361,7 @@ int trace_array_vprintk(struct trace_array *tr, | |||
1361 | pause_graph_tracing(); | 1361 | pause_graph_tracing(); |
1362 | raw_local_irq_save(irq_flags); | 1362 | raw_local_irq_save(irq_flags); |
1363 | __raw_spin_lock(&trace_buf_lock); | 1363 | __raw_spin_lock(&trace_buf_lock); |
1364 | if (args == NULL) { | 1364 | len = vsnprintf(trace_buf, TRACE_BUF_SIZE, fmt, args); |
1365 | strncpy(trace_buf, fmt, TRACE_BUF_SIZE); | ||
1366 | len = strlen(trace_buf); | ||
1367 | } else | ||
1368 | len = vsnprintf(trace_buf, TRACE_BUF_SIZE, fmt, args); | ||
1369 | 1365 | ||
1370 | size = sizeof(*entry) + len + 1; | 1366 | size = sizeof(*entry) + len + 1; |
1371 | buffer = tr->buffer; | 1367 | buffer = tr->buffer; |
@@ -1516,6 +1512,8 @@ static void *s_next(struct seq_file *m, void *v, loff_t *pos) | |||
1516 | int i = (int)*pos; | 1512 | int i = (int)*pos; |
1517 | void *ent; | 1513 | void *ent; |
1518 | 1514 | ||
1515 | WARN_ON_ONCE(iter->leftover); | ||
1516 | |||
1519 | (*pos)++; | 1517 | (*pos)++; |
1520 | 1518 | ||
1521 | /* can't go backwards */ | 1519 | /* can't go backwards */ |
@@ -1614,8 +1612,16 @@ static void *s_start(struct seq_file *m, loff_t *pos) | |||
1614 | ; | 1612 | ; |
1615 | 1613 | ||
1616 | } else { | 1614 | } else { |
1617 | l = *pos - 1; | 1615 | /* |
1618 | p = s_next(m, p, &l); | 1616 | * If we overflowed the seq_file before, then we want |
1617 | * to just reuse the trace_seq buffer again. | ||
1618 | */ | ||
1619 | if (iter->leftover) | ||
1620 | p = iter; | ||
1621 | else { | ||
1622 | l = *pos - 1; | ||
1623 | p = s_next(m, p, &l); | ||
1624 | } | ||
1619 | } | 1625 | } |
1620 | 1626 | ||
1621 | trace_event_read_lock(); | 1627 | trace_event_read_lock(); |
@@ -1923,6 +1929,7 @@ static enum print_line_t print_trace_line(struct trace_iterator *iter) | |||
1923 | static int s_show(struct seq_file *m, void *v) | 1929 | static int s_show(struct seq_file *m, void *v) |
1924 | { | 1930 | { |
1925 | struct trace_iterator *iter = v; | 1931 | struct trace_iterator *iter = v; |
1932 | int ret; | ||
1926 | 1933 | ||
1927 | if (iter->ent == NULL) { | 1934 | if (iter->ent == NULL) { |
1928 | if (iter->tr) { | 1935 | if (iter->tr) { |
@@ -1942,9 +1949,27 @@ static int s_show(struct seq_file *m, void *v) | |||
1942 | if (!(trace_flags & TRACE_ITER_VERBOSE)) | 1949 | if (!(trace_flags & TRACE_ITER_VERBOSE)) |
1943 | print_func_help_header(m); | 1950 | print_func_help_header(m); |
1944 | } | 1951 | } |
1952 | } else if (iter->leftover) { | ||
1953 | /* | ||
1954 | * If we filled the seq_file buffer earlier, we | ||
1955 | * want to just show it now. | ||
1956 | */ | ||
1957 | ret = trace_print_seq(m, &iter->seq); | ||
1958 | |||
1959 | /* ret should this time be zero, but you never know */ | ||
1960 | iter->leftover = ret; | ||
1961 | |||
1945 | } else { | 1962 | } else { |
1946 | print_trace_line(iter); | 1963 | print_trace_line(iter); |
1947 | trace_print_seq(m, &iter->seq); | 1964 | ret = trace_print_seq(m, &iter->seq); |
1965 | /* | ||
1966 | * If we overflow the seq_file buffer, then it will | ||
1967 | * ask us for this data again at start up. | ||
1968 | * Use that instead. | ||
1969 | * ret is 0 if seq_file write succeeded. | ||
1970 | * -1 otherwise. | ||
1971 | */ | ||
1972 | iter->leftover = ret; | ||
1948 | } | 1973 | } |
1949 | 1974 | ||
1950 | return 0; | 1975 | return 0; |
@@ -2898,6 +2923,10 @@ static int tracing_release_pipe(struct inode *inode, struct file *file) | |||
2898 | else | 2923 | else |
2899 | cpumask_clear_cpu(iter->cpu_file, tracing_reader_cpumask); | 2924 | cpumask_clear_cpu(iter->cpu_file, tracing_reader_cpumask); |
2900 | 2925 | ||
2926 | |||
2927 | if (iter->trace->pipe_close) | ||
2928 | iter->trace->pipe_close(iter); | ||
2929 | |||
2901 | mutex_unlock(&trace_types_lock); | 2930 | mutex_unlock(&trace_types_lock); |
2902 | 2931 | ||
2903 | free_cpumask_var(iter->started); | 2932 | free_cpumask_var(iter->started); |
@@ -3320,6 +3349,16 @@ tracing_entries_write(struct file *filp, const char __user *ubuf, | |||
3320 | return cnt; | 3349 | return cnt; |
3321 | } | 3350 | } |
3322 | 3351 | ||
3352 | static int mark_printk(const char *fmt, ...) | ||
3353 | { | ||
3354 | int ret; | ||
3355 | va_list args; | ||
3356 | va_start(args, fmt); | ||
3357 | ret = trace_vprintk(0, fmt, args); | ||
3358 | va_end(args); | ||
3359 | return ret; | ||
3360 | } | ||
3361 | |||
3323 | static ssize_t | 3362 | static ssize_t |
3324 | tracing_mark_write(struct file *filp, const char __user *ubuf, | 3363 | tracing_mark_write(struct file *filp, const char __user *ubuf, |
3325 | size_t cnt, loff_t *fpos) | 3364 | size_t cnt, loff_t *fpos) |
@@ -3346,7 +3385,7 @@ tracing_mark_write(struct file *filp, const char __user *ubuf, | |||
3346 | } else | 3385 | } else |
3347 | buf[cnt] = '\0'; | 3386 | buf[cnt] = '\0'; |
3348 | 3387 | ||
3349 | cnt = trace_vprintk(0, buf, NULL); | 3388 | cnt = mark_printk("%s", buf); |
3350 | kfree(buf); | 3389 | kfree(buf); |
3351 | *fpos += cnt; | 3390 | *fpos += cnt; |
3352 | 3391 | ||
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 1d7f4830a80d..7fa33cab6962 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -272,6 +272,7 @@ struct tracer_flags { | |||
272 | * @pipe_open: called when the trace_pipe file is opened | 272 | * @pipe_open: called when the trace_pipe file is opened |
273 | * @wait_pipe: override how the user waits for traces on trace_pipe | 273 | * @wait_pipe: override how the user waits for traces on trace_pipe |
274 | * @close: called when the trace file is released | 274 | * @close: called when the trace file is released |
275 | * @pipe_close: called when the trace_pipe file is released | ||
275 | * @read: override the default read callback on trace_pipe | 276 | * @read: override the default read callback on trace_pipe |
276 | * @splice_read: override the default splice_read callback on trace_pipe | 277 | * @splice_read: override the default splice_read callback on trace_pipe |
277 | * @selftest: selftest to run on boot (see trace_selftest.c) | 278 | * @selftest: selftest to run on boot (see trace_selftest.c) |
@@ -290,6 +291,7 @@ struct tracer { | |||
290 | void (*pipe_open)(struct trace_iterator *iter); | 291 | void (*pipe_open)(struct trace_iterator *iter); |
291 | void (*wait_pipe)(struct trace_iterator *iter); | 292 | void (*wait_pipe)(struct trace_iterator *iter); |
292 | void (*close)(struct trace_iterator *iter); | 293 | void (*close)(struct trace_iterator *iter); |
294 | void (*pipe_close)(struct trace_iterator *iter); | ||
293 | ssize_t (*read)(struct trace_iterator *iter, | 295 | ssize_t (*read)(struct trace_iterator *iter, |
294 | struct file *filp, char __user *ubuf, | 296 | struct file *filp, char __user *ubuf, |
295 | size_t cnt, loff_t *ppos); | 297 | size_t cnt, loff_t *ppos); |
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 45e6c01b2e4d..a43d009c561a 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c | |||
@@ -14,9 +14,20 @@ | |||
14 | #include "trace.h" | 14 | #include "trace.h" |
15 | #include "trace_output.h" | 15 | #include "trace_output.h" |
16 | 16 | ||
17 | struct fgraph_data { | 17 | struct fgraph_cpu_data { |
18 | pid_t last_pid; | 18 | pid_t last_pid; |
19 | int depth; | 19 | int depth; |
20 | int ignore; | ||
21 | }; | ||
22 | |||
23 | struct fgraph_data { | ||
24 | struct fgraph_cpu_data *cpu_data; | ||
25 | |||
26 | /* Place to preserve last processed entry. */ | ||
27 | struct ftrace_graph_ent_entry ent; | ||
28 | struct ftrace_graph_ret_entry ret; | ||
29 | int failed; | ||
30 | int cpu; | ||
20 | }; | 31 | }; |
21 | 32 | ||
22 | #define TRACE_GRAPH_INDENT 2 | 33 | #define TRACE_GRAPH_INDENT 2 |
@@ -384,7 +395,7 @@ verif_pid(struct trace_seq *s, pid_t pid, int cpu, struct fgraph_data *data) | |||
384 | if (!data) | 395 | if (!data) |
385 | return TRACE_TYPE_HANDLED; | 396 | return TRACE_TYPE_HANDLED; |
386 | 397 | ||
387 | last_pid = &(per_cpu_ptr(data, cpu)->last_pid); | 398 | last_pid = &(per_cpu_ptr(data->cpu_data, cpu)->last_pid); |
388 | 399 | ||
389 | if (*last_pid == pid) | 400 | if (*last_pid == pid) |
390 | return TRACE_TYPE_HANDLED; | 401 | return TRACE_TYPE_HANDLED; |
@@ -435,26 +446,49 @@ static struct ftrace_graph_ret_entry * | |||
435 | get_return_for_leaf(struct trace_iterator *iter, | 446 | get_return_for_leaf(struct trace_iterator *iter, |
436 | struct ftrace_graph_ent_entry *curr) | 447 | struct ftrace_graph_ent_entry *curr) |
437 | { | 448 | { |
438 | struct ring_buffer_iter *ring_iter; | 449 | struct fgraph_data *data = iter->private; |
450 | struct ring_buffer_iter *ring_iter = NULL; | ||
439 | struct ring_buffer_event *event; | 451 | struct ring_buffer_event *event; |
440 | struct ftrace_graph_ret_entry *next; | 452 | struct ftrace_graph_ret_entry *next; |
441 | 453 | ||
442 | ring_iter = iter->buffer_iter[iter->cpu]; | 454 | /* |
455 | * If the previous output failed to write to the seq buffer, | ||
456 | * then we just reuse the data from before. | ||
457 | */ | ||
458 | if (data && data->failed) { | ||
459 | curr = &data->ent; | ||
460 | next = &data->ret; | ||
461 | } else { | ||
443 | 462 | ||
444 | /* First peek to compare current entry and the next one */ | 463 | ring_iter = iter->buffer_iter[iter->cpu]; |
445 | if (ring_iter) | 464 | |
446 | event = ring_buffer_iter_peek(ring_iter, NULL); | 465 | /* First peek to compare current entry and the next one */ |
447 | else { | 466 | if (ring_iter) |
448 | /* We need to consume the current entry to see the next one */ | 467 | event = ring_buffer_iter_peek(ring_iter, NULL); |
449 | ring_buffer_consume(iter->tr->buffer, iter->cpu, NULL); | 468 | else { |
450 | event = ring_buffer_peek(iter->tr->buffer, iter->cpu, | 469 | /* |
451 | NULL); | 470 | * We need to consume the current entry to see |
452 | } | 471 | * the next one. |
472 | */ | ||
473 | ring_buffer_consume(iter->tr->buffer, iter->cpu, NULL); | ||
474 | event = ring_buffer_peek(iter->tr->buffer, iter->cpu, | ||
475 | NULL); | ||
476 | } | ||
453 | 477 | ||
454 | if (!event) | 478 | if (!event) |
455 | return NULL; | 479 | return NULL; |
480 | |||
481 | next = ring_buffer_event_data(event); | ||
456 | 482 | ||
457 | next = ring_buffer_event_data(event); | 483 | if (data) { |
484 | /* | ||
485 | * Save current and next entries for later reference | ||
486 | * if the output fails. | ||
487 | */ | ||
488 | data->ent = *curr; | ||
489 | data->ret = *next; | ||
490 | } | ||
491 | } | ||
458 | 492 | ||
459 | if (next->ent.type != TRACE_GRAPH_RET) | 493 | if (next->ent.type != TRACE_GRAPH_RET) |
460 | return NULL; | 494 | return NULL; |
@@ -640,7 +674,7 @@ print_graph_entry_leaf(struct trace_iterator *iter, | |||
640 | 674 | ||
641 | if (data) { | 675 | if (data) { |
642 | int cpu = iter->cpu; | 676 | int cpu = iter->cpu; |
643 | int *depth = &(per_cpu_ptr(data, cpu)->depth); | 677 | int *depth = &(per_cpu_ptr(data->cpu_data, cpu)->depth); |
644 | 678 | ||
645 | /* | 679 | /* |
646 | * Comments display at + 1 to depth. Since | 680 | * Comments display at + 1 to depth. Since |
@@ -688,7 +722,7 @@ print_graph_entry_nested(struct trace_iterator *iter, | |||
688 | 722 | ||
689 | if (data) { | 723 | if (data) { |
690 | int cpu = iter->cpu; | 724 | int cpu = iter->cpu; |
691 | int *depth = &(per_cpu_ptr(data, cpu)->depth); | 725 | int *depth = &(per_cpu_ptr(data->cpu_data, cpu)->depth); |
692 | 726 | ||
693 | *depth = call->depth; | 727 | *depth = call->depth; |
694 | } | 728 | } |
@@ -782,19 +816,34 @@ static enum print_line_t | |||
782 | print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s, | 816 | print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s, |
783 | struct trace_iterator *iter) | 817 | struct trace_iterator *iter) |
784 | { | 818 | { |
785 | int cpu = iter->cpu; | 819 | struct fgraph_data *data = iter->private; |
786 | struct ftrace_graph_ent *call = &field->graph_ent; | 820 | struct ftrace_graph_ent *call = &field->graph_ent; |
787 | struct ftrace_graph_ret_entry *leaf_ret; | 821 | struct ftrace_graph_ret_entry *leaf_ret; |
822 | static enum print_line_t ret; | ||
823 | int cpu = iter->cpu; | ||
788 | 824 | ||
789 | if (print_graph_prologue(iter, s, TRACE_GRAPH_ENT, call->func)) | 825 | if (print_graph_prologue(iter, s, TRACE_GRAPH_ENT, call->func)) |
790 | return TRACE_TYPE_PARTIAL_LINE; | 826 | return TRACE_TYPE_PARTIAL_LINE; |
791 | 827 | ||
792 | leaf_ret = get_return_for_leaf(iter, field); | 828 | leaf_ret = get_return_for_leaf(iter, field); |
793 | if (leaf_ret) | 829 | if (leaf_ret) |
794 | return print_graph_entry_leaf(iter, field, leaf_ret, s); | 830 | ret = print_graph_entry_leaf(iter, field, leaf_ret, s); |
795 | else | 831 | else |
796 | return print_graph_entry_nested(iter, field, s, cpu); | 832 | ret = print_graph_entry_nested(iter, field, s, cpu); |
797 | 833 | ||
834 | if (data) { | ||
835 | /* | ||
836 | * If we failed to write our output, then we need to make | ||
837 | * note of it. Because we already consumed our entry. | ||
838 | */ | ||
839 | if (s->full) { | ||
840 | data->failed = 1; | ||
841 | data->cpu = cpu; | ||
842 | } else | ||
843 | data->failed = 0; | ||
844 | } | ||
845 | |||
846 | return ret; | ||
798 | } | 847 | } |
799 | 848 | ||
800 | static enum print_line_t | 849 | static enum print_line_t |
@@ -810,7 +859,7 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s, | |||
810 | 859 | ||
811 | if (data) { | 860 | if (data) { |
812 | int cpu = iter->cpu; | 861 | int cpu = iter->cpu; |
813 | int *depth = &(per_cpu_ptr(data, cpu)->depth); | 862 | int *depth = &(per_cpu_ptr(data->cpu_data, cpu)->depth); |
814 | 863 | ||
815 | /* | 864 | /* |
816 | * Comments display at + 1 to depth. This is the | 865 | * Comments display at + 1 to depth. This is the |
@@ -873,7 +922,7 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent, | |||
873 | int i; | 922 | int i; |
874 | 923 | ||
875 | if (data) | 924 | if (data) |
876 | depth = per_cpu_ptr(data, iter->cpu)->depth; | 925 | depth = per_cpu_ptr(data->cpu_data, iter->cpu)->depth; |
877 | 926 | ||
878 | if (print_graph_prologue(iter, s, 0, 0)) | 927 | if (print_graph_prologue(iter, s, 0, 0)) |
879 | return TRACE_TYPE_PARTIAL_LINE; | 928 | return TRACE_TYPE_PARTIAL_LINE; |
@@ -941,8 +990,33 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent, | |||
941 | enum print_line_t | 990 | enum print_line_t |
942 | print_graph_function(struct trace_iterator *iter) | 991 | print_graph_function(struct trace_iterator *iter) |
943 | { | 992 | { |
993 | struct ftrace_graph_ent_entry *field; | ||
994 | struct fgraph_data *data = iter->private; | ||
944 | struct trace_entry *entry = iter->ent; | 995 | struct trace_entry *entry = iter->ent; |
945 | struct trace_seq *s = &iter->seq; | 996 | struct trace_seq *s = &iter->seq; |
997 | int cpu = iter->cpu; | ||
998 | int ret; | ||
999 | |||
1000 | if (data && per_cpu_ptr(data->cpu_data, cpu)->ignore) { | ||
1001 | per_cpu_ptr(data->cpu_data, cpu)->ignore = 0; | ||
1002 | return TRACE_TYPE_HANDLED; | ||
1003 | } | ||
1004 | |||
1005 | /* | ||
1006 | * If the last output failed, there's a possibility we need | ||
1007 | * to print out the missing entry which would never go out. | ||
1008 | */ | ||
1009 | if (data && data->failed) { | ||
1010 | field = &data->ent; | ||
1011 | iter->cpu = data->cpu; | ||
1012 | ret = print_graph_entry(field, s, iter); | ||
1013 | if (ret == TRACE_TYPE_HANDLED && iter->cpu != cpu) { | ||
1014 | per_cpu_ptr(data->cpu_data, iter->cpu)->ignore = 1; | ||
1015 | ret = TRACE_TYPE_NO_CONSUME; | ||
1016 | } | ||
1017 | iter->cpu = cpu; | ||
1018 | return ret; | ||
1019 | } | ||
946 | 1020 | ||
947 | switch (entry->type) { | 1021 | switch (entry->type) { |
948 | case TRACE_GRAPH_ENT: { | 1022 | case TRACE_GRAPH_ENT: { |
@@ -952,7 +1026,7 @@ print_graph_function(struct trace_iterator *iter) | |||
952 | * sizeof(struct ftrace_graph_ent_entry) is very small, | 1026 | * sizeof(struct ftrace_graph_ent_entry) is very small, |
953 | * it can be safely saved at the stack. | 1027 | * it can be safely saved at the stack. |
954 | */ | 1028 | */ |
955 | struct ftrace_graph_ent_entry *field, saved; | 1029 | struct ftrace_graph_ent_entry saved; |
956 | trace_assign_type(field, entry); | 1030 | trace_assign_type(field, entry); |
957 | saved = *field; | 1031 | saved = *field; |
958 | return print_graph_entry(&saved, s, iter); | 1032 | return print_graph_entry(&saved, s, iter); |
@@ -1030,31 +1104,54 @@ static void print_graph_headers(struct seq_file *s) | |||
1030 | static void graph_trace_open(struct trace_iterator *iter) | 1104 | static void graph_trace_open(struct trace_iterator *iter) |
1031 | { | 1105 | { |
1032 | /* pid and depth on the last trace processed */ | 1106 | /* pid and depth on the last trace processed */ |
1033 | struct fgraph_data *data = alloc_percpu(struct fgraph_data); | 1107 | struct fgraph_data *data; |
1034 | int cpu; | 1108 | int cpu; |
1035 | 1109 | ||
1110 | iter->private = NULL; | ||
1111 | |||
1112 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
1036 | if (!data) | 1113 | if (!data) |
1037 | pr_warning("function graph tracer: not enough memory\n"); | 1114 | goto out_err; |
1038 | else | 1115 | |
1039 | for_each_possible_cpu(cpu) { | 1116 | data->cpu_data = alloc_percpu(struct fgraph_cpu_data); |
1040 | pid_t *pid = &(per_cpu_ptr(data, cpu)->last_pid); | 1117 | if (!data->cpu_data) |
1041 | int *depth = &(per_cpu_ptr(data, cpu)->depth); | 1118 | goto out_err_free; |
1042 | *pid = -1; | 1119 | |
1043 | *depth = 0; | 1120 | for_each_possible_cpu(cpu) { |
1044 | } | 1121 | pid_t *pid = &(per_cpu_ptr(data->cpu_data, cpu)->last_pid); |
1122 | int *depth = &(per_cpu_ptr(data->cpu_data, cpu)->depth); | ||
1123 | int *ignore = &(per_cpu_ptr(data->cpu_data, cpu)->ignore); | ||
1124 | *pid = -1; | ||
1125 | *depth = 0; | ||
1126 | *ignore = 0; | ||
1127 | } | ||
1045 | 1128 | ||
1046 | iter->private = data; | 1129 | iter->private = data; |
1130 | |||
1131 | return; | ||
1132 | |||
1133 | out_err_free: | ||
1134 | kfree(data); | ||
1135 | out_err: | ||
1136 | pr_warning("function graph tracer: not enough memory\n"); | ||
1047 | } | 1137 | } |
1048 | 1138 | ||
1049 | static void graph_trace_close(struct trace_iterator *iter) | 1139 | static void graph_trace_close(struct trace_iterator *iter) |
1050 | { | 1140 | { |
1051 | free_percpu(iter->private); | 1141 | struct fgraph_data *data = iter->private; |
1142 | |||
1143 | if (data) { | ||
1144 | free_percpu(data->cpu_data); | ||
1145 | kfree(data); | ||
1146 | } | ||
1052 | } | 1147 | } |
1053 | 1148 | ||
1054 | static struct tracer graph_trace __read_mostly = { | 1149 | static struct tracer graph_trace __read_mostly = { |
1055 | .name = "function_graph", | 1150 | .name = "function_graph", |
1056 | .open = graph_trace_open, | 1151 | .open = graph_trace_open, |
1152 | .pipe_open = graph_trace_open, | ||
1057 | .close = graph_trace_close, | 1153 | .close = graph_trace_close, |
1154 | .pipe_close = graph_trace_close, | ||
1058 | .wait_pipe = poll_wait_pipe, | 1155 | .wait_pipe = poll_wait_pipe, |
1059 | .init = graph_trace_init, | 1156 | .init = graph_trace_init, |
1060 | .reset = graph_trace_reset, | 1157 | .reset = graph_trace_reset, |
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index b6c12c6a1bcd..8e46b3323cdc 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c | |||
@@ -23,13 +23,21 @@ static struct hlist_head event_hash[EVENT_HASHSIZE] __read_mostly; | |||
23 | 23 | ||
24 | static int next_event_type = __TRACE_LAST_TYPE + 1; | 24 | static int next_event_type = __TRACE_LAST_TYPE + 1; |
25 | 25 | ||
26 | void trace_print_seq(struct seq_file *m, struct trace_seq *s) | 26 | int trace_print_seq(struct seq_file *m, struct trace_seq *s) |
27 | { | 27 | { |
28 | int len = s->len >= PAGE_SIZE ? PAGE_SIZE - 1 : s->len; | 28 | int len = s->len >= PAGE_SIZE ? PAGE_SIZE - 1 : s->len; |
29 | int ret; | ||
30 | |||
31 | ret = seq_write(m, s->buffer, len); | ||
29 | 32 | ||
30 | seq_write(m, s->buffer, len); | 33 | /* |
34 | * Only reset this buffer if we successfully wrote to the | ||
35 | * seq_file buffer. | ||
36 | */ | ||
37 | if (!ret) | ||
38 | trace_seq_init(s); | ||
31 | 39 | ||
32 | trace_seq_init(s); | 40 | return ret; |
33 | } | 41 | } |
34 | 42 | ||
35 | enum print_line_t trace_print_bprintk_msg_only(struct trace_iterator *iter) | 43 | enum print_line_t trace_print_bprintk_msg_only(struct trace_iterator *iter) |
@@ -85,7 +93,7 @@ trace_seq_printf(struct trace_seq *s, const char *fmt, ...) | |||
85 | va_list ap; | 93 | va_list ap; |
86 | int ret; | 94 | int ret; |
87 | 95 | ||
88 | if (!len) | 96 | if (s->full || !len) |
89 | return 0; | 97 | return 0; |
90 | 98 | ||
91 | va_start(ap, fmt); | 99 | va_start(ap, fmt); |
@@ -93,8 +101,10 @@ trace_seq_printf(struct trace_seq *s, const char *fmt, ...) | |||
93 | va_end(ap); | 101 | va_end(ap); |
94 | 102 | ||
95 | /* If we can't write it all, don't bother writing anything */ | 103 | /* If we can't write it all, don't bother writing anything */ |
96 | if (ret >= len) | 104 | if (ret >= len) { |
105 | s->full = 1; | ||
97 | return 0; | 106 | return 0; |
107 | } | ||
98 | 108 | ||
99 | s->len += ret; | 109 | s->len += ret; |
100 | 110 | ||
@@ -119,14 +129,16 @@ trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args) | |||
119 | int len = (PAGE_SIZE - 1) - s->len; | 129 | int len = (PAGE_SIZE - 1) - s->len; |
120 | int ret; | 130 | int ret; |
121 | 131 | ||
122 | if (!len) | 132 | if (s->full || !len) |
123 | return 0; | 133 | return 0; |
124 | 134 | ||
125 | ret = vsnprintf(s->buffer + s->len, len, fmt, args); | 135 | ret = vsnprintf(s->buffer + s->len, len, fmt, args); |
126 | 136 | ||
127 | /* If we can't write it all, don't bother writing anything */ | 137 | /* If we can't write it all, don't bother writing anything */ |
128 | if (ret >= len) | 138 | if (ret >= len) { |
139 | s->full = 1; | ||
129 | return 0; | 140 | return 0; |
141 | } | ||
130 | 142 | ||
131 | s->len += ret; | 143 | s->len += ret; |
132 | 144 | ||
@@ -139,14 +151,16 @@ int trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary) | |||
139 | int len = (PAGE_SIZE - 1) - s->len; | 151 | int len = (PAGE_SIZE - 1) - s->len; |
140 | int ret; | 152 | int ret; |
141 | 153 | ||
142 | if (!len) | 154 | if (s->full || !len) |
143 | return 0; | 155 | return 0; |
144 | 156 | ||
145 | ret = bstr_printf(s->buffer + s->len, len, fmt, binary); | 157 | ret = bstr_printf(s->buffer + s->len, len, fmt, binary); |
146 | 158 | ||
147 | /* If we can't write it all, don't bother writing anything */ | 159 | /* If we can't write it all, don't bother writing anything */ |
148 | if (ret >= len) | 160 | if (ret >= len) { |
161 | s->full = 1; | ||
149 | return 0; | 162 | return 0; |
163 | } | ||
150 | 164 | ||
151 | s->len += ret; | 165 | s->len += ret; |
152 | 166 | ||
@@ -167,8 +181,13 @@ int trace_seq_puts(struct trace_seq *s, const char *str) | |||
167 | { | 181 | { |
168 | int len = strlen(str); | 182 | int len = strlen(str); |
169 | 183 | ||
170 | if (len > ((PAGE_SIZE - 1) - s->len)) | 184 | if (s->full) |
185 | return 0; | ||
186 | |||
187 | if (len > ((PAGE_SIZE - 1) - s->len)) { | ||
188 | s->full = 1; | ||
171 | return 0; | 189 | return 0; |
190 | } | ||
172 | 191 | ||
173 | memcpy(s->buffer + s->len, str, len); | 192 | memcpy(s->buffer + s->len, str, len); |
174 | s->len += len; | 193 | s->len += len; |
@@ -178,9 +197,14 @@ int trace_seq_puts(struct trace_seq *s, const char *str) | |||
178 | 197 | ||
179 | int trace_seq_putc(struct trace_seq *s, unsigned char c) | 198 | int trace_seq_putc(struct trace_seq *s, unsigned char c) |
180 | { | 199 | { |
181 | if (s->len >= (PAGE_SIZE - 1)) | 200 | if (s->full) |
182 | return 0; | 201 | return 0; |
183 | 202 | ||
203 | if (s->len >= (PAGE_SIZE - 1)) { | ||
204 | s->full = 1; | ||
205 | return 0; | ||
206 | } | ||
207 | |||
184 | s->buffer[s->len++] = c; | 208 | s->buffer[s->len++] = c; |
185 | 209 | ||
186 | return 1; | 210 | return 1; |
@@ -188,9 +212,14 @@ int trace_seq_putc(struct trace_seq *s, unsigned char c) | |||
188 | 212 | ||
189 | int trace_seq_putmem(struct trace_seq *s, const void *mem, size_t len) | 213 | int trace_seq_putmem(struct trace_seq *s, const void *mem, size_t len) |
190 | { | 214 | { |
191 | if (len > ((PAGE_SIZE - 1) - s->len)) | 215 | if (s->full) |
192 | return 0; | 216 | return 0; |
193 | 217 | ||
218 | if (len > ((PAGE_SIZE - 1) - s->len)) { | ||
219 | s->full = 1; | ||
220 | return 0; | ||
221 | } | ||
222 | |||
194 | memcpy(s->buffer + s->len, mem, len); | 223 | memcpy(s->buffer + s->len, mem, len); |
195 | s->len += len; | 224 | s->len += len; |
196 | 225 | ||
@@ -203,6 +232,9 @@ int trace_seq_putmem_hex(struct trace_seq *s, const void *mem, size_t len) | |||
203 | const unsigned char *data = mem; | 232 | const unsigned char *data = mem; |
204 | int i, j; | 233 | int i, j; |
205 | 234 | ||
235 | if (s->full) | ||
236 | return 0; | ||
237 | |||
206 | #ifdef __BIG_ENDIAN | 238 | #ifdef __BIG_ENDIAN |
207 | for (i = 0, j = 0; i < len; i++) { | 239 | for (i = 0, j = 0; i < len; i++) { |
208 | #else | 240 | #else |
@@ -220,8 +252,13 @@ void *trace_seq_reserve(struct trace_seq *s, size_t len) | |||
220 | { | 252 | { |
221 | void *ret; | 253 | void *ret; |
222 | 254 | ||
223 | if (len > ((PAGE_SIZE - 1) - s->len)) | 255 | if (s->full) |
256 | return 0; | ||
257 | |||
258 | if (len > ((PAGE_SIZE - 1) - s->len)) { | ||
259 | s->full = 1; | ||
224 | return NULL; | 260 | return NULL; |
261 | } | ||
225 | 262 | ||
226 | ret = s->buffer + s->len; | 263 | ret = s->buffer + s->len; |
227 | s->len += len; | 264 | s->len += len; |
@@ -233,8 +270,14 @@ int trace_seq_path(struct trace_seq *s, struct path *path) | |||
233 | { | 270 | { |
234 | unsigned char *p; | 271 | unsigned char *p; |
235 | 272 | ||
236 | if (s->len >= (PAGE_SIZE - 1)) | 273 | if (s->full) |
274 | return 0; | ||
275 | |||
276 | if (s->len >= (PAGE_SIZE - 1)) { | ||
277 | s->full = 1; | ||
237 | return 0; | 278 | return 0; |
279 | } | ||
280 | |||
238 | p = d_path(path, s->buffer + s->len, PAGE_SIZE - s->len); | 281 | p = d_path(path, s->buffer + s->len, PAGE_SIZE - s->len); |
239 | if (!IS_ERR(p)) { | 282 | if (!IS_ERR(p)) { |
240 | p = mangle_path(s->buffer + s->len, p, "\n"); | 283 | p = mangle_path(s->buffer + s->len, p, "\n"); |
@@ -247,6 +290,7 @@ int trace_seq_path(struct trace_seq *s, struct path *path) | |||
247 | return 1; | 290 | return 1; |
248 | } | 291 | } |
249 | 292 | ||
293 | s->full = 1; | ||
250 | return 0; | 294 | return 0; |
251 | } | 295 | } |
252 | 296 | ||
@@ -373,6 +417,9 @@ int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm, | |||
373 | unsigned long vmstart = 0; | 417 | unsigned long vmstart = 0; |
374 | int ret = 1; | 418 | int ret = 1; |
375 | 419 | ||
420 | if (s->full) | ||
421 | return 0; | ||
422 | |||
376 | if (mm) { | 423 | if (mm) { |
377 | const struct vm_area_struct *vma; | 424 | const struct vm_area_struct *vma; |
378 | 425 | ||