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 /kernel/trace | |
| 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>
Diffstat (limited to 'kernel/trace')
| -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 */ | ||
