diff options
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 | } |