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 /kernel | |
| 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
Diffstat (limited to 'kernel')
| -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 |
4 files changed, 242 insertions, 57 deletions
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 | ||
