Patches contributed by Eötvös Lorand University


commit 79202ba9ff8cf570a75596f42e011167734d1c4b
Author: Ingo Molnar <mingo@elte.hu>
Date:   Tue May 26 08:10:00 2009 +0200

    perf_counter, x86: Fix APIC NMI programming
    
    My Nehalem box locks up in certain situations (with an
    always-asserted NMI causing a lockup) if the PMU LVT
    entry is programmed between NMI and IRQ mode with a
    high frequency.
    
    Standardize exlusively on NMIs instead.
    
    [ Impact: fix lockup ]
    
    Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
    Cc: Mike Galbraith <efault@gmx.de>
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
    Cc: Marcelo Tosatti <mtosatti@redhat.com>
    Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: John Kacur <jkacur@redhat.com>
    LKML-Reference: <new-submission>
    Signed-off-by: Ingo Molnar <mingo@elte.hu>

diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c
index 189bf9d7cdab..ece3813c7a3c 100644
--- a/arch/x86/kernel/cpu/perf_counter.c
+++ b/arch/x86/kernel/cpu/perf_counter.c
@@ -285,14 +285,10 @@ static int __hw_perf_counter_init(struct perf_counter *counter)
 		hwc->config |= ARCH_PERFMON_EVENTSEL_OS;
 
 	/*
-	 * If privileged enough, allow NMI events:
+	 * Use NMI events all the time:
 	 */
-	hwc->nmi = 0;
-	if (hw_event->nmi) {
-		if (sysctl_perf_counter_priv && !capable(CAP_SYS_ADMIN))
-			return -EACCES;
-		hwc->nmi = 1;
-	}
+	hwc->nmi	= 1;
+	hw_event->nmi	= 1;
 
 	if (!hwc->irq_period)
 		hwc->irq_period = x86_pmu.max_period;
@@ -553,9 +549,6 @@ fixed_mode_idx(struct perf_counter *counter, struct hw_perf_counter *hwc)
 	if (!x86_pmu.num_counters_fixed)
 		return -1;
 
-	if (unlikely(hwc->nmi))
-		return -1;
-
 	event = hwc->config & ARCH_PERFMON_EVENT_MASK;
 
 	if (unlikely(event == x86_pmu.event_map(PERF_COUNT_INSTRUCTIONS)))
@@ -806,9 +799,6 @@ static int amd_pmu_handle_irq(struct pt_regs *regs, int nmi)
 		counter = cpuc->counters[idx];
 		hwc = &counter->hw;
 
-		if (counter->hw_event.nmi != nmi)
-			continue;
-
 		val = x86_perf_counter_update(counter, hwc, idx);
 		if (val & (1ULL << (x86_pmu.counter_bits - 1)))
 			continue;

commit 0127c3ea082ee9f1034789b978dfc7fd83254617
Author: Ingo Molnar <mingo@elte.hu>
Date:   Mon May 25 22:03:26 2009 +0200

    perf_counter: fix warning & lockup
    
     - remove bogus warning
     - fix wakeup from NMI path lockup
     - also fix up whitespace noise in perf_counter.h
    
    Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
    Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
    Cc: John Kacur <jkacur@redhat.com>
    LKML-Reference: <20090525153931.703093461@chello.nl>
    Signed-off-by: Ingo Molnar <mingo@elte.hu>

diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h
index e3a7585d3e43..2b16ed37b74c 100644
--- a/include/linux/perf_counter.h
+++ b/include/linux/perf_counter.h
@@ -73,7 +73,7 @@ enum sw_event_ids {
 	PERF_SW_EVENTS_MAX		= 7,
 };
 
-#define __PERF_COUNTER_MASK(name) 			\
+#define __PERF_COUNTER_MASK(name)			\
 	(((1ULL << PERF_COUNTER_##name##_BITS) - 1) <<	\
 	 PERF_COUNTER_##name##_SHIFT)
 
@@ -98,14 +98,14 @@ enum sw_event_ids {
  * in the overflow packets.
  */
 enum perf_counter_record_format {
-	PERF_RECORD_IP		= 1U << 0,
-	PERF_RECORD_TID		= 1U << 1,
-	PERF_RECORD_TIME	= 1U << 2,
-	PERF_RECORD_ADDR	= 1U << 3,
-	PERF_RECORD_GROUP	= 1U << 4,
-	PERF_RECORD_CALLCHAIN	= 1U << 5,
-	PERF_RECORD_CONFIG	= 1U << 6,
-	PERF_RECORD_CPU		= 1U << 7,
+	PERF_RECORD_IP			= 1U << 0,
+	PERF_RECORD_TID			= 1U << 1,
+	PERF_RECORD_TIME		= 1U << 2,
+	PERF_RECORD_ADDR		= 1U << 3,
+	PERF_RECORD_GROUP		= 1U << 4,
+	PERF_RECORD_CALLCHAIN		= 1U << 5,
+	PERF_RECORD_CONFIG		= 1U << 6,
+	PERF_RECORD_CPU			= 1U << 7,
 };
 
 /*
@@ -235,13 +235,13 @@ enum perf_event_type {
 	 * correlate userspace IPs to code. They have the following structure:
 	 *
 	 * struct {
-	 * 	struct perf_event_header	header;
+	 *	struct perf_event_header	header;
 	 *
-	 * 	u32				pid, tid;
-	 * 	u64				addr;
-	 * 	u64				len;
-	 * 	u64				pgoff;
-	 * 	char				filename[];
+	 *	u32				pid, tid;
+	 *	u64				addr;
+	 *	u64				len;
+	 *	u64				pgoff;
+	 *	char				filename[];
 	 * };
 	 */
 	PERF_EVENT_MMAP			= 1,
@@ -249,27 +249,27 @@ enum perf_event_type {
 
 	/*
 	 * struct {
-	 * 	struct perf_event_header	header;
+	 *	struct perf_event_header	header;
 	 *
-	 * 	u32				pid, tid;
-	 * 	char				comm[];
+	 *	u32				pid, tid;
+	 *	char				comm[];
 	 * };
 	 */
 	PERF_EVENT_COMM			= 3,
 
 	/*
 	 * struct {
-	 * 	struct perf_event_header	header;
-	 * 	u64				time;
-	 * 	u64				irq_period;
+	 *	struct perf_event_header	header;
+	 *	u64				time;
+	 *	u64				irq_period;
 	 * };
 	 */
 	PERF_EVENT_PERIOD		= 4,
 
 	/*
 	 * struct {
-	 * 	struct perf_event_header	header;
-	 * 	u64				time;
+	 *	struct perf_event_header	header;
+	 *	u64				time;
 	 * };
 	 */
 	PERF_EVENT_THROTTLE		= 5,
@@ -280,23 +280,23 @@ enum perf_event_type {
 	 * will be PERF_RECORD_*
 	 *
 	 * struct {
-	 * 	struct perf_event_header	header;
+	 *	struct perf_event_header	header;
 	 *
-	 * 	{ u64			ip;	  } && PERF_RECORD_IP
-	 * 	{ u32			pid, tid; } && PERF_RECORD_TID
-	 * 	{ u64			time;     } && PERF_RECORD_TIME
-	 * 	{ u64			addr;     } && PERF_RECORD_ADDR
-	 * 	{ u64			config;   } && PERF_RECORD_CONFIG
-	 * 	{ u32			cpu, res; } && PERF_RECORD_CPU
+	 *	{ u64			ip;	  } && PERF_RECORD_IP
+	 *	{ u32			pid, tid; } && PERF_RECORD_TID
+	 *	{ u64			time;     } && PERF_RECORD_TIME
+	 *	{ u64			addr;     } && PERF_RECORD_ADDR
+	 *	{ u64			config;   } && PERF_RECORD_CONFIG
+	 *	{ u32			cpu, res; } && PERF_RECORD_CPU
 	 *
-	 * 	{ u64			nr;
-	 * 	  { u64 event, val; } 	cnt[nr];  } && PERF_RECORD_GROUP
+	 *	{ u64			nr;
+	 *	  { u64 event, val; }	cnt[nr];  } && PERF_RECORD_GROUP
 	 *
-	 * 	{ u16			nr,
-	 * 				hv,
-	 * 				kernel,
-	 * 				user;
-	 * 	  u64			ips[nr];  } && PERF_RECORD_CALLCHAIN
+	 *	{ u16			nr,
+	 *				hv,
+	 *				kernel,
+	 *				user;
+	 *	  u64			ips[nr];  } && PERF_RECORD_CALLCHAIN
 	 * };
 	 */
 };
@@ -406,7 +406,7 @@ struct perf_mmap_data {
 	atomic_t			wakeup;		/* needs a wakeup    */
 
 	struct perf_counter_mmap_page   *user_page;
-	void 				*data_pages[0];
+	void				*data_pages[0];
 };
 
 struct perf_pending_entry {
@@ -422,7 +422,7 @@ struct perf_counter {
 	struct list_head		list_entry;
 	struct list_head		event_entry;
 	struct list_head		sibling_list;
-	int 				nr_siblings;
+	int				nr_siblings;
 	struct perf_counter		*group_leader;
 	const struct pmu		*pmu;
 
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c
index ec9c4007a7f9..070f92d3232a 100644
--- a/kernel/perf_counter.c
+++ b/kernel/perf_counter.c
@@ -2576,7 +2576,7 @@ static void perf_log_throttle(struct perf_counter *counter, int enable)
 		.time = sched_clock(),
 	};
 
-	ret = perf_output_begin(&handle, counter, sizeof(throttle_event), 0, 0);
+	ret = perf_output_begin(&handle, counter, sizeof(throttle_event), 1, 0);
 	if (ret)
 		return;
 
@@ -3449,8 +3449,6 @@ void perf_counter_exit_task(struct task_struct *child)
 	struct perf_counter_context *child_ctx;
 	unsigned long flags;
 
-	WARN_ON_ONCE(child != current);
-
 	child_ctx = child->perf_counter_ctxp;
 
 	if (likely(!child_ctx))

commit 53b441a565bf4036ab49c8ea04c5ad06ace7dd6b
Author: Ingo Molnar <mingo@elte.hu>
Date:   Mon May 25 21:41:28 2009 +0200

    Revert "perf_counter, x86: speed up the scheduling fast-path"
    
    This reverts commit b68f1d2e7aa21029d73c7d453a8046e95d351740.
    
    It is causing problems (stuck/stuttering profiling) - when mixed
    NMI and non-NMI counters are used.
    
    Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
    Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
    Cc: John Kacur <jkacur@redhat.com>
    LKML-Reference: <20090525153931.703093461@chello.nl>
    Signed-off-by: Ingo Molnar <mingo@elte.hu>

diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c
index c4b543d1a86f..189bf9d7cdab 100644
--- a/arch/x86/kernel/cpu/perf_counter.c
+++ b/arch/x86/kernel/cpu/perf_counter.c
@@ -293,7 +293,6 @@ static int __hw_perf_counter_init(struct perf_counter *counter)
 			return -EACCES;
 		hwc->nmi = 1;
 	}
-	perf_counters_lapic_init(hwc->nmi);
 
 	if (!hwc->irq_period)
 		hwc->irq_period = x86_pmu.max_period;
@@ -612,6 +611,8 @@ static int x86_pmu_enable(struct perf_counter *counter)
 		hwc->counter_base = x86_pmu.perfctr;
 	}
 
+	perf_counters_lapic_init(hwc->nmi);
+
 	x86_pmu.disable(hwc, idx);
 
 	cpuc->counters[idx] = counter;
@@ -1037,7 +1038,7 @@ void __init init_hw_perf_counters(void)
 
 	pr_info("... counter mask:    %016Lx\n", perf_counter_mask);
 
-	perf_counters_lapic_init(1);
+	perf_counters_lapic_init(0);
 	register_die_notifier(&perf_counter_nmi_notifier);
 }
 

commit d3f4b3855ba87caff8f35e738c7e7e3bad0a6ab1
Author: Ingo Molnar <mingo@elte.hu>
Date:   Mon May 25 14:40:01 2009 +0200

    perf stat: flip around ':k' and ':u' flags
    
    This output:
    
     $ perf stat -e 0:1:k -e 0:1:u ./hello
      Performance counter stats for './hello':
              140131  instructions         (events)
             1906968  instructions         (events)
    
    Is quite confusing - as :k means "user instructions", :u means
    "kernel instructions".
    
    Flip them around - as the 'exclude' property is not intuitive in
    the flag naming.
    
    Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
    Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
    Cc: John Kacur <jkacur@redhat.com>
    Cc: Mike Galbraith <efault@gmx.de>
    LKML-Reference: <new-submission>
    Signed-off-by: Ingo Molnar <mingo@elte.hu>

diff --git a/Documentation/perf_counter/builtin-stat.c b/Documentation/perf_counter/builtin-stat.c
index 8ae01d51f291..88c70be99031 100644
--- a/Documentation/perf_counter/builtin-stat.c
+++ b/Documentation/perf_counter/builtin-stat.c
@@ -266,9 +266,9 @@ static __u64 match_event_symbols(char *str)
 
 	switch (sscanf(str, "%d:%llu:%2s", &type, &id, mask_str)) {
 		case 3:
-			if (strchr(mask_str, 'u'))
-				event_mask[nr_counters] |= EVENT_MASK_USER;
 			if (strchr(mask_str, 'k'))
+				event_mask[nr_counters] |= EVENT_MASK_USER;
+			if (strchr(mask_str, 'u'))
 				event_mask[nr_counters] |= EVENT_MASK_KERNEL;
 		case 2:
 			return EID(type, id);

commit e4cbb4e3ac8b09fdb11e39e5a5611bfab0a7cd1a
Author: Ingo Molnar <mingo@elte.hu>
Date:   Tue May 19 15:50:30 2009 +0200

    perf_counter: Move child perfcounter init to after scheduler init
    
    Initialize a task's perfcounters (inherit from parent, etc.) after
    the child task's scheduler fields have been initialized already.
    
    [ Impact: cleanup ]
    
    Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
    Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
    Cc: John Kacur <jkacur@redhat.com>
    Cc: Mike Galbraith <efault@gmx.de>
    LKML-Reference: <new-submission>
    Signed-off-by: Ingo Molnar <mingo@elte.hu>

diff --git a/kernel/fork.c b/kernel/fork.c
index e72a09f5355b..675e01e9072a 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -984,7 +984,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 		goto fork_out;
 
 	rt_mutex_init_task(p);
-	perf_counter_init_task(p);
 
 #ifdef CONFIG_PROVE_LOCKING
 	DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled);
@@ -1096,6 +1095,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
 
 	/* Perform scheduler related setup. Assign this task to a CPU. */
 	sched_fork(p, clone_flags);
+	perf_counter_init_task(p);
 
 	if ((retval = audit_alloc(p)))
 		goto bad_fork_cleanup_policy;

commit 85a9f9200226ddffc2ea50dae6a8df04c033ecd4
Author: Ingo Molnar <mingo@elte.hu>
Date:   Mon May 25 09:59:50 2009 +0200

    perf_counter tools: increase limits, fix
    
    NR_CPUS and NR_COUNTERS goes up quadratic ... 1024x4096 was far
    too ambitious upper limit - go for 256x256 which is still plenty.
    
    [ Impact: reduce perf tool memory consumption ]
    
    Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
    Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
    Cc: John Kacur <jkacur@redhat.com>
    Cc: Mike Galbraith <efault@gmx.de>
    LKML-Reference: <new-submission>
    Signed-off-by: Ingo Molnar <mingo@elte.hu>

diff --git a/Documentation/perf_counter/perf.h b/Documentation/perf_counter/perf.h
index a517683fc661..5a2520bb7e55 100644
--- a/Documentation/perf_counter/perf.h
+++ b/Documentation/perf_counter/perf.h
@@ -61,8 +61,8 @@ sys_perf_counter_open(struct perf_counter_hw_event *hw_event_uptr,
 		       group_fd, flags);
 }
 
-#define MAX_COUNTERS			1024
-#define MAX_NR_CPUS			4096
+#define MAX_COUNTERS			256
+#define MAX_NR_CPUS			256
 
 #define EID(type, id) (((__u64)(type) << PERF_COUNTER_TYPE_SHIFT) | (id))
 

commit a3862d3f814ce7dfca9eed56ac23d29db3aee8d5
Author: Ingo Molnar <mingo@elte.hu>
Date:   Sun May 24 09:02:37 2009 +0200

    perf_counter: Increase mmap limit
    
    In a default 'perf top' run the tool will create a counter for
    each online CPU. With enough CPUs this will eventually exhaust
    the default limit.
    
    So scale it up with the number of online CPUs.
    
    Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
    Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
    Cc: John Kacur <jkacur@redhat.com>
    Cc: Mike Galbraith <efault@gmx.de>
    LKML-Reference: <new-submission>
    Signed-off-by: Ingo Molnar <mingo@elte.hu>

diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c
index cb4062559b47..6cdf8248eda2 100644
--- a/kernel/perf_counter.c
+++ b/kernel/perf_counter.c
@@ -1704,6 +1704,12 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
 
 	user_extra = nr_pages + 1;
 	user_lock_limit = sysctl_perf_counter_mlock >> (PAGE_SHIFT - 10);
+
+	/*
+	 * Increase the limit linearly with more CPUs:
+	 */
+	user_lock_limit *= num_online_cpus();
+
 	user_locked = atomic_long_read(&user->locked_vm) + user_extra;
 
 	extra = 0;

commit c6eb13847ba081552d2af644219bddeff7110caf
Author: Ingo Molnar <mingo@elte.hu>
Date:   Fri May 22 18:18:28 2009 +0200

    perf_counter tools: increase limits
    
    I tried to run with 300 active counters and the tools bailed out
    because our limit was at 64. So increase the counter limit to 1024
    and the CPU limit to 4096.
    
    Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
    Cc: Marcelo Tosatti <mtosatti@redhat.com>
    Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    LKML-Reference: <new-submission>
    Signed-off-by: Ingo Molnar <mingo@elte.hu>

diff --git a/Documentation/perf_counter/perf.h b/Documentation/perf_counter/perf.h
index 6fa3656399f4..81a737444c8f 100644
--- a/Documentation/perf_counter/perf.h
+++ b/Documentation/perf_counter/perf.h
@@ -54,8 +54,8 @@ sys_perf_counter_open(struct perf_counter_hw_event *hw_event_uptr,
 		       group_fd, flags);
 }
 
-#define MAX_COUNTERS			64
-#define MAX_NR_CPUS			256
+#define MAX_COUNTERS			1024
+#define MAX_NR_CPUS			4096
 
 #define EID(type, id) (((__u64)(type) << PERF_COUNTER_TYPE_SHIFT) | (id))
 

commit 910431c7f2e963017d767b29c80ae706421e569f
Author: Ingo Molnar <mingo@elte.hu>
Date:   Fri May 22 12:32:15 2009 +0200

    perf_counter: fix !PERF_COUNTERS build failure
    
    Update the !CONFIG_PERF_COUNTERS prototype too, for
    perf_counter_task_sched_out().
    
    [ Impact: build fix ]
    
    Signed-off-by: Paul Mackerras <paulus@samba.org>
    Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
    Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
    Cc: Marcelo Tosatti <mtosatti@redhat.com>
    Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
    LKML-Reference: <18966.10666.517218.332164@cargo.ozlabs.ibm.com>
    Signed-off-by: Ingo Molnar <mingo@elte.hu>

diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h
index 4cae01a50450..2eedae8498d3 100644
--- a/include/linux/perf_counter.h
+++ b/include/linux/perf_counter.h
@@ -625,7 +625,8 @@ extern void perf_counter_init(void);
 static inline void
 perf_counter_task_sched_in(struct task_struct *task, int cpu)		{ }
 static inline void
-perf_counter_task_sched_out(struct task_struct *task, int cpu)		{ }
+perf_counter_task_sched_out(struct task_struct *task,
+			    struct task_struct *next, int cpu)		{ }
 static inline void
 perf_counter_task_tick(struct task_struct *task, int cpu)		{ }
 static inline void perf_counter_init_task(struct task_struct *child)	{ }

commit 34adc8062227f41b04ade0ff3fbd1dbe3002669e
Author: Ingo Molnar <mingo@elte.hu>
Date:   Wed May 20 20:13:28 2009 +0200

    perf_counter: Fix context removal deadlock
    
    Disable the PMU globally before removing a counter from a
    context. This fixes the following lockup:
    
    [22081.741922] ------------[ cut here ]------------
    [22081.746668] WARNING: at arch/x86/kernel/cpu/perf_counter.c:803 intel_pmu_handle_irq+0x9b/0x24e()
    [22081.755624] Hardware name: X8DTN
    [22081.758903] perfcounters: irq loop stuck!
    [22081.762985] Modules linked in:
    [22081.766136] Pid: 11082, comm: perf Not tainted 2.6.30-rc6-tip #226
    [22081.772432] Call Trace:
    [22081.774940]  <NMI>  [<ffffffff81019aed>] ? intel_pmu_handle_irq+0x9b/0x24e
    [22081.781993]  [<ffffffff81019aed>] ? intel_pmu_handle_irq+0x9b/0x24e
    [22081.788368]  [<ffffffff8104505c>] ? warn_slowpath_common+0x77/0xa3
    [22081.794649]  [<ffffffff810450d3>] ? warn_slowpath_fmt+0x40/0x45
    [22081.800696]  [<ffffffff81019aed>] ? intel_pmu_handle_irq+0x9b/0x24e
    [22081.807080]  [<ffffffff814d1a72>] ? perf_counter_nmi_handler+0x3f/0x4a
    [22081.813751]  [<ffffffff814d2d09>] ? notifier_call_chain+0x58/0x86
    [22081.819951]  [<ffffffff8105b250>] ? notify_die+0x2d/0x32
    [22081.825392]  [<ffffffff814d1414>] ? do_nmi+0x8e/0x242
    [22081.830538]  [<ffffffff814d0f0a>] ? nmi+0x1a/0x20
    [22081.835342]  [<ffffffff8117e102>] ? selinux_file_free_security+0x0/0x1a
    [22081.842105]  [<ffffffff81018793>] ? x86_pmu_disable_counter+0x15/0x41
    [22081.848673]  <<EOE>>  [<ffffffff81018f3d>] ? x86_pmu_disable+0x86/0x103
    [22081.855512]  [<ffffffff8108fedd>] ? __perf_counter_remove_from_context+0x0/0xfe
    [22081.862926]  [<ffffffff8108fcbc>] ? counter_sched_out+0x30/0xce
    [22081.868909]  [<ffffffff8108ff36>] ? __perf_counter_remove_from_context+0x59/0xfe
    [22081.876382]  [<ffffffff8106808a>] ? smp_call_function_single+0x6c/0xe6
    [22081.882955]  [<ffffffff81091b96>] ? perf_release+0x86/0x14c
    [22081.888600]  [<ffffffff810c4c84>] ? __fput+0xe7/0x195
    [22081.893718]  [<ffffffff810c213e>] ? filp_close+0x5b/0x62
    [22081.899107]  [<ffffffff81046a70>] ? put_files_struct+0x64/0xc2
    [22081.905031]  [<ffffffff8104841a>] ? do_exit+0x1e2/0x6ef
    [22081.910360]  [<ffffffff814d0a60>] ? _spin_lock_irqsave+0x9/0xe
    [22081.916292]  [<ffffffff8104898e>] ? do_group_exit+0x67/0x93
    [22081.921953]  [<ffffffff810489cc>] ? sys_exit_group+0x12/0x16
    [22081.927759]  [<ffffffff8100baab>] ? system_call_fastpath+0x16/0x1b
    [22081.934076] ---[ end trace 3a3936ce3e1b4505 ]---
    
    And could potentially also fix the lockup reported by Marcelo Tosatti.
    
    Also, print more debug info in case of a detected lockup.
    
    [ Impact: fix lockup ]
    
    Reported-by: Marcelo Tosatti <mtosatti@redhat.com>
    Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
    Cc: Paul Mackerras <paulus@samba.org>
    Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    LKML-Reference: <new-submission>
    Signed-off-by: Ingo Molnar <mingo@elte.hu>

diff --git a/arch/x86/kernel/cpu/perf_counter.c b/arch/x86/kernel/cpu/perf_counter.c
index c109819c2cb9..6cc1660db8d6 100644
--- a/arch/x86/kernel/cpu/perf_counter.c
+++ b/arch/x86/kernel/cpu/perf_counter.c
@@ -740,6 +740,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs, int nmi)
 again:
 	if (++loops > 100) {
 		WARN_ONCE(1, "perfcounters: irq loop stuck!\n");
+		perf_counter_print_debug();
 		return 1;
 	}
 
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c
index 69d4de815963..08584c16049f 100644
--- a/kernel/perf_counter.c
+++ b/kernel/perf_counter.c
@@ -208,18 +208,17 @@ static void __perf_counter_remove_from_context(void *info)
 		return;
 
 	spin_lock_irqsave(&ctx->lock, flags);
+	/*
+	 * Protect the list operation against NMI by disabling the
+	 * counters on a global level.
+	 */
+	perf_disable();
 
 	counter_sched_out(counter, cpuctx, ctx);
 
 	counter->task = NULL;
 
-	/*
-	 * Protect the list operation against NMI by disabling the
-	 * counters on a global level. NOP for non NMI based counters.
-	 */
-	perf_disable();
 	list_del_counter(counter, ctx);
-	perf_enable();
 
 	if (!ctx->task) {
 		/*
@@ -231,6 +230,7 @@ static void __perf_counter_remove_from_context(void *info)
 			    perf_max_counters - perf_reserved_percpu);
 	}
 
+	perf_enable();
 	spin_unlock_irqrestore(&ctx->lock, flags);
 }