]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
dma-debug: Ensure mappings are created and released with matching attributes
authorLeon Romanovsky <leonro@nvidia.com>
Fri, 1 May 2026 06:35:10 +0000 (09:35 +0300)
committerMarek Szyprowski <m.szyprowski@samsung.com>
Fri, 8 May 2026 20:28:19 +0000 (22:28 +0200)
The DMA API expects that callers use the same attributes when mapping
and unmapping. Add tracking to verify this and catch mismatches.

Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
Reviewed-by: Samiullah Khawaja <skhawaja@google.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Link: https://lore.kernel.org/r/20260501-dma-attrs-debug-v2-6-8dbac75cd501@nvidia.com
kernel/dma/debug.c

index 3dfed51c3d9aab6100a32cae68184052be2c444c..c38efc1ac8d6cde71ddfe3692fb4c0ec86ccf7ad 100644 (file)
@@ -1074,6 +1074,29 @@ static void check_unmap(struct dma_debug_entry *ref)
                           type2name[entry->type]);
        }
 
+       /*
+        * This may be no bug in reality - but DMA API still expects
+        * that entry is unmapped with same attributes as it was mapped.
+        *
+        * DMA_ATTR_UNMAP_VALID lists the attributes that must be identical
+        * between map and unmap. Any attribute outside this set (e.g.
+        * DMA_ATTR_NO_WARN, DMA_ATTR_SKIP_CPU_SYNC) is allowed to differ.
+        */
+#define DMA_ATTR_UNMAP_VALID                                               \
+       (DMA_ATTR_NO_KERNEL_MAPPING | DMA_ATTR_FORCE_CONTIGUOUS |          \
+        DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT | DMA_ATTR_PRIVILEGED | \
+        DMA_ATTR_CC_SHARED)
+       if ((ref->attrs & DMA_ATTR_UNMAP_VALID) !=
+           (entry->attrs & DMA_ATTR_UNMAP_VALID)) {
+               err_printk(ref->dev, entry,
+                          "device driver frees "
+                          "DMA memory with different attributes "
+                          "[device address=0x%016llx] [size=%llu bytes] "
+                          "[mapped with 0x%lx] [unmapped with 0x%lx]\n",
+                          ref->dev_addr, ref->size, entry->attrs, ref->attrs);
+       }
+#undef DMA_ATTR_UNMAP_VALID
+
        hash_bucket_del(entry);
        put_hash_bucket(bucket, flags);