Re: [Patch v3 8/8] perf/x86/intel: Prevent drain_pebs() reentry

Peter Zijlstra <[email protected]>
Newsgroups org.kernel.vger.linux-perf-users,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
On Tue, Aug 11, 2026 at 09:39:23AM +0800, Mi, Dapeng wrote:
> 
> On 8/10/2026 9:01 PM, Peter Zijlstra wrote:
> > On Fri, Jul 17, 2026 at 04:03:42PM +0800, Dapeng Mi wrote:
> >> The PEBS buffer is shared by all events on a CPU, so drain_pebs() must
> >> not run concurrently. If it is reentered, one instance may observe stale
> >> buffer state and potentially access out-of-bound memory.
> >>
> >> Most invocations happen in NMI context, which naturally prevents reentry.
> >> However, drain_pebs() is also reachable from process context via
> >> intel_pmu_drain_pebs_buffer().
> >>
> >> In those paths, the PMU is often already disabled, but not guaranteed.
> >> For example, __intel_pmu_pebs_disable() only disables the target counter,
> >> so other active counters can still raise a PMI and interrupt an in-flight
> >> drain_pebs().
> >>
> >> Introduce __intel_pmu_quiesce() and __intel_pmu_resume() helpers and
> >> use them in intel_pmu_drain_pebs_buffer() to disable the full PMU
> >> around the drain_pebs() call, preventing reentry.
> >>
> > It is not at all clear to me where the exact recursion happens. (The
> > word you're looking for was recursion, not concurrent).
> 
> Yes, the word "concurrently" is not accurate, reentry is the more accurate
> word.
> 
> Currently drain_pebs() would be called in two places, one is the in the PMI
> handler, like handle_pmi_common(). The other place is
> intel_pmu_drain_pebs_buffer() which is from process context.
> 
> So when intel_pmu_drain_pebs_buffer() is calling drain_pebs(), if there is
> an active PEBS event triggering PMI, it would interrupt current in-flight
> drain_pebs() and lead to drain_pebs() reentry.

What is the actual callchain here?

Because the one I'm thinking off is:

  perf_ctx_disable();
  perf_ctx_sched_task_cb()
    x86_pmu_sched_task()
      intel_pmu_sched_task()
	intel_pmu_pebs_sched_task()
	  intel_pmu_drain_pebs_buffer();
  perf_ctx_enable();

And that one has the full pmu disabled, because of context switch etc.
And then there is one in perf_read():

  pmu->read()
    intel_pmu_read_event()
      pmu_enabled = cpuc->enabled;
      cpuc->enabled = 0;
      if (pmu_enabled)
        intel_pmu_disable_all();
      intel_pmu_drain_pebs_buffer();
      cpuc->enabled = pmu_enabled;
      if (pmu_enabled)
        intel_pmu_enable_all();

So what specific callchain is going sideways?
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.