]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
dma-mapping: trace more error paths
authorSean Anderson <sean.anderson@linux.dev>
Fri, 18 Oct 2024 15:00:37 +0000 (11:00 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 19 Sep 2025 14:35:42 +0000 (16:35 +0200)
[ Upstream commit 68b6dbf1f441c4eba3b8511728a41cf9b01dca35 ]

It can be surprising to the user if DMA functions are only traced on
success. On failure, it can be unclear what the source of the problem
is. Fix this by tracing all functions even when they fail. Cases where
we BUG/WARN are skipped, since those should be sufficiently noisy
already.

Signed-off-by: Sean Anderson <sean.anderson@linux.dev>
Reviewed-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Stable-dep-of: 7e2368a21741 ("dma-debug: don't enforce dma mapping check on noncoherent allocations")
Signed-off-by: Sasha Levin <sashal@kernel.org>
include/trace/events/dma.h
kernel/dma/mapping.c

index 45cc0ca8287feaaac2dac30c768a4e82619ce226..63b55ccc4f00cdcfe52db69480cff83b203d7389 100644 (file)
@@ -158,6 +158,7 @@ DEFINE_EVENT(dma_alloc_class, name, \
 
 DEFINE_ALLOC_EVENT(dma_alloc);
 DEFINE_ALLOC_EVENT(dma_alloc_pages);
+DEFINE_ALLOC_EVENT(dma_alloc_sgt_err);
 
 TRACE_EVENT(dma_alloc_sgt,
        TP_PROTO(struct device *dev, struct sg_table *sgt, size_t size,
@@ -322,6 +323,41 @@ TRACE_EVENT(dma_map_sg,
                decode_dma_attrs(__entry->attrs))
 );
 
+TRACE_EVENT(dma_map_sg_err,
+       TP_PROTO(struct device *dev, struct scatterlist *sgl, int nents,
+                int err, enum dma_data_direction dir, unsigned long attrs),
+       TP_ARGS(dev, sgl, nents, err, dir, attrs),
+
+       TP_STRUCT__entry(
+               __string(device, dev_name(dev))
+               __dynamic_array(u64, phys_addrs, nents)
+               __field(int, err)
+               __field(enum dma_data_direction, dir)
+               __field(unsigned long, attrs)
+       ),
+
+       TP_fast_assign(
+               struct scatterlist *sg;
+               int i;
+
+               __assign_str(device);
+               for_each_sg(sgl, sg, nents, i)
+                       ((u64 *)__get_dynamic_array(phys_addrs))[i] = sg_phys(sg);
+               __entry->err = err;
+               __entry->dir = dir;
+               __entry->attrs = attrs;
+       ),
+
+       TP_printk("%s dir=%s dma_addrs=%s err=%d attrs=%s",
+               __get_str(device),
+               decode_dma_data_direction(__entry->dir),
+               __print_array(__get_dynamic_array(phys_addrs),
+                             __get_dynamic_array_len(phys_addrs) /
+                               sizeof(u64), sizeof(u64)),
+               __entry->err,
+               decode_dma_attrs(__entry->attrs))
+);
+
 TRACE_EVENT(dma_unmap_sg,
        TP_PROTO(struct device *dev, struct scatterlist *sgl, int nents,
                 enum dma_data_direction dir, unsigned long attrs),
index 690aeda8bd7dadc3ea6dce672604d77611f28bab..32dcf8492bbcdfa0a872e5ef77f659293dc1e29b 100644 (file)
@@ -223,6 +223,7 @@ static int __dma_map_sg_attrs(struct device *dev, struct scatterlist *sg,
                debug_dma_map_sg(dev, sg, nents, ents, dir, attrs);
        } else if (WARN_ON_ONCE(ents != -EINVAL && ents != -ENOMEM &&
                                ents != -EIO && ents != -EREMOTEIO)) {
+               trace_dma_map_sg_err(dev, sg, nents, ents, dir, attrs);
                return -EIO;
        }
 
@@ -604,20 +605,26 @@ void *dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
        if (WARN_ON_ONCE(flag & __GFP_COMP))
                return NULL;
 
-       if (dma_alloc_from_dev_coherent(dev, size, dma_handle, &cpu_addr))
+       if (dma_alloc_from_dev_coherent(dev, size, dma_handle, &cpu_addr)) {
+               trace_dma_alloc(dev, cpu_addr, *dma_handle, size,
+                               DMA_BIDIRECTIONAL, flag, attrs);
                return cpu_addr;
+       }
 
        /* let the implementation decide on the zone to allocate from: */
        flag &= ~(__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM);
 
-       if (dma_alloc_direct(dev, ops))
+       if (dma_alloc_direct(dev, ops)) {
                cpu_addr = dma_direct_alloc(dev, size, dma_handle, flag, attrs);
-       else if (use_dma_iommu(dev))
+       } else if (use_dma_iommu(dev)) {
                cpu_addr = iommu_dma_alloc(dev, size, dma_handle, flag, attrs);
-       else if (ops->alloc)
+       } else if (ops->alloc) {
                cpu_addr = ops->alloc(dev, size, dma_handle, flag, attrs);
-       else
+       } else {
+               trace_dma_alloc(dev, NULL, 0, size, DMA_BIDIRECTIONAL, flag,
+                               attrs);
                return NULL;
+       }
 
        trace_dma_alloc(dev, cpu_addr, *dma_handle, size, DMA_BIDIRECTIONAL,
                        flag, attrs);
@@ -642,11 +649,11 @@ void dma_free_attrs(struct device *dev, size_t size, void *cpu_addr,
         */
        WARN_ON(irqs_disabled());
 
+       trace_dma_free(dev, cpu_addr, dma_handle, size, DMA_BIDIRECTIONAL,
+                      attrs);
        if (!cpu_addr)
                return;
 
-       trace_dma_free(dev, cpu_addr, dma_handle, size, DMA_BIDIRECTIONAL,
-                      attrs);
        debug_dma_free_coherent(dev, size, cpu_addr, dma_handle);
        if (dma_alloc_direct(dev, ops))
                dma_direct_free(dev, size, cpu_addr, dma_handle, attrs);
@@ -688,6 +695,8 @@ struct page *dma_alloc_pages(struct device *dev, size_t size,
                trace_dma_alloc_pages(dev, page_to_virt(page), *dma_handle,
                                      size, dir, gfp, 0);
                debug_dma_map_page(dev, page, 0, size, dir, *dma_handle, 0);
+       } else {
+               trace_dma_alloc_pages(dev, NULL, 0, size, dir, gfp, 0);
        }
        return page;
 }
@@ -772,6 +781,8 @@ struct sg_table *dma_alloc_noncontiguous(struct device *dev, size_t size,
                sgt->nents = 1;
                trace_dma_alloc_sgt(dev, sgt, size, dir, gfp, attrs);
                debug_dma_map_sg(dev, sgt->sgl, sgt->orig_nents, 1, dir, attrs);
+       } else {
+               trace_dma_alloc_sgt_err(dev, NULL, 0, size, gfp, dir, attrs);
        }
        return sgt;
 }