diff options
-rw-r--r-- | kernel/trace/trace.c | 83 |
1 files changed, 65 insertions, 18 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index e36da7ff59bf..6be9df1aa513 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -204,6 +204,37 @@ static struct trace_array global_trace; | |||
204 | 204 | ||
205 | LIST_HEAD(ftrace_trace_arrays); | 205 | LIST_HEAD(ftrace_trace_arrays); |
206 | 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 | |||
207 | int filter_current_check_discard(struct ring_buffer *buffer, | 238 | int filter_current_check_discard(struct ring_buffer *buffer, |
208 | struct ftrace_event_call *call, void *rec, | 239 | struct ftrace_event_call *call, void *rec, |
209 | struct ring_buffer_event *event) | 240 | struct ring_buffer_event *event) |
@@ -2831,10 +2862,9 @@ static const struct seq_operations tracer_seq_ops = { | |||
2831 | }; | 2862 | }; |
2832 | 2863 | ||
2833 | static struct trace_iterator * | 2864 | static struct trace_iterator * |
2834 | __tracing_open(struct inode *inode, struct file *file, bool snapshot) | 2865 | __tracing_open(struct trace_array *tr, struct trace_cpu *tc, |
2866 | struct inode *inode, struct file *file, bool snapshot) | ||
2835 | { | 2867 | { |
2836 | struct trace_cpu *tc = inode->i_private; | ||
2837 | struct trace_array *tr = tc->tr; | ||
2838 | struct trace_iterator *iter; | 2868 | struct trace_iterator *iter; |
2839 | int cpu; | 2869 | int cpu; |
2840 | 2870 | ||
@@ -2913,8 +2943,6 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot) | |||
2913 | tracing_iter_reset(iter, cpu); | 2943 | tracing_iter_reset(iter, cpu); |
2914 | } | 2944 | } |
2915 | 2945 | ||
2916 | tr->ref++; | ||
2917 | |||
2918 | mutex_unlock(&trace_types_lock); | 2946 | mutex_unlock(&trace_types_lock); |
2919 | 2947 | ||
2920 | return iter; | 2948 | return iter; |
@@ -2944,17 +2972,20 @@ static int tracing_release(struct inode *inode, struct file *file) | |||
2944 | struct trace_array *tr; | 2972 | struct trace_array *tr; |
2945 | int cpu; | 2973 | int cpu; |
2946 | 2974 | ||
2947 | if (!(file->f_mode & FMODE_READ)) | 2975 | /* Writes do not use seq_file, need to grab tr from inode */ |
2976 | if (!(file->f_mode & FMODE_READ)) { | ||
2977 | struct trace_cpu *tc = inode->i_private; | ||
2978 | |||
2979 | trace_array_put(tc->tr); | ||
2948 | return 0; | 2980 | return 0; |
2981 | } | ||
2949 | 2982 | ||
2950 | iter = m->private; | 2983 | iter = m->private; |
2951 | tr = iter->tr; | 2984 | tr = iter->tr; |
2985 | trace_array_put(tr); | ||
2952 | 2986 | ||
2953 | mutex_lock(&trace_types_lock); | 2987 | mutex_lock(&trace_types_lock); |
2954 | 2988 | ||
2955 | WARN_ON(!tr->ref); | ||
2956 | tr->ref--; | ||
2957 | |||
2958 | for_each_tracing_cpu(cpu) { | 2989 | for_each_tracing_cpu(cpu) { |
2959 | if (iter->buffer_iter[cpu]) | 2990 | if (iter->buffer_iter[cpu]) |
2960 | ring_buffer_read_finish(iter->buffer_iter[cpu]); | 2991 | ring_buffer_read_finish(iter->buffer_iter[cpu]); |
@@ -2973,20 +3004,23 @@ static int tracing_release(struct inode *inode, struct file *file) | |||
2973 | kfree(iter->trace); | 3004 | kfree(iter->trace); |
2974 | kfree(iter->buffer_iter); | 3005 | kfree(iter->buffer_iter); |
2975 | seq_release_private(inode, file); | 3006 | seq_release_private(inode, file); |
3007 | |||
2976 | return 0; | 3008 | return 0; |
2977 | } | 3009 | } |
2978 | 3010 | ||
2979 | static int tracing_open(struct inode *inode, struct file *file) | 3011 | static int tracing_open(struct inode *inode, struct file *file) |
2980 | { | 3012 | { |
3013 | struct trace_cpu *tc = inode->i_private; | ||
3014 | struct trace_array *tr = tc->tr; | ||
2981 | struct trace_iterator *iter; | 3015 | struct trace_iterator *iter; |
2982 | int ret = 0; | 3016 | int ret = 0; |
2983 | 3017 | ||
3018 | if (trace_array_get(tr) < 0) | ||
3019 | return -ENODEV; | ||
3020 | |||
2984 | /* If this file was open for write, then erase contents */ | 3021 | /* If this file was open for write, then erase contents */ |
2985 | if ((file->f_mode & FMODE_WRITE) && | 3022 | if ((file->f_mode & FMODE_WRITE) && |
2986 | (file->f_flags & O_TRUNC)) { | 3023 | (file->f_flags & O_TRUNC)) { |
2987 | struct trace_cpu *tc = inode->i_private; | ||
2988 | struct trace_array *tr = tc->tr; | ||
2989 | |||
2990 | if (tc->cpu == RING_BUFFER_ALL_CPUS) | 3024 | if (tc->cpu == RING_BUFFER_ALL_CPUS) |
2991 | tracing_reset_online_cpus(&tr->trace_buffer); | 3025 | tracing_reset_online_cpus(&tr->trace_buffer); |
2992 | else | 3026 | else |
@@ -2994,12 +3028,16 @@ static int tracing_open(struct inode *inode, struct file *file) | |||
2994 | } | 3028 | } |
2995 | 3029 | ||
2996 | if (file->f_mode & FMODE_READ) { | 3030 | if (file->f_mode & FMODE_READ) { |
2997 | iter = __tracing_open(inode, file, false); | 3031 | iter = __tracing_open(tr, tc, inode, file, false); |
2998 | if (IS_ERR(iter)) | 3032 | if (IS_ERR(iter)) |
2999 | ret = PTR_ERR(iter); | 3033 | ret = PTR_ERR(iter); |
3000 | else if (trace_flags & TRACE_ITER_LATENCY_FMT) | 3034 | else if (trace_flags & TRACE_ITER_LATENCY_FMT) |
3001 | iter->iter_flags |= TRACE_FILE_LAT_FMT; | 3035 | iter->iter_flags |= TRACE_FILE_LAT_FMT; |
3002 | } | 3036 | } |
3037 | |||
3038 | if (ret < 0) | ||
3039 | trace_array_put(tr); | ||
3040 | |||
3003 | return ret; | 3041 | return ret; |
3004 | } | 3042 | } |
3005 | 3043 | ||
@@ -4575,12 +4613,16 @@ struct ftrace_buffer_info { | |||
4575 | static int tracing_snapshot_open(struct inode *inode, struct file *file) | 4613 | static int tracing_snapshot_open(struct inode *inode, struct file *file) |
4576 | { | 4614 | { |
4577 | struct trace_cpu *tc = inode->i_private; | 4615 | struct trace_cpu *tc = inode->i_private; |
4616 | struct trace_array *tr = tc->tr; | ||
4578 | struct trace_iterator *iter; | 4617 | struct trace_iterator *iter; |
4579 | struct seq_file *m; | 4618 | struct seq_file *m; |
4580 | int ret = 0; | 4619 | int ret = 0; |
4581 | 4620 | ||
4621 | if (trace_array_get(tr) < 0) | ||
4622 | return -ENODEV; | ||
4623 | |||
4582 | if (file->f_mode & FMODE_READ) { | 4624 | if (file->f_mode & FMODE_READ) { |
4583 | iter = __tracing_open(inode, file, true); | 4625 | iter = __tracing_open(tr, tc, inode, file, true); |
4584 | if (IS_ERR(iter)) | 4626 | if (IS_ERR(iter)) |
4585 | ret = PTR_ERR(iter); | 4627 | ret = PTR_ERR(iter); |
4586 | } else { | 4628 | } else { |
@@ -4593,13 +4635,16 @@ static int tracing_snapshot_open(struct inode *inode, struct file *file) | |||
4593 | kfree(m); | 4635 | kfree(m); |
4594 | return -ENOMEM; | 4636 | return -ENOMEM; |
4595 | } | 4637 | } |
4596 | iter->tr = tc->tr; | 4638 | iter->tr = tr; |
4597 | iter->trace_buffer = &tc->tr->max_buffer; | 4639 | iter->trace_buffer = &tc->tr->max_buffer; |
4598 | iter->cpu_file = tc->cpu; | 4640 | iter->cpu_file = tc->cpu; |
4599 | m->private = iter; | 4641 | m->private = iter; |
4600 | file->private_data = m; | 4642 | file->private_data = m; |
4601 | } | 4643 | } |
4602 | 4644 | ||
4645 | if (ret < 0) | ||
4646 | trace_array_put(tr); | ||
4647 | |||
4603 | return ret; | 4648 | return ret; |
4604 | } | 4649 | } |
4605 | 4650 | ||
@@ -4680,9 +4725,12 @@ out: | |||
4680 | static int tracing_snapshot_release(struct inode *inode, struct file *file) | 4725 | static int tracing_snapshot_release(struct inode *inode, struct file *file) |
4681 | { | 4726 | { |
4682 | struct seq_file *m = file->private_data; | 4727 | struct seq_file *m = file->private_data; |
4728 | int ret; | ||
4729 | |||
4730 | ret = tracing_release(inode, file); | ||
4683 | 4731 | ||
4684 | if (file->f_mode & FMODE_READ) | 4732 | if (file->f_mode & FMODE_READ) |
4685 | return tracing_release(inode, file); | 4733 | return ret; |
4686 | 4734 | ||
4687 | /* If write only, the seq_file is just a stub */ | 4735 | /* If write only, the seq_file is just a stub */ |
4688 | if (m) | 4736 | if (m) |
@@ -4927,8 +4975,7 @@ static int tracing_buffers_release(struct inode *inode, struct file *file) | |||
4927 | 4975 | ||
4928 | mutex_lock(&trace_types_lock); | 4976 | mutex_lock(&trace_types_lock); |
4929 | 4977 | ||
4930 | WARN_ON(!iter->tr->ref); | 4978 | __trace_array_put(iter->tr); |
4931 | iter->tr->ref--; | ||
4932 | 4979 | ||
4933 | if (info->spare) | 4980 | if (info->spare) |
4934 | ring_buffer_free_read_page(iter->trace_buffer->buffer, info->spare); | 4981 | ring_buffer_free_read_page(iter->trace_buffer->buffer, info->spare); |