From: Leon Hwang <leon.hwang@linux.dev>
To: Chengkaitao <pilgrimtao@gmail.com>,
martin.lau@linux.dev, ast@kernel.org, daniel@iogearbox.net,
andrii@kernel.org, eddyz87@gmail.com, song@kernel.org,
yonghong.song@linux.dev, john.fastabend@gmail.com,
kpsingh@kernel.org, sdf@fomichev.me, haoluo@google.com,
jolsa@kernel.org, shuah@kernel.org, chengkaitao@kylinos.cn,
linux-kselftest@vger.kernel.org
Cc: bpf@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v4 5/6] bpf: add bpf_list_is_first/last/empty kfuncs
Date: Wed, 4 Mar 2026 11:30:07 +0800 [thread overview]
Message-ID: <37bdb73c-095b-4239-806b-8ea51a2d27a5@linux.dev> (raw)
In-Reply-To: <20260303135219.33726-6-pilgrimtao@gmail.com>
On 3/3/26 21:52, Chengkaitao wrote:
> From: Kaitao Cheng <chengkaitao@kylinos.cn>
>
> 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.
>
> In previous versions, to implement the above functionality, it was
> 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 <chengkaitao@kylinos.cn>
> ---
> kernel/bpf/helpers.c | 41 +++++++++++++++++++++++++++++++++++++++++
> kernel/bpf/verifier.c | 15 +++++++++++++--
> 2 files changed, 54 insertions(+), 2 deletions(-)
>
> diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
> index 488810da8f30..3a64a9bab06b 100644
> --- a/kernel/bpf/helpers.c
> +++ b/kernel/bpf/helpers.c
> @@ -2523,6 +2523,44 @@ __bpf_kfunc int bpf_list_add_impl(struct bpf_list_head *head,
> return 0;
> }
>
> +__bpf_kfunc bool bpf_list_is_first(struct bpf_list_head *head, struct bpf_list_node *node)
> +{
> + struct list_head *h = (struct list_head *)head;
> + struct bpf_list_node_kern *n = (struct bpf_list_node_kern *)node;
> +
> + if (unlikely(!h->next) || list_empty(h))
> + return false;
> +
> + if (READ_ONCE(n->owner) != head)
> + return false;
> +
> + return h->next == &n->list_head;
> +}
> +
> +__bpf_kfunc bool bpf_list_is_last(struct bpf_list_head *head, struct bpf_list_node *node)
> +{
> + struct list_head *h = (struct list_head *)head;
> + struct bpf_list_node_kern *n = (struct bpf_list_node_kern *)node;
> +
> + if (unlikely(!h->next) || list_empty(h))
> + return false;
> +
> + if (READ_ONCE(n->owner) != head)
> + return false;
> +
> + return h->prev == &n->list_head;
> +}
> +
bpf_list_is_first() and bpf_list_is_last() are nearly identical. The
duplicated code should be avoided.
> +__bpf_kfunc bool bpf_list_empty(struct bpf_list_head *head)
> +{
> + struct list_head *h = (struct list_head *)head;
> +
> + if (unlikely(!h->next))
> + return true;
NIT: A comment here explaining why !h->next returns true would be helpful.
Thanks,
Leon
> +
> + return list_empty(h);
> +}
> +
> __bpf_kfunc struct bpf_rb_node *bpf_rbtree_remove(struct bpf_rb_root *root,
> struct bpf_rb_node *node)
> {
> @@ -4593,6 +4631,9 @@ 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_add_impl)
> +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 6dfd4afff1cf..78652ccd2a89 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -12465,6 +12465,9 @@ enum special_kfunc_type {
> KF_bpf_list_front,
> KF_bpf_list_back,
> KF_bpf_list_add_impl,
> + 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,
> @@ -12527,6 +12530,9 @@ BTF_ID(func, bpf_list_del)
> BTF_ID(func, bpf_list_front)
> BTF_ID(func, bpf_list_back)
> BTF_ID(func, bpf_list_add_impl)
> +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)
> @@ -13003,7 +13009,10 @@ static bool is_bpf_list_api_kfunc(u32 btf_id)
> btf_id == special_kfunc_list[KF_bpf_list_del] ||
> btf_id == special_kfunc_list[KF_bpf_list_front] ||
> btf_id == special_kfunc_list[KF_bpf_list_back] ||
> - btf_id == special_kfunc_list[KF_bpf_list_add_impl];
> + btf_id == special_kfunc_list[KF_bpf_list_add_impl] ||
> + btf_id == special_kfunc_list[KF_bpf_list_is_first] ||
> + btf_id == special_kfunc_list[KF_bpf_list_is_last] ||
> + btf_id == special_kfunc_list[KF_bpf_list_empty];
> }
>
> static bool is_bpf_rbtree_api_kfunc(u32 btf_id)
> @@ -13126,7 +13135,9 @@ static bool check_kfunc_is_graph_node_api(struct bpf_verifier_env *env,
> ret = (kfunc_btf_id == special_kfunc_list[KF_bpf_list_push_front_impl] ||
> kfunc_btf_id == special_kfunc_list[KF_bpf_list_push_back_impl] ||
> kfunc_btf_id == special_kfunc_list[KF_bpf_list_del] ||
> - kfunc_btf_id == special_kfunc_list[KF_bpf_list_add_impl]);
> + kfunc_btf_id == special_kfunc_list[KF_bpf_list_add_impl] ||
> + kfunc_btf_id == special_kfunc_list[KF_bpf_list_is_first] ||
> + kfunc_btf_id == special_kfunc_list[KF_bpf_list_is_last]);
> break;
> case BPF_RB_NODE:
> ret = (kfunc_btf_id == special_kfunc_list[KF_bpf_rbtree_remove] ||
next prev parent reply other threads:[~2026-03-04 3:30 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-03 13:52 [PATCH v4 0/6] bpf: Extend the bpf_list family of APIs Chengkaitao
2026-03-03 13:52 ` [PATCH v4 1/6] bpf: Introduce the bpf_list_del kfunc Chengkaitao
2026-03-04 3:27 ` Leon Hwang
2026-03-03 13:52 ` [PATCH v4 2/6] selftests/bpf: Add test cases for bpf_list_del Chengkaitao
2026-03-04 3:27 ` Leon Hwang
2026-03-03 13:52 ` [PATCH v4 3/6] bpf: add bpf_list_add_impl to insert node after a given list node Chengkaitao
2026-03-03 14:40 ` bot+bpf-ci
2026-03-04 3:29 ` Leon Hwang
2026-03-03 13:52 ` [PATCH v4 4/6] selftests/bpf: Add test case for bpf_list_add_impl Chengkaitao
2026-03-03 13:52 ` [PATCH v4 5/6] bpf: add bpf_list_is_first/last/empty kfuncs Chengkaitao
2026-03-04 3:30 ` Leon Hwang [this message]
2026-03-03 13:52 ` [PATCH v4 6/6] selftests/bpf: Add test cases for bpf_list_is_first/is_last/empty Chengkaitao
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=37bdb73c-095b-4239-806b-8ea51a2d27a5@linux.dev \
--to=leon.hwang@linux.dev \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=chengkaitao@kylinos.cn \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=haoluo@google.com \
--cc=john.fastabend@gmail.com \
--cc=jolsa@kernel.org \
--cc=kpsingh@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=martin.lau@linux.dev \
--cc=pilgrimtao@gmail.com \
--cc=sdf@fomichev.me \
--cc=shuah@kernel.org \
--cc=song@kernel.org \
--cc=yonghong.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.