* [PATCH 0/2] drm/gpusvm: fix IOVA unmap path in __drm_gpusvm_unmap_pages()
@ 2026-06-27 3:33 Honglei Huang
2026-06-27 3:33 ` [PATCH 1/2] drm/gpusvm: avoid reading uninitialized dma_addr[0].dir on IOVA unmap Honglei Huang
2026-06-27 3:33 ` [PATCH 2/2] drm/gpusvm: do not route system pages to device_unmap() " Honglei Huang
0 siblings, 2 replies; 5+ messages in thread
From: Honglei Huang @ 2026-06-27 3:33 UTC (permalink / raw)
To: sima, matthew.brost, rodrigo.vivi, thomas.hellstrom, dakr,
intel-xe
Cc: Ray.Huang, dri-devel, honghuan
From: Honglei Huang <honghuan@amd.com>
Two small fixes for the IOVA unmap path in __drm_gpusvm_unmap_pages(),
both spotted by AI review:
- Avoid reading dma_addr[0].dir when no pages were mapped (the
get_pages() error path can reach unmap with npages == 0 and an
uninitialised dma_addr array). Use a zeroing allocator and guard the
direction argument with npages.
- Do not route system pages to the device_unmap() callback on the IOVA
path. Branch off addr->proto so system pages only get an explicit
dma_unmap_page() in the non IOVA case, and only real device pages
reach device_unmap().
Honglei Huang (2):
drm/gpusvm: avoid reading uninitialized dma_addr[0].dir on IOVA unmap
drm/gpusvm: do not route system pages to device_unmap() on IOVA unmap
drivers/gpu/drm/drm_gpusvm.c | 28 ++++++++++++++++++++--------
1 file changed, 20 insertions(+), 8 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/2] drm/gpusvm: avoid reading uninitialized dma_addr[0].dir on IOVA unmap
2026-06-27 3:33 [PATCH 0/2] drm/gpusvm: fix IOVA unmap path in __drm_gpusvm_unmap_pages() Honglei Huang
@ 2026-06-27 3:33 ` Honglei Huang
2026-06-27 3:52 ` sashiko-bot
2026-06-27 3:33 ` [PATCH 2/2] drm/gpusvm: do not route system pages to device_unmap() " Honglei Huang
1 sibling, 1 reply; 5+ messages in thread
From: Honglei Huang @ 2026-06-27 3:33 UTC (permalink / raw)
To: sima, matthew.brost, rodrigo.vivi, thomas.hellstrom, dakr,
intel-xe
Cc: Ray.Huang, dri-devel, honghuan
From: Honglei Huang <honghuan@amd.com>
__drm_gpusvm_unmap_pages() unconditionally reads
svm_pages->dma_addr[0].dir to pass the DMA direction to dma_iova_destroy()
whenever dma_use_iova() is true. On the error path of drm_gpusvm_get_pages()
the first dma_iova_link() may fail at i == 0, jumping to err_unmap with
num_dma_mapped == 0. As dma_addr came from a non zeroing allocator, dma_addr[0]
is then uninitialised, so the direction argument reads garbage. This trips
KMSAN and feeds a bogus dma_data_direction to the DMA layer.
Allocate the dma_addr array with the kvzalloc_objs() so every entry
has a correct value, and guard the direction argument
with npages so dma_iova_destroy() never dereferences dma_addr[0] when no
pages were mapped.
Reported-by: Sashiko AI review
Signed-off-by: Honglei Huang <honghuan@amd.com>
---
drivers/gpu/drm/drm_gpusvm.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c
index b2a848a7b2d..a9adf128eec 100644
--- a/drivers/gpu/drm/drm_gpusvm.c
+++ b/drivers/gpu/drm/drm_gpusvm.c
@@ -1224,10 +1224,17 @@ static void __drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
};
bool use_iova = dma_use_iova(&svm_pages->state);
+ /*
+ * On the get_pages() error path npages can be 0 with
+ * dma_addr[0] still unpopulated, while the IOVA reservation
+ * already needs tearing down. Pass DMA_BIDIRECTIONAL in that
+ * case instead of reading dma_addr[0].dir.
+ */
if (use_iova)
dma_iova_destroy(dev, &svm_pages->state,
svm_pages->state_offset,
- svm_pages->dma_addr[0].dir, 0);
+ npages ? svm_pages->dma_addr[0].dir :
+ DMA_BIDIRECTIONAL, 0);
for (i = 0, j = 0; i < npages; j++) {
struct drm_pagemap_addr *addr = &svm_pages->dma_addr[j];
@@ -1548,7 +1555,7 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm,
/* Unlock and restart mapping to allocate memory. */
drm_gpusvm_notifier_unlock(gpusvm);
svm_pages->dma_addr =
- kvmalloc_objs(*svm_pages->dma_addr, npages);
+ kvzalloc_objs(*svm_pages->dma_addr, npages);
if (!svm_pages->dma_addr) {
err = -ENOMEM;
goto err_free;
--
2.34.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/2] drm/gpusvm: do not route system pages to device_unmap() on IOVA unmap
2026-06-27 3:33 [PATCH 0/2] drm/gpusvm: fix IOVA unmap path in __drm_gpusvm_unmap_pages() Honglei Huang
2026-06-27 3:33 ` [PATCH 1/2] drm/gpusvm: avoid reading uninitialized dma_addr[0].dir on IOVA unmap Honglei Huang
@ 2026-06-27 3:33 ` Honglei Huang
2026-06-27 4:02 ` sashiko-bot
1 sibling, 1 reply; 5+ messages in thread
From: Honglei Huang @ 2026-06-27 3:33 UTC (permalink / raw)
To: sima, matthew.brost, rodrigo.vivi, thomas.hellstrom, dakr,
intel-xe
Cc: Ray.Huang, dri-devel, honghuan
From: Honglei Huang <honghuan@amd.com>
In a mixed range: ctx->allow_mixed dpagemap is not NULL while some entries
are system pages. The unmap loop used:
dma_unmap_page(...);
else if (dpagemap && dpagemap->ops->device_unmap)
dpagemap->ops->device_unmap(...);
When use_iova is true the first condition is false for system pages, so they
fall through to device_unmap() and a system DMA address is handed to the
device specific unmap callback, risking invalid accesses or state corruption.
Key the branch off addr->proto instead: system pages only need an explicit
dma_unmap_page() in the non IOVA case, IOVA system pages are already torn
down by the single dma_iova_destroy(), and only genuine device pages
reach device_unmap().
Reported-by: Sashiko AI review
Signed-off-by: Honglei Huang <honghuan@amd.com>
---
drivers/gpu/drm/drm_gpusvm.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c
index a9adf128eec..96c14618591 100644
--- a/drivers/gpu/drm/drm_gpusvm.c
+++ b/drivers/gpu/drm/drm_gpusvm.c
@@ -1239,12 +1239,17 @@ static void __drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
for (i = 0, j = 0; i < npages; j++) {
struct drm_pagemap_addr *addr = &svm_pages->dma_addr[j];
- if (!use_iova && addr->proto == DRM_INTERCONNECT_SYSTEM)
- dma_unmap_page(dev,
- addr->addr,
- PAGE_SIZE << addr->order,
- addr->dir);
- else if (dpagemap && dpagemap->ops->device_unmap)
+ if (addr->proto == DRM_INTERCONNECT_SYSTEM) {
+ /*
+ * IOVA pages are cleaned by the ma_iova_destroy() above.
+ * only the non IOVA mappings need unmap here.
+ */
+ if (!use_iova)
+ dma_unmap_page(dev,
+ addr->addr,
+ PAGE_SIZE << addr->order,
+ addr->dir);
+ } else if (dpagemap && dpagemap->ops->device_unmap)
dpagemap->ops->device_unmap(dpagemap,
dev, addr);
i += 1 << addr->order;
--
2.34.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] drm/gpusvm: avoid reading uninitialized dma_addr[0].dir on IOVA unmap
2026-06-27 3:33 ` [PATCH 1/2] drm/gpusvm: avoid reading uninitialized dma_addr[0].dir on IOVA unmap Honglei Huang
@ 2026-06-27 3:52 ` sashiko-bot
0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-06-27 3:52 UTC (permalink / raw)
To: Honglei Huang; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Device memory mappings created by `device_map` are leaked on the error path in `drm_gpusvm_get_pages()` because `svm_pages->dpagemap` is NULL.
--
commit ba7f1a24074336f55f3749b1bf75d6961df95930
Author: Honglei Huang <honghuan@amd.com>
drm/gpusvm: avoid reading uninitialized dma_addr[0].dir on IOVA unmap
This commit fixes an issue where an uninitialized DMA direction could be
passed to dma_iova_destroy() on the get_pages() error path. It guards
the direction argument with a check on npages and zeroes the dma_addr array.
> diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c
> index 958cb605aedd5..2d74e2aae0a77 100644
> --- a/drivers/gpu/drm/drm_gpusvm.c
> +++ b/drivers/gpu/drm/drm_gpusvm.c
> @@ -1146,10 +1146,17 @@ static void __drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
> };
> bool use_iova = dma_use_iova(&svm_pages->state);
>
> + /*
> + * On the get_pages() error path npages can be 0 with
> + * dma_addr[0] still unpopulated, while the IOVA reservation
> + * already needs tearing down. Pass DMA_BIDIRECTIONAL in that
> + * case instead of reading dma_addr[0].dir.
> + */
> if (use_iova)
> dma_iova_destroy(dev, &svm_pages->state,
> svm_pages->state_offset,
> - svm_pages->dma_addr[0].dir, 0);
> + npages ? svm_pages->dma_addr[0].dir :
> + DMA_BIDIRECTIONAL, 0);
>
> for (i = 0, j = 0; i < npages; j++) {
> struct drm_pagemap_addr *addr = &svm_pages->dma_addr[j];
[Severity: High]
This is a pre-existing issue, but does this error path leak device mappings?
When drm_gpusvm_get_pages() maps device pages successfully using
dpagemap->ops->device_map(), but then fails on a subsequent page (for
example, returning -EOPNOTSUPP because ctx->allow_mixed is false), it jumps
to the err_unmap label:
drm_gpusvm_get_pages() {
...
err_unmap:
svm_pages->flags.has_dma_mapping = true;
__drm_gpusvm_unmap_pages(gpusvm, svm_pages, num_dma_mapped);
}
However, svm_pages->dpagemap hasn't been assigned the local dpagemap yet.
When __drm_gpusvm_unmap_pages() runs, it reads the uninitialized
svm_pages->dpagemap as NULL.
This causes the cleanup loop in __drm_gpusvm_unmap_pages() to skip
device_unmap():
__drm_gpusvm_unmap_pages() {
struct drm_pagemap *dpagemap = svm_pages->dpagemap;
...
for (i = 0, j = 0; i < npages; j++) {
...
} else if (dpagemap && dpagemap->ops->device_unmap) {
dpagemap->ops->device_unmap(dpagemap, dev, addr);
}
}
}
Since dpagemap is NULL, device_unmap() is never called for the already
mapped pages. Can this permanently leak the device mappings?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627033325.3795298-1-honglei1.huang@amd.com?part=1
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] drm/gpusvm: do not route system pages to device_unmap() on IOVA unmap
2026-06-27 3:33 ` [PATCH 2/2] drm/gpusvm: do not route system pages to device_unmap() " Honglei Huang
@ 2026-06-27 4:02 ` sashiko-bot
0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-06-27 4:02 UTC (permalink / raw)
To: Honglei Huang; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] IOVA address space is permanently leaked when unmapping mixed ranges because `dma_iova_try_alloc` allocates for the entire range but `dma_iova_destroy` only frees the linked portion.
--
commit 00ffc2a555c26b1b1afa96a3e7aabeee992b2163
Author: Honglei Huang <honghuan@amd.com>
drm/gpusvm: do not route system pages to device_unmap() on IOVA unmap
This commit fixes an issue in mixed ranges where system pages were incorrectly
routed to device_unmap() during IOVA unmap by checking the page protocol.
> diff --git a/drivers/gpu/drm/drm_gpusvm.c b/drivers/gpu/drm/drm_gpusvm.c
> index 2d74e2aae0a77..80b9a3f4cb919 100644
> --- a/drivers/gpu/drm/drm_gpusvm.c
> +++ b/drivers/gpu/drm/drm_gpusvm.c
> @@ -1161,12 +1161,17 @@ static void __drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
> for (i = 0, j = 0; i < npages; j++) {
> struct drm_pagemap_addr *addr = &svm_pages->dma_addr[j];
>
> - if (!use_iova && addr->proto == DRM_INTERCONNECT_SYSTEM)
> - dma_unmap_page(dev,
> - addr->addr,
> - PAGE_SIZE << addr->order,
> - addr->dir);
> - else if (dpagemap && dpagemap->ops->device_unmap)
> + if (addr->proto == DRM_INTERCONNECT_SYSTEM) {
> + /*
> + * IOVA pages are cleaned by the ma_iova_destroy() above.
[Severity: High]
This isn't a bug introduced by this patch, but looking at how IOVA pages are
cleaned up here, does this leak IOVA address space for mixed ranges?
In drm_gpusvm_get_pages(), dma_iova_try_alloc() allocates IOVA space for the
entire range size:
dma_iova_try_alloc(gpusvm->drm->dev, state, 0, npages * PAGE_SIZE);
However, when this range is unmapped in __drm_gpusvm_unmap_pages(),
dma_iova_destroy() is called with svm_pages->state_offset as the length:
dma_iova_destroy(dev, &svm_pages->state,
svm_pages->state_offset,
npages ? svm_pages->dma_addr[0].dir :
DMA_BIDIRECTIONAL, 0);
If a user-space application allocates a range and migrates part of it to
device memory (creating a mixed range), state_offset will only be the sum
of the linked system page sizes.
Since dma_iova_destroy() only frees exactly the requested length, it seems
the unlinked portion of the original IOVA allocation is permanently leaked,
which could eventually exhaust the IOVA space.
> + */
> + if (!use_iova)
> + dma_unmap_page(dev,
> + addr->addr,
> + PAGE_SIZE << addr->order,
> + addr->dir);
> + } else if (dpagemap && dpagemap->ops->device_unmap)
> dpagemap->ops->device_unmap(dpagemap,
> dev, addr);
> i += 1 << addr->order;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627033325.3795298-1-honglei1.huang@amd.com?part=2
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-06-27 4:02 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-27 3:33 [PATCH 0/2] drm/gpusvm: fix IOVA unmap path in __drm_gpusvm_unmap_pages() Honglei Huang
2026-06-27 3:33 ` [PATCH 1/2] drm/gpusvm: avoid reading uninitialized dma_addr[0].dir on IOVA unmap Honglei Huang
2026-06-27 3:52 ` sashiko-bot
2026-06-27 3:33 ` [PATCH 2/2] drm/gpusvm: do not route system pages to device_unmap() " Honglei Huang
2026-06-27 4:02 ` sashiko-bot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.