Skip to contentSkip to conversation

dma-mapping: don't trace the DMA address when the allocation fails

PATCH Applied Donggeun Yoo 3 participants 3 messages Sep 7 – Sep 9

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH v2 1/1 dma-mapping: don't trace the DMA address when the allocation fails

dma_alloc_attrs() passes *dma_handle to trace_dma_alloc() without checking whether the allocation succeeded. No backend writes it on
failure: dma_direct_alloc(), iommu_dma_alloc() and the dma_map_ops instances assign it only on the path that returns a buffer. Callers usually pass an uninitialized automatic variable, so a failed allocation records whatever the stack held, next to the virt_addr=(null) that marks the record as an error:

dma_alloc: dmatrace dir=BIDIRECTIONAL dma_addr=deadbeefdeadbeef size=1099511627776 virt_addr=0000000000000000

The device coherent pool path reaches the same call: a non-zero return from dma_alloc_from_dev_coherent() means the request was handled, not that it succeeded, so cpu_addr is NULL and dma_handle is untouched once the pool runs out.

For an allocation event a NULL virt_addr already means the request failed, so the address field carries nothing. Report 0 for it in the event class rather than at each call site, which covers dma_alloc_pages() and dma_alloc_sgt_err() as well.

Fixes 038eb433dc14 ("dma-mapping: add tracing for dma-mapping API calls")
Fixes 68b6dbf1f441 ("dma-mapping: trace more error paths")

---
v2:
- report 0 in the event class instead of splitting the two call sites,
as suggested by Marek. kernel/dma/mapping.c is untouched now, so debug_dma_alloc_coherent() keeps being called for a failed allocation
and decides for itself what to do with it.
- tested on x86_64 rather than compile-tested only.
v1: https://lore.kernel.org/linux-iommu/[email protected]/

Tested with a module that puts a known value in the caller's handle and then asks for 1 TiB from a 32-bit capable device, with the dma_alloc event enabled. Before, the record carries the caller's stale value; after, it carries 0:

-dma_addr=deadbeefdeadbeef size=1099511627776 virt_addr=0000000000000000 +dma_addr=0 size=1099511627776 virt_addr=0000000000000000

A PAGE_SIZE request from the same device, as a control, reports its real address on both kernels, matching the handle the caller got back.

This changes what the record contains, not what the caller does:
*dma_handle is still read to build the tracepoint arguments, since those are evaluated before the static branch.

 include/trace/events/dma.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
