From nobody Wed Jun 17 06:02:58 2026 Received: from out-181.mta1.migadu.com (out-181.mta1.migadu.com [95.215.58.181]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 610C521FF23; Mon, 27 Apr 2026 16:59:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777309167; cv=none; b=LmKN3W7Y7pnfxRh0HfmYmjPeRsDx+YoFytv00/r0vqj4wmql5sSgC69LlXIp1K5Tq5mE2C/PjZBT40diWi12AkxRiGhrCLh0YCgTzjETx3ePxtb8+Erb1H6zq4pGU7YdaT+FyYY69cJp4VNBL1XZxcC8TFRIGlSRM8mE1X/AL7A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777309167; c=relaxed/simple; bh=whicB2ftr5oTRrTNIW+rmCW4aEeQ9SHLQFsgKCkj210=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=V+MWQnibqFRmKpFkAr3fds0JcWSxfPozyyTAbtghXQsZYFPsbGOyjWjNIGovSvk60/kzspalzM6w9Vh4Dr3twT99FeYay358q/olAqbbDXIzMePlREpntJru2Hj4lopq+GCNVN1TsVl3ycINv+6N/GNAeRjpFyRcP6MhotUOk2Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=sQdMoABB; arc=none smtp.client-ip=95.215.58.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="sQdMoABB" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1777309163; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=2Svt+4NlaIIFnDXWH/eCk2Ml80i80lObraw1UrKQl8Y=; b=sQdMoABBd2Dfl+OPTz0lmHecx/bDu/iIBz8zhcfZkFgAHCXhuLPOZvHqL+iILoUD0jt7rE dx4+ScstADMWzjT2JdVY2PBP4iNUHG2/xGy7bx9zQNSYNJqVX4H13wAVNVeCledFhLdwXS o1bfvYB0buNxslXDiB5u8sA9JGz1G2s= From: Kaitao cheng To: martin.lau@linux.dev, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, eddyz87@gmail.com, song@kernel.org, yonghong.song@linux.dev, john.fastabend@gmail.com, kpsingh@kernel.org, sdf@fomichev.me, haoluo@google.com, jolsa@kernel.org, shuah@kernel.org, chengkaitao@kylinos.cn, linux-kselftest@vger.kernel.org Cc: bpf@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH bpf-next v10 1/8] bpf: refactor __bpf_list_del to take list node pointer Date: Tue, 28 Apr 2026 00:58:59 +0800 Message-ID: <20260427165906.84420-2-kaitao.cheng@linux.dev> In-Reply-To: <20260427165906.84420-1-kaitao.cheng@linux.dev> References: <20260427165906.84420-1-kaitao.cheng@linux.dev> 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 X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Kaitao Cheng Refactor __bpf_list_del to accept (head, struct list_head *n) instead of (head, bool tail). The caller now passes the specific node to remove: bpf_list_pop_front passes h->next, bpf_list_pop_back passes h->prev. Prepares for introducing bpf_list_del(head, node) kfunc to remove an arbitrary node when the user holds ownership. Signed-off-by: Kaitao Cheng --- kernel/bpf/helpers.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index baa12b24bb64..9cd7b028592c 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -2550,22 +2550,24 @@ __bpf_kfunc int bpf_list_push_back_impl(struct bpf_= list_head *head, return bpf_list_push_back(head, node, meta__ign, off); } =20 -static struct bpf_list_node *__bpf_list_del(struct bpf_list_head *head, bo= ol tail) +static struct bpf_list_node *__bpf_list_del(struct bpf_list_head *head, + struct list_head *n) { - struct list_head *n, *h =3D (void *)head; + struct list_head *h =3D (void *)head; struct bpf_list_node_kern *node; =20 /* If list_head was 0-initialized by map, bpf_obj_init_field wasn't * called on its fields, so init here */ - if (unlikely(!h->next)) + if (unlikely(!h->next)) { INIT_LIST_HEAD(h); + return NULL; + } if (list_empty(h)) return NULL; =20 - n =3D tail ? h->prev : h->next; node =3D container_of(n, struct bpf_list_node_kern, list_head); - if (WARN_ON_ONCE(READ_ONCE(node->owner) !=3D head)) + if (unlikely(READ_ONCE(node->owner) !=3D head)) return NULL; =20 list_del_init(n); @@ -2575,12 +2577,16 @@ static struct bpf_list_node *__bpf_list_del(struct = bpf_list_head *head, bool tai =20 __bpf_kfunc struct bpf_list_node *bpf_list_pop_front(struct bpf_list_head = *head) { - return __bpf_list_del(head, false); + struct list_head *h =3D (void *)head; + + return __bpf_list_del(head, h->next); } =20 __bpf_kfunc struct bpf_list_node *bpf_list_pop_back(struct bpf_list_head *= head) { - return __bpf_list_del(head, true); + struct list_head *h =3D (void *)head; + + return __bpf_list_del(head, h->prev); } =20 __bpf_kfunc struct bpf_list_node *bpf_list_front(struct bpf_list_head *hea= d) --=20 2.50.1 (Apple Git-155) From nobody Wed Jun 17 06:02:58 2026 Received: from out-173.mta1.migadu.com (out-173.mta1.migadu.com [95.215.58.173]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 87D263DA7EA for ; Mon, 27 Apr 2026 16:59:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.173 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777309175; cv=none; b=bQaxU7uYZoV8rFDJDLnl+BACTmGN4CnRTdK1v6vYZpGyCb6YuNG5ZcwZ/nlLc4jMrFaeM+QPmaJtwrOj5eIzpozX/OfU+UwoGATp9VQuvH1+mVv0puvOwngwz3wlyyGGqrrWxIxxAfxwvYzAU4y53P1gjlDFZj61OSXD8d77x14= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777309175; c=relaxed/simple; bh=MOXXlwv5+jPHoFenwU0Df/VSUFEVmpOCvtOJ2sq+C0A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=aqT9BZHdgVleYNeKR0HKpCCWoVnpGS+ApoTyGl8tw70SkjGzV8nFNJmUII0hiNUbdOXGQXKrRcm3Az6YPSMvmcWMFB74lld4tA8Gk5YID69KIr4bhdz+oU/eeZncZ4Lo7ZNxK23fzVD0DkpwUN/Et9rHudIEr9GxWOujRyijF6w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=OKgnb+T5; arc=none smtp.client-ip=95.215.58.173 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="OKgnb+T5" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1777309168; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=pCpRvT4uR2xbcKg4iuq0VJjzAy9PY+FmlCoNRTQS6mc=; b=OKgnb+T5qr64syIE9uMG6QOu0GvbC7CxuSFC90rkxWZiOdcW632iaRirknfcSMHnZFjc+c Hg9mgPNGMhkvD1z9ay8Qk9ArTYzBFey+mIK2PfDI4ZgSvXz5smtBGXrYi5ESbkteKey50v 7NKQ+OCFSoO49fKMzbHPg78zcg4r7xM= From: Kaitao cheng To: martin.lau@linux.dev, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, eddyz87@gmail.com, song@kernel.org, yonghong.song@linux.dev, john.fastabend@gmail.com, kpsingh@kernel.org, sdf@fomichev.me, haoluo@google.com, jolsa@kernel.org, shuah@kernel.org, chengkaitao@kylinos.cn, linux-kselftest@vger.kernel.org Cc: bpf@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH bpf-next v10 2/8] bpf: clear list node owner and unlink before drop Date: Tue, 28 Apr 2026 00:59:00 +0800 Message-ID: <20260427165906.84420-3-kaitao.cheng@linux.dev> In-Reply-To: <20260427165906.84420-1-kaitao.cheng@linux.dev> References: <20260427165906.84420-1-kaitao.cheng@linux.dev> 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 X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Kaitao Cheng When draining a BPF list_head, clear each node's owner pointer while still holding the spinlock, so concurrent readers always see a consistent owner. Delink each node with list_del_init() before calling __bpf_obj_drop_impl(), preventing subsequent users who hold a reference count to the node from acquiring an invalid next node. Signed-off-by: Kaitao Cheng --- kernel/bpf/helpers.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 9cd7b028592c..1e8754877dd1 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -2247,10 +2247,11 @@ EXPORT_SYMBOL_GPL(bpf_base_func_proto); void bpf_list_head_free(const struct btf_field *field, void *list_head, struct bpf_spin_lock *spin_lock) { - struct list_head *head =3D list_head, *orig_head =3D list_head; + struct list_head *head =3D list_head, drain, *pos, *n; =20 BUILD_BUG_ON(sizeof(struct list_head) > sizeof(struct bpf_list_head)); BUILD_BUG_ON(__alignof__(struct list_head) > __alignof__(struct bpf_list_= head)); + INIT_LIST_HEAD(&drain); =20 /* Do the actual list draining outside the lock to not hold the lock for * too long, and also prevent deadlocks if tracing programs end up @@ -2261,20 +2262,23 @@ void bpf_list_head_free(const struct btf_field *fie= ld, void *list_head, __bpf_spin_lock_irqsave(spin_lock); if (!head->next || list_empty(head)) goto unlock; - head =3D head->next; + list_for_each_safe(pos, n, head) { + WRITE_ONCE(container_of(pos, + struct bpf_list_node_kern, list_head)->owner, NULL); + list_move_tail(pos, &drain); + } unlock: - INIT_LIST_HEAD(orig_head); + INIT_LIST_HEAD(head); __bpf_spin_unlock_irqrestore(spin_lock); =20 - while (head !=3D orig_head) { - void *obj =3D head; - - obj -=3D field->graph_root.node_offset; - head =3D head->next; + while (!list_empty(&drain)) { + pos =3D drain.next; + list_del_init(pos); /* The contained type can also have resources, including a * bpf_list_head which needs to be freed. */ - __bpf_obj_drop_impl(obj, field->graph_root.value_rec, false); + __bpf_obj_drop_impl((char *)pos - field->graph_root.node_offset, + field->graph_root.value_rec, false); } } =20 --=20 2.50.1 (Apple Git-155) From nobody Wed Jun 17 06:02:58 2026 Received: from out-170.mta1.migadu.com (out-170.mta1.migadu.com [95.215.58.170]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B5EE83DA7F5 for ; Mon, 27 Apr 2026 16:59:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.170 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777309178; cv=none; b=Z3vK4YwaXoBMbGHRq4XJ2WecDgTmvQVKC2dt6OKZh1pSPYnC7mH0dbYZs9TS3ACzUAq8G+aoh8R1rQhAwhFrHp00zx58vItXOE8OSVIaFsh4Rw/+5XHBzIZ+PygwdS5Wj2M6QF8vQVjYKjTvNiPVk1vrye+JEdiB7/wtkZ0/Ml8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777309178; c=relaxed/simple; bh=anDkAin6bRlzRMPVlynK7/7TJNEy5a/mdefQRK4EtCw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=aMqc6j75uSAuXhTFOwwC2Ba3jb32VyLWwXb6zsjeTcx3Rx4oR3ocRG+ZCTyIq9JyQSc1abUFJWesrRpgmL+PXe98eahqFIfvUbolCq7/5w+62pddzJ1ejU5/pGV+sja3csRnFtz6LD5urXNHj+cjSA3+Lv+WDk35zWjqHQKT3Pc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=GGXHLS5T; arc=none smtp.client-ip=95.215.58.170 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="GGXHLS5T" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1777309172; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=sfDNacsy6+YXnBjKQmcVLo7bpaOxccX77oa8AMBMhws=; b=GGXHLS5TXucOhrenOIYkaGeOMCXp4O5iJufAwYC0x0xTZGdim/TGxbsJsknemUBVkzjqJ8 kNkqvyorx3bYF51SMuDM8PTgMKzw/Trbn3VEkRoWApDvaMHXZA45kYpuJ18EUEBkRUGI/q 9mbUKi5XudTuWjG1Qn18AWohvNilr2w= From: Kaitao cheng To: martin.lau@linux.dev, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, eddyz87@gmail.com, song@kernel.org, yonghong.song@linux.dev, john.fastabend@gmail.com, kpsingh@kernel.org, sdf@fomichev.me, haoluo@google.com, jolsa@kernel.org, shuah@kernel.org, chengkaitao@kylinos.cn, linux-kselftest@vger.kernel.org Cc: bpf@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH bpf-next v10 3/8] bpf: Introduce the bpf_list_del kfunc. Date: Tue, 28 Apr 2026 00:59:01 +0800 Message-ID: <20260427165906.84420-4-kaitao.cheng@linux.dev> In-Reply-To: <20260427165906.84420-1-kaitao.cheng@linux.dev> References: <20260427165906.84420-1-kaitao.cheng@linux.dev> 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 X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Kaitao Cheng Allow users to remove any node from a linked list. We have added an additional parameter bpf_list_head *head to bpf_list_del, as the verifier requires the head parameter to check whether the lock is being held. Signed-off-by: Kaitao Cheng --- kernel/bpf/helpers.c | 10 ++++++++++ kernel/bpf/verifier.c | 6 +++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 1e8754877dd1..51b6ea4bb8cb 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -2593,6 +2593,15 @@ __bpf_kfunc struct bpf_list_node *bpf_list_pop_back(= struct bpf_list_head *head) return __bpf_list_del(head, h->prev); } =20 +__bpf_kfunc struct bpf_list_node *bpf_list_del(struct bpf_list_head *head, + struct bpf_list_node *node) +{ + struct bpf_list_node_kern *kn =3D (void *)node; + + /* verifier guarantees node is a list node rather than list head */ + return __bpf_list_del(head, &kn->list_head); +} + __bpf_kfunc struct bpf_list_node *bpf_list_front(struct bpf_list_head *hea= d) { struct list_head *h =3D (struct list_head *)head; @@ -4725,6 +4734,7 @@ BTF_ID_FLAGS(func, bpf_list_push_back, KF_IMPLICIT_AR= GS) BTF_ID_FLAGS(func, bpf_list_push_back_impl) BTF_ID_FLAGS(func, bpf_list_pop_front, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_list_pop_back, KF_ACQUIRE | KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_list_del, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_list_front, KF_RET_NULL) BTF_ID_FLAGS(func, bpf_list_back, KF_RET_NULL) BTF_ID_FLAGS(func, bpf_task_acquire, KF_ACQUIRE | KF_RCU | KF_RET_NULL) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 03f9e16c2abe..3c0e0076bd69 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -10744,6 +10744,7 @@ enum special_kfunc_type { KF_bpf_list_push_back, KF_bpf_list_pop_front, KF_bpf_list_pop_back, + KF_bpf_list_del, KF_bpf_list_front, KF_bpf_list_back, KF_bpf_cast_to_kern_ctx, @@ -10812,6 +10813,7 @@ BTF_ID(func, bpf_list_push_back_impl) BTF_ID(func, bpf_list_push_back) BTF_ID(func, bpf_list_pop_front) BTF_ID(func, bpf_list_pop_back) +BTF_ID(func, bpf_list_del) BTF_ID(func, bpf_list_front) BTF_ID(func, bpf_list_back) BTF_ID(func, bpf_cast_to_kern_ctx) @@ -11334,6 +11336,7 @@ static bool is_bpf_list_api_kfunc(u32 btf_id) return is_bpf_list_push_kfunc(btf_id) || btf_id =3D=3D special_kfunc_list[KF_bpf_list_pop_front] || btf_id =3D=3D special_kfunc_list[KF_bpf_list_pop_back] || + btf_id =3D=3D special_kfunc_list[KF_bpf_list_del] || btf_id =3D=3D special_kfunc_list[KF_bpf_list_front] || btf_id =3D=3D special_kfunc_list[KF_bpf_list_back]; } @@ -11456,7 +11459,8 @@ static bool check_kfunc_is_graph_node_api(struct bp= f_verifier_env *env, =20 switch (node_field_type) { case BPF_LIST_NODE: - ret =3D is_bpf_list_push_kfunc(kfunc_btf_id); + ret =3D is_bpf_list_push_kfunc(kfunc_btf_id) || + kfunc_btf_id =3D=3D special_kfunc_list[KF_bpf_list_del]; break; case BPF_RB_NODE: ret =3D (is_bpf_rbtree_add_kfunc(kfunc_btf_id) || --=20 2.50.1 (Apple Git-155) From nobody Wed Jun 17 06:02:58 2026 Received: from out-170.mta1.migadu.com (out-170.mta1.migadu.com [95.215.58.170]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 708023CB2F0 for ; Mon, 27 Apr 2026 16:59:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.170 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777309184; cv=none; b=GpXRp3bwz+cLpAOakz1l/ji6dYIHPFY6VIRQqmEDFBdQTAmsjGqCuqJx322FSqIIX8YMM12+EmOc1yTmi8dgnNCl1jzMS8QUgpjwRN20GwuZpV86lWe9QysTQSuSoBwaqPmm6Wd6PSC7WEilbQSCyVsKJDTGBvDaYudadAgsZOw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777309184; c=relaxed/simple; bh=/muV6dCbtwkyaf+jEkinQUctflZqYwvGPQ4RwozJAdA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=i6q8bqsCj+dBOSHo2uG24kyR6XmKb0gJFrwOEDOMk9NXngc6jg9gOdMH18v0c1UnjYWHc1adj7YFyvlrik9P1G4ZyNRsPtBaevYfXTN+0mwLlsFjTfz+k4Cp5AuUQyt+xAFdArEata0/Lmt2vNE+/BmwNQL1HzhEUid1x75D4yQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=oDVD3+3s; arc=none smtp.client-ip=95.215.58.170 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="oDVD3+3s" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1777309177; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=qshHdS20MoOXvQLCKPvaR8JOP07zv3n46ucSvb4Lric=; b=oDVD3+3smQUJcS9Dsi6HZWdQcNHa9nZ0Vwe/QhgM28uKbXkzNDuaXnFBeELRKTjIkiOTnX DRQpk8wUrLAti/t/OdinrdeHQZEnDd79LUgVteIqGU2dZo7tT3tkRXU+bjJ9oUBWoSqaLF GV0/30NGQsg4cBxxP+6D8/7PxgCfojo= From: Kaitao cheng To: martin.lau@linux.dev, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, eddyz87@gmail.com, song@kernel.org, yonghong.song@linux.dev, john.fastabend@gmail.com, kpsingh@kernel.org, sdf@fomichev.me, haoluo@google.com, jolsa@kernel.org, shuah@kernel.org, chengkaitao@kylinos.cn, linux-kselftest@vger.kernel.org Cc: bpf@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH bpf-next v10 4/8] bpf: refactor __bpf_list_add to take insertion point via **prev_ptr Date: Tue, 28 Apr 2026 00:59:02 +0800 Message-ID: <20260427165906.84420-5-kaitao.cheng@linux.dev> In-Reply-To: <20260427165906.84420-1-kaitao.cheng@linux.dev> References: <20260427165906.84420-1-kaitao.cheng@linux.dev> 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 X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Kaitao Cheng Refactor __bpf_list_add to accept (node, head, struct list_head **prev_ptr, ..) instead of (node, head, bool tail, ..). Load prev from *prev_ptr after INIT_LIST_HEAD(h), so we never dereference an uninitialized h->prev when head was 0-initialized (e.g. push_back passes &h->prev). When prev is not the list head, validate that prev is in the list via its owner. Prepares for bpf_list_add(head, new, prev, ..) to insert after a given list node. Signed-off-by: Kaitao Cheng --- kernel/bpf/helpers.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 51b6ea4bb8cb..5388078f3171 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -2471,9 +2471,11 @@ __bpf_kfunc void *bpf_refcount_acquire_impl(void *p_= _refcounted_kptr, void *meta =20 static int __bpf_list_add(struct bpf_list_node_kern *node, struct bpf_list_head *head, - bool tail, struct btf_record *rec, u64 off) + struct list_head **prev_ptr, + struct btf_record *rec, u64 off) { struct list_head *n =3D &node->list_head, *h =3D (void *)head; + struct list_head *prev; =20 /* If list_head was 0-initialized by map, bpf_obj_init_field wasn't * called on its fields, so init here @@ -2481,19 +2483,31 @@ static int __bpf_list_add(struct bpf_list_node_kern= *node, if (unlikely(!h->next)) INIT_LIST_HEAD(h); =20 + prev =3D *prev_ptr; + + /* When prev is not the list head, it must be a node in this list. */ + if (prev !=3D h) { + struct bpf_list_node_kern *prev_kn =3D + container_of(prev, struct bpf_list_node_kern, list_head); + + if (unlikely(READ_ONCE(prev_kn->owner) !=3D head)) + goto fail; + } + /* node->owner !=3D NULL implies !list_empty(n), no need to separately * check the latter */ - if (cmpxchg(&node->owner, NULL, BPF_PTR_POISON)) { - /* Only called from BPF prog, no need to migrate_disable */ - __bpf_obj_drop_impl((void *)n - off, rec, false); - return -EINVAL; - } + if (cmpxchg(&node->owner, NULL, BPF_PTR_POISON)) + goto fail; =20 - tail ? list_add_tail(n, h) : list_add(n, h); + list_add(n, prev); WRITE_ONCE(node->owner, head); - return 0; + +fail: + /* Only called from BPF prog, no need to migrate_disable */ + __bpf_obj_drop_impl((void *)n - off, rec, false); + return -EINVAL; } =20 /** @@ -2514,8 +2528,9 @@ __bpf_kfunc int bpf_list_push_front(struct bpf_list_h= ead *head, u64 off) { struct bpf_list_node_kern *n =3D (void *)node; + struct list_head *h =3D (void *)head; =20 - return __bpf_list_add(n, head, false, meta ? meta->record : NULL, off); + return __bpf_list_add(n, head, &h, meta ? meta->record : NULL, off); } =20 __bpf_kfunc int bpf_list_push_front_impl(struct bpf_list_head *head, @@ -2543,8 +2558,9 @@ __bpf_kfunc int bpf_list_push_back(struct bpf_list_he= ad *head, u64 off) { struct bpf_list_node_kern *n =3D (void *)node; + struct list_head *h =3D (void *)head; =20 - return __bpf_list_add(n, head, true, meta ? meta->record : NULL, off); + return __bpf_list_add(n, head, &h->prev, meta ? meta->record : NULL, off); } =20 __bpf_kfunc int bpf_list_push_back_impl(struct bpf_list_head *head, --=20 2.50.1 (Apple Git-155) From nobody Wed Jun 17 06:02:58 2026 Received: from out-179.mta1.migadu.com (out-179.mta1.migadu.com [95.215.58.179]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ABCE83BC696 for ; Mon, 27 Apr 2026 16:59:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777309185; cv=none; b=sNoGaEx76FT9E75VJBFWhnr7QUwQbTFJe1XY0uWYb+fZrNk1mwNh8iJoZtZP94jz8x75yE9tSULEhpXH5tAEtBuJ/0U3e2kAstgOCb+vp6Yq6OAnB432lK+ydxu9LpTNj5mJtxvdBrqWIAqlcOMa8rRzx3b+Dhqr8yQjuPm0haQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777309185; c=relaxed/simple; bh=5p64GKPG5304730wA3md9aMwwm3p5LHhf4Lb7/Btios=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LdG5lVqJuXUbWObOU4Yty13z1HaVwZsuDQmuJ/faVGD8b8DwF4t7RkGOXnbENgoTH04DQOY0rSV9BhTim3O/roirqqhRMXzBbT59xzlN+ou2A2Axc3ooQPZDfWcUsWNdlJqJVXGrKWn12cv8BdKkALYY6nGUszvreOx7SLH/If8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=TRFj+ha2; arc=none smtp.client-ip=95.215.58.179 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="TRFj+ha2" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1777309181; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=WUwkb+rVEVAyaI4tzJled16qKyxWqmXsFV4GgQBJAAI=; b=TRFj+ha29nxtVqf7G/L8eEaL09U0MEa+C+ZEDa8LIaPMNHYFmkFSQq5gdjVPzt/5F0b0wm qqZyDDeBuivb8yssrWGkcEBAL78BbDyXUTGvCf0qHGhmb5qMbSmHuKti8oAycs/EKGNO0M foFtFwg1ky5b+kxjMZnrtwFqP60qQoo= From: Kaitao cheng To: martin.lau@linux.dev, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, eddyz87@gmail.com, song@kernel.org, yonghong.song@linux.dev, john.fastabend@gmail.com, kpsingh@kernel.org, sdf@fomichev.me, haoluo@google.com, jolsa@kernel.org, shuah@kernel.org, chengkaitao@kylinos.cn, linux-kselftest@vger.kernel.org Cc: bpf@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH bpf-next v10 5/8] bpf: Add bpf_list_add to insert node after a given list node Date: Tue, 28 Apr 2026 00:59:03 +0800 Message-ID: <20260427165906.84420-6-kaitao.cheng@linux.dev> In-Reply-To: <20260427165906.84420-1-kaitao.cheng@linux.dev> References: <20260427165906.84420-1-kaitao.cheng@linux.dev> 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 X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Kaitao Cheng Add a new kfunc bpf_list_add(head, new, prev, meta, off) that inserts 'new' after 'prev' in the BPF linked list. Both must be in the same list; 'prev' must already be in the list. The new node must be an owning reference (e.g. from bpf_obj_new); the kfunc consumes that reference and the node becomes non-owning once inserted. We have added an additional parameter bpf_list_head *head to bpf_list_add, as the verifier requires the head parameter to check whether the lock is being held. Returns 0 on success, -EINVAL if 'prev' is not in a list or 'new' is already in a list (or duplicate insertion). On failure, the kernel drops the passed-in node. Signed-off-by: Kaitao Cheng --- kernel/bpf/helpers.c | 11 +++++++++++ kernel/bpf/verifier.c | 12 +++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 5388078f3171..2b8e8d4284a5 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -2570,6 +2570,16 @@ __bpf_kfunc int bpf_list_push_back_impl(struct bpf_l= ist_head *head, return bpf_list_push_back(head, node, meta__ign, off); } =20 +__bpf_kfunc int bpf_list_add(struct bpf_list_head *head, struct bpf_list_n= ode *new, + struct bpf_list_node *prev, struct btf_struct_meta *meta, + u64 off) +{ + struct bpf_list_node_kern *n =3D (void *)new, *p =3D (void *)prev; + struct list_head *prev_ptr =3D &p->list_head; + + return __bpf_list_add(n, head, &prev_ptr, meta ? meta->record : NULL, off= ); +} + static struct bpf_list_node *__bpf_list_del(struct bpf_list_head *head, struct list_head *n) { @@ -4748,6 +4758,7 @@ BTF_ID_FLAGS(func, bpf_list_push_front, KF_IMPLICIT_A= RGS) BTF_ID_FLAGS(func, bpf_list_push_front_impl) BTF_ID_FLAGS(func, bpf_list_push_back, KF_IMPLICIT_ARGS) BTF_ID_FLAGS(func, bpf_list_push_back_impl) +BTF_ID_FLAGS(func, bpf_list_add, KF_IMPLICIT_ARGS) BTF_ID_FLAGS(func, bpf_list_pop_front, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_list_pop_back, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_list_del, KF_ACQUIRE | KF_RET_NULL) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 3c0e0076bd69..50f8732aa065 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -10742,6 +10742,7 @@ enum special_kfunc_type { KF_bpf_list_push_front, KF_bpf_list_push_back_impl, KF_bpf_list_push_back, + KF_bpf_list_add, KF_bpf_list_pop_front, KF_bpf_list_pop_back, KF_bpf_list_del, @@ -10811,6 +10812,7 @@ BTF_ID(func, bpf_list_push_front_impl) BTF_ID(func, bpf_list_push_front) BTF_ID(func, bpf_list_push_back_impl) BTF_ID(func, bpf_list_push_back) +BTF_ID(func, bpf_list_add) BTF_ID(func, bpf_list_pop_front) BTF_ID(func, bpf_list_pop_back) BTF_ID(func, bpf_list_del) @@ -10923,7 +10925,8 @@ static bool is_bpf_list_push_kfunc(u32 func_id) return func_id =3D=3D special_kfunc_list[KF_bpf_list_push_front] || func_id =3D=3D special_kfunc_list[KF_bpf_list_push_front_impl] || func_id =3D=3D special_kfunc_list[KF_bpf_list_push_back] || - func_id =3D=3D special_kfunc_list[KF_bpf_list_push_back_impl]; + func_id =3D=3D special_kfunc_list[KF_bpf_list_push_back_impl] || + func_id =3D=3D special_kfunc_list[KF_bpf_list_add]; } =20 static bool is_bpf_rbtree_add_kfunc(u32 func_id) @@ -19228,8 +19231,11 @@ int bpf_fixup_kfunc_call(struct bpf_verifier_env *= env, struct bpf_insn *insn, int struct_meta_reg =3D BPF_REG_3; int node_offset_reg =3D BPF_REG_4; =20 - /* rbtree_add has extra 'less' arg, so args-to-fixup are in diff regs */ - if (is_bpf_rbtree_add_kfunc(desc->func_id)) { + /* list_add/rbtree_add have an extra arg (prev/less), + * so args-to-fixup are in diff regs. + */ + if (desc->func_id =3D=3D special_kfunc_list[KF_bpf_list_add] || + is_bpf_rbtree_add_kfunc(desc->func_id)) { struct_meta_reg =3D BPF_REG_4; node_offset_reg =3D BPF_REG_5; } --=20 2.50.1 (Apple Git-155) From nobody Wed Jun 17 06:02:58 2026 Received: from out-188.mta1.migadu.com (out-188.mta1.migadu.com [95.215.58.188]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5C46E3DA7C8 for ; Mon, 27 Apr 2026 16:59:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.188 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777309192; cv=none; b=ZLWWpenBT2TRCR5PxsLnkSGiyg/0PjwZhtjkeHQ/SuwsJKjFjBxYvytGcuR0L5LNVCmNkYg4hdek97m1KuH2XrVz7fZSBg8EIlbyAzjgMX2hSsskMcucL730S4ouq5r+TLi/RIi+BYBdsgBMmojPYGRP6qAq9lCNnmbE/xZ+O10= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777309192; c=relaxed/simple; bh=BE+YmEUt2JlQE2gs3eOXXlXi3+oQVNhffbC4hhexUgQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=h6FbpptKJKl2h22ixyZH+AELBYeJ0QwS4acQSbWZXhcekyf6a5XI/3gWKdy25AyDZQJ/KZgos9niaMNHYoXAu4WWNfOx4ZNHe5G7Y3T0pf58+obfiRBtiRuwlc2setUPY+O5usxLkYhcdmQ6rOUmo9Fr2Yt8kBMQ2WJ/Hzi3P4c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=v+Js1ZIU; arc=none smtp.client-ip=95.215.58.188 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="v+Js1ZIU" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1777309186; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=viZAzy5wHOfBg6qG2TFSvCcCTYkJmVz3UMaSUgtttXI=; b=v+Js1ZIU6dgWgcYF0AbcNUswMfAmhoR8CwW+w0IbPgvSun0ROh9IUOmxc7jMMCaGEyQxed vbSeEZpurvIjMTG3Y1BVo0Enczv2WdVyxu5qCddNuwF83QXuB5+N29Gx77TCsrqXE6CGc8 38Nk3h+cWIpaWNsn4l0k3AEGuHsVxgs= From: Kaitao cheng To: martin.lau@linux.dev, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, eddyz87@gmail.com, song@kernel.org, yonghong.song@linux.dev, john.fastabend@gmail.com, kpsingh@kernel.org, sdf@fomichev.me, haoluo@google.com, jolsa@kernel.org, shuah@kernel.org, chengkaitao@kylinos.cn, linux-kselftest@vger.kernel.org Cc: bpf@vger.kernel.org, linux-kernel@vger.kernel.org, Emil Tsalapatis Subject: [PATCH bpf-next v10 6/8] bpf: add bpf_list_is_first/last/empty kfuncs Date: Tue, 28 Apr 2026 00:59:04 +0800 Message-ID: <20260427165906.84420-7-kaitao.cheng@linux.dev> In-Reply-To: <20260427165906.84420-1-kaitao.cheng@linux.dev> References: <20260427165906.84420-1-kaitao.cheng@linux.dev> 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 X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Kaitao Cheng Add three kfuncs for BPF linked list queries: - bpf_list_is_first(head, node): true if node is the first in the list. - bpf_list_is_last(head, node): true if node is the last in the list. - bpf_list_empty(head): true if the list has no entries. Currently, without these kfuncs, to implement the above functionality it is necessary to first call bpf_list_pop_front/back to retrieve the first or last node before checking whether the passed-in node was the first or last one. After the check, the node had to be pushed back into the list using bpf_list_push_front/back, which was very inefficient. Now, with the bpf_list_is_first/last/empty kfuncs, we can directly check whether a node is the first, last, or whether the list is empty, without having to first retrieve the node. Signed-off-by: Kaitao Cheng Reviewed-by: Emil Tsalapatis --- kernel/bpf/helpers.c | 38 ++++++++++++++++++++++++++++++++++++++ kernel/bpf/verifier.c | 15 +++++++++++++-- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 2b8e8d4284a5..dfd465badd9d 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -2648,6 +2648,41 @@ __bpf_kfunc struct bpf_list_node *bpf_list_back(stru= ct bpf_list_head *head) return (struct bpf_list_node *)h->prev; } =20 +__bpf_kfunc bool bpf_list_is_first(struct bpf_list_head *head, struct bpf_= list_node *node) +{ + struct list_head *h =3D (struct list_head *)head; + struct bpf_list_node_kern *kn =3D (struct bpf_list_node_kern *)node; + + if (READ_ONCE(kn->owner) !=3D head) + return false; + + return list_is_first(&kn->list_head, h); +} + +__bpf_kfunc bool bpf_list_is_last(struct bpf_list_head *head, struct bpf_l= ist_node *node) +{ + struct list_head *h =3D (struct list_head *)head; + struct bpf_list_node_kern *kn =3D (struct bpf_list_node_kern *)node; + + if (READ_ONCE(kn->owner) !=3D head) + return false; + + return list_is_last(&kn->list_head, h); +} + +__bpf_kfunc bool bpf_list_empty(struct bpf_list_head *head) +{ + struct list_head *h =3D (struct list_head *)head; + + /* If list_head was 0-initialized by map, bpf_obj_init_field wasn't + * called on its fields, so init here + */ + if (unlikely(!h->next)) + INIT_LIST_HEAD(h); + + return list_empty(h); +} + __bpf_kfunc struct bpf_rb_node *bpf_rbtree_remove(struct bpf_rb_root *root, struct bpf_rb_node *node) { @@ -4764,6 +4799,9 @@ BTF_ID_FLAGS(func, bpf_list_pop_back, KF_ACQUIRE | KF= _RET_NULL) BTF_ID_FLAGS(func, bpf_list_del, KF_ACQUIRE | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_list_front, KF_RET_NULL) BTF_ID_FLAGS(func, bpf_list_back, KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_list_is_first) +BTF_ID_FLAGS(func, bpf_list_is_last) +BTF_ID_FLAGS(func, bpf_list_empty) BTF_ID_FLAGS(func, bpf_task_acquire, KF_ACQUIRE | KF_RCU | KF_RET_NULL) BTF_ID_FLAGS(func, bpf_task_release, KF_RELEASE) BTF_ID_FLAGS(func, bpf_rbtree_remove, KF_ACQUIRE | KF_RET_NULL) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 50f8732aa065..ca33f35bc3eb 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -10748,6 +10748,9 @@ enum special_kfunc_type { KF_bpf_list_del, KF_bpf_list_front, KF_bpf_list_back, + KF_bpf_list_is_first, + KF_bpf_list_is_last, + KF_bpf_list_empty, KF_bpf_cast_to_kern_ctx, KF_bpf_rdonly_cast, KF_bpf_rcu_read_lock, @@ -10818,6 +10821,9 @@ BTF_ID(func, bpf_list_pop_back) BTF_ID(func, bpf_list_del) BTF_ID(func, bpf_list_front) BTF_ID(func, bpf_list_back) +BTF_ID(func, bpf_list_is_first) +BTF_ID(func, bpf_list_is_last) +BTF_ID(func, bpf_list_empty) BTF_ID(func, bpf_cast_to_kern_ctx) BTF_ID(func, bpf_rdonly_cast) BTF_ID(func, bpf_rcu_read_lock) @@ -11341,7 +11347,10 @@ static bool is_bpf_list_api_kfunc(u32 btf_id) btf_id =3D=3D special_kfunc_list[KF_bpf_list_pop_back] || btf_id =3D=3D special_kfunc_list[KF_bpf_list_del] || btf_id =3D=3D special_kfunc_list[KF_bpf_list_front] || - btf_id =3D=3D special_kfunc_list[KF_bpf_list_back]; + btf_id =3D=3D special_kfunc_list[KF_bpf_list_back] || + btf_id =3D=3D special_kfunc_list[KF_bpf_list_is_first] || + btf_id =3D=3D special_kfunc_list[KF_bpf_list_is_last] || + btf_id =3D=3D special_kfunc_list[KF_bpf_list_empty]; } =20 static bool is_bpf_rbtree_api_kfunc(u32 btf_id) @@ -11463,7 +11472,9 @@ static bool check_kfunc_is_graph_node_api(struct bp= f_verifier_env *env, switch (node_field_type) { case BPF_LIST_NODE: ret =3D is_bpf_list_push_kfunc(kfunc_btf_id) || - kfunc_btf_id =3D=3D special_kfunc_list[KF_bpf_list_del]; + kfunc_btf_id =3D=3D special_kfunc_list[KF_bpf_list_del] || + kfunc_btf_id =3D=3D special_kfunc_list[KF_bpf_list_is_first] || + kfunc_btf_id =3D=3D special_kfunc_list[KF_bpf_list_is_last]; break; case BPF_RB_NODE: ret =3D (is_bpf_rbtree_add_kfunc(kfunc_btf_id) || --=20 2.50.1 (Apple Git-155) From nobody Wed Jun 17 06:02:58 2026 Received: from out-170.mta1.migadu.com (out-170.mta1.migadu.com [95.215.58.170]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D74E53DA7DF for ; Mon, 27 Apr 2026 16:59:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.170 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777309197; cv=none; b=ckg+LR9pBwTIylgnC9iPMOg5YlkikSwEz0fxuq9oHuo140Eyglhx3AwLbiUrPsdrLUSWRPcPd9ZLMxZUA4JJVIc1gCBNgC0tAo/SRFw6q+OwFgu8CGh61iKdAMZzC9nwkfnmxzIU5XpgXjORtQOf8H2fWuKOu6bAA3mzkytCYKs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777309197; c=relaxed/simple; bh=3/dhJ8s/gTLp5FfI4tzFmnbnLZHdbFW3dNsyriiTHY4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=MJvXa3KUoV+lkXLXMAOYcOC34cnbDBV8bj7eVmMASInFrDcN9ff0OybPoQ5x2//o26Y1Vg7TPk1M8xWVwmadojJ7lA9JAKTkhRtYDTovkZQJsMSw/Q0RL6Izvpubm71h5D5JWrMyYl5fCSd77ne9nBBO9fyezqaxxyCa/nm2ekA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=ugsZeunf; arc=none smtp.client-ip=95.215.58.170 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="ugsZeunf" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1777309191; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=l40L11oPsTEKSxgVhQkbOKoDGaw16jzWQ7998spksOs=; b=ugsZeunfRcjM5dEFHrzb6qVR/jNpprj1fTtKN5JZXkTxbcqK6psEfn0qNboXh21AKaWGJN JIpJTNJLCgf6/dx3BgWWT2khdXwpayc5dN5TR4dueYSC30jXR3ufmHq8/zVR4dBJc8ibdw akd2XK38mCL3FvmFxmOeNj3iQ3dHmz4= From: Kaitao cheng To: martin.lau@linux.dev, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, eddyz87@gmail.com, song@kernel.org, yonghong.song@linux.dev, john.fastabend@gmail.com, kpsingh@kernel.org, sdf@fomichev.me, haoluo@google.com, jolsa@kernel.org, shuah@kernel.org, chengkaitao@kylinos.cn, linux-kselftest@vger.kernel.org Cc: bpf@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH bpf-next v10 7/8] bpf: allow non-owning list-node args via __nonown_allowed Date: Tue, 28 Apr 2026 00:59:05 +0800 Message-ID: <20260427165906.84420-8-kaitao.cheng@linux.dev> In-Reply-To: <20260427165906.84420-1-kaitao.cheng@linux.dev> References: <20260427165906.84420-1-kaitao.cheng@linux.dev> 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 X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Kaitao Cheng KF_ARG_PTR_TO_LIST_NODE normally requires an owning reference (PTR_TO_BTF_ID | MEM_ALLOC with ref_obj_id). Introduce and use the __nonown_allowed annotation on selected list-node arguments so non-owning references with ref_obj_id=3D=3D0 are accepted as well. This enables passing bpf_list_front() / bpf_list_back() results to: bpf_list_add() as insertion point (prev) bpf_list_del() as deletion target (node) bpf_list_is_first/last() as query target (node) Verifier keeps existing owning-ref checks by default; only arguments annotated with __nonown_allowed bypass MEM_ALLOC/ref_obj_id checks and then follow the same list-node validation path. Signed-off-by: Kaitao Cheng --- Documentation/bpf/kfuncs.rst | 22 ++++++++++++++++++++-- kernel/bpf/helpers.c | 20 +++++++++++--------- kernel/bpf/verifier.c | 13 +++++++++++++ 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/Documentation/bpf/kfuncs.rst b/Documentation/bpf/kfuncs.rst index 75e6c078e0e7..3a9db1108b95 100644 --- a/Documentation/bpf/kfuncs.rst +++ b/Documentation/bpf/kfuncs.rst @@ -207,8 +207,26 @@ Here, the buffer may be NULL. If the buffer is not NUL= L, it must be at least buffer__szk bytes in size. The kfunc is responsible for checking if the bu= ffer is NULL before using it. =20 -2.3.5 __str Annotation ----------------------------- +2.3.5 __nonown_allowed Annotation +--------------------------------- + +This annotation is used to indicate that the parameter may be a non-owning= reference. + +An example is given below:: + + __bpf_kfunc int bpf_list_add(..., struct bpf_list_node + *prev__nonown_allowed, ...) + { + ... + } + +For the ``prev__nonown_allowed`` parameter (resolved as ``KF_ARG_PTR_TO_LI= ST_NODE``), +suffix ``__nonown_allowed`` retains the usual owning-pointer rules and also +permits a non-owning reference with no ref_obj_id (e.g. the return value of +bpf_list_front() / bpf_list_back()). + +2.3.6 __str Annotation +---------------------- This annotation is used to indicate that the argument is a constant string. =20 An example is given below:: diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index dfd465badd9d..f2f8705f0e9a 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -2571,10 +2571,10 @@ __bpf_kfunc int bpf_list_push_back_impl(struct bpf_= list_head *head, } =20 __bpf_kfunc int bpf_list_add(struct bpf_list_head *head, struct bpf_list_n= ode *new, - struct bpf_list_node *prev, struct btf_struct_meta *meta, - u64 off) + struct bpf_list_node *prev__nonown_allowed, + struct btf_struct_meta *meta, u64 off) { - struct bpf_list_node_kern *n =3D (void *)new, *p =3D (void *)prev; + struct bpf_list_node_kern *n =3D (void *)new, *p =3D (void *)prev__nonown= _allowed; struct list_head *prev_ptr =3D &p->list_head; =20 return __bpf_list_add(n, head, &prev_ptr, meta ? meta->record : NULL, off= ); @@ -2620,9 +2620,9 @@ __bpf_kfunc struct bpf_list_node *bpf_list_pop_back(s= truct bpf_list_head *head) } =20 __bpf_kfunc struct bpf_list_node *bpf_list_del(struct bpf_list_head *head, - struct bpf_list_node *node) + struct bpf_list_node *node__nonown_allowed) { - struct bpf_list_node_kern *kn =3D (void *)node; + struct bpf_list_node_kern *kn =3D (void *)node__nonown_allowed; =20 /* verifier guarantees node is a list node rather than list head */ return __bpf_list_del(head, &kn->list_head); @@ -2648,10 +2648,11 @@ __bpf_kfunc struct bpf_list_node *bpf_list_back(str= uct bpf_list_head *head) return (struct bpf_list_node *)h->prev; } =20 -__bpf_kfunc bool bpf_list_is_first(struct bpf_list_head *head, struct bpf_= list_node *node) +__bpf_kfunc bool bpf_list_is_first(struct bpf_list_head *head, + struct bpf_list_node *node__nonown_allowed) { struct list_head *h =3D (struct list_head *)head; - struct bpf_list_node_kern *kn =3D (struct bpf_list_node_kern *)node; + struct bpf_list_node_kern *kn =3D (struct bpf_list_node_kern *)node__nono= wn_allowed; =20 if (READ_ONCE(kn->owner) !=3D head) return false; @@ -2659,10 +2660,11 @@ __bpf_kfunc bool bpf_list_is_first(struct bpf_list_= head *head, struct bpf_list_n return list_is_first(&kn->list_head, h); } =20 -__bpf_kfunc bool bpf_list_is_last(struct bpf_list_head *head, struct bpf_l= ist_node *node) +__bpf_kfunc bool bpf_list_is_last(struct bpf_list_head *head, + struct bpf_list_node *node__nonown_allowed) { struct list_head *h =3D (struct list_head *)head; - struct bpf_list_node_kern *kn =3D (struct bpf_list_node_kern *)node; + struct bpf_list_node_kern *kn =3D (struct bpf_list_node_kern *)node__nono= wn_allowed; =20 if (READ_ONCE(kn->owner) !=3D head) return false; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index ca33f35bc3eb..08ab337866bf 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -10502,6 +10502,11 @@ static bool is_kfunc_arg_nullable(const struct btf= *btf, const struct btf_param return btf_param_match_suffix(btf, arg, "__nullable"); } =20 +static bool is_kfunc_arg_nonown_allowed(const struct btf *btf, const struc= t btf_param *arg) +{ + return btf_param_match_suffix(btf, arg, "__nonown_allowed"); +} + static bool is_kfunc_arg_const_str(const struct btf *btf, const struct btf= _param *arg) { return btf_param_match_suffix(btf, arg, "__str"); @@ -12017,6 +12022,13 @@ static int check_kfunc_args(struct bpf_verifier_en= v *env, struct bpf_kfunc_call_ return ret; break; case KF_ARG_PTR_TO_LIST_NODE: + if (is_kfunc_arg_nonown_allowed(btf, &args[i]) && + type_is_non_owning_ref(reg->type) && !reg->ref_obj_id) { + /* Allow bpf_list_front/back return value for + * __nonown_allowed list-node arguments. + */ + goto check_ok; + } if (reg->type !=3D (PTR_TO_BTF_ID | MEM_ALLOC)) { verbose(env, "%s expected pointer to allocated object\n", reg_arg_name(env, argno)); @@ -12026,6 +12038,7 @@ static int check_kfunc_args(struct bpf_verifier_env= *env, struct bpf_kfunc_call_ verbose(env, "allocated object must be referenced\n"); return -EINVAL; } +check_ok: ret =3D process_kf_arg_ptr_to_list_node(env, reg, argno, meta); if (ret < 0) return ret; --=20 2.50.1 (Apple Git-155) From nobody Wed Jun 17 06:02:58 2026 Received: from out-174.mta1.migadu.com (out-174.mta1.migadu.com [95.215.58.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F25083DA7F0; Mon, 27 Apr 2026 17:00:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777309204; cv=none; b=MUxwGy1d1TONmDiDThFMIif/oELEgAiJiVmPErKsZLAxpuD/Imky149LpA1T0YPqAwh61mL2Y8V5K0lFPLFP16+vJXHdqTu4w7AvJloQkkzlL/BYjl7FQCMOsNSgQB84SV0IaCX8GPzJMB5t5KLxOIttx8nDac6qPwkLgc+oEe0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777309204; c=relaxed/simple; bh=kRF9RHp407Fxt7W9NCJuN2XXVOJ+iJ65bCFZX7kuqVQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=g3oDmg5mDTWrfIqjpkVC5ImfKuAqlMYrlEVT7lMbF74SANtIU8nEF3WHMmGzIMT+NypvfDsMxoPBcxQ5b6k3Pk2Y5luMCpnyH9kQIEIYKhhlpGEdXcONfUz4Ew5EAlKiNPdf2s+f0g95EoToJPuzeY2XtP3qdSV3JPi6BWwHTCs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=nH4vDO1h; arc=none smtp.client-ip=95.215.58.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="nH4vDO1h" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1777309199; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=MkHpM1vn80llxrmN+R6WT0i6FCnOAAEKA+jHxtvWc3A=; b=nH4vDO1h8VpYG5UF1x80+lRLPJXdwRwPRrM0Lb3EFwR2tTlse8imwin1flc2nuWyJ6tKc8 ST7p1Kzk/D0k3s8hd4Tyng59if9h+xjX7QjV6XeNXVgxmMQWKoTBr4CRXpj74B2lTuSnV7 A5vTK2OGxJccpwpqBsDpVwLPAh8vwtI= From: Kaitao cheng To: martin.lau@linux.dev, ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, eddyz87@gmail.com, song@kernel.org, yonghong.song@linux.dev, john.fastabend@gmail.com, kpsingh@kernel.org, sdf@fomichev.me, haoluo@google.com, jolsa@kernel.org, shuah@kernel.org, chengkaitao@kylinos.cn, linux-kselftest@vger.kernel.org Cc: bpf@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH bpf-next v10 8/8] selftests/bpf: Add test cases for bpf_list_del/add/is_first/is_last/empty Date: Tue, 28 Apr 2026 00:59:06 +0800 Message-ID: <20260427165906.84420-9-kaitao.cheng@linux.dev> In-Reply-To: <20260427165906.84420-1-kaitao.cheng@linux.dev> References: <20260427165906.84420-1-kaitao.cheng@linux.dev> 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 X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Kaitao Cheng Extend refcounted_kptr with tests for bpf_list_add (including prev from bpf_list_front and bpf_refcount_acquire), bpf_list_del (including node from bpf_list_front, bpf_rbtree_remove and bpf_refcount_acquire), bpf_list_empty, bpf_list_is_first/last, and push_back on uninit head. To verify the validity of bpf_list_del/add, the test also expects the verifier to reject calls to bpf_list_del/add made without holding the spin_lock. Signed-off-by: Kaitao Cheng --- .../selftests/bpf/progs/refcounted_kptr.c | 421 ++++++++++++++++++ 1 file changed, 421 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/refcounted_kptr.c b/tools/te= sting/selftests/bpf/progs/refcounted_kptr.c index c847398837cc..21ae06797b18 100644 --- a/tools/testing/selftests/bpf/progs/refcounted_kptr.c +++ b/tools/testing/selftests/bpf/progs/refcounted_kptr.c @@ -367,6 +367,427 @@ long insert_rbtree_and_stash__del_tree_##rem_tree(voi= d *ctx) \ INSERT_STASH_READ(true, "insert_stash_read: remove from tree"); INSERT_STASH_READ(false, "insert_stash_read: don't remove from tree"); =20 +SEC("tc") +__description("list_empty_test: list empty before add, non-empty after add= ") +__success __retval(0) +int list_empty_test(void *ctx) +{ + struct node_data *node_new; + + bpf_spin_lock(&lock); + if (!bpf_list_empty(&head)) { + bpf_spin_unlock(&lock); + return -1; + } + bpf_spin_unlock(&lock); + + node_new =3D bpf_obj_new(typeof(*node_new)); + if (!node_new) + return -2; + + bpf_spin_lock(&lock); + bpf_list_push_front(&head, &node_new->l); + + if (bpf_list_empty(&head)) { + bpf_spin_unlock(&lock); + return -3; + } + bpf_spin_unlock(&lock); + return 0; +} + +static struct node_data *__add_in_list(struct bpf_list_head *head, + struct bpf_spin_lock *lock) +{ + struct node_data *node_new, *node_ref; + + node_new =3D bpf_obj_new(typeof(*node_new)); + if (!node_new) + return NULL; + + node_ref =3D bpf_refcount_acquire(node_new); + + bpf_spin_lock(lock); + bpf_list_push_front(head, &node_new->l); + bpf_spin_unlock(lock); + return node_ref; +} + +SEC("tc") +__description("list_is_edge_test1: is_first on first node, is_last on last= node") +__success __retval(0) +int list_is_edge_test1(void *ctx) +{ + struct node_data *node_first, *node_last; + int err =3D 0; + + node_last =3D __add_in_list(&head, &lock); + if (!node_last) + return -1; + + node_first =3D __add_in_list(&head, &lock); + if (!node_first) { + bpf_obj_drop(node_last); + return -2; + } + + bpf_spin_lock(&lock); + if (!bpf_list_is_first(&head, &node_first->l)) { + err =3D -3; + goto fail; + } + if (!bpf_list_is_last(&head, &node_last->l)) + err =3D -4; + +fail: + bpf_spin_unlock(&lock); + bpf_obj_drop(node_first); + bpf_obj_drop(node_last); + return err; +} + +SEC("tc") +__description("list_is_edge_test2: accept list_front/list_back return valu= e") +__success __retval(0) +int list_is_edge_test2(void *ctx) +{ + struct bpf_list_node *front, *back; + struct node_data *a, *b; + long err =3D 0; + + a =3D __add_in_list(&head, &lock); + if (!a) + return -1; + + b =3D __add_in_list(&head, &lock); + if (!b) { + bpf_obj_drop(a); + return -2; + } + + bpf_spin_lock(&lock); + front =3D bpf_list_front(&head); + back =3D bpf_list_back(&head); + if (!front || !back) { + err =3D -3; + goto out_unlock; + } + + if (!bpf_list_is_first(&head, front) || bpf_list_is_last(&head, front)) { + err =3D -4; + goto out_unlock; + } + + if (!bpf_list_is_last(&head, back) || bpf_list_is_first(&head, back)) { + err =3D -5; + goto out_unlock; + } + +out_unlock: + bpf_spin_unlock(&lock); + bpf_obj_drop(a); + bpf_obj_drop(b); + return err; +} + +SEC("tc") +__description("list_is_edge_test3: single node is both first and last") +__success __retval(0) +int list_is_edge_test3(void *ctx) +{ + struct node_data *tmp; + struct bpf_list_node *node; + long err =3D 0; + + tmp =3D __add_in_list(&head, &lock); + if (!tmp) + return -1; + + bpf_spin_lock(&lock); + node =3D bpf_list_front(&head); + if (!node) { + bpf_spin_unlock(&lock); + bpf_obj_drop(tmp); + return -2; + } + + if (!bpf_list_is_first(&head, node) || !bpf_list_is_last(&head, node)) + err =3D -3; + bpf_spin_unlock(&lock); + + bpf_obj_drop(tmp); + return err; +} + +SEC("tc") +__description("list_del_test1: del returns removed nodes") +__success __retval(0) +int list_del_test1(void *ctx) +{ + struct node_data *node_first, *node_last; + struct bpf_list_node *bpf_node_first, *bpf_node_last; + int err =3D 0; + + node_last =3D __add_in_list(&head, &lock); + if (!node_last) + return -1; + + node_first =3D __add_in_list(&head, &lock); + if (!node_first) { + bpf_obj_drop(node_last); + return -2; + } + + bpf_spin_lock(&lock); + bpf_node_last =3D bpf_list_del(&head, &node_last->l); + bpf_node_first =3D bpf_list_del(&head, &node_first->l); + bpf_spin_unlock(&lock); + + if (bpf_node_first) + bpf_obj_drop(container_of(bpf_node_first, struct node_data, l)); + else + err =3D -3; + + if (bpf_node_last) + bpf_obj_drop(container_of(bpf_node_last, struct node_data, l)); + else + err =3D -4; + + bpf_obj_drop(node_first); + bpf_obj_drop(node_last); + return err; +} + +SEC("tc") +__description("list_del_test2: remove an arbitrary node from the list") +__success __retval(0) +int list_del_test2(void *ctx) +{ + struct bpf_rb_node *rb; + struct bpf_list_node *l; + struct node_data *n; + long err; + + err =3D __insert_in_tree_and_list(&head, &root, &lock); + if (err) + return err; + + bpf_spin_lock(&lock); + rb =3D bpf_rbtree_first(&root); + if (!rb) { + bpf_spin_unlock(&lock); + return -4; + } + + rb =3D bpf_rbtree_remove(&root, rb); + if (!rb) { + bpf_spin_unlock(&lock); + return -5; + } + + n =3D container_of(rb, struct node_data, r); + l =3D bpf_list_del(&head, &n->l); + bpf_spin_unlock(&lock); + bpf_obj_drop(n); + if (!l) + return -6; + + bpf_obj_drop(container_of(l, struct node_data, l)); + return 0; +} + +SEC("tc") +__description("list_del_test3: list_del accepts list_front return value as= node") +__success __retval(0) +int list_del_test3(void *ctx) +{ + struct node_data *tmp; + struct bpf_list_node *bpf_node, *l; + long err =3D 0; + + tmp =3D __add_in_list(&head, &lock); + if (!tmp) + return -1; + + bpf_spin_lock(&lock); + bpf_node =3D bpf_list_front(&head); + if (!bpf_node) { + bpf_spin_unlock(&lock); + err =3D -2; + goto fail; + } + + l =3D bpf_list_del(&head, bpf_node); + bpf_spin_unlock(&lock); + if (!l) { + err =3D -3; + goto fail; + } + + bpf_obj_drop(container_of(l, struct node_data, l)); + bpf_obj_drop(tmp); + return 0; + +fail: + bpf_obj_drop(tmp); + return err; +} + +SEC("tc") +__description("list_add_test1: insert new node after prev") +__success __retval(0) +int list_add_test1(void *ctx) +{ + struct node_data *node_first; + struct node_data *new_node; + long err =3D 0; + + node_first =3D __add_in_list(&head, &lock); + if (!node_first) + return -1; + + new_node =3D bpf_obj_new(typeof(*new_node)); + if (!new_node) { + err =3D -2; + goto fail; + } + + bpf_spin_lock(&lock); + err =3D bpf_list_add(&head, &new_node->l, &node_first->l); + bpf_spin_unlock(&lock); + if (err) { + err =3D -3; + goto fail; + } + +fail: + bpf_obj_drop(node_first); + return err; +} + +SEC("tc") +__description("list_add_test2: list_add accepts list_front return value as= prev") +__success __retval(0) +int list_add_test2(void *ctx) +{ + struct node_data *new_node, *tmp; + struct bpf_list_node *bpf_node; + long err =3D 0; + + tmp =3D __add_in_list(&head, &lock); + if (!tmp) + return -1; + + new_node =3D bpf_obj_new(typeof(*new_node)); + if (!new_node) { + err =3D -2; + goto fail; + } + + bpf_spin_lock(&lock); + bpf_node =3D bpf_list_front(&head); + if (!bpf_node) { + bpf_spin_unlock(&lock); + bpf_obj_drop(new_node); + err =3D -3; + goto fail; + } + + err =3D bpf_list_add(&head, &new_node->l, bpf_node); + bpf_spin_unlock(&lock); + if (err) { + err =3D -4; + goto fail; + } + +fail: + bpf_obj_drop(tmp); + return err; +} + +struct uninit_head_val { + struct bpf_spin_lock lock; + struct bpf_list_head head __contains(node_data, l); +}; + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, int); + __type(value, struct uninit_head_val); + __uint(max_entries, 1); +} uninit_head_map SEC(".maps"); + +SEC("tc") +__description("list_push_back_uninit_head: push_back on 0-initialized list= head") +__success __retval(0) +int list_push_back_uninit_head(void *ctx) +{ + struct uninit_head_val *st; + struct node_data *node; + int ret =3D -1, key =3D 0; + + st =3D bpf_map_lookup_elem(&uninit_head_map, &key); + if (!st) + return -1; + + node =3D bpf_obj_new(typeof(*node)); + if (!node) + return -1; + + bpf_spin_lock(&st->lock); + ret =3D bpf_list_push_back(&st->head, &node->l); + bpf_spin_unlock(&st->lock); + + return ret; +} + +SEC("?tc") +__failure __msg("bpf_spin_lock at off=3D32 must be held for bpf_list_head") +long list_del_without_lock_fail(void *ctx) +{ + struct node_data *n; + struct bpf_list_node *l; + + n =3D bpf_obj_new(typeof(*n)); + if (!n) + return -1; + + /* Error case: delete list node without holding lock */ + l =3D bpf_list_del(&head, &n->l); + bpf_obj_drop(n); + if (!l) + return -2; + bpf_obj_drop(container_of(l, struct node_data, l)); + + return 0; +} + +SEC("?tc") +__failure __msg("bpf_spin_lock at off=3D32 must be held for bpf_list_head") +long list_add_without_lock_fail(void *ctx) +{ + struct node_data *n, *prev; + + n =3D bpf_obj_new(typeof(*n)); + if (!n) + return -1; + + prev =3D bpf_obj_new(typeof(*prev)); + if (!prev) { + bpf_obj_drop(n); + return -1; + } + + /* Error case: add list node without holding lock */ + if (bpf_list_add(&head, &n->l, &prev->l)) { + bpf_obj_drop(prev); + bpf_obj_drop(n); + return -2; + } + + return 0; +} + SEC("tc") __success long rbtree_refcounted_node_ref_escapes(void *ctx) --=20 2.50.1 (Apple Git-155)