mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-21 21:38:04 -04:00
gpu/buddy: bail out of try_harder when alignment cannot be honoured
The try_harder contiguous fallback could return a range whose start
offset did not match the caller's min_block_size. When a candidate's
start is misaligned, realign it: free the misaligned run and reallocate
exactly @size at the next lower min_block_size boundary. This keeps the
returned size unchanged with no surplus to trim, and rejects the request
only when no aligned candidate fits.
v2: align misaligned candidates down to min_block_size instead of
bailing out, for both the RHS and LHS paths (Matthew).
Fixes: 0a1844bf0b ("drm/buddy: Improve contiguous memory allocation")
Suggested-by: Christian König <christian.koenig@amd.com>
Cc: Matthew Auld <matthew.auld@intel.com>
Cc: Christian König <christian.koenig@amd.com>
Cc: Timur Kristóf <timur.kristof@gmail.com>
Cc: stable@vger.kernel.org
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
Tested-by: John Olender <john.olender@gmail.com>
Signed-off-by: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
Link: https://patch.msgid.link/20260709131050.1022759-1-Arunpravin.PaneerSelvam@amd.com
This commit is contained in:
@@ -1084,22 +1084,30 @@ 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,
|
||||
struct list_head *blocks)
|
||||
{
|
||||
u64 aligned_offset = round_down(unaligned_offset, min_block_size);
|
||||
|
||||
return __gpu_buddy_alloc_range(mm, aligned_offset, size, NULL, blocks);
|
||||
}
|
||||
|
||||
static int __alloc_contig_try_harder(struct gpu_buddy *mm,
|
||||
u64 size,
|
||||
u64 min_block_size,
|
||||
struct list_head *blocks)
|
||||
{
|
||||
u64 rhs_offset, lhs_offset, lhs_size, filled;
|
||||
u64 rhs_offset, lhs_offset, filled;
|
||||
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;
|
||||
|
||||
@@ -1115,31 +1123,48 @@ 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;
|
||||
|
||||
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);
|
||||
|
||||
/* Allocate blocks traversing LHS */
|
||||
lhs_offset = gpu_buddy_block_offset(block) - lhs_size;
|
||||
err = __gpu_buddy_alloc_range(mm, lhs_offset, lhs_size,
|
||||
NULL, &blocks_lhs);
|
||||
if (!err) {
|
||||
list_splice(&blocks_lhs, blocks);
|
||||
if (!err && IS_ALIGNED(rhs_offset, min_block_size))
|
||||
return 0;
|
||||
} else if (err != -ENOSPC) {
|
||||
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,
|
||||
blocks);
|
||||
if (!err)
|
||||
return 0;
|
||||
if (err != -ENOSPC) {
|
||||
gpu_buddy_free_list_internal(mm, blocks);
|
||||
return err;
|
||||
}
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (size - filled > rhs_offset)
|
||||
goto next;
|
||||
|
||||
lhs_offset = rhs_offset - (size - filled);
|
||||
|
||||
/* 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, blocks);
|
||||
if (!err)
|
||||
return 0;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user