An UNMAP (or the unmap half of a REMAP) can leave a BO with no remaining VMA mappings anywhere. Such a BO is unlikely to be touched again soon, so rather than leaving it at whatever priority band it had while still in active use, drop it to XE_BO_PRIORITY_LOW, the lowest level, so it becomes one of the first candidates considered for eviction/shrinking. This applies both to BOs private to a VM and to extobjs shared across multiple VMs (bo->vm == NULL) -- an extobj with no bindings left anywhere is just as good an eviction/shrink candidate as an unmapped private BO. Imported bos are excluded, since their vma_count is never tracked (xe_bo_vma_count_inc/dec_locked() are no-ops for them), so it would never reflect anything meaningful.
This has to be done inside xe_vma_destroy() itself, right after xe_bo_vma_count_dec_locked(), rather than by its callers after the fact: xe_vma_destroy() may drop the last reference to the BO via xe_bo_put() in xe_vma_destroy_late() (called either synchronously, or asynchronously via a fence callback), so a caller that stashed a pointer to the BO before calling xe_vma_destroy() and then dereferences it afterwards risks a use-after-free. Doing the check and update before that possible final put avoids this. bo->purgeable.vma_count, which xe_bo_vma_count_dec_locked() just updated, tells us whether the BO has become fully unmapped. A REMAP that only shrinks a mapping still leaves vma_count > 0 via the prev/next VMA(s) created earlier in the bind, so those are correctly left untouched. This runs under the BO's dma-resv, already asserted held via xe_bo_assert_held() just above. Cc: Carlos Santa <[email protected]> Cc: Ryan Neph <[email protected]> Assisted-by: GitHub_Copilot:claude-sonnet-5 Signed-off-by: Matthew Brost <[email protected]> --- drivers/gpu/drm/xe/xe_vm.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index d42390e7ae2f..8f3827f957ea 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -1282,6 +1282,22 @@ static void xe_vma_destroy(struct xe_vma *vma, struct dma_fence *fence) xe_bo_vma_count_dec_locked(bo); if (vma->attr.purgeable_state == XE_MADV_PURGEABLE_WILLNEED) xe_bo_willneed_put_locked(bo); + + /* + * @bo has just lost a VMA mapping. If it now has none left + * anywhere, it is unlikely to be used again soon, so lower + * its TTM priority to the lowest level, making it one of the + * first buffers considered for eviction/shrinking. This + * applies both to BOs private to @vm and to extobjs shared + * across multiple VMs (bo->vm == NULL), but not to imported + * bos, whose vma_count is never tracked. Must be done here, + * rather than by the caller, as this may be the last + * reference to @bo (see xe_vma_destroy_late()). + */ + if (!drm_gem_is_imported(&bo->ttm.base) && + !bo->purgeable.vma_count && + bo->ttm.priority != XE_BO_PRIORITY_LOW) + xe_bo_update_ttm_priority(bo, XE_BO_PRIORITY_LOW); } xe_vm_assert_held(vm); -- 2.34.1
