aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_output.c
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2009-09-14 00:16:56 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2009-09-14 00:16:56 -0400
commitfc8e1ead9314cf0e0f1922e661428b93d3a50d88 (patch)
treef3cb97c4769b74f6627a59769f1ed5c92a13c58a /kernel/trace/trace_output.c
parent2bcaa6a4238094c5695d5b1943078388d82d3004 (diff)
parent9de48cc300fb10f7d9faa978670becf5e352462a (diff)
Merge branch 'next' into for-linus
Diffstat (limited to 'kernel/trace/trace_output.c')
-rw-r--r--kernel/trace/trace_output.c239
1 files changed, 212 insertions, 27 deletions
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
index 64b54a59c55b..e0c2545622e8 100644
--- a/kernel/trace/trace_output.c
+++ b/kernel/trace/trace_output.c
@@ -14,11 +14,24 @@
14/* must be a power of 2 */ 14/* must be a power of 2 */
15#define EVENT_HASHSIZE 128 15#define EVENT_HASHSIZE 128
16 16
17static DEFINE_MUTEX(trace_event_mutex); 17DECLARE_RWSEM(trace_event_mutex);
18
19DEFINE_PER_CPU(struct trace_seq, ftrace_event_seq);
20EXPORT_PER_CPU_SYMBOL(ftrace_event_seq);
21
18static struct hlist_head event_hash[EVENT_HASHSIZE] __read_mostly; 22static struct hlist_head event_hash[EVENT_HASHSIZE] __read_mostly;
19 23
20static int next_event_type = __TRACE_LAST_TYPE + 1; 24static int next_event_type = __TRACE_LAST_TYPE + 1;
21 25
26void trace_print_seq(struct seq_file *m, struct trace_seq *s)
27{
28 int len = s->len >= PAGE_SIZE ? PAGE_SIZE - 1 : s->len;
29
30 seq_write(m, s->buffer, len);
31
32 trace_seq_init(s);
33}
34
22enum print_line_t trace_print_bprintk_msg_only(struct trace_iterator *iter) 35enum print_line_t trace_print_bprintk_msg_only(struct trace_iterator *iter)
23{ 36{
24 struct trace_seq *s = &iter->seq; 37 struct trace_seq *s = &iter->seq;
@@ -84,6 +97,39 @@ trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
84 97
85 return len; 98 return len;
86} 99}
100EXPORT_SYMBOL_GPL(trace_seq_printf);
101
102/**
103 * trace_seq_vprintf - sequence printing of trace information
104 * @s: trace sequence descriptor
105 * @fmt: printf format string
106 *
107 * The tracer may use either sequence operations or its own
108 * copy to user routines. To simplify formating of a trace
109 * trace_seq_printf is used to store strings into a special
110 * buffer (@s). Then the output may be either used by
111 * the sequencer or pulled into another buffer.
112 */
113int
114trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
115{
116 int len = (PAGE_SIZE - 1) - s->len;
117 int ret;
118
119 if (!len)
120 return 0;
121
122 ret = vsnprintf(s->buffer + s->len, len, fmt, args);
123
124 /* If we can't write it all, don't bother writing anything */
125 if (ret >= len)
126 return 0;
127
128 s->len += ret;
129
130 return len;
131}
132EXPORT_SYMBOL_GPL(trace_seq_vprintf);
87 133
88int trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary) 134int trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary)
89{ 135{
@@ -201,6 +247,67 @@ int trace_seq_path(struct trace_seq *s, struct path *path)
201 return 0; 247 return 0;
202} 248}
203 249
250const char *
251ftrace_print_flags_seq(struct trace_seq *p, const char *delim,
252 unsigned long flags,
253 const struct trace_print_flags *flag_array)
254{
255 unsigned long mask;
256 const char *str;
257 const char *ret = p->buffer + p->len;
258 int i;
259
260 for (i = 0; flag_array[i].name && flags; i++) {
261
262 mask = flag_array[i].mask;
263 if ((flags & mask) != mask)
264 continue;
265
266 str = flag_array[i].name;
267 flags &= ~mask;
268 if (p->len && delim)
269 trace_seq_puts(p, delim);
270 trace_seq_puts(p, str);
271 }
272
273 /* check for left over flags */
274 if (flags) {
275 if (p->len && delim)
276 trace_seq_puts(p, delim);
277 trace_seq_printf(p, "0x%lx", flags);
278 }
279
280 trace_seq_putc(p, 0);
281
282 return ret;
283}
284EXPORT_SYMBOL(ftrace_print_flags_seq);
285
286const char *
287ftrace_print_symbols_seq(struct trace_seq *p, unsigned long val,
288 const struct trace_print_flags *symbol_array)
289{
290 int i;
291 const char *ret = p->buffer + p->len;
292
293 for (i = 0; symbol_array[i].name; i++) {
294
295 if (val != symbol_array[i].mask)
296 continue;
297
298 trace_seq_puts(p, symbol_array[i].name);
299 break;
300 }
301
302 if (!p->len)
303 trace_seq_printf(p, "0x%lx", val);
304
305 trace_seq_putc(p, 0);
306
307 return ret;
308}
309EXPORT_SYMBOL(ftrace_print_symbols_seq);
310
204#ifdef CONFIG_KRETPROBES 311#ifdef CONFIG_KRETPROBES
205static inline const char *kretprobed(const char *name) 312static inline const char *kretprobed(const char *name)
206{ 313{
@@ -311,17 +418,20 @@ seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s,
311 418
312 if (ip == ULONG_MAX || !ret) 419 if (ip == ULONG_MAX || !ret)
313 break; 420 break;
314 if (i && ret) 421 if (ret)
315 ret = trace_seq_puts(s, " <- "); 422 ret = trace_seq_puts(s, " => ");
316 if (!ip) { 423 if (!ip) {
317 if (ret) 424 if (ret)
318 ret = trace_seq_puts(s, "??"); 425 ret = trace_seq_puts(s, "??");
426 if (ret)
427 ret = trace_seq_puts(s, "\n");
319 continue; 428 continue;
320 } 429 }
321 if (!ret) 430 if (!ret)
322 break; 431 break;
323 if (ret) 432 if (ret)
324 ret = seq_print_user_ip(s, mm, ip, sym_flags); 433 ret = seq_print_user_ip(s, mm, ip, sym_flags);
434 ret = trace_seq_puts(s, "\n");
325 } 435 }
326 436
327 if (mm) 437 if (mm)
@@ -455,6 +565,7 @@ static int task_state_char(unsigned long state)
455 * @type: the type of event to look for 565 * @type: the type of event to look for
456 * 566 *
457 * Returns an event of type @type otherwise NULL 567 * Returns an event of type @type otherwise NULL
568 * Called with trace_event_read_lock() held.
458 */ 569 */
459struct trace_event *ftrace_find_event(int type) 570struct trace_event *ftrace_find_event(int type)
460{ 571{
@@ -464,7 +575,7 @@ struct trace_event *ftrace_find_event(int type)
464 575
465 key = type & (EVENT_HASHSIZE - 1); 576 key = type & (EVENT_HASHSIZE - 1);
466 577
467 hlist_for_each_entry_rcu(event, n, &event_hash[key], node) { 578 hlist_for_each_entry(event, n, &event_hash[key], node) {
468 if (event->type == type) 579 if (event->type == type)
469 return event; 580 return event;
470 } 581 }
@@ -472,6 +583,46 @@ struct trace_event *ftrace_find_event(int type)
472 return NULL; 583 return NULL;
473} 584}
474 585
586static LIST_HEAD(ftrace_event_list);
587
588static int trace_search_list(struct list_head **list)
589{
590 struct trace_event *e;
591 int last = __TRACE_LAST_TYPE;
592
593 if (list_empty(&ftrace_event_list)) {
594 *list = &ftrace_event_list;
595 return last + 1;
596 }
597
598 /*
599 * We used up all possible max events,
600 * lets see if somebody freed one.
601 */
602 list_for_each_entry(e, &ftrace_event_list, list) {
603 if (e->type != last + 1)
604 break;
605 last++;
606 }
607
608 /* Did we used up all 65 thousand events??? */
609 if ((last + 1) > FTRACE_MAX_EVENT)
610 return 0;
611
612 *list = &e->list;
613 return last + 1;
614}
615
616void trace_event_read_lock(void)
617{
618 down_read(&trace_event_mutex);
619}
620
621void trace_event_read_unlock(void)
622{
623 up_read(&trace_event_mutex);
624}
625
475/** 626/**
476 * register_ftrace_event - register output for an event type 627 * register_ftrace_event - register output for an event type
477 * @event: the event type to register 628 * @event: the event type to register
@@ -492,22 +643,42 @@ int register_ftrace_event(struct trace_event *event)
492 unsigned key; 643 unsigned key;
493 int ret = 0; 644 int ret = 0;
494 645
495 mutex_lock(&trace_event_mutex); 646 down_write(&trace_event_mutex);
496 647
497 if (!event) { 648 if (WARN_ON(!event))
498 ret = next_event_type++;
499 goto out; 649 goto out;
500 }
501 650
502 if (!event->type) 651 INIT_LIST_HEAD(&event->list);
503 event->type = next_event_type++; 652
504 else if (event->type > __TRACE_LAST_TYPE) { 653 if (!event->type) {
654 struct list_head *list = NULL;
655
656 if (next_event_type > FTRACE_MAX_EVENT) {
657
658 event->type = trace_search_list(&list);
659 if (!event->type)
660 goto out;
661
662 } else {
663
664 event->type = next_event_type++;
665 list = &ftrace_event_list;
666 }
667
668 if (WARN_ON(ftrace_find_event(event->type)))
669 goto out;
670
671 list_add_tail(&event->list, list);
672
673 } else if (event->type > __TRACE_LAST_TYPE) {
505 printk(KERN_WARNING "Need to add type to trace.h\n"); 674 printk(KERN_WARNING "Need to add type to trace.h\n");
506 WARN_ON(1); 675 WARN_ON(1);
507 }
508
509 if (ftrace_find_event(event->type))
510 goto out; 676 goto out;
677 } else {
678 /* Is this event already used */
679 if (ftrace_find_event(event->type))
680 goto out;
681 }
511 682
512 if (event->trace == NULL) 683 if (event->trace == NULL)
513 event->trace = trace_nop_print; 684 event->trace = trace_nop_print;
@@ -520,14 +691,25 @@ int register_ftrace_event(struct trace_event *event)
520 691
521 key = event->type & (EVENT_HASHSIZE - 1); 692 key = event->type & (EVENT_HASHSIZE - 1);
522 693
523 hlist_add_head_rcu(&event->node, &event_hash[key]); 694 hlist_add_head(&event->node, &event_hash[key]);
524 695
525 ret = event->type; 696 ret = event->type;
526 out: 697 out:
527 mutex_unlock(&trace_event_mutex); 698 up_write(&trace_event_mutex);
528 699
529 return ret; 700 return ret;
530} 701}
702EXPORT_SYMBOL_GPL(register_ftrace_event);
703
704/*
705 * Used by module code with the trace_event_mutex held for write.
706 */
707int __unregister_ftrace_event(struct trace_event *event)
708{
709 hlist_del(&event->node);
710 list_del(&event->list);
711 return 0;
712}
531 713
532/** 714/**
533 * unregister_ftrace_event - remove a no longer used event 715 * unregister_ftrace_event - remove a no longer used event
@@ -535,12 +717,13 @@ int register_ftrace_event(struct trace_event *event)
535 */ 717 */
536int unregister_ftrace_event(struct trace_event *event) 718int unregister_ftrace_event(struct trace_event *event)
537{ 719{
538 mutex_lock(&trace_event_mutex); 720 down_write(&trace_event_mutex);
539 hlist_del(&event->node); 721 __unregister_ftrace_event(event);
540 mutex_unlock(&trace_event_mutex); 722 up_write(&trace_event_mutex);
541 723
542 return 0; 724 return 0;
543} 725}
726EXPORT_SYMBOL_GPL(unregister_ftrace_event);
544 727
545/* 728/*
546 * Standard events 729 * Standard events
@@ -833,14 +1016,16 @@ static enum print_line_t trace_stack_print(struct trace_iterator *iter,
833 1016
834 trace_assign_type(field, iter->ent); 1017 trace_assign_type(field, iter->ent);
835 1018
1019 if (!trace_seq_puts(s, "<stack trace>\n"))
1020 goto partial;
836 for (i = 0; i < FTRACE_STACK_ENTRIES; i++) { 1021 for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
837 if (i) { 1022 if (!field->caller[i] || (field->caller[i] == ULONG_MAX))
838 if (!trace_seq_puts(s, " <= ")) 1023 break;
839 goto partial; 1024 if (!trace_seq_puts(s, " => "))
1025 goto partial;
840 1026
841 if (!seq_print_ip_sym(s, field->caller[i], flags)) 1027 if (!seq_print_ip_sym(s, field->caller[i], flags))
842 goto partial; 1028 goto partial;
843 }
844 if (!trace_seq_puts(s, "\n")) 1029 if (!trace_seq_puts(s, "\n"))
845 goto partial; 1030 goto partial;
846 } 1031 }
@@ -868,10 +1053,10 @@ static enum print_line_t trace_user_stack_print(struct trace_iterator *iter,
868 1053
869 trace_assign_type(field, iter->ent); 1054 trace_assign_type(field, iter->ent);
870 1055
871 if (!seq_print_userip_objs(field, s, flags)) 1056 if (!trace_seq_puts(s, "<user stack trace>\n"))
872 goto partial; 1057 goto partial;
873 1058
874 if (!trace_seq_putc(s, '\n')) 1059 if (!seq_print_userip_objs(field, s, flags))
875 goto partial; 1060 goto partial;
876 1061
877 return TRACE_TYPE_HANDLED; 1062 return TRACE_TYPE_HANDLED;