Re: [PATCH] dma-direct: Clear pages before coherent remap
From: Robin Murphy
Date: Mon May 18 2026 - 08:49:06 EST
On 17/05/2026 5:29 am, Rosen Penev wrote:
Clear pages through their page mapping before creating a coherent
remap for dma-direct allocations. Some architectures implement the
coherent remap as uncached memory, where the generic memset() path may
use cache-only zeroing instructions that are not valid for the returned
CPU mapping.
Which architectures? I'd fear they're just broken in that case - there's every chance that once the caller gets a coherent allocation back, they could also invoke memset() on it - either explicitly, or automatically inserted by the compiler for a structure/array initialisation, or if the buffer subsequently gets mmap()ed to userspace then who knows what. If that's really a problem, this patch isn't going to solve it.
It's rather the point that we clear the buffer the same way that the caller is subsequently going to access it (not least to minimise the chance of any other possible weird coherency side-effects).
Thanks,
Robin.
Keep the existing memset() for non-remapped allocations, but avoid
normal memset() on the remapped coherent allocation path.
Assisted-by: Codex:GPT-5.5
Signed-off-by: Rosen Penev <rosenp@xxxxxxxxx>
---
kernel/dma/direct.c | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index 583c5922bca2..76f7bf43bd28 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -8,6 +8,7 @@
#include <linux/export.h>
#include <linux/mm.h>
#include <linux/dma-map-ops.h>
+#include <linux/highmem.h>
#include <linux/scatterlist.h>
#include <linux/pfn.h>
#include <linux/vmalloc.h>
@@ -104,6 +105,15 @@ static void __dma_direct_free_pages(struct device *dev, struct page *page,
dma_free_contiguous(dev, page, size);
}
+static void dma_direct_zero_pages(struct page *page, size_t size)
+{
+ unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
+ unsigned long i;
+
+ for (i = 0; i < count; i++)
+ clear_highpage(page + i);
+}
+
static struct page *dma_direct_alloc_swiotlb(struct device *dev, size_t size)
{
struct page *page = swiotlb_alloc(dev, size);
@@ -268,6 +278,13 @@ void *dma_direct_alloc(struct device *dev, size_t size,
if (remap) {
pgprot_t prot = dma_pgprot(dev, PAGE_KERNEL, attrs);
+ /*
+ * Zero via the page mapping before creating a potentially
+ * uncached remap. Some architectures cannot safely run normal
+ * memset on uncached memory.
+ */
+ dma_direct_zero_pages(page, size);
+
if (force_dma_unencrypted(dev))
prot = pgprot_decrypted(prot);
@@ -283,10 +300,9 @@ void *dma_direct_alloc(struct device *dev, size_t size,
ret = page_address(page);
if (dma_set_decrypted(dev, ret, size))
goto out_leak_pages;
+ memset(ret, 0, size);
}
- memset(ret, 0, size);
-
if (set_uncached) {
arch_dma_prep_coherent(page, size);
ret = arch_dma_set_uncached(ret, size);