diff options
Diffstat (limited to 'kernel/trace/trace.c')
-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 10d3f0871b48..9d076a1ffa0b 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -193,6 +193,37 @@ static struct trace_array global_trace; | |||
193 | 193 | ||
194 | LIST_HEAD(ftrace_trace_arrays); | 194 | LIST_HEAD(ftrace_trace_arrays); |
195 | 195 | ||
196 | int trace_array_get(struct trace_array *this_tr) | ||
197 | { | ||
198 | struct trace_array *tr; | ||
199 | int ret = -ENODEV; | ||
200 | |||
201 | mutex_lock(&trace_types_lock); | ||
202 | list_for_each_entry(tr, &ftrace_trace_arrays, list) { | ||
203 | if (tr == this_tr) { | ||
204 | tr->ref++; | ||
205 | ret = 0; | ||
206 | break; | ||
207 | } | ||
208 | } | ||
209 | mutex_unlock(&trace_types_lock); | ||
210 | |||
211 | return ret; | ||
212 | } | ||
213 | |||
214 | static void __trace_array_put(struct trace_array *this_tr) | ||
215 | { | ||
216 | WARN_ON(!this_tr->ref); | ||
217 | this_tr->ref--; | ||
218 | } | ||
219 | |||
220 | void trace_array_put(struct trace_array *this_tr) | ||
221 | { | ||
222 | mutex_lock(&trace_types_lock); | ||
223 | __trace_array_put(this_tr); | ||
224 | mutex_unlock(&trace_types_lock); | ||
225 | } | ||
226 | |||
196 | int filter_current_check_discard(struct ring_buffer *buffer, | 227 | int filter_current_check_discard(struct ring_buffer *buffer, |
197 | struct ftrace_event_call *call, void *rec, | 228 | struct ftrace_event_call *call, void *rec, |
198 | struct ring_buffer_event *event) | 229 | struct ring_buffer_event *event) |
@@ -2768,10 +2799,9 @@ static const struct seq_operations tracer_seq_ops = { | |||
2768 | }; | 2799 | }; |
2769 | 2800 | ||
2770 | static struct trace_iterator * | 2801 | static struct trace_iterator * |
2771 | __tracing_open(struct inode *inode, struct file *file, bool snapshot) | 2802 | __tracing_open(struct trace_array *tr, struct trace_cpu *tc, |
2803 | struct inode *inode, struct file *file, bool snapshot) | ||
2772 | { | 2804 | { |
2773 | struct trace_cpu *tc = inode->i_private; | ||
2774 | struct trace_array *tr = tc->tr; | ||
2775 | struct trace_iterator *iter; | 2805 | struct trace_iterator *iter; |
2776 | int cpu; | 2806 | int cpu; |
2777 | 2807 | ||
@@ -2850,8 +2880,6 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot) | |||
2850 | tracing_iter_reset(iter, cpu); | 2880 | tracing_iter_reset(iter, cpu); |
2851 | } | 2881 | } |
2852 | 2882 | ||
2853 | tr->ref++; | ||
2854 | |||
2855 | mutex_unlock(&trace_types_lock); | 2883 | mutex_unlock(&trace_types_lock); |
2856 | 2884 | ||
2857 | return iter; | 2885 | return iter; |
@@ -2881,17 +2909,20 @@ static int tracing_release(struct inode *inode, struct file *file) | |||
2881 | struct trace_array *tr; | 2909 | struct trace_array *tr; |
2882 | int cpu; | 2910 | int cpu; |
2883 | 2911 | ||
2884 | if (!(file->f_mode & FMODE_READ)) | 2912 | /* Writes do not use seq_file, need to grab tr from inode */ |
2913 | if (!(file->f_mode & FMODE_READ)) { | ||
2914 | struct trace_cpu *tc = inode->i_private; | ||
2915 | |||
2916 | trace_array_put(tc->tr); | ||
2885 | return 0; | 2917 | return 0; |
2918 | } | ||
2886 | 2919 | ||
2887 | iter = m->private; | 2920 | iter = m->private; |
2888 | tr = iter->tr; | 2921 | tr = iter->tr; |
2922 | trace_array_put(tr); | ||
2889 | 2923 | ||
2890 | mutex_lock(&trace_types_lock); | 2924 | mutex_lock(&trace_types_lock); |
2891 | 2925 | ||
2892 | WARN_ON(!tr->ref); | ||
2893 | tr->ref--; | ||
2894 | |||
2895 | for_each_tracing_cpu(cpu) { | 2926 | for_each_tracing_cpu(cpu) { |
2896 | if (iter->buffer_iter[cpu]) | 2927 | if (iter->buffer_iter[cpu]) |
2897 | ring_buffer_read_finish(iter->buffer_iter[cpu]); | 2928 | ring_buffer_read_finish(iter->buffer_iter[cpu]); |
@@ -2910,20 +2941,23 @@ static int tracing_release(struct inode *inode, struct file *file) | |||
2910 | kfree(iter->trace); | 2941 | kfree(iter->trace); |
2911 | kfree(iter->buffer_iter); | 2942 | kfree(iter->buffer_iter); |
2912 | seq_release_private(inode, file); | 2943 | seq_release_private(inode, file); |
2944 | |||
2913 | return 0; | 2945 | return 0; |
2914 | } | 2946 | } |
2915 | 2947 | ||
2916 | static int tracing_open(struct inode *inode, struct file *file) | 2948 | static int tracing_open(struct inode *inode, struct file *file) |
2917 | { | 2949 | { |
2950 | struct trace_cpu *tc = inode->i_private; | ||
2951 | struct trace_array *tr = tc->tr; | ||
2918 | struct trace_iterator *iter; | 2952 | struct trace_iterator *iter; |
2919 | int ret = 0; | 2953 | int ret = 0; |
2920 | 2954 | ||
2955 | if (trace_array_get(tr) < 0) | ||
2956 | return -ENODEV; | ||
2957 | |||
2921 | /* If this file was open for write, then erase contents */ | 2958 | /* If this file was open for write, then erase contents */ |
2922 | if ((file->f_mode & FMODE_WRITE) && | 2959 | if ((file->f_mode & FMODE_WRITE) && |
2923 | (file->f_flags & O_TRUNC)) { | 2960 | (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) | 2961 | if (tc->cpu == RING_BUFFER_ALL_CPUS) |
2928 | tracing_reset_online_cpus(&tr->trace_buffer); | 2962 | tracing_reset_online_cpus(&tr->trace_buffer); |
2929 | else | 2963 | else |
@@ -2931,12 +2965,16 @@ static int tracing_open(struct inode *inode, struct file *file) | |||
2931 | } | 2965 | } |
2932 | 2966 | ||
2933 | if (file->f_mode & FMODE_READ) { | 2967 | if (file->f_mode & FMODE_READ) { |
2934 | iter = __tracing_open(inode, file, false); | 2968 | iter = __tracing_open(tr, tc, inode, file, false); |
2935 | if (IS_ERR(iter)) | 2969 | if (IS_ERR(iter)) |
2936 | ret = PTR_ERR(iter); | 2970 | ret = PTR_ERR(iter); |
2937 | else if (trace_flags & TRACE_ITER_LATENCY_FMT) | 2971 | else if (trace_flags & TRACE_ITER_LATENCY_FMT) |
2938 | iter->iter_flags |= TRACE_FILE_LAT_FMT; | 2972 | iter->iter_flags |= TRACE_FILE_LAT_FMT; |
2939 | } | 2973 | } |
2974 | |||
2975 | if (ret < 0) | ||
2976 | trace_array_put(tr); | ||
2977 | |||
2940 | return ret; | 2978 | return ret; |
2941 | } | 2979 | } |
2942 | 2980 | ||
@@ -4512,12 +4550,16 @@ struct ftrace_buffer_info { | |||
4512 | static int tracing_snapshot_open(struct inode *inode, struct file *file) | 4550 | static int tracing_snapshot_open(struct inode *inode, struct file *file) |
4513 | { | 4551 | { |
4514 | struct trace_cpu *tc = inode->i_private; | 4552 | struct trace_cpu *tc = inode->i_private; |
4553 | struct trace_array *tr = tc->tr; | ||
4515 | struct trace_iterator *iter; | 4554 | struct trace_iterator *iter; |
4516 | struct seq_file *m; | 4555 | struct seq_file *m; |
4517 | int ret = 0; | 4556 | int ret = 0; |
4518 | 4557 | ||
4558 | if (trace_array_get(tr) < 0) | ||
4559 | return -ENODEV; | ||
4560 | |||
4519 | if (file->f_mode & FMODE_READ) { | 4561 | if (file->f_mode & FMODE_READ) { |
4520 | iter = __tracing_open(inode, file, true); | 4562 | iter = __tracing_open(tr, tc, inode, file, true); |
4521 | if (IS_ERR(iter)) | 4563 | if (IS_ERR(iter)) |
4522 | ret = PTR_ERR(iter); | 4564 | ret = PTR_ERR(iter); |
4523 | } else { | 4565 | } else { |
@@ -4530,13 +4572,16 @@ static int tracing_snapshot_open(struct inode *inode, struct file *file) | |||
4530 | kfree(m); | 4572 | kfree(m); |
4531 | return -ENOMEM; | 4573 | return -ENOMEM; |
4532 | } | 4574 | } |
4533 | iter->tr = tc->tr; | 4575 | iter->tr = tr; |
4534 | iter->trace_buffer = &tc->tr->max_buffer; | 4576 | iter->trace_buffer = &tc->tr->max_buffer; |
4535 | iter->cpu_file = tc->cpu; | 4577 | iter->cpu_file = tc->cpu; |
4536 | m->private = iter; | 4578 | m->private = iter; |
4537 | file->private_data = m; | 4579 | file->private_data = m; |
4538 | } | 4580 | } |
4539 | 4581 | ||
4582 | if (ret < 0) | ||
4583 | trace_array_put(tr); | ||
4584 | |||
4540 | return ret; | 4585 | return ret; |
4541 | } | 4586 | } |
4542 | 4587 | ||
@@ -4617,9 +4662,12 @@ out: | |||
4617 | static int tracing_snapshot_release(struct inode *inode, struct file *file) | 4662 | static int tracing_snapshot_release(struct inode *inode, struct file *file) |
4618 | { | 4663 | { |
4619 | struct seq_file *m = file->private_data; | 4664 | struct seq_file *m = file->private_data; |
4665 | int ret; | ||
4666 | |||
4667 | ret = tracing_release(inode, file); | ||
4620 | 4668 | ||
4621 | if (file->f_mode & FMODE_READ) | 4669 | if (file->f_mode & FMODE_READ) |
4622 | return tracing_release(inode, file); | 4670 | return ret; |
4623 | 4671 | ||
4624 | /* If write only, the seq_file is just a stub */ | 4672 | /* If write only, the seq_file is just a stub */ |
4625 | if (m) | 4673 | if (m) |
@@ -4864,8 +4912,7 @@ static int tracing_buffers_release(struct inode *inode, struct file *file) | |||
4864 | 4912 | ||
4865 | mutex_lock(&trace_types_lock); | 4913 | mutex_lock(&trace_types_lock); |
4866 | 4914 | ||
4867 | WARN_ON(!iter->tr->ref); | 4915 | __trace_array_put(iter->tr); |
4868 | iter->tr->ref--; | ||
4869 | 4916 | ||
4870 | if (info->spare) | 4917 | if (info->spare) |
4871 | ring_buffer_free_read_page(iter->trace_buffer->buffer, info->spare); | 4918 | ring_buffer_free_read_page(iter->trace_buffer->buffer, info->spare); |