From: Matthew Auld <matthew.auld@intel.com>
To: sashiko-reviews@lists.linux.dev,
Arunpravin Paneer Selvam <arunpravin.paneerselvam@amd.com>,
dri-devel@lists.freedesktop.org, intel-gfx@lists.freedesktop.org,
intel-xe@lists.freedesktop.org
Subject: Re: [PATCH v5 1/2] gpu/buddy: restore two-pass clear/dirty guard for range-biased allocation
Date: Tue, 20 Oct 2026 10:52:21 +0100 [thread overview]
Message-ID: <30e81db2-a56a-464b-93ea-c74aa161fdde@intel.com> (raw)
In-Reply-To: <sashiko-outbox-178464@kernel.org>
On 20/10/2026 09:00, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [High] gpu/buddy: block_incompatible() mishandles split and mixed blocks in __alloc_range_bias()
> --
>
> commit 6dff7f0e6dce9c68ecb98f2d911199843d2b4401
> Author: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
>
> gpu/buddy: restore two-pass clear/dirty guard for range-biased allocation
>
> This commit introduces a two-pass search in __gpu_buddy_alloc_range_bias()
> using block_incompatible() in the strict pass to prevent range-restricted
> allocations from splitting opposite-class (clear vs. dirty) blocks unless
> no matching blocks exist in the range.
>
>> diff --git a/drivers/gpu/buddy.c b/drivers/gpu/buddy.c
>> index 503f7d5934e4b..91935c71c5255 100644
>> --- a/drivers/gpu/buddy.c
>> +++ b/drivers/gpu/buddy.c
>> @@ -1240,11 +1240,19 @@ static void __gpu_buddy_undo_splits(struct gpu_buddy *mm,
>> }
>> }
>>
>> +static bool block_incompatible(struct gpu_buddy_block *block, unsigned int flags)
>> +{
>> + bool needs_clear = flags & GPU_BUDDY_CLEAR_ALLOCATION;
>> +
>> + return needs_clear != gpu_buddy_block_is_clear(block);
>> +}
>> +
>> static struct gpu_buddy_block *
>> __alloc_range_bias(struct gpu_buddy *mm,
>> u64 start, u64 end,
>> unsigned int order,
>> - unsigned long flags)
>> + unsigned long flags,
>> + bool fallback)
>> {
>
> [ ... ]
>
>> @@ -1298,6 +1304,9 @@ __alloc_range_bias(struct gpu_buddy *mm,
>> continue;
>> }
>>
>> + if (!fallback && block_incompatible(block, flags))
>> + continue;
>> +
>> if (contains(start, end, block_start, block_end) &&
>> order == gpu_buddy_block_order(block)) {
>> /*
>> @@ -1315,38 +1324,8 @@ __alloc_range_bias(struct gpu_buddy *mm,
>> goto err_undo;
>> }
>>
>> - /*
>> - * Top-down is a strict address-placement policy, so when it is
>> - * requested we ignore clear steering and simply descend the
>> - * right (higher-address) child first. Only a non-top-down clear
>> - * request biases the descent towards clear/has_clear subtrees.
>> - */
>> - if ((flags & GPU_BUDDY_CLEAR_ALLOCATION) &&
>> - !(flags & GPU_BUDDY_TOPDOWN_ALLOCATION)) {
>> - struct gpu_buddy_block *prefer;
>> -
>> - if (gpu_buddy_block_is_clear(block->right))
>> - prefer = block->right;
>> - else if (gpu_buddy_block_is_clear(block->left))
>> - prefer = block->left;
>> - else if (block->right->has_clear)
>> - prefer = block->right;
>> - else if (block->left->has_clear)
>> - prefer = block->left;
>> - else
>> - prefer = block->right;
>> -
>> - if (prefer == block->right) {
>> - list_add(&block->left->tmp_link, &dfs);
>> - list_add(&block->right->tmp_link, &dfs);
>> - } else {
>> - list_add(&block->right->tmp_link, &dfs);
>> - list_add(&block->left->tmp_link, &dfs);
>> - }
>> - } else {
>> - list_add(&block->left->tmp_link, &dfs);
>> - list_add(&block->right->tmp_link, &dfs);
>> - }
>> + list_add(&block->left->tmp_link, &dfs);
>> + list_add(&block->right->tmp_link, &dfs);
>> } while (1);
>
> [Severity: High]
> Does calling block_incompatible() on every visited node in
> __alloc_range_bias() before checking whether the block is split or mixed
> mishandle internal GPU_BUDDY_SPLIT nodes and coalesced GPU_BLOCK_MIXED free
> blocks?
>
> First, when mark_split() transitions a block to GPU_BUDDY_SPLIT, it leaves
> the previous GPU_BUDDY_HEADER_CLEAR bit intact on the internal node:
>
> drivers/gpu/buddy.c:mark_split() {
> block->header &= ~GPU_BUDDY_HEADER_STATE;
> block->header |= GPU_BUDDY_SPLIT;
> ...
> }
>
> Because gpu_buddy_init() initializes roots as dirty, any root or ancestor
> split while dirty keeps gpu_buddy_block_is_clear(block) == false while any
> descendant remains allocated. Conversely, a clear block that is split and
> later has a descendant freed as dirty keeps gpu_buddy_block_is_clear(block)
> == true on the split ancestor.
>
> When __gpu_buddy_alloc_range_bias() runs the first pass (fallback = false),
> __alloc_range_bias() evaluates block_incompatible(block, flags) on those
> GPU_BUDDY_SPLIT ancestors and skips the entire subtree without descending
> into its children. If no other root satisfies the request, the first pass
> returns -ENOSPC and __gpu_buddy_alloc_range_bias() falls back to the second
> pass (fallback = true), where block_incompatible() is disabled and the
> clear/has_clear child-ordering preference has been removed, causing the
> search to split the highest-address extent regardless of class.
>
> Second, __gpu_buddy_free() coalesces adjacent clear and dirty free buddies
> into a single GPU_BUDDY_FREE block with state GPU_BLOCK_MIXED, which has
> gpu_buddy_block_is_clear(block) == false and block->has_clear == true:
>
> 1. For clear range allocations (flags & GPU_BUDDY_CLEAR_ALLOCATION), Pass 1
> sees gpu_buddy_block_is_clear(block) == false on a GPU_BLOCK_MIXED block
> and skips it via block_incompatible() without splitting it to reach the
> clear sub-blocks inside. Pass 2 then splits the mixed block without clear
> child-steering and unconditionally visits block->right first, returning a
> dirty block whenever the clear half is in block->left.
>
> 2. For dirty range allocations (!(flags & GPU_BUDDY_CLEAR_ALLOCATION)),
> block_incompatible() returns false on a higher-order GPU_BLOCK_MIXED
> block because gpu_buddy_block_is_clear(block) is false. Pass 1 then calls
> split_block(mm, block), which reclassifies block->left and block->right
> via mark_free(). If the child overlapping [start, end) is clear while the
> dirty child lies outside [start, end), Pass 1 rejects the clear child via
> block_incompatible() and skips the other child without calling
> __gpu_buddy_undo_splits().
>
> Wouldn't leaving that split GPU_BLOCK_MIXED block unmerged keep both
> children in GPU_BUDDY_FREE state, preventing ancestor coalescing on teardown
> and triggering gpu_buddy_assert(gpu_buddy_block_is_free(mm->roots[i])) while
> leaking the split child gpu_buddy_block structures in gpu_buddy_fini()?
Analysis looks correct to me. We assume if you get as far as doing an
actual split, then that must mean there is something in there which is
compatible, either you find it with some number of splits or one of the
split calls hits an error, which takes care to undo the splits. But now
with that compat check, this breaks, since we don't know ahead of time
if it will find something which is also compat. Arun, thoughts?
>
> [ ... ]
>
next prev parent reply other threads:[~2026-10-20 9:52 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-20 5:55 [PATCH v5 1/2] gpu/buddy: restore two-pass clear/dirty guard for range-biased allocation Arunpravin Paneer Selvam
2026-10-20 5:55 ` [PATCH v5 2/2] gpu/buddy: add range-restricted contiguous allocation fallback Arunpravin Paneer Selvam
2026-10-20 8:08 ` sashiko-bot
2026-10-20 6:04 ` ✓ CI.KUnit: success for series starting with [v5,1/2] gpu/buddy: restore two-pass clear/dirty guard for range-biased allocation Patchwork
2026-10-20 6:35 ` ✓ i915.CI.BAT: " Patchwork
2026-10-20 6:42 ` ✓ Xe.CI.BAT: " Patchwork
2026-10-20 8:00 ` [PATCH v5 1/2] " sashiko-bot
2026-10-20 9:52 ` Matthew Auld [this message]
2026-10-20 10:39 ` Matthew Auld
2026-10-20 8:35 ` ✗ Xe.CI.FULL: failure for series starting with [v5,1/2] " Patchwork
2026-10-20 12:09 ` ✗ i915.CI.Full: " Patchwork
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=30e81db2-a56a-464b-93ea-c74aa161fdde@intel.com \
--to=matthew.auld@intel.com \
--cc=arunpravin.paneerselvam@amd.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=intel-gfx@lists.freedesktop.org \
--cc=intel-xe@lists.freedesktop.org \
--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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.