]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/xe/pt: prevent invalid cursor access for purged BOs
authorMatthew Auld <matthew.auld@intel.com>
Thu, 25 Jun 2026 15:20:58 +0000 (16:20 +0100)
committerThomas Hellström <thomas.hellstrom@linux.intel.com>
Thu, 2 Jul 2026 10:29:43 +0000 (12:29 +0200)
During a page table walk for binding, xe_pt_stage_bind() explicitly
skips initializing the xe_res_cursor for purged BOs, treating them
similarly to NULL VMAs by only setting the cursor size.

However, xe_pt_hugepte_possible() and xe_pt_scan_64K() did not check
if the BO was purged before attempting to walk the cursor using
xe_res_dma() and xe_res_next(). Because the cursor was left
uninitialized for purged BOs, this falls through and triggers
warnings like:

  WARNING: drivers/gpu/drm/xe/xe_res_cursor.h:274 at xe_res_next

Fix this by explicitly checking if the BO is purged in both
xe_pt_hugepte_possible() and xe_pt_scan_64K(), returning early just
as we do for NULL VMAs, avoiding the invalid cursor accesses entirely.

As a precaution, also zero-initialize the cursor in xe_pt_stage_bind()
to ensure we don't pass garbage data into the page table walkers
if we ever hit a similar edge case in the future.

Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/8418
Fixes: ad9843aac91a ("drm/xe/madvise: Implement purgeable buffer object support")
Assisted-by: Copilot:gemini-3.1-pro-preview
Reported-by: Matthew Schwartz <matthew.schwartz@linux.dev>
Signed-off-by: Matthew Auld <matthew.auld@intel.com>
Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Arvind Yadav <arvind.yadav@intel.com>
Reviewed-by: Matthew Brost <matthew.brost@intel.com>
Tested-by: Matthew Schwartz <matthew.schwartz@linux.dev>
Link: https://patch.msgid.link/20260625152054.450125-8-matthew.auld@intel.com
(cherry picked from commit 4c7b9c6ece32440e5a435a92076d049450cd2d2e)
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
drivers/gpu/drm/xe/xe_pt.c

index 3380ce710a4834787b0ff23b709f772860696682..670bc2206feab3840b9585575ec1084b3bcd564a 100644 (file)
@@ -433,6 +433,7 @@ xe_pt_insert_entry(struct xe_pt_stage_bind_walk *xe_walk, struct xe_pt *parent,
 static bool xe_pt_hugepte_possible(u64 addr, u64 next, unsigned int level,
                                   struct xe_pt_stage_bind_walk *xe_walk)
 {
+       struct xe_bo *bo = xe_vma_bo(xe_walk->vma);
        u64 size, dma;
 
        if (level > MAX_HUGEPTE_LEVEL)
@@ -446,8 +447,8 @@ static bool xe_pt_hugepte_possible(u64 addr, u64 next, unsigned int level,
        if (next - xe_walk->va_curs_start > xe_walk->curs->size)
                return false;
 
-       /* null VMA's do not have dma addresses */
-       if (xe_vma_is_null(xe_walk->vma))
+       /* null VMA's and purged BO's do not have dma addresses */
+       if (xe_vma_is_null(xe_walk->vma) || (bo && xe_bo_is_purged(bo)))
                return true;
 
        /* if we are clearing page table, no dma addresses*/
@@ -468,6 +469,7 @@ static bool xe_pt_hugepte_possible(u64 addr, u64 next, unsigned int level,
 static bool
 xe_pt_scan_64K(u64 addr, u64 next, struct xe_pt_stage_bind_walk *xe_walk)
 {
+       struct xe_bo *bo = xe_vma_bo(xe_walk->vma);
        struct xe_res_cursor curs = *xe_walk->curs;
 
        if (!IS_ALIGNED(addr, SZ_64K))
@@ -476,8 +478,8 @@ xe_pt_scan_64K(u64 addr, u64 next, struct xe_pt_stage_bind_walk *xe_walk)
        if (next > xe_walk->l0_end_addr)
                return false;
 
-       /* null VMA's do not have dma addresses */
-       if (xe_vma_is_null(xe_walk->vma))
+       /* null VMA's and purged BO's do not have dma addresses */
+       if (xe_vma_is_null(xe_walk->vma) || (bo && xe_bo_is_purged(bo)))
                return true;
 
        xe_res_next(&curs, addr - xe_walk->va_curs_start);
@@ -708,7 +710,7 @@ xe_pt_stage_bind(struct xe_tile *tile, struct xe_vma *vma,
 {
        struct xe_device *xe = tile_to_xe(tile);
        struct xe_bo *bo = xe_vma_bo(vma);
-       struct xe_res_cursor curs;
+       struct xe_res_cursor curs = {};
        struct xe_vm *vm = xe_vma_vm(vma);
        struct xe_pt_stage_bind_walk xe_walk = {
                .base = {