From: sashiko-bot@kernel.org
To: "Matthew Brost" <matthew.brost@intel.com>
Cc: dri-devel@lists.freedesktop.org
Subject: Re: [PATCH v2 32/33] drm/xe: Finalize defrag-IOVA moves with post-copy job
Date: Fri, 10 Jul 2026 22:36:51 +0000 [thread overview]
Message-ID: <20260710223652.212231F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260710215442.2444235-33-matthew.brost@intel.com>
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [Critical] Error paths tear down the destination IOVA mapping without waiting for the submitted asynchronous GPU copy job, leading to IOMMU faults and Write-After-Free.
- [High] xe_bo_defrag_use_iova() checks only the new_tt for IOVA support, ignoring whether old_tt actually uses IOVA, leading to invalid IOVA transfer and IOMMU corruption.
- [High] TLB/L2 cache invalidation for the IOVA defrag is scheduled too early, leading to stale entries in the GPU TLB after the IOMMU update completes.
- [High] Allocating memory with GFP_KERNEL while holding the BO's dma_resv lock creates an AB-BA deadlock risk with the DRM memory shrinker.
- [High] Incomplete SWIOTLB bounce buffer handling causes the GPU to read uninitialized memory after defragmentation.
- [Medium] The return value of dma_iova_sync() is ignored in the defrag finalize job, potentially leaving the IOTLB/cache unflushed.
--
--- Patch [32]: [PATCH v2 32/33] drm/xe: Finalize defrag-IOVA moves with post-copy job ---
commit 23b117a272c85c9d94147e6761afd74a17131d1f
Author: Matthew Brost <matthew.brost@intel.com>
Subject: drm/xe: Finalize defrag-IOVA moves with post-copy job
This commit wires up end-to-end defrag for IOVA-mapped BOs. A defrag move
is eligible whenever the destination TT is IOVA mapped. The packed-copy
step moves only changed pages, and a post-copy finalize job tears down the
temporary packed mapping and relinks the copied pages.
> diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c
> index 16d9e135cba2e..0eee53f4d653f 100644
> --- a/drivers/gpu/drm/xe/xe_bo.c
> +++ b/drivers/gpu/drm/xe/xe_bo.c
[ ... ]
> @@ -855,7 +854,6 @@ struct xe_tt_iova_run_collect {
> };
>
> /* Geometrically grow @arr (element size @elem) to hold at least @need slots. */
> -__maybe_unused
> static int xe_tt_iova_grow(void **arr, unsigned int *cap, unsigned int need,
> size_t elem)
> {
> @@ -866,13 +864,12 @@ static int xe_tt_iova_grow(void **arr, unsigned int *cap, unsigned int need,
> return 0;
>
> new_cap = *cap ? *cap * 2 : 64;
> if (new_cap < need)
> new_cap = need;
>
> p = krealloc_array(*arr, new_cap, elem, GFP_KERNEL);
[Severity: High]
Is it safe to use GFP_KERNEL here? This is called from xe_bo_move() while
holding the buffer object's dma_resv lock.
If the memory allocator triggers direct reclaim, it can invoke the DRM
memory shrinker, which will attempt to acquire dma_resv locks to evict
buffer objects, leading to an AB-BA deadlock.
> if (!p)
> return -ENOMEM;
[ ... ]
> @@ -1047,6 +1041,129 @@ static int xe_tt_map_iova_copy(struct xe_device *xe, struct ttm_tt *new_tt,
> +static struct dma_fence *xe_iova_defrag_job_run(struct xe_dep_job *dep_job)
> +{
[ ... ]
> + /*
> + * Relink the freshly copied new pages from the snapshot captured at job
> + * creation. The destination tt's page array may have been mutated (or
> + * torn down) by TTM since then, so it is never dereferenced here.
> + * Borrowed pages are shared with the old tt and stay correctly linked
> + * for free, so the snapshot only covers the changed runs.
> + */
> + for (l = 0; l < job->copy.nr_links; l++) {
> + int ret = dma_iova_link(dev, &xe_tt->iova,
> + job->copy.links[l].phys,
> + job->copy.links[l].offset,
> + job->copy.links[l].len,
> + DMA_BIDIRECTIONAL,
> + DMA_ATTR_SKIP_CPU_SYNC);
[Severity: High]
Does skipping CPU sync here break configurations using SWIOTLB?
When using DMA_ATTR_SKIP_CPU_SYNC, the DMA API allocates a new bounce
buffer for the physical page but bypasses copying the physical page
contents into it.
This would cause the new IOVA mapping to point to an uninitialized bounce
buffer, leading to the GPU reading uninitialized memory.
> + /*
> + * Point of no failure: the data is already copied and the
> + * reservation ownership has been transferred. A relink failure
> + * leaves a hole in the mapping; there is no safe recovery, so
> + * just warn.
> + */
> + drm_WARN_ON(&xe->drm, ret);
> + }
> +
> + /* Sync the relinked changed runs into the device's view. */
> + for (r = 0; r < job->copy.nr_runs; r++) {
> + size_t off = (size_t)job->copy.runs[r].start << PAGE_SHIFT;
> + size_t len = (size_t)job->copy.runs[r].count << PAGE_SHIFT;
> +
> + dma_iova_sync(dev, &xe_tt->iova, off, len);
[Severity: Medium]
Should the return value of dma_iova_sync() be checked here?
While this is a point of no return and the job cannot be aborted gracefully,
silently ignoring the error hides IOMMU cache sync failures.
A failure could result in stale IOMMU caches and GPU data corruption, so
perhaps at least a drm_WARN_ON() is warranted, similar to the
dma_iova_link() call above.
> + }
[ ... ]
> @@ -1063,7 +1180,6 @@ static int xe_tt_map_iova_copy(struct xe_device *xe, struct ttm_tt *new_tt,
> -__maybe_unused
> static void xe_tt_iova_transfer(struct xe_device *xe,
> struct xe_ttm_tt *new_tt,
> struct xe_ttm_tt *old_tt)
> {
> new_tt->iova = old_tt->iova;
[Severity: High]
What happens if the original old_tt failed to allocate an IOVA mapping and
fell back to an SG mapping?
If old_tt->use_iova is false, old_tt->iova would be uninitialized or empty.
Copying it here would overwrite the valid new_tt->iova state, which could
lead to IOMMU corruption when the finalize job attempts to link pages.
> new_tt->iova_linked = true;
[ ... ]
> +static struct dma_fence *
> +xe_bo_defrag_iova_copy(struct xe_device *xe, struct xe_migrate *migrate,
> + struct xe_bo *bo, struct ttm_resource *old_mem,
> + struct ttm_resource *new_mem, struct ttm_tt *old_tt,
> + bool handle_system_ccs)
> +{
[ ... ]
> + job = kzalloc(sizeof(*job), GFP_KERNEL);
[Severity: High]
Could this GFP_KERNEL allocation cause a deadlock?
Just like the allocation in xe_tt_iova_grow(), this executes under the
buffer object's dma_resv lock during xe_bo_move(). If memory pressure
triggers the shrinker, it might try to acquire the same dma_resv lock.
> + if (!job) {
> + err = -ENOMEM;
> + goto err_fence;
> + }
[ ... ]
> +err_job_init:
> + drm_sched_job_cleanup(&job->dep.drm);
> +err_job:
> + kfree(job);
> +err_fence:
> + dma_fence_put(copy_fence);
> +err_unmap:
> + if (packed)
> + dma_iova_unlink(xe->drm.dev, &new_xe_tt->iova, 0,
> + (size_t)copy.nr_changed << PAGE_SHIFT,
> + DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC);
[Severity: Critical]
Is it safe to unlink the IOVA mapping here without waiting for copy_fence
to signal?
By destroying the destination IOVA page tables immediately, the asynchronous
GPU migration job might still be actively writing to those addresses.
This could result in IOMMU faults or write-after-free corruption if TTM
aborts the move and frees the physical pages while the GPU blit is still
running.
> +err_copy:
> + xe_tt_iova_copy_fini(©);
> + return ERR_PTR(err);
> +}
[ ... ]
> +/*
> + * xe_bo_defrag_use_iova - Whether a defrag move should use the packed IOVA path.
> + */
> +static bool xe_bo_defrag_use_iova(struct ttm_buffer_object *ttm_bo)
> +{
> + struct xe_ttm_tt *xe_tt;
> +
> + if (!ttm_bo->defrag_old_tt || !ttm_bo->ttm)
> + return false;
> +
> + xe_tt = container_of(ttm_bo->ttm, struct xe_ttm_tt, ttm);
> + return xe_tt->use_iova;
[Severity: High]
Does this check adequately ensure the old_tt is actually using IOVA?
The function verifies new_tt->use_iova, but omits checking
old_tt->use_iova.
If the initial old_tt fell back to an SG mapping, this path would still
return true as long as new_tt is IOVA-eligible. This would then misroute
the move to xe_bo_defrag_iova_copy() and trigger the uninitialized IOVA
transfer mentioned earlier.
> +}
[ ... ]
> @@ -1388,6 +1647,8 @@ static int xe_bo_trigger_rebind(struct xe_device *xe, struct xe_bo *bo,
> */
> if (!xe_vm_flush_vm_bo_tlb_async(vm, bo, vm_bo))
> continue;
> + else if (defrag_iova)
> + drm_gpuvm_bo_evict(vm_bo, true);
[Severity: High]
Can this sequence cause the GPU to access freed physical pages?
The function xe_vm_flush_vm_bo_tlb_async() flushes the TLB asynchronously
based on the current fences in the reservation. However, this is executed
before the migration and finalize jobs are added to the buffer object's
reservation.
Because the eviction marking is skipped for defrag_iova, the userspace GPU
context is not stopped. It can access the buffer object and repopulate the
GPU TLB with the old IOMMU translations after this premature flush
completes, but before the finalize job actually updates the IOMMU.
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260710215442.2444235-1-matthew.brost@intel.com?part=32
next prev parent reply other threads:[~2026-07-10 22:36 UTC|newest]
Thread overview: 61+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-10 21:54 [PATCH v2 00/33] drm/ttm, drm/xe: Minimize dma-resv hold times and defragment sub-optimally backed BOs Matthew Brost
2026-07-10 21:54 ` [PATCH v2 01/33] drm/ttm/pool: Allow backing off reclaim at the beneficial order Matthew Brost
2026-07-10 22:08 ` sashiko-bot
2026-07-11 10:38 ` Christian König
2026-07-10 21:54 ` [PATCH v2 02/33] drm/ttm/pool: Add ttm_pool_page_order_nodma() helper Matthew Brost
2026-07-11 10:39 ` Christian König
2026-07-10 21:54 ` [PATCH v2 03/33] drm/ttm: Record sub-optimal page order allocations in ttm_tt Matthew Brost
2026-07-10 21:54 ` [PATCH v2 04/33] drm/ttm: Introduce ttm_pool_alloc_iter for __ttm_pool_alloc() Matthew Brost
2026-07-10 22:03 ` sashiko-bot
2026-07-10 21:54 ` [PATCH v2 05/33] drm/ttm: Support defragmentation moves Matthew Brost
2026-07-10 22:09 ` sashiko-bot
2026-07-10 21:54 ` [PATCH v2 06/33] drm/ttm: Add fault injection for beneficial-order allocation failures Matthew Brost
2026-07-10 21:54 ` [PATCH v2 07/33] drm/ttm: Harvest beneficial-order pages on defragmentation moves Matthew Brost
2026-07-10 22:19 ` sashiko-bot
2026-07-10 21:54 ` [PATCH v2 08/33] drm/ttm: Bound page (re)allocation per defragmentation move Matthew Brost
2026-07-10 22:17 ` sashiko-bot
2026-07-10 21:54 ` [PATCH v2 09/33] drm/ttm: Preallocate beneficial-order defrag pages outside the lock Matthew Brost
2026-07-10 22:09 ` sashiko-bot
2026-07-10 21:54 ` [PATCH v2 10/33] drm/ttm: Add full out-of-lock preallocation for ttm_pool_alloc() Matthew Brost
2026-07-10 21:54 ` [PATCH v2 11/33] drm/gpusvm: Add a DMA-mapping accounting callback Matthew Brost
2026-07-10 22:10 ` sashiko-bot
2026-07-10 21:54 ` [PATCH v2 12/33] drm/xe: Add debugfs stats for DMA-mapped pages per order Matthew Brost
2026-07-10 22:23 ` sashiko-bot
2026-07-10 21:54 ` [PATCH v2 13/33] drm/xe: Flush L2 asynchronously in xe_bo_trigger_rebind() Matthew Brost
2026-07-10 22:18 ` sashiko-bot
2026-07-10 21:54 ` [PATCH v2 14/33] drm/xe: Destroy page tables after unlinking all VMAs on VM close Matthew Brost
2026-07-10 21:54 ` [PATCH v2 15/33] drm/xe: Track BOs backed at a sub-optimal page order Matthew Brost
2026-07-10 22:18 ` sashiko-bot
2026-07-10 21:54 ` [PATCH v2 16/33] drm/xe: Back off beneficial-order reclaim under defrag pressure Matthew Brost
2026-07-10 21:54 ` [PATCH v2 17/33] drm/xe: Add xe_migrate_copy_defrag() for on-GPU defrag copies Matthew Brost
2026-07-10 22:17 ` sashiko-bot
2026-07-10 21:54 ` [PATCH v2 18/33] drm/xe: Handle defrag moves in xe_bo_move() Matthew Brost
2026-07-10 22:25 ` sashiko-bot
2026-07-10 21:54 ` [PATCH v2 19/33] drm/xe: Skip self-copies for borrowed pages on defrag moves Matthew Brost
2026-07-10 22:18 ` sashiko-bot
2026-07-10 21:54 ` [PATCH v2 20/33] drm/xe: Add a page defragmentation worker Matthew Brost
2026-07-10 22:24 ` sashiko-bot
2026-07-10 21:54 ` [PATCH v2 21/33] drm/xe: Add defrag GT stats Matthew Brost
2026-07-10 22:16 ` sashiko-bot
2026-07-10 21:54 ` [PATCH v2 22/33] drm/xe: Add Kconfig.profile options for BO defrag configuration Matthew Brost
2026-07-10 21:54 ` [PATCH v2 23/33] drm/xe: Defrag using out-of-lock page preallocation Matthew Brost
2026-07-10 22:27 ` sashiko-bot
2026-07-10 21:54 ` [PATCH v2 24/33] drm/xe: Add defrag profiling tracepoints Matthew Brost
2026-07-10 22:18 ` sashiko-bot
2026-07-10 21:54 ` [PATCH v2 25/33] drm/xe: Preallocate system BO backing outside the dma-resv lock Matthew Brost
2026-07-10 22:21 ` sashiko-bot
2026-07-10 21:54 ` [PATCH v2 26/33] drm/xe: Add tracepoint for xe_gem_create_ioctl Matthew Brost
2026-07-10 22:20 ` sashiko-bot
2026-07-10 21:54 ` [PATCH v2 27/33] drm/xe: Add IOVA-based xe_res_cursor variant Matthew Brost
2026-07-10 22:24 ` sashiko-bot
2026-07-10 21:54 ` [PATCH v2 28/33] drm/xe: Use IOVA-based DMA mapping for eligible tt BOs Matthew Brost
2026-07-10 21:54 ` [PATCH v2 29/33] drm/xe: Add per-device dependency scheduler for IOVA defrag finalize Matthew Brost
2026-07-10 22:27 ` sashiko-bot
2026-07-10 21:54 ` [PATCH v2 30/33] drm/xe: Add packed copy-step IOVA mapping for defrag Matthew Brost
2026-07-10 21:54 ` [PATCH v2 31/33] drm/xe: Blit src-natural to dst-packed for defrag-IOVA copies Matthew Brost
2026-07-10 22:30 ` sashiko-bot
2026-07-10 21:54 ` [PATCH v2 32/33] drm/xe: Finalize defrag-IOVA moves with post-copy job Matthew Brost
2026-07-10 22:36 ` sashiko-bot [this message]
2026-07-10 21:54 ` [PATCH v2 33/33] drm/amdgpu: Preallocate system BO pages outside the reservation lock Matthew Brost
2026-07-10 22:29 ` sashiko-bot
2026-07-11 10:33 ` [PATCH v2 00/33] drm/ttm, drm/xe: Minimize dma-resv hold times and defragment sub-optimally backed BOs Christian König
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260710223652.212231F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=matthew.brost@intel.com \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox