mm/vmalloc: support non-blocking GFP flags in alloc_vmap_area()

alloc_vmap_area() currently assumes that sleeping is allowed during
allocation.  This is not true for callers which pass non-blocking GFP
flags, such as GFP_ATOMIC or GFP_NOWAIT.

This patch adds logic to detect whether the given gfp_mask permits
blocking.  It avoids invoking might_sleep() or falling back to reclaim
path if blocking is not allowed.

This makes alloc_vmap_area() safer for use in non-sleeping contexts, where
previously it could hit unexpected sleeps, trigger warnings.

It is a preparation and adjustment step to later allow both GFP_ATOMIC and
GFP_NOWAIT allocations in this series.

Link: https://lkml.kernel.org/r/20251007122035.56347-4-urezki@gmail.com
Signed-off-by: Uladzislau Rezki (Sony) <urezki@gmail.com>
Acked-by: Michal Hocko <mhocko@suse.com>
Reviewed-by: Baoquan He <bhe@redhat.com>
Cc: Alexander Potapenko <glider@google.com>
Cc: Andrey Ryabinin <ryabinin.a.a@gmail.com>
Cc: Marco Elver <elver@google.com>
Cc: Michal Hocko <mhocko@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
pull/1354/merge
Uladzislau Rezki (Sony) 2025-10-07 14:20:28 +02:00 committed by Andrew Morton
parent e781c1c0a9
commit 86e968d8ca
1 changed files with 16 additions and 4 deletions

View File

@ -2017,6 +2017,7 @@ static struct vmap_area *alloc_vmap_area(unsigned long size,
unsigned long freed;
unsigned long addr;
unsigned int vn_id;
bool allow_block;
int purged = 0;
int ret;
@ -2028,7 +2029,8 @@ static struct vmap_area *alloc_vmap_area(unsigned long size,
/* Only reclaim behaviour flags are relevant. */
gfp_mask = gfp_mask & GFP_RECLAIM_MASK;
might_sleep();
allow_block = gfpflags_allow_blocking(gfp_mask);
might_sleep_if(allow_block);
/*
* If a VA is obtained from a global heap(if it fails here)
@ -2062,7 +2064,8 @@ retry:
* This is not a fast path. Check if yielding is needed. This
* is the only reschedule point in the vmalloc() path.
*/
cond_resched();
if (allow_block)
cond_resched();
}
trace_alloc_vmap_area(addr, size, align, vstart, vend, IS_ERR_VALUE(addr));
@ -2071,8 +2074,16 @@ retry:
* If an allocation fails, the error value is
* returned. Therefore trigger the overflow path.
*/
if (IS_ERR_VALUE(addr))
goto overflow;
if (IS_ERR_VALUE(addr)) {
if (allow_block)
goto overflow;
/*
* We can not trigger any reclaim logic because
* sleeping is not allowed, thus fail an allocation.
*/
goto out_free_va;
}
va->va_start = addr;
va->va_end = addr + size;
@ -2122,6 +2133,7 @@ overflow:
pr_warn("vmalloc_node_range for size %lu failed: Address range restricted to %#lx - %#lx\n",
size, vstart, vend);
out_free_va:
kmem_cache_free(vmap_area_cachep, va);
return ERR_PTR(-EBUSY);
}