On Wed, Sep 30, 2026 at 04:06:51PM -0300, Maíra Canal wrote:
> 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]>
Reviewed-by: Thadeu Lima de Souza Cascardo <[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
>