Commit 53ab6680 authored by Li Zefan's avatar Li Zefan Committed by Ingo Molnar

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: default avatarLi 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: default avatarIngo Molnar <mingo@elte.hu>
parent e6d9491b
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include <linux/fs.h> #include <linux/fs.h>
#include "trace_output.h" #include "trace_output.h"
#include "trace_stat.h"
#include "trace.h" #include "trace.h"
#include <linux/hw_breakpoint.h> #include <linux/hw_breakpoint.h>
...@@ -444,103 +443,77 @@ struct tracer ksym_tracer __read_mostly = ...@@ -444,103 +443,77 @@ struct tracer ksym_tracer __read_mostly =
.print_line = ksym_trace_output .print_line = ksym_trace_output
}; };
__init static int init_ksym_trace(void)
{
struct dentry *d_tracer;
struct dentry *entry;
d_tracer = tracing_init_dentry();
ksym_filter_entry_count = 0;
entry = debugfs_create_file("ksym_trace_filter", 0644, d_tracer,
NULL, &ksym_tracing_fops);
if (!entry)
pr_warning("Could not create debugfs "
"'ksym_trace_filter' file\n");
return register_tracer(&ksym_tracer);
}
device_initcall(init_ksym_trace);
#ifdef CONFIG_PROFILE_KSYM_TRACER #ifdef CONFIG_PROFILE_KSYM_TRACER
static int ksym_tracer_stat_headers(struct seq_file *m) static int ksym_profile_show(struct seq_file *m, void *v)
{ {
struct hlist_node *node;
struct trace_ksym *entry;
int access_type = 0;
char fn_name[KSYM_NAME_LEN];
seq_puts(m, " Access Type "); seq_puts(m, " Access Type ");
seq_puts(m, " Symbol Counter\n"); seq_puts(m, " Symbol Counter\n");
seq_puts(m, " ----------- "); seq_puts(m, " ----------- ");
seq_puts(m, " ------ -------\n"); seq_puts(m, " ------ -------\n");
return 0;
}
static int ksym_tracer_stat_show(struct seq_file *m, void *v) rcu_read_lock();
{ hlist_for_each_entry_rcu(entry, node, &ksym_filter_head, ksym_hlist) {
struct hlist_node *stat = v;
struct trace_ksym *entry;
int access_type = 0;
char fn_name[KSYM_NAME_LEN];
entry = hlist_entry(stat, struct trace_ksym, ksym_hlist); access_type = entry->attr.bp_type;
access_type = entry->attr.bp_type; switch (access_type) {
case HW_BREAKPOINT_R:
seq_puts(m, " R ");
break;
case HW_BREAKPOINT_W:
seq_puts(m, " W ");
break;
case HW_BREAKPOINT_R | HW_BREAKPOINT_W:
seq_puts(m, " RW ");
break;
default:
seq_puts(m, " NA ");
}
switch (access_type) { if (lookup_symbol_name(entry->attr.bp_addr, fn_name) >= 0)
case HW_BREAKPOINT_R: seq_printf(m, " %-36s", fn_name);
seq_puts(m, " R "); else
break; seq_printf(m, " %-36s", "<NA>");
case HW_BREAKPOINT_W: seq_printf(m, " %15llu\n",
seq_puts(m, " W "); (unsigned long long)atomic64_read(&entry->counter));
break;
case HW_BREAKPOINT_R | HW_BREAKPOINT_W:
seq_puts(m, " RW ");
break;
default:
seq_puts(m, " NA ");
} }
rcu_read_unlock();
if (lookup_symbol_name(entry->attr.bp_addr, fn_name) >= 0)
seq_printf(m, " %-36s", fn_name);
else
seq_printf(m, " %-36s", "<NA>");
seq_printf(m, " %15llu\n",
(unsigned long long)atomic64_read(&entry->counter));
return 0; return 0;
} }
static void *ksym_tracer_stat_start(struct tracer_stat *trace) static int ksym_profile_open(struct inode *node, struct file *file)
{ {
return ksym_filter_head.first; return single_open(file, ksym_profile_show, NULL);
}
static void *
ksym_tracer_stat_next(void *v, int idx)
{
struct hlist_node *stat = v;
return stat->next;
} }
static struct tracer_stat ksym_tracer_stats = { static const struct file_operations ksym_profile_fops = {
.name = "ksym_tracer", .open = ksym_profile_open,
.stat_start = ksym_tracer_stat_start, .read = seq_read,
.stat_next = ksym_tracer_stat_next, .llseek = seq_lseek,
.stat_headers = ksym_tracer_stat_headers, .release = single_release,
.stat_show = ksym_tracer_stat_show
}; };
#endif /* CONFIG_PROFILE_KSYM_TRACER */
__init static int ksym_tracer_stat_init(void) __init static int init_ksym_trace(void)
{ {
int ret; struct dentry *d_tracer;
ret = register_stat_tracer(&ksym_tracer_stats); d_tracer = tracing_init_dentry();
if (ret) {
printk(KERN_WARNING "Warning: could not register "
"ksym tracer stats\n");
return 1;
}
return 0; trace_create_file("ksym_trace_filter", 0644, d_tracer,
NULL, &ksym_tracing_fops);
#ifdef CONFIG_PROFILE_KSYM_TRACER
trace_create_file("ksym_profile", 0444, d_tracer,
NULL, &ksym_profile_fops);
#endif
return register_tracer(&ksym_tracer);
} }
fs_initcall(ksym_tracer_stat_init); device_initcall(init_ksym_trace);
#endif /* CONFIG_PROFILE_KSYM_TRACER */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment