When pcpu_get_vm_areas() has to split a free vmap_area in the middle (NE_FIT_TYPE), va_clip() needs an extra vmap_area object. It takes the per-cpu ne_fit_preload_node if one is there, and otherwise falls back to kmem_cache_alloc(GFP_NOWAIT), which may fail and return -ENOMEM. pcpu_get_vm_areas() never preloads, and a single call can do more than one such split: on a NUMA system it places one area per node group, so the first split consumes the preloaded object and the next one depends on the GFP_NOWAIT allocation. That failure is expected and already handled: the recovery path returns the areas clipped so far to the free tree, purges lazily freed areas and retries. But the error is checked with WARN_ON_ONCE(), so a transient allocation failure under memory pressure or fault injection triggers a kernel warning, and a panic with panic_on_warn. syzbot hit this on a two-node VM while creating a per-cpu BPF array map. Keep the WARN_ON_ONCE() for errors other than -ENOMEM, which do indicate a bug, and take the recovery path either way. This matches what commit b9183788a2de ("mm/vmalloc: do not warn on -ENOMEM from va_alloc()") did for the other va_clip() caller. Fixes: 1b23ff80b399 ("mm/vmalloc: invoke classify_va_fit_type() in adjust_va_to_fit_type()") Reported-by: syzbot+442828bb356b10813a47@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=442828bb356b10813a47 Signed-off-by: Palla Raghunath --- mm/vmalloc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mm/vmalloc.c b/mm/vmalloc.c index bea9f76ed7e7..24c7d0a5472e 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -5107,9 +5107,14 @@ struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets, ret = va_clip(&free_vmap_area_root, &free_vmap_area_list, va, start, size); - if (WARN_ON_ONCE(unlikely(ret))) - /* It is a BUG(), but trigger recovery instead. */ + if (unlikely(ret)) { + /* + * -ENOMEM from the GFP_NOWAIT fallback is expected. + * Anything else is a BUG(), but trigger recovery instead. + */ + WARN_ON_ONCE(ret != -ENOMEM); goto recovery; + } /* Allocated area. */ va = vas[area]; -- 2.34.1