mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
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:
parent
d1b894c5bb
commit
0bc7c196f3
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user