]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - kernel/events/core.c
cgroup: improve css_from_dir() into css_tryget_from_dir()
[karo-tx-linux.git] / kernel / events / core.c
index 72348dc192c11e7a85560b67bc792415d969e22f..a3c3ab50271af3453845c1bb925fe03e811e0b1b 100644 (file)
@@ -119,7 +119,8 @@ static int cpu_function_call(int cpu, int (*func) (void *info), void *info)
 
 #define PERF_FLAG_ALL (PERF_FLAG_FD_NO_GROUP |\
                       PERF_FLAG_FD_OUTPUT  |\
-                      PERF_FLAG_PID_CGROUP)
+                      PERF_FLAG_PID_CGROUP |\
+                      PERF_FLAG_FD_CLOEXEC)
 
 /*
  * branch priv levels that need permission checks
@@ -341,7 +342,7 @@ struct perf_cgroup {
 static inline struct perf_cgroup *
 perf_cgroup_from_task(struct task_struct *task)
 {
-       return container_of(task_css(task, perf_subsys_id),
+       return container_of(task_css(task, perf_event_cgrp_id),
                            struct perf_cgroup, css);
 }
 
@@ -369,11 +370,6 @@ perf_cgroup_match(struct perf_event *event)
                                    event->cgrp->css.cgroup);
 }
 
-static inline bool perf_tryget_cgroup(struct perf_event *event)
-{
-       return css_tryget(&event->cgrp->css);
-}
-
 static inline void perf_put_cgroup(struct perf_event *event)
 {
        css_put(&event->cgrp->css);
@@ -592,9 +588,7 @@ static inline int perf_cgroup_connect(int fd, struct perf_event *event,
        if (!f.file)
                return -EBADF;
 
-       rcu_read_lock();
-
-       css = css_from_dir(f.file->f_dentry, &perf_subsys);
+       css = css_tryget_from_dir(f.file->f_dentry, &perf_event_cgrp_subsys);
        if (IS_ERR(css)) {
                ret = PTR_ERR(css);
                goto out;
@@ -603,13 +597,6 @@ static inline int perf_cgroup_connect(int fd, struct perf_event *event,
        cgrp = container_of(css, struct perf_cgroup, css);
        event->cgrp = cgrp;
 
-       /* must be done before we fput() the file */
-       if (!perf_tryget_cgroup(event)) {
-               event->cgrp = NULL;
-               ret = -ENOENT;
-               goto out;
-       }
-
        /*
         * all events in a group must monitor
         * the same cgroup because a task belongs
@@ -620,7 +607,6 @@ static inline int perf_cgroup_connect(int fd, struct perf_event *event,
                ret = -EINVAL;
        }
 out:
-       rcu_read_unlock();
        fdput(f);
        return ret;
 }
@@ -1396,6 +1382,8 @@ event_sched_out(struct perf_event *event,
        if (event->state != PERF_EVENT_STATE_ACTIVE)
                return;
 
+       perf_pmu_disable(event->pmu);
+
        event->state = PERF_EVENT_STATE_INACTIVE;
        if (event->pending_disable) {
                event->pending_disable = 0;
@@ -1412,6 +1400,8 @@ event_sched_out(struct perf_event *event,
                ctx->nr_freq--;
        if (event->attr.exclusive || !cpuctx->active_oncpu)
                cpuctx->exclusive = 0;
+
+       perf_pmu_enable(event->pmu);
 }
 
 static void
@@ -1652,6 +1642,7 @@ event_sched_in(struct perf_event *event,
                 struct perf_event_context *ctx)
 {
        u64 tstamp = perf_event_time(event);
+       int ret = 0;
 
        if (event->state <= PERF_EVENT_STATE_OFF)
                return 0;
@@ -1674,10 +1665,13 @@ event_sched_in(struct perf_event *event,
         */
        smp_wmb();
 
+       perf_pmu_disable(event->pmu);
+
        if (event->pmu->add(event, PERF_EF_START)) {
                event->state = PERF_EVENT_STATE_INACTIVE;
                event->oncpu = -1;
-               return -EAGAIN;
+               ret = -EAGAIN;
+               goto out;
        }
 
        event->tstamp_running += tstamp - event->tstamp_stopped;
@@ -1693,7 +1687,10 @@ event_sched_in(struct perf_event *event,
        if (event->attr.exclusive)
                cpuctx->exclusive = 1;
 
-       return 0;
+out:
+       perf_pmu_enable(event->pmu);
+
+       return ret;
 }
 
 static int
