drm/gpusvm: free the whole IOVA reservation on unmap

dma_iova_try_alloc() reserves IOVA for the entire range, but in a mixed
range only the system pages are linked (their total size is state_offset)
while device pages never touch the IOVA state. dma_iova_destroy() with
state_offset only frees the linked part, permanently leaking the IOVA
reserved for the device pages and eventually exhausting the IOVA space.

Unlink the linked system-page portion and free the whole reserved IOVA
instead. On the get_pages() error path state_offset is 0 (no page linked,
dma_addr[0] unpopulated), so skip the unlink and just free the reservation;
this also avoids reading the uninitialized dma_addr[0].dir there.

Allocate the dma_addr array with the zeroing kvzalloc_objs() so every entry
has a well-defined value.

This issue was found by Sashiko AI review.

Fixes: 37ad039fb3 ("drm/gpusvm: Use dma-map IOVA alloc, link, and sync API in GPU SVM")
Cc: stable@vger.kernel.org
Reviewed-by: Matthew Brost <matthew.brost@intel.com>
Signed-off-by: Honglei Huang <honghuan@amd.com>
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Link: https://patch.msgid.link/20260701062800.409248-2-honghuan@amd.com
This commit is contained in:
Honglei Huang 2026-07-01 14:27:58 +08:00 committed by Matthew Brost
parent d1b894c5bb
commit 0bc7c196f3

View File

@ -1146,10 +1146,19 @@ static void __drm_gpusvm_unmap_pages(struct drm_gpusvm *gpusvm,
};
bool use_iova = dma_use_iova(&svm_pages->state);
if (use_iova)
dma_iova_destroy(dev, &svm_pages->state,
svm_pages->state_offset,
svm_pages->dma_addr[0].dir, 0);
/*
* IOVA is reserved for the whole range but only the linked
* system pages (state_offset bytes) need unlinking; free the
* entire reservation to avoid leaking the device-page part.
* On the error path state_offset is 0, so just free it.
*/
if (use_iova) {
if (svm_pages->state_offset)
dma_iova_unlink(dev, &svm_pages->state, 0,
svm_pages->state_offset,
svm_pages->dma_addr[0].dir, 0);
dma_iova_free(dev, &svm_pages->state);
}
for (i = 0, j = 0; i < npages; j++) {
struct drm_pagemap_addr *addr = &svm_pages->dma_addr[j];
@ -1486,7 +1495,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;