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: |