From nobody Tue May 26 04:49:42 2026 Received: from out-178.mta0.migadu.com (out-178.mta0.migadu.com [91.218.175.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 9969B410D18; Tue, 12 May 2026 05:59:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778565614; cv=none; b=exC8QB4IIGm+nYZLC4q3nEwRlIhM2fyVmIRbNKSgKKFelIF7HIUD31P/egjTKVtzgKzxXMVcMs++2PFpfOYFxjp5VlU8kMKlkY3Ab2fa4pDmVjWuqre9zrZd9oPAIDitbuCq+4EAC0U/ymT8FLFlEDFE3ce13BkUNgo8AdWDpJo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778565614; c=relaxed/simple; bh=whicB2ftr5oTRrTNIW+rmCW4aEeQ9SHLQFsgKCkj210=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=DiDrXBFj7aBVT4n++HllQ+OHto7Mlg4iwWhNUFZGzKCyzifWkSDwIbmn/Q461QXu1tcnXznMRVZNNuLYBGvPN9zPrgHsIJ+sYGZybbfAaYij9rZuPDIpgsHNK1VZCjpwQpYy+ULxxZUwcpn+2xjFeQpzT5w75aIGsUPU1/LssJk= 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=fP1J/eXX; arc=none smtp.client-ip=91.218.175.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="fP1J/eXX" 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=1778565582; 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=fP1J/eXX7t3frf+lw1lGF9VPcd7W83eIvpJZtOzIWiFqwY6ifpnzw/PJTlU+1Y1vC2Yzg+ IVABDCmQoFBStd4nbWOnHfrPwzhAfow/75wEg0B1VudH3xMKBMfGF1z3EZTacOSLVCoy6f qMgjTlwcuLPRLCHG4uWnneVYsOndxzM= 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 RESEND bpf-next v10 1/8] bpf: refactor __bpf_list_del to take list node pointer Date: Tue, 12 May 2026 13:59:12 +0800 Message-ID: <20260512055919.95716-2-kaitao.cheng@linux.dev> In-Reply-To: <20260512055919.95716-1-kaitao.cheng@linux.dev> References: <20260512055919.95716-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 | 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 Tue May 26 04:49:42 2026 Received: from out-172.mta0.migadu.com (out-172.mta0.migadu.com [91.218.175.172]) (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 654CD40F8E9 for ; Tue, 12 May 2026 05:59:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778565602; cv=none; b=kJIi3TZU+MNjILUk1EJRhrSJ9QxsvM43GZCs5AJSyYQsYiElzey8wfKcgu8N7lOWYgOqKuFdpPJ5nVtuO8IuY+pH1OWp2eR/ySrxNVoV8pZ5pPmg7h4wNHul1YqObJyez7AWUrIfq77w8Hr3kvxLWTEwGRFFqOSva7+TN5I/8+Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778565602; c=relaxed/simple; bh=MOXXlwv5+jPHoFenwU0Df/VSUFEVmpOCvtOJ2sq+C0A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Z99Cd7QdESrTDDQT+++EHlDoGsGaGhf7l0YnGbdroVgdiTvqNtxP1H1fB6EN0zy487CWNPlJ0aG6Le6NEGm2cvnq7kKqSdeiP7PyKCipa8nX05ix8XVU0ciQLGRrIVNIDNV3MoxSAqM8bcpEH+d6++Wioc+frkBZGKlRiF38vhY= 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=D6Atz+E7; arc=none smtp.client-ip=91.218.175.172 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="D6Atz+E7" 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=1778565586; 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=D6Atz+E72y/TXC6e0lOQNHzZwA2GKySFNMXqOoxxsTalmaRRb0Ebs3KjT+0Zl/44bS4YSh u81afk/E93ByxiZPD1PtcG25NheEezEMAo9mbG4EN0dRESz3IeAjIYSoB4Y0G5481LEjn4 Tf/ebBXaRcxFGUHeSh8AQduJilv+s8k= 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 RESEND bpf-next v10 2/8] bpf: clear list node owner and unlink before drop Date: Tue, 12 May 2026 13:59:13 +0800 Message-ID: <20260512055919.95716-3-kaitao.cheng@linux.dev> In-Reply-To: <20260512055919.95716-1-kaitao.cheng@linux.dev> References: <20260512055919.95716-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 Tue May 26 04:49:42 2026 Received: from out-177.mta0.migadu.com (out-177.mta0.migadu.com [91.218.175.177]) (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 4F5AF413258; Tue, 12 May 2026 05:59:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.177 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778565609; cv=none; b=C4D6nDVC2UpcFWFBnOnVCcXlILqwF7pHMWTPRdxOeJ0+Hf1PWreYFdj2AbOypvQlx9Y+S8XZIN4VrnYURTS4N/FPzvrBl5T4Vz06cxx7PdcwLcChHOuWpklqCCsIXjHnoLbdfR21eh6ZGGC2qVtQeSVxiyEe6cNSUm32Emi59ks= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778565609; c=relaxed/simple; bh=anDkAin6bRlzRMPVlynK7/7TJNEy5a/mdefQRK4EtCw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=QQ71tBTz6jpvyzo1S3+Sr0gV/FdWNYs46MFNk0o9o1MM5mKtOzQw1m9u2E80+gS3BLv+TTbG76JaWSKfkVOXBbOh9LCzeSLYWnfXSWg69urDTagNZl6eALj9o6R5NJbmitmj9Wwt2SE4KNJX5jzwhj0BlVVPbj+MevxafOKZqcQ= 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=GRhKJxcS; arc=none smtp.client-ip=91.218.175.177 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="GRhKJxcS" 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=1778565591; 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=GRhKJxcS3aasgcPPHieC5HYrXEwKibazUkvRis69r0CyB3Nukz3rV+e4/MynwP6HUkrk6Z QkAKa8guBmgZpV/Bd0+EppDA+gPWArofTJ+Rpj1akCAubb+sBakHNP+rk8456TxNC58Dnz 4OcfaBYvI2Pn4JmSSMP4hasYEBpHOgI= 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 RESEND bpf-next v10 3/8] bpf: Introduce the bpf_list_del kfunc. Date: Tue, 12 May 2026 13:59:14 +0800 Message-ID: <20260512055919.95716-4-kaitao.cheng@linux.dev> In-Reply-To: <20260512055919.95716-1-kaitao.cheng@linux.dev> References: <20260512055919.95716-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 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 Tue May 26 04:49:42 2026 Received: from out-177.mta0.migadu.com (out-177.mta0.migadu.com [91.218.175.177]) (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 343E441B358 for ; Tue, 12 May 2026 06:00:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.177 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778565605; cv=none; b=S0XmxQ2WPod6S/g5EA3D5ARLwnm/4+ytRCj/uZPQF0CEA0zAdygH80x+HSMcqh37zuXXYj96K4gerx1OUym37BpxGn3f5n03fdX5hErRnVswYcPCa6MAySqKopvcn8vtOyjq1HOHSrYNQiRnthw+j6/OH4Ij9Nk40JTrOCwULE8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778565605; c=relaxed/simple; bh=/muV6dCbtwkyaf+jEkinQUctflZqYwvGPQ4RwozJAdA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lMKWCrRrDIMOyPCejlMNPJdFCJg4XufaKkdOLxAhrzfvsVp94S3piK/53JSPKw6GrJnAU6R0hQ/ZH7HzgojGFn8ioou1MWAmJmjhyMXMw1qn36eS/bHiJp/6cIIZQOMBK1W4VpoNB0qYCzSeWfGLfMgf3UUcng9rB4pN4KW/Pu4= 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=joCiE6Ir; arc=none smtp.client-ip=91.218.175.177 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="joCiE6Ir" 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=1778565596; 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=joCiE6IrlOavpz3M7en68uslNinXVdSR6G0kolQQD/1WUpDmH85CD7SviQ5xkejiO+xWXt 9e86pk2H5wz4NwINnY8pXQcVZzJTTaeRRLFOxujcgqfFGVaH/R8uolgebT0mYVRlv5a9cH bapHdHwfgsAfMS8NmEVAU9jiQr7XcQI= 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 RESEND bpf-next v10 4/8] bpf: refactor __bpf_list_add to take insertion point via **prev_ptr Date: Tue, 12 May 2026 13:59:15 +0800 Message-ID: <20260512055919.95716-5-kaitao.cheng@linux.dev> In-Reply-To: <20260512055919.95716-1-kaitao.cheng@linux.dev> References: <20260512055919.95716-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 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 Tue May 26 04:49:42 2026 Received: from out-170.mta0.migadu.com (out-170.mta0.migadu.com [91.218.175.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 D3BC340DFC7 for ; Tue, 12 May 2026 06:00:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.170 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778565619; cv=none; b=N5Zp7FslVBXXkNjXt8hIJwat/cCZ14gIojKYQbQEOhhWUgw64jYweSUby0vCLbrlyUSuj+Bb+C9cFc193Ur/I6SIk/ZuTmiR/mB2kTbvNU+rmGHhrGPDBdDypwIQey/m8eHVno5ybplcyD3tnOPGQ3UrJMgXAvqHuxPE2AiFXyc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778565619; c=relaxed/simple; bh=5p64GKPG5304730wA3md9aMwwm3p5LHhf4Lb7/Btios=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LNhRA3qkgNmflZm+7Q0tb8m15qknFIEMhMjSY3Yup9bMPgKXp2m7IAdAo9sA9v49EolZlt3o1HubPPRL6d5flqTbAw3BhmLZtckY+bzNv+QJmRIZZrrmvWODjlUCY4DCl/bdmPTHfiecr92R1UH1R67mgp2KggOLcpuvmsG57aE= 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=d9U7gtdP; arc=none smtp.client-ip=91.218.175.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="d9U7gtdP" 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=1778565600; 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=d9U7gtdPQe3MaUuT7FdIdky8oB6KYMLPQEoCT+V7jSCI5PMoDFbfCR8bxfM0SYWoQP3C/i R2souKj7JPydRPG91BHoZEDuQczG96WjQH1Md0WZiP1LXvickLzikhpXR10Pe1cGQm4reo tH4U8osKMq3KmlM+zPe3HkMInNHzNoQ= 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 RESEND bpf-next v10 5/8] bpf: Add bpf_list_add to insert node after a given list node Date: Tue, 12 May 2026 13:59:16 +0800 Message-ID: <20260512055919.95716-6-kaitao.cheng@linux.dev> In-Reply-To: <20260512055919.95716-1-kaitao.cheng@linux.dev> References: <20260512055919.95716-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 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 Tue May 26 04:49:42 2026 Received: from out-173.mta0.migadu.com (out-173.mta0.migadu.com [91.218.175.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 7881A40B6E6 for ; Tue, 12 May 2026 06:00:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.173 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778565625; cv=none; b=alJMFY6shVzi5QiF3y4GWYcqZ+WATRcXIqkGf7cdMoLHYI2CLl7XMGpC95NdbR0FhCLn1Y20sx+CFInmBBtAU565dKb8dmiyS0ux5/orVDXRpCb1R5BRKkWoikbS50NY0Uy4+RXGrd5ufFQeITJLkWEDY2QbJMpcFKWvpbURbP4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778565625; c=relaxed/simple; bh=BE+YmEUt2JlQE2gs3eOXXlXi3+oQVNhffbC4hhexUgQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bpEM5gmst1/yOzIt4z9noLgWScmnalXDds6yR6QZZ9zoAyerqMbxjlBdziHUfZlXIaydiRg7/99NZVq1xJAmFKqJmr0b9iSm5s7otHppAPz4XV+jf0Vyql76pmwvvk9Dt4GJjLO7j37j0XXoae96J1Slc3JR0vMw9kFSG6941Sc= 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=fBesmGYR; arc=none smtp.client-ip=91.218.175.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="fBesmGYR" 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=1778565606; 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=fBesmGYRsFxpoMwMuWmpFQwBVWnOuSzq3/u3hSl5CBAWP0dcnJZn4PtAAx9yT1lZsBlmLt zJ7THcDjat7AEVuo50SEiVIsGM6y956cG4tyVPB4Ze2Hb9RobkQRJHw9J8CpojNkwLobRn NWN2cW3T5VqnRNbtRdiI2oR/B7nWGqg= 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 RESEND bpf-next v10 6/8] bpf: add bpf_list_is_first/last/empty kfuncs Date: Tue, 12 May 2026 13:59:17 +0800 Message-ID: <20260512055919.95716-7-kaitao.cheng@linux.dev> In-Reply-To: <20260512055919.95716-1-kaitao.cheng@linux.dev> References: <20260512055919.95716-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 Reviewed-by: Eduard Zingerman --- 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 Tue May 26 04:49:42 2026 Received: from out-184.mta0.migadu.com (out-184.mta0.migadu.com [91.218.175.184]) (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 F0C8F406296; Tue, 12 May 2026 06:00:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.184 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778565629; cv=none; b=Z5ReX/87j9JbdZMTEPqyYOwqK0+vdYLo26ERSVjOYZtFEUYt9cNtulnElZ6KoG8//1q7tjG6a/m3+Bp/43PmaB2esTnDxymnAXeKi202w1IZJVxSTuUTIY4M4tTOvy0j+zXSIoeLkmkMJ5S8iJB1wbK07yxzc9h+rmtIg1/7BxY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778565629; c=relaxed/simple; bh=3/dhJ8s/gTLp5FfI4tzFmnbnLZHdbFW3dNsyriiTHY4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZXk1/dIu5KWGqKp0OaX3m8z5NJfwZAwqsSRgM1CMxNxHRjMNykRiZQJSHQosudo+Ulc7QvsWXUYZP4XBHS2Eyd4jNDj1oETUNP6tvVu9qsn5Hgf5jkLckhiVGmVBuyuJ8ChOaZDgt0GUibRGt+uWfKhNjdaAgxZfQ6wIKQD9ETs= 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=xhllyi74; arc=none smtp.client-ip=91.218.175.184 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="xhllyi74" 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=1778565610; 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=xhllyi74T2L3GxX3zb0Asw/m4N6jRSCbiR4nNypiwBz77STD8cLfd35WcMrD2PCj2DPoN7 f/QsTizLBZyliO+JDFTLyLFi40gx3AK1QplYrBWYR3i+UCn0wISrJzwvBpf9FWn5rC8dbz gOQ3PawcnxeKgU+aNLn1nJrMP2/YI8s= 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 RESEND bpf-next v10 7/8] bpf: allow non-owning list-node args via __nonown_allowed Date: Tue, 12 May 2026 13:59:18 +0800 Message-ID: <20260512055919.95716-8-kaitao.cheng@linux.dev> In-Reply-To: <20260512055919.95716-1-kaitao.cheng@linux.dev> References: <20260512055919.95716-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 Reviewed-by: Eduard Zingerman --- 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 Tue May 26 04:49:42 2026 Received: from out-184.mta0.migadu.com (out-184.mta0.migadu.com [91.218.175.184]) (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 7F58B407582 for ; Tue, 12 May 2026 06:00:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.184 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778565636; cv=none; b=JiXYvb/JfkmExmv3LLSFlMPS7O7fmFt4yABuMjgTdBAsPomXEhDr/HINLLja9vNwiBDGdPpZxoecZIGe/7S3vKMu0VxWTvU8aUBXJifeMzenuWusCrkFvuC6qFb1XoItDWRfX1lKcD7FrLwy1Nos97ToisOmB7aIUCCxZYjmgKI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778565636; c=relaxed/simple; bh=kRF9RHp407Fxt7W9NCJuN2XXVOJ+iJ65bCFZX7kuqVQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=q4ZGylWDzyuG+Pmb9AP0/AFJOQH42N5Ai/D37zrV2FVaZnXgqhNlpQRX7REP6gCrPuYnHYvyZKw11rCmD1XA994nXp399Z4CN+iY+Y/7EY6S/WTCqqngNKpn3wdEIzg8x/ZQcMh2F9RDXr0rZ5OROwIVRueq0D/aaBGJSEmUoB8= 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=e69zZ4NY; arc=none smtp.client-ip=91.218.175.184 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="e69zZ4NY" 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=1778565615; 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=e69zZ4NYpLqH1ixrjBCxt8xdNV3c8uTl91/qk5fjjo+D2jJ4gUpRgJJY1But4SRJmzLy1P bSrvUG5275oZU4ddcoe/Gii/nxI2KEzvTYTT5EcTEXaVEtWET8IUruoLixpZopTLx8AHd+ 52RgL1m5AsLWoF0Nv1qLIA4Ae9w1op4= 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 RESEND bpf-next v10 8/8] selftests/bpf: Add test cases for bpf_list_del/add/is_first/is_last/empty Date: Tue, 12 May 2026 13:59:19 +0800 Message-ID: <20260512055919.95716-9-kaitao.cheng@linux.dev> In-Reply-To: <20260512055919.95716-1-kaitao.cheng@linux.dev> References: <20260512055919.95716-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)