diff options
Diffstat (limited to 'kernel/trace/trace.c')
| -rw-r--r-- | kernel/trace/trace.c | 72 |
1 files changed, 57 insertions, 15 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index ee8da93e91e0..944cd021aabf 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
| @@ -119,7 +119,7 @@ enum ftrace_dump_mode ftrace_dump_on_oops; | |||
| 119 | /* When set, tracing will stop when a WARN*() is hit */ | 119 | /* When set, tracing will stop when a WARN*() is hit */ |
| 120 | int __disable_trace_on_warning; | 120 | int __disable_trace_on_warning; |
| 121 | 121 | ||
| 122 | static int tracing_set_tracer(const char *buf); | 122 | static int tracing_set_tracer(struct trace_array *tr, const char *buf); |
| 123 | 123 | ||
| 124 | #define MAX_TRACER_SIZE 100 | 124 | #define MAX_TRACER_SIZE 100 |
| 125 | static char bootup_tracer_buf[MAX_TRACER_SIZE] __initdata; | 125 | static char bootup_tracer_buf[MAX_TRACER_SIZE] __initdata; |
| @@ -1231,7 +1231,7 @@ int register_tracer(struct tracer *type) | |||
| 1231 | 1231 | ||
| 1232 | printk(KERN_INFO "Starting tracer '%s'\n", type->name); | 1232 | printk(KERN_INFO "Starting tracer '%s'\n", type->name); |
| 1233 | /* Do we want this tracer to start on bootup? */ | 1233 | /* Do we want this tracer to start on bootup? */ |
| 1234 | tracing_set_tracer(type->name); | 1234 | tracing_set_tracer(&global_trace, type->name); |
| 1235 | default_bootup_tracer = NULL; | 1235 | default_bootup_tracer = NULL; |
| 1236 | /* disable other selftests, since this will break it. */ | 1236 | /* disable other selftests, since this will break it. */ |
| 1237 | tracing_selftest_disabled = true; | 1237 | tracing_selftest_disabled = true; |
| @@ -3122,27 +3122,52 @@ static int tracing_open(struct inode *inode, struct file *file) | |||
| 3122 | return ret; | 3122 | return ret; |
| 3123 | } | 3123 | } |
| 3124 | 3124 | ||
| 3125 | /* | ||
| 3126 | * Some tracers are not suitable for instance buffers. | ||
| 3127 | * A tracer is always available for the global array (toplevel) | ||
| 3128 | * or if it explicitly states that it is. | ||
| 3129 | */ | ||
| 3130 | static bool | ||
| 3131 | trace_ok_for_array(struct tracer *t, struct trace_array *tr) | ||
| 3132 | { | ||
| 3133 | return (tr->flags & TRACE_ARRAY_FL_GLOBAL) || t->allow_instances; | ||
| 3134 | } | ||
| 3135 | |||
| 3136 | /* Find the next tracer that this trace array may use */ | ||
| 3137 | static struct tracer * | ||
| 3138 | get_tracer_for_array(struct trace_array *tr, struct tracer *t) | ||
| 3139 | { | ||
| 3140 | while (t && !trace_ok_for_array(t, tr)) | ||
| 3141 | t = t->next; | ||
| 3142 | |||
| 3143 | return t; | ||
| 3144 | } | ||
| 3145 | |||
| 3125 | static void * | 3146 | static void * |
| 3126 | t_next(struct seq_file *m, void *v, loff_t *pos) | 3147 | t_next(struct seq_file *m, void *v, loff_t *pos) |
| 3127 | { | 3148 | { |
| 3149 | struct trace_array *tr = m->private; | ||
| 3128 | struct tracer *t = v; | 3150 | struct tracer *t = v; |
| 3129 | 3151 | ||
| 3130 | (*pos)++; | 3152 | (*pos)++; |
| 3131 | 3153 | ||
| 3132 | if (t) | 3154 | if (t) |
| 3133 | t = t->next; | 3155 | t = get_tracer_for_array(tr, t->next); |
| 3134 | 3156 | ||
| 3135 | return t; | 3157 | return t; |
| 3136 | } | 3158 | } |
| 3137 | 3159 | ||
| 3138 | static void *t_start(struct seq_file *m, loff_t *pos) | 3160 | static void *t_start(struct seq_file *m, loff_t *pos) |
| 3139 | { | 3161 | { |
| 3162 | struct trace_array *tr = m->private; | ||
| 3140 | struct tracer *t; | 3163 | struct tracer *t; |
| 3141 | loff_t l = 0; | 3164 | loff_t l = 0; |
| 3142 | 3165 | ||
| 3143 | mutex_lock(&trace_types_lock); | 3166 | mutex_lock(&trace_types_lock); |
| 3144 | for (t = trace_types; t && l < *pos; t = t_next(m, t, &l)) | 3167 | |
| 3145 | ; | 3168 | t = get_tracer_for_array(tr, trace_types); |
| 3169 | for (; t && l < *pos; t = t_next(m, t, &l)) | ||
| 3170 | ; | ||
| 3146 | 3171 | ||
| 3147 | return t; | 3172 | return t; |
| 3148 | } | 3173 | } |
| @@ -3177,10 +3202,21 @@ static const struct seq_operations show_traces_seq_ops = { | |||
| 3177 | 3202 | ||
| 3178 | static int show_traces_open(struct inode *inode, struct file *file) | 3203 | static int show_traces_open(struct inode *inode, struct file *file) |
| 3179 | { | 3204 | { |
| 3205 | struct trace_array *tr = inode->i_private; | ||
| 3206 | struct seq_file *m; | ||
| 3207 | int ret; | ||
| 3208 | |||
| 3180 | if (tracing_disabled) | 3209 | if (tracing_disabled) |
| 3181 | return -ENODEV; | 3210 | return -ENODEV; |
| 3182 | 3211 | ||
| 3183 | return seq_open(file, &show_traces_seq_ops); | 3212 | ret = seq_open(file, &show_traces_seq_ops); |
| 3213 | if (ret) | ||
| 3214 | return ret; | ||
| 3215 | |||
| 3216 | m = file->private_data; | ||
| 3217 | m->private = tr; | ||
| 3218 | |||
| 3219 | return 0; | ||
| 3184 | } | 3220 | } |
| 3185 | 3221 | ||
| 3186 | static ssize_t | 3222 | static ssize_t |
| @@ -3871,10 +3907,9 @@ create_trace_option_files(struct trace_array *tr, struct tracer *tracer); | |||
| 3871 | static void | 3907 | static void |
| 3872 | destroy_trace_option_files(struct trace_option_dentry *topts); | 3908 | destroy_trace_option_files(struct trace_option_dentry *topts); |
| 3873 | 3909 | ||
| 3874 | static int tracing_set_tracer(const char *buf) | 3910 | static int tracing_set_tracer(struct trace_array *tr, const char *buf) |
| 3875 | { | 3911 | { |
| 3876 | static struct trace_option_dentry *topts; | 3912 | static struct trace_option_dentry *topts; |
| 3877 | struct trace_array *tr = &global_trace; | ||
| 3878 | struct tracer *t; | 3913 | struct tracer *t; |
| 3879 | #ifdef CONFIG_TRACER_MAX_TRACE | 3914 | #ifdef CONFIG_TRACER_MAX_TRACE |
| 3880 | bool had_max_tr; | 3915 | bool had_max_tr; |
| @@ -3902,6 +3937,12 @@ static int tracing_set_tracer(const char *buf) | |||
| 3902 | if (t == tr->current_trace) | 3937 | if (t == tr->current_trace) |
| 3903 | goto out; | 3938 | goto out; |
| 3904 | 3939 | ||
| 3940 | /* Some tracers are only allowed for the top level buffer */ | ||
| 3941 | if (!trace_ok_for_array(t, tr)) { | ||
| 3942 | ret = -EINVAL; | ||
| 3943 | goto out; | ||
| 3944 | } | ||
| 3945 | |||
| 3905 | trace_branch_disable(); | 3946 | trace_branch_disable(); |
| 3906 | 3947 | ||
| 3907 | tr->current_trace->enabled = false; | 3948 | tr->current_trace->enabled = false; |
| @@ -3958,6 +3999,7 @@ static ssize_t | |||
| 3958 | tracing_set_trace_write(struct file *filp, const char __user *ubuf, | 3999 | tracing_set_trace_write(struct file *filp, const char __user *ubuf, |
| 3959 | size_t cnt, loff_t *ppos) | 4000 | size_t cnt, loff_t *ppos) |
| 3960 | { | 4001 | { |
| 4002 | struct trace_array *tr = filp->private_data; | ||
| 3961 | char buf[MAX_TRACER_SIZE+1]; | 4003 | char buf[MAX_TRACER_SIZE+1]; |
| 3962 | int i; | 4004 | int i; |
| 3963 | size_t ret; | 4005 | size_t ret; |
| @@ -3977,7 +4019,7 @@ tracing_set_trace_write(struct file *filp, const char __user *ubuf, | |||
| 3977 | for (i = cnt - 1; i > 0 && isspace(buf[i]); i--) | 4019 | for (i = cnt - 1; i > 0 && isspace(buf[i]); i--) |
| 3978 | buf[i] = 0; | 4020 | buf[i] = 0; |
| 3979 | 4021 | ||
| 3980 | err = tracing_set_tracer(buf); | 4022 | err = tracing_set_tracer(tr, buf); |
| 3981 | if (err) | 4023 | if (err) |
| 3982 | return err; | 4024 | return err; |
| 3983 | 4025 | ||
| @@ -6193,6 +6235,12 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer) | |||
| 6193 | { | 6235 | { |
| 6194 | int cpu; | 6236 | int cpu; |
| 6195 | 6237 | ||
| 6238 | trace_create_file("available_tracers", 0444, d_tracer, | ||
| 6239 | tr, &show_traces_fops); | ||
| 6240 | |||
| 6241 | trace_create_file("current_tracer", 0644, d_tracer, | ||
| 6242 | tr, &set_tracer_fops); | ||
| 6243 | |||
| 6196 | trace_create_file("tracing_cpumask", 0644, d_tracer, | 6244 | trace_create_file("tracing_cpumask", 0644, d_tracer, |
| 6197 | tr, &tracing_cpumask_fops); | 6245 | tr, &tracing_cpumask_fops); |
| 6198 | 6246 | ||
| @@ -6245,12 +6293,6 @@ static __init int tracer_init_debugfs(void) | |||
| 6245 | 6293 | ||
| 6246 | init_tracer_debugfs(&global_trace, d_tracer); | 6294 | init_tracer_debugfs(&global_trace, d_tracer); |
| 6247 | 6295 | ||
| 6248 | trace_create_file("available_tracers", 0444, d_tracer, | ||
| 6249 | &global_trace, &show_traces_fops); | ||
| 6250 | |||
| 6251 | trace_create_file("current_tracer", 0644, d_tracer, | ||
| 6252 | &global_trace, &set_tracer_fops); | ||
| 6253 | |||
| 6254 | #ifdef CONFIG_TRACER_MAX_TRACE | 6296 | #ifdef CONFIG_TRACER_MAX_TRACE |
| 6255 | trace_create_file("tracing_max_latency", 0644, d_tracer, | 6297 | trace_create_file("tracing_max_latency", 0644, d_tracer, |
| 6256 | &tracing_max_latency, &tracing_max_lat_fops); | 6298 | &tracing_max_latency, &tracing_max_lat_fops); |
