diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-28 21:10:39 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-28 21:10:39 -0400 |
| commit | 6803f37e0955c7cc7ebe4363cf2bab5552e4716d (patch) | |
| tree | ff4dc956f564b3b94fce96ed08609f561ca1c646 | |
| parent | 561d9e8185883a8d0788cb15090873d4f13323f5 (diff) | |
| parent | 09d8091c024ec88d1541d93eb8ddb2bd5cf10c39 (diff) | |
Merge tag 'trace-fixes-3.11-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace
Pull tracing fixes from Steven Rostedt:
"Oleg is working on fixing a very tight race between opening a event
file and deleting that event at the same time (both must be done as
root).
I also found a bug while testing Oleg's patches which has to do with a
race with kprobes using the function tracer.
There's also a deadlock fix that was introduced with the previous
fixes"
* tag 'trace-fixes-3.11-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace:
tracing: Remove locking trace_types_lock from tracing_reset_all_online_cpus()
ftrace: Add check for NULL regs if ops has SAVE_REGS set
tracing: Kill trace_cpu struct/members
tracing: Change tracing_fops/snapshot_fops to rely on tracing_get_cpu()
tracing: Change tracing_entries_fops to rely on tracing_get_cpu()
tracing: Change tracing_stats_fops to rely on tracing_get_cpu()
tracing: Change tracing_buffers_fops to rely on tracing_get_cpu()
tracing: Change tracing_pipe_fops() to rely on tracing_get_cpu()
tracing: Introduce trace_create_cpu_file() and tracing_get_cpu()
| -rw-r--r-- | kernel/trace/ftrace.c | 18 | ||||
| -rw-r--r-- | kernel/trace/trace.c | 197 | ||||
| -rw-r--r-- | kernel/trace/trace.h | 8 |
3 files changed, 95 insertions, 128 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 67708f46baae..8ce9eefc5bb4 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
| @@ -1441,12 +1441,22 @@ ftrace_hash_move(struct ftrace_ops *ops, int enable, | |||
| 1441 | * the hashes are freed with call_rcu_sched(). | 1441 | * the hashes are freed with call_rcu_sched(). |
| 1442 | */ | 1442 | */ |
| 1443 | static int | 1443 | static int |
| 1444 | ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip) | 1444 | ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip, void *regs) |
| 1445 | { | 1445 | { |
| 1446 | struct ftrace_hash *filter_hash; | 1446 | struct ftrace_hash *filter_hash; |
| 1447 | struct ftrace_hash *notrace_hash; | 1447 | struct ftrace_hash *notrace_hash; |
| 1448 | int ret; | 1448 | int ret; |
| 1449 | 1449 | ||
| 1450 | #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS | ||
| 1451 | /* | ||
| 1452 | * There's a small race when adding ops that the ftrace handler | ||
| 1453 | * that wants regs, may be called without them. We can not | ||
| 1454 | * allow that handler to be called if regs is NULL. | ||
| 1455 | */ | ||
| 1456 | if (regs == NULL && (ops->flags & FTRACE_OPS_FL_SAVE_REGS)) | ||
| 1457 | return 0; | ||
| 1458 | #endif | ||
| 1459 | |||
| 1450 | filter_hash = rcu_dereference_raw_notrace(ops->filter_hash); | 1460 | filter_hash = rcu_dereference_raw_notrace(ops->filter_hash); |
| 1451 | notrace_hash = rcu_dereference_raw_notrace(ops->notrace_hash); | 1461 | notrace_hash = rcu_dereference_raw_notrace(ops->notrace_hash); |
| 1452 | 1462 | ||
| @@ -4218,7 +4228,7 @@ static inline void ftrace_startup_enable(int command) { } | |||
| 4218 | # define ftrace_shutdown_sysctl() do { } while (0) | 4228 | # define ftrace_shutdown_sysctl() do { } while (0) |
| 4219 | 4229 | ||
| 4220 | static inline int | 4230 | static inline int |
| 4221 | ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip) | 4231 | ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip, void *regs) |
| 4222 | { | 4232 | { |
| 4223 | return 1; | 4233 | return 1; |
| 4224 | } | 4234 | } |
| @@ -4241,7 +4251,7 @@ ftrace_ops_control_func(unsigned long ip, unsigned long parent_ip, | |||
| 4241 | do_for_each_ftrace_op(op, ftrace_control_list) { | 4251 | do_for_each_ftrace_op(op, ftrace_control_list) { |
| 4242 | if (!(op->flags & FTRACE_OPS_FL_STUB) && | 4252 | if (!(op->flags & FTRACE_OPS_FL_STUB) && |
| 4243 | !ftrace_function_local_disabled(op) && | 4253 | !ftrace_function_local_disabled(op) && |
| 4244 | ftrace_ops_test(op, ip)) | 4254 | ftrace_ops_test(op, ip, regs)) |
| 4245 | op->func(ip, parent_ip, op, regs); | 4255 | op->func(ip, parent_ip, op, regs); |
| 4246 | } while_for_each_ftrace_op(op); | 4256 | } while_for_each_ftrace_op(op); |
| 4247 | trace_recursion_clear(TRACE_CONTROL_BIT); | 4257 | trace_recursion_clear(TRACE_CONTROL_BIT); |
| @@ -4274,7 +4284,7 @@ __ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip, | |||
| 4274 | */ | 4284 | */ |
| 4275 | preempt_disable_notrace(); | 4285 | preempt_disable_notrace(); |
| 4276 | do_for_each_ftrace_op(op, ftrace_ops_list) { | 4286 | do_for_each_ftrace_op(op, ftrace_ops_list) { |
| 4277 | if (ftrace_ops_test(op, ip)) | 4287 | if (ftrace_ops_test(op, ip, regs)) |
| 4278 | op->func(ip, parent_ip, op, regs); | 4288 | op->func(ip, parent_ip, op, regs); |
| 4279 | } while_for_each_ftrace_op(op); | 4289 | } while_for_each_ftrace_op(op); |
| 4280 | preempt_enable_notrace(); | 4290 | preempt_enable_notrace(); |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 3f2477713aca..882ec1dd1515 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
| @@ -1224,18 +1224,17 @@ void tracing_reset_current(int cpu) | |||
| 1224 | tracing_reset(&global_trace.trace_buffer, cpu); | 1224 | tracing_reset(&global_trace.trace_buffer, cpu); |
| 1225 | } | 1225 | } |
| 1226 | 1226 | ||
| 1227 | /* Must have trace_types_lock held */ | ||
| 1227 | void tracing_reset_all_online_cpus(void) | 1228 | void tracing_reset_all_online_cpus(void) |
| 1228 | { | 1229 | { |
| 1229 | struct trace_array *tr; | 1230 | struct trace_array *tr; |
| 1230 | 1231 | ||
| 1231 | mutex_lock(&trace_types_lock); | ||
| 1232 | list_for_each_entry(tr, &ftrace_trace_arrays, list) { | 1232 | list_for_each_entry(tr, &ftrace_trace_arrays, list) { |
| 1233 | tracing_reset_online_cpus(&tr->trace_buffer); | 1233 | tracing_reset_online_cpus(&tr->trace_buffer); |
| 1234 | #ifdef CONFIG_TRACER_MAX_TRACE | 1234 | #ifdef CONFIG_TRACER_MAX_TRACE |
| 1235 | tracing_reset_online_cpus(&tr->max_buffer); | 1235 | tracing_reset_online_cpus(&tr->max_buffer); |
| 1236 | #endif | 1236 | #endif |
| 1237 | } | 1237 | } |
| 1238 | mutex_unlock(&trace_types_lock); | ||
| 1239 | } | 1238 | } |
| 1240 | 1239 | ||
| 1241 | #define SAVED_CMDLINES 128 | 1240 | #define SAVED_CMDLINES 128 |
| @@ -2843,6 +2842,17 @@ static int s_show(struct seq_file *m, void *v) | |||
| 2843 | return 0; | 2842 | return 0; |
| 2844 | } | 2843 | } |
| 2845 | 2844 | ||
| 2845 | /* | ||
| 2846 | * Should be used after trace_array_get(), trace_types_lock | ||
| 2847 | * ensures that i_cdev was already initialized. | ||
| 2848 | */ | ||
| 2849 | static inline int tracing_get_cpu(struct inode *inode) | ||
| 2850 | { | ||
| 2851 | if (inode->i_cdev) /* See trace_create_cpu_file() */ | ||
| 2852 | return (long)inode->i_cdev - 1; | ||
| 2853 | return RING_BUFFER_ALL_CPUS; | ||
| 2854 | } | ||
| 2855 | |||
| 2846 | static const struct seq_operations tracer_seq_ops = { | 2856 | static const struct seq_operations tracer_seq_ops = { |
| 2847 | .start = s_start, | 2857 | .start = s_start, |
| 2848 | .next = s_next, | 2858 | .next = s_next, |
| @@ -2851,9 +2861,9 @@ static const struct seq_operations tracer_seq_ops = { | |||
| 2851 | }; | 2861 | }; |
| 2852 | 2862 | ||
| 2853 | static struct trace_iterator * | 2863 | static struct trace_iterator * |
| 2854 | __tracing_open(struct trace_array *tr, struct trace_cpu *tc, | 2864 | __tracing_open(struct inode *inode, struct file *file, bool snapshot) |
| 2855 | struct inode *inode, struct file *file, bool snapshot) | ||
| 2856 | { | 2865 | { |
| 2866 | struct trace_array *tr = inode->i_private; | ||
| 2857 | struct trace_iterator *iter; | 2867 | struct trace_iterator *iter; |
| 2858 | int cpu; | 2868 | int cpu; |
| 2859 | 2869 | ||
| @@ -2894,8 +2904,8 @@ __tracing_open(struct trace_array *tr, struct trace_cpu *tc, | |||
| 2894 | iter->trace_buffer = &tr->trace_buffer; | 2904 | iter->trace_buffer = &tr->trace_buffer; |
| 2895 | iter->snapshot = snapshot; | 2905 | iter->snapshot = snapshot; |
| 2896 | iter->pos = -1; | 2906 | iter->pos = -1; |
| 2907 | iter->cpu_file = tracing_get_cpu(inode); | ||
| 2897 | mutex_init(&iter->mutex); | 2908 | mutex_init(&iter->mutex); |
| 2898 | iter->cpu_file = tc->cpu; | ||
| 2899 | 2909 | ||
| 2900 | /* Notify the tracer early; before we stop tracing. */ | 2910 | /* Notify the tracer early; before we stop tracing. */ |
| 2901 | if (iter->trace && iter->trace->open) | 2911 | if (iter->trace && iter->trace->open) |
| @@ -2971,44 +2981,22 @@ static int tracing_open_generic_tr(struct inode *inode, struct file *filp) | |||
| 2971 | filp->private_data = inode->i_private; | 2981 | filp->private_data = inode->i_private; |
| 2972 | 2982 | ||
| 2973 | return 0; | 2983 | 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 | } | 2984 | } |
| 2993 | 2985 | ||
| 2994 | static int tracing_release(struct inode *inode, struct file *file) | 2986 | static int tracing_release(struct inode *inode, struct file *file) |
| 2995 | { | 2987 | { |
| 2988 | struct trace_array *tr = inode->i_private; | ||
| 2996 | struct seq_file *m = file->private_data; | 2989 | struct seq_file *m = file->private_data; |
| 2997 | struct trace_iterator *iter; | 2990 | struct trace_iterator *iter; |
| 2998 | struct trace_array *tr; | ||
| 2999 | int cpu; | 2991 | int cpu; |
| 3000 | 2992 | ||
| 3001 | /* Writes do not use seq_file, need to grab tr from inode */ | ||
| 3002 | if (!(file->f_mode & FMODE_READ)) { | 2993 | if (!(file->f_mode & FMODE_READ)) { |
| 3003 | struct trace_cpu *tc = inode->i_private; | 2994 | trace_array_put(tr); |
| 3004 | |||
| 3005 | trace_array_put(tc->tr); | ||
| 3006 | return 0; | 2995 | return 0; |
| 3007 | } | 2996 | } |
| 3008 | 2997 | ||
| 2998 | /* Writes do not use seq_file */ | ||
| 3009 | |||
