From: sashiko-bot@kernel.org
To: "Matthew Brost" <matthew.brost@intel.com>
Cc: dri-devel@lists.freedesktop.org
Subject: Re: [PATCH v2 07/33] drm/ttm: Harvest beneficial-order pages on defragmentation moves
Date: Fri, 10 Jul 2026 22:19:56 +0000 [thread overview]
Message-ID: <20260710221956.BDECD1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260710215442.2444235-8-matthew.brost@intel.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Critical] Defragmentation of DMA-allocated or external TTs causes massive out-of-bounds memory writes due to misinterpreting page private data as an allocation order.
- [Critical] Misaligned chunks between the old and new TT lead to partial chunk harvesting, resulting in a severe use-after-free.
- [High] If the driver's move callback returns `-EMULTIHOP`, the defragmentation rollback is bypassed, causing a permanent memory leak of the original buffer object TT.
--
--- Patch [7]: [PATCH v2 07/33] drm/ttm: Harvest beneficial-order pages on defragmentation moves ---
commit 74e91ed102adee47c82989ab7b4f83fd70da47c2
Author: Matthew Brost <matthew.brost@intel.com>
drm/ttm: Harvest beneficial-order pages on defragmentation moves
A defragmentation move relocates a populated tt into a freshly allocated
one so that sub-beneficial-order chunks can be upgraded to the device's
beneficial order. Previously, if allocation could not complete entirely
at beneficial order, the move failed and all progress was discarded.
Instead, once allocation has successfully upgraded part of the object,
the remainder of the old tt is harvested to complete the new tt. Thread
the BO's old, still-populated tt into the page allocator via a new
ttm_operation_ctx::defrag_old_tt.
> diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
> --- a/drivers/gpu/drm/ttm/ttm_bo.c
> +++ b/drivers/gpu/drm/ttm/ttm_bo.c
[ ... ]
> @@ -218,10 +225,18 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
> if (defrag)
> ttm_bo_unmap_virtual(bo);
>
> ret = bdev->funcs->move(bo, evict, ctx, mem, hop);
> if (ret) {
> if (ret == -EMULTIHOP)
> return ret;
> goto out_err;
> }
>
> if (bo->defrag_old_tt) {
[Severity: High]
If bdev->funcs->move() returns -EMULTIHOP, does returning immediately bypass
the out_err rollback path?
It looks like the original TT remains stashed in bo->defrag_old_tt instead of
being restored.
When the move is retried, it appears bo->defrag_old_tt would be overwritten
or cleared, causing the original buffer object TT and its unborrowed pages
to be permanently leaked.
> diff --git a/drivers/gpu/drm/ttm/ttm_pool.c b/drivers/gpu/drm/ttm/ttm_pool.c
> --- a/drivers/gpu/drm/ttm/ttm_pool.c
> +++ b/drivers/gpu/drm/ttm/ttm_pool.c
[ ... ]
> +static int ttm_pool_iter_reuse_old(struct ttm_pool_alloc_iter *it)
> +{
> + unsigned int harvest_order;
> + pgoff_t off;
> + int r;
> +
> + if (!it->defrag_old_tt || !it->beneficial_order)
> + return TTM_POOL_ITER_FILL;
> +
> + off = it->tt->num_pages - it->alloc->remaining_pages;
> + harvest_order = ttm_pool_defrag_old_order(it->pool, it->defrag_old_tt,
> + off, &it->old_cursor);
> +
> + if (harvest_order < it->beneficial_order &&
> + it->order >= it->beneficial_order)
> + return TTM_POOL_ITER_FILL;
> +
> + it->order = harvest_order;
> + r = ttm_pool_harvest_page(it->defrag_old_tt, it->order, off, it->alloc);
[Severity: Critical]
What happens if the new TT allocation size is unaligned, causing the offset
into the old TT to land in the middle of a large chunk?
Could ttm_pool_iter_reuse_old() or ttm_pool_harvest_remaining() harvest a
partial chunk, such as just the tail page?
If it harvests a tail page, the page order would be read as 0 since the
private data is only populated on the head page.
> diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
> --- a/drivers/gpu/drm/ttm/ttm_tt.c
> +++ b/drivers/gpu/drm/ttm/ttm_tt.c
[ ... ]
> +void ttm_tt_defrag_disown_borrowed(struct ttm_tt *tt, const struct ttm_tt *src)
> +{
> + pgoff_t i = 0, run_start = 0;
> + bool in_run = false;
[ ... ]
> + while (i < tt->num_pages) {
> + struct page *sp = src->pages[i];
> + unsigned int order = sp ? ttm_pool_page_order_nodma(sp) : 0;
> + pgoff_t nr = 1UL << order;
[Severity: Critical]
Can defragmentation be initiated on a buffer object that uses a DMA-allocated
or external TT?
Looking at ttm_bo_handle_move_mem(), it does not appear to restrict
defragmentation to non-DMA pools.
If a DMA-allocated TT is defragmented, wouldn't ttm_pool_page_order_nodma()
incorrectly read the DMA pointer stored in the page private data as an
integer order?
This would result in a huge bitshift when calculating nr, which is then
used in the loop increment or the memset() calls, potentially causing severe
out-of-bounds memory writes.
> + if (sp && tt->pages[i] == sp) {
> + if (!in_run) {
> + run_start = i;
> + in_run = true;
> + }
> + } else if (in_run) {
> + memset(&tt->pages[run_start], 0,
> + (i - run_start) * sizeof(*tt->pages));
[Severity: Critical]
Following up on the potential for harvesting an unaligned tail page (noted in
ttm_pool.c), if ttm_pool_iter_reuse_old() harvested a tail page, wouldn't
this logic clear the pointer in the old TT for that tail page, but leave the
head page pointer intact?
When the old TT is eventually destroyed, wouldn't ttm_pool_free_range() free
the entire chunk back to the system (since the head page still indicates a
large order) while the tail page is still actively mapped and used by the new
TT, leading to a severe use-after-free regression?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260710215442.2444235-1-matthew.brost@intel.com?part=7
next prev parent reply other threads:[~2026-07-10 22:19 UTC|newest]
Thread overview: 58+ 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-10 21:54 ` [PATCH v2 02/33] drm/ttm/pool: Add ttm_pool_page_order_nodma() helper Matthew Brost
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 [this message]
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
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
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=20260710221956.BDECD1F000E9@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