diff options
-rw-r--r-- | Documentation/kernel-parameters.txt | 13 | ||||
-rw-r--r-- | Documentation/trace/events.txt | 15 | ||||
-rw-r--r-- | Documentation/trace/ftrace.txt | 13 | ||||
-rw-r--r-- | include/linux/ftrace.h | 9 | ||||
-rw-r--r-- | include/trace/syscall.h | 1 | ||||
-rw-r--r-- | kernel/panic.c | 3 | ||||
-rw-r--r-- | kernel/sysctl.c | 7 | ||||
-rw-r--r-- | kernel/trace/ftrace.c | 38 | ||||
-rw-r--r-- | kernel/trace/trace.c | 338 | ||||
-rw-r--r-- | kernel/trace/trace.h | 17 | ||||
-rw-r--r-- | kernel/trace/trace_events.c | 166 | ||||
-rw-r--r-- | kernel/trace/trace_events_filter.c | 6 | ||||
-rw-r--r-- | kernel/trace/trace_functions.c | 103 | ||||
-rw-r--r-- | kernel/trace/trace_irqsoff.c | 4 | ||||
-rw-r--r-- | kernel/trace/trace_kprobe.c | 190 | ||||
-rw-r--r-- | kernel/trace/trace_selftest.c | 18 | ||||
-rw-r--r-- | kernel/trace/trace_syscalls.c | 21 | ||||
-rw-r--r-- | kernel/trace/trace_uprobe.c | 4 |
18 files changed, 694 insertions, 272 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 75236f1972d9..15356aca938c 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -3081,6 +3081,19 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
3081 | See also Documentation/trace/ftrace.txt "trace options" | 3081 | See also Documentation/trace/ftrace.txt "trace options" |
3082 | section. | 3082 | section. |
3083 | 3083 | ||
3084 | traceoff_on_warning | ||
3085 | [FTRACE] enable this option to disable tracing when a | ||
3086 | warning is hit. This turns off "tracing_on". Tracing can | ||
3087 | be enabled again by echoing '1' into the "tracing_on" | ||
3088 | file located in /sys/kernel/debug/tracing/ | ||
3089 | |||
3090 | This option is useful, as it disables the trace before | ||
3091 | the WARNING dump is called, which prevents the trace to | ||
3092 | be filled with content caused by the warning output. | ||
3093 | |||
3094 | This option can also be set at run time via the sysctl | ||
3095 | option: kernel/traceoff_on_warning | ||
3096 | |||
3084 | transparent_hugepage= | 3097 | transparent_hugepage= |
3085 | [KNL] | 3098 | [KNL] |
3086 | Format: [always|madvise|never] | 3099 | Format: [always|madvise|never] |
diff --git a/Documentation/trace/events.txt b/Documentation/trace/events.txt index bb24c2a0e870..37732a220d33 100644 --- a/Documentation/trace/events.txt +++ b/Documentation/trace/events.txt | |||
@@ -183,13 +183,22 @@ The relational-operators depend on the type of the field being tested: | |||
183 | 183 | ||
184 | The operators available for numeric fields are: | 184 | The operators available for numeric fields are: |
185 | 185 | ||
186 | ==, !=, <, <=, >, >= | 186 | ==, !=, <, <=, >, >=, & |
187 | 187 | ||
188 | And for string fields they are: | 188 | And for string fields they are: |
189 | 189 | ||
190 | ==, != | 190 | ==, !=, ~ |
191 | 191 | ||
192 | Currently, only exact string matches are supported. | 192 | The glob (~) only accepts a wild card character (*) at the start and or |
193 | end of the string. For example: | ||
194 | |||
195 | prev_comm ~ "*sh" | ||
196 | prev_comm ~ "sh*" | ||
197 | prev_comm ~ "*sh*" | ||
198 | |||
199 | But does not allow for it to be within the string: | ||
200 | |||
201 | prev_comm ~ "ba*sh" <-- is invalid | ||
193 | 202 | ||
194 | 5.2 Setting filters | 203 | 5.2 Setting filters |
195 | ------------------- | 204 | ------------------- |
diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt index bfe8c29b1f1d..b937c6e2163c 100644 --- a/Documentation/trace/ftrace.txt +++ b/Documentation/trace/ftrace.txt | |||
@@ -2430,6 +2430,19 @@ The following commands are supported: | |||
2430 | echo '!schedule:disable_event:sched:sched_switch' > \ | 2430 | echo '!schedule:disable_event:sched:sched_switch' > \ |
2431 | set_ftrace_filter | 2431 | set_ftrace_filter |
2432 | 2432 | ||
2433 | - dump | ||
2434 | When the function is hit, it will dump the contents of the ftrace | ||
2435 | ring buffer to the console. This is useful if you need to debug | ||
2436 | something, and want to dump the trace when a certain function | ||
2437 | is hit. Perhaps its a function that is called before a tripple | ||
2438 | fault happens and does not allow you to get a regular dump. | ||
2439 | |||
2440 | - cpudump | ||
2441 | When the function is hit, it will dump the contents of the ftrace | ||
2442 | ring buffer for the current CPU to the console. Unlike the "dump" | ||
2443 | command, it only prints out the contents of the ring buffer for the | ||
2444 | CPU that executed the function that triggered the dump. | ||
2445 | |||
2433 | trace_pipe | 2446 | trace_pipe |
2434 | ---------- | 2447 | ---------- |
2435 | 2448 | ||
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 99d0fbcbaf79..9f15c0064c50 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h | |||
@@ -566,10 +566,6 @@ static inline ssize_t ftrace_filter_write(struct file *file, const char __user * | |||
566 | size_t cnt, loff_t *ppos) { return -ENODEV; } | 566 | size_t cnt, loff_t *ppos) { return -ENODEV; } |
567 | static inline ssize_t ftrace_notrace_write(struct file *file, const char __user *ubuf, | 567 | static inline ssize_t ftrace_notrace_write(struct file *file, const char __user *ubuf, |
568 | size_t cnt, loff_t *ppos) { return -ENODEV; } | 568 | size_t cnt, loff_t *ppos) { return -ENODEV; } |
569 | static inline loff_t ftrace_regex_lseek(struct file *file, loff_t offset, int whence) | ||
570 | { | ||
571 | return -ENODEV; | ||
572 | } | ||
573 | static inline int | 569 | static inline int |
574 | ftrace_regex_release(struct inode *inode, struct file *file) { return -ENODEV; } | 570 | ftrace_regex_release(struct inode *inode, struct file *file) { return -ENODEV; } |
575 | #endif /* CONFIG_DYNAMIC_FTRACE */ | 571 | #endif /* CONFIG_DYNAMIC_FTRACE */ |
@@ -828,10 +824,15 @@ enum ftrace_dump_mode; | |||
828 | 824 | ||
829 | extern enum ftrace_dump_mode ftrace_dump_on_oops; | 825 | extern enum ftrace_dump_mode ftrace_dump_on_oops; |
830 | 826 | ||
827 | extern void disable_trace_on_warning(void); | ||
828 | extern int __disable_trace_on_warning; | ||
829 | |||
831 | #ifdef CONFIG_PREEMPT | 830 | #ifdef CONFIG_PREEMPT |
832 | #define INIT_TRACE_RECURSION .trace_recursion = 0, | 831 | #define INIT_TRACE_RECURSION .trace_recursion = 0, |
833 | #endif | 832 | #endif |
834 | 833 | ||
834 | #else /* CONFIG_TRACING */ | ||
835 | static inline void disable_trace_on_warning(void) { } | ||
835 | #endif /* CONFIG_TRACING */ | 836 | #endif /* CONFIG_TRACING */ |
836 | 837 | ||
837 | #ifndef INIT_TRACE_RECURSION | 838 | #ifndef INIT_TRACE_RECURSION |
diff --git a/include/trace/syscall.h b/include/trace/syscall.h index 84bc4197e736..fed853f3d7aa 100644 --- a/include/trace/syscall.h +++ b/include/trace/syscall.h | |||
@@ -16,6 +16,7 @@ | |||
16 | * @nb_args: number of parameters it takes | 16 | * @nb_args: number of parameters it takes |
17 | * @types: list of types as strings | 17 | * @types: list of types as strings |
18 | * @args: list of args as strings (args[i] matches types[i]) | 18 | * @args: list of args as strings (args[i] matches types[i]) |
19 | * @enter_fields: list of fields for syscall_enter trace event | ||
19 | * @enter_event: associated syscall_enter trace event | 20 | * @enter_event: associated syscall_enter trace event |
20 | * @exit_event: associated syscall_exit trace event | 21 | * @exit_event: associated syscall_exit trace event |
21 | */ | 22 | */ |
diff --git a/kernel/panic.c b/kernel/panic.c index 97712319f128..801864600514 100644 --- a/kernel/panic.c +++ b/kernel/panic.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/notifier.h> | 15 | #include <linux/notifier.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/random.h> | 17 | #include <linux/random.h> |
18 | #include <linux/ftrace.h> | ||
18 | #include <linux/reboot.h> | 19 | #include <linux/reboot.h> |
19 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
20 | #include <linux/kexec.h> | 21 | #include <linux/kexec.h> |
@@ -399,6 +400,8 @@ struct slowpath_args { | |||
399 | static void warn_slowpath_common(const char *file, int line, void *caller, | 400 | static void warn_slowpath_common(const char *file, int line, void *caller, |
400 | unsigned taint, struct slowpath_args *args) | 401 | unsigned taint, struct slowpath_args *args) |
401 | { | 402 | { |
403 | disable_trace_on_warning(); | ||
404 | |||
402 | pr_warn("------------[ cut here ]------------\n"); | 405 | pr_warn("------------[ cut here ]------------\n"); |
403 | pr_warn("WARNING: CPU: %d PID: %d at %s:%d %pS()\n", | 406 | pr_warn("WARNING: CPU: %d PID: %d at %s:%d %pS()\n", |
404 | raw_smp_processor_id(), current->pid, file, line, caller); | 407 | raw_smp_processor_id(), current->pid, file, line, caller); |
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 4ce13c3cedb9..e5b31aff67aa 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -599,6 +599,13 @@ static struct ctl_table kern_table[] = { | |||
599 | .mode = 0644, | 599 | .mode = 0644, |
600 | .proc_handler = proc_dointvec, | 600 | .proc_handler = proc_dointvec, |
601 | }, | 601 | }, |
602 | { | ||
603 | .procname = "traceoff_on_warning", | ||
604 | .data = &__disable_trace_on_warning, | ||
605 | .maxlen = sizeof(__disable_trace_on_warning), | ||
606 | .mode = 0644, | ||
607 | .proc_handler = proc_dointvec, | ||
608 | }, | ||
602 | #endif | 609 | #endif |
603 | #ifdef CONFIG_MODULES | 610 | #ifdef CONFIG_MODULES |
604 | { | 611 | { |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 6c508ff33c62..67708f46baae 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -413,6 +413,17 @@ static int __register_ftrace_function(struct ftrace_ops *ops) | |||
413 | return 0; | 413 | return 0; |
414 | } | 414 | } |
415 | 415 | ||
416 | static void ftrace_sync(struct work_struct *work) | ||
417 | { | ||
418 | /* | ||
419 | * This function is just a stub to implement a hard force | ||
420 | * of synchronize_sched(). This requires synchronizing | ||
421 | * tasks even in userspace and idle. | ||
422 | * | ||
423 | * Yes, function tracing is rude. | ||
424 | */ | ||
425 | } | ||
426 | |||
416 | static int __unregister_ftrace_function(struct ftrace_ops *ops) | 427 | static int __unregister_ftrace_function(struct ftrace_ops *ops) |
417 | { | 428 | { |
418 | int ret; | 429 | int ret; |
@@ -440,8 +451,12 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops) | |||
440 | * so there'll be no new users. We must ensure | 451 | * so there'll be no new users. We must ensure |
441 | * all current users are done before we free | 452 | * all current users are done before we free |
442 | * the control data. | 453 | * the control data. |
454 | * Note synchronize_sched() is not enough, as we | ||
455 | * use preempt_disable() to do RCU, but the function | ||
456 | * tracer can be called where RCU is not active | ||
457 | * (before user_exit()). | ||
443 | */ | 458 | */ |
444 | synchronize_sched(); | 459 | schedule_on_each_cpu(ftrace_sync); |
445 | control_ops_free(ops); | 460 | control_ops_free(ops); |
446 | } | 461 | } |
447 | } else | 462 | } else |
@@ -456,9 +471,13 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops) | |||
456 | /* | 471 | /* |
457 | * Dynamic ops may be freed, we must make sure that all | 472 | * Dynamic ops may be freed, we must make sure that all |
458 | * callers are done before leaving this function. | 473 | * callers are done before leaving this function. |
474 | * | ||
475 | * Again, normal synchronize_sched() is not good enough. | ||
476 | * We need to do a hard force of sched synchronization. | ||
459 | */ | 477 | */ |
460 | if (ops->flags & FTRACE_OPS_FL_DYNAMIC) | 478 | if (ops->flags & FTRACE_OPS_FL_DYNAMIC) |
461 | synchronize_sched(); | 479 | schedule_on_each_cpu(ftrace_sync); |
480 | |||
462 | 481 | ||
463 | return 0; | 482 | return 0; |
464 | } | 483 | } |
@@ -622,12 +641,18 @@ static int function_stat_show(struct seq_file *m, void *v) | |||
622 | if (rec->counter <= 1) | 641 | if (rec->counter <= 1) |
623 | stddev = 0; | 642 | stddev = 0; |
624 | else { | 643 | else { |
625 | stddev = rec->time_squared - rec->counter * avg * avg; | 644 | /* |
645 | * Apply Welford's method: | ||
646 | * s^2 = 1 / (n * (n-1)) * (n * \Sum (x_i)^2 - (\Sum x_i)^2) | ||
647 | */ | ||
648 | stddev = rec->counter * rec->time_squared - | ||
649 | rec->time * rec->time; | ||
650 | |||
626 | /* | 651 | /* |
627 | * Divide only 1000 for ns^2 -> us^2 conversion. | 652 | * Divide only 1000 for ns^2 -> us^2 conversion. |
628 | * trace_print_graph_duration will divide 1000 again. | 653 | * trace_print_graph_duration will divide 1000 again. |
629 | */ | 654 | */ |
630 | do_div(stddev, (rec->counter - 1) * 1000); | 655 | do_div(stddev, rec->counter * (rec->counter - 1) * 1000); |
631 | } | 656 | } |
632 | 657 | ||
633 | trace_seq_init(&s); | 658 | trace_seq_init(&s); |
@@ -3512,8 +3537,12 @@ EXPORT_SYMBOL_GPL(ftrace_set_global_notrace); | |||
3512 | static char ftrace_notrace_buf[FTRACE_FILTER_SIZE] __initdata; | 3537 | static char ftrace_notrace_buf[FTRACE_FILTER_SIZE] __initdata; |
3513 | static char ftrace_filter_buf[FTRACE_FILTER_SIZE] __initdata; | 3538 | static char ftrace_filter_buf[FTRACE_FILTER_SIZE] __initdata; |
3514 | 3539 | ||
3540 | /* Used by function selftest to not test if filter is set */ | ||
3541 | bool ftrace_filter_param __initdata; | ||
3542 | |||
3515 | static int __init set_ftrace_notrace(char *str) | 3543 | static int __init set_ftrace_notrace(char *str) |
3516 | { | 3544 | { |
3545 | ftrace_filter_param = true; | ||
3517 | strlcpy(ftrace_notrace_buf, str, FTRACE_FILTER_SIZE); | 3546 | strlcpy(ftrace_notrace_buf, str, FTRACE_FILTER_SIZE); |
3518 | return 1; | 3547 | return 1; |
3519 | } | 3548 | } |
@@ -3521,6 +3550,7 @@ __setup("ftrace_notrace=", set_ftrace_notrace); | |||
3521 | 3550 | ||
3522 | static int __init set_ftrace_filter(char *str) | 3551 | static int __init set_ftrace_filter(char *str) |
3523 | { | 3552 | { |
3553 | ftrace_filter_param = true; | ||
3524 | strlcpy(ftrace_filter_buf, str, FTRACE_FILTER_SIZE); | 3554 | strlcpy(ftrace_filter_buf, str, FTRACE_FILTER_SIZE); |
3525 | return 1; | 3555 | return 1; |
3526 | } | 3556 | } |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index e71a8be4a6ee..0cd500bffd9b 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -115,6 +115,9 @@ cpumask_var_t __read_mostly tracing_buffer_mask; | |||
115 | 115 | ||
116 | enum ftrace_dump_mode ftrace_dump_on_oops; | 116 | enum ftrace_dump_mode ftrace_dump_on_oops; |
117 | 117 | ||
118 | /* When set, tracing will stop when a WARN*() is hit */ | ||
119 | int __disable_trace_on_warning; | ||
120 | |||
118 | static int tracing_set_tracer(const char *buf); | 121 | static int tracing_set_tracer(const char *buf); |
119 | 122 | ||
120 | #define MAX_TRACER_SIZE 100 | 123 | #define MAX_TRACER_SIZE 100 |
@@ -149,6 +152,13 @@ static int __init set_ftrace_dump_on_oops(char *str) | |||
149 | } | 152 | } |
150 | __setup("ftrace_dump_on_oops", set_ftrace_dump_on_oops); | 153 | __setup("ftrace_dump_on_oops", set_ftrace_dump_on_oops); |
151 | 154 | ||
155 | static int __init stop_trace_on_warning(char *str) | ||
156 | { | ||
157 | __disable_trace_on_warning = 1; | ||
158 | return 1; | ||
159 | } | ||
160 | __setup("traceoff_on_warning=", stop_trace_on_warning); | ||
161 | |||
152 | static int __init boot_alloc_snapshot(char *str) | 162 | static int __init boot_alloc_snapshot(char *str) |
153 | { | 163 | { |
154 | allocate_snapshot = true; | 164 | allocate_snapshot = true; |
@@ -170,6 +180,7 @@ static int __init set_trace_boot_options(char *str) | |||
170 | } | 180 | } |
171 | __setup("trace_options=", set_trace_boot_options); | 181 | __setup("trace_options=", set_trace_boot_options); |
172 | 182 | ||
183 | |||
173 | unsigned long long ns2usecs(cycle_t nsec) | 184 | unsigned long long ns2usecs(cycle_t nsec) |
174 | { | 185 | { |
175 | nsec += 500; | 186 | nsec += 500; |
@@ -193,6 +204,37 @@ static struct trace_array global_trace; | |||
193 | 204 | ||
194 | LIST_HEAD(ftrace_trace_arrays); | 205 | LIST_HEAD(ftrace_trace_arrays); |
195 | 206 | ||
207 | int trace_array_get(struct trace_array *this_tr) | ||
208 | { | ||
209 | struct trace_array *tr; | ||
210 | int ret = -ENODEV; | ||
211 | |||
212 | mutex_lock(&trace_types_lock); | ||
213 | list_for_each_entry(tr, &ftrace_trace_arrays, list) { | ||
214 | if (tr == this_tr) { | ||
215 | tr->ref++; | ||
216 | ret = 0; | ||
217 | break; | ||
218 | } | ||
219 | } | ||
220 | mutex_unlock(&trace_types_lock); | ||
221 | |||
222 | return ret; | ||
223 | } | ||
224 | |||
225 | static void __trace_array_put(struct trace_array *this_tr) | ||
226 | { | ||
227 | WARN_ON(!this_tr->ref); | ||
228 | this_tr->ref--; | ||
229 | } | ||
230 | |||
231 | void trace_array_put(struct trace_array *this_tr) | ||
232 | { | ||
233 | mutex_lock(&trace_types_lock); | ||
234 | __trace_array_put(this_tr); | ||
235 | mutex_unlock(&trace_types_lock); | ||
236 | } | ||
237 | |||
196 | int filter_current_check_discard(struct ring_buffer *buffer, | 238 | int filter_current_check_discard(struct ring_buffer *buffer, |
197 | struct ftrace_event_call *call, void *rec, | 239 | struct ftrace_event_call *call, void *rec, |
198 | struct ring_buffer_event *event) | 240 | struct ring_buffer_event *event) |
@@ -215,9 +257,24 @@ cycle_t ftrace_now(int cpu) | |||
215 | return ts; | 257 | return ts; |
216 | } | 258 | } |
217 | 259 | ||
260 | /** | ||
261 | * tracing_is_enabled - Show if global_trace has been disabled | ||
262 | * | ||
263 | * Shows if the global trace has been enabled or not. It uses the | ||
264 | * mirror flag "buffer_disabled" to be used in fast paths such as for | ||
265 | * the irqsoff tracer. But it may be inaccurate due to races. If you | ||
266 | * need to know the accurate state, use tracing_is_on() which is a little | ||
267 | * slower, but accurate. | ||
268 | */ | ||
218 | int tracing_is_enabled(void) | 269 | int tracing_is_enabled(void) |
219 | { | 270 | { |
220 | return tracing_is_on(); | 271 | /* |
272 | * For quick access (irqsoff uses this in fast path), just | ||
273 | * return the mirror variable of the state of the ring buffer. | ||
274 | * It's a little racy, but we don't really care. | ||
275 | */ | ||
276 | smp_rmb(); | ||
277 | return !global_trace.buffer_disabled; | ||
221 | } | 278 | } |
222 | 279 | ||
223 | /* | 280 | /* |
@@ -240,7 +297,7 @@ static struct tracer *trace_types __read_mostly; | |||
240 | /* | 297 | /* |
241 | * trace_types_lock is used to protect the trace_types list. | 298 | * trace_types_lock is used to protect the trace_types list. |
242 | */ | 299 | */ |
243 | static DEFINE_MUTEX(trace_types_lock); | 300 | DEFINE_MUTEX(trace_types_lock); |
244 | 301 | ||
245 | /* | 302 | /* |
246 | * serialize the access of the ring buffer | 303 | * serialize the access of the ring buffer |
@@ -330,6 +387,23 @@ unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK | | |||
330 | TRACE_ITER_GRAPH_TIME | TRACE_ITER_RECORD_CMD | TRACE_ITER_OVERWRITE | | 387 | TRACE_ITER_GRAPH_TIME | TRACE_ITER_RECORD_CMD | TRACE_ITER_OVERWRITE | |
331 | TRACE_ITER_IRQ_INFO | TRACE_ITER_MARKERS | TRACE_ITER_FUNCTION; | 388 | TRACE_ITER_IRQ_INFO | TRACE_ITER_MARKERS | TRACE_ITER_FUNCTION; |
332 | 389 | ||
390 | static void tracer_tracing_on(struct trace_array *tr) | ||
391 | { | ||
392 | if (tr->trace_buffer.buffer) | ||
393 | ring_buffer_record_on(tr->trace_buffer.buffer); | ||
394 | /* | ||
395 | * This flag is looked at when buffers haven't been allocated | ||
396 | * yet, or by some tracers (like irqsoff), that just want to | ||
397 | * know if the ring buffer has been disabled, but it can handle | ||
398 | * races of where it gets disabled but we still do a record. | ||
399 | * As the check is in the fast path of the tracers, it is more | ||
400 | * important to be fast than accurate. | ||
401 | */ | ||
402 | tr->buffer_disabled = 0; | ||
403 | /* Make the flag seen by readers */ | ||
404 | smp_wmb(); | ||
405 | } | ||
406 | |||
333 | /** | 407 | /** |
334 | * tracing_on - enable tracing buffers | 408 | * tracing_on - enable tracing buffers |
335 | * | 409 | * |
@@ -338,15 +412,7 @@ unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK | | |||
338 | */ | 412 | */ |
339 | void tracing_on(void) | 413 | void tracing_on(void) |
340 | { | 414 | { |
341 | if (global_trace.trace_buffer.buffer) | 415 | tracer_tracing_on(&global_trace); |
342 | ring_buffer_record_on(global_trace.trace_buffer.buffer); | ||
343 | /* | ||
344 | * This flag is only looked at when buffers haven't been | ||
345 | * allocated yet. We don't really care about the race | ||
346 | * between setting this flag and actually turning | ||
347 | * on the buffer. | ||
348 | */ | ||
349 | global_trace.buffer_disabled = 0; | ||
350 | } | 416 | } |
351 | EXPORT_SYMBOL_GPL(tracing_on); | 417 | EXPORT_SYMBOL_GPL(tracing_on); |
352 | 418 | ||
@@ -540,6 +606,23 @@ void tracing_snapshot_alloc(void) | |||
540 | EXPORT_SYMBOL_GPL(tracing_snapshot_alloc); | 606 | EXPORT_SYMBOL_GPL(tracing_snapshot_alloc); |
541 | #endif /* CONFIG_TRACER_SNAPSHOT */ | 607 | #endif /* CONFIG_TRACER_SNAPSHOT */ |
542 | 608 | ||
609 | static void tracer_tracing_off(struct trace_array *tr) | ||
610 | { | ||
611 | if (tr->trace_buffer.buffer) | ||
612 | ring_buffer_record_off(tr->trace_buffer.buffer); | ||
613 | /* | ||
614 | * This flag is looked at when buffers haven't been allocated | ||
615 | * yet, or by some tracers (like irqsoff), that just want to | ||
616 | * know if the ring buffer has been disabled, but it can handle | ||
617 | * races of where it gets disabled but we still do a record. | ||
618 | * As the check is in the fast path of the tracers, it is more | ||
619 | * important to be fast than accurate. | ||
620 | */ | ||
621 | tr->buffer_disabled = 1; | ||
622 | /* Make the flag seen by readers */ | ||
623 | smp_wmb(); | ||
624 | } | ||
625 | |||
543 | /** | 626 | /** |
544 | * tracing_off - turn off tracing buffers | 627 | * tracing_off - turn off tracing buffers |
545 | * | 628 | * |
@@ -550,26 +633,35 @@ EXPORT_SYMBOL_GPL(tracing_snapshot_alloc); | |||
550 | */ | 633 | */ |
551 | void tracing_off(void) | 634 | void tracing_off(void) |
552 | { | 635 | { |
553 | if (global_trace.trace_buffer.buffer) | 636 | tracer_tracing_off(&global_trace); |
554 | ring_buffer_record_off(global_trace.trace_buffer.buffer); | ||
555 | /* | ||
556 | * This flag is only looked at when buffers haven't been | ||
557 | * allocated yet. We don't really care about the race | ||
558 | * between setting this flag and actually turning | ||
559 | * on the buffer. | ||
560 | */ | ||
561 | global_trace.buffer_disabled = 1; | ||
562 | } | 637 | } |
563 | EXPORT_SYMBOL_GPL(tracing_off); | 638 | EXPORT_SYMBOL_GPL(tracing_off); |
564 | 639 | ||
640 | void disable_trace_on_warning(void) | ||
641 | { | ||
642 | if (__disable_trace_on_warning) | ||
643 | tracing_off(); | ||
644 | } | ||
645 | |||
646 | /** | ||
647 | * tracer_tracing_is_on - show real state of ring buffer enabled | ||
648 | * @tr : the trace array to know if ring buffer is enabled | ||
649 | * | ||
650 | * Shows real state of the ring buffer if it is enabled or not. | ||
651 | */ | ||
652 | static int tracer_tracing_is_on(struct trace_array *tr) | ||
653 | { | ||
654 | if (tr->trace_buffer.buffer) | ||
655 | return ring_buffer_record_is_on(tr->trace_buffer.buffer); | ||
656 | return !tr->buffer_disabled; | ||
657 | } | ||
658 | |||
565 | /** | 659 | /** |
566 | * tracing_is_on - show state of ring buffers enabled | 660 | * tracing_is_on - show state of ring buffers enabled |
567 | */ | 661 | */ |
568 | int tracing_is_on(void) | 662 | int tracing_is_on(void) |
569 | { | 663 | { |
570 | if (global_trace.trace_buffer.buffer) | 664 | return tracer_tracing_is_on(&global_trace); |
571 | return ring_buffer_record_is_on(global_trace.trace_buffer.buffer); | ||
572 | return !global_trace.buffer_disabled; | ||
573 | } | 665 | } |
574 | EXPORT_SYMBOL_GPL(tracing_is_on); | 666 | EXPORT_SYMBOL_GPL(tracing_is_on); |
575 | 667 | ||
@@ -1543,15 +1635,6 @@ trace_function(struct trace_array *tr, | |||
1543 | __buffer_unlock_commit(buffer, event); | 1635 | __buffer_unlock_commit(buffer, event); |
1544 | } | 1636 | } |
1545 | 1637 | ||
1546 | void | ||
1547 | ftrace(struct trace_array *tr, struct trace_array_cpu *data, | ||
1548 | unsigned long ip, unsigned long parent_ip, unsigned long flags, | ||
1549 | int pc) | ||
1550 | { | ||
1551 | if (likely(!atomic_read(&data->disabled))) | ||
1552 | trace_function(tr, ip, parent_ip, flags, pc); | ||
1553 | } | ||
1554 | |||
1555 | #ifdef CONFIG_STACKTRACE | 1638 | #ifdef CONFIG_STACKTRACE |
1556 | 1639 | ||
1557 | #define FTRACE_STACK_MAX_ENTRIES (PAGE_SIZE / sizeof(unsigned long)) | 1640 | #define FTRACE_STACK_MAX_ENTRIES (PAGE_SIZE / sizeof(unsigned long)) |
@@ -2768,10 +2851,9 @@ static const struct seq_operations tracer_seq_ops = { | |||
2768 | }; | 2851 | }; |
2769 | 2852 | ||
2770 | static struct trace_iterator * | 2853 | static struct trace_iterator * |
2771 | __tracing_open(struct inode *inode, struct file *file, bool snapshot) | 2854 | __tracing_open(struct trace_array *tr, struct trace_cpu *tc, |
2855 | struct inode *inode, struct file *file, bool snapshot) | ||
2772 | { | 2856 | { |
2773 | struct trace_cpu *tc = inode->i_private; | ||
2774 | struct trace_array *tr = tc->tr; | ||
2775 | struct trace_iterator *iter; | 2857 | struct trace_iterator *iter; |
2776 | int cpu; | 2858 | int cpu; |
2777 | 2859 | ||
@@ -2850,8 +2932,6 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot) | |||
2850 | tracing_iter_reset(iter, cpu); | 2932 | tracing_iter_reset(iter, cpu); |
2851 | } | 2933 | } |
2852 | 2934 | ||
2853 | tr->ref++; | ||
2854 | |||
2855 | mutex_unlock(&trace_types_lock); | 2935 | mutex_unlock(&trace_types_lock); |
2856 | 2936 | ||
2857 | return iter; | 2937 | return iter; |
@@ -2874,6 +2954,43 @@ int tracing_open_generic(struct inode *inode, struct file *filp) | |||
2874 | return 0; | 2954 | return 0; |
2875 | } | 2955 | } |
2876 | 2956 | ||
2957 | /* | ||
2958 | * Open and update trace_array ref count. | ||
2959 | * Must have the current trace_array passed to it. | ||
2960 | */ | ||
2961 | static int tracing_open_generic_tr(struct inode *inode, struct file *filp) | ||
2962 | { | ||
2963 | struct trace_array *tr = inode->i_private; | ||
2964 | |||
2965 | if (tracing_disabled) | ||
2966 | return -ENODEV; | ||
2967 | |||
2968 | if (trace_array_get(tr) < 0) | ||
2969 | return -ENODEV; | ||
2970 | |||
2971 | filp->private_data = inode->i_private; | ||
2972 | |||
2973 | return 0; | ||
2974 | |||
2975 | } | ||
2976 | |||
2977 | static int tracing_open_generic_tc(struct inode *inode, struct file *filp) | ||
2978 | { | ||
2979 | struct trace_cpu *tc = inode->i_private; | ||
2980 | struct trace_array *tr = tc->tr; | ||
2981 | |||
2982 | if (tracing_disabled) | ||
2983 | return -ENODEV; | ||
2984 | |||
2985 | if (trace_array_get(tr) < 0) | ||
2986 | return -ENODEV; | ||
2987 | |||
2988 | filp->private_data = inode->i_private; | ||
2989 | |||
2990 | return 0; | ||
2991 | |||
2992 | } | ||
2993 | |||
2877 | static int tracing_release(struct inode *inode, struct file *file) | 2994 | static int tracing_release(struct inode *inode, struct file *file) |
2878 | { | 2995 | { |
2879 | struct seq_file *m = file->private_data; | 2996 | struct seq_file *m = file->private_data; |
@@ -2881,17 +2998,20 @@ static int tracing_release(struct inode *inode, struct file *file) | |||
2881 | struct trace_array *tr; | 2998 | struct trace_array *tr; |
2882 | int cpu; | 2999 | int cpu; |
2883 | 3000 | ||
2884 | if (!(file->f_mode & FMODE_READ)) | 3001 | /* Writes do not use seq_file, need to grab tr from inode */ |
3002 | if (!(file->f_mode & FMODE_READ)) { | ||
3003 | struct trace_cpu *tc = inode->i_private; | ||
3004 | |||
3005 | trace_array_put(tc->tr); | ||
2885 | return 0; | 3006 | return 0; |
3007 | } | ||
2886 | 3008 | ||
2887 | iter = m->private; | 3009 | iter = m->private; |
2888 | tr = iter->tr; | 3010 | tr = iter->tr; |
3011 | trace_array_put(tr); | ||
2889 | 3012 | ||
2890 | mutex_lock(&trace_types_lock); | 3013 | mutex_lock(&trace_types_lock); |
2891 | 3014 | ||
2892 | WARN_ON(!tr->ref); | ||
2893 | tr->ref--; | ||
2894 | |||
2895 | for_each_tracing_cpu(cpu) { | 3015 | for_each_tracing_cpu(cpu) { |
2896 | if (iter->buffer_iter[cpu]) | 3016 | if (iter->buffer_iter[cpu]) |
2897 | ring_buffer_read_finish(iter->buffer_iter[cpu]); | 3017 | ring_buffer_read_finish(iter->buffer_iter[cpu]); |
@@ -2910,20 +3030,49 @@ static int tracing_release(struct inode *inode, struct file *file) | |||
2910 | kfree(iter->trace); | 3030 | kfree(iter->trace); |
2911 | kfree(iter->buffer_iter); | 3031 | kfree(iter->buffer_iter); |
2912 | seq_release_private(inode, file); | 3032 | seq_release_private(inode, file); |
3033 | |||
3034 | return 0; | ||
3035 | } | ||
3036 | |||
3037 | static int tracing_release_generic_tr(struct inode *inode, struct file *file) | ||
3038 | { | ||
3039 | struct trace_array *tr = inode->i_private; | ||
3040 | |||
3041 | trace_array_put(tr); | ||
2913 | return 0; | 3042 | return 0; |
2914 | } | 3043 | } |
2915 | 3044 | ||
3045 | static int tracing_release_generic_tc(struct inode *inode, struct file *file) | ||
3046 | { | ||
3047 | struct trace_cpu *tc = inode->i_private; | ||
3048 | struct trace_array *tr = tc->tr; | ||
3049 | |||
3050 | trace_array_put(tr); | ||
3051 | return 0; | ||
3052 | } | ||
3053 | |||
3054 | static int tracing_single_release_tr(struct inode *inode, struct file *file) | ||
3055 | { | ||
3056 | struct trace_array *tr = inode->i_private; | ||
3057 | |||
3058 | trace_array_put(tr); | ||
3059 | |||
3060 | return single_release(inode, file); | ||
3061 | } | ||
3062 | |||
2916 | static int tracing_open(struct inode *inode, struct file *file) | 3063 | static int tracing_open(struct inode *inode, struct file *file) |
2917 | { | 3064 | { |
3065 | struct trace_cpu *tc = inode->i_private; | ||
3066 | struct trace_array *tr = tc->tr; | ||
2918 | struct trace_iterator *iter; | 3067 | struct trace_iterator *iter; |
2919 | int ret = 0; | 3068 | int ret = 0; |
2920 | 3069 | ||
3070 | if (trace_array_get(tr) < 0) | ||
3071 | return -ENODEV; | ||
3072 | |||
2921 | /* If this file was open for write, then erase contents */ | 3073 | /* If this file was open for write, then erase contents */ |
2922 | if ((file->f_mode & FMODE_WRITE) && | 3074 | if ((file->f_mode & FMODE_WRITE) && |
2923 | (file->f_flags & O_TRUNC)) { | 3075 | (file->f_flags & O_TRUNC)) { |
2924 | struct trace_cpu *tc = inode->i_private; | ||
2925 | struct trace_array *tr = tc->tr; | ||
2926 | |||
2927 | if (tc->cpu == RING_BUFFER_ALL_CPUS) | 3076 | if (tc->cpu == RING_BUFFER_ALL_CPUS) |
2928 | tracing_reset_online_cpus(&tr->trace_buffer); | 3077 | tracing_reset_online_cpus(&tr->trace_buffer); |
2929 | else | 3078 | else |
@@ -2931,12 +3080,16 @@ static int tracing_open(struct inode *inode, struct file *file) | |||
2931 | } | 3080 | } |
2932 | 3081 | ||
2933 | if (file->f_mode & FMODE_READ) { | 3082 | if (file->f_mode & FMODE_READ) { |
2934 | iter = __tracing_open(inode, file, false); | 3083 | iter = __tracing_open(tr, tc, inode, file, false); |
2935 | if (IS_ERR(iter)) | 3084 | if (IS_ERR(iter)) |
2936 | ret = PTR_ERR(iter); | 3085 | ret = PTR_ERR(iter); |
2937 | else if (trace_flags & TRACE_ITER_LATENCY_FMT) | 3086 | else if (trace_flags & TRACE_ITER_LATENCY_FMT) |
2938 | iter->iter_flags |= TRACE_FILE_LAT_FMT; | 3087 | iter->iter_flags |= TRACE_FILE_LAT_FMT; |
2939 | } | 3088 | } |
3089 | |||
3090 | if (ret < 0) | ||
3091 | trace_array_put(tr); | ||
3092 | |||
2940 | return ret; | 3093 | return ret; |
2941 | } | 3094 | } |
2942 | 3095 | ||
@@ -3293,9 +3446,14 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf, | |||
3293 | 3446 | ||
3294 | static int tracing_trace_options_open(struct inode *inode, struct file *file) | 3447 | static int tracing_trace_options_open(struct inode *inode, struct file *file) |
3295 | { | 3448 | { |
3449 | struct trace_array *tr = inode->i_private; | ||
3450 | |||
3296 | if (tracing_disabled) | 3451 | if (tracing_disabled) |
3297 | return -ENODEV; | 3452 | return -ENODEV; |
3298 | 3453 | ||
3454 | if (trace_array_get(tr) < 0) | ||
3455 | return -ENODEV; | ||
3456 | |||
3299 | return single_open(file, tracing_trace_options_show, inode->i_private); | 3457 | return single_open(file, tracing_trace_options_show, inode->i_private); |
3300 | } | 3458 | } |
3301 | 3459 | ||
@@ -3303,7 +3461,7 @@ static const struct file_operations tracing_iter_fops = { | |||
3303 | .open = tracing_trace_options_open, | 3461 | .open = tracing_trace_options_open, |
3304 | .read = seq_read, | 3462 | .read = seq_read, |
3305 | .llseek = seq_lseek, | 3463 | .llseek = seq_lseek, |
3306 | .release = single_release, | 3464 | .release = tracing_single_release_tr, |
3307 | .write = tracing_trace_options_write, | 3465 | .write = tracing_trace_options_write, |
3308 | }; | 3466 | }; |
3309 | 3467 | ||
@@ -3791,6 +3949,9 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp) | |||
3791 | if (tracing_disabled) | 3949 | if (tracing_disabled) |
3792 | return -ENODEV; | 3950 | return -ENODEV; |
3793 | 3951 | ||
3952 | if (trace_array_get(tr) < 0) | ||
3953 | return -ENODEV; | ||
3954 | |||
3794 | mutex_lock(&trace_types_lock); | 3955 | mutex_lock(&trace_types_lock); |
3795 | 3956 | ||
3796 | /* create a buffer to store the information to pass to userspace */ | 3957 | /* create a buffer to store the information to pass to userspace */ |
@@ -3843,6 +4004,7 @@ out: | |||
3843 | fail: | 4004 | fail: |
3844 | kfree(iter->trace); | 4005 | kfree(iter->trace); |
3845 | kfree(iter); | 4006 | kfree(iter); |
4007 | __trace_array_put(tr); | ||
3846 | mutex_unlock(&trace_types_lock); | 4008 | mutex_unlock(&trace_types_lock); |
3847 | return ret; | 4009 | return ret; |
3848 | } | 4010 | } |
@@ -3850,6 +4012,8 @@ fail: | |||
3850 | static int tracing_release_pipe(struct inode *inode, struct file *file) | 4012 | static int tracing_release_pipe(struct inode *inode, struct file *file) |
3851 | { | 4013 | { |
3852 | struct trace_iterator *iter = file->private_data; | 4014 | struct trace_iterator *iter = file->private_data; |
4015 | struct trace_cpu *tc = inode->i_private; | ||
4016 | struct trace_array *tr = tc->tr; | ||
3853 | 4017 | ||
3854 | mutex_lock(&trace_types_lock); | 4018 | mutex_lock(&trace_types_lock); |
3855 | 4019 | ||
@@ -3863,6 +4027,8 @@ static int tracing_release_pipe(struct inode *inode, struct file *file) | |||
3863 | kfree(iter->trace); | 4027 | kfree(iter->trace); |
3864 | kfree(iter); | 4028 | kfree(iter); |
3865 | 4029 | ||
4030 | trace_array_put(tr); | ||
4031 | |||
3866 | return 0; | 4032 | return 0; |
3867 | } | 4033 | } |
3868 | 4034 | ||
@@ -3939,7 +4105,7 @@ static int tracing_wait_pipe(struct file *filp) | |||
3939 | * | 4105 | * |
3940 | * iter->pos will be 0 if we haven't read anything. | 4106 | * iter->pos will be 0 if we haven't read anything. |
3941 | */ | 4107 | */ |
3942 | if (!tracing_is_enabled() && iter->pos) | 4108 | if (!tracing_is_on() && iter->pos) |
3943 | break; | 4109 | break; |
3944 | } | 4110 | } |
3945 | 4111 | ||
@@ -4320,6 +4486,8 @@ tracing_free_buffer_release(struct inode *inode, struct file *filp) | |||
4320 | /* resize the ring buffer to 0 */ | 4486 | /* resize the ring buffer to 0 */ |
4321 | tracing_resize_ring_buffer(tr, 0, RING_BUFFER_ALL_CPUS); | 4487 | tracing_resize_ring_buffer(tr, 0, RING_BUFFER_ALL_CPUS); |
4322 | 4488 | ||
4489 | trace_array_put(tr); | ||
4490 | |||
4323 | return 0; | 4491 | return 0; |
4324 | } | 4492 | } |
4325 | 4493 | ||
@@ -4328,6 +4496,7 @@ tracing_mark_write(struct file *filp, const char __user *ubuf, | |||
4328 | size_t cnt, loff_t *fpos) | 4496 | size_t cnt, loff_t *fpos) |
4329 | { | 4497 | { |
4330 | unsigned long addr = (unsigned long)ubuf; | 4498 | unsigned long addr = (unsigned long)ubuf; |
4499 | struct trace_array *tr = filp->private_data; | ||
4331 | struct ring_buffer_event *event; | 4500 | struct ring_buffer_event *event; |
4332 | struct ring_buffer *buffer; | 4501 | struct ring_buffer *buffer; |
4333 | struct print_entry *entry; | 4502 | struct print_entry *entry; |
@@ -4387,7 +4556,7 @@ tracing_mark_write(struct file *filp, const char __user *ubuf, | |||
4387 | 4556 | ||
4388 | local_save_flags(irq_flags); | 4557 | local_save_flags(irq_flags); |
4389 | size = sizeof(*entry) + cnt + 2; /* possible \n added */ | 4558 | size = sizeof(*entry) + cnt + 2; /* possible \n added */ |
4390 | buffer = global_trace.trace_buffer.buffer; | 4559 | buffer = tr->trace_buffer.buffer; |
4391 | event = trace_buffer_lock_reserve(buffer, TRACE_PRINT, size, | 4560 | event = trace_buffer_lock_reserve(buffer, TRACE_PRINT, size, |
4392 | irq_flags, preempt_count()); | 4561 | irq_flags, preempt_count()); |
4393 | if (!event) { | 4562 | if (!event) { |
@@ -4495,10 +4664,20 @@ static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf, | |||
4495 | 4664 | ||
4496 | static int tracing_clock_open(struct inode *inode, struct file *file) | 4665 | static int tracing_clock_open(struct inode *inode, struct file *file) |
4497 | { | 4666 | { |
4667 | struct trace_array *tr = inode->i_private; | ||
4668 | int ret; | ||
4669 | |||
4498 | if (tracing_disabled) | 4670 | if (tracing_disabled) |
4499 | return -ENODEV; | 4671 | return -ENODEV; |
4500 | 4672 | ||
4501 | return single_open(file, tracing_clock_show, inode->i_private); | 4673 | if (trace_array_get(tr)) |
4674 | return -ENODEV; | ||
4675 | |||
4676 | ret = single_open(file, tracing_clock_show, inode->i_private); | ||
4677 | if (ret < 0) | ||
4678 | trace_array_put(tr); | ||
4679 | |||
4680 | return ret; | ||
4502 | } | 4681 | } |
4503 | 4682 | ||
4504 | struct ftrace_buffer_info { | 4683 | struct ftrace_buffer_info { |
@@ -4511,12 +4690,16 @@ struct ftrace_buffer_info { | |||
4511 | static int tracing_snapshot_open(struct inode *inode, struct file *file) | 4690 | static int tracing_snapshot_open(struct inode *inode, struct file *file) |
4512 | { | 4691 | { |
4513 | struct trace_cpu *tc = inode->i_private; | 4692 | struct trace_cpu *tc = inode->i_private; |
4693 | struct trace_array *tr = tc->tr; | ||
4514 | struct trace_iterator *iter; | 4694 | struct trace_iterator *iter; |
4515 | struct seq_file *m; | 4695 | struct seq_file *m; |
4516 | int ret = 0; | 4696 | int ret = 0; |
4517 | 4697 | ||
4698 | if (trace_array_get(tr) < 0) | ||
4699 | return -ENODEV; | ||
4700 | |||
4518 | if (file->f_mode & FMODE_READ) { | 4701 | if (file->f_mode & FMODE_READ) { |
4519 | iter = __tracing_open(inode, file, true); | 4702 | iter = __tracing_open(tr, tc, inode, file, true); |
4520 | if (IS_ERR(iter)) | 4703 | if (IS_ERR(iter)) |
4521 | ret = PTR_ERR(iter); | 4704 | ret = PTR_ERR(iter); |
4522 | } else { | 4705 | } else { |
@@ -4529,13 +4712,16 @@ static int tracing_snapshot_open(struct inode *inode, struct file *file) | |||
4529 | kfree(m); | 4712 | kfree(m); |
4530 | return -ENOMEM; | 4713 | return -ENOMEM; |
4531 | } | 4714 | } |
4532 | iter->tr = tc->tr; | 4715 | iter->tr = tr; |
4533 | iter->trace_buffer = &tc->tr->max_buffer; | 4716 | iter->trace_buffer = &tc->tr->max_buffer; |
4534 | iter->cpu_file = tc->cpu; | 4717 | iter->cpu_file = tc->cpu; |
4535 | m->private = iter; | 4718 | m->private = iter; |
4536 | file->private_data = m; | 4719 | file->private_data = m; |
4537 | } | 4720 | } |
4538 | 4721 | ||
4722 | if (ret < 0) | ||
4723 | trace_array_put(tr); | ||
4724 | |||
4539 | return ret; | 4725 | return ret; |
4540 | } | 4726 | } |
4541 | 4727 | ||
@@ -4616,9 +4802,12 @@ out: | |||
4616 | static int tracing_snapshot_release(struct inode *inode, struct file *file) | 4802 | static int tracing_snapshot_release(struct inode *inode, struct file *file) |
4617 | { | 4803 | { |
4618 | struct seq_file *m = file->private_data; | 4804 | struct seq_file *m = file->private_data; |
4805 | int ret; | ||
4806 | |||
4807 | ret = tracing_release(inode, file); | ||
4619 | 4808 | ||
4620 | if (file->f_mode & FMODE_READ) | 4809 | if (file->f_mode & FMODE_READ) |
4621 | return tracing_release(inode, file); | 4810 | return ret; |
4622 | 4811 | ||
4623 | /* If write only, the seq_file is just a stub */ | 4812 | /* If write only, the seq_file is just a stub */ |
4624 | if (m) | 4813 | if (m) |
@@ -4684,34 +4873,38 @@ static const struct file_operations tracing_pipe_fops = { | |||
4684 | }; | 4873 | }; |
4685 | 4874 | ||
4686 | static const struct file_operations tracing_entries_fops = { | 4875 | static const struct file_operations tracing_entries_fops = { |
4687 | .open = tracing_open_generic, | 4876 | .open = tracing_open_generic_tc, |
4688 | .read = tracing_entries_read, | 4877 | .read = tracing_entries_read, |
4689 | .write = tracing_entries_write, | 4878 | .write = tracing_entries_write, |
4690 | .llseek = generic_file_llseek, | 4879 | .llseek = generic_file_llseek, |
4880 | .release = tracing_release_generic_tc, | ||
4691 | }; | 4881 | }; |
4692 | 4882 | ||
4693 | static const struct file_operations tracing_total_entries_fops = { | 4883 | static const struct file_operations tracing_total_entries_fops = { |
4694 | .open = tracing_open_generic, | 4884 | .open = tracing_open_generic_tr, |
4695 | .read = tracing_total_entries_read, | 4885 | .read = tracing_total_entries_read, |
4696 | .llseek = generic_file_llseek, | 4886 | .llseek = generic_file_llseek, |
4887 | .release = tracing_release_generic_tr, | ||
4697 | }; | 4888 | }; |
4698 | 4889 | ||
4699 | static const struct file_operations tracing_free_buffer_fops = { | 4890 | static const struct file_operations tracing_free_buffer_fops = { |
4891 | .open = tracing_open_generic_tr, | ||
4700 | .write = tracing_free_buffer_write, | 4892 | .write = tracing_free_buffer_write, |
4701 | .release = tracing_free_buffer_release, | 4893 | .release = tracing_free_buffer_release, |
4702 | }; | 4894 | }; |
4703 | 4895 | ||
4704 | static const struct file_operations tracing_mark_fops = { | 4896 | static const struct file_operations tracing_mark_fops = { |
4705 | .open = tracing_open_generic, | 4897 | .open = tracing_open_generic_tr, |
4706 | .write = tracing_mark_write, | 4898 | .write = tracing_mark_write, |
4707 | .llseek = generic_file_llseek, | 4899 | .llseek = generic_file_llseek, |
4900 | .release = tracing_release_generic_tr, | ||
4708 | }; | 4901 | }; |
4709 | 4902 | ||
4710 | static const struct file_operations trace_clock_fops = { | 4903 | static const struct file_operations trace_clock_fops = { |
4711 | .open = tracing_clock_open, | 4904 | .open = tracing_clock_open, |
4712 | .read = seq_read, | 4905 | .read = seq_read, |
4713 | .llseek = seq_lseek, | 4906 | .llseek = seq_lseek, |
4714 | .release = single_release, | 4907 | .release = tracing_single_release_tr, |
4715 | .write = tracing_clock_write, | 4908 | .write = tracing_clock_write, |
4716 | }; | 4909 | }; |
4717 | 4910 | ||
@@ -4739,13 +4932,19 @@ static int tracing_buffers_open(struct inode *inode, struct file *filp) | |||
4739 | struct trace_cpu *tc = inode->i_private; | 4932 | struct trace_cpu *tc = inode->i_private; |
4740 | struct trace_array *tr = tc->tr; | 4933 | struct trace_array *tr = tc->tr; |
4741 | struct ftrace_buffer_info *info; | 4934 | struct ftrace_buffer_info *info; |
4935 | int ret; | ||
4742 | 4936 | ||
4743 | if (tracing_disabled) | 4937 | if (tracing_disabled) |
4744 | return -ENODEV; | 4938 | return -ENODEV; |
4745 | 4939 | ||
4940 | if (trace_array_get(tr) < 0) | ||
4941 | return -ENODEV; | ||
4942 | |||
4746 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 4943 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
4747 | if (!info) | 4944 | if (!info) { |
4945 | trace_array_put(tr); | ||
4748 | return -ENOMEM; | 4946 | return -ENOMEM; |
4947 | } | ||
4749 | 4948 | ||
4750 | mutex_lock(&trace_types_lock); | 4949 | mutex_lock(&trace_types_lock); |
4751 | 4950 | ||
@@ -4763,7 +4962,11 @@ static int tracing_buffers_open(struct inode *inode, struct file *filp) | |||
4763 | 4962 | ||
4764 | mutex_unlock(&trace_types_lock); | 4963 | mutex_unlock(&trace_types_lock); |
4765 | 4964 | ||
4766 | return nonseekable_open(inode, filp); | 4965 | ret = nonseekable_open(inode, filp); |
4966 | if (ret < 0) | ||
4967 | trace_array_put(tr); | ||
4968 | |||
4969 | return ret; | ||
4767 | } | 4970 | } |
4768 | 4971 | ||
4769 | static unsigned int | 4972 | static unsigned int |
@@ -4863,8 +5066,7 @@ static int tracing_buffers_release(struct inode *inode, struct file *file) | |||
4863 | 5066 | ||
4864 | mutex_lock(&trace_types_lock); | 5067 | mutex_lock(&trace_types_lock); |
4865 | 5068 | ||
4866 | WARN_ON(!iter->tr->ref); | 5069 | __trace_array_put(iter->tr); |
4867 | iter->tr->ref--; | ||
4868 | 5070 | ||
4869 | if (info->spare) | 5071 | if (info->spare) |
4870 | ring_buffer_free_read_page(iter->trace_buffer->buffer, info->spare); | 5072 | ring_buffer_free_read_page(iter->trace_buffer->buffer, info->spare); |
@@ -5612,15 +5814,10 @@ rb_simple_read(struct file *filp, char __user *ubuf, | |||
5612 | size_t cnt, loff_t *ppos) | 5814 | size_t cnt, loff_t *ppos) |
5613 | { | 5815 | { |
5614 | struct trace_array *tr = filp->private_data; | 5816 | struct trace_array *tr = filp->private_data; |
5615 | struct ring_buffer *buffer = tr->trace_buffer.buffer; | ||
5616 | char buf[64]; | 5817 | char buf[64]; |
5617 | int r; | 5818 | int r; |
5618 | 5819 | ||
5619 | if (buffer) | 5820 | r = tracer_tracing_is_on(tr); |
5620 | r = ring_buffer_record_is_on(buffer); | ||
5621 | else | ||
5622 | r = 0; | ||
5623 | |||
5624 | r = sprintf(buf, "%d\n", r); | 5821 | r = sprintf(buf, "%d\n", r); |
5625 | 5822 | ||
5626 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); | 5823 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); |
@@ -5642,11 +5839,11 @@ rb_simple_write(struct file *filp, const char __user *ubuf, | |||
5642 | if (buffer) { | 5839 | if (buffer) { |
5643 | mutex_lock(&trace_types_lock); | 5840 | mutex_lock(&trace_types_lock); |
5644 | if (val) { | 5841 | if (val) { |
5645 | ring_buffer_record_on(buffer); | 5842 | tracer_tracing_on(tr); |
5646 | if (tr->current_trace->start) | 5843 | if (tr->current_trace->start) |
5647 | tr->current_trace->start(tr); | 5844 | tr->current_trace->start(tr); |
5648 | } else { | 5845 | } else { |
5649 | ring_buffer_record_off(buffer); | 5846 | tracer_tracing_off(tr); |
5650 | if (tr->current_trace->stop) | 5847 | if (tr->current_trace->stop) |
5651 | tr->current_trace->stop(tr); | 5848 | tr->current_trace->stop(tr); |
5652 | } | 5849 | } |
@@ -5659,9 +5856,10 @@ rb_simple_write(struct file *filp, const char __user *ubuf, | |||
5659 | } | 5856 | } |
5660 | 5857 | ||
5661 | static const struct file_operations rb_simple_fops = { | 5858 | static const struct file_operations rb_simple_fops = { |
5662 | .open = tracing_open_generic, | 5859 | .open = tracing_open_generic_tr, |
5663 | .read = rb_simple_read, | 5860 | .read = rb_simple_read, |
5664 | .write = rb_simple_write, | 5861 | .write = rb_simple_write, |
5862 | .release = tracing_release_generic_tr, | ||
5665 | .llseek = default_llseek, | 5863 | .llseek = default_llseek, |
5666 | }; | 5864 | }; |
5667 | 5865 | ||
@@ -5933,7 +6131,7 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer) | |||
5933 | trace_create_file("buffer_total_size_kb", 0444, d_tracer, | 6131 | trace_create_file("buffer_total_size_kb", 0444, d_tracer, |
5934 | tr, &tracing_total_entries_fops); | 6132 | tr, &tracing_total_entries_fops); |
5935 | 6133 | ||
5936 | trace_create_file("free_buffer", 0644, d_tracer, | 6134 | trace_create_file("free_buffer", 0200, d_tracer, |
5937 | tr, &tracing_free_buffer_fops); | 6135 | tr, &tracing_free_buffer_fops); |
5938 | 6136 | ||
5939 | trace_create_file("trace_marker", 0220, d_tracer, | 6137 | trace_create_file("trace_marker", 0220, d_tracer, |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 20572ed88c5c..4a4f6e1828b6 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -224,6 +224,11 @@ enum { | |||
224 | 224 | ||
225 | extern struct list_head ftrace_trace_arrays; | 225 | extern struct list_head ftrace_trace_arrays; |
226 | 226 | ||
227 | extern struct mutex trace_types_lock; | ||
228 | |||
229 | extern int trace_array_get(struct trace_array *tr); | ||
230 | extern void trace_array_put(struct trace_array *tr); | ||
231 | |||
227 | /* | 232 | /* |
228 | * The global tracer (top) should be the first trace array added, | 233 | * The global tracer (top) should be the first trace array added, |
229 | * but we check the flag anyway. | 234 | * but we check the flag anyway. |
@@ -554,11 +559,6 @@ void tracing_iter_reset(struct trace_iterator *iter, int cpu); | |||
554 | 559 | ||
555 | void poll_wait_pipe(struct trace_iterator *iter); | 560 | void poll_wait_pipe(struct trace_iterator *iter); |
556 | 561 | ||
557 | void ftrace(struct trace_array *tr, | ||
558 | struct trace_array_cpu *data, | ||
559 | unsigned long ip, | ||
560 | unsigned long parent_ip, | ||
561 | unsigned long flags, int pc); | ||
562 | void tracing_sched_switch_trace(struct trace_array *tr, | 562 | void tracing_sched_switch_trace(struct trace_array *tr, |
563 | struct task_struct *prev, | 563 | struct task_struct *prev, |
564 | struct task_struct *next, | 564 | struct task_struct *next, |
@@ -774,6 +774,7 @@ print_graph_function_flags(struct trace_iterator *iter, u32 flags) | |||
774 | extern struct list_head ftrace_pids; | 774 | extern struct list_head ftrace_pids; |
775 | 775 | ||
776 | #ifdef CONFIG_FUNCTION_TRACER | 776 | #ifdef CONFIG_FUNCTION_TRACER |
777 | extern bool ftrace_filter_param __initdata; | ||
777 | static inline int ftrace_trace_task(struct task_struct *task) | 778 | static inline int ftrace_trace_task(struct task_struct *task) |
778 | { | 779 | { |
779 | if (list_empty(&ftrace_pids)) | 780 | if (list_empty(&ftrace_pids)) |
@@ -899,12 +900,6 @@ static inline void trace_branch_disable(void) | |||
899 | /* set ring buffers to default size if not already done so */ | 900 | /* set ring buffers to default size if not already done so */ |
900 | int tracing_update_buffers(void); | 901 | int tracing_update_buffers(void); |
901 | 902 | ||
902 | /* trace event type bit fields, not numeric */ | ||
903 | enum { | ||
904 | TRACE_EVENT_TYPE_PRINTF = 1, | ||
905 | TRACE_EVENT_TYPE_RAW = 2, | ||
906 | }; | ||
907 | |||
908 | struct ftrace_event_field { | 903 | struct ftrace_event_field { |
909 | struct list_head link; | 904 | struct list_head link; |
910 | const char *name; | 905 | const char *name; |
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 27963e2bf4bf..7d854290bf81 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -41,6 +41,23 @@ static LIST_HEAD(ftrace_common_fields); | |||
41 | static struct kmem_cache *field_cachep; | 41 | static struct kmem_cache *field_cachep; |
42 | static struct kmem_cache *file_cachep; | 42 | static struct kmem_cache *file_cachep; |
43 | 43 | ||
44 | #define SYSTEM_FL_FREE_NAME (1 << 31) | ||
45 | |||
46 | static inline int system_refcount(struct event_subsystem *system) | ||
47 | { | ||
48 | return system->ref_count & ~SYSTEM_FL_FREE_NAME; | ||
49 | } | ||
50 | |||
51 | static int system_refcount_inc(struct event_subsystem *system) | ||
52 | { | ||
53 | return (system->ref_count++) & ~SYSTEM_FL_FREE_NAME; | ||
54 | } | ||
55 | |||
56 | static int system_refcount_dec(struct event_subsystem *system) | ||
57 | { | ||
58 | return (--system->ref_count) & ~SYSTEM_FL_FREE_NAME; | ||
59 | } | ||
60 | |||
44 | /* Double loops, do not use break, only goto's work */ | 61 | /* Double loops, do not use break, only goto's work */ |
45 | #define do_for_each_event_file(tr, file) \ | 62 | #define do_for_each_event_file(tr, file) \ |
46 | list_for_each_entry(tr, &ftrace_trace_arrays, list) { \ | 63 | list_for_each_entry(tr, &ftrace_trace_arrays, list) { \ |
@@ -97,7 +114,7 @@ static int __trace_define_field(struct list_head *head, const char *type, | |||
97 | 114 | ||
98 | field = kmem_cache_alloc(field_cachep, GFP_TRACE); | 115 | field = kmem_cache_alloc(field_cachep, GFP_TRACE); |
99 | if (!field) | 116 | if (!field) |
100 | goto err; | 117 | return -ENOMEM; |
101 | 118 | ||
102 | field->name = name; | 119 | field->name = name; |
103 | field->type = type; | 120 | field->type = type; |
@@ -114,11 +131,6 @@ static int __trace_define_field(struct list_head *head, const char *type, | |||
114 | list_add(&field->link, head); | 131 | list_add(&field->link, head); |
115 | 132 | ||
116 | return 0; | 133 | return 0; |
117 | |||
118 | err: | ||
119 | kmem_cache_free(field_cachep, field); | ||
120 | |||
121 | return -ENOMEM; | ||
122 | } | 134 | } |
123 | 135 | ||
124 | int trace_define_field(struct ftrace_event_call *call, const char *type, | 136 | int trace_define_field(struct ftrace_event_call *call, const char *type, |
@@ -279,9 +291,11 @@ static int __ftrace_event_enable_disable(struct ftrace_event_file *file, | |||
279 | } | 291 | } |
280 | call->class->reg(call, TRACE_REG_UNREGISTER, file); | 292 | call->class->reg(call, TRACE_REG_UNREGISTER, file); |
281 | } | 293 | } |
282 | /* If in SOFT_MODE, just set the SOFT_DISABLE_BIT */ | 294 | /* If in SOFT_MODE, just set the SOFT_DISABLE_BIT, else clear it */ |
283 | if (file->flags & FTRACE_EVENT_FL_SOFT_MODE) | 295 | if (file->flags & FTRACE_EVENT_FL_SOFT_MODE) |
284 | set_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &file->flags); | 296 | set_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &file->flags); |
297 | else | ||
298 | clear_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &file->flags); | ||
285 | break; | 299 | break; |
286 | case 1: | 300 | case 1: |
287 | /* | 301 | /* |
@@ -349,8 +363,8 @@ static void __put_system(struct event_subsystem *system) | |||
349 | { | 363 | { |
350 | struct event_filter *filter = system->filter; | 364 | struct event_filter *filter = system->filter; |
351 | 365 | ||
352 | WARN_ON_ONCE(system->ref_count == 0); | 366 | WARN_ON_ONCE(system_refcount(system) == 0); |
353 | if (--system->ref_count) | 367 | if (system_refcount_dec(system)) |
354 | return; | 368 | return; |
355 | 369 | ||
356 | list_del(&system->list); | 370 | list_del(&system->list); |
@@ -359,13 +373,15 @@ static void __put_system(struct event_subsystem *system) | |||
359 | kfree(filter->filter_string); | 373 | kfree(filter->filter_string); |
360 | kfree(filter); | 374 | kfree(filter); |
361 | } | 375 | } |
376 | if (system->ref_count & SYSTEM_FL_FREE_NAME) | ||
377 | kfree(system->name); | ||
362 | kfree(system); | 378 | kfree(system); |
363 | } | 379 | } |
364 | 380 | ||
365 | static void __get_system(struct event_subsystem *system) | 381 | static void __get_system(struct event_subsystem *system) |
366 | { | 382 | { |
367 | WARN_ON_ONCE(system->ref_count == 0); | 383 | WARN_ON_ONCE(system_refcount(system) == 0); |
368 | system->ref_count++; | 384 | system_refcount_inc(system); |
369 | } | 385 | } |
370 | 386 | ||
371 | static void __get_system_dir(struct ftrace_subsystem_dir *dir) | 387 | static void __get_system_dir(struct ftrace_subsystem_dir *dir) |
@@ -379,7 +395,7 @@ static void __put_system_dir(struct ftrace_subsystem_dir *dir) | |||
379 | { | 395 | { |
380 | WARN_ON_ONCE(dir->ref_count == 0); | 396 | WARN_ON_ONCE(dir->ref_count == 0); |
381 | /* If the subsystem is about to be freed, the dir must be too */ | 397 | /* If the subsystem is about to be freed, the dir must be too */ |
382 | WARN_ON_ONCE(dir->subsystem->ref_count == 1 && dir->ref_count != 1); | 398 | WARN_ON_ONCE(system_refcount(dir->subsystem) == 1 && dir->ref_count != 1); |
383 | 399 | ||
384 | __put_system(dir->subsystem); | 400 | __put_system(dir->subsystem); |
385 | if (!--dir->ref_count) | 401 | if (!--dir->ref_count) |
@@ -394,16 +410,45 @@ static void put_system(struct ftrace_subsystem_dir *dir) | |||
394 | } | 410 | } |
395 | 411 | ||
396 | /* | 412 | /* |
413 | * Open and update trace_array ref count. | ||
414 | * Must have the current trace_array passed to it. | ||
415 | */ | ||
416 | static int tracing_open_generic_file(struct inode *inode, struct file *filp) | ||
417 | { | ||
418 | struct ftrace_event_file *file = inode->i_private; | ||
419 | struct trace_array *tr = file->tr; | ||
420 | int ret; | ||
421 | |||
422 | if (trace_array_get(tr) < 0) | ||
423 | return -ENODEV; | ||
424 | |||
425 | ret = tracing_open_generic(inode, filp); | ||
426 | if (ret < 0) | ||
427 | trace_array_put(tr); | ||
428 | return ret; | ||
429 | } | ||
430 | |||
431 | static int tracing_release_generic_file(struct inode *inode, struct file *filp) | ||
432 | { | ||
433 | struct ftrace_event_file *file = inode->i_private; | ||
434 | struct trace_array *tr = file->tr; | ||
435 | |||
436 | trace_array_put(tr); | ||
437 | |||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | /* | ||
397 | * __ftrace_set_clr_event(NULL, NULL, NULL, set) will set/unset all events. | 442 | * __ftrace_set_clr_event(NULL, NULL, NULL, set) will set/unset all events. |
398 | */ | 443 | */ |
399 | static int __ftrace_set_clr_event(struct trace_array *tr, const char *match, | 444 | static int |
400 | const char *sub, const char *event, int set) | 445 | __ftrace_set_clr_event_nolock(struct trace_array *tr, const char *match, |
446 | const char *sub, const char *event, int set) | ||
401 | { | 447 | { |
402 | struct ftrace_event_file *file; | 448 | struct ftrace_event_file *file; |
403 | struct ftrace_event_call *call; | 449 | struct ftrace_event_call *call; |
404 | int ret = -EINVAL; | 450 | int ret = -EINVAL; |
405 | 451 | ||
406 | mutex_lock(&event_mutex); | ||
407 | list_for_each_entry(file, &tr->events, list) { | 452 | list_for_each_entry(file, &tr->events, list) { |
408 | 453 | ||
409 | call = file->event_call; | 454 | call = file->event_call; |
@@ -429,6 +474,17 @@ static int __ftrace_set_clr_event(struct trace_array *tr, const char *match, | |||
429 | 474 | ||
430 | ret = 0; | 475 | ret = 0; |
431 | } | 476 | } |
477 | |||
478 | return ret; | ||
479 | } | ||
480 | |||
481 | static int __ftrace_set_clr_event(struct trace_array *tr, const char *match, | ||
482 | const char *sub, const char *event, int set) | ||
483 | { | ||
484 | int ret; | ||
485 | |||
486 | mutex_lock(&event_mutex); | ||
487 | ret = __ftrace_set_clr_event_nolock(tr, match, sub, event, set); | ||
432 | mutex_unlock(&event_mutex); | 488 | mutex_unlock(&event_mutex); |
433 | 489 | ||
434 | return ret; | 490 | return ret; |
@@ -624,17 +680,17 @@ event_enable_read(struct file *filp, char __user *ubuf, size_t cnt, | |||
624 | loff_t *ppos) | 680 | loff_t *ppos) |
625 | { | 681 | { |
626 | struct ftrace_event_file *file = filp->private_data; | 682 | struct ftrace_event_file *file = filp->private_data; |
627 | char *buf; | 683 | char buf[4] = "0"; |
628 | 684 | ||
629 | if (file->flags & FTRACE_EVENT_FL_ENABLED) { | 685 | if (file->flags & FTRACE_EVENT_FL_ENABLED && |
630 | if (file->flags & FTRACE_EVENT_FL_SOFT_DISABLED) | 686 | !(file->flags & FTRACE_EVENT_FL_SOFT_DISABLED)) |
631 | buf = "0*\n"; | 687 | strcpy(buf, "1"); |
632 | else if (file->flags & FTRACE_EVENT_FL_SOFT_MODE) | 688 | |
633 | buf = "1*\n"; | 689 | if (file->flags & FTRACE_EVENT_FL_SOFT_DISABLED || |
634 | else | 690 | file->flags & FTRACE_EVENT_FL_SOFT_MODE) |
635 | buf = "1\n"; | 691 | strcat(buf, "*"); |
636 | } else | 692 | |
637 | buf = "0\n"; | 693 | strcat(buf, "\n"); |
638 | 694 | ||
639 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, strlen(buf)); | 695 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, strlen(buf)); |
640 | } | 696 | } |
@@ -992,6 +1048,7 @@ static int subsystem_open(struct inode *inode, struct file *filp) | |||
992 | int ret; | 1048 | int ret; |
993 | 1049 | ||
994 | /* Make sure the system still exists */ | 1050 | /* Make sure the system still exists */ |
1051 | mutex_lock(&trace_types_lock); | ||
995 | mutex_lock(&event_mutex); | 1052 | mutex_lock(&event_mutex); |
996 | list_for_each_entry(tr, &ftrace_trace_arrays, list) { | 1053 | list_for_each_entry(tr, &ftrace_trace_arrays, list) { |
997 | list_for_each_entry(dir, &tr->systems, list) { | 1054 | list_for_each_entry(dir, &tr->systems, list) { |
@@ -1007,6 +1064,7 @@ static int subsystem_open(struct inode *inode, struct file *filp) | |||
1007 | } | 1064 | } |
1008 | exit_loop: | 1065 | exit_loop: |
1009 | mutex_unlock(&event_mutex); | 1066 | mutex_unlock(&event_mutex); |
1067 | mutex_unlock(&trace_types_lock); | ||
1010 | 1068 | ||
1011 | if (!system) | 1069 | if (!system) |
1012 | return -ENODEV; | 1070 | return -ENODEV; |
@@ -1014,9 +1072,17 @@ static int subsystem_open(struct inode *inode, struct file *filp) | |||
1014 | /* Some versions of gcc think dir can be uninitialized here */ | 1072 | /* Some versions of gcc think dir can be uninitialized here */ |
1015 | WARN_ON(!dir); | 1073 | WARN_ON(!dir); |
1016 | 1074 | ||
1075 | /* Still need to increment the ref count of the system */ | ||
1076 | if (trace_array_get(tr) < 0) { | ||
1077 | put_system(dir); | ||
1078 | return -ENODEV; | ||
1079 | } | ||
1080 | |||
1017 | ret = tracing_open_generic(inode, filp); | 1081 | ret = tracing_open_generic(inode, filp); |
1018 | if (ret < 0) | 1082 | if (ret < 0) { |
1083 | trace_array_put(tr); | ||
1019 | put_system(dir); | 1084 | put_system(dir); |
1085 | } | ||
1020 | 1086 | ||
1021 | return ret; | 1087 | return ret; |
1022 | } | 1088 | } |
@@ -1027,16 +1093,23 @@ static int system_tr_open(struct inode *inode, struct file *filp) | |||
1027 | struct trace_array *tr = inode->i_private; | 1093 | struct trace_array *tr = inode->i_private; |
1028 | int ret; | 1094 | int ret; |
1029 | 1095 | ||
1096 | if (trace_array_get(tr) < 0) | ||
1097 | return -ENODEV; | ||
1098 | |||
1030 | /* Make a temporary dir that has no system but points to tr */ | 1099 | /* Make a temporary dir that has no system but points to tr */ |
1031 | dir = kzalloc(sizeof(*dir), GFP_KERNEL); | 1100 | dir = kzalloc(sizeof(*dir), GFP_KERNEL); |
1032 | if (!dir) | 1101 | if (!dir) { |
1102 | trace_array_put(tr); | ||
1033 | return -ENOMEM; | 1103 | return -ENOMEM; |
1104 | } | ||
1034 | 1105 | ||
1035 | dir->tr = tr; | 1106 | dir->tr = tr; |
1036 | 1107 | ||
1037 | ret = tracing_open_generic(inode, filp); | 1108 | ret = tracing_open_generic(inode, filp); |
1038 | if (ret < 0) | 1109 | if (ret < 0) { |
1110 | trace_array_put(tr); | ||
1039 | kfree(dir); | 1111 | kfree(dir); |
1112 | } | ||
1040 | 1113 | ||
1041 | filp->private_data = dir; | 1114 | filp->private_data = dir; |
1042 | 1115 | ||
@@ -1047,6 +1120,8 @@ static int subsystem_release(struct inode *inode, struct file *file) | |||
1047 | { | 1120 | { |
1048 | struct ftrace_subsystem_dir *dir = file->private_data; | 1121 | struct ftrace_subsystem_dir *dir = file->private_data; |
1049 | 1122 | ||
1123 | trace_array_put(dir->tr); | ||
1124 | |||
1050 | /* | 1125 | /* |
1051 | * If dir->subsystem is NULL, then this is a temporary | 1126 | * If dir->subsystem is NULL, then this is a temporary |
1052 | * descriptor that was made for a trace_array to enable | 1127 | * descriptor that was made for a trace_array to enable |
@@ -1174,9 +1249,10 @@ static const struct file_operations ftrace_set_event_fops = { | |||
1174 | }; | 1249 | }; |
1175 | 1250 | ||
1176 | static const struct file_operations ftrace_enable_fops = { | 1251 | static const struct file_operations ftrace_enable_fops = { |
1177 | .open = tracing_open_generic, | 1252 | .open = tracing_open_generic_file, |
1178 | .read = event_enable_read, | 1253 | .read = event_enable_read, |
1179 | .write = event_enable_write, | 1254 | .write = event_enable_write, |
1255 | .release = tracing_release_generic_file, | ||
1180 | .llseek = default_llseek, | 1256 | .llseek = default_llseek, |
1181 | }; | 1257 | }; |
1182 | 1258 | ||
@@ -1279,7 +1355,15 @@ create_new_subsystem(const char *name) | |||
1279 | return NULL; | 1355 | return NULL; |
1280 | 1356 | ||
1281 | system->ref_count = 1; | 1357 | system->ref_count = 1; |
1282 | system->name = name; | 1358 | |
1359 | /* Only allocate if dynamic (kprobes and modules) */ | ||
1360 | if (!core_kernel_data((unsigned long)name)) { | ||
1361 | system->ref_count |= SYSTEM_FL_FREE_NAME; | ||
1362 | system->name = kstrdup(name, GFP_KERNEL); | ||
1363 | if (!system->name) | ||
1364 | goto out_free; | ||
1365 | } else | ||
1366 | system->name = name; | ||
1283 | 1367 | ||
1284 | system->filter = NULL; | 1368 | system->filter = NULL; |
1285 | 1369 | ||
@@ -1292,6 +1376,8 @@ create_new_subsystem(const char *name) | |||
1292 | return system; | 1376 | return system; |
1293 | 1377 | ||
1294 | out_free: | 1378 | out_free: |
1379 | if (system->ref_count & SYSTEM_FL_FREE_NAME) | ||
1380 | kfree(system->name); | ||
1295 | kfree(system); | 1381 | kfree(system); |
1296 | return NULL; | 1382 | return NULL; |
1297 | } | 1383 | } |
@@ -1591,6 +1677,7 @@ static void __add_event_to_tracers(struct ftrace_event_call *call, | |||
1591 | int trace_add_event_call(struct ftrace_event_call *call) | 1677 | int trace_add_event_call(struct ftrace_event_call *call) |
1592 | { | 1678 | { |
1593 | int ret; | 1679 | int ret; |
1680 | mutex_lock(&trace_types_lock); | ||
1594 | mutex_lock(&event_mutex); | 1681 | mutex_lock(&event_mutex); |
1595 | 1682 | ||
1596 | ret = __register_event(call, NULL); | 1683 | ret = __register_event(call, NULL); |
@@ -1598,11 +1685,13 @@ int trace_add_event_call(struct ftrace_event_call *call) | |||
1598 | __add_event_to_tracers(call, NULL); | 1685 | __add_event_to_tracers(call, NULL); |
1599 | 1686 | ||
1600 | mutex_unlock(&event_mutex); | 1687 | mutex_unlock(&event_mutex); |
1688 | mutex_unlock(&trace_types_lock); | ||
1601 | return ret; | 1689 | return ret; |
1602 | } | 1690 | } |
1603 | 1691 | ||
1604 | /* | 1692 | /* |
1605 | * Must be called under locking both of event_mutex and trace_event_sem. | 1693 | * Must be called under locking of trace_types_lock, event_mutex and |
1694 | * trace_event_sem. | ||
1606 | */ | 1695 | */ |
1607 | static void __trace_remove_event_call(struct ftrace_event_call *call) | 1696 | static void __trace_remove_event_call(struct ftrace_event_call *call) |
1608 | { | 1697 | { |
@@ -1614,11 +1703,13 @@ static void __trace_remove_event_call(struct ftrace_event_call *call) | |||
1614 | /* Remove an event_call */ | 1703 | /* Remove an event_call */ |
1615 | void trace_remove_event_call(struct ftrace_event_call *call) | 1704 | void trace_remove_event_call(struct ftrace_event_call *call) |
1616 | { | 1705 | { |
1706 | mutex_lock(&trace_types_lock); | ||
1617 | mutex_lock(&event_mutex); | 1707 | mutex_lock(&event_mutex); |
1618 | down_write(&trace_event_sem); | 1708 | down_write(&trace_event_sem); |
1619 | __trace_remove_event_call(call); | 1709 | __trace_remove_event_call(call); |
1620 | up_write(&trace_event_sem); | 1710 | up_write(&trace_event_sem); |
1621 | mutex_unlock(&event_mutex); | 1711 | mutex_unlock(&event_mutex); |
1712 | mutex_unlock(&trace_types_lock); | ||
1622 | } | 1713 | } |
1623 | 1714 | ||
1624 | #define for_each_event(event, start, end) \ | 1715 | #define for_each_event(event, start, end) \ |
@@ -1762,6 +1853,7 @@ static int trace_module_notify(struct notifier_block *self, | |||
1762 | { | 1853 | { |
1763 | struct module *mod = data; | 1854 | struct module *mod = data; |
1764 | 1855 | ||
1856 | mutex_lock(&trace_types_lock); | ||
1765 | mutex_lock(&event_mutex); | 1857 | mutex_lock(&event_mutex); |
1766 | switch (val) { | 1858 | switch (val) { |
1767 | case MODULE_STATE_COMING: | 1859 | case MODULE_STATE_COMING: |
@@ -1772,6 +1864,7 @@ static int trace_module_notify(struct notifier_block *self, | |||
1772 | break; | 1864 | break; |
1773 | } | 1865 | } |
1774 | mutex_unlock(&event_mutex); | 1866 | mutex_unlock(&event_mutex); |
1867 | mutex_unlock(&trace_types_lock); | ||
1775 | 1868 | ||
1776 | return 0; | 1869 | return 0; |
1777 | } | 1870 | } |
@@ -2011,10 +2104,7 @@ event_enable_func(struct ftrace_hash *hash, | |||
2011 | int ret; | 2104 | int ret; |
2012 | 2105 | ||
2013 | /* hash funcs only work with set_ftrace_filter */ | 2106 | /* hash funcs only work with set_ftrace_filter */ |
2014 | if (!enabled) | 2107 | if (!enabled || !param) |
2015 | return -EINVAL; | ||
2016 | |||
2017 | if (!param) | ||
2018 | return -EINVAL; | 2108 | return -EINVAL; |
2019 | 2109 | ||
2020 | system = strsep(¶m, ":"); | 2110 | system = strsep(¶m, ":"); |
@@ -2329,11 +2419,11 @@ early_event_add_tracer(struct dentry *parent, struct trace_array *tr) | |||
2329 | 2419 | ||
2330 | int event_trace_del_tracer(struct trace_array *tr) | 2420 | int event_trace_del_tracer(struct trace_array *tr) |
2331 | { | 2421 | { |
2332 | /* Disable any running events */ | ||
2333 | __ftrace_set_clr_event(tr, NULL, NULL, NULL, 0); | ||
2334 | |||
2335 | mutex_lock(&event_mutex); | 2422 | mutex_lock(&event_mutex); |
2336 | 2423 | ||
2424 | /* Disable any running events */ | ||
2425 | __ftrace_set_clr_event_nolock(tr, NULL, NULL, NULL, 0); | ||
2426 | |||
2337 | down_write(&trace_event_sem); | 2427 | down_write(&trace_event_sem); |
2338 | __trace_remove_event_dirs(tr); | 2428 | __trace_remove_event_dirs(tr); |
2339 | debugfs_remove_recursive(tr->event_dir); | 2429 | debugfs_remove_recursive(tr->event_dir); |
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index e1b653f7e1ca..0d883dc057d6 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c | |||
@@ -44,6 +44,7 @@ enum filter_op_ids | |||
44 | OP_LE, | 44 | OP_LE, |
45 | OP_GT, | 45 | OP_GT, |
46 | OP_GE, | 46 | OP_GE, |
47 | OP_BAND, | ||
47 | OP_NONE, | 48 | OP_NONE, |
48 | OP_OPEN_PAREN, | 49 | OP_OPEN_PAREN, |
49 | }; | 50 | }; |
@@ -54,6 +55,7 @@ struct filter_op { | |||
54 | int precedence; | 55 | int precedence; |
55 | }; | 56 | }; |
56 | 57 | ||
58 | /* Order must be the same as enum filter_op_ids above */ | ||
57 | static struct filter_op filter_ops[] = { | 59 | static struct filter_op filter_ops[] = { |
58 | { OP_OR, "||", 1 }, | 60 | { OP_OR, "||", 1 }, |
59 | { OP_AND, "&&", 2 }, | 61 | { OP_AND, "&&", 2 }, |
@@ -64,6 +66,7 @@ static struct filter_op filter_ops[] = { | |||
64 | { OP_LE, "<=", 5 }, | 66 | { OP_LE, "<=", 5 }, |
65 | { OP_GT, ">", 5 }, | 67 | { OP_GT, ">", 5 }, |
66 | { OP_GE, ">=", 5 }, | 68 | { OP_GE, ">=", 5 }, |
69 | { OP_BAND, "&", 6 }, | ||
67 | { OP_NONE, "OP_NONE", 0 }, | 70 | { OP_NONE, "OP_NONE", 0 }, |
68 | { OP_OPEN_PAREN, "(", 0 }, | 71 | { OP_OPEN_PAREN, "(", 0 }, |
69 | }; | 72 | }; |
@@ -156,6 +159,9 @@ static int filter_pred_##type(struct filter_pred *pred, void *event) \ | |||
156 | case OP_GE: \ | 159 | case OP_GE: \ |
157 | match = (*addr >= val); \ | 160 | match = (*addr >= val); \ |
158 | break; \ | 161 | break; \ |
162 | case OP_BAND: \ | ||
163 | match = (*addr & val); \ | ||
164 | break; \ | ||
159 | default: \ | 165 | default: \ |
160 | break; \ | 166 | break; \ |
161 | } \ | 167 | } \ |
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c index c4d6d7191988..b863f93b30f3 100644 --- a/kernel/trace/trace_functions.c +++ b/kernel/trace/trace_functions.c | |||
@@ -290,6 +290,21 @@ ftrace_stacktrace_count(unsigned long ip, unsigned long parent_ip, void **data) | |||
290 | trace_dump_stack(STACK_SKIP); | 290 | trace_dump_stack(STACK_SKIP); |
291 | } | 291 | } |
292 | 292 | ||
293 | static void | ||
294 | ftrace_dump_probe(unsigned long ip, unsigned long parent_ip, void **data) | ||
295 | { | ||
296 | if (update_count(data)) | ||
297 | ftrace_dump(DUMP_ALL); | ||
298 | } | ||
299 | |||
300 | /* Only dump the current CPU buffer. */ | ||
301 | static void | ||
302 | ftrace_cpudump_probe(unsigned long ip, unsigned long parent_ip, void **data) | ||
303 | { | ||
304 | if (update_count(data)) | ||
305 | ftrace_dump(DUMP_ORIG); | ||
306 | } | ||
307 | |||
293 | static int | 308 | static int |
294 | ftrace_probe_print(const char *name, struct seq_file *m, | 309 | ftrace_probe_print(const char *name, struct seq_file *m, |
295 | unsigned long ip, void *data) | 310 | unsigned long ip, void *data) |
@@ -327,6 +342,20 @@ ftrace_stacktrace_print(struct seq_file *m, unsigned long ip, | |||
327 | return ftrace_probe_print("stacktrace", m, ip, data); | 342 | return ftrace_probe_print("stacktrace", m, ip, data); |
328 | } | 343 | } |
329 | 344 | ||
345 | static int | ||
346 | ftrace_dump_print(struct seq_file *m, unsigned long ip, | ||
347 | struct ftrace_probe_ops *ops, void *data) | ||
348 | { | ||
349 | return ftrace_probe_print("dump", m, ip, data); | ||
350 | } | ||
351 | |||
352 | static int | ||
353 | ftrace_cpudump_print(struct seq_file *m, unsigned long ip, | ||
354 | struct ftrace_probe_ops *ops, void *data) | ||
355 | { | ||
356 | return ftrace_probe_print("cpudump", m, ip, data); | ||
357 | } | ||
358 | |||
330 | static struct ftrace_probe_ops traceon_count_probe_ops = { | 359 | static struct ftrace_probe_ops traceon_count_probe_ops = { |
331 | .func = ftrace_traceon_count, | 360 | .func = ftrace_traceon_count, |
332 | .print = ftrace_traceon_print, | 361 | .print = ftrace_traceon_print, |
@@ -342,6 +371,16 @@ static struct ftrace_probe_ops stacktrace_count_probe_ops = { | |||
342 | .print = ftrace_stacktrace_print, | 371 | .print = ftrace_stacktrace_print, |
343 | }; | 372 | }; |
344 | 373 | ||
374 | static struct ftrace_probe_ops dump_probe_ops = { | ||
375 | .func = ftrace_dump_probe, | ||
376 | .print = ftrace_dump_print, | ||
377 | }; | ||
378 | |||
379 | static struct ftrace_probe_ops cpudump_probe_ops = { | ||
380 | .func = ftrace_cpudump_probe, | ||
381 | .print = ftrace_cpudump_print, | ||
382 | }; | ||
383 | |||
345 | static struct ftrace_probe_ops traceon_probe_ops = { | 384 | static struct ftrace_probe_ops traceon_probe_ops = { |
346 | .func = ftrace_traceon, | 385 | .func = ftrace_traceon, |
347 | .print = ftrace_traceon_print, | 386 | .print = ftrace_traceon_print, |
@@ -425,6 +464,32 @@ ftrace_stacktrace_callback(struct ftrace_hash *hash, | |||
425 | param, enable); | 464 | param, enable); |
426 | } | 465 | } |
427 | 466 | ||
467 | static int | ||
468 | ftrace_dump_callback(struct ftrace_hash *hash, | ||
469 | char *glob, char *cmd, char *param, int enable) | ||
470 | { | ||
471 | struct ftrace_probe_ops *ops; | ||
472 | |||
473 | ops = &dump_probe_ops; | ||
474 | |||
475 | /* Only dump once. */ | ||
476 | return ftrace_trace_probe_callback(ops, hash, glob, cmd, | ||
477 | "1", enable); | ||
478 | } | ||
479 | |||
480 | static int | ||
481 | ftrace_cpudump_callback(struct ftrace_hash *hash, | ||
482 | char *glob, char *cmd, char *param, int enable) | ||
483 | { | ||
484 | struct ftrace_probe_ops *ops; | ||
485 | |||
486 | ops = &cpudump_probe_ops; | ||
487 | |||
488 | /* Only dump once. */ | ||
489 | return ftrace_trace_probe_callback(ops, hash, glob, cmd, | ||
490 | "1", enable); | ||
491 | } | ||
492 | |||
428 | static struct ftrace_func_command ftrace_traceon_cmd = { | 493 | static struct ftrace_func_command ftrace_traceon_cmd = { |
429 | .name = "traceon", | 494 | .name = "traceon", |
430 | .func = ftrace_trace_onoff_callback, | 495 | .func = ftrace_trace_onoff_callback, |
@@ -440,6 +505,16 @@ static struct ftrace_func_command ftrace_stacktrace_cmd = { | |||
440 | .func = ftrace_stacktrace_callback, | 505 | .func = ftrace_stacktrace_callback, |
441 | }; | 506 | }; |
442 | 507 | ||
508 | static struct ftrace_func_command ftrace_dump_cmd = { | ||
509 | .name = "dump", | ||
510 | .func = ftrace_dump_callback, | ||
511 | }; | ||
512 | |||
513 | static struct ftrace_func_command ftrace_cpudump_cmd = { | ||
514 | .name = "cpudump", | ||
515 | .func = ftrace_cpudump_callback, | ||
516 | }; | ||
517 | |||
443 | static int __init init_func_cmd_traceon(void) | 518 | static int __init init_func_cmd_traceon(void) |
444 | { | 519 | { |
445 | int ret; | 520 | int ret; |
@@ -450,13 +525,31 @@ static int __init init_func_cmd_traceon(void) | |||
450 | 525 | ||
451 | ret = register_ftrace_command(&ftrace_traceon_cmd); | 526 | ret = register_ftrace_command(&ftrace_traceon_cmd); |
452 | if (ret) | 527 | if (ret) |
453 | unregister_ftrace_command(&ftrace_traceoff_cmd); | 528 | goto out_free_traceoff; |
454 | 529 | ||
455 | ret = register_ftrace_command(&ftrace_stacktrace_cmd); | 530 | ret = register_ftrace_command(&ftrace_stacktrace_cmd); |
456 | if (ret) { | 531 | if (ret) |
457 | unregister_ftrace_command(&ftrace_traceoff_cmd); | 532 | goto out_free_traceon; |
458 | unregister_ftrace_command(&ftrace_traceon_cmd); | 533 | |
459 | } | 534 | ret = register_ftrace_command(&ftrace_dump_cmd); |
535 | if (ret) | ||
536 | goto out_free_stacktrace; | ||
537 | |||
538 | ret = register_ftrace_command(&ftrace_cpudump_cmd); | ||
539 | if (ret) | ||
540 | goto out_free_dump; | ||
541 | |||
542 | return 0; | ||
543 | |||
544 | out_free_dump: | ||
545 | unregister_ftrace_command(&ftrace_dump_cmd); | ||
546 | out_free_stacktrace: | ||
547 | unregister_ftrace_command(&ftrace_stacktrace_cmd); | ||
548 | out_free_traceon: | ||
549 | unregister_ftrace_command(&ftrace_traceon_cmd); | ||
550 | out_free_traceoff: | ||
551 | unregister_ftrace_command(&ftrace_traceoff_cmd); | ||
552 | |||
460 | return ret; | 553 | return ret; |
461 | } | 554 | } |
462 | #else | 555 | #else |
diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c index b19d065a28cb..2aefbee93a6d 100644 --- a/kernel/trace/trace_irqsoff.c +++ b/kernel/trace/trace_irqsoff.c | |||
@@ -373,7 +373,7 @@ start_critical_timing(unsigned long ip, unsigned long parent_ip) | |||
373 | struct trace_array_cpu *data; | 373 | struct trace_array_cpu *data; |
374 | unsigned long flags; | 374 | unsigned long flags; |
375 | 375 | ||
376 | if (likely(!tracer_enabled)) | 376 | if (!tracer_enabled || !tracing_is_enabled()) |
377 | return; | 377 | return; |
378 | 378 | ||
379 | cpu = raw_smp_processor_id(); | 379 | cpu = raw_smp_processor_id(); |
@@ -416,7 +416,7 @@ stop_critical_timing(unsigned long ip, unsigned long parent_ip) | |||
416 | else | 416 | else |
417 | return; | 417 | return; |
418 | 418 | ||
419 | if (!tracer_enabled) | 419 | if (!tracer_enabled || !tracing_is_enabled()) |
420 | return; | 420 | return; |
421 | 421 | ||
422 | data = per_cpu_ptr(tr->trace_buffer.data, cpu); | 422 | data = per_cpu_ptr(tr->trace_buffer.data, cpu); |
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 9f46e98ba8f2..7ed6976493c8 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
@@ -35,12 +35,17 @@ struct trace_probe { | |||
35 | const char *symbol; /* symbol name */ | 35 | const char *symbol; /* symbol name */ |
36 | struct ftrace_event_class class; | 36 | struct ftrace_event_class class; |
37 | struct ftrace_event_call call; | 37 | struct ftrace_event_call call; |
38 | struct ftrace_event_file * __rcu *files; | 38 | struct list_head files; |
39 | ssize_t size; /* trace entry size */ | 39 | ssize_t size; /* trace entry size */ |
40 | unsigned int nr_args; | 40 | unsigned int nr_args; |
41 | struct probe_arg args[]; | 41 | struct probe_arg args[]; |
42 | }; | 42 | }; |
43 | 43 | ||
44 | struct event_file_link { | ||
45 | struct ftrace_event_file *file; | ||
46 | struct list_head list; | ||
47 | }; | ||
48 | |||
44 | #define SIZEOF_TRACE_PROBE(n) \ | 49 | #define SIZEOF_TRACE_PROBE(n) \ |
45 | (offsetof(struct trace_probe, args) + \ | 50 | (offsetof(struct trace_probe, args) + \ |
46 | (sizeof(struct probe_arg) * (n))) | 51 | (sizeof(struct probe_arg) * (n))) |
@@ -150,6 +155,7 @@ static struct trace_probe *alloc_trace_probe(const char *group, | |||
150 | goto error; | 155 | goto error; |
151 | 156 | ||
152 | INIT_LIST_HEAD(&tp->list); | 157 | INIT_LIST_HEAD(&tp->list); |
158 | INIT_LIST_HEAD(&tp->files); | ||
153 | return tp; | 159 | return tp; |
154 | error: | 160 | error: |
155 | kfree(tp->call.name); | 161 | kfree(tp->call.name); |
@@ -183,25 +189,6 @@ static struct trace_probe *find_trace_probe(const char *event, | |||
183 | return NULL; | 189 | return NULL; |
184 | } | 190 | } |
185 | 191 | ||
186 | static int trace_probe_nr_files(struct trace_probe *tp) | ||
187 | { | ||
188 | struct ftrace_event_file **file; | ||
189 | int ret = 0; | ||
190 | |||
191 | /* | ||
192 | * Since all tp->files updater is protected by probe_enable_lock, | ||
193 | * we don't need to lock an rcu_read_lock. | ||
194 | */ | ||
195 | file = rcu_dereference_raw(tp->files); | ||
196 | if (file) | ||
197 | while (*(file++)) | ||
198 | ret++; | ||
199 | |||
200 | return ret; | ||
201 | } | ||
202 | |||
203 | static DEFINE_MUTEX(probe_enable_lock); | ||
204 | |||
205 | /* | 192 | /* |
206 | * Enable trace_probe | 193 | * Enable trace_probe |
207 | * if the file is NULL, enable "perf" handler, or enable "trace" handler. | 194 | * if the file is NULL, enable "perf" handler, or enable "trace" handler. |
@@ -211,67 +198,42 @@ enable_trace_probe(struct trace_probe *tp, struct ftrace_event_file *file) | |||
211 | { | 198 | { |
212 | int ret = 0; | 199 | int ret = 0; |
213 | 200 | ||
214 | mutex_lock(&probe_enable_lock); | ||
215 | |||
216 | if (file) { | 201 | if (file) { |
217 | struct ftrace_event_file **new, **old; | 202 | struct event_file_link *link; |
218 | int n = trace_probe_nr_files(tp); | 203 | |
219 | 204 | link = kmalloc(sizeof(*link), GFP_KERNEL); | |
220 | old = rcu_dereference_raw(tp->files); | 205 | if (!link) { |
221 | /* 1 is for new one and 1 is for stopper */ | ||
222 | new = kzalloc((n + 2) * sizeof(struct ftrace_event_file *), | ||
223 | GFP_KERNEL); | ||
224 | if (!new) { | ||
225 | ret = -ENOMEM; | 206 | ret = -ENOMEM; |
226 | goto out_unlock; | 207 | goto out; |
227 | } | 208 | } |
228 | memcpy(new, old, n * sizeof(struct ftrace_event_file *)); | ||
229 | new[n] = file; | ||
230 | /* The last one keeps a NULL */ | ||
231 | 209 | ||
232 | rcu_assign_pointer(tp->files, new); | 210 | link->file = file; |
233 | tp->flags |= TP_FLAG_TRACE; | 211 | list_add_tail_rcu(&link->list, &tp->files); |
234 | 212 | ||
235 | if (old) { | 213 | tp->flags |= TP_FLAG_TRACE; |
236 | /* Make sure the probe is done with old files */ | ||
237 | synchronize_sched(); | ||
238 | kfree(old); | ||
239 | } | ||
240 | } else | 214 | } else |
241 | tp->flags |= TP_FLAG_PROFILE; | 215 | tp->flags |= TP_FLAG_PROFILE; |
242 | 216 | ||
243 | if (trace_probe_is_enabled(tp) && trace_probe_is_registered(tp) && | 217 | if (trace_probe_is_registered(tp) && !trace_probe_has_gone(tp)) { |
244 | !trace_probe_has_gone(tp)) { | ||
245 | if (trace_probe_is_return(tp)) | 218 | if (trace_probe_is_return(tp)) |
246 | ret = enable_kretprobe(&tp->rp); | 219 | ret = enable_kretprobe(&tp->rp); |
247 | else | 220 | else |
248 | ret = enable_kprobe(&tp->rp.kp); | 221 | ret = enable_kprobe(&tp->rp.kp); |
249 | } | 222 | } |
250 | 223 | out: | |
251 | out_unlock: | ||
252 | mutex_unlock(&probe_enable_lock); | ||
253 | |||
254 | return ret; | 224 | return ret; |
255 | } | 225 | } |
256 | 226 | ||
257 | static int | 227 | static struct event_file_link * |
258 | trace_probe_file_index(struct trace_probe *tp, struct ftrace_event_file *file) | 228 | find_event_file_link(struct trace_probe *tp, struct ftrace_event_file *file) |
259 | { | 229 | { |
260 | struct ftrace_event_file **files; | 230 | struct event_file_link *link; |
261 | int i; | ||
262 | 231 | ||
263 | /* | 232 | list_for_each_entry(link, &tp->files, list) |
264 | * Since all tp->files updater is protected by probe_enable_lock, | 233 | if (link->file == file) |
265 | * we don't need to lock an rcu_read_lock. | 234 | return link; |
266 | */ | ||
267 | files = rcu_dereference_raw(tp->files); | ||
268 | if (files) { | ||
269 | for (i = 0; files[i]; i++) | ||
270 | if (files[i] == file) | ||
271 | return i; | ||
272 | } | ||
273 | 235 | ||
274 | return -1; | 236 | return NULL; |
275 | } | 237 | } |
276 | 238 | ||
277 | /* | 239 | /* |
@@ -283,41 +245,24 @@ disable_trace_probe(struct trace_probe *tp, struct ftrace_event_file *file) | |||
283 | { | 245 | { |
284 | int ret = 0; | 246 | int ret = 0; |
285 | 247 | ||
286 | mutex_lock(&probe_enable_lock); | ||
287 | |||
288 | if (file) { | 248 | if (file) { |
289 | struct ftrace_event_file **new, **old; | 249 | struct event_file_link *link; |
290 | int n = trace_probe_nr_files(tp); | ||
291 | int i, j; | ||
292 | 250 | ||
293 | old = rcu_dereference_raw(tp->files); | 251 | link = find_event_file_link(tp, file); |
294 | if (n == 0 || trace_probe_file_index(tp, file) < 0) { | 252 | if (!link) { |
295 | ret = -EINVAL; | 253 | ret = -EINVAL; |
296 | goto out_unlock; | 254 | goto out; |
297 | } | 255 | } |
298 | 256 | ||
299 | if (n == 1) { /* Remove the last file */ | 257 | list_del_rcu(&link->list); |
300 | tp->flags &= ~TP_FLAG_TRACE; | 258 | /* synchronize with kprobe_trace_func/kretprobe_trace_func */ |
301 | new = NULL; | 259 | synchronize_sched(); |
302 | } else { | 260 | kfree(link); |
303 | new = kzalloc(n * sizeof(struct ftrace_event_file *), | ||
304 | GFP_KERNEL); | ||
305 | if (!new) { | ||
306 | ret = -ENOMEM; | ||
307 | goto out_unlock; | ||
308 | } | ||
309 | |||
310 | /* This copy & check loop copies the NULL stopper too */ | ||
311 | for (i = 0, j = 0; j < n && i < n + 1; i++) | ||
312 | if (old[i] != file) | ||
313 | new[j++] = old[i]; | ||
314 | } | ||
315 | 261 | ||
316 | rcu_assign_pointer(tp->files, new); | 262 | if (!list_empty(&tp->files)) |
263 | goto out; | ||
317 | 264 | ||
318 | /* Make sure the probe is done with old files */ | 265 | tp->flags &= ~TP_FLAG_TRACE; |
319 | synchronize_sched(); | ||
320 | kfree(old); | ||
321 | } else | 266 | } else |
322 | tp->flags &= ~TP_FLAG_PROFILE; | 267 | tp->flags &= ~TP_FLAG_PROFILE; |
323 | 268 | ||
@@ -327,10 +272,7 @@ disable_trace_probe(struct trace_probe *tp, struct ftrace_event_file *file) | |||
327 | else | 272 | else |
328 | disable_kprobe(&tp->rp.kp); | 273 | disable_kprobe(&tp->rp.kp); |
329 | } | 274 | } |
330 | 275 | out: | |
331 | out_unlock: | ||
332 | mutex_unlock(&probe_enable_lock); | ||
333 | |||
334 | return ret; | 276 | return ret; |
335 | } | 277 | } |
336 | 278 | ||
@@ -885,20 +827,10 @@ __kprobe_trace_func(struct trace_probe *tp, struct pt_regs *regs, | |||
885 | static __kprobes void | 827 | static __kprobes void |
886 | kprobe_trace_func(struct trace_probe *tp, struct pt_regs *regs) | 828 | kprobe_trace_func(struct trace_probe *tp, struct pt_regs *regs) |
887 | { | 829 | { |
888 | /* | 830 | struct event_file_link *link; |
889 | * Note: preempt is already disabled around the kprobe handler. | ||
890 | * However, we still need an smp_read_barrier_depends() corresponding | ||
891 | * to smp_wmb() in rcu_assign_pointer() to access the pointer. | ||
892 | */ | ||
893 | struct ftrace_event_file **file = rcu_dereference_raw(tp->files); | ||
894 | |||
895 | if (unlikely(!file)) | ||
896 | return; | ||
897 | 831 | ||
898 | while (*file) { | 832 | list_for_each_entry_rcu(link, &tp->files, list) |
899 | __kprobe_trace_func(tp, regs, *file); | 833 | __kprobe_trace_func(tp, regs, link->file); |
900 | file++; | ||
901 | } | ||
902 | } | 834 | } |
903 | 835 | ||
904 | /* Kretprobe handler */ | 836 | /* Kretprobe handler */ |
@@ -945,20 +877,10 @@ static __kprobes void | |||
945 | kretprobe_trace_func(struct trace_probe *tp, struct kretprobe_instance *ri, | 877 | kretprobe_trace_func(struct trace_probe *tp, struct kretprobe_instance *ri, |
946 | struct pt_regs *regs) | 878 | struct pt_regs *regs) |
947 | { | 879 | { |
948 | /* | 880 | struct event_file_link *link; |
949 | * Note: preempt is already disabled around the kprobe handler. | ||
950 | * However, we still need an smp_read_barrier_depends() corresponding | ||
951 | * to smp_wmb() in rcu_assign_pointer() to access the pointer. | ||
952 | */ | ||
953 | struct ftrace_event_file **file = rcu_dereference_raw(tp->files); | ||
954 | 881 | ||
955 | if (unlikely(!file)) | 882 | list_for_each_entry_rcu(link, &tp->files, list) |
956 | return; | 883 | __kretprobe_trace_func(tp, ri, regs, link->file); |
957 | |||
958 | while (*file) { | ||
959 | __kretprobe_trace_func(tp, ri, regs, *file); | ||
960 | file++; | ||
961 | } | ||
962 | } | 884 | } |
963 | 885 | ||
964 | /* Event entry printers */ | 886 | /* Event entry printers */ |
@@ -1157,6 +1079,10 @@ kprobe_perf_func(struct trace_probe *tp, struct pt_regs *regs) | |||
1157 | int size, __size, dsize; | 1079 | int size, __size, dsize; |
1158 | int rctx; | 1080 | int rctx; |
1159 | 1081 | ||
1082 | head = this_cpu_ptr(call->perf_events); | ||
1083 | if (hlist_empty(head)) | ||
1084 | return; | ||
1085 | |||
1160 | dsize = __get_data_size(tp, regs); | 1086 | dsize = __get_data_size(tp, regs); |
1161 | __size = sizeof(*entry) + tp->size + dsize; | 1087 | __size = sizeof(*entry) + tp->size + dsize; |
1162 | size = ALIGN(__size + sizeof(u32), sizeof(u64)); | 1088 | size = ALIGN(__size + sizeof(u32), sizeof(u64)); |
@@ -1172,10 +1098,7 @@ kprobe_perf_func(struct trace_probe *tp, struct pt_regs *regs) | |||
1172 | entry->ip = (unsigned long)tp->rp.kp.addr; | 1098 | entry->ip = (unsigned long)tp->rp.kp.addr; |
1173 | memset(&entry[1], 0, dsize); | 1099 | memset(&entry[1], 0, dsize); |
1174 | store_trace_args(sizeof(*entry), tp, regs, (u8 *)&entry[1], dsize); | 1100 | store_trace_args(sizeof(*entry), tp, regs, (u8 *)&entry[1], dsize); |
1175 | 1101 | perf_trace_buf_submit(entry, size, rctx, 0, 1, regs, head, NULL); | |
1176 | head = this_cpu_ptr(call->perf_events); | ||
1177 | perf_trace_buf_submit(entry, size, rctx, | ||
1178 | entry->ip, 1, regs, head, NULL); | ||
1179 | } | 1102 | } |
1180 | 1103 | ||
1181 | /* Kretprobe profile handler */ | 1104 | /* Kretprobe profile handler */ |
@@ -1189,6 +1112,10 @@ kretprobe_perf_func(struct trace_probe *tp, struct kretprobe_instance *ri, | |||
1189 | int size, __size, dsize; | 1112 | int size, __size, dsize; |
1190 | int rctx; | 1113 | int rctx; |
1191 | 1114 | ||
1115 | head = this_cpu_ptr(call->perf_events); | ||
1116 | if (hlist_empty(head)) | ||
1117 | return; | ||
1118 | |||
1192 | dsize = __get_data_size(tp, regs); | 1119 | dsize = __get_data_size(tp, regs); |
1193 | __size = sizeof(*entry) + tp->size + dsize; | 1120 | __size = sizeof(*entry) + tp->size + dsize; |
1194 | size = ALIGN(__size + sizeof(u32), sizeof(u64)); | 1121 | size = ALIGN(__size + sizeof(u32), sizeof(u64)); |
@@ -1204,13 +1131,16 @@ kretprobe_perf_func(struct trace_probe *tp, struct kretprobe_instance *ri, | |||
1204 | entry->func = (unsigned long)tp->rp.kp.addr; | 1131 | entry->func = (unsigned long)tp->rp.kp.addr; |
1205 | entry->ret_ip = (unsigned long)ri->ret_addr; | 1132 | entry->ret_ip = (unsigned long)ri->ret_addr; |
1206 | store_trace_args(sizeof(*entry), tp, regs, (u8 *)&entry[1], dsize); | 1133 | store_trace_args(sizeof(*entry), tp, regs, (u8 *)&entry[1], dsize); |
1207 | 1134 | perf_trace_buf_submit(entry, size, rctx, 0, 1, regs, head, NULL); | |
1208 | head = this_cpu_ptr(call->perf_events); | ||
1209 | perf_trace_buf_submit(entry, size, rctx, | ||
1210 | entry->ret_ip, 1, regs, head, NULL); | ||
1211 | } | 1135 | } |
1212 | #endif /* CONFIG_PERF_EVENTS */ | 1136 | #endif /* CONFIG_PERF_EVENTS */ |
1213 | 1137 | ||
1138 | /* | ||
1139 | * called by perf_trace_init() or __ftrace_set_clr_event() under event_mutex. | ||
1140 | * | ||
1141 | * kprobe_trace_self_tests_init() does enable_trace_probe/disable_trace_probe | ||
1142 | * lockless, but we can't race with this __init function. | ||
1143 | */ | ||
1214 | static __kprobes | 1144 | static __kprobes |
1215 | int kprobe_register(struct ftrace_event_call *event, | 1145 | int kprobe_register(struct ftrace_event_call *event, |
1216 | enum trace_reg type, void *data) | 1146 | enum trace_reg type, void *data) |
@@ -1376,6 +1306,10 @@ find_trace_probe_file(struct trace_probe *tp, struct trace_array *tr) | |||
1376 | return NULL; | 1306 | return NULL; |
1377 | } | 1307 | } |
1378 | 1308 | ||
1309 | /* | ||
1310 | * Nobody but us can call enable_trace_probe/disable_trace_probe at this | ||
1311 | * stage, we can do this lockless. | ||
1312 | */ | ||
1379 | static __init int kprobe_trace_self_tests_init(void) | 1313 | static __init int kprobe_trace_self_tests_init(void) |
1380 | { | 1314 | { |
1381 | int ret, warn = 0; | 1315 | int ret, warn = 0; |
diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c index 2901e3b88590..a7329b7902f8 100644 --- a/kernel/trace/trace_selftest.c +++ b/kernel/trace/trace_selftest.c | |||
@@ -640,13 +640,20 @@ out: | |||
640 | * Enable ftrace, sleep 1/10 second, and then read the trace | 640 | * Enable ftrace, sleep 1/10 second, and then read the trace |
641 | * buffer to see if all is in order. | 641 | * buffer to see if all is in order. |
642 | */ | 642 | */ |
643 | int | 643 | __init int |
644 | trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr) | 644 | trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr) |
645 | { | 645 | { |
646 | int save_ftrace_enabled = ftrace_enabled; | 646 | int save_ftrace_enabled = ftrace_enabled; |
647 | unsigned long count; | 647 | unsigned long count; |
648 | int ret; | 648 | int ret; |
649 | 649 | ||
650 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
651 | if (ftrace_filter_param) { | ||
652 | printk(KERN_CONT " ... kernel command line filter set: force PASS ... "); | ||
653 | return 0; | ||
654 | } | ||
655 | #endif | ||
656 | |||
650 | /* make sure msleep has been recorded */ | 657 | /* make sure msleep has been recorded */ |
651 | msleep(1); | 658 | msleep(1); |
652 | 659 | ||
@@ -727,13 +734,20 @@ static int trace_graph_entry_watchdog(struct ftrace_graph_ent *trace) | |||
727 | * Pretty much the same than for the function tracer from which the selftest | 734 | * Pretty much the same than for the function tracer from which the selftest |
728 | * has been borrowed. | 735 | * has been borrowed. |
729 | */ | 736 | */ |
730 | int | 737 | __init int |
731 | trace_selftest_startup_function_graph(struct tracer *trace, | 738 | trace_selftest_startup_function_graph(struct tracer *trace, |
732 | struct trace_array *tr) | 739 | struct trace_array *tr) |
733 | { | 740 | { |
734 | int ret; | 741 | int ret; |
735 | unsigned long count; | 742 | unsigned long count; |
736 | 743 | ||
744 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
745 | if (ftrace_filter_param) { | ||
746 | printk(KERN_CONT " ... kernel command line filter set: force PASS ... "); | ||
747 | return 0; | ||
748 | } | ||
749 | #endif | ||
750 | |||
737 | /* | 751 | /* |
738 | * Simulate the init() callback but we attach a watchdog callback | 752 | * Simulate the init() callback but we attach a watchdog callback |
739 | * to detect and recover from possible hangs | 753 | * to detect and recover from possible hangs |
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 8f2ac73c7a5f..322e16461072 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c | |||
@@ -306,6 +306,8 @@ static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id) | |||
306 | struct syscall_metadata *sys_data; | 306 | struct syscall_metadata *sys_data; |
307 | struct ring_buffer_event *event; | 307 | struct ring_buffer_event *event; |
308 | struct ring_buffer *buffer; | 308 | struct ring_buffer *buffer; |
309 | unsigned long irq_flags; | ||
310 | int pc; | ||
309 | int syscall_nr; | 311 | int syscall_nr; |
310 | int size; | 312 | int size; |
311 | 313 | ||
@@ -321,9 +323,12 @@ static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id) | |||
321 | 323 | ||
322 | size = sizeof(*entry) + sizeof(unsigned long) * sys_data->nb_args; | 324 | size = sizeof(*entry) + sizeof(unsigned long) * sys_data->nb_args; |
323 | 325 | ||
326 | local_save_flags(irq_flags); | ||
327 | pc = preempt_count(); | ||
328 | |||
324 | buffer = tr->trace_buffer.buffer; | 329 | buffer = tr->trace_buffer.buffer; |
325 | event = trace_buffer_lock_reserve(buffer, | 330 | event = trace_buffer_lock_reserve(buffer, |
326 | sys_data->enter_event->event.type, size, 0, 0); | 331 | sys_data->enter_event->event.type, size, irq_flags, pc); |
327 | if (!event) | 332 | if (!event) |
328 | return; | 333 | return; |
329 | 334 | ||
@@ -333,7 +338,8 @@ static void ftrace_syscall_enter(void *data, struct pt_regs *regs, long id) | |||
333 | 338 | ||
334 | if (!filter_current_check_discard(buffer, sys_data->enter_event, | 339 | if (!filter_current_check_discard(buffer, sys_data->enter_event, |
335 | entry, event)) | 340 | entry, event)) |
336 | trace_current_buffer_unlock_commit(buffer, event, 0, 0); | 341 | trace_current_buffer_unlock_commit(buffer, event, |
342 | irq_flags, pc); | ||
337 | } | 343 | } |
338 | 344 | ||
339 | static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret) | 345 | static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret) |
@@ -343,6 +349,8 @@ static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret) | |||
343 | struct syscall_metadata *sys_data; | 349 | struct syscall_metadata *sys_data; |
344 | struct ring_buffer_event *event; | 350 | struct ring_buffer_event *event; |
345 | struct ring_buffer *buffer; | 351 | struct ring_buffer *buffer; |
352 | unsigned long irq_flags; | ||
353 | int pc; | ||
346 | int syscall_nr; | 354 | int syscall_nr; |
347 | 355 | ||
348 | syscall_nr = trace_get_syscall_nr(current, regs); | 356 | syscall_nr = trace_get_syscall_nr(current, regs); |
@@ -355,9 +363,13 @@ static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret) | |||
355 | if (!sys_data) | 363 | if (!sys_data) |
356 | return; | 364 | return; |
357 | 365 | ||
366 | local_save_flags(irq_flags); | ||
367 | pc = preempt_count(); | ||
368 | |||
358 | buffer = tr->trace_buffer.buffer; | 369 | buffer = tr->trace_buffer.buffer; |
359 | event = trace_buffer_lock_reserve(buffer, | 370 | event = trace_buffer_lock_reserve(buffer, |
360 | sys_data->exit_event->event.type, sizeof(*entry), 0, 0); | 371 | sys_data->exit_event->event.type, sizeof(*entry), |
372 | irq_flags, pc); | ||
361 | if (!event) | 373 | if (!event) |
362 | return; | 374 | return; |
363 | 375 | ||
@@ -367,7 +379,8 @@ static void ftrace_syscall_exit(void *data, struct pt_regs *regs, long ret) | |||
367 | 379 | ||
368 | if (!filter_current_check_discard(buffer, sys_data->exit_event, | 380 | if (!filter_current_check_discard(buffer, sys_data->exit_event, |
369 | entry, event)) | 381 | entry, event)) |
370 | trace_current_buffer_unlock_commit(buffer, event, 0, 0); | 382 | trace_current_buffer_unlock_commit(buffer, event, |
383 | irq_flags, pc); | ||
371 | } | 384 | } |
372 | 385 | ||
373 | static int reg_event_syscall_enter(struct ftrace_event_file *file, | 386 | static int reg_event_syscall_enter(struct ftrace_event_file *file, |
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index 32494fb0ee64..d5d0cd368a56 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c | |||
@@ -283,8 +283,10 @@ static int create_trace_uprobe(int argc, char **argv) | |||
283 | return -EINVAL; | 283 | return -EINVAL; |
284 | } | 284 | } |
285 | arg = strchr(argv[1], ':'); | 285 | arg = strchr(argv[1], ':'); |
286 | if (!arg) | 286 | if (!arg) { |
287 | ret = -EINVAL; | ||
287 | goto fail_address_parse; | 288 | goto fail_address_parse; |
289 | } | ||
288 | 290 | ||
289 | *arg++ = '\0'; | 291 | *arg++ = '\0'; |
290 | filename = argv[1]; | 292 | filename = argv[1]; |