From nobody Mon Sep 28 06:34:53 2026 Received: from mail-pl1-f171.google.com (mail-pl1-f171.google.com [209.85.214.171]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 74EC73F4835 for ; Tue, 25 Aug 2026 09:50:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787651410; cv=none; b=CtXS2T8y1OaiQNlJT5ouPE1RM4FybdML7TADojr55dKYftPC894c+wYYlwWfN6ERCzPqKP0xzeUGPIWsHwgHF2y98mvgN9M2X3CW/dtKuwwe/DAxKLf1swjoEhmbjoZA/zy+PUUt8vII48GEjOCdq5In2gpweBsrs2DUQRvvB7c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787651410; c=relaxed/simple; bh=PyE160OajPSsqQd9ddyOfvbdMpeClWf6VPakHByI8uA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=pcJS6UuwGEA2IHUm7viEKMx+aibben1Xzh8Awm1g/afoysovma6AyaT+iOvtu6BP2wFS04/eiIg+1NyE7g9qj/xBKjWb7Vh1zYDRAjdSoPgnnQ9VrX2YL6dwQw7XGhfz5xlGBZL3c85QTVUGoimwq3LmUm7ibzYzkFOW6epB0II= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=mylXEhIO; arc=none smtp.client-ip=209.85.214.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="mylXEhIO" Received: by mail-pl1-f171.google.com with SMTP id d9443c01a7336-2d5655cc850so49983245ad.3 for ; Tue, 25 Aug 2026 02:50:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787651408; x=1788256208; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=W7cSIyxl/i1oxSUvdnacr9V24YcqM8fZNDWiyKdu00s=; b=mylXEhIOn2K1qqw1nMVq4eo5yJ2TnzTcl+0GdsooM5a0b8Y0cYu8qS2oq6AHCzjWBW 6q5DReILtgQinihErYEGpenSQItpt4AnYHzllNvMB7w10xWKvZKfogS/cFP3IEb0Ho6T KpMzA/czWthiNcW0ux5NhwdFWws3vxbvevnUG0c9Ieb5j7rpj7dvMx+lufLU2EqcXycG LcQliSZvQyKnH1FS82BrgFQigDIHP1ydA8KSeHPPL3oXlsXp1Zz4NZuQTVxUmricyU// WdrD6v02+/fIAoep7PhyRI74kjccojGm0Mh/fDC2nyoIUyd6MkJwl6pPvqq0J+JS772r qXWQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787651408; x=1788256208; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=W7cSIyxl/i1oxSUvdnacr9V24YcqM8fZNDWiyKdu00s=; b=h0hxo13f/ik9XsEQjy7BFhWGbCdMLORKVk+96YV4MtyiPGPmO2zuMAe95FaM5lxRfk YS9s8s2HbrztZMRuxEKXdA+DCMxcSue3QEhndHtzPXZmrGKwH2ddA78YgGauDzOoDRjZ gnk5KHRrVcaT82xvIz6nm3hfr5Xf9u4ugGGTONclr9STLxRGXjUYY0bkcDq+WQL2hgkN Jup/3+sn/7ke8/VXtCZ2i5Zmnbhy3vJDOvS8n/6JRNKcVL/Q154mxuj3cFhfSBBiRyq7 eCEuHzWXGaQnid11PVn+HqHo77pM6BaEAADaZTDtb/GtPfk/4TCMKGqrZDD9fJhaXzd7 74iA== X-Gm-Message-State: AFuF++lpBkp1ZrdHbfhxq4q6/+tmAm9rKbECtp4xOjGEYFTqUhs77BU0 q+mLFsX89m4PYewEKJROq7vSr/cwIkSifuUr6r5+Hfeft4fU8tlrG8Rh X-Gm-Gg: AR+sD12/+2Ho82nN5YB6dyKa2qHBcFuHSkew3M15GSCNMe3X7Pty1I5xtcZ9kMY3i/I onzfqt8B85UivXcrH99gm2kGc7opmPQhbmCxSrz1PpQ4jj6Kz6BSg8So8lTVBvEktCGoNlSgBtb UezMlTRuN2guWGlGmr+jNng95JCqegK5VB+1zbm6DxzxBH3vUynNQeDwYL+uWUU3Ybtpcz1yAq5 LSvUTd/AScvKzjibKHLLP6RkI2JQNb85+R78DbATou/nXK7s/cnhtZQ73776iE39ZiXXSv5Vqj3 A018ly9k6rDJBrUWrTKq4/it9kyO0P56xlqk180+vEhcF+kcllKpS7LQO+HoBfTsKIOh0kAwwEJ xAw6l9r0yngXbRYUi7AMVZCTth5KyUqz3l+7T1/xTrQbOgHk3wzyMD2m1OnmTArcH52OC9ZhXub QMimua+gDjmf6GpuB+q3TXOni7k7g302+p1aX1D52DGdf0G5q4acvVYB8m/suSS2pXJOQkPTRxM PQHCufpxh5IUKrZ0zDX2OSazO/+F0hreMg= X-Received: by 2002:a17:903:390d:b0:2c9:fb11:1bf4 with SMTP id d9443c01a7336-2d64af4eea9mr635232355ad.7.1787651407659; Tue, 25 Aug 2026 02:50:07 -0700 (PDT) Received: from localhost.localdomain ([103.120.31.178]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-32827662702sm5923062eec.10.2026.08.25.02.50.03 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Tue, 25 Aug 2026 02:50:07 -0700 (PDT) From: Khawar Ahemad To: bpf@vger.kernel.org Cc: linux-kernel@vger.kernel.org, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, eddyz87@gmail.com, jiayuan.chen@linux.dev, emil@etsalapatis.com, ahemadkhawar123@gmail.com Subject: [PATCH bpf-next v6 1/4] bpf: Add a sleepable page allocator for map memory Date: Tue, 25 Aug 2026 15:19:52 +0530 Message-ID: <20260825094955.83240-2-ahemadkhawar123@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260825094955.83240-1-ahemadkhawar123@gmail.com> References: <20260825094955.83240-1-ahemadkhawar123@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Jiayuan Chen bpf_map_alloc_pages() picks the allocator via can_alloc_pages(), a conservative guess for BPF program context that is always false under PREEMPT_RT. So even a caller that really is sleepable gets the non-blocking allocator, which never reclaims and never engages the OOM machinery. Add bpf_map_alloc_page_sleepable() for callers that know they are sleepable. Like the other bpf map allocators it places the page on the map's numa_node and does not follow the faulting task's NUMA mempolicy; arena memory is shared, so the map's node is the right placement policy. The next patch uses it from the arena page fault handler. Signed-off-by: Jiayuan Chen Reviewed-by: Emil Tsalapatis Signed-off-by: Khawar Ahemad --- include/linux/bpf.h | 1 + kernel/bpf/syscall.c | 21 +++++++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index b3cd28d9e3..c817c99d29 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -2784,6 +2784,7 @@ struct bpf_prog *bpf_prog_get_curr_or_next(u32 *id); =20 int bpf_map_alloc_pages(const struct bpf_map *map, int nid, unsigned long nr_pages, struct page **page_array); +struct page *bpf_map_alloc_page_sleepable(const struct bpf_map *map); #ifdef CONFIG_MEMCG void bpf_map_memcg_enter(const struct bpf_map *map, struct mem_cgroup **ol= d_memcg, struct mem_cgroup **new_memcg); diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 6874ba1424..f9b81638e5 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -602,15 +602,14 @@ static bool can_alloc_pages(void) !IS_ENABLED(CONFIG_PREEMPT_RT); } =20 +#define BPF_PAGE_GFP (GFP_KERNEL | __GFP_ZERO | __GFP_ACCOUNT | __GFP_NOWA= RN) + static struct page *__bpf_alloc_page(int nid) { if (!can_alloc_pages()) return alloc_pages_nolock(__GFP_ACCOUNT, nid, 0); =20 - return alloc_pages_node(nid, - GFP_KERNEL | __GFP_ZERO | __GFP_ACCOUNT - | __GFP_NOWARN, - 0); + return alloc_pages_node(nid, BPF_PAGE_GFP, 0); } =20 int bpf_map_alloc_pages(const struct bpf_map *map, int nid, @@ -636,6 +635,20 @@ int bpf_map_alloc_pages(const struct bpf_map *map, int= nid, return ret; } =20 +/* + * For callers that know they run in a sleepable context, e.g. a user page + * fault handler. can_alloc_pages() is a conservative guess made for BPF + * program context - notably it is always false on PREEMPT_RT - so going + * through bpf_map_alloc_pages() there would needlessly pick the + * non-blocking allocator, which never reclaims and never engages the OOM + * machinery. + */ +struct page *bpf_map_alloc_page_sleepable(const struct bpf_map *map) +{ + might_sleep(); + return alloc_pages_node(map->numa_node, BPF_PAGE_GFP, 0); +} + static int btf_field_cmp(const void *a, const void *b) { const struct btf_field *f1 =3D a, *f2 =3D b; --=20 2.54.0 (Apple Git-157) From nobody Mon Sep 28 06:34:53 2026 Received: from mail-pg1-f181.google.com (mail-pg1-f181.google.com [209.85.215.181]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 249323F328A for ; Tue, 25 Aug 2026 09:50:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787651415; cv=none; b=mUh/Cl6I0K3T2/AQaixzseWQ4kDtKvFoSdkAcoFy4igytiSBkcRwLrKdfhpw3nxQe5hmVIZlkJVdkEB7zf+VC9VOZU7C5XN26qwSnbjgrbE1xj7HIVFk/DYTHAsVvl3U1NC1XpkJAN7mevd9OE4QxP6K433DpIP196rtV61ft+M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787651415; c=relaxed/simple; bh=nCIKMze/nePG9edrgFsirG3py5omd/Tnqbe3SwzpmlM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=eY7sKpifAnOVK3/EMMs+wztTYWlbCX7wMwHnI7X8olV31BZBnSFW4zFxC7h/0LxsSXTuihjNy1BV3MO43bqF28f8Ig+FeNnZ2VCVX9oE9bg63bs2+ZixhkeEIjoxfLC6zM4VHIS3T3PuVLhEC2JXkwJqhfOH6ZVyLDkz019FxIo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=sf42y449; arc=none smtp.client-ip=209.85.215.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="sf42y449" Received: by mail-pg1-f181.google.com with SMTP id 41be03b00d2f7-cc11a905ba5so3298360a12.2 for ; Tue, 25 Aug 2026 02:50:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787651412; x=1788256212; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=XGkExxMyhBiKuGkp4+FT/b5oczqhluEeBce3FhXEQbg=; b=sf42y449qxRSJY/PxMS4Pu5UnI6EhxDpFgALuCg5SfMpF80Vnkp29z7NVsM+QX0T0u 7+WUyKEh7chdyAlacI7WPKfYJ7oGrvRvKz0WdFjnvLTn1W+hemC07WJuftOmhoXORZos QcqzAcXHtl7bes0hjxTv8SjCAOAA/Z4tdLJ8jWW04u1Kjlab0TQ9WKh/J9kH5KWtUBhw cUMMWbmiGF9b5doYOD2uDuXlCltxGsQnxzoVUaqc+1UJfWq81SBzgycWp81aLV77zs2R n+ZJBImOLs456n/eR5TCdFC+5xg/SIVZZs2y6MJ5PEXpVsQWwm7Pzk2NJt1aq2l9QTHg B4ig== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787651412; x=1788256212; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=XGkExxMyhBiKuGkp4+FT/b5oczqhluEeBce3FhXEQbg=; b=DCMoop3CfKXZAUTvFBG/yfwTQ4mLdNF2x37o/lR/05wS4/W+L6I7g85a+sXq5cj1ip 4m7rKXnmIoAUyPRuTP+HKqRqk69ucbiUl/NlvdUNUPr9JBkik9MwT+eqbpSuC8mT+Z3S Z/1BDCUYkXgGo+jrYVzt0ml3bE9/nrhJIL+UUIrelmgQ70osS4XEUK1zvaXi3hLaxHbh /WB5dEUbW6VveawX74XWAnHbN0cg2smbGRB+WH4RY/AacBvV7v37sxcgOWhXZf3kiXdA B0cdi3r669nIfddniB13t8ArrZTv4KgMbphxkg5Eskac5IwildL1peZ7DR7hiNpMM3Yi 8qQQ== X-Gm-Message-State: AFuF++nU1OO3Km7v5fJE7V2uVl7Ree9KJ8B1bvBsKOOLeRhYOKhDiC+z 2Ydb91c7o4zFy9cg+MsiYHM0kIPnR74+EM5lhzRkFzPdejqsu6LBJiFK X-Gm-Gg: AR+sD13OsiuxB25mf0hK8nwqQFccU8DrKjRoKZEQiD2zRk+6Ewskt8msW3dUsyKZilQ LpBYRtDoxhH+lr75IB788D1BSuxA1RlXDYQauofSmK4810+qPALNIqWg9cPkvPtSSBo3vOyiqdv ShneG0rUbIE4OALWONhLzFOMBzw/3MIRuA0ewwO5Y/fVu/Q0ElBsX1TO4wREUyEoKK3UFjXRd4s 3NVkyA4NJRSg5LsS1JyupOT80AUemwUC7pt77V8m0Nw/ust6ZzJrlcMwL+BD7RVDslVOfs3zP7t qAIPjSDp6Tns0Uolk+xzC7sQEiMsR3TApt/7cx+uyvO+RlSn8mVWVJ4PhUeFxL3+o3eXcoUdVwi gJwmB+GOYPu/Yu5clMxdeo0p1KBxrlmM75hFz11uQJKiBsB8SBTnztOPK0JCRpwzb3BsJWXVAky eycgYyF55Yg90PHL1ybWoAieEWIAW58Yq5e377H6/7+ckr+hXJv7hId7qTue3Y66Um0sHLX+doQ /KLmTaD6gh26z1oCHzfW5U3nQvUYG9DCTM= X-Received: by 2002:a05:6a20:ce4f:b0:3cb:d156:d362 with SMTP id adf61e73a8af0-3cd90fbd2admr11259855637.3.1787651412251; Tue, 25 Aug 2026 02:50:12 -0700 (PDT) Received: from localhost.localdomain ([103.120.31.178]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-32827662702sm5923062eec.10.2026.08.25.02.50.08 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Tue, 25 Aug 2026 02:50:11 -0700 (PDT) From: Khawar Ahemad To: bpf@vger.kernel.org Cc: linux-kernel@vger.kernel.org, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, eddyz87@gmail.com, jiayuan.chen@linux.dev, emil@etsalapatis.com, ahemadkhawar123@gmail.com Subject: [PATCH bpf-next v6 2/4] bpf: arena: allocate the fault-in page outside the lock Date: Tue, 25 Aug 2026 15:19:53 +0530 Message-ID: <20260825094955.83240-3-ahemadkhawar123@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260825094955.83240-1-ahemadkhawar123@gmail.com> References: <20260825094955.83240-1-ahemadkhawar123@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Jiayuan Chen arena_vm_fault() allocated the page while holding arena->spinlock, so it could only use the non-blocking allocator. Once the memcg is at memory.max that allocation just fails, the fault turns into VM_FAULT_SIGSEGV, and the process gets a SIGSEGV on a perfectly valid arena address. Hitting memory.max is routine (e.g. page cache from reading a big file), so this kills innocent processes. Rework the fault handler: - Preallocate the page before taking the lock, like do_anonymous_page() does, so it can sleep and go through reclaim and the memcg OOM killer, instead of turning a routine memory.max into a fake segfault. - On allocation failure return VM_FAULT_SIGBUS. The allocation already ran reclaim and the OOM killer, so the failure is non-recoverable. For a task faulting its own arena this changes nothing: the OOM killer already picked it inside the allocation and it dies by SIGKILL, the SIGBUS is shadowed by the pending fatal signal, and the memcg OOM is still reported. VM_FAULT_OOM would instead be retried by the fault path and can livelock when the charged memcg is not the faulting task's (e.g. a shared arena) and its OOM killer cannot reach it. - A lockless probe skips that preallocation when a page is already mapped (e.g. allocated by the bpf program), so the common case wastes no allocation. The rare race where such a page is freed before we take the lock falls back to the non-blocking allocator under the lock. - Return VM_FAULT_SIGBUS for the other non-recoverable errors (lock failure, range-tree and page-table failures) instead of VM_FAULT_SIGSEGV; only BPF_F_SEGV_ON_FAULT, and a scratch-page hole under that flag, is a real user addressing error and keeps VM_FAULT_SIGSEGV. - Tidy up the error labels. Reviewed-by: Emil Tsalapatis Signed-off-by: Jiayuan Chen Signed-off-by: Khawar Ahemad --- kernel/bpf/arena.c | 90 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 69 insertions(+), 21 deletions(-) diff --git a/kernel/bpf/arena.c b/kernel/bpf/arena.c index 7b6847200b..fa462a0ff1 100644 --- a/kernel/bpf/arena.c +++ b/kernel/bpf/arena.c @@ -481,7 +481,8 @@ static vm_fault_t arena_vm_fault(struct vm_fault *vmf) struct bpf_map *map =3D vmf->vma->vm_file->private_data; struct bpf_arena *arena =3D container_of(map, struct bpf_arena, map); struct mem_cgroup *new_memcg, *old_memcg; - struct page *page; + struct page *page, *new_page =3D NULL; + vm_fault_t fault_ret; long kbase, kaddr; unsigned long flags; int ret; @@ -489,59 +490,106 @@ static vm_fault_t arena_vm_fault(struct vm_fault *vm= f) kbase =3D bpf_arena_get_kern_vm_start(arena); kaddr =3D kbase + (u32)(vmf->address); =20 - if (raw_res_spin_lock_irqsave(&arena->spinlock, flags)) + page =3D vmalloc_to_page((void *)kaddr); + if (!page && !(arena->map.map_flags & BPF_F_SEGV_ON_FAULT)) { + /* + * Preallocate outside the lock with a sleepable allocator so it + * can reclaim and run the memcg OOM killer, which the + * non-blocking allocator under arena->spinlock cannot. A NULL + * return is non-recoverable, so fail with VM_FAULT_SIGBUS; + * VM_FAULT_OOM would be retried by the fault path and can + * livelock when the charged memcg is not the faulting task's. + */ + bpf_map_memcg_enter(&arena->map, &old_memcg, &new_memcg); + new_page =3D bpf_map_alloc_page_sleepable(map); + bpf_map_memcg_exit(old_memcg, new_memcg); + if (!new_page) + return VM_FAULT_SIGBUS; + } + + if (raw_res_spin_lock_irqsave(&arena->spinlock, flags)) { /* * A failed lock means a possible deadlock was detected. Don't * return VM_FAULT_RETRY: this handler never took mmap_lock, but * the fault path would re-take it on retry and deadlock. Fail. */ + if (new_page) + free_pages_nolock(new_page, 0); return VM_FAULT_SIGBUS; + } =20 page =3D vmalloc_to_page((void *)kaddr); if (page) { - if (page =3D=3D arena->scratch_page) - /* BPF triggered scratch here; don't lazy-alloc over it */ - goto out_sigsegv; + if (page =3D=3D arena->scratch_page) { + /* + * A scratch page marks a hole. Segfault only if the user + * asked for it; otherwise we could lazy-allocate but + * choose not to over a hole, so report a bus error. + */ + fault_ret =3D (arena->map.map_flags & BPF_F_SEGV_ON_FAULT) ? + VM_FAULT_SIGSEGV : VM_FAULT_SIGBUS; + goto out_err_locked; + } /* already have a page vmap-ed */ goto out; } =20 + if (arena->map.map_flags & BPF_F_SEGV_ON_FAULT) { + /* User space requested to segfault when page is not allocated by bpf pr= og */ + fault_ret =3D VM_FAULT_SIGSEGV; + goto out_err_locked; + } + bpf_map_memcg_enter(&arena->map, &old_memcg, &new_memcg); =20 - if (arena->map.map_flags & BPF_F_SEGV_ON_FAULT) - /* User space requested to segfault when page is not allocated by bpf pr= og */ - goto out_sigsegv_memcg; + if (!new_page) { + /* + * Very rare race: the bpf program had allocated a page here, so + * the lockless probe saw it and we skipped preallocation, but it + * freed the page before we took the lock. Now we do need one; + * sleeping is not allowed here, so fall back to the non-blocking + * allocator and give up if it fails. + */ + ret =3D bpf_map_alloc_pages(map, map->numa_node, 1, &new_page); + if (ret) { + fault_ret =3D VM_FAULT_SIGBUS; + goto out_err_locked_memcg; + } + } =20 ret =3D range_tree_clear(&arena->rt, vmf->pgoff, 1); - if (ret) - goto out_sigsegv_memcg; - - struct apply_range_data data =3D { .arena =3D arena, .pages =3D &page, .i= =3D 0 }; - /* Account into memcg of the process that created bpf_arena */ - ret =3D bpf_map_alloc_pages(map, NUMA_NO_NODE, 1, &page); if (ret) { - range_tree_set(&arena->rt, vmf->pgoff, 1); - goto out_sigsegv_memcg; + fault_ret =3D VM_FAULT_SIGBUS; + goto out_err_locked_memcg; } + struct apply_range_data data =3D { .arena =3D arena, .pages =3D &new_page= , .i =3D 0 }; =20 ret =3D apply_to_page_range(&init_mm, kaddr, PAGE_SIZE, apply_range_set_c= b, &data); if (ret) { range_tree_set(&arena->rt, vmf->pgoff, 1); - free_pages_nolock(page, 0); - goto out_sigsegv_memcg; + fault_ret =3D VM_FAULT_SIGBUS; + goto out_err_locked_memcg; } flush_vmap_cache(kaddr, PAGE_SIZE); bpf_map_memcg_exit(old_memcg, new_memcg); + /* new_page was consumed */ + page =3D new_page; + new_page =3D NULL; out: page_ref_add(page, 1); raw_res_spin_unlock_irqrestore(&arena->spinlock, flags); + if (new_page) + free_pages_nolock(new_page, 0); vmf->page =3D page; return 0; -out_sigsegv_memcg: + +out_err_locked_memcg: bpf_map_memcg_exit(old_memcg, new_memcg); -out_sigsegv: +out_err_locked: raw_res_spin_unlock_irqrestore(&arena->spinlock, flags); - return VM_FAULT_SIGSEGV; + if (new_page) + free_pages_nolock(new_page, 0); + return fault_ret; } =20 static const struct vm_operations_struct arena_vm_ops =3D { --=20 2.54.0 (Apple Git-157) From nobody Mon Sep 28 06:34:53 2026 Received: from mail-pf1-f179.google.com (mail-pf1-f179.google.com [209.85.210.179]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 99DF83F39D8 for ; Tue, 25 Aug 2026 09:50:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787651419; cv=none; b=nbdoO0qMlCQJABfjiz2NtjY51+kny+Vz0mr2Mq+lYZ1YmeqehLgiZ05OcfofCOmp33+WblXlPZsAf3YGma9GwcYyPIcY5tb/j0XsUwZUz4550wrTx2tq+eTX14h8zR2X+SzYbZz9iAMNmfeDXbHPTVR7mns1xVG5r5F8WThKIC0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787651419; c=relaxed/simple; bh=/yvTesosUitvxpBGbkVrq+T3ZwnrBfxMu1Tk0/tPvCI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=aYtyWXF1v0cDJ1sEavNQke2iJgefFq8trtFPHMDJUZPh++lhMCRMxRLx8GzUJKva7QSpCGpa89Nugh+gfNmpJzUs/cyZie57YgJOgvTu1Cd36Z0FSzpJR10FRBgJ6+ppis4mqOWaWtHObfVUUsiFZO3w5yTAd1LUmW2nPnvwA3E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=CngOv4bz; arc=none smtp.client-ip=209.85.210.179 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="CngOv4bz" Received: by mail-pf1-f179.google.com with SMTP id d2e1a72fcca58-84fa3b14ee1so3613228b3a.0 for ; Tue, 25 Aug 2026 02:50:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787651417; x=1788256217; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=0rBrebsEU++q5oyTmtoojXSPfykwosiXDRrVD5SURpU=; b=CngOv4bzYh+25ozMucU3E6MIUefWURDeHhjBbjDsIW4AimcgCwmuboDqdUbU9p3M3k 7/Boc0MPIbzZwAAyo/j7VAeGsGncu5xwleC6zY9zCVdSoSgFVNi3RrWr7O6IdbVgkmC/ xhKI67Yb4vI6K0eiBFqo0YkmQTkCA/8ulIpLpMKLb2Iet4InUKfyzNfNMRJvbhCcxLvX qQJV/Q0NqlvxDQy5cPlTAAZ4G4F7aYlaNlIxeeawtpEMUjanvr97QsvLEryK4r93cMkh b/RyC4VSERs9xfk64vPm5QZPwHKickM1q3ArX+AG/gIOdZgsRLFZ+tDg3/JxX9cATL7i bi+Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787651417; x=1788256217; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=0rBrebsEU++q5oyTmtoojXSPfykwosiXDRrVD5SURpU=; b=FWNqd71si4t4Wzh+s485L6s8U58OxXqTRcJfhY71br0v3t/Ok0qUATdi00FGhmo4zJ 9inbV/WcY9/LcifM1FlgJJI87WdpZXBrGqaEVHSJ3Ac1PofiEdcZ1VRXM0pWZWX72lpG YZ2mNELo2SDqBURUH4BphiOTuBP27FUzLL5EYsCZsblO+d+qE9oApXNou57X+ZVJaqE9 dVPZtA2eM7uRMmzmYkpBQNz5nhbkJckUIwzuJFWl/sV6ZoHCHNViGhCZmiilnF16IdbD nv/5gvDplWTDlzwVU3Sx5uHaOYvU4Q1PUifmNDgmP1yqp/S1X7lr8/Oas2S+90d0HmPV hVVA== X-Gm-Message-State: AFuF++kQ5NHt5r2/4vndM8I01nH4sA1X+QLUlP1EzcF/kh0aosHiX+Yb XArB2vLZjIBF7wonjdF4l2toIgWyNrw3gqviVEVI5S3qgEg+K+YzXutQ X-Gm-Gg: AR+sD10I8aGStvit8e8r/LRC/1HXSVGx16kT6yo2gBY92MLtffjM61J3MNQAF3xgslx fM1tfBQIL42XbxFzUyniELWrBm6z7jAoLpvCZU/Ew+tCWMdaq7ZbEow/WxoAeO54lBb84goNki3 TidPeC6q46/ftEuKllygfTCvZWYeCR84U9ITq9YRz8XQzbnfeoRUrwSxIqQmsrdmssWuF0WJAUd OIfpkk09F/hLfZBCj4tNtwzOnsTQ2MyNkk2smyptf0T6tkBEJSUew6BkjohrhX9+5qCP9YdIobf cA0l/xVIOJDXECJi6/flw7w7JfQwmmBT/aaKVWtYfvpL7uwSKBOyrOIRiMleEPWK3ZkgZPukFss BAVIxUT4AYxMOMlNxix74595omg4V2tpymNDIOasL2WSfpdP8yn7RSW3EbDfhXS8eatBwz5ZeV0 CDGk0eujvSR4n4gOKR75W0nNxOHpPy/9UhByz+S98yrzAzw7J6Yw8jEx0MQdXXNtxMZrY0TYyKh E1aihbbEs3AEGi0kGJcVEJM X-Received: by 2002:a05:6a21:138f:b0:3c1:fbf:1e2e with SMTP id adf61e73a8af0-3cd3008bf4bmr56836649637.10.1787651416876; Tue, 25 Aug 2026 02:50:16 -0700 (PDT) Received: from localhost.localdomain ([103.120.31.178]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-32827662702sm5923062eec.10.2026.08.25.02.50.12 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Tue, 25 Aug 2026 02:50:16 -0700 (PDT) From: Khawar Ahemad To: bpf@vger.kernel.org Cc: linux-kernel@vger.kernel.org, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, eddyz87@gmail.com, jiayuan.chen@linux.dev, emil@etsalapatis.com, ahemadkhawar123@gmail.com Subject: [PATCH bpf-next v6 3/4] selftests/bpf: Add read_cgroup_file() to cgroup_helpers Date: Tue, 25 Aug 2026 15:19:54 +0530 Message-ID: <20260825094955.83240-4-ahemadkhawar123@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260825094955.83240-1-ahemadkhawar123@gmail.com> References: <20260825094955.83240-1-ahemadkhawar123@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Jiayuan Chen cgroup_helpers has write_cgroup_file()/write_cgroup_file_parent() but no read counterpart. Add read_cgroup_file() and read_cgroup_file_parent() so a forked child can read a cgroup file (e.g. memory.current) from the work dir owned by the parent that set the environment up, without hand-building the /mnt/... path. Reviewed-by: Emil Tsalapatis Signed-off-by: Jiayuan Chen Signed-off-by: Khawar Ahemad --- tools/testing/selftests/bpf/cgroup_helpers.c | 67 ++++++++++++++++++++ tools/testing/selftests/bpf/cgroup_helpers.h | 4 ++ 2 files changed, 71 insertions(+) diff --git a/tools/testing/selftests/bpf/cgroup_helpers.c b/tools/testing/s= elftests/bpf/cgroup_helpers.c index 45cd0b479f..4183ff6150 100644 --- a/tools/testing/selftests/bpf/cgroup_helpers.c +++ b/tools/testing/selftests/bpf/cgroup_helpers.c @@ -188,6 +188,73 @@ int write_cgroup_file_parent(const char *relative_path= , const char *file, return __write_cgroup_file(cgroup_path, file, buf); } =20 +static int __read_cgroup_file(const char *cgroup_path, const char *file, + char *buf, size_t len) +{ + char file_path[PATH_MAX + 1]; + ssize_t got; + int fd; + + snprintf(file_path, sizeof(file_path), "%s/%s", cgroup_path, file); + fd =3D open(file_path, O_RDONLY); + if (fd < 0) { + log_err("Opening %s", file_path); + return 1; + } + + got =3D read(fd, buf, len - 1); + if (got < 0) { + log_err("Reading %s", file_path); + close(fd); + return 1; + } + buf[got] =3D '\0'; + close(fd); + return 0; +} + +/** + * read_cgroup_file() - Read from a cgroup file + * @relative_path: The cgroup path, relative to the workdir + * @file: The name of the file in cgroupfs to read from + * @buf: Buffer to read into, NUL-terminated on success + * @len: Size of @buf + * + * Read from a file in the given cgroup's directory. + * + * If successful, 0 is returned. + */ +int read_cgroup_file(const char *relative_path, const char *file, + char *buf, size_t len) +{ + char cgroup_path[PATH_MAX - 24]; + + format_cgroup_path(cgroup_path, relative_path); + return __read_cgroup_file(cgroup_path, file, buf, len); +} + +/** + * read_cgroup_file_parent() - Read from a cgroup file in the parent proce= ss + * workdir + * @relative_path: The cgroup path, relative to the parent process workdir + * @file: The name of the file in cgroupfs to read from + * @buf: Buffer to read into, NUL-terminated on success + * @len: Size of @buf + * + * Read from a file in the given cgroup's directory under the parent proce= ss + * workdir. + * + * If successful, 0 is returned. + */ +int read_cgroup_file_parent(const char *relative_path, const char *file, + char *buf, size_t len) +{ + char cgroup_path[PATH_MAX - 24]; + + format_parent_cgroup_path(cgroup_path, relative_path); + return __read_cgroup_file(cgroup_path, file, buf, len); +} + /** * setup_cgroup_environment() - Setup the cgroup environment * diff --git a/tools/testing/selftests/bpf/cgroup_helpers.h b/tools/testing/s= elftests/bpf/cgroup_helpers.h index 3857304be8..d42d2e1304 100644 --- a/tools/testing/selftests/bpf/cgroup_helpers.h +++ b/tools/testing/selftests/bpf/cgroup_helpers.h @@ -15,6 +15,10 @@ int write_cgroup_file(const char *relative_path, const c= har *file, const char *buf); int write_cgroup_file_parent(const char *relative_path, const char *file, const char *buf); +int read_cgroup_file(const char *relative_path, const char *file, + char *buf, size_t len); +int read_cgroup_file_parent(const char *relative_path, const char *file, + char *buf, size_t len); int cgroup_setup_and_join(const char *relative_path); int get_root_cgroup(void); int create_and_get_cgroup(const char *relative_path); --=20 2.54.0 (Apple Git-157) From nobody Mon Sep 28 06:34:53 2026 Received: from mail-pl1-f178.google.com (mail-pl1-f178.google.com [209.85.214.178]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 59FC63F44FC for ; Tue, 25 Aug 2026 09:50:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787651423; cv=none; b=medUrQSfx4gFrQutd+KIm6ZhlcxrkMJh4IHLGZ3WC6jZoOYOKQkapYMjuC2pZ4PTtubK1AWVrPe3E4aX/OEau/UaMkL94AVEqcf55kfQF/m+gmJMqCeo7t5+FG/juSRjK5vc8zJflaxq7cDY1ph6n1GN5XXTtEMlX7DjBFoKh4A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787651423; c=relaxed/simple; bh=eNDvW0Iu/zHTiE51wOyu+eKdfoNYQuHT3TsRyRKxraE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=luGzzRQaWPIATUtd7CU9QwlG2ehtBpD0q30QLA39z0dXlRapxPEtdlJQcUqoH0gSUXGC4mWfTjRhYlbW8q6F7vnvQtX+fRHS0HPp3W1OznhlCWR3zSWVLYkb1DB4/phRXxXShFBYZl3DRWkFvtmqdsMSv9BTWCtz8U8ZLeKEfus= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=fg+8HDhD; arc=none smtp.client-ip=209.85.214.178 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="fg+8HDhD" Received: by mail-pl1-f178.google.com with SMTP id d9443c01a7336-2caea3f742bso67855625ad.0 for ; Tue, 25 Aug 2026 02:50:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787651421; x=1788256221; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=gmMis3erKTu0LnQVLezup5OoKQv5cNc8ZInftLWaecQ=; b=fg+8HDhDCH6gTPUig9U/5ItNyki6d6XAjJ1noArxdM1FQvJQ3cTWRuk/M5vmaLHOmi nImtgx6K4nR0n5Wiz2Pksc4LlRvTTK4hhuJs2NzQpS+6OSijo8ZuytWg5TsJ/sYnpuYz cMc3fHz4XQUs9axrk0jdpHPXaxNPgNy8PBUts5M2E2Li0Nq6lw2Q/hv+WR3TMp8HiXYV IEzspS0hYV1dBctMslt1BCDw/gxpVZTsdjzxelllulSrXsb9hbiouo7cUl0zw7G4xvjJ p4eDt3mu6ZChSFpr4Jf28CgkinQX0NUTWqI/Ftfe5xvDwCc5qUSnT+WG8XmsEGowrgOt voKg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787651421; x=1788256221; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=gmMis3erKTu0LnQVLezup5OoKQv5cNc8ZInftLWaecQ=; b=dTVLmyFjVdkYgRJwn4VdUos5YZdTGpG7Y9xbh1GDpW4zWZ7+6vG9Ze/7Kj6Ra2yGsX CF6rZ0gpeZUAf3jBQ+b3uKCnAUChEp5/MF0e8wXwl9w00YHFP7a8LxP+d9UowYksSOep 7QrspC3qF+zFyOdAALMQP1Ta5zA/0lCn5QuGEUPiO0sOLKd5ICQAsOJBzYVJ43jc6A3D jfw3sRphgKgsqPFUsoCmnEq/ZPGiG/JjfysNaDz5YSL+E5cHIqk0fS1w8PGSJPKUv4z9 IoQnpP4E1ZmwtipFK/wllpBErdipFjwt65iLsvpMz5GaU2jG3O+UcTedKHxLrG/SywoA xEiA== X-Gm-Message-State: AFuF++ksYu3Rgv91Q5ssBdQVdr11Trbgtu9LlKHLJs+cF1Pi5tEZYbDi 2OGUQ+nQ2Wm66nBhvoPBcZzDO0qJD3En16aFhiVxb2xjfHcY0DroF8N3aHnjnQSO1ps= X-Gm-Gg: AR+sD10xTHOPvprafDwTaZIpY9wTteVqVPp7gdU5ZDycT4zFyImz6898smYZkRPxHSj gCJgIxn4ImcgT7H+zVdOOSlfzthpWkxfbeK3SFd5l9P9N2oHIStEFIwKfhZXIEHbOac5xJs2Jx1 twoQOw6YmU6BtAoewA8O3xdJz3JhrqJK0iqzIZNzoCoBnh7T9nZFXNC+Uvsu609l8RRBxuqYJ1f ql3mbyD6FZnkbpMsKjb8/WRPUFyPJqmlew7X9WuMNpUdd7+pWxjrdkWSK//r6to6kKLtcqYuAD7 x3UWTu5FCga1CG88VmUkTaPEuXQ2ijbgquVuf0SM08CABkkHb7WeYBOTgWFb1v2we2ZAzJOqWAi 5YDsam2EgXSy8HwDg14qte9VwKRmJWtLMktjNdtRaoE037QeTgiCj4odI7dumrmQZG1LzV5FGUH McviZhzaCFXFdh1D3Vw8QIs8C+y5udlhDLEs8xM8d+UXzXtDNpJxTUwBIrUFLhpavMi5+RgSMB9 R1YxnvRIg96m40ZSnEzqnsx X-Received: by 2002:a17:902:e784:b0:2cf:ba10:6d6 with SMTP id d9443c01a7336-2d64af6f8dbmr615701665ad.4.1787651421388; Tue, 25 Aug 2026 02:50:21 -0700 (PDT) Received: from localhost.localdomain ([103.120.31.178]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-32827662702sm5923062eec.10.2026.08.25.02.50.17 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Tue, 25 Aug 2026 02:50:20 -0700 (PDT) From: Khawar Ahemad To: bpf@vger.kernel.org Cc: linux-kernel@vger.kernel.org, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, eddyz87@gmail.com, jiayuan.chen@linux.dev, emil@etsalapatis.com, ahemadkhawar123@gmail.com Subject: [PATCH bpf-next v6 4/4] selftests/bpf: Add a test for arena fault-in under memory.max Date: Tue, 25 Aug 2026 15:19:55 +0530 Message-ID: <20260825094955.83240-5-ahemadkhawar123@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260825094955.83240-1-ahemadkhawar123@gmail.com> References: <20260825094955.83240-1-ahemadkhawar123@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Jiayuan Chen A child joins a memcg capped 64M above its post-load usage and faults an arena in until it runs out of that budget. With the fix the arena page comes from the sleepable allocator, so hitting memory.max goes through the memcg OOM path and the child is OOM-killed, which the test checks via memory.events "oom_kill". Without the fix the test may still pass, because a concurrent blocking allocation in the child (e.g. a COW fault on an inherited page) can hit memory.max and OOM-kill it first. The goal is only that the fixed kernel passes reliably. # test_progs -v -t arena_memcg serial_test_arena_memcg:PASS:child killed by signal serial_test_arena_memcg:PASS:memcg oom_kill #5 arena_memcg:OK # dmesg (the OOM comes from the arena sleepable allocation) test_progs invoked oom-killer: gfp_mask=3DGFP_KERNEL_ACCOUNT|__GFP_ZERO arena_vm_fault+0x4bc/0xad0 Memory cgroup out of memory: Killed process 473 (test_progs) Reviewed-by: Emil Tsalapatis Signed-off-by: Jiayuan Chen Signed-off-by: Khawar Ahemad --- .../selftests/bpf/prog_tests/arena_memcg.c | 157 ++++++++++++++++++ .../testing/selftests/bpf/progs/arena_memcg.c | 24 +++ 2 files changed, 181 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/arena_memcg.c create mode 100644 tools/testing/selftests/bpf/progs/arena_memcg.c diff --git a/tools/testing/selftests/bpf/prog_tests/arena_memcg.c b/tools/t= esting/selftests/bpf/prog_tests/arena_memcg.c new file mode 100644 index 0000000000..752d29f299 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/arena_memcg.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include +#include +#ifndef PAGE_SIZE /* on some archs it comes in sys/user.h */ +#define PAGE_SIZE getpagesize() +#endif + +#include "cgroup_helpers.h" +#include "arena_memcg.skel.h" + +#define CG_PATH "/arena_memcg" + +/* Budget the arena gets on top of whatever is already charged after load.= */ +#define ARENA_BUDGET (64 * 1024 * 1024) + +static void dump_memcg(int (*rd)(const char *, const char *, char *, size_= t)) +{ + char buf[512]; + + /* + * memory.current reads 0 once the child has left the cgroup, so it only + * carries information when dumped from the live child; memory.peak and + * memory.events survive the child and tell the story either way. + */ + if (!rd(CG_PATH, "memory.current", buf, sizeof(buf))) + fprintf(stderr, "memory.current: %s", buf); + if (!rd(CG_PATH, "memory.max", buf, sizeof(buf))) + fprintf(stderr, "memory.max: %s", buf); + if (!rd(CG_PATH, "memory.peak", buf, sizeof(buf))) + fprintf(stderr, "memory.peak: %s", buf); + if (!rd(CG_PATH, "memory.events", buf, sizeof(buf))) + fprintf(stderr, "memory.events:\n%s", buf); + fflush(stderr); +} + +/* Read one key from a flat keyed cgroup file, e.g. "oom_kill" in memory.e= vents. */ +static long cg_read_key(const char *cg, const char *file, const char *key) +{ + char buf[512], *p; + + if (read_cgroup_file(cg, file, buf, sizeof(buf))) + return -1; + p =3D strstr(buf, key); + if (!p) + return -1; + return strtol(p + strlen(key), NULL, 10); +} + +void serial_test_arena_memcg(void) +{ + int cgroup_fd =3D -1, status, err; + const long ps =3D PAGE_SIZE; + char buf[64]; + pid_t pid; + + err =3D setup_cgroup_environment(); + if (!ASSERT_OK(err, "setup_cgroup_environment")) + return; + + cgroup_fd =3D create_and_get_cgroup(CG_PATH); + if (!ASSERT_OK_FD(cgroup_fd, "create_and_get_cgroup")) + goto out; + + /* No memory controller -> nothing to test. */ + if (read_cgroup_file(CG_PATH, "memory.current", buf, sizeof(buf))) { + fprintf(stderr, "%s:SKIP:no memory controller\n", __func__); + test__skip(); + goto out; + } + + pid =3D fork(); + if (!ASSERT_GE(pid, 0, "fork")) + goto out; + if (pid =3D=3D 0) { + struct arena_memcg *cskel; + __u32 i, npages; + char *base; + size_t sz; + long cur; + + /* + * Do everything from the child: the arena vma is VM_DONTCOPY so + * it would not survive fork(), only the child should be under the + * limit so that a memcg OOM cannot pick test_progs, and a map is + * charged to the memcg of the task that creates it - so join + * before load. The cgroup work dir belongs to the parent that set + * the environment up, so reach it with the _parent() helpers. + * Errors are reported to the parent through the exit code, since + * ASSERT_* in a forked child does not reach it. + */ + snprintf(buf, sizeof(buf), "%d", getpid()); + if (write_cgroup_file_parent(CG_PATH, "cgroup.procs", buf)) + _exit(2); + + cskel =3D arena_memcg__open_and_load(); + if (!cskel) + _exit(3); + + base =3D bpf_map__initial_value(cskel->maps.arena, &sz); + if (!base) + _exit(4); + npages =3D bpf_map__max_entries(cskel->maps.arena); + + /* + * Cap only now, after load: everything but the fault-in is + * charged, so the arena gets a fixed budget regardless of what + * the load itself cost, and the load can never hit the limit. + */ + if (read_cgroup_file_parent(CG_PATH, "memory.current", buf, sizeof(buf))) + _exit(5); + cur =3D strtol(buf, NULL, 10); + snprintf(buf, sizeof(buf), "%ld", cur + ARENA_BUDGET); + if (write_cgroup_file_parent(CG_PATH, "memory.max", buf)) + _exit(6); + + for (i =3D 0; i < npages; i++) + base[(size_t)i * ps] =3D 1; + /* Faulted everything without dying: dump why (only under -v). */ + dump_memcg(read_cgroup_file_parent); + _exit(0); + } + + if (!ASSERT_EQ(waitpid(pid, &status, 0), pid, "waitpid")) + goto out; + + /* A non-zero exit means the child failed to set up; the code says where.= */ + if (WIFEXITED(status) && WEXITSTATUS(status)) { + ASSERT_OK(WEXITSTATUS(status), "child setup"); + goto out; + } + + /* + * Faulting a valid arena address until memory.max is hit must not look + * like an invalid access. Without the fix the fault path allocated with + * the non-blocking allocator, turned its -ENOMEM into VM_FAULT_SIGSEGV, + * and the child died with SIGSEGV on a valid address; now it is handled + * by the memcg OOM path instead. A SIGKILL alone would not prove the + * memcg OOM killer did it (a global OOM or an unrelated crash could also + * kill the child), so check memory.events.oom_kill, which records the + * memcg OOM and survives the child. + */ + if (!ASSERT_TRUE(WIFSIGNALED(status), "child killed by signal")) + goto out; + if (!ASSERT_GE(cg_read_key(CG_PATH, "memory.events", "oom_kill"), 1, + "memcg oom_kill")) + dump_memcg(read_cgroup_file); +out: + if (cgroup_fd >=3D 0) + close(cgroup_fd); + cleanup_cgroup_environment(); +} diff --git a/tools/testing/selftests/bpf/progs/arena_memcg.c b/tools/testin= g/selftests/bpf/progs/arena_memcg.c new file mode 100644 index 0000000000..88259cfea0 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/arena_memcg.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include "bpf_arena_common.h" + +struct { + __uint(type, BPF_MAP_TYPE_ARENA); + __uint(map_flags, BPF_F_MMAPABLE); + __uint(max_entries, 50000); /* number of pages */ +#ifdef __TARGET_ARCH_arm64 + __ulong(map_extra, 0x1ull << 32); /* start of mmap() region */ +#else + __ulong(map_extra, 0x1ull << 44); /* start of mmap() region */ +#endif +} arena SEC(".maps"); + +SEC("syscall") +int noop(void *ctx) +{ + return 0; +} + +char _license[] SEC("license") =3D "GPL"; --=20 2.54.0 (Apple Git-157)