[PATCH] lib/scatterlist: fix sg_page_count and sg_dma_page_count
From: Julian Orth
Date: Sun Mar 08 2026 - 09:56:01 EST
A user reported memory corruption in the Jay wayland compositor [1]. The
corruption started when archlinux enabled
CONFIG_TRANSPARENT_HUGEPAGE_SHMEM_HUGE_WITHIN_SIZE in kernel 6.19.5.
The compositor uses udmabuf to upload memory from memfds to the GPU.
When running an affected kernel, the following warnings are logged:
a - addrs >= max_entries
WARNING: drivers/gpu/drm/drm_prime.c:1089 at drm_prime_sg_to_dma_addr_array+0x86/0xc0, CPU#31: jay/1864
[...]
Call Trace:
<TASK>
amdgpu_bo_move+0x188/0x800 [amdgpu 3b451640234948027c09e9b39e6520bc7e5471cf]
Disabling the use of huge pages at runtime via
/sys/kernel/mm/transparent_hugepage/shmem_enabled fixes the issue.
udmabuf allocates a scatterlist with buffer_size/PAGE_SIZE entries. Each
entry has a length of PAGE_SIZE. With huge pages disabled, it appears
that sg->offset is always 0. With huge pages enabled, sg->offset is
incremented by PAGE_SIZE until the end of the huge page.
With the code before this patch, this causes __sg_page_iter_dma_next to
iterate 1 + 2 + 3 + ... + 512 times over a single huge page instead of
512 times.
This effect can be seen in the screenshot provided by the user where
parts of the image are repeated and with each repetition the base offset
shifts by one page and the size of the repeated data grows by one page.
[1]: https://github.com/mahkoh/jay/issues/779
Fixes: a321e91b6d73 ("lib/scatterlist: add simple page iterator")
Fixes: d901b2760dc6 ("lib/scatterlist: Provide a DMA page iterator")
Signed-off-by: Julian Orth <ju.orth@xxxxxxxxx>
---
I have not verified if this negatively affects any other users of the
iterator interface. In particular, if sg->offset is allowed to not be
page aligned.
The use of sg->offset in these functions looks suspect and removing it
fixes the issue. I have not looked further than that.
---
lib/scatterlist.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index d773720d11bf..001f33ec4e49 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -738,7 +738,7 @@ EXPORT_SYMBOL(__sg_page_iter_start);
static int sg_page_count(struct scatterlist *sg)
{
- return PAGE_ALIGN(sg->offset + sg->length) >> PAGE_SHIFT;
+ return PAGE_ALIGN(sg->length) >> PAGE_SHIFT;
}
bool __sg_page_iter_next(struct sg_page_iter *piter)
@@ -762,7 +762,7 @@ EXPORT_SYMBOL(__sg_page_iter_next);
static int sg_dma_page_count(struct scatterlist *sg)
{
- return PAGE_ALIGN(sg->offset + sg_dma_len(sg)) >> PAGE_SHIFT;
+ return PAGE_ALIGN(sg_dma_len(sg)) >> PAGE_SHIFT;
}
bool __sg_page_iter_dma_next(struct sg_dma_page_iter *dma_iter)
---
base-commit: fb07430e6f98ccff61f6f1a06d01d7f12e29c6d3
change-id: 20260308-scatterlist-8a06ca446bc1
Best regards,
--
Julian Orth <ju.orth@xxxxxxxxx>