Merge branch 'perf/urgent' into perf/core
authorIngo Molnar <mingo@elte.hu>
Thu, 18 Aug 2011 19:56:42 +0000 (21:56 +0200)
committerIngo Molnar <mingo@elte.hu>
Thu, 18 Aug 2011 19:56:47 +0000 (21:56 +0200)
Merge reason: add the latest fixes.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event_amd.c
arch/x86/kernel/cpu/perf_event_intel.c
kernel/events/core.c
kernel/watchdog.c

index 4ee3abf..594d425 100644 (file)
@@ -129,6 +129,8 @@ struct cpu_hw_events {
         * AMD specific bits
         */
        struct amd_nb           *amd_nb;
+
+       void                    *kfree_on_online;
 };
 
 #define __EVENT_CONSTRAINT(c, n, m, w) {\
@@ -1466,10 +1468,12 @@ static int __cpuinit
 x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
 {
        unsigned int cpu = (long)hcpu;
+       struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
        int ret = NOTIFY_OK;
 
        switch (action & ~CPU_TASKS_FROZEN) {
        case CPU_UP_PREPARE:
+               cpuc->kfree_on_online = NULL;
                if (x86_pmu.cpu_prepare)
                        ret = x86_pmu.cpu_prepare(cpu);
                break;
@@ -1479,6 +1483,10 @@ x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
                        x86_pmu.cpu_starting(cpu);
                break;
 
+       case CPU_ONLINE:
+               kfree(cpuc->kfree_on_online);
+               break;
+
        case CPU_DYING:
                if (x86_pmu.cpu_dying)
                        x86_pmu.cpu_dying(cpu);
index 941caa2..ee9436c 100644 (file)
@@ -350,7 +350,7 @@ static void amd_pmu_cpu_starting(int cpu)
                        continue;
 
                if (nb->nb_id == nb_id) {
-                       kfree(cpuc->amd_nb);
+                       cpuc->kfree_on_online = cpuc->amd_nb;
                        cpuc->amd_nb = nb;
                        break;
                }
index f88af2c..3751494 100644 (file)
@@ -1362,7 +1362,7 @@ static void intel_pmu_cpu_starting(int cpu)
 
                pc = per_cpu(cpu_hw_events, i).shared_regs;
                if (pc && pc->core_id == core_id) {
-                       kfree(cpuc->shared_regs);
+                       cpuc->kfree_on_online = cpuc->shared_regs;
                        cpuc->shared_regs = pc;
                        break;
                }
index b8785e2..adc3ef3 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/hardirq.h>
 #include <linux/rculist.h>
 #include <linux/uaccess.h>
+#include <linux/suspend.h>
 #include <linux/syscalls.h>
 #include <linux/anon_inodes.h>
 #include <linux/kernel_stat.h>
@@ -5715,6 +5716,7 @@ struct pmu *perf_init_event(struct perf_event *event)
        pmu = idr_find(&pmu_idr, event->attr.type);
        rcu_read_unlock();
        if (pmu) {
+               event->pmu = pmu;
                ret = pmu->event_init(event);
                if (ret)
                        pmu = ERR_PTR(ret);
@@ -5722,6 +5724,7 @@ struct pmu *perf_init_event(struct perf_event *event)
        }
 
        list_for_each_entry_rcu(pmu, &pmus, entry) {
+               event->pmu = pmu;
                ret = pmu->event_init(event);
                if (!ret)
                        goto unlock;
@@ -5848,8 +5851,6 @@ done:
                return ERR_PTR(err);
        }
 
-       event->pmu = pmu;
-
        if (!event->parent) {
                if (event->attach_state & PERF_ATTACH_TASK)
                        jump_label_inc(&perf_sched_events);
@@ -6809,7 +6810,7 @@ static void __cpuinit perf_event_init_cpu(int cpu)
        struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu);
 
        mutex_lock(&swhash->hlist_mutex);
-       if (swhash->hlist_refcount > 0) {
+       if (swhash->hlist_refcount > 0 && !swhash->swevent_hlist) {
                struct swevent_hlist *hlist;
 
                hlist = kzalloc_node(sizeof(*hlist), GFP_KERNEL, cpu_to_node(cpu));
@@ -6898,7 +6899,14 @@ perf_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
 {
        unsigned int cpu = (long)hcpu;
 
-       switch (action & ~CPU_TASKS_FROZEN) {
+       /*
+        * Ignore suspend/resume action, the perf_pm_notifier will
+        * take care of that.
+        */
+       if (action & CPU_TASKS_FROZEN)
+               return NOTIFY_OK;
+
+       switch (action) {
 
        case CPU_UP_PREPARE:
        case CPU_DOWN_FAILED:
@@ -6917,6 +6925,90 @@ perf_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
        return NOTIFY_OK;
 }
 
+static void perf_pm_resume_cpu(void *unused)
+{
+       struct perf_cpu_context *cpuctx;
+       struct perf_event_context *ctx;
+       struct pmu *pmu;
+       int idx;
+
+       idx = srcu_read_lock(&pmus_srcu);
+       list_for_each_entry_rcu(pmu, &pmus, entry) {
+               cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
+               ctx = cpuctx->task_ctx;
+
+               perf_ctx_lock(cpuctx, ctx);
+               perf_pmu_disable(cpuctx->ctx.pmu);
+
+               cpu_ctx_sched_out(cpuctx, EVENT_ALL);
+               if (ctx)
+                       ctx_sched_out(ctx, cpuctx, EVENT_ALL);
+
+               perf_pmu_enable(cpuctx->ctx.pmu);
+               perf_ctx_unlock(cpuctx, ctx);
+       }
+       srcu_read_unlock(&pmus_srcu, idx);
+}
+
+static void perf_pm_suspend_cpu(void *unused)
+{
+       struct perf_cpu_context *cpuctx;
+       struct perf_event_context *ctx;
+       struct pmu *pmu;
+       int idx;
+
+       idx = srcu_read_lock(&pmus_srcu);
+       list_for_each_entry_rcu(pmu, &pmus, entry) {
+               cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
+               ctx = cpuctx->task_ctx;
+
+               perf_ctx_lock(cpuctx, ctx);
+               perf_pmu_disable(cpuctx->ctx.pmu);
+
+               perf_event_sched_in(cpuctx, ctx, current);
+
+               perf_pmu_enable(cpuctx->ctx.pmu);
+               perf_ctx_unlock(cpuctx, ctx);
+       }
+       srcu_read_unlock(&pmus_srcu, idx);
+}
+
+static int perf_resume(void)
+{
+       get_online_cpus();
+       smp_call_function(perf_pm_resume_cpu, NULL, 1);
+       put_online_cpus();
+
+       return NOTIFY_OK;
+}
+
+static int perf_suspend(void)
+{
+       get_online_cpus();
+       smp_call_function(perf_pm_suspend_cpu, NULL, 1);
+       put_online_cpus();
+
+       return NOTIFY_OK;
+}
+
+static int perf_pm(struct notifier_block *self, unsigned long action, void *ptr)
+{
+       switch (action) {
+       case PM_POST_HIBERNATION:
+       case PM_POST_SUSPEND:
+               return perf_resume();
+       case PM_HIBERNATION_PREPARE:
+       case PM_SUSPEND_PREPARE:
+               return perf_suspend();
+       default:
+               return NOTIFY_DONE;
+       }
+}
+
+static struct notifier_block perf_pm_notifier = {
+       .notifier_call = perf_pm,
+};
+
 void __init perf_event_init(void)
 {
        int ret;
@@ -6931,6 +7023,7 @@ void __init perf_event_init(void)
        perf_tp_register();
        perf_cpu_notifier(perf_cpu_notify);
        register_reboot_notifier(&perf_reboot_notifier);
+       register_pm_notifier(&perf_pm_notifier);
 
        ret = init_hw_breakpoint();
        WARN(ret, "hw_breakpoint initialization failed with: %d", ret);
index 36491cd..e952a13 100644 (file)
@@ -438,7 +438,7 @@ static int watchdog_enable(int cpu)
 
        /* create the watchdog thread */
        if (!p) {
-               p = kthread_create(watchdog, (void *)(unsigned long)cpu, "watchdog/%d", cpu);
+               p = kthread_create_on_node(watchdog, NULL, cpu_to_node(cpu), "watchdog/%d", cpu);
                if (IS_ERR(p)) {
                        printk(KERN_ERR "softlockup watchdog for %i failed\n", cpu);
                        if (!err) {