]> xenbits.xensource.com Git - people/aperard/linux.git/commitdiff
drm/buddy: fix range bias
authorMatthew Auld <matthew.auld@intel.com>
Mon, 19 Feb 2024 12:18:52 +0000 (12:18 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 6 Mar 2024 14:45:10 +0000 (14:45 +0000)
commit f41900e4a6ef019d64a70394b0e0c3bd048d4ec8 upstream.

There is a corner case here where start/end is after/before the block
range we are currently checking. If so we need to be sure that splitting
the block will eventually give use the block size we need. To do that we
should adjust the block range to account for the start/end, and only
continue with the split if the size/alignment will fit the requested
size. Not doing so can result in leaving split blocks unmerged when it
eventually fails.

Fixes: afea229fe102 ("drm: improve drm_buddy_alloc function")
Signed-off-by: Matthew Auld <matthew.auld@intel.com>
Cc: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
Cc: Christian König <christian.koenig@amd.com>
Cc: <stable@vger.kernel.org> # v5.18+
Reviewed-by: Arunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240219121851.25774-4-matthew.auld@intel.com
Signed-off-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/gpu/drm/drm_buddy.c

index 7098f125b54a9a3004ea98345f7ec486cc8ae24a..fd32041f82263bebd5d264812a4b31a9d3f7e6f7 100644 (file)
@@ -332,6 +332,7 @@ alloc_range_bias(struct drm_buddy *mm,
                 u64 start, u64 end,
                 unsigned int order)
 {
+       u64 req_size = mm->chunk_size << order;
        struct drm_buddy_block *block;
        struct drm_buddy_block *buddy;
        LIST_HEAD(dfs);
@@ -367,6 +368,15 @@ alloc_range_bias(struct drm_buddy *mm,
                if (drm_buddy_block_is_allocated(block))
                        continue;
 
+               if (block_start < start || block_end > end) {
+                       u64 adjusted_start = max(block_start, start);
+                       u64 adjusted_end = min(block_end, end);
+
+                       if (round_down(adjusted_end + 1, req_size) <=
+                           round_up(adjusted_start, req_size))
+                               continue;
+               }
+
                if (contains(start, end, block_start, block_end) &&
                    order == drm_buddy_block_order(block)) {
                        /*