OSDN Git Service

perf: Provide a separate task context for swevents
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / kernel / perf_event.c
index 7223ea8..357ee8d 100644 (file)
@@ -4709,6 +4709,8 @@ static int perf_swevent_init(struct perf_event *event)
 }
 
 static struct pmu perf_swevent = {
+       .task_ctx_nr    = perf_sw_context,
+
        .event_init     = perf_swevent_init,
        .add            = perf_swevent_add,
        .del            = perf_swevent_del,
@@ -4800,6 +4802,8 @@ static int perf_tp_event_init(struct perf_event *event)
 }
 
 static struct pmu perf_tracepoint = {
+       .task_ctx_nr    = perf_sw_context,
+
        .event_init     = perf_tp_event_init,
        .add            = perf_trace_add,
        .del            = perf_trace_del,
@@ -4988,6 +4992,8 @@ static int cpu_clock_event_init(struct perf_event *event)
 }
 
 static struct pmu perf_cpu_clock = {
+       .task_ctx_nr    = perf_sw_context,
+
        .event_init     = cpu_clock_event_init,
        .add            = cpu_clock_event_add,
        .del            = cpu_clock_event_del,
@@ -5063,6 +5069,8 @@ static int task_clock_event_init(struct perf_event *event)
 }
 
 static struct pmu perf_task_clock = {
+       .task_ctx_nr    = perf_sw_context,
+
        .event_init     = task_clock_event_init,
        .add            = task_clock_event_add,
        .del            = task_clock_event_del,
@@ -5490,6 +5498,7 @@ SYSCALL_DEFINE5(perf_event_open,
        struct perf_event_context *ctx;
        struct file *event_file = NULL;
        struct file *group_file = NULL;
+       struct pmu *pmu;
        int event_fd;
        int fput_needed = 0;
        int err;
@@ -5522,20 +5531,11 @@ SYSCALL_DEFINE5(perf_event_open,
                goto err_fd;
        }
 
-       /*
-        * Get the target context (task or percpu):
-        */
-       ctx = find_get_context(event->pmu, pid, cpu);
-       if (IS_ERR(ctx)) {
-               err = PTR_ERR(ctx);
-               goto err_alloc;
-       }
-
        if (group_fd != -1) {
                group_leader = perf_fget_light(group_fd, &fput_needed);
                if (IS_ERR(group_leader)) {
                        err = PTR_ERR(group_leader);
-                       goto err_context;
+                       goto err_alloc;
                }
                group_file = group_leader->filp;
                if (flags & PERF_FLAG_FD_OUTPUT)
@@ -5545,6 +5545,23 @@ SYSCALL_DEFINE5(perf_event_open,
        }
 
        /*
+        * Special case software events and allow them to be part of
+        * any hardware group.
+        */
+       pmu = event->pmu;
+       if ((pmu->task_ctx_nr == perf_sw_context) && group_leader)
+               pmu = group_leader->pmu;
+
+       /*
+        * Get the target context (task or percpu):
+        */
+       ctx = find_get_context(pmu, pid, cpu);
+       if (IS_ERR(ctx)) {
+               err = PTR_ERR(ctx);
+               goto err_group_fd;
+       }
+
+       /*
         * Look up the group leader (we will attach this event to it):
         */
        if (group_leader) {
@@ -5605,8 +5622,9 @@ SYSCALL_DEFINE5(perf_event_open,
        return event_fd;
 
 err_context:
-       fput_light(group_file, fput_needed);
        put_ctx(ctx);
+err_group_fd:
+       fput_light(group_file, fput_needed);
 err_alloc:
        free_event(event);
 err_fd: