Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf: Add bpf_list_{front,back} kfunc

In the kernel fq qdisc implementation, it only needs to look at
the fields of the first node in a list but does not always
need to remove it from the list. It is more convenient to have
a peek kfunc for the list. It works similar to the bpf_rbtree_first().

This patch adds bpf_list_{front,back} kfunc. The verifier is changed
such that the kfunc returning "struct bpf_list_node *" will be
marked as non-owning. The exception is the KF_ACQUIRE kfunc. The
net effect is only the new bpf_list_{front,back} kfuncs will
have its return pointer marked as non-owning.

Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Link: https://lore.kernel.org/r/20250506015857.817950-8-martin.lau@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Martin KaFai Lau and committed by
Alexei Starovoitov
fb5b4802 3fab84f0

+32 -2
+22
kernel/bpf/helpers.c
··· 2293 2293 return __bpf_list_del(head, true); 2294 2294 } 2295 2295 2296 + __bpf_kfunc struct bpf_list_node *bpf_list_front(struct bpf_list_head *head) 2297 + { 2298 + struct list_head *h = (struct list_head *)head; 2299 + 2300 + if (list_empty(h) || unlikely(!h->next)) 2301 + return NULL; 2302 + 2303 + return (struct bpf_list_node *)h->next; 2304 + } 2305 + 2306 + __bpf_kfunc struct bpf_list_node *bpf_list_back(struct bpf_list_head *head) 2307 + { 2308 + struct list_head *h = (struct list_head *)head; 2309 + 2310 + if (list_empty(h) || unlikely(!h->next)) 2311 + return NULL; 2312 + 2313 + return (struct bpf_list_node *)h->prev; 2314 + } 2315 + 2296 2316 __bpf_kfunc struct bpf_rb_node *bpf_rbtree_remove(struct bpf_rb_root *root, 2297 2317 struct bpf_rb_node *node) 2298 2318 { ··· 3256 3236 BTF_ID_FLAGS(func, bpf_list_push_back_impl) 3257 3237 BTF_ID_FLAGS(func, bpf_list_pop_front, KF_ACQUIRE | KF_RET_NULL) 3258 3238 BTF_ID_FLAGS(func, bpf_list_pop_back, KF_ACQUIRE | KF_RET_NULL) 3239 + BTF_ID_FLAGS(func, bpf_list_front, KF_RET_NULL) 3240 + BTF_ID_FLAGS(func, bpf_list_back, KF_RET_NULL) 3259 3241 BTF_ID_FLAGS(func, bpf_task_acquire, KF_ACQUIRE | KF_RCU | KF_RET_NULL) 3260 3242 BTF_ID_FLAGS(func, bpf_task_release, KF_RELEASE) 3261 3243 BTF_ID_FLAGS(func, bpf_rbtree_remove, KF_ACQUIRE | KF_RET_NULL)
+10 -2
kernel/bpf/verifier.c
··· 12079 12079 KF_bpf_list_push_back_impl, 12080 12080 KF_bpf_list_pop_front, 12081 12081 KF_bpf_list_pop_back, 12082 + KF_bpf_list_front, 12083 + KF_bpf_list_back, 12082 12084 KF_bpf_cast_to_kern_ctx, 12083 12085 KF_bpf_rdonly_cast, 12084 12086 KF_bpf_rcu_read_lock, ··· 12126 12124 BTF_ID(func, bpf_list_push_back_impl) 12127 12125 BTF_ID(func, bpf_list_pop_front) 12128 12126 BTF_ID(func, bpf_list_pop_back) 12127 + BTF_ID(func, bpf_list_front) 12128 + BTF_ID(func, bpf_list_back) 12129 12129 BTF_ID(func, bpf_cast_to_kern_ctx) 12130 12130 BTF_ID(func, bpf_rdonly_cast) 12131 12131 BTF_ID(func, bpf_rbtree_remove) ··· 12164 12160 BTF_ID(func, bpf_list_push_back_impl) 12165 12161 BTF_ID(func, bpf_list_pop_front) 12166 12162 BTF_ID(func, bpf_list_pop_back) 12163 + BTF_ID(func, bpf_list_front) 12164 + BTF_ID(func, bpf_list_back) 12167 12165 BTF_ID(func, bpf_cast_to_kern_ctx) 12168 12166 BTF_ID(func, bpf_rdonly_cast) 12169 12167 BTF_ID(func, bpf_rcu_read_lock) ··· 12604 12598 return btf_id == special_kfunc_list[KF_bpf_list_push_front_impl] || 12605 12599 btf_id == special_kfunc_list[KF_bpf_list_push_back_impl] || 12606 12600 btf_id == special_kfunc_list[KF_bpf_list_pop_front] || 12607 - btf_id == special_kfunc_list[KF_bpf_list_pop_back]; 12601 + btf_id == special_kfunc_list[KF_bpf_list_pop_back] || 12602 + btf_id == special_kfunc_list[KF_bpf_list_front] || 12603 + btf_id == special_kfunc_list[KF_bpf_list_back]; 12608 12604 } 12609 12605 12610 12606 static bool is_bpf_rbtree_api_kfunc(u32 btf_id) ··· 13911 13903 if (is_kfunc_ret_null(&meta)) 13912 13904 regs[BPF_REG_0].id = id; 13913 13905 regs[BPF_REG_0].ref_obj_id = id; 13914 - } else if (is_rbtree_node_type(ptr_type)) { 13906 + } else if (is_rbtree_node_type(ptr_type) || is_list_node_type(ptr_type)) { 13915 13907 ref_set_non_owning(env, &regs[BPF_REG_0]); 13916 13908 } 13917 13909