diff options
| author | Steven Rostedt (Red Hat) <rostedt@goodmis.org> | 2013-07-01 23:34:22 -0400 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2013-07-02 10:17:04 -0400 |
| commit | 7b85af63034818e43aee6c1d7bf1c7c6796a9073 (patch) | |
| tree | 4bc354897ff28147a5aedb7c318608a30d46e61b /kernel | |
| parent | ff451961a8b2a17667a7bfa39c86fb9b351445db (diff) | |
tracing: Get trace_array ref counts when accessing trace files
When a trace file is opened that may access a trace array, it must
increment its ref count to prevent it from being deleted.
Cc: stable@vger.kernel.org # 3.10
Reported-by: Alexander Lam <azl@google.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/trace/trace.c | 121 |
1 files changed, 112 insertions, 9 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 6be9df1aa513..6d9bd9b43e43 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
| @@ -2965,6 +2965,43 @@ int tracing_open_generic(struct inode *inode, struct file *filp) | |||
| 2965 | return 0; | 2965 | return 0; |
| 2966 | } | 2966 | } |
| 2967 | 2967 | ||
| 2968 | /* | ||
| 2969 | * Open and update trace_array ref count. | ||
| 2970 | * Must have the current trace_array passed to it. | ||
| 2971 | */ | ||
| 2972 | int tracing_open_generic_tr(struct inode *inode, struct file *filp) | ||
| 2973 | { | ||
| 2974 | struct trace_array *tr = inode->i_private; | ||
| 2975 | |||
| 2976 | if (tracing_disabled) | ||
| 2977 | return -ENODEV; | ||
| 2978 | |||
| 2979 | if (trace_array_get(tr) < 0) | ||
| 2980 | return -ENODEV; | ||
| 2981 | |||
| 2982 | filp->private_data = inode->i_private; | ||
| 2983 | |||
| 2984 | return 0; | ||
| 2985 | |||
| 2986 | } | ||
| 2987 | |||
| 2988 | int tracing_open_generic_tc(struct inode *inode, struct file *filp) | ||
| 2989 | { | ||
| 2990 | struct trace_cpu *tc = inode->i_private; | ||
| 2991 | struct trace_array *tr = tc->tr; | ||
| 2992 | |||
| 2993 | if (tracing_disabled) | ||
| 2994 | return -ENODEV; | ||
| 2995 | |||
| 2996 | if (trace_array_get(tr) < 0) | ||
| 2997 | return -ENODEV; | ||
| 2998 | |||
| 2999 | filp->private_data = inode->i_private; | ||
| 3000 | |||
| 3001 | return 0; | ||
| 3002 | |||
| 3003 | } | ||
| 3004 | |||
| 2968 | static int tracing_release(struct inode *inode, struct file *file) | 3005 | static int tracing_release(struct inode *inode, struct file *file) |
| 2969 | { | 3006 | { |
| 2970 | struct seq_file *m = file->private_data; | 3007 | struct seq_file *m = file->private_data; |
| @@ -3008,6 +3045,32 @@ static int tracing_release(struct inode *inode, struct file *file) | |||
| 3008 | return 0; | 3045 | return 0; |
| 3009 | } | 3046 | } |
| 3010 | 3047 | ||
| 3048 | static int tracing_release_generic_tr(struct inode *inode, struct file *file) | ||
| 3049 | { | ||
| 3050 | struct trace_array *tr = inode->i_private; | ||
| 3051 | |||
| 3052 | trace_array_put(tr); | ||
| 3053 | return 0; | ||
| 3054 | } | ||
| 3055 | |||
| 3056 | static int tracing_release_generic_tc(struct inode *inode, struct file *file) | ||
| 3057 | { | ||
| 3058 | struct trace_cpu *tc = inode->i_private; | ||
| 3059 | struct trace_array *tr = tc->tr; | ||
| 3060 | |||
| 3061 | trace_array_put(tr); | ||
| 3062 | return 0; | ||
| 3063 | } | ||
| 3064 | |||
| 3065 | static int tracing_single_release_tr(struct inode *inode, struct file *file) | ||
| 3066 | { | ||
| 3067 | struct trace_array *tr = inode->i_private; | ||
| 3068 | |||
| 3069 | trace_array_put(tr); | ||
| 3070 | |||
| 3071 | return single_release(inode, file); | ||
| 3072 | } | ||
| 3073 | |||
| 3011 | static int tracing_open(struct inode *inode, struct file *file) | 3074 | static int tracing_open(struct inode *inode, struct file *file) |
| 3012 | { | 3075 | { |
| 3013 | struct trace_cpu *tc = inode->i_private; | 3076 | struct trace_cpu *tc = inode->i_private; |
| @@ -3394,9 +3457,14 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf, | |||
| 3394 | 3457 | ||
| 3395 | static int tracing_trace_options_open(struct inode *inode, struct file *file) | 3458 | static int tracing_trace_options_open(struct inode *inode, struct file *file) |
| 3396 | { | 3459 | { |
| 3460 | struct trace_array *tr = inode->i_private; | ||
| 3461 | |||
| 3397 | if (tracing_disabled) | 3462 | if (tracing_disabled) |
| 3398 | return -ENODEV; | 3463 | return -ENODEV; |
| 3399 | 3464 | ||
| 3465 | if (trace_array_get(tr) < 0) | ||
| 3466 | return -ENODEV; | ||
| 3467 | |||
| 3400 | return single_open(file, tracing_trace_options_show, inode->i_private); | 3468 | return single_open(file, tracing_trace_options_show, inode->i_private); |
| 3401 | } | 3469 | } |
| 3402 | 3470 | ||
| @@ -3404,7 +3472,7 @@ static const struct file_operations tracing_iter_fops = { | |||
| 3404 | .open = tracing_trace_options_open, | 3472 | .open = tracing_trace_options_open, |
| 3405 | .read = seq_read, | 3473 | .read = seq_read, |
| 3406 | .llseek = seq_lseek, | 3474 | .llseek = seq_lseek, |
| 3407 | .release = single_release, | 3475 | .release = tracing_single_release_tr, |
| 3408 | .write = tracing_trace_options_write, | 3476 | .write = tracing_trace_options_write, |
| 3409 | }; | 3477 | }; |
| 3410 | 3478 | ||
| @@ -3892,6 +3960,9 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp) | |||
| 3892 | if (tracing_disabled) | 3960 | if (tracing_disabled) |
| 3893 | return -ENODEV; | 3961 | return -ENODEV; |
| 3894 | 3962 | ||
| 3963 | if (trace_array_get(tr) < 0) | ||
| 3964 | return -ENODEV; | ||
| 3965 | |||
| 3895 | mutex_lock(&trace_types_lock); | 3966 | mutex_lock(&trace_types_lock); |
| 3896 | 3967 | ||
| 3897 | /* create a buffer to store the information to pass to userspace */ | 3968 | /* create a buffer to store the information to pass to userspace */ |
| @@ -3944,6 +4015,7 @@ out: | |||
| 3944 | fail: | 4015 | fail: |
| 3945 | kfree(iter->trace); | 4016 | kfree(iter->trace); |
| 3946 | kfree(iter); | 4017 | kfree(iter); |
| 4018 | __trace_array_put(tr); | ||
| 3947 | mutex_unlock(&trace_types_lock); | 4019 | mutex_unlock(&trace_types_lock); |
| 3948 | return ret; | 4020 | return ret; |
| 3949 | } | 4021 | } |
| @@ -3951,6 +4023,8 @@ fail: | |||
| 3951 | static int tracing_release_pipe(struct inode *inode, struct file *file) | 4023 | static int tracing_release_pipe(struct inode *inode, struct file *file) |
| 3952 | { | 4024 | { |
| 3953 | struct trace_iterator *iter = file->private_data; | 4025 | struct trace_iterator *iter = file->private_data; |
| 4026 | struct trace_cpu *tc = inode->i_private; | ||
| 4027 | struct trace_array *tr = tc->tr; | ||
| 3954 | 4028 | ||
| 3955 | mutex_lock(&trace_types_lock); | 4029 | mutex_lock(&trace_types_lock); |
| 3956 | 4030 | ||
| @@ -3964,6 +4038,8 @@ static int tracing_release_pipe(struct inode *inode, struct file *file) | |||
| 3964 | kfree(iter->trace); | 4038 | kfree(iter->trace); |
| 3965 | kfree(iter); | 4039 | kfree(iter); |
| 3966 | 4040 | ||
| 4041 | trace_array_put(tr); | ||
| 4042 | |||
| 3967 | return 0; | 4043 | return 0; |
| 3968 | } | 4044 | } |
| 3969 | 4045 | ||
| @@ -4421,6 +4497,8 @@ tracing_free_buffer_release(struct inode *inode, struct file *filp) | |||
| 4421 | /* resize the ring buffer to 0 */ | 4497 | /* resize the ring buffer to 0 */ |
| 4422 | tracing_resize_ring_buffer(tr, 0, RING_BUFFER_ALL_CPUS); | 4498 | tracing_resize_ring_buffer(tr, 0, RING_BUFFER_ALL_CPUS); |
| 4423 | 4499 | ||
| 4500 | trace_array_put(tr); | ||
| 4501 | |||
| 4424 | return 0; | 4502 | return 0; |
| 4425 | } | 4503 | } |
| 4426 | 4504 | ||
| @@ -4597,10 +4675,20 @@ static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf, | |||
| 4597 | 4675 | ||
| 4598 | static int tracing_clock_open(struct inode *inode, struct file *file) | 4676 | static int tracing_clock_open(struct inode *inode, struct file *file) |
| 4599 | { | 4677 | { |
| 4678 | struct trace_array *tr = inode->i_private; | ||
| 4679 | int ret; | ||
| 4680 | |||
| 4600 | if (tracing_disabled) | 4681 | if (tracing_disabled) |
| 4601 | return -ENODEV; | 4682 | return -ENODEV; |
| 4602 | 4683 | ||
| 4603 | return single_open(file, tracing_clock_show, inode->i_private); | 4684 | if (trace_array_get(tr)) |
| 4685 | return -ENODEV; | ||
| 4686 | |||
| 4687 | ret = single_open(file, tracing_clock_show, inode->i_private); | ||
| 4688 | if (ret < 0) | ||
| 4689 | trace_array_put(tr); | ||
| 4690 | |||
| 4691 | return ret; | ||
| 4604 | } | 4692 | } |
| 4605 | 4693 | ||
| 4606 | struct ftrace_buffer_info { | 4694 | struct ftrace_buffer_info { |
| @@ -4796,34 +4884,38 @@ static const struct file_operations tracing_pipe_fops = { | |||
| 4796 | }; | 4884 | }; |
| 4797 | 4885 | ||
| 4798 | static const struct file_operations tracing_entries_fops = { | 4886 | static const struct file_operations tracing_entries_fops = { |
| 4799 | .open = tracing_open_generic, | 4887 | .open = tracing_open_generic_tc, |
| 4800 | .read = tracing_entries_read, | 4888 | .read = tracing_entries_read, |
| 4801 | .write = tracing_entries_write, | 4889 | .write = tracing_entries_write, |
| 4802 | .llseek = generic_file_llseek, | 4890 | .llseek = generic_file_llseek, |
| 4891 | .release = tracing_release_generic_tc, | ||
| 4803 | }; | 4892 | }; |
| 4804 | 4893 | ||
| 4805 | static const struct file_operations tracing_total_entries_fops = { | 4894 | static const struct file_operations tracing_total_entries_fops = { |
| 4806 | .open = tracing_open_generic, | 4895 | .open = tracing_open_generic_tr, |
| 4807 | .read = tracing_total_entries_read, | 4896 | .read = tracing_total_entries_read, |
| 4808 | .llseek = generic_file_llseek, | 4897 | .llseek = generic_file_llseek, |
| 4898 | .release = tracing_release_generic_tr, | ||
| 4809 | }; | 4899 | }; |
| 4810 | 4900 | ||
| 4811 | static const struct file_operations tracing_free_buffer_fops = { | 4901 | static const struct file_operations tracing_free_buffer_fops = { |
| 4902 | .open = tracing_open_generic_tr, | ||
| 4812 | .write = tracing_free_buffer_write, | 4903 | .write = tracing_free_buffer_write, |
| 4813 | .release = tracing_free_buffer_release, | 4904 | .release = tracing_free_buffer_release, |
| 4814 | }; | 4905 | }; |
| 4815 | 4906 | ||
| 4816 | static const struct file_operations tracing_mark_fops = { | 4907 | static const struct file_operations tracing_mark_fops = { |
| 4817 | .open = tracing_open_generic, | 4908 | .open = tracing_open_generic_tr, |
| 4818 | .write = tracing_mark_write, | 4909 | .write = tracing_mark_write, |
| 4819 | .llseek = generic_file_llseek, | 4910 | .llseek = generic_file_llseek, |
| 4911 | .release = tracing_release_generic_tr, | ||
| 4820 | }; | 4912 | }; |
| 4821 | 4913 | ||
| 4822 | static const struct file_operations trace_clock_fops = { | 4914 | static const struct file_operations trace_clock_fops = { |
| 4823 | .open = tracing_clock_open, | 4915 | .open = tracing_clock_open, |
| 4824 | .read = seq_read, | 4916 | .read = seq_read, |
| 4825 | .llseek = seq_lseek, | 4917 | .llseek = seq_lseek, |
| 4826 | .release = single_release, | 4918 | .release = tracing_single_release_tr, |
| 4827 | .write = tracing_clock_write, | 4919 | .write = tracing_clock_write, |
| 4828 | }; | 4920 | }; |
| 4829 | 4921 | ||
| @@ -4851,13 +4943,19 @@ static int tracing_buffers_open(struct inode *inode, struct file *filp) | |||
| 4851 | struct trace_cpu *tc = inode->i_private; | 4943 | struct trace_cpu *tc = inode->i_private; |
| 4852 | struct trace_array *tr = tc->tr; | 4944 | struct trace_array *tr = tc->tr; |
| 4853 | struct ftrace_buffer_info *info; | 4945 | struct ftrace_buffer_info *info; |
| 4946 | int ret; | ||
| 4854 | 4947 | ||
| 4855 | if (tracing_disabled) | 4948 | if (tracing_disabled) |
| 4856 | return -ENODEV; | 4949 | return -ENODEV; |
| 4857 | 4950 | ||
| 4951 | if (trace_array_get(tr) < 0) | ||
| 4952 | return -ENODEV; | ||
| 4953 | |||
| 4858 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 4954 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
| 4859 | if (!info) | 4955 | if (!info) { |
| 4956 | trace_array_put(tr); | ||
| 4860 | return -ENOMEM; | 4957 | return -ENOMEM; |
| 4958 | } | ||
| 4861 | 4959 | ||
| 4862 | mutex_lock(&trace_types_lock); | 4960 | mutex_lock(&trace_types_lock); |
| 4863 | 4961 | ||
| @@ -4875,7 +4973,11 @@ static int tracing_buffers_open(struct inode *inode, struct file *filp) | |||
| 4875 | 4973 | ||
| 4876 | mutex_unlock(&trace_types_lock); | 4974 | mutex_unlock(&trace_types_lock); |
| 4877 | 4975 | ||
| 4878 | return nonseekable_open(inode, filp); | 4976 | ret = nonseekable_open(inode, filp); |
| 4977 | if (ret < 0) | ||
| 4978 | trace_array_put(tr); | ||
| 4979 | |||
| 4980 | return ret; | ||
| 4879 | } | 4981 | } |
| 4880 | 4982 | ||
| 4881 | static unsigned int | 4983 | static unsigned int |
| @@ -5765,9 +5867,10 @@ rb_simple_write(struct file *filp, const char __user *ubuf, | |||
| 5765 | } | 5867 | } |
| 5766 | 5868 | ||
| 5767 | static const struct file_operations rb_simple_fops = { | 5869 | static const struct file_operations rb_simple_fops = { |
| 5768 | .open = tracing_open_generic, | 5870 | .open = tracing_open_generic_tr, |
| 5769 | .read = rb_simple_read, | 5871 | .read = rb_simple_read, |
| 5770 | .write = rb_simple_write, | 5872 | .write = rb_simple_write, |
| 5873 | .release = tracing_release_generic_tr, | ||
| 5771 | .llseek = default_llseek, | 5874 | .llseek = default_llseek, |
| 5772 | }; | 5875 | }; |
| 5773 | 5876 | ||
