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) + 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); + + if (lhs_size > rhs_offset) + 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; + 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 -- 2.34.1
