From: Jiayuan Chen <jiayuan.chen@linux.dev>
To: bot+bpf-ci@kernel.org, bpf@vger.kernel.org
Cc: emil@etsalapatis.com, ast@kernel.org, daniel@iogearbox.net,
andrii@kernel.org, eddyz87@gmail.com, memxor@gmail.com,
martin.lau@linux.dev, song@kernel.org, yonghong.song@linux.dev,
jolsa@kernel.org, ihor.solodrai@linux.dev,
linux-kernel@vger.kernel.org, martin.lau@kernel.org,
clm@meta.com
Subject: Re: [PATCH bpf-next v4 2/4] bpf: arena: allocate the fault-in page outside the lock
Date: Fri, 21 Aug 2026 18:31:55 +0800 [thread overview]
Message-ID: <44f56d87-14eb-4fb8-bade-09c94aa0952b@linux.dev> (raw)
In-Reply-To: <b951553281d4e1491647aad4c4c0a8fac03d6b78ecac351fd216888eaae6ce72@mail.kernel.org>
On 8/21/26 1:59 PM, bot+bpf-ci@kernel.org wrote:
>> diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c
>> index 7b6847200b43..50dac9ba0f5e 100644
>> --- a/kernel/bpf/arena.c
>> +++ b/kernel/bpf/arena.c
> [ ... ]
>
>> @@ -489,59 +490,108 @@ static vm_fault_t arena_vm_fault(struct vm_fault *vmf)
>> kbase = bpf_arena_get_kern_vm_start(arena);
>> kaddr = kbase + (u32)(vmf->address);
>>
>> + page = vmalloc_to_page((void *)kaddr);
>> + if (!page && !(arena->map.map_flags & BPF_F_SEGV_ON_FAULT)) {
>> + /*
>> + * We run in process context here, so preallocate the page
>> + * outside the lock with an explicitly sleepable allocator. It
>> + * can then go through reclaim (both memcg and global) and the
>> + * OOM path, the way do_anonymous_page() does; under
>> + * arena->spinlock only the non-blocking allocator is available,
>> + * which never reclaims. That also decides the return value:
>> + * VM_FAULT_OOM below is only meaningful if the OOM machinery was
>> + * actually engaged, which the non-blocking allocator never does.
>> + */
>> + bpf_map_memcg_enter(&arena->map, &old_memcg, &new_memcg);
>> + new_page = bpf_map_alloc_page_sleepable(map);
>> + bpf_map_memcg_exit(old_memcg, new_memcg);
>> + if (!new_page)
>> + return VM_FAULT_OOM;
>> + }
> Can this return VM_FAULT_OOM when the allocation is charged to a foreign
> memcg?
>
> The preallocation charges the arena creator's memcg, not current's:
>
> bpf_map_memcg_enter(&arena->map, &old_memcg, &new_memcg);
> /* set_active_memcg(bpf_map_get_memcg(map)) */
>
> new_page = bpf_map_alloc_page_sleepable(map);
> /* GFP_KERNEL|__GFP_ZERO|__GFP_ACCOUNT|__GFP_NOWARN */
>
> For an order-0 GFP_KERNEL allocation the only realistic NULL is a memcg
> charge rejection. mem_cgroup_oom() calls out_of_memory() with oom_control
> pointing at the arena owner's memcg, so the OOM killer can only select
> victims inside that cgroup.
>
> VM_FAULT_OOM reaches pagefault_out_of_memory() (mm/oom_kill.c:1180-1193),
> which only resolves current->memcg_in_oom; otherwise it prints the
> rate-limited "Huh VM_FAULT_OOM leaked out to the #PF handler. Retrying PF"
> message and returns. Because the over-limit memcg is foreign, killing
> tasks there never makes fatal_signal_pending(current) true, so
> try_charge_memcg()'s force-charge escape hatch never fires.
>
> If the owner memcg's charge is dominated by memory its tasks cannot free
> (for example the arena's own pages, which are only freed by the bpf program
> or by map destruction and are unreclaimable), or if that cgroup has no
> OOM-eligible tasks left, mem_cgroup_oom() returns false, try_charge_memcg()
> returns -ENOMEM, and the instruction is retried in a loop.
>
> This creates an unbounded fault/retry livelock burning CPU in the faulting
> task plus dmesg spam, where the pre-image returned a bounded
> VM_FAULT_SIGSEGV. Before this patch the in-lock allocator never engaged
> reclaim or the OOM killer, so a user touching an arena page could not kill
> anything. Now any task that can mmap the arena (the fd can be passed via
> SCM_RIGHTS or a bpffs pin, so the faulting task need not be in the owner's
> cgroup at all) can drive the memcg OOM killer in the owner's cgroup one
> task at a time simply by faulting in pages.
Thanks, you're right — this is a real bug, and I could reproduce it.
The root cause is simply that we return VM_FAULT_OOM.
That return value does nothing useful for arena: all reclaim and OOM
handling (both memcg and global) already happens inside
bpf_map_alloc_page_sleepable().
The fix is to return VM_FAULT_SIGBUS instead of VM_FAULT_OOM.
next prev parent reply other threads:[~2026-08-21 10:32 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-21 5:01 [PATCH bpf-next v4 0/4] bpf: arena: handle memory.max on fault-in with reclaim/OOM Jiayuan Chen
2026-08-21 5:06 ` [PATCH bpf-next v4 1/4] bpf: Add a sleepable page allocator for map memory Jiayuan Chen
2026-08-21 5:06 ` [PATCH bpf-next v4 2/4] bpf: arena: allocate the fault-in page outside the lock Jiayuan Chen
2026-08-21 5:59 ` bot+bpf-ci
2026-08-21 10:31 ` Jiayuan Chen [this message]
2026-08-21 5:06 ` [PATCH bpf-next v4 3/4] selftests/bpf: Add read_cgroup_file() to cgroup_helpers Jiayuan Chen
2026-08-21 5:06 ` [PATCH bpf-next v4 4/4] selftests/bpf: Add a test for arena fault-in under memory.max Jiayuan Chen
2026-08-21 5:59 ` bot+bpf-ci
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=44f56d87-14eb-4fb8-bade-09c94aa0952b@linux.dev \
--to=jiayuan.chen@linux.dev \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bot+bpf-ci@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=clm@meta.com \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=emil@etsalapatis.com \
--cc=ihor.solodrai@linux.dev \
--cc=jolsa@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=martin.lau@kernel.org \
--cc=martin.lau@linux.dev \
--cc=memxor@gmail.com \
--cc=song@kernel.org \
--cc=yonghong.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.