Merge commit '8700c95adb03' into timers/nohz
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / kernel / events / core.c
index ddb993b52190e9504b2b4505ec263034eb65801c..6b41c1899a8b00acc0ca48ae30b0e8dfbdd2ad9d 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/ftrace_event.h>
 #include <linux/hw_breakpoint.h>
 #include <linux/mm_types.h>
+#include <linux/cgroup.h>
 
 #include "internal.h"
 
@@ -234,6 +235,20 @@ static void perf_ctx_unlock(struct perf_cpu_context *cpuctx,
 
 #ifdef CONFIG_CGROUP_PERF
 
+/*
+ * perf_cgroup_info keeps track of time_enabled for a cgroup.
+ * This is a per-cpu dynamically allocated data structure.
+ */
+struct perf_cgroup_info {
+       u64                             time;
+       u64                             timestamp;
+};
+
+struct perf_cgroup {
+       struct cgroup_subsys_state      css;
+       struct perf_cgroup_info __percpu *info;
+};
+
 /*
  * Must ensure cgroup is pinned (css_get) before calling
  * this function. In other words, we cannot call this function
@@ -252,7 +267,22 @@ perf_cgroup_match(struct perf_event *event)
        struct perf_event_context *ctx = event->ctx;
        struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
 
-       return !event->cgrp || event->cgrp == cpuctx->cgrp;
+       /* @event doesn't care about cgroup */
+       if (!event->cgrp)
+               return true;
+
+       /* wants specific cgroup scope but @cpuctx isn't associated with any */
+       if (!cpuctx->cgrp)
+               return false;
+
+       /*
+        * Cgroup scoping is recursive.  An event enabled for a cgroup is
+        * also enabled for all its descendant cgroups.  If @cpuctx's
+        * cgroup is a descendant of @event's (the test covers identity
+        * case), it's a match.
+        */
+       return cgroup_is_descendant(cpuctx->cgrp->css.cgroup,
+                                   event->cgrp->css.cgroup);
 }
 
 static inline bool perf_tryget_cgroup(struct perf_event *event)
@@ -966,9 +996,15 @@ static void perf_event__header_size(struct perf_event *event)
        if (sample_type & PERF_SAMPLE_PERIOD)
                size += sizeof(data->period);
 
+       if (sample_type & PERF_SAMPLE_WEIGHT)
+               size += sizeof(data->weight);
+
        if (sample_type & PERF_SAMPLE_READ)
                size += event->read_size;
 
+       if (sample_type & PERF_SAMPLE_DATA_SRC)
+               size += sizeof(data->data_src.val);
+
        event->header_size = size;
 }
 
@@ -4193,6 +4229,12 @@ void perf_output_sample(struct perf_output_handle *handle,
                perf_output_sample_ustack(handle,
                                          data->stack_user_size,
                                          data->regs_user.regs);
+
+       if (sample_type & PERF_SAMPLE_WEIGHT)
+               perf_output_put(handle, data->weight);
+
+       if (sample_type & PERF_SAMPLE_DATA_SRC)
+               perf_output_put(handle, data->data_src.val);
 }
 
 void perf_prepare_sample(struct perf_event_header *header,
@@ -4449,12 +4491,15 @@ static void perf_event_task_event(struct perf_task_event *task_event)
                        if (ctxn < 0)
                                goto next;
                        ctx = rcu_dereference(current->perf_event_ctxp[ctxn]);
+                       if (ctx)
+                               perf_event_task_ctx(ctx, task_event);
                }
-               if (ctx)
-                       perf_event_task_ctx(ctx, task_event);
 next:
                put_cpu_ptr(pmu->pmu_cpu_context);
        }
+       if (task_event->task_ctx)
+               perf_event_task_ctx(task_event->task_ctx, task_event);
+
        rcu_read_unlock();
 }
 
@@ -4608,6 +4653,7 @@ void perf_event_comm(struct task_struct *task)
        struct perf_event_context *ctx;
        int ctxn;
 
+       rcu_read_lock();
        for_each_task_context_nr(ctxn) {
                ctx = task->perf_event_ctxp[ctxn];
                if (!ctx)
@@ -4615,6 +4661,7 @@ void perf_event_comm(struct task_struct *task)
 
                perf_event_enable_on_exec(ctx);
        }
+       rcu_read_unlock();
 
        if (!atomic_read(&nr_comm_events))
                return;
@@ -4749,7 +4796,8 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
        } else {
                if (arch_vma_name(mmap_event->vma)) {
                        name = strncpy(tmp, arch_vma_name(mmap_event->vma),
-                                      sizeof(tmp));
+                                      sizeof(tmp) - 1);
+                       tmp[sizeof(tmp) - 1] = '\0';
                        goto got_name;
                }
 
@@ -4776,6 +4824,9 @@ got_name:
        mmap_event->file_name = name;
        mmap_event->file_size = size;
 
+       if (!(vma->vm_flags & VM_EXEC))
+               mmap_event->event_id.header.misc |= PERF_RECORD_MISC_MMAP_DATA;
+
        mmap_event->event_id.header.size = sizeof(mmap_event->event_id) + size;
 
        rcu_read_lock();
@@ -5342,7 +5393,7 @@ static void sw_perf_event_destroy(struct perf_event *event)
 
 static int perf_swevent_init(struct perf_event *event)
 {
-       int event_id = event->attr.config;
+       u64 event_id = event->attr.config;
 
        if (event->attr.type != PERF_TYPE_SOFTWARE)
                return -ENOENT;
@@ -5662,6 +5713,7 @@ static void perf_swevent_init_hrtimer(struct perf_event *event)
                event->attr.sample_period = NSEC_PER_SEC / freq;
                hwc->sample_period = event->attr.sample_period;
                local64_set(&hwc->period_left, hwc->sample_period);
+               hwc->last_period = hwc->sample_period;
                event->attr.freq = 0;
        }
 }
@@ -5997,6 +6049,7 @@ skip_type:
        if (pmu->pmu_cpu_context)
                goto got_cpu_context;
 
+       ret = -ENOMEM;
        pmu->pmu_cpu_context = alloc_percpu(struct perf_cpu_context);
        if (!pmu->pmu_cpu_context)
                goto free_dev;
@@ -7524,12 +7577,5 @@ struct cgroup_subsys perf_subsys = {
        .css_free       = perf_cgroup_css_free,
        .exit           = perf_cgroup_exit,
        .attach         = perf_cgroup_attach,
-
-       /*
-        * perf_event cgroup doesn't handle nesting correctly.
-        * ctx->nr_cgroups adjustments should be propagated through the
-        * cgroup hierarchy.  Fix it and remove the following.
-        */
-       .broken_hierarchy = true,
 };
 #endif /* CONFIG_CGROUP_PERF */