The BO cache size list has one entry per BO page count, so its size
scales with the largest BO ever freed. A 64 MiB BO already needs at
least an order-6 allocation, which fails under fragmentation and
triggers a warn_alloc() splat on BO close:

  page allocation failure: order:7, mode:0x40cc0(GFP_KERNEL|__GFP_COMP)
  Call trace:
   ...
   warn_alloc+0x118/0x190
   __alloc_pages_slowpath+0x4a8/0x520
   ...
   __kmalloc_noprof+0x3ac/0x5d8
   vc4_free_object+0x128/0x370 [vc4]
   drm_gem_object_handle_put_unlocked+0xb8/0x158 [drm]
   drm_gem_object_release_handle+0x74/0xe8 [drm]
   drm_gem_handle_delete+0x6c/0xa8 [drm]
   drm_gem_close_ioctl+0x34/0x50 [drm]

The list doesn't need physically contiguous memory. Use kvmalloc_objs()
so large lists can fall back to vmalloc(), avoiding the allocation
failure.

Fixes: c826a6e10644 ("drm/vc4: Add a BO cache.")
Signed-off-by: Maíra Canal <[email protected]>
---
 drivers/gpu/drm/vc4/vc4_bo.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c
index ea1be891ac78..7b8b3364000f 100644
--- a/drivers/gpu/drm/vc4/vc4_bo.c
+++ b/drivers/gpu/drm/vc4/vc4_bo.c
@@ -204,7 +204,7 @@ static struct list_head *vc4_get_cache_list_for_size(struct 
drm_device *dev,
                struct list_head *new_list;
                uint32_t i;
 
-               new_list = kmalloc_objs(struct list_head, new_size);
+               new_list = kvmalloc_objs(struct list_head, new_size);
                if (!new_list)
                        return NULL;
 
@@ -224,7 +224,7 @@ static struct list_head *vc4_get_cache_list_for_size(struct 
drm_device *dev,
                for (i = vc4->bo_cache.size_list_size; i < new_size; i++)
                        INIT_LIST_HEAD(&new_list[i]);
 
-               kfree(vc4->bo_cache.size_list);
+               kvfree(vc4->bo_cache.size_list);
                vc4->bo_cache.size_list = new_list;
                vc4->bo_cache.size_list_size = new_size;
        }
@@ -1052,7 +1052,7 @@ static void vc4_bo_cache_destroy(struct drm_device *dev, 
void *unused)
        cancel_work_sync(&vc4->bo_cache.time_work);
 
        vc4_bo_cache_purge(dev);
-       kfree(vc4->bo_cache.size_list);
+       kvfree(vc4->bo_cache.size_list);
 
        for (i = 0; i < vc4->num_labels; i++) {
                if (vc4->bo_labels[i].num_allocated) {
-- 
2.55.0

Reply via email to