* [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
* 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
* [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 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.