aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexei Starovoitov <alexei.starovoitov@gmail.com>2016-01-25 23:59:49 -0500
committerIngo Molnar <mingo@kernel.org>2016-01-29 02:35:25 -0500
commite03e7ee34fdd1c3ef494949a75cb8c61c7265fa9 (patch)
tree17835d21a367a7b6cea78c93c076e7f65843767f
parent828b6f0e26170938d617e99a17177453be4d77a3 (diff)
perf/bpf: Convert perf_event_array to use struct file
Robustify refcounting. Signed-off-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Arnaldo Carvalho de Melo <acme@infradead.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Daniel Borkmann <daniel@iogearbox.net> Cc: David Ahern <dsahern@gmail.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Vince Weaver <vincent.weaver@maine.edu> Cc: Wang Nan <wangnan0@huawei.com> Cc: vince@deater.net Link: http://lkml.kernel.org/r/20160126045947.GA40151@ast-mbp.thefacebook.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--include/linux/perf_event.h4
-rw-r--r--kernel/bpf/arraymap.c21
-rw-r--r--kernel/events/core.c21
-rw-r--r--kernel/trace/bpf_trace.c14
4 files changed, 33 insertions, 27 deletions
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 6612732d8fd0..4f90434b8d64 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -729,7 +729,7 @@ extern int perf_event_init_task(struct task_struct *child);
729extern void perf_event_exit_task(struct task_struct *child); 729extern void perf_event_exit_task(struct task_struct *child);
730extern void perf_event_free_task(struct task_struct *task); 730extern void perf_event_free_task(struct task_struct *task);
731extern void perf_event_delayed_put(struct task_struct *task); 731extern void perf_event_delayed_put(struct task_struct *task);
732extern struct perf_event *perf_event_get(unsigned int fd); 732extern struct file *perf_event_get(unsigned int fd);
733extern const struct perf_event_attr *perf_event_attrs(struct perf_event *event); 733extern const struct perf_event_attr *perf_event_attrs(struct perf_event *event);
734extern void perf_event_print_debug(void); 734extern void perf_event_print_debug(void);
735extern void perf_pmu_disable(struct pmu *pmu); 735extern void perf_pmu_disable(struct pmu *pmu);
@@ -1070,7 +1070,7 @@ static inline int perf_event_init_task(struct task_struct *child) { return 0; }
1070static inline void perf_event_exit_task(struct task_struct *child) { } 1070static inline void perf_event_exit_task(struct task_struct *child) { }
1071static inline void perf_event_free_task(struct task_struct *task) { } 1071static inline void perf_event_free_task(struct task_struct *task) { }
1072static inline void perf_event_delayed_put(struct task_struct *task) { } 1072static inline void perf_event_delayed_put(struct task_struct *task) { }
1073static inline struct perf_event *perf_event_get(unsigned int fd) { return ERR_PTR(-EINVAL); } 1073static inline struct file *perf_event_get(unsigned int fd) { return ERR_PTR(-EINVAL); }
1074static inline const struct perf_event_attr *perf_event_attrs(struct perf_event *event) 1074static inline const struct perf_event_attr *perf_event_attrs(struct perf_event *event)
1075{ 1075{
1076 return ERR_PTR(-EINVAL); 1076 return ERR_PTR(-EINVAL);
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index b0799bced518..89ebbc4d1164 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -291,10 +291,13 @@ static void *perf_event_fd_array_get_ptr(struct bpf_map *map, int fd)
291{ 291{
292 struct perf_event *event; 292 struct perf_event *event;
293 const struct perf_event_attr *attr; 293 const struct perf_event_attr *attr;
294 struct file *file;
294 295
295 event = perf_event_get(fd); 296 file = perf_event_get(fd);
296 if (IS_ERR(event)) 297 if (IS_ERR(file))
297 return event; 298 return file;
299
300 event = file->private_data;
298 301
299 attr = perf_event_attrs(event); 302 attr = perf_event_attrs(event);
300 if (IS_ERR(attr)) 303 if (IS_ERR(attr))
@@ -304,24 +307,22 @@ static void *perf_event_fd_array_get_ptr(struct bpf_map *map, int fd)
304 goto err; 307 goto err;
305 308
306 if (attr->type == PERF_TYPE_RAW) 309 if (attr->type == PERF_TYPE_RAW)
307 return event; 310 return file;
308 311
309 if (attr->type == PERF_TYPE_HARDWARE) 312 if (attr->type == PERF_TYPE_HARDWARE)
310 return event; 313 return file;
311 314
312 if (attr->type == PERF_TYPE_SOFTWARE && 315 if (attr->type == PERF_TYPE_SOFTWARE &&
313 attr->config == PERF_COUNT_SW_BPF_OUTPUT) 316 attr->config == PERF_COUNT_SW_BPF_OUTPUT)
314 return event; 317 return file;
315err: 318err:
316 perf_event_release_kernel(event); 319 fput(file);
317 return ERR_PTR(-EINVAL); 320 return ERR_PTR(-EINVAL);
318} 321}
319 322
320static void perf_event_fd_array_put_ptr(void *ptr) 323static void perf_event_fd_array_put_ptr(void *ptr)
321{ 324{
322 struct perf_event *event = ptr; 325 fput((struct file *)ptr);
323
324 perf_event_release_kernel(event);
325} 326}
326 327
327static const struct bpf_map_ops perf_event_array_ops = { 328static const struct bpf_map_ops perf_event_array_ops = {
diff --git a/kernel/events/core.c b/kernel/events/core.c
index fe97f95f204e..eb44730afea5 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -8916,21 +8916,20 @@ void perf_event_delayed_put(struct task_struct *task)
8916 WARN_ON_ONCE(task->perf_event_ctxp[ctxn]); 8916 WARN_ON_ONCE(task->perf_event_ctxp[ctxn]);
8917} 8917}
8918 8918
8919struct perf_event *perf_event_get(unsigned int fd) 8919struct file *perf_event_get(unsigned int fd)
8920{ 8920{
8921 int err; 8921 struct file *file;
8922 struct fd f;
8923 struct perf_event *event;
8924 8922
8925 err = perf_fget_light(fd, &f); 8923 file = fget_raw(fd);
8926 if (err) 8924 if (!file)
8927 return ERR_PTR(err); 8925 return ERR_PTR(-EBADF);
8928 8926
8929 event = f.file->private_data; 8927 if (file->f_op != &perf_fops) {
8930 atomic_long_inc(&event->refcount); 8928 fput(file);
8931 fdput(f); 8929 return ERR_PTR(-EBADF);
8930 }
8932 8931
8933 return event; 8932 return file;
8934} 8933}
8935 8934
8936const struct perf_event_attr *perf_event_attrs(struct perf_event *event) 8935const struct perf_event_attr *perf_event_attrs(struct perf_event *event)
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 45dd798bcd37..326a75e884db 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -191,14 +191,17 @@ static u64 bpf_perf_event_read(u64 r1, u64 index, u64 r3, u64 r4, u64 r5)
191 struct bpf_map *map = (struct bpf_map *) (unsigned long) r1; 191 struct bpf_map *map = (struct bpf_map *) (unsigned long) r1;
192 struct bpf_array *array = container_of(map, struct bpf_array, map); 192 struct bpf_array *array = container_of(map, struct bpf_array, map);
193 struct perf_event *event; 193 struct perf_event *event;
194 struct file *file;
194 195
195 if (unlikely(index >= array->map.max_entries)) 196 if (unlikely(index >= array->map.max_entries))
196 return -E2BIG; 197 return -E2BIG;
197 198
198 event = (struct perf_event *)array->ptrs[index]; 199 file = (struct file *)array->ptrs[index];
199 if (!event) 200 if (unlikely(!file))
200 return -ENOENT; 201 return -ENOENT;
201 202
203 event = file->private_data;
204
202 /* make sure event is local and doesn't have pmu::count */ 205 /* make sure event is local and doesn't have pmu::count */
203 if (event->oncpu != smp_processor_id() || 206 if (event->oncpu != smp_processor_id() ||
204 event->pmu->count) 207 event->pmu->count)
@@ -228,6 +231,7 @@ static u64 bpf_perf_event_output(u64 r1, u64 r2, u64 index, u64 r4, u64 size)
228 void *data = (void *) (long) r4; 231 void *data = (void *) (long) r4;
229 struct perf_sample_data sample_data; 232 struct perf_sample_data sample_data;
230 struct perf_event *event; 233 struct perf_event *event;
234 struct file *file;
231 struct perf_raw_record raw = { 235 struct perf_raw_record raw = {
232 .size = size, 236 .size = size,
233 .data = data, 237 .data = data,
@@ -236,10 +240,12 @@ static u64 bpf_perf_event_output(u64 r1, u64 r2, u64 index, u64 r4, u64 size)
236 if (unlikely(index >= array->map.max_entries)) 240 if (unlikely(index >= array->map.max_entries))
237 return -E2BIG; 241 return -E2BIG;
238 242
239 event = (struct perf_event *)array->ptrs[index]; 243 file = (struct file *)array->ptrs[index];
240 if (unlikely(!event)) 244 if (unlikely(!file))
241 return -ENOENT; 245 return -ENOENT;
242 246
247 event = file->private_data;
248
243 if (unlikely(event->attr.type != PERF_TYPE_SOFTWARE || 249 if (unlikely(event->attr.type != PERF_TYPE_SOFTWARE ||
244 event->attr.config != PERF_COUNT_SW_BPF_OUTPUT)) 250 event->attr.config != PERF_COUNT_SW_BPF_OUTPUT))
245 return -EINVAL; 251 return -EINVAL;