Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755598AbbGCUIl (ORCPT ); Fri, 3 Jul 2015 16:08:41 -0400 Received: from mga09.intel.com ([134.134.136.24]:62254 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755526AbbGCUIe convert rfc822-to-8bit (ORCPT ); Fri, 3 Jul 2015 16:08:34 -0400 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.15,402,1432623600"; d="scan'208";a="758064716" From: "Liang, Kan" To: Peter Zijlstra , Vince Weaver CC: "linux-kernel@vger.kernel.org" , Ingo Molnar , Arnaldo Carvalho de Melo , "Stephane Eranian" Subject: RE: perf: fuzzer triggered warning in intel_pmu_drain_pebs_nhm() Thread-Topic: perf: fuzzer triggered warning in intel_pmu_drain_pebs_nhm() Thread-Index: AQHQtZIrWo8WhOngikicIZVMqW8Mb53KKJlQ Date: Fri, 3 Jul 2015 20:08:27 +0000 Message-ID: <37D7C6CF3E00A74B8858931C1DB2F07701885A65@SHSMSX103.ccr.corp.intel.com> References: <20150703131336.GI19282@twins.programming.kicks-ass.net> In-Reply-To: <20150703131336.GI19282@twins.programming.kicks-ass.net> Accept-Language: zh-CN, en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.239.127.40] Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 8BIT MIME-Version: 1.0 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 4016 Lines: 113 > > I've not yet tried to reproduce, but the below could explain things. > > On disabling an event we first clear our cpuc->pebs_enabled bits, only to > then check them to see if there are any set, and if so, drain the buffer. > > If we just cleared the last bit, we'll fail to drain the buffer. > > If we then program another event on that counter and another PEBS event, > we can hit the above WARN with the 'stale' entries left over from the > previous event. > > --- > arch/x86/kernel/cpu/perf_event_intel_ds.c | 16 ++++++++-------- > 1 file changed, 8 insertions(+), 8 deletions(-) > > diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c > b/arch/x86/kernel/cpu/perf_event_intel_ds.c > index 71fc40238843..041a30ba5654 100644 > --- a/arch/x86/kernel/cpu/perf_event_intel_ds.c > +++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c > @@ -548,7 +548,7 @@ int intel_pmu_drain_bts_buffer(void) > > static inline void intel_pmu_drain_pebs_buffer(void) { > - struct pt_regs regs; > + struct pt_regs regs; /* SAMPLE_REGS_INTR must not be set for > +FREERUNNING */ > > x86_pmu.drain_pebs(®s); > } > @@ -755,13 +755,6 @@ void intel_pmu_pebs_disable(struct perf_event > *event) > struct hw_perf_event *hwc = &event->hw; > struct debug_store *ds = cpuc->ds; > > - cpuc->pebs_enabled &= ~(1ULL << hwc->idx); > - > - if (event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT) > - cpuc->pebs_enabled &= ~(1ULL << (hwc->idx + 32)); > - else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST) > - cpuc->pebs_enabled &= ~(1ULL << 63); > - > if (ds->pebs_interrupt_threshold > > ds->pebs_buffer_base + x86_pmu.pebs_record_size) { > intel_pmu_drain_pebs_buffer(); > @@ -769,6 +762,13 @@ void intel_pmu_pebs_disable(struct perf_event > *event) > perf_sched_cb_dec(event->ctx->pmu); > } > > + cpuc->pebs_enabled &= ~(1ULL << hwc->idx); > + > + if (event->hw.flags & PERF_X86_EVENT_PEBS_LDLAT) > + cpuc->pebs_enabled &= ~(1ULL << (hwc->idx + 32)); > + else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST) > + cpuc->pebs_enabled &= ~(1ULL << 63); > + > if (cpuc->enabled) > wrmsrl(MSR_IA32_PEBS_ENABLE, cpuc->pebs_enabled); > If we cleared the last bit, we not only drain the buffer but also decrease the event->ctx->pmu, which is used to flush the PEBS buffer during context switches. We need to disable cpuc->pebs_enabled before changing event->ctx->pmu as below. diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c index 71fc402..76285c1 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_ds.c +++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c @@ -754,6 +754,11 @@ void intel_pmu_pebs_disable(struct perf_event *event) struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct hw_perf_event *hwc = &event->hw; struct debug_store *ds = cpuc->ds; + bool large_pebs = ds->pebs_interrupt_threshold > + ds->pebs_buffer_base + x86_pmu.pebs_record_size; + + if (large_pebs) + intel_pmu_drain_pebs_buffer(); cpuc->pebs_enabled &= ~(1ULL << hwc->idx); @@ -762,12 +767,8 @@ void intel_pmu_pebs_disable(struct perf_event *event) else if (event->hw.flags & PERF_X86_EVENT_PEBS_ST) cpuc->pebs_enabled &= ~(1ULL << 63); - if (ds->pebs_interrupt_threshold > - ds->pebs_buffer_base + x86_pmu.pebs_record_size) { - intel_pmu_drain_pebs_buffer(); - if (!pebs_is_enabled(cpuc)) - perf_sched_cb_dec(event->ctx->pmu); - } + if (large_pebs && !pebs_is_enabled(cpuc)) + perf_sched_cb_dec(event->ctx->pmu); if (cpuc->enabled) wrmsrl(MSR_IA32_PEBS_ENABLE, cpuc->pebs_enabled); Thanks, Kan -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/