diff options
| -rw-r--r-- | include/linux/perf_event.h | 9 | ||||
| -rw-r--r-- | include/linux/sched.h | 1 | ||||
| -rw-r--r-- | kernel/hw_breakpoint.c | 2 | ||||
| -rw-r--r-- | kernel/perf_event.c | 40 |
4 files changed, 33 insertions, 19 deletions
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 9ecfd856ce6e..c1173520f14d 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
| @@ -952,14 +952,7 @@ extern int perf_event_overflow(struct perf_event *event, int nmi, | |||
| 952 | */ | 952 | */ |
| 953 | static inline int is_software_event(struct perf_event *event) | 953 | static inline int is_software_event(struct perf_event *event) |
| 954 | { | 954 | { |
| 955 | switch (event->attr.type) { | 955 | return event->pmu->task_ctx_nr == perf_sw_context; |
| 956 | case PERF_TYPE_SOFTWARE: | ||
| 957 | case PERF_TYPE_TRACEPOINT: | ||
| 958 | /* for now the breakpoint stuff also works as software event */ | ||
| 959 | case PERF_TYPE_BREAKPOINT: | ||
| 960 | return 1; | ||
| 961 | } | ||
| 962 | return 0; | ||
| 963 | } | 956 | } |
| 964 | 957 | ||
| 965 | extern atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX]; | 958 | extern atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX]; |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 89d6023c6f82..eb3c1ceec06e 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
| @@ -1163,6 +1163,7 @@ struct rcu_node; | |||
| 1163 | enum perf_event_task_context { | 1163 | enum perf_event_task_context { |
| 1164 | perf_invalid_context = -1, | 1164 | perf_invalid_context = -1, |
| 1165 | perf_hw_context = 0, | 1165 | perf_hw_context = 0, |
| 1166 | perf_sw_context, | ||
| 1166 | perf_nr_task_contexts, | 1167 | perf_nr_task_contexts, |
| 1167 | }; | 1168 | }; |
| 1168 | 1169 | ||
diff --git a/kernel/hw_breakpoint.c b/kernel/hw_breakpoint.c index 6f150095cafe..3b2aaffb65f0 100644 --- a/kernel/hw_breakpoint.c +++ b/kernel/hw_breakpoint.c | |||
| @@ -610,6 +610,8 @@ static void hw_breakpoint_stop(struct perf_event *bp, int flags) | |||
| 610 | } | 610 | } |
| 611 | 611 | ||
| 612 | static struct pmu perf_breakpoint = { | 612 | static struct pmu perf_breakpoint = { |
| 613 | .task_ctx_nr = perf_sw_context, /* could eventually get its own */ | ||
| 614 | |||
| 613 | .event_init = hw_breakpoint_event_init, | 615 | .event_init = hw_breakpoint_event_init, |
| 614 | .add = hw_breakpoint_add, | 616 | .add = hw_breakpoint_add, |
| 615 | .del = hw_breakpoint_del, | 617 | .del = hw_breakpoint_del, |
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 7223ea875861..357ee8d5e8ae 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
| @@ -4709,6 +4709,8 @@ static int perf_swevent_init(struct perf_event *event) | |||
| 4709 | } | 4709 | } |
| 4710 | 4710 | ||
| 4711 | static struct pmu perf_swevent = { | 4711 | static struct pmu perf_swevent = { |
| 4712 | .task_ctx_nr = perf_sw_context, | ||
| 4713 | |||
| 4712 | .event_init = perf_swevent_init, | 4714 | .event_init = perf_swevent_init, |
| 4713 | .add = perf_swevent_add, | 4715 | .add = perf_swevent_add, |
| 4714 | .del = perf_swevent_del, | 4716 | .del = perf_swevent_del, |
| @@ -4800,6 +4802,8 @@ static int perf_tp_event_init(struct perf_event *event) | |||
| 4800 | } | 4802 | } |
| 4801 | 4803 | ||
| 4802 | static struct pmu perf_tracepoint = { | 4804 | static struct pmu perf_tracepoint = { |
| 4805 | .task_ctx_nr = perf_sw_context, | ||
| 4806 | |||
| 4803 | .event_init = perf_tp_event_init, | 4807 | .event_init = perf_tp_event_init, |
| 4804 | .add = perf_trace_add, | 4808 | .add = perf_trace_add, |
| 4805 | .del = perf_trace_del, | 4809 | .del = perf_trace_del, |
| @@ -4988,6 +4992,8 @@ static int cpu_clock_event_init(struct perf_event *event) | |||
| 4988 | } | 4992 | } |
| 4989 | 4993 | ||
| 4990 | static struct pmu perf_cpu_clock = { | 4994 | static struct pmu perf_cpu_clock = { |
| 4995 | .task_ctx_nr = perf_sw_context, | ||
| 4996 | |||
| 4991 | .event_init = cpu_clock_event_init, | 4997 | .event_init = cpu_clock_event_init, |
| 4992 | .add = cpu_clock_event_add, | 4998 | .add = cpu_clock_event_add, |
| 4993 | .del = cpu_clock_event_del, | 4999 | .del = cpu_clock_event_del, |
| @@ -5063,6 +5069,8 @@ static int task_clock_event_init(struct perf_event *event) | |||
| 5063 | } | 5069 | } |
| 5064 | 5070 | ||
| 5065 | static struct pmu perf_task_clock = { | 5071 | static struct pmu perf_task_clock = { |
| 5072 | .task_ctx_nr = perf_sw_context, | ||
| 5073 | |||
| 5066 | .event_init = task_clock_event_init, | 5074 | .event_init = task_clock_event_init, |
| 5067 | .add = task_clock_event_add, | 5075 | .add = task_clock_event_add, |
| 5068 | .del = task_clock_event_del, | 5076 | .del = task_clock_event_del, |
| @@ -5490,6 +5498,7 @@ SYSCALL_DEFINE5(perf_event_open, | |||
| 5490 | struct perf_event_context *ctx; | 5498 | struct perf_event_context *ctx; |
| 5491 | struct file *event_file = NULL; | 5499 | struct file *event_file = NULL; |
| 5492 | struct file *group_file = NULL; | 5500 | struct file *group_file = NULL; |
| 5501 | struct pmu *pmu; | ||
| 5493 | int event_fd; | 5502 | int event_fd; |
| 5494 | int fput_needed = 0; | 5503 | int fput_needed = 0; |
| 5495 | int err; | 5504 | int err; |
| @@ -5522,20 +5531,11 @@ SYSCALL_DEFINE5(perf_event_open, | |||
| 5522 | goto err_fd; | 5531 | goto err_fd; |
| 5523 | } | 5532 | } |
| 5524 | 5533 | ||
| 5525 | /* | ||
| 5526 | * Get the target context (task or percpu): | ||
| 5527 | */ | ||
| 5528 | ctx = find_get_context(event->pmu, pid, cpu); | ||
| 5529 | if (IS_ERR(ctx)) { | ||
| 5530 | err = PTR_ERR(ctx); | ||
| 5531 | goto err_alloc; | ||
| 5532 | } | ||
| 5533 | |||
| 5534 | if (group_fd != -1) { | 5534 | if (group_fd != -1) { |
| 5535 | group_leader = perf_fget_light(group_fd, &fput_needed); | 5535 | group_leader = perf_fget_light(group_fd, &fput_needed); |
| 5536 | if (IS_ERR(group_leader)) { | 5536 | if (IS_ERR(group_leader)) { |
| 5537 | err = PTR_ERR(group_leader); | 5537 | err = PTR_ERR(group_leader); |
| 5538 | goto err_context; | 5538 | goto err_alloc; |
| 5539 | } | 5539 | } |
| 5540 | group_file = group_leader->filp; | 5540 | group_file = group_leader->filp; |
| 5541 | if (flags & PERF_FLAG_FD_OUTPUT) | 5541 | if (flags & PERF_FLAG_FD_OUTPUT) |
| @@ -5545,6 +5545,23 @@ SYSCALL_DEFINE5(perf_event_open, | |||
| 5545 | } | 5545 | } |
| 5546 | 5546 | ||
| 5547 | /* | 5547 | /* |
| 5548 | * Special case software events and allow them to be part of | ||
| 5549 | * any hardware group. | ||
| 5550 | */ | ||
| 5551 | pmu = event->pmu; | ||
| 5552 | if ((pmu->task_ctx_nr == perf_sw_context) && group_leader) | ||
| 5553 | pmu = group_leader->pmu; | ||
| 5554 | |||
| 5555 | /* | ||
| 5556 | * Get the target context (task or percpu): | ||
| 5557 | */ | ||
| 5558 | ctx = find_get_context(pmu, pid, cpu); | ||
| 5559 | if (IS_ERR(ctx)) { | ||
| 5560 | err = PTR_ERR(ctx); | ||
| 5561 | goto err_group_fd; | ||
| 5562 | } | ||
| 5563 | |||
| 5564 | /* | ||
| 5548 | * Look up the group leader (we will attach this event to it): | 5565 | * Look up the group leader (we will attach this event to it): |
| 5549 | */ | 5566 | */ |
| 5550 | if (group_leader) { | 5567 | if (group_leader) { |
| @@ -5605,8 +5622,9 @@ SYSCALL_DEFINE5(perf_event_open, | |||
| 5605 | return event_fd; | 5622 | return event_fd; |
| 5606 | 5623 | ||
| 5607 | err_context: | 5624 | err_context: |
| 5608 | fput_light(group_file, fput_needed); | ||
| 5609 | put_ctx(ctx); | 5625 | put_ctx(ctx); |
| 5626 | err_group_fd: | ||
| 5627 | fput_light(group_file, fput_needed); | ||
| 5610 | err_alloc: | 5628 | err_alloc: |
| 5611 | free_event(event); | 5629 | free_event(event); |
| 5612 | err_fd: | 5630 | err_fd: |