@@ -2743,6 +2740,8 @@ static void perf_adjust_freq_unthr_context(struct perf_event_context *ctx,
                if (!event_filter_match(event))
                        continue;
 
+               perf_pmu_disable(event->pmu);
+
                hwc = &event->hw;
 
                if (hwc->interrupts == MAX_INTERRUPTS) {
@@ -2752,7 +2751,7 @@ static void perf_adjust_freq_unthr_context(struct perf_event_context *ctx,
                }
 
                if (!event->attr.freq || !event->attr.sample_freq)
-                       continue;
+                       goto next;
 
                /*
                 * stop the event and update event->count
@@ -2774,6 +2773,8 @@ static void perf_adjust_freq_unthr_context(struct perf_event_context *ctx,
                        perf_adjust_period(event, period, delta, false);
 
                event->pmu->start(event, delta > 0 ? PERF_EF_RELOAD : 0);
+       next:
+               perf_pmu_enable(event->pmu);
        }
 
        perf_pmu_enable(ctx->pmu);
@@ -3527,7 +3528,7 @@ static void perf_event_for_each(struct perf_event *event,
 static int perf_event_period(struct perf_event *event, u64 __user *arg)
 {
        struct perf_event_context *ctx = event->ctx;
-       int ret = 0;
+       int ret = 0, active;
        u64 value;
 
        if (!is_sampling_event(event))
@@ -3551,6 +3552,20 @@ static int perf_event_period(struct perf_event *event, u64 __user *arg)
                event->attr.sample_period = value;
                event->hw.sample_period = value;
        }
+
+       active = (event->state == PERF_EVENT_STATE_ACTIVE);
+       if (active) {
+               perf_pmu_disable(ctx->pmu);
+               event->pmu->stop(event, PERF_EF_UPDATE);
+       }
+
+       local64_set(&event->hw.period_left, 0);
+
+       if (active) {
+               event->pmu->start(event, PERF_EF_RELOAD);
+               perf_pmu_enable(ctx->pmu);
+       }
+
 unlock:
        raw_spin_unlock_irq(&ctx->lock);
 
@@ -6655,6 +6670,9 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
        INIT_LIST_HEAD(&event->event_entry);
        INIT_LIST_HEAD(&event->sibling_list);
        INIT_LIST_HEAD(&event->rb_entry);
+       INIT_LIST_HEAD(&event->active_entry);
+       INIT_HLIST_NODE(&event->hlist_entry);
+
 
        init_waitqueue_head(&event->waitq);
        init_irq_work(&event->pending, perf_pending_event);
@@ -6965,6 +6983,7 @@ SYSCALL_DEFINE5(perf_event_open,
        int event_fd;
        int move_group = 0;
        int err;
+       int f_flags = O_RDWR;
 
        /* for future expandability... */
        if (flags & ~PERF_FLAG_ALL)
@@ -6993,7 +7012,10 @@ SYSCALL_DEFINE5(perf_event_open,
        if ((flags & PERF_FLAG_PID_CGROUP) && (pid == -1 || cpu == -1))
                return -EINVAL;
 
-       event_fd = get_unused_fd();
+       if (flags & PERF_FLAG_FD_CLOEXEC)
+               f_flags |= O_CLOEXEC;
+
+       event_fd = get_unused_fd_flags(f_flags);
        if (event_fd < 0)
                return event_fd;
 
@@ -7115,7 +7137,8 @@ SYSCALL_DEFINE5(perf_event_open,
                        goto err_context;
        }
 
-       event_file = anon_inode_getfile("[perf_event]", &perf_fops, event, O_RDWR);
+       event_file = anon_inode_getfile("[perf_event]", &perf_fops, event,
+                                       f_flags);
        if (IS_ERR(event_file)) {
                err = PTR_ERR(event_file);
                goto err_context;
@@ -8017,9 +8040,7 @@ static void perf_cgroup_exit(struct cgroup_subsys_state *css,
        task_function_call(task, __perf_cgroup_move, task);
 }
 
-struct cgroup_subsys perf_subsys = {
-       .name           = "perf_event",
-       .subsys_id      = perf_subsys_id,
+struct cgroup_subsys perf_event_cgrp_subsys = {
        .css_alloc      = perf_cgroup_css_alloc,
        .css_free       = perf_cgroup_css_free,
        .exit           = perf_cgroup_exit,