On 6/19/2026 6:15 PM, Matthew Auld wrote:
On 18/06/2026 13:47, Arunpravin Paneer Selvam wrote:
The try_harder contiguous fallback could return a range whose start
offset did not match the caller's min_block_size. Check each candidate
against the requested alignment and reject the allocation when no
candidate satisfies it, instead of handing back a misaligned range.
Suggested-by: Christian König <[email protected]>
Fixes: 0a1844bf0b53 ("drm/buddy: Improve contiguous memory allocation")
Cc: Matthew Auld <[email protected]>
Cc: Christian König <[email protected]>
Cc: Timur Kristóf <[email protected]>
Cc: John Olender <[email protected]>
Cc: [email protected]
Signed-off-by: Arunpravin Paneer Selvam
<[email protected]>
---
drivers/gpu/buddy.c | 33 +++++++++++++++++++++------------
1 file changed, 21 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/buddy.c b/drivers/gpu/buddy.c
index dc81fe0301ce..28ed3250ac57 100644
--- a/drivers/gpu/buddy.c
+++ b/drivers/gpu/buddy.c
@@ -1127,13 +1127,11 @@ static int __alloc_contig_try_harder(struct
gpu_buddy *mm,
struct gpu_buddy_block *block;
unsigned int tree, order;
LIST_HEAD(blocks_lhs);
- unsigned long pages;
u64 modify_size;
int err;
modify_size = rounddown_pow_of_two(size);
- pages = modify_size >> ilog2(mm->chunk_size);
- order = fls(pages) - 1;
+ order = ilog2(modify_size) - ilog2(mm->chunk_size);
if (order == 0)
return -ENOSPC;
@@ -1149,31 +1147,42 @@ static int __alloc_contig_try_harder(struct
gpu_buddy *mm,
while (iter) {
block = rbtree_get_free_block(iter);
- /* Allocate blocks traversing RHS */
rhs_offset = gpu_buddy_block_offset(block);
+
+ /* Allocate blocks traversing RHS */
err = __gpu_buddy_alloc_range(mm, rhs_offset, size,
&filled, blocks);
- if (!err || err != -ENOSPC)
+ if (err && err != -ENOSPC)
return err;
+ if (!err && IS_ALIGNED(rhs_offset, min_block_size))
+ return 0;
+ if (!err)
Should we do some kind of rhs = round_down(rhs, min_block_size) at the
start? Just wondering if we can get something misaligned here, that
should have succeeded if we just applied the round_down first, in some
edge case?
Done - when the whole size fits at rhs_offset but the start is
misaligned, we drop it and realign to the min_block_size boundary below
instead of bailing.
+ goto next;
- lhs_size = max((size - filled), min_block_size);
- if (!IS_ALIGNED(lhs_size, min_block_size))
- lhs_size = round_up(lhs_size, min_block_size);
+ lhs_size = round_up(max((size - filled), min_block_size),
+ min_block_size);
Can this be simplified as: round_up(size - filled, min_block_size) ?
Dropped round_up/lhs_size entirely, we realign and allocate exactly
size, so the max/round_up is gone.
+
+ if (lhs_size > rhs_offset)
What is the idea with this check?
We reach here only on a partial RHS fill, so the leftover size - filled
must be taken from the space left of rhs_offset;
if that leftover exceeds rhs_offset there isn't room, so we skip.
It also prevents the next line's u64 rhs_offset - (size - filled) from
underflowing.
+ goto next;
/* Allocate blocks traversing LHS */
- lhs_offset = gpu_buddy_block_offset(block) - lhs_size;
+ lhs_offset = rhs_offset - lhs_size;
+
+ if (!IS_ALIGNED(lhs_offset, min_block_size))
+ goto next;
Would it make sense to just align the lhs down, if misaligned, instead
of baling? If the final size we get back is slightly too large, we can
just apply a trim at the end?
Done - we realign lhs_offset (round_down) and request exactly size, so
there is no surplus to trim.
Please review the v2.
Regards,
Arun.
+
err = __gpu_buddy_alloc_range(mm, lhs_offset, lhs_size,
NULL, &blocks_lhs);
if (!err) {
list_splice(&blocks_lhs, blocks);
return 0;
- } else if (err != -ENOSPC) {
+ }
+ if (err != -ENOSPC) {
gpu_buddy_free_list_internal(mm, blocks);
return err;
}
- /* Free blocks for the next iteration */
+next:
gpu_buddy_free_list_internal(mm, blocks);
-
iter = rb_prev(iter);
}
}
base-commit: b9e2d5cdaab05c997be3a69d9b372d7676683e1b