diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-16 15:23:18 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-16 15:23:18 -0500 |
commit | b29c8306a368cf65782669eba079f81dc861c54d (patch) | |
tree | 35d75aa0e671070d4024f11338d3ae89b078b1ed /kernel/trace/ftrace.c | |
parent | 0bde7294e2ada03d0f1cc61cec51274081d9a9cf (diff) | |
parent | 3a81a5210b7d33bb6d836b4c4952a54166a336f3 (diff) |
Merge tag 'trace-3.13' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace
Pull tracing update from Steven Rostedt:
"This batch of changes is mostly clean ups and small bug fixes. The
only real feature that was added this release is from Namhyung Kim,
who introduced "set_graph_notrace" filter that lets you run the
function graph tracer and not trace particular functions and their
call chain.
Tom Zanussi added some updates to the ftrace multibuffer tracing that
made it more consistent with the top level tracing.
One of the fixes for perf function tracing required an API change in
RCU; the addition of "rcu_is_watching()". As Paul McKenney is pushing
that change in this release too, he gave me a branch that included all
the changes to get that working, and I pulled that into my tree in
order to complete the perf function tracing fix"
* tag 'trace-3.13' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace:
tracing: Add rcu annotation for syscall trace descriptors
tracing: Do not use signed enums with unsigned long long in fgragh output
tracing: Remove unused function ftrace_off_permanent()
tracing: Do not assign filp->private_data to freed memory
tracing: Add helper function tracing_is_disabled()
tracing: Open tracer when ftrace_dump_on_oops is used
tracing: Add support for SOFT_DISABLE to syscall events
tracing: Make register/unregister_ftrace_command __init
tracing: Update event filters for multibuffer
recordmcount.pl: Add support for __fentry__
ftrace: Have control op function callback only trace when RCU is watching
rcu: Do not trace rcu_is_watching() functions
ftrace/x86: skip over the breakpoint for ftrace caller
trace/trace_stat: use rbtree postorder iteration helper instead of opencoding
ftrace: Add set_graph_notrace filter
ftrace: Narrow down the protected area of graph_lock
ftrace: Introduce struct ftrace_graph_data
ftrace: Get rid of ftrace_graph_filter_enabled
tracing: Fix potential out-of-bounds in trace_get_user()
tracing: Show more exact help information about snapshot
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r-- | kernel/trace/ftrace.c | 161 |
1 files changed, 123 insertions, 38 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 03cf44ac54d3..22fa55696760 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -3307,7 +3307,11 @@ void unregister_ftrace_function_probe_all(char *glob) | |||
3307 | static LIST_HEAD(ftrace_commands); | 3307 | static LIST_HEAD(ftrace_commands); |
3308 | static DEFINE_MUTEX(ftrace_cmd_mutex); | 3308 | static DEFINE_MUTEX(ftrace_cmd_mutex); |
3309 | 3309 | ||
3310 | int register_ftrace_command(struct ftrace_func_command *cmd) | 3310 | /* |
3311 | * Currently we only register ftrace commands from __init, so mark this | ||
3312 | * __init too. | ||
3313 | */ | ||
3314 | __init int register_ftrace_command(struct ftrace_func_command *cmd) | ||
3311 | { | 3315 | { |
3312 | struct ftrace_func_command *p; | 3316 | struct ftrace_func_command *p; |
3313 | int ret = 0; | 3317 | int ret = 0; |
@@ -3326,7 +3330,11 @@ int register_ftrace_command(struct ftrace_func_command *cmd) | |||
3326 | return ret; | 3330 | return ret; |
3327 | } | 3331 | } |
3328 | 3332 | ||
3329 | int unregister_ftrace_command(struct ftrace_func_command *cmd) | 3333 | /* |
3334 | * Currently we only unregister ftrace commands from __init, so mark | ||
3335 | * this __init too. | ||
3336 | */ | ||
3337 | __init int unregister_ftrace_command(struct ftrace_func_command *cmd) | ||
3330 | { | 3338 | { |
3331 | struct ftrace_func_command *p, *n; | 3339 | struct ftrace_func_command *p, *n; |
3332 | int ret = -ENODEV; | 3340 | int ret = -ENODEV; |
@@ -3641,7 +3649,7 @@ __setup("ftrace_filter=", set_ftrace_filter); | |||
3641 | 3649 | ||
3642 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 3650 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
3643 | static char ftrace_graph_buf[FTRACE_FILTER_SIZE] __initdata; | 3651 | static char ftrace_graph_buf[FTRACE_FILTER_SIZE] __initdata; |
3644 | static int ftrace_set_func(unsigned long *array, int *idx, char *buffer); | 3652 | static int ftrace_set_func(unsigned long *array, int *idx, int size, char *buffer); |
3645 | 3653 | ||
3646 | static int __init set_graph_function(char *str) | 3654 | static int __init set_graph_function(char *str) |
3647 | { | 3655 | { |
@@ -3659,7 +3667,7 @@ static void __init set_ftrace_early_graph(char *buf) | |||
3659 | func = strsep(&buf, ","); | 3667 | func = strsep(&buf, ","); |
3660 | /* we allow only one expression at a time */ | 3668 | /* we allow only one expression at a time */ |
3661 | ret = ftrace_set_func(ftrace_graph_funcs, &ftrace_graph_count, | 3669 | ret = ftrace_set_func(ftrace_graph_funcs, &ftrace_graph_count, |
3662 | func); | 3670 | FTRACE_GRAPH_MAX_FUNCS, func); |
3663 | if (ret) | 3671 | if (ret) |
3664 | printk(KERN_DEBUG "ftrace: function %s not " | 3672 | printk(KERN_DEBUG "ftrace: function %s not " |
3665 | "traceable\n", func); | 3673 | "traceable\n", func); |
@@ -3776,15 +3784,25 @@ static const struct file_operations ftrace_notrace_fops = { | |||
3776 | static DEFINE_MUTEX(graph_lock); | 3784 | static DEFINE_MUTEX(graph_lock); |
3777 | 3785 | ||
3778 | int ftrace_graph_count; | 3786 | int ftrace_graph_count; |
3779 | int ftrace_graph_filter_enabled; | 3787 | int ftrace_graph_notrace_count; |
3780 | unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS] __read_mostly; | 3788 | unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS] __read_mostly; |
3789 | unsigned long ftrace_graph_notrace_funcs[FTRACE_GRAPH_MAX_FUNCS] __read_mostly; | ||
3790 | |||
3791 | struct ftrace_graph_data { | ||
3792 | unsigned long *table; | ||
3793 | size_t size; | ||
3794 | int *count; | ||
3795 | const struct seq_operations *seq_ops; | ||
3796 | }; | ||
3781 | 3797 | ||
3782 | static void * | 3798 | static void * |
3783 | __g_next(struct seq_file *m, loff_t *pos) | 3799 | __g_next(struct seq_file *m, loff_t *pos) |
3784 | { | 3800 | { |
3785 | if (*pos >= ftrace_graph_count) | 3801 | struct ftrace_graph_data *fgd = m->private; |
3802 | |||
3803 | if (*pos >= *fgd->count) | ||
3786 | return NULL; | 3804 | return NULL; |
3787 | return &ftrace_graph_funcs[*pos]; | 3805 | return &fgd->table[*pos]; |
3788 | } | 3806 | } |
3789 | 3807 | ||
3790 | static void * | 3808 | static void * |
@@ -3796,10 +3814,12 @@ g_next(struct seq_file *m, void *v, loff_t *pos) | |||
3796 | 3814 | ||
3797 | static void *g_start(struct seq_file *m, loff_t *pos) | 3815 | static void *g_start(struct seq_file *m, loff_t *pos) |
3798 | { | 3816 | { |
3817 | struct ftrace_graph_data *fgd = m->private; | ||
3818 | |||
3799 | mutex_lock(&graph_lock); | 3819 | mutex_lock(&graph_lock); |
3800 | 3820 | ||
3801 | /* Nothing, tell g_show to print all functions are enabled */ | 3821 | /* Nothing, tell g_show to print all functions are enabled */ |
3802 | if (!ftrace_graph_filter_enabled && !*pos) | 3822 | if (!*fgd->count && !*pos) |
3803 | return (void *)1; | 3823 | return (void *)1; |
3804 | 3824 | ||
3805 | return __g_next(m, pos); | 3825 | return __g_next(m, pos); |
@@ -3835,38 +3855,88 @@ static const struct seq_operations ftrace_graph_seq_ops = { | |||
3835 | }; | 3855 | }; |
3836 | 3856 | ||
3837 | static int | 3857 | static int |
3838 | ftrace_graph_open(struct inode *inode, struct file *file) | 3858 | __ftrace_graph_open(struct inode *inode, struct file *file, |
3859 | struct ftrace_graph_data *fgd) | ||
3839 | { | 3860 | { |
3840 | int ret = 0; | 3861 | int ret = 0; |
3841 | 3862 | ||
3842 | if (unlikely(ftrace_disabled)) | ||
3843 | return -ENODEV; | ||
3844 | |||
3845 | mutex_lock(&graph_lock); | 3863 | mutex_lock(&graph_lock); |
3846 | if ((file->f_mode & FMODE_WRITE) && | 3864 | if ((file->f_mode & FMODE_WRITE) && |
3847 | (file->f_flags & O_TRUNC)) { | 3865 | (file->f_flags & O_TRUNC)) { |
3848 | ftrace_graph_filter_enabled = 0; | 3866 | *fgd->count = 0; |
3849 | ftrace_graph_count = 0; | 3867 | memset(fgd->table, 0, fgd->size * sizeof(*fgd->table)); |
3850 | memset(ftrace_graph_funcs, 0, sizeof(ftrace_graph_funcs)); | ||
3851 | } | 3868 | } |
3852 | mutex_unlock(&graph_lock); | 3869 | mutex_unlock(&graph_lock); |
3853 | 3870 | ||
3854 | if (file->f_mode & FMODE_READ) | 3871 | if (file->f_mode & FMODE_READ) { |
3855 | ret = seq_open(file, &ftrace_graph_seq_ops); | 3872 | ret = seq_open(file, fgd->seq_ops); |
3873 | if (!ret) { | ||
3874 | struct seq_file *m = file->private_data; | ||
3875 | m->private = fgd; | ||
3876 | } | ||
3877 | } else | ||
3878 | file->private_data = fgd; | ||
3856 | 3879 | ||
3857 | return ret; | 3880 | return ret; |
3858 | } | 3881 | } |
3859 | 3882 | ||
3860 | static int | 3883 | static int |
3884 | ftrace_graph_open(struct inode *inode, struct file *file) | ||
3885 | { | ||
3886 | struct ftrace_graph_data *fgd; | ||
3887 | |||
3888 | if (unlikely(ftrace_disabled)) | ||
3889 | return -ENODEV; | ||
3890 | |||
3891 | fgd = kmalloc(sizeof(*fgd), GFP_KERNEL); | ||
3892 | if (fgd == NULL) | ||
3893 | return -ENOMEM; | ||
3894 | |||
3895 | fgd->table = ftrace_graph_funcs; | ||
3896 | fgd->size = FTRACE_GRAPH_MAX_FUNCS; | ||
3897 | fgd->count = &ftrace_graph_count; | ||
3898 | fgd->seq_ops = &ftrace_graph_seq_ops; | ||
3899 | |||
3900 | return __ftrace_graph_open(inode, file, fgd); | ||
3901 | } | ||
3902 | |||
3903 | static int | ||
3904 | ftrace_graph_notrace_open(struct inode *inode, struct file *file) | ||
3905 | { | ||
3906 | struct ftrace_graph_data *fgd; | ||
3907 | |||
3908 | if (unlikely(ftrace_disabled)) | ||
3909 | return -ENODEV; | ||
3910 | |||
3911 | fgd = kmalloc(sizeof(*fgd), GFP_KERNEL); | ||
3912 | if (fgd == NULL) | ||
3913 | return -ENOMEM; | ||
3914 | |||
3915 | fgd->table = ftrace_graph_notrace_funcs; | ||
3916 | fgd->size = FTRACE_GRAPH_MAX_FUNCS; | ||
3917 | fgd->count = &ftrace_graph_notrace_count; | ||
3918 | fgd->seq_ops = &ftrace_graph_seq_ops; | ||
3919 | |||
3920 | return __ftrace_graph_open(inode, file, fgd); | ||
3921 | } | ||
3922 | |||
3923 | static int | ||
3861 | ftrace_graph_release(struct inode *inode, struct file *file) | 3924 | ftrace_graph_release(struct inode *inode, struct file *file) |
3862 | { | 3925 | { |
3863 | if (file->f_mode & FMODE_READ) | 3926 | if (file->f_mode & FMODE_READ) { |
3927 | struct seq_file *m = file->private_data; | ||
3928 | |||
3929 | kfree(m->private); | ||
3864 | seq_release(inode, file); | 3930 | seq_release(inode, file); |
3931 | } else { | ||
3932 | kfree(file->private_data); | ||
3933 | } | ||
3934 | |||
3865 | return 0; | 3935 | return 0; |
3866 | } | 3936 | } |
3867 | 3937 | ||
3868 | static int | 3938 | static int |
3869 | ftrace_set_func(unsigned long *array, int *idx, char *buffer) | 3939 | ftrace_set_func(unsigned long *array, int *idx, int size, char *buffer) |
3870 | { | 3940 | { |
3871 | struct dyn_ftrace *rec; | 3941 | struct dyn_ftrace *rec; |
3872 | struct ftrace_page *pg; | 3942 | struct ftrace_page *pg; |
@@ -3879,7 +3949,7 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer) | |||
3879 | 3949 | ||
3880 | /* decode regex */ | 3950 | /* decode regex */ |
3881 | type = filter_parse_regex(buffer, strlen(buffer), &search, ¬); | 3951 | type = filter_parse_regex(buffer, strlen(buffer), &search, ¬); |
3882 | if (!not && *idx >= FTRACE_GRAPH_MAX_FUNCS) | 3952 | if (!not && *idx >= size) |
3883 | return -EBUSY; | 3953 | return -EBUSY; |
3884 | 3954 | ||
3885 | search_len = strlen(search); | 3955 | search_len = strlen(search); |
@@ -3907,7 +3977,7 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer) | |||
3907 | fail = 0; | 3977 | fail = 0; |
3908 | if (!exists) { | 3978 | if (!exists) { |
3909 | array[(*idx)++] = rec->ip; | 3979 | array[(*idx)++] = rec->ip; |
3910 | if (*idx >= FTRACE_GRAPH_MAX_FUNCS) | 3980 | if (*idx >= size) |
3911 | goto out; | 3981 | goto out; |
3912 | } | 3982 | } |
3913 | } else { | 3983 | } else { |
@@ -3925,8 +3995,6 @@ out: | |||
3925 | if (fail) | 3995 | if (fail) |
3926 | return -EINVAL; | 3996 | return -EINVAL; |
3927 | 3997 | ||
3928 | ftrace_graph_filter_enabled = !!(*idx); | ||
3929 | |||
3930 | return 0; | 3998 | return 0; |
3931 | } | 3999 | } |
3932 | 4000 | ||
@@ -3935,36 +4003,33 @@ ftrace_graph_write(struct file *file, const char __user *ubuf, | |||
3935 | size_t cnt, loff_t *ppos) | 4003 | size_t cnt, loff_t *ppos) |
3936 | { | 4004 | { |
3937 | struct trace_parser parser; | 4005 | struct trace_parser parser; |
3938 | ssize_t read, ret; | 4006 | ssize_t read, ret = 0; |
4007 | struct ftrace_graph_data *fgd = file->private_data; | ||
3939 | 4008 | ||
3940 | if (!cnt) | 4009 | if (!cnt) |
3941 | return 0; | 4010 | return 0; |
3942 | 4011 | ||
3943 | mutex_lock(&graph_lock); | 4012 | if (trace_parser_get_init(&parser, FTRACE_BUFF_MAX)) |
3944 | 4013 | return -ENOMEM; | |
3945 | if (trace_parser_get_init(&parser, FTRACE_BUFF_MAX)) { | ||
3946 | ret = -ENOMEM; | ||
3947 | goto out_unlock; | ||
3948 | } | ||
3949 | 4014 | ||
3950 | read = trace_get_user(&parser, ubuf, cnt, ppos); | 4015 | read = trace_get_user(&parser, ubuf, cnt, ppos); |
3951 | 4016 | ||
3952 | if (read >= 0 && trace_parser_loaded((&parser))) { | 4017 | if (read >= 0 && trace_parser_loaded((&parser))) { |
3953 | parser.buffer[parser.idx] = 0; | 4018 | parser.buffer[parser.idx] = 0; |
3954 | 4019 | ||
4020 | mutex_lock(&graph_lock); | ||
4021 | |||
3955 | /* we allow only one expression at a time */ | 4022 | /* we allow only one expression at a time */ |
3956 | ret = ftrace_set_func(ftrace_graph_funcs, &ftrace_graph_count, | 4023 | ret = ftrace_set_func(fgd->table, fgd->count, fgd->size, |
3957 | parser.buffer); | 4024 | parser.buffer); |
3958 | if (ret) | 4025 | |
3959 | goto out_free; | 4026 | mutex_unlock(&graph_lock); |
3960 | } | 4027 | } |
3961 | 4028 | ||
3962 | ret = read; | 4029 | if (!ret) |
4030 | ret = read; | ||
3963 | 4031 | ||
3964 | out_free: | ||
3965 | trace_parser_put(&parser); | 4032 | trace_parser_put(&parser); |
3966 | out_unlock: | ||
3967 | mutex_unlock(&graph_lock); | ||
3968 | 4033 | ||
3969 | return ret; | 4034 | return ret; |
3970 | } | 4035 | } |
@@ -3976,6 +4041,14 @@ static const struct file_operations ftrace_graph_fops = { | |||
3976 | .llseek = ftrace_filter_lseek, | 4041 | .llseek = ftrace_filter_lseek, |
3977 | .release = ftrace_graph_release, | 4042 | .release = ftrace_graph_release, |
3978 | }; | 4043 | }; |
4044 | |||
4045 | static const struct file_operations ftrace_graph_notrace_fops = { | ||
4046 | .open = ftrace_graph_notrace_open, | ||
4047 | .read = seq_read, | ||
4048 | .write = ftrace_graph_write, | ||
4049 | .llseek = ftrace_filter_lseek, | ||
4050 | .release = ftrace_graph_release, | ||
4051 | }; | ||
3979 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | 4052 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |
3980 | 4053 | ||
3981 | static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer) | 4054 | static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer) |
@@ -3997,6 +4070,9 @@ static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer) | |||
3997 | trace_create_file("set_graph_function", 0444, d_tracer, | 4070 | trace_create_file("set_graph_function", 0444, d_tracer, |
3998 | NULL, | 4071 | NULL, |
3999 | &ftrace_graph_fops); | 4072 | &ftrace_graph_fops); |
4073 | trace_create_file("set_graph_notrace", 0444, d_tracer, | ||
4074 | NULL, | ||
4075 | &ftrace_graph_notrace_fops); | ||
4000 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | 4076 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ |
4001 | 4077 | ||
4002 | return 0; | 4078 | return 0; |
@@ -4320,12 +4396,21 @@ ftrace_ops_control_func(unsigned long ip, unsigned long parent_ip, | |||
4320 | */ | 4396 | */ |
4321 | preempt_disable_notrace(); | 4397 | preempt_disable_notrace(); |
4322 | trace_recursion_set(TRACE_CONTROL_BIT); | 4398 | trace_recursion_set(TRACE_CONTROL_BIT); |
4399 | |||
4400 | /* | ||
4401 | * Control funcs (perf) uses RCU. Only trace if | ||
4402 | * RCU is currently active. | ||
4403 | */ | ||
4404 | if (!rcu_is_watching()) | ||
4405 | goto out; | ||
4406 | |||
4323 | do_for_each_ftrace_op(op, ftrace_control_list) { | 4407 | do_for_each_ftrace_op(op, ftrace_control_list) { |
4324 | if (!(op->flags & FTRACE_OPS_FL_STUB) && | 4408 | if (!(op->flags & FTRACE_OPS_FL_STUB) && |
4325 | !ftrace_function_local_disabled(op) && | 4409 | !ftrace_function_local_disabled(op) && |
4326 | ftrace_ops_test(op, ip, regs)) | 4410 | ftrace_ops_test(op, ip, regs)) |
4327 | op->func(ip, parent_ip, op, regs); | 4411 | op->func(ip, parent_ip, op, regs); |
4328 | } while_for_each_ftrace_op(op); | 4412 | } while_for_each_ftrace_op(op); |
4413 | out: | ||
4329 | trace_recursion_clear(TRACE_CONTROL_BIT); | 4414 | trace_recursion_clear(TRACE_CONTROL_BIT); |
4330 | preempt_enable_notrace(); | 4415 | preempt_enable_notrace(); |
4331 | } | 4416 | } |