From nobody Sun May 24 21:37:00 2026 Received: from out-176.mta1.migadu.com (out-176.mta1.migadu.com [95.215.58.176]) (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 86BDB35677C for ; Thu, 21 May 2026 03:24:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.176 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779333858; cv=none; b=lmbICBGqxQN84VMJVucWDuYQ7uv0GunSxKDx17c5oktObPvjHG8vLtY8yghI/Vz9SlOa+3rUTkbkTFqthoZ/gPHtCbYcI27+TiPAZ1IJnAN5iXhHKlkjDxl5Wsr0siEuxLvuPY88s/kt8le1vGCUBD/PGUbtq1f6Dqaj9BwsCLQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779333858; c=relaxed/simple; bh=rD6BPyHAy18d6Lnl6no3lJqWl9uAgSBgPoYSBUNiw2A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=nYaIJRG7twm8uoSsQoli5dS+vnAakdPqYXqow+Ju195QB5wvblvpjiXgTz7xmYORpk0Xv/BTS/CH6yP7BQw7xMrzhOPZ6sPcv8Ga6WxEn4TJWfWLqkpmSBNLARzxXcuxP8Om0R82pVuQ4d8GYPk8QLSmVlxzrkFeaWIDXhfaWEY= 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=BdVeZsKf; arc=none smtp.client-ip=95.215.58.176 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="BdVeZsKf" 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=1779333854; 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=DKCQHFdvmeJokAPjmIjM8nkmZr0xlAyybv33vgc3Gkw=; b=BdVeZsKfwPZZohrjsudY78FjsIRo1yER5lwS2PM5SQjkL/xWS2rVFKrQIPQCznKKjIw9CH 30MMMn2BCz2zrc7G6r/Ox06wCX+XroCbFhoIRNMPkgl70JTjSLeQ4cRhK6b7FO135W3SH/ TACfHhFU7TQ+9FYK7fenazpCgRhZhNU= From: Kaitao Cheng To: ast@kernel.org, corbet@lwn.net, martin.lau@linux.dev, 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, skhan@linuxfoundation.org, memxor@gmail.com Cc: bpf@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, vmalik@redhat.com, linux-kselftest@vger.kernel.org Subject: [PATCH bpf-next v11 1/8] bpf: refactor __bpf_list_del to take list node pointer Date: Thu, 21 May 2026 11:22:59 +0800 Message-ID: <20260521032306.97118-2-kaitao.cheng@linux.dev> In-Reply-To: <20260521032306.97118-1-kaitao.cheng@linux.dev> References: <20260521032306.97118-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 Reviewed-by: Eduard Zingerman --- kernel/bpf/helpers.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 07de26e7314c..094457c3e6d3 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -2550,37 +2550,44 @@ __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); - WRITE_ONCE(node->owner, NULL); + /* Ensure __bpf_list_add() sees the node as unlinked. */ + smp_store_release(&node->owner, NULL); return (struct bpf_list_node *)n; } =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 Sun May 24 21:37:00 2026 Received: from out-186.mta1.migadu.com (out-186.mta1.migadu.com [95.215.58.186]) (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 7BDE138422F for ; Thu, 21 May 2026 03:24:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.186 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779333863; cv=none; b=crEMWWW0jL4A1t3lQkr65KOm1VzMQ69K9vsROKfd+IXahQWajKekbCMw+tlZPgni5rS+EsrBqtyo4K/wNatWd3ylYtpzKdnI8i3Gqh0rjM8OXgFBRC3UUlR6tr5YkY8c7GeQ4b5JS4WG0SM3UUXWVlNmonh/JtpVJtq99ZO+L7M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779333863; c=relaxed/simple; bh=uTA/IPe0SD3xMXt47BGiypLhOKhs44rGXPEp3qX5o8Q=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RPBNWeN6PdXagpRHDjgAliKs6IAf4hlEpnnexJvn5tLAW2FxmSc1fqL+gDwo7SpRFR8nc2UZvqeXSryXcvA79hxOUo8FTRt0Dd9vWJQM9LU5KRzW98gcbgYB/yuSLRCY46H9JJ/b3RFZF05/6/ZCw3VH4CXU9Mxsnw3Sj+5tCcs= 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=Q/ziLl55; arc=none smtp.client-ip=95.215.58.186 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="Q/ziLl55" 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=1779333859; 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=EibCAjpYj8bsk5BcAAI7Zy4bc3E7PcZnr8SoDxq6ulc=; b=Q/ziLl55fMtz/TMzFoyk3a5EKDsGd1AFw0qH2POzV2eSOrImf4X0GLOIm43dLqybdwmCpb ZaMtCgS18bdvI4cQNslKfpVWPtOnV4t+ZAFqgSJPmkuIxtjiWUZDFscvgBo3BUuO+tUl2K rlJTfCBY4YPbTThDHShQgdBQ6NI279Q= From: Kaitao Cheng To: ast@kernel.org, corbet@lwn.net, martin.lau@linux.dev, 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, skhan@linuxfoundation.org, memxor@gmail.com Cc: bpf@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, vmalik@redhat.com, linux-kselftest@vger.kernel.org Subject: [PATCH bpf-next v11 2/8] bpf: clear list node owner and unlink before drop Date: Thu, 21 May 2026 11:23:00 +0800 Message-ID: <20260521032306.97118-3-kaitao.cheng@linux.dev> In-Reply-To: <20260521032306.97118-1-kaitao.cheng@linux.dev> References: <20260521032306.97118-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 The issue only becomes exposed once bpf_list_del() is available: callers can pass an arbitrary bpf_list_head and bpf_list_node pair, including nodes that are not actually linked to the supplied head, or nodes that outlive their original head after refcount-based retention. This was not practically reachable for callers restricted to pop-style helpers alone; bpf_list_del() widens the API surface. A failure mode appears when bpf_list_head_free() runs while a program still holds an independent refcount on a node (for example via bpf_refcount_acquire()). The list head value embedded in map memory can go away while the node object survives. If node->owner is left pointing at the old head address until drop completes, that pointer becomes stale. If a new bpf_list_head is later allocated at the same address and the stale node is passed to bpf_list_del(), the owner comparison can succeed even though the node is not really linked to the new head, and list_del_init() will follow bogus next/prev pointers with the risk of memory corruption. When draining a bpf_list_head, mark each node owner with BPF_PTR_POISON under the map spinlock while moving it to a private drain list, then list_del_init() the node and clear owner to NULL before calling __bpf_obj_drop_impl(). Concurrent readers therefore never observe a node that appears linked to a head while its list_head is inconsistent, and surviving refcounted nodes never retain a stale non-NULL owner. Signed-off-by: Kaitao Cheng --- kernel/bpf/helpers.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 094457c3e6d3..59855b434f0b 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,30 @@ 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) { + struct bpf_list_node_kern *node; + + node =3D container_of(pos, struct bpf_list_node_kern, list_head); + WRITE_ONCE(node->owner, BPF_PTR_POISON); + 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; + while (!list_empty(&drain)) { + struct bpf_list_node_kern *node; =20 - obj -=3D field->graph_root.node_offset; - head =3D head->next; + pos =3D drain.next; + node =3D container_of(pos, struct bpf_list_node_kern, list_head); + list_del_init(pos); + /* Ensure __bpf_list_add() sees the node as unlinked. */ + smp_store_release(&node->owner, NULL); /* 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 Sun May 24 21:37:00 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 C101038236F for ; Thu, 21 May 2026 03:24:27 +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=1779333869; cv=none; b=Y3eNEAZQREaAo3+oWSoBWePQhmm1iDrmGShErutCuJzbs/h0ptt5fWPGL0CWxhl1AeU9L02Q+9PlHmFR6TeQ4U9HM6xQ2fe0qb1gVLgXVm8ms46R8zZN9KMY1WHxAEYUgMnN+l6w78BM95qL099SByCb1chQyTUlDC7o5lGxRck= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779333869; c=relaxed/simple; bh=QF0VQigiS9C8x3qp/3dv7AfSItMP6oTWZARJW1nciTo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=UyvJjzSG2e5NgIsi6wZ4PnkxxDnDtaKcVH5mmZNw6S/Fi/cqRo2HwN7HDjYM1JPSCyPD8fSBBNjjnzBdPmEyvgmFmCe1GBP/HZTVGGTlqtQ8xg5mPmKcFIOMIuZx/tCEx+E8hK9BErlLov6yJbNLfEDnSFKmrCsI9lXZO9Ku/fg= 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=QbmasXAN; 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="QbmasXAN" 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=1779333865; 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=+BjQ1+jDF+nnJfG5AqBJZDyfiRu75uMNz4SpIOWGGKo=; b=QbmasXANKZfP06EIaUAJG9KzxtXEnieFSZCWEw2jcu6As5oo+VnFdKSq2AWeWmUCf9RM/n mLLDYK6UQncQyoe+aPOoc0MIxtyC+huWp2OdUtPJ1D7167bLX/8sMfqw2GXQWo9ecS29gZ yF8FuqsEo2mlPM4AGfIDyqCybG7Etlc= From: Kaitao Cheng To: ast@kernel.org, corbet@lwn.net, martin.lau@linux.dev, 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, skhan@linuxfoundation.org, memxor@gmail.com Cc: bpf@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, vmalik@redhat.com, linux-kselftest@vger.kernel.org Subject: [PATCH bpf-next v11 3/8] bpf: allow non-owning list-node args via __nonown_allowed Date: Thu, 21 May 2026 11:23:01 +0800 Message-ID: <20260521032306.97118-4-kaitao.cheng@linux.dev> In-Reply-To: <20260521032306.97118-1-kaitao.cheng@linux.dev> References: <20260521032306.97118-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 the __nonown_allowed annotation on selected list-node arguments so non-owning references with ref_obj_id=3D=3D0 are accepted as well. This patch only adds the generic verifier support and documents the annotation. Later patches in the series will apply it to bpf_list_add /del(), and bpf_list_is_first/last(), allowing bpf_list_front/back() results to be used as the insertion point, deletion target, or query target for those kfuncs. 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 Reviewed-by: Eduard Zingerman --- Documentation/bpf/kfuncs.rst | 22 ++++++++++++++++++++-- kernel/bpf/verifier.c | 13 +++++++++++++ 2 files changed, 33 insertions(+), 2 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/verifier.c b/kernel/bpf/verifier.c index 8dd79b735a69..f3cf8d85bea0 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -10714,6 +10714,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"); @@ -12244,6 +12249,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)); @@ -12253,6 +12265,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 Sun May 24 21:37:00 2026 Received: from out-178.mta1.migadu.com (out-178.mta1.migadu.com [95.215.58.178]) (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 82017383991 for ; Thu, 21 May 2026 03:24:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779333874; cv=none; b=uWF8ZXOhtfDqRfgnv4RBaj+ZoYGUluLFDSgKE3rq7Tn7MGBQYgMfFSQM4wAmMBfAjiXb1mbDBFCwNI7PTDtGQZ4MFVxuH2ptWgGZvi2tyz14AJWPv3CX0qmHncpUjOdDtAOpAGVdL+poldZ/N1jN0vD8Y2PzB4oB60Ou0gsqFVs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779333874; c=relaxed/simple; bh=n1u7wfvS9KQ/rHla2vNiEZSupvdE/D2/76zixfz2PDg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=h6fLYlZNQeVrafbDJ/Q1S3dZooP93vDw+BO2hv2x+2Vxz3m+0u0IA2L3wVqAIlxm7FSUW93Xwv6WIu7fTGX8WQPxBusHiiUT0dAms3+ryRHWSZXuwUS1Q3dfHfXJvmiOyrY0WJToysfzwIfMiaCQ5mVWOq0I0poPUjSala0r7BU= 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=TkZSwgeR; arc=none smtp.client-ip=95.215.58.178 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="TkZSwgeR" 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=1779333870; 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=qkrmEkazbdspFx3y70iFA03SYZiuUXZn+VIyQDVFkvg=; b=TkZSwgeRPvCb7Mm5yNXOe8N+hh3znna4Me3OqrFOyvc3l9gHFhx+9UsVOe7BU1xuHdTIuT iktUIyVK2wL8WL3KzLc5dEehmnS+S/sxY/nF8pKDnXiCO632iNco2of0YaYmsfqYtoteG1 7uEb0TVDhomWN9LvEOO52xtm9aRvoX4= From: Kaitao Cheng To: ast@kernel.org, corbet@lwn.net, martin.lau@linux.dev, 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, skhan@linuxfoundation.org, memxor@gmail.com Cc: bpf@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, vmalik@redhat.com, linux-kselftest@vger.kernel.org Subject: [PATCH bpf-next v11 4/8] bpf: Introduce the bpf_list_del kfunc. Date: Thu, 21 May 2026 11:23:02 +0800 Message-ID: <20260521032306.97118-5-kaitao.cheng@linux.dev> In-Reply-To: <20260521032306.97118-1-kaitao.cheng@linux.dev> References: <20260521032306.97118-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 Reviewed-by: Eduard Zingerman --- 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 59855b434f0b..804c201c28f3 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -2601,6 +2601,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__nonown_allowed) +{ + struct bpf_list_node_kern *kn =3D (void *)node__nonown_allowed; + + /* 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; @@ -4733,6 +4742,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 f3cf8d85bea0..35eebb5e7769 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -10961,6 +10961,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, @@ -11029,6 +11030,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) @@ -11549,6 +11551,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]; } @@ -11671,7 +11674,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 Sun May 24 21:37:00 2026 Received: from out-180.mta1.migadu.com (out-180.mta1.migadu.com [95.215.58.180]) (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 9DE7F38422A for ; Thu, 21 May 2026 03:24:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.180 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779333879; cv=none; b=XzxS41mgCD3O07+vEAdjY/dOEOburgxb8vAdAWNYY+BGitMuqcsWmSAlR9t9MJfenm6cZXMEahM61GsIig+soVcN5rP3c+bc76rNbSTZowofUsMi9BAg3N5Q+62TWRoAYNltJ+dnOgljCqmPa76kxw7hz8yB5BhspVjguQnUg+o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779333879; c=relaxed/simple; bh=4MLpMmMkk6Xzy1pnGdy9h6hh38Q7yAzgn2oOXx8QzAo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=sxeIlEfdcGi7+C8jfMyjVCw60vdXw8C9LT4smAL393BN/+cmXZu8OCyfphAsduACYIJWFty4yBT13dGXzG2svbte4hgI+ILzwCwj10RbJ3A+J9bMMz2IGoeVfywbO0QxSHUcg9cUTSXXxEI5kxyMwjrq85mRkyy/WryalnQz3Bs= 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=a3/I3SfI; arc=none smtp.client-ip=95.215.58.180 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="a3/I3SfI" 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=1779333875; 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=At1YoeTWsHYJviBgCEh2Fe6MhwIuuXtFcpxRcZ3B/SU=; b=a3/I3SfIMisI/oV28rLOvjp+HhBtGMNyeLx1zuCo9a92qdeuSmCrGMZdD+Bziqd2mh2GJT KTFunknuAFHgs2fdLv5kvggxQGcg/d4mkkteAFzTvqHDQgFRh6DJcFfKto5MSFmiturYbw 2F/4DJ/XthM42zgXLmiig8L+HSyvOSY= From: Kaitao Cheng To: ast@kernel.org, corbet@lwn.net, martin.lau@linux.dev, 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, skhan@linuxfoundation.org, memxor@gmail.com Cc: bpf@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, vmalik@redhat.com, linux-kselftest@vger.kernel.org Subject: [PATCH bpf-next v11 5/8] bpf: refactor __bpf_list_add to take insertion point via **prev_ptr Date: Thu, 21 May 2026 11:23:03 +0800 Message-ID: <20260521032306.97118-6-kaitao.cheng@linux.dev> In-Reply-To: <20260521032306.97118-1-kaitao.cheng@linux.dev> References: <20260521032306.97118-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 Reviewed-by: Eduard Zingerman --- 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 804c201c28f3..1c69476c8a09 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -2478,9 +2478,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 @@ -2488,19 +2490,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 /** @@ -2521,8 +2535,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, @@ -2550,8 +2565,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 Sun May 24 21:37:00 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 7E7623859EE for ; Thu, 21 May 2026 03:24:42 +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=1779333884; cv=none; b=LX3XMkiDvrD7MJEzLaSEAXlBNEKWZLWrdqPTYym8Of4z8pjfoCASmMDijT7nJWiToHBtja9E9d1KegdTI49EIF9vsY7NViWpXdFDC/ykxxfFiDoOFmNC9BCMhzxzdPHsvD1/ni7mcgNPDsANJQ+E0hUkwNI3ufOoUuY6Gfa2iLc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779333884; c=relaxed/simple; bh=+BtilysjVVxO3ABeOMvlyB+8+Ttt5znjOUyB3PcI7s8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rY/YWz8qYF9XuU6dcJb2BdHS1dzK/Wd0aphg3rG28qHxfIGYfndkfGxJ5mSZBl9xzSw9F9PRq90v/wvJmmKb7IfI7GYAuKnUBrpTYv6hdtONSzEkmPrtVZFzEjkUpi6MTQsu5I760QuESoMJUGFfbTd1u6E7CIuuMGgYrYbNqGs= 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=dPCYBrLT; 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="dPCYBrLT" 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=1779333880; 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=jGyFnbwX8XkqTWxZDvl1NqVaoqhkKtKsutTFkKeV2Vg=; b=dPCYBrLTiI7xfKNGYWi0ykInKCr1plrt4IHusFF44eZ9uxxbIGptIvduyUOw/lvxfXAYUV PVKJh4r+tXEQG/S3A0lEgQiNSZR7Q00msTp9U/Kqwft/43rXwJWY/ndAcvT1GGm+aBNjor 9UMZ7Ex6218cG7hqbBk6753kZNG73pU= From: Kaitao Cheng To: ast@kernel.org, corbet@lwn.net, martin.lau@linux.dev, 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, skhan@linuxfoundation.org, memxor@gmail.com Cc: bpf@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, vmalik@redhat.com, linux-kselftest@vger.kernel.org Subject: [PATCH bpf-next v11 6/8] bpf: Add bpf_list_add to insert node after a given list node Date: Thu, 21 May 2026 11:23:04 +0800 Message-ID: <20260521032306.97118-7-kaitao.cheng@linux.dev> In-Reply-To: <20260521032306.97118-1-kaitao.cheng@linux.dev> References: <20260521032306.97118-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 Reviewed-by: Eduard Zingerman --- 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 1c69476c8a09..89579165ef4d 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -2577,6 +2577,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__nonown_allowed, + struct btf_struct_meta *meta, u64 off) +{ + struct bpf_list_node_kern *n =3D (void *)new, *p =3D (void *)prev__nonown= _allowed; + 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) { @@ -4756,6 +4766,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 35eebb5e7769..662ad7312697 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -10959,6 +10959,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, @@ -11028,6 +11029,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) @@ -11140,7 +11142,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) @@ -19524,8 +19527,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 Sun May 24 21:37:00 2026 Received: from out-182.mta1.migadu.com (out-182.mta1.migadu.com [95.215.58.182]) (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 825933822B4; Thu, 21 May 2026 03:24:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779333890; cv=none; b=PZAFM5tTyzD+SDi3x8N0K2nkxZ1X/38DsCt22dQ12TS8rZeNeTo21Vi3scnd9Bj7p74qrLBuC9/alrNVwb6ndIKDfcrFg41rO1ItGadnrimKFI1XJwHd23IPrteveu7W3KYVs1SE/UR8Mt7hrF3Odn8FJk1PB9eqRaUW88X3xSk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779333890; c=relaxed/simple; bh=e0BLPZF0W2n+jN/JnZKz67oRVTlrLWBUGzpdlvERSKk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=N4lRcH/jD/oYccESxAzVJCL8wc1yIPv3/e4qL4Xq2XyU4InAIc8Phn/1O35GANajZLtm3vn1Zg+4LodlBR9XnIbN8L+Skz5QcvZCowlHoQvKik8qTBqK2HfNp87cyoGrPhXDRTichB62kASz7cgAK95vzRkfLNWsoeFa5xGJ0zY= 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=hHQ8FKXt; arc=none smtp.client-ip=95.215.58.182 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="hHQ8FKXt" 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=1779333886; 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=ElWLdrCbk8g1PoRY5Me2SOYGZbdC80GXt7KhUPW29fY=; b=hHQ8FKXtOwvBV/1S2ldKNZWC8T1xf03OX4IiS056QwTgQuMA+NlGwxb4wAcl0qvPo843kA W9/4DFagL8QPo2Fc/9vW44hwMyAC809D1Ai2XGXR5KeniaZZgvuSFdlqMVpoL98kt1+OXU rOqiEl42FGvwf/fJqgs9oVKEYK/wavg= From: Kaitao Cheng To: ast@kernel.org, corbet@lwn.net, martin.lau@linux.dev, 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, skhan@linuxfoundation.org, memxor@gmail.com Cc: bpf@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, vmalik@redhat.com, linux-kselftest@vger.kernel.org, Emil Tsalapatis Subject: [PATCH bpf-next v11 7/8] bpf: add bpf_list_is_first/last/empty kfuncs Date: Thu, 21 May 2026 11:23:05 +0800 Message-ID: <20260521032306.97118-8-kaitao.cheng@linux.dev> In-Reply-To: <20260521032306.97118-1-kaitao.cheng@linux.dev> References: <20260521032306.97118-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 | 40 ++++++++++++++++++++++++++++++++++++++++ kernel/bpf/verifier.c | 15 +++++++++++++-- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 89579165ef4d..b6c3d02d5593 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -2656,6 +2656,43 @@ __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__nonown_allowed) +{ + struct list_head *h =3D (struct list_head *)head; + struct bpf_list_node_kern *kn =3D (struct bpf_list_node_kern *)node__nono= wn_allowed; + + 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_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__nono= wn_allowed; + + 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) { @@ -4772,6 +4809,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 662ad7312697..d9bdc3b32c05 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -10965,6 +10965,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, @@ -11035,6 +11038,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) @@ -11556,7 +11562,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) @@ -11678,7 +11687,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 Sun May 24 21:37:00 2026 Received: from out-189.mta1.migadu.com (out-189.mta1.migadu.com [95.215.58.189]) (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 A209D368D43 for ; Thu, 21 May 2026 03:24:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.189 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779333898; cv=none; b=B6EnB84XB5BUwgskSemMaUeX3I+uWW9uYwXUAxlaCAC7SCwV8JeuQpsjVtgnMPy3v63ynUqx7ZjzPiKh48C4TMj0UrNyhEF+c/mM5trwfp0KCtdTIg8BjZ30/p3is6B3C0FeR7ZVYSCfwhCgR7GREYNT02DEhB8EqRFdjy8BV+o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779333898; c=relaxed/simple; bh=lRzdTY4rArJAWpvVMCOhx/ScdYO4118ZNjZk+wf61L0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LtSAXLNMT39Yr+4PaAxYFA3siCDb71BxVzrylPh+k/PsDgh/qQIre133lMEWC6x4u6r8Xd9Rk7VfmfhoijMRuLXDj8ql4jDc9xA+B3Iz9V0zNdlU8EMe7b7Bf5E+VFBcY7Oly7zSTJeP6woWVl51L1aqKs5x8ZDOz7k203Y845g= 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=FEdzfKgk; arc=none smtp.client-ip=95.215.58.189 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="FEdzfKgk" 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=1779333894; 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=QxaCbTJqwX0/DV0iaDY79WsPPuIghKS/hijc+otlBjE=; b=FEdzfKgkixJMu7eB4/T9XvJX7rI7JjQ87ls6L7MDxqMYQfd0P09bPtD9IUC5rEqcKJGxsP IyYRSw6Lpz8uEt8yiry41y7dYG22oTa/TRah6saCiWMv9etiy/5fBovJi07I51VPlh65QG +tNTZZPHg1+iKVBY/sxXaG0zqYbn5sM= From: Kaitao Cheng To: ast@kernel.org, corbet@lwn.net, martin.lau@linux.dev, 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, skhan@linuxfoundation.org, memxor@gmail.com Cc: bpf@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, vmalik@redhat.com, linux-kselftest@vger.kernel.org Subject: [PATCH bpf-next v11 8/8] selftests/bpf: Add test cases for bpf_list_del/add/is_first/is_last/empty Date: Thu, 21 May 2026 11:23:06 +0800 Message-ID: <20260521032306.97118-9-kaitao.cheng@linux.dev> In-Reply-To: <20260521032306.97118-1-kaitao.cheng@linux.dev> References: <20260521032306.97118-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..13de169ad68f 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; + long err; + + 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 */ + err =3D bpf_list_add(&head, &n->l, &prev->l); + bpf_obj_drop(prev); + if (err) + return -2; + + return 0; +} + SEC("tc") __success long rbtree_refcounted_node_ref_escapes(void *ctx) --=20 2.50.1 (Apple Git-155)