From: sashiko-bot@kernel.org
To: "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 v6 2/2] gpu/buddy: add range-restricted contiguous allocation fallback
Date: Wed, 21 Oct 2026 12:46:37 +0000 [thread overview]
Message-ID: <sashiko-outbox-180272@kernel.org> (raw)
In-Reply-To: <20261021121813.1820345-2-arunpravin.paneerselvam@amd.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] gpu/buddy: spurious -ENOSPC in __alloc_contig_try_harder() for range allocs
--
commit 14acba1e552d60bba9eee2e544118f0040222647
Author: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
gpu/buddy: add range-restricted contiguous allocation fallback
This commit extends __alloc_contig_try_harder() with a [range_start,
range_end) window and routes range-restricted contiguous allocations through
it when no single naturally aligned power-of-two block is available. It also
adds KUnit tests covering fragmented range-restricted contiguous allocations.
> diff --git a/drivers/gpu/buddy.c b/drivers/gpu/buddy.c
> index 8eb5835d6944c..693176ee3daf9 100644
> --- a/drivers/gpu/buddy.c
> +++ b/drivers/gpu/buddy.c
> @@ -1723,43 +1723,32 @@ static int __gpu_buddy_alloc_range(struct gpu_buddy *mm,
> blocks, total_allocated_on_err);
> }
>
> -static int __alloc_contig_aligned_retry(struct gpu_buddy *mm,
> - u64 unaligned_offset,
> - u64 size,
> - u64 min_block_size,
> - unsigned long flags,
> - struct list_head *blocks)
> -{
> - u64 aligned_offset = round_down(unaligned_offset, min_block_size);
> -
> - return __gpu_buddy_alloc_range(mm, aligned_offset, size, flags,
> - NULL, blocks);
> -}
> -
> static int __alloc_contig_try_harder(struct gpu_buddy *mm,
> + u64 range_start, u64 range_end,
> u64 size,
> u64 min_block_size,
> unsigned long flags,
> struct list_head *blocks)
> {
> - u64 rhs_offset, lhs_offset, filled;
> + u64 rhs_offset, lhs_offset, filled, aligned;
> struct gpu_buddy_block *block;
> + unsigned int min_order, order;
> struct rb_root *root;
> struct rb_node *iter;
> unsigned long pages;
> - unsigned int order;
> u64 modify_size;
> int err;
>
> + min_order = ilog2(min_block_size) - ilog2(mm->chunk_size);
> +
> modify_size = rounddown_pow_of_two(size);
> pages = modify_size >> ilog2(mm->chunk_size);
> order = fls(pages) - 1;
> - if (order == 0)
> - return -ENOSPC;
>
> +retry_order:
> root = &mm->free_tree[order];
> if (RB_EMPTY_ROOT(root))
> - return -ENOSPC;
> + goto next_order;
>
> iter = rb_last(root);
> while (iter) {
> @@ -1767,25 +1756,48 @@ static int __alloc_contig_try_harder(struct gpu_buddy *mm,
>
> rhs_offset = gpu_buddy_block_offset(block);
>
> + if (rhs_offset >= range_end) {
> + iter = rb_prev(iter);
> + continue;
> + }
> + if (rhs_offset < range_start)
> + break;
> +
> /* Allocate blocks traversing RHS */
> err = __gpu_buddy_alloc_range(mm, rhs_offset, size,
> flags, &filled, blocks);
> if (err && err != -ENOSPC)
> return err;
> - if (!err && IS_ALIGNED(rhs_offset, min_block_size))
> +
> + if (!err)
> + filled = size;
> +
> + /* Clamp a full or partial fill that crosses range_end. */
> + if (rhs_offset + filled > range_end) {
> + gpu_buddy_free_list_internal(mm, blocks);
> + filled = range_end - rhs_offset;
> + err = -ENOSPC;
> + }
> +
> + if (!err && IS_ALIGNED(rhs_offset, min_block_size) &&
> + rhs_offset >= range_start)
> return 0;
> +
> if (!err) {
> /* Allocate the unaligned RHS offset using round_down */
> gpu_buddy_free_list_internal(mm, blocks);
> - err = __alloc_contig_aligned_retry(mm, rhs_offset,
> - size,
> - min_block_size,
> - flags, blocks);
> - if (!err)
> - return 0;
> - if (err != -ENOSPC) {
> - gpu_buddy_free_list_internal(mm, blocks);
> - return err;
> +
> + aligned = round_down(rhs_offset, min_block_size);
> + if (aligned >= range_start &&
> + aligned + size <= range_end) {
> + err = __gpu_buddy_alloc_range(mm, aligned, size,
> + flags, NULL, blocks);
> + if (!err)
> + return 0;
> + if (err != -ENOSPC) {
> + gpu_buddy_free_list_internal(mm, blocks);
> + return err;
> + }
> }
> goto next;
> }
> @@ -1797,21 +1809,73 @@ static int __alloc_contig_try_harder(struct gpu_buddy *mm,
>
> /* Allocate the unaligned LHS offset using round_down */
> gpu_buddy_free_list_internal(mm, blocks);
> - err = __alloc_contig_aligned_retry(mm, lhs_offset,
> - size,
> - min_block_size,
> - flags, blocks);
> - if (!err)
> - return 0;
> - if (err != -ENOSPC) {
> - gpu_buddy_free_list_internal(mm, blocks);
> - return err;
> +
> + aligned = round_down(lhs_offset, min_block_size);
> + if (aligned >= range_start && aligned + size <= range_end) {
> + err = __gpu_buddy_alloc_range(mm, aligned, size,
> + flags, NULL, blocks);
> + if (!err)
> + return 0;
> + if (err != -ENOSPC) {
> + gpu_buddy_free_list_internal(mm, blocks);
> + return err;
> + }
> }
> next:
> gpu_buddy_free_list_internal(mm, blocks);
> iter = rb_prev(iter);
> }
>
> +next_order:
> + if (order > min_order) {
> + order--;
> + goto retry_order;
> + }
> +
> + /* A non-range request would already have used a larger free block. */
> + if (!(flags & GPU_BUDDY_RANGE_ALLOCATION))
> + return -ENOSPC;
> +
> + /*
> + * Last resort: the span may sit inside a larger coalesced free block
> + * that the anchored search above never visits. Walk the higher-order
> + * free trees (bounded by the number of free blocks, not by the window
> + * size) and carve the highest aligned span that fits inside each block
> + * overlapping the window.
> + */
> + for (order = fls(modify_size >> ilog2(mm->chunk_size));
> + order <= mm->max_order; order++) {
> + for (iter = rb_last(&mm->free_tree[order]); iter;
> + iter = rb_prev(iter)) {
> + u64 low, high;
> +
> + block = rbtree_get_free_block(iter);
> + low = max(gpu_buddy_block_offset(block), range_start);
> + high = min(gpu_buddy_block_offset(block) +
> + gpu_buddy_block_size(mm, block), range_end);
> +
> + if (gpu_buddy_block_offset(block) >= range_end)
> + continue;
> + if (gpu_buddy_block_offset(block) +
> + gpu_buddy_block_size(mm, block) <= range_start)
> + break;
> + if (high < low + size)
> + continue;
> +
> + aligned = round_down(high - size, min_block_size);
> + if (aligned < low)
> + continue;
> +
> + err = __gpu_buddy_alloc_range(mm, aligned, size, flags,
> + NULL, blocks);
> + if (!err)
> + return 0;
> + gpu_buddy_free_list_internal(mm, blocks);
> + if (err != -ENOSPC)
> + return err;
> + }
> + }
> +
> return -ENOSPC;
> }
[Severity: Medium]
Can __alloc_contig_try_harder() in drivers/gpu/buddy.c still return a
spurious -ENOSPC when gpu_buddy_alloc_blocks() falls back to it for a
range-restricted or min_block_size-aligned contiguous allocation, if the
valid contiguous span straddles a higher-order block boundary, a block
starting below range_start, or a trailing block smaller than min_block_size?
In the first pass, the anchored search starts at
order = fls(pages) - 1, breaks out of the free_tree walk as soon as
rhs_offset < range_start:
if (rhs_offset < range_start)
break;
and stops descending at min_order:
if (order > min_order) {
order--;
goto retry_order;
}
In the second pass, the higher-order free_tree walk clips each individual
free block to [range_start, range_end) via [low, high) and requires the
entire request to fit inside that single block's clipped window:
if (high < low + size)
continue;
aligned = round_down(high - size, min_block_size);
if (aligned < low)
continue;
Because the second pass only tests placements contained within a single
higher-order block and never stitches across adjacent free blocks, it looks
like valid contiguous placements are missed in three cases:
1. A span straddling two higher-order blocks. For example, with chunk_size
of 4K, if [16K, 32K) is free at order 2 and [32K, 64K) is free at order 3, a
request for size = 12K, min_block_size = 4K in [24K, 40K) finds free_tree[1]
and free_tree[0] empty in the first pass. The second pass clips [16K, 32K)
to [24K, 32K) (8K < 12K) and [32K, 64K) to [32K, 40K) (8K < 12K), skipping
both and returning -ENOSPC even though the entire [24K, 40K) window is free.
2. A span straddling a block that starts below range_start and an adjacent
higher-order block. With the same free blocks [16K, 32K) at order 2 and
[32K, 64K) at order 3, a request for size = 20K, min_block_size = 4K in
[20K, 44K) starts at order 2, sees rhs_offset = 16K < range_start (20K), and
breaks without probing from range_start. The second pass clips [32K, 64K) to
[32K, 44K) (12K < 20K) and skips it, returning -ENOSPC when [20K, 44K) is
completely free.
3. A span straddling a higher-order block and a trailing free block with
order < min_order. Since min_block_size constrains the start alignment of
the contiguous span rather than the size of trailing blocks stitched into
it, if [0, 16K) is free at order 2 and [16K, 20K) is free at order 0, a
request for size = 12K, min_block_size = 8K (min_order = 1) in [8K, 24K)
stops descending at min_order = 1 without visiting [16K, 20K) at order 0,
and the second pass skips [0, 16K) because [8K, 16K) is only 8K (< 12K),
missing the valid 8K-aligned placement at [8K, 20K).
Should the anchored search instead start from mm->max_order down to order 0,
and clamp blocks that start below range_start (with rhs_offset + block_size >
range_start) to start probing at range_start?
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261021121813.1820345-1-arunpravin.paneerselvam@amd.com?part=2
next prev parent reply other threads:[~2026-10-21 12:46 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-21 12:18 [PATCH v6 1/2] gpu/buddy: restore two-pass clear/dirty guard for range-biased allocation Arunpravin Paneer Selvam
2026-10-21 12:18 ` [PATCH v6 2/2] gpu/buddy: add range-restricted contiguous allocation fallback Arunpravin Paneer Selvam
2026-10-21 12:46 ` sashiko-bot [this message]
2026-10-21 12:49 ` [PATCH v6 1/2] gpu/buddy: restore two-pass clear/dirty guard for range-biased allocation Matthew Auld
2026-10-21 13:45 ` Arunpravin Paneer Selvam
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=sashiko-outbox-180272@kernel.org \
--to=sashiko-bot@kernel.org \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox