On Fri, 30 Jan 2026 11:33:17 +0530 Deepanshu Kartikey <[email protected]> wrote:
> The dma_map_sg tracepoint can trigger a perf buffer overflow when > tracing large scatter-gather lists. With devices like virtio-gpu > creating large DRM buffers, nents can exceed 1000 entries, resulting > in: > > phys_addrs: 1000 * 8 bytes = 8,000 bytes > dma_addrs: 1000 * 8 bytes = 8,000 bytes > lengths: 1000 * 4 bytes = 4,000 bytes > Total: ~20,000 bytes > > This exceeds PERF_MAX_TRACE_SIZE (8192 bytes), causing: > > WARNING: CPU: 0 PID: 5497 at kernel/trace/trace_event_perf.c:405 > perf buffer not large enough, wanted 24620, have 8192 > > Cap all three dynamic arrays at a fixed size of 128 entries. This limits > the total event size to approximately 2,760 bytes, safely under the 8KB > limit while still providing sufficient debugging information for typical > cases. > > The tracepoint now records the full nents/ents counts and a truncated > flag so users can see when data has been capped. > > Reported-by: [email protected] > Closes: https://syzkaller.appspot.com/bug?extid=28cea38c382fd15e751a > Signed-off-by: Deepanshu Kartikey <[email protected]> > --- > include/trace/events/dma.h | 25 +++++++++++++++++++------ > 1 file changed, 19 insertions(+), 6 deletions(-) > > diff --git a/include/trace/events/dma.h b/include/trace/events/dma.h > index b3fef140ae15..c4e1a9f0c9c4 100644 > --- a/include/trace/events/dma.h > +++ b/include/trace/events/dma.h > @@ -275,6 +275,8 @@ TRACE_EVENT(dma_free_sgt, > sizeof(u64), sizeof(u64))) > ); > > +#define DMA_TRACE_MAX_ENTRIES 128 > + > TRACE_EVENT(dma_map_sg, > TP_PROTO(struct device *dev, struct scatterlist *sgl, int nents, > int ents, enum dma_data_direction dir, unsigned long attrs), > @@ -282,9 +284,12 @@ TRACE_EVENT(dma_map_sg, > > TP_STRUCT__entry( > __string(device, dev_name(dev)) > - __dynamic_array(u64, phys_addrs, nents) > - __dynamic_array(u64, dma_addrs, ents) > - __dynamic_array(unsigned int, lengths, ents) > + __field(int, full_nents) > + __field(int, full_ents) > + __field(bool, truncated) > + __dynamic_array(u64, phys_addrs, DMA_TRACE_MAX_ENTRIES) > + __dynamic_array(u64, dma_addrs, DMA_TRACE_MAX_ENTRIES) > + __dynamic_array(unsigned int, lengths, DMA_TRACE_MAX_ENTRIES) This isn't doing what you want. You just used a dynamic array and allocated a fixed size for it, regardless of if you use all of it or not. What you want to do is: __dynamic_array(u64, phys_addrs, min(nents, DMA_TRACE_MAX_ENTRIES)) __dynamic_array(u64, dma_addrs, min(ents, DMA_TRACE_MAX_ENTRIES)) __dynamic_array(unsigned int, lengths, min(ents, DMA_TRACE_MAX_ENTRIES)) And the same for the rest. -- Steve > __field(enum dma_data_direction, dir) > __field(unsigned long, attrs) > ),
