Re: [PATCH V3 3/6] powerpc/perf: Add AUX buffer management to capture HTM trace data

Athira Rajeev <[email protected]>
Newsgroups dev.linux.lists.sashiko-reviews,org.kernel.vger.linux-perf-users
Message-ID <[email protected]>

> On 25 Jul 2026, at 1:15 PM, [email protected] wrote:
> 
> Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
> - [Critical] Using a shared per-CPU `perf_output_handle` causes a NULL pointer dereference on reentrancy between process and NMI contexts.
> - [High] Stale AUX buffer state (`collect_htm_trace`) permanently prevents dumping trace data for subsequent tracing sessions.
> - [Medium] The PMU driver fails to reject snapshot (overwrite) mode, leading to an infinite `-ENOSPC` drain loop in userspace.
> --
> 
> --- Patch [3]: [PATCH V3 3/6] powerpc/perf: Add AUX buffer management to capture HTM trace data ---
> commit 35468a18c6f5ab02b21271ca4f3e9ece1b6d7df7
> Author: Athira Rajeev <[email protected]>
> powerpc/perf: Add AUX buffer management to capture HTM trace data
> 
> This commit implements support for auxiliary (AUX) ring buffers in the HTM PMU
> driver. It enables high-volume trace data to be streamed directly into a perf
> AUX buffer for deferred post-processing.
> 
>> diff --git a/arch/powerpc/perf/htm-perf.c b/arch/powerpc/perf/htm-perf.c
>> index 84a5601ee7f73..f880a5fc88330 100644
>> --- a/arch/powerpc/perf/htm-perf.c
>> +++ b/arch/powerpc/perf/htm-perf.c
> [ ... ]
>> @@ -415,8 +431,237 @@ static void htm_event_del(struct perf_event *event, int flags)
>> /* pmu_private freed by event->destroy = reset_htm_active */
>> }
>> 
>> +static ssize_t htm_dump_sample_data(struct perf_event *event)
>> +{
>> + struct htm_pmu_ctx *htm_ctx = this_cpu_ptr(&htm_pmu_ctx);
>> + struct htm_target_id *target = event->pmu_private;
>> + struct htm_pmu_buf *aux_buf;
>> + struct htm_config cfg = target->cfg;
>> + u64 chunk_size, dump_offset, page_index, page_offset;
>> + u64 max_contiguous_bytes, expected_phys, scan_index, actual_phys;
>> + u64 hypervisor_target_phys;
>> + void *target_page_virt;
>> + ssize_t ret = 0;
>> + int retries = 0;
>> + long rc;
>> +
>> + /* Start AUX transaction session framework */
>> + aux_buf = perf_aux_output_begin(&htm_ctx->handle, event);
> 
> [Severity: Critical]
> Does using a shared per-CPU perf_output_handle here risk a NULL pointer
> dereference on reentrancy?
> 
> If a process context read is interrupted by an NMI on the same CPU, and that
> NMI also calls perf_pmu_read() on the HTM event, perf_aux_output_begin() will
> detect the nesting, clear handle->event to NULL, and exit.
> 
> When the NMI returns to the process context, could the outer
> perf_aux_output_end() call subsequently dereference the NULL handle->event?

No, because, The reentrancy concern is handled by perf_aux_output_begin() itself 

 nest = READ_ONCE(rb->aux_nest);
        /*
         * Nesting is not supported for AUX area, make sure nested
         * writers are caught early
         */
        if (WARN_ON_ONCE(nest))
                goto err_put;


rb->aux_nest is a per-ring-buffer nesting counter maintained by the perf core. Before writing anything to the per-CPU handle, perf_aux_output_begin() checks this counter. If a nested caller (NMI, BPF, or any interrupt) attempts to begin an AUX transaction on the same ring buffer while one is already in progress, it hits the WARN_ON_ONCE and returns NULL. 

>> + if (!aux_buf)
>> + return 0;
>> +
>> + if (!aux_buf->collect_htm_trace) {
> 
> [Severity: High]
> Can stale AUX buffer state prevent dumping trace data for subsequent sessions?
> 
> If a trace is stopped and drained, aux_buf->collect_htm_trace is set to 0. 
> If the event is restarted, htm_event_start() doesn't appear to reset this 
> flag.
> 
> Would this early bailout then cause trace data for all subsequent sessions to
> be permanently dropped?
Sure, good catch, will address this in V4
> 
>> + perf_aux_output_end(&htm_ctx->handle, 0);
>> + return 0;
>> + }
> [ ... ]
>> +/*
>> + * Set up pmu-private data structures for an AUX area
>> + * **pages contains the aux buffer allocated for this event
>> + * for the corresponding cpu. rb_alloc_aux uses "alloc_pages_node"
>> + * and returns pointer to each page address.
>> + * PMU capabilities: PERF_PMU_CAP_AUX_NO_SG | PERF_PMU_CAP_AUX_PREFER_LARGE
>> + * to try get closest possible physically contiguous page blocks.
>> + *
>> + * The aux private data structure ie, "struct htm_pmu_buf" mainly
>> + * saves
>> + * - buf->base: aux buffer base address
>> + * - buf->head: offset from base address where data will be written to.
>> + * - buf->size: Size of allocated memory
>> + */
>> +static void *htm_setup_aux(struct perf_event *event, void **pages,
>> + int nr_pages, bool snapshot)
>> +{
>> + int cpu = event->cpu;
>> + struct htm_pmu_buf *buf;
>> +
>> + if (!nr_pages)
>> + return NULL;
>> +
>> + if (cpu == -1)
>> + cpu = raw_smp_processor_id();
>> +
>> + buf = kzalloc_node(sizeof(*buf), GFP_KERNEL, cpu_to_node(cpu));
>> + if (!buf)
>> + return NULL;
>> +
>> + buf->nr_pages = nr_pages;
>> + buf->snapshot = snapshot;
> 
> [Severity: Medium]
> Does the driver need to validate and reject snapshot (overwrite) mode?
> 
> When in snapshot mode, perf_aux_output_begin() leaves handle.size = 0.
> This would cause htm_dump_sample_data() to interpret chunk_size as 0, fallback
> to returning -ENOSPC, and cause htm_event_read() to set event->count = 1.
> 
> Could this result in the userspace perf tool spinning in an infinite retry
> loop waiting for space that will never become available?
Sure
I will have this change in V4

Thanks
Athira
> 
>> + buf->size = (u64)nr_pages << PAGE_SHIFT;
>> + buf->pages = pages;
>> +
>> + buf->base = pages[0];
> 
> -- 
> Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
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.