include/trace/events/dma.h +1 -1
index 9df02c1511de..b06d8f99922d 100644
@@ -134,7 +134,7 @@ DECLARE_EVENT_CLASS(dma_alloc_class,
 	TP_fast_assign(
 		__assign_str(device);
 		__entry->virt_addr = virt_addr;
-		__entry->dma_addr = dma_addr;
+		__entry->dma_addr = virt_addr ? dma_addr : 0;
 		__entry->size = size;
 		__entry->flags = flags;
 		__entry->dir = dir;

base-commit: cee9395acd8043be0644b25c34bfa86623f2b935

Signature · 1 line
2.53.0
Reviewed-by on v2 1/1
#1 lore raw
Quoted 66 lines · Donggeun Yoo

dma_alloc_attrs() passes *dma_handle to trace_dma_alloc() without checking whether the allocation succeeded. No backend writes it on
failure: dma_direct_alloc(), iommu_dma_alloc() and the dma_map_ops instances assign it only on the path that returns a buffer. Callers usually pass an uninitialized automatic variable, so a failed allocation records whatever the stack held, next to the virt_addr=(null) that marks the record as an error:

dma_alloc: dmatrace dir=BIDIRECTIONAL dma_addr=deadbeefdeadbeef size=1099511627776 virt_addr=0000000000000000

The device coherent pool path reaches the same call: a non-zero return from dma_alloc_from_dev_coherent() means the request was handled, not that it succeeded, so cpu_addr is NULL and dma_handle is untouched once the pool runs out.

For an allocation event a NULL virt_addr already means the request failed, so the address field carries nothing. Report 0 for it in the event class rather than at each call site, which covers dma_alloc_pages() and dma_alloc_sgt_err() as well.

Fixes 038eb433dc14 ("dma-mapping: add tracing for dma-mapping API calls")
Fixes 68b6dbf1f441 ("dma-mapping: trace more error paths")

---
v2:
- report 0 in the event class instead of splitting the two call sites,
as suggested by Marek. kernel/dma/mapping.c is untouched now, so debug_dma_alloc_coherent() keeps being called for a failed allocation
and decides for itself what to do with it.
- tested on x86_64 rather than compile-tested only.
v1: https://lore.kernel.org/linux-iommu/[email protected]/

Tested with a module that puts a known value in the caller's handle and then asks for 1 TiB from a 32-bit capable device, with the dma_alloc event enabled. Before, the record carries the caller's stale value; after, it carries 0:

-dma_addr=deadbeefdeadbeef size=1099511627776 virt_addr=0000000000000000 +dma_addr=0 size=1099511627776 virt_addr=0000000000000000

A PAGE_SIZE request from the same device, as a control, reports its real address on both kernels, matching the handle the caller got back.

This changes what the record contains, not what the caller does:
*dma_handle is still read to build the tracepoint arguments, since those are evaluated before the static branch.

  include/trace/events/dma.h | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
include/trace/events/dma.h +1 -1
index 9df02c1511de..b06d8f99922d 100644
@@ -134,7 +134,7 @@ DECLARE_EVENT_CLASS(dma_alloc_class,
  	TP_fast_assign(
  		__assign_str(device);
  		__entry->virt_addr = virt_addr;
-		__entry->dma_addr = dma_addr;
+		__entry->dma_addr = virt_addr ? dma_addr : 0;
  		__entry->size = size;
  		__entry->flags = flags;
  		__entry->dir = dir;
Quoted 1 line

base-commit: cee9395acd8043be0644b25c34bfa86623f2b935

maintainer Applied
#2 lore raw
In reply to Donggeun Yoo
Quoted 21 lines · Donggeun Yoo

dma_alloc_attrs() passes *dma_handle to trace_dma_alloc() without checking whether the allocation succeeded. No backend writes it on
failure: dma_direct_alloc(), iommu_dma_alloc() and the dma_map_ops instances assign it only on the path that returns a buffer. Callers usually pass an uninitialized automatic variable, so a failed allocation records whatever the stack held, next to the virt_addr=(null) that marks the record as an error:

dma_alloc: dmatrace dir=BIDIRECTIONAL dma_addr=deadbeefdeadbeef size=1099511627776 virt_addr=0000000000000000

The device coherent pool path reaches the same call: a non-zero return from dma_alloc_from_dev_coherent() means the request was handled, not that it succeeded, so cpu_addr is NULL and dma_handle is untouched once the pool runs out.

For an allocation event a NULL virt_addr already means the request failed, so the address field carries nothing. Report 0 for it in the event class rather than at each call site, which covers dma_alloc_pages() and dma_alloc_sgt_err() as well.

Quoted 4 lines
Fixes 038eb433dc14 ("dma-mapping: add tracing for dma-mapping API calls")
Fixes 68b6dbf1f441 ("dma-mapping: trace more error paths")

Applied to dma-mapping-fixes, thanks!

Quoted 41 lines

---
v2:
- report 0 in the event class instead of splitting the two call sites,
as suggested by Marek. kernel/dma/mapping.c is untouched now, so debug_dma_alloc_coherent() keeps being called for a failed allocation
and decides for itself what to do with it.
- tested on x86_64 rather than compile-tested only.
v1: https://lore.kernel.org/linux-iommu/[email protected]/

Tested with a module that puts a known value in the caller's handle and then asks for 1 TiB from a 32-bit capable device, with the dma_alloc event enabled. Before, the record carries the caller's stale value; after, it carries 0:

-dma_addr=deadbeefdeadbeef size=1099511627776 virt_addr=0000000000000000 +dma_addr=0 size=1099511627776 virt_addr=0000000000000000

A PAGE_SIZE request from the same device, as a control, reports its real address on both kernels, matching the handle the caller got back.

This changes what the record contains, not what the caller does:
*dma_handle is still read to build the tracepoint arguments, since those are evaluated before the static branch.

 include/trace/events/dma.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
include/trace/events/dma.h +1 -1
index 9df02c1511de..b06d8f99922d 100644
@@ -134,7 +134,7 @@ DECLARE_EVENT_CLASS(dma_alloc_class,
 	TP_fast_assign(
 		__assign_str(device);
 		__entry->virt_addr = virt_addr;
-		__entry->dma_addr = dma_addr;
+		__entry->dma_addr = virt_addr ? dma_addr : 0;
 		__entry->size = size;
 		__entry->flags = flags;
 		__entry->dir = dir;
Quoted 1 line

base-commit: cee9395acd8043be0644b25c34bfa86623f2b935

Best regards

Signature · 2 lines
Marek Szyprowski, PhD
Samsung R&D Institute Poland