diff options
author | Li Zefan <lizf@cn.fujitsu.com> | 2009-12-30 01:24:03 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-12-30 01:50:50 -0500 |
commit | 53ab668064edaeef99c0ee22799483d45f4c81f6 (patch) | |
tree | 1aa92f9e5bbddb61cbc3d5683180dc64abe341fc | |
parent | e6d9491bf8ba6728cc86aeabbc688d20ec0563b5 (diff) |
ksym_tracer: Remove trace_stat
trace_stat is problematic. Don't use it, use seqfile instead.
This fixes a race that reading the stat file is not protected by
any lock, which can lead to use after free.
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: K.Prasad <prasad@linux.vnet.ibm.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
LKML-Reference: <4B3AF203.40200@cn.fujitsu.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | kernel/trace/trace_ksym.c | 127 |
1 files changed, 50 insertions, 77 deletions
diff --git a/kernel/trace/trace_ksym.c b/kernel/trace/trace_ksym.c index 67d79f709fc5..94103cdcf9d8 100644 --- a/kernel/trace/trace_ksym.c +++ b/kernel/trace/trace_ksym.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/fs.h> | 26 | #include <linux/fs.h> |
27 | 27 | ||
28 | #include "trace_output.h" | 28 | #include "trace_output.h" |
29 | #include "trace_stat.h" | ||
30 | #include "trace.h" | 29 | #include "trace.h" |
31 | 30 | ||
32 | #include <linux/hw_breakpoint.h> | 31 | #include <linux/hw_breakpoint.h> |
@@ -444,103 +443,77 @@ struct tracer ksym_tracer __read_mostly = | |||
444 | .print_line = ksym_trace_output | 443 | .print_line = ksym_trace_output |
445 | }; | 444 | }; |
446 | 445 | ||
447 | __init static int init_ksym_trace(void) | ||
448 | { | ||
449 | struct dentry *d_tracer; | ||
450 | struct dentry *entry; | ||
451 | |||
452 | d_tracer = tracing_init_dentry(); | ||
453 | ksym_filter_entry_count = 0; | ||
454 | |||
455 | entry = debugfs_create_file("ksym_trace_filter", 0644, d_tracer, | ||
456 | NULL, &ksym_tracing_fops); | ||
457 | if (!entry) | ||
458 | pr_warning("Could not create debugfs " | ||
459 | "'ksym_trace_filter' file\n"); | ||
460 | |||
461 | return register_tracer(&ksym_tracer); | ||
462 | } | ||
463 | device_initcall(init_ksym_trace); | ||
464 | |||
465 | |||
466 | #ifdef CONFIG_PROFILE_KSYM_TRACER | 446 | #ifdef CONFIG_PROFILE_KSYM_TRACER |
467 | static int ksym_tracer_stat_headers(struct seq_file *m) | 447 | static int ksym_profile_show(struct seq_file *m, void *v) |
468 | { | 448 | { |
449 | struct hlist_node *node; | ||
450 | struct trace_ksym *entry; | ||
451 | int access_type = 0; | ||
452 | char fn_name[KSYM_NAME_LEN]; | ||
453 | |||
469 | seq_puts(m, " Access Type "); | 454 | seq_puts(m, " Access Type "); |
470 | seq_puts(m, " Symbol Counter\n"); | 455 | seq_puts(m, " Symbol Counter\n"); |
471 | seq_puts(m, " ----------- "); | 456 | seq_puts(m, " ----------- "); |
472 | seq_puts(m, " ------ -------\n"); | 457 | seq_puts(m, " ------ -------\n"); |
473 | return 0; | ||
474 | } | ||
475 | 458 | ||
476 | static int ksym_tracer_stat_show(struct seq_file *m, void *v) | 459 | rcu_read_lock(); |
477 | { | 460 | hlist_for_each_entry_rcu(entry, node, &ksym_filter_head, ksym_hlist) { |
478 | struct hlist_node *stat = v; | ||
479 | struct trace_ksym *entry; | ||
480 | int access_type = 0; | ||
481 | char fn_name[KSYM_NAME_LEN]; | ||
482 | 461 | ||
483 | entry = hlist_entry(stat, struct trace_ksym, ksym_hlist); | 462 | access_type = entry->attr.bp_type; |
484 | 463 | ||
485 | access_type = entry->attr.bp_type; | 464 | switch (access_type) { |
465 | case HW_BREAKPOINT_R: | ||
466 | seq_puts(m, " R "); | ||
467 | break; | ||
468 | case HW_BREAKPOINT_W: | ||
469 | seq_puts(m, " W "); | ||
470 | break; | ||
471 | case HW_BREAKPOINT_R | HW_BREAKPOINT_W: | ||
472 | seq_puts(m, " RW "); | ||
473 | break; | ||
474 | default: | ||
475 | seq_puts(m, " NA "); | ||
476 | } | ||
486 | 477 | ||
487 | switch (access_type) { | 478 | if (lookup_symbol_name(entry->attr.bp_addr, fn_name) >= 0) |
488 | case HW_BREAKPOINT_R: | 479 | seq_printf(m, " %-36s", fn_name); |
489 | seq_puts(m, " R "); | 480 | else |
490 | break; | 481 | seq_printf(m, " %-36s", "<NA>"); |
491 | case HW_BREAKPOINT_W: | 482 | seq_printf(m, " %15llu\n", |
492 | seq_puts(m, " W "); | 483 | (unsigned long long)atomic64_read(&entry->counter)); |
493 | break; | ||
494 | case HW_BREAKPOINT_R | HW_BREAKPOINT_W: | ||
495 | seq_puts(m, " RW "); | ||
496 | break; | ||
497 | default: | ||
498 | seq_puts(m, " NA "); | ||
499 | } | 484 | } |
500 | 485 | rcu_read_unlock(); | |
501 | if (lookup_symbol_name(entry->attr.bp_addr, fn_name) >= 0) | ||
502 | seq_printf(m, " %-36s", fn_name); | ||
503 | else | ||
504 | seq_printf(m, " %-36s", "<NA>"); | ||
505 | seq_printf(m, " %15llu\n", | ||
506 | (unsigned long long)atomic64_read(&entry->counter)); | ||
507 | 486 | ||
508 | return 0; | 487 | return 0; |
509 | } | 488 | } |
510 | 489 | ||
511 | static void *ksym_tracer_stat_start(struct tracer_stat *trace) | 490 | static int ksym_profile_open(struct inode *node, struct file *file) |
512 | { | 491 | { |
513 | return ksym_filter_head.first; | 492 | return single_open(file, ksym_profile_show, NULL); |
514 | } | ||
515 | |||
516 | static void * | ||
517 | ksym_tracer_stat_next(void *v, int idx) | ||
518 | { | ||
519 | struct hlist_node *stat = v; | ||
520 | |||
521 | return stat->next; | ||
522 | } | 493 | } |
523 | 494 | ||
524 | static struct tracer_stat ksym_tracer_stats = { | 495 | static const struct file_operations ksym_profile_fops = { |
525 | .name = "ksym_tracer", | 496 | .open = ksym_profile_open, |
526 | .stat_start = ksym_tracer_stat_start, | 497 | .read = seq_read, |
527 | .stat_next = ksym_tracer_stat_next, | 498 | .llseek = seq_lseek, |
528 | .stat_headers = ksym_tracer_stat_headers, | 499 | .release = single_release, |
529 | .stat_show = ksym_tracer_stat_show | ||
530 | }; | 500 | }; |
501 | #endif /* CONFIG_PROFILE_KSYM_TRACER */ | ||
531 | 502 | ||
532 | __init static int ksym_tracer_stat_init(void) | 503 | __init static int init_ksym_trace(void) |
533 | { | 504 | { |
534 | int ret; | 505 | struct dentry *d_tracer; |
535 | 506 | ||
536 | ret = register_stat_tracer(&ksym_tracer_stats); | 507 | d_tracer = tracing_init_dentry(); |
537 | if (ret) { | ||
538 | printk(KERN_WARNING "Warning: could not register " | ||
539 | "ksym tracer stats\n"); | ||
540 | return 1; | ||
541 | } | ||
542 | 508 | ||
543 | return 0; | 509 | trace_create_file("ksym_trace_filter", 0644, d_tracer, |
510 | NULL, &ksym_tracing_fops); | ||
511 | |||
512 | #ifdef CONFIG_PROFILE_KSYM_TRACER | ||
513 | trace_create_file("ksym_profile", 0444, d_tracer, | ||
514 | NULL, &ksym_profile_fops); | ||
515 | #endif | ||
516 | |||
517 | return register_tracer(&ksym_tracer); | ||
544 | } | 518 | } |
545 | fs_initcall(ksym_tracer_stat_init); | 519 | device_initcall(init_ksym_trace); |
546 | #endif /* CONFIG_PROFILE_KSYM_TRACER */ | ||