xref: /linux/tools/testing/selftests/bpf/progs/rbtree_search_kptr.c (revision 0fc8f6200d2313278fbf4539bbab74677c685531)
1580fa343SKaitao Cheng // SPDX-License-Identifier: GPL-2.0
2580fa343SKaitao Cheng /* Copyright (c) 2026 KylinSoft Corporation. */
3580fa343SKaitao Cheng 
4580fa343SKaitao Cheng #include <vmlinux.h>
5580fa343SKaitao Cheng #include <bpf/bpf_helpers.h>
6580fa343SKaitao Cheng #include "bpf_misc.h"
7580fa343SKaitao Cheng #include "bpf_experimental.h"
8580fa343SKaitao Cheng 
9580fa343SKaitao Cheng #define NR_NODES 16
10580fa343SKaitao Cheng 
11580fa343SKaitao Cheng struct node_data {
12580fa343SKaitao Cheng 	int data;
13580fa343SKaitao Cheng };
14580fa343SKaitao Cheng 
15580fa343SKaitao Cheng struct tree_node {
16580fa343SKaitao Cheng 	struct bpf_rb_node node;
17580fa343SKaitao Cheng 	u64 key;
18580fa343SKaitao Cheng 	struct node_data __kptr * node_data;
19580fa343SKaitao Cheng };
20580fa343SKaitao Cheng 
21*ed8fa4b8SKaitao Cheng struct tree_node_ref {
22*ed8fa4b8SKaitao Cheng 	struct bpf_refcount ref;
23*ed8fa4b8SKaitao Cheng 	struct bpf_rb_node node;
24*ed8fa4b8SKaitao Cheng 	u64 key;
25*ed8fa4b8SKaitao Cheng 	struct node_data __kptr * node_data;
26*ed8fa4b8SKaitao Cheng };
27*ed8fa4b8SKaitao Cheng 
28580fa343SKaitao Cheng #define private(name) SEC(".data." #name) __hidden __aligned(8)
29580fa343SKaitao Cheng 
30580fa343SKaitao Cheng private(A) struct bpf_rb_root root __contains(tree_node, node);
31580fa343SKaitao Cheng private(A) struct bpf_spin_lock lock;
32580fa343SKaitao Cheng 
33*ed8fa4b8SKaitao Cheng private(B) struct bpf_rb_root root_r __contains(tree_node_ref, node);
34*ed8fa4b8SKaitao Cheng private(B) struct bpf_spin_lock lock_r;
35*ed8fa4b8SKaitao Cheng 
36580fa343SKaitao Cheng static bool less(struct bpf_rb_node *a, const struct bpf_rb_node *b)
37580fa343SKaitao Cheng {
38580fa343SKaitao Cheng 	struct tree_node *node_a, *node_b;
39580fa343SKaitao Cheng 
40580fa343SKaitao Cheng 	node_a = container_of(a, struct tree_node, node);
41580fa343SKaitao Cheng 	node_b = container_of(b, struct tree_node, node);
42580fa343SKaitao Cheng 
43580fa343SKaitao Cheng 	return node_a->key < node_b->key;
44580fa343SKaitao Cheng }
45580fa343SKaitao Cheng 
46580fa343SKaitao Cheng SEC("syscall")
47580fa343SKaitao Cheng __retval(0)
48580fa343SKaitao Cheng long rbtree_search_kptr(void *ctx)
49580fa343SKaitao Cheng {
50580fa343SKaitao Cheng 	struct tree_node *tnode;
51580fa343SKaitao Cheng 	struct bpf_rb_node *rb_n;
52580fa343SKaitao Cheng 	struct node_data __kptr * node_data;
53580fa343SKaitao Cheng 	int lookup_key  = NR_NODES / 2;
54580fa343SKaitao Cheng 	int lookup_data = NR_NODES / 2;
55580fa343SKaitao Cheng 	int i, data, ret = 0;
56580fa343SKaitao Cheng 
57580fa343SKaitao Cheng 	for (i = 0; i < NR_NODES && can_loop; i++) {
58580fa343SKaitao Cheng 		tnode = bpf_obj_new(typeof(*tnode));
59580fa343SKaitao Cheng 		if (!tnode)
60580fa343SKaitao Cheng 			return __LINE__;
61580fa343SKaitao Cheng 
62580fa343SKaitao Cheng 		node_data = bpf_obj_new(typeof(*node_data));
63580fa343SKaitao Cheng 		if (!node_data) {
64580fa343SKaitao Cheng 			bpf_obj_drop(tnode);
65580fa343SKaitao Cheng 			return __LINE__;
66580fa343SKaitao Cheng 		}
67580fa343SKaitao Cheng 
68580fa343SKaitao Cheng 		tnode->key = i;
69580fa343SKaitao Cheng 		node_data->data = i;
70580fa343SKaitao Cheng 
71580fa343SKaitao Cheng 		node_data = bpf_kptr_xchg(&tnode->node_data, node_data);
72580fa343SKaitao Cheng 		if (node_data)
73580fa343SKaitao Cheng 			bpf_obj_drop(node_data);
74580fa343SKaitao Cheng 
75580fa343SKaitao Cheng 		bpf_spin_lock(&lock);
76580fa343SKaitao Cheng 		bpf_rbtree_add(&root, &tnode->node, less);
77580fa343SKaitao Cheng 		bpf_spin_unlock(&lock);
78580fa343SKaitao Cheng 	}
79580fa343SKaitao Cheng 
80580fa343SKaitao Cheng 	bpf_spin_lock(&lock);
81580fa343SKaitao Cheng 	rb_n = bpf_rbtree_root(&root);
82580fa343SKaitao Cheng 	while (rb_n && can_loop) {
83580fa343SKaitao Cheng 		tnode = container_of(rb_n, struct tree_node, node);
84580fa343SKaitao Cheng 		node_data = bpf_kptr_xchg(&tnode->node_data, NULL);
85580fa343SKaitao Cheng 		if (!node_data) {
86580fa343SKaitao Cheng 			ret = __LINE__;
87580fa343SKaitao Cheng 			goto fail;
88580fa343SKaitao Cheng 		}
89580fa343SKaitao Cheng 
90580fa343SKaitao Cheng 		data = node_data->data;
91580fa343SKaitao Cheng 		node_data = bpf_kptr_xchg(&tnode->node_data, node_data);
92580fa343SKaitao Cheng 		if (node_data) {
93580fa343SKaitao Cheng 			bpf_spin_unlock(&lock);
94580fa343SKaitao Cheng 			bpf_obj_drop(node_data);
95580fa343SKaitao Cheng 			return __LINE__;
96580fa343SKaitao Cheng 		}
97580fa343SKaitao Cheng 
98580fa343SKaitao Cheng 		if (lookup_key == tnode->key) {
99580fa343SKaitao Cheng 			if (data == lookup_data)
100580fa343SKaitao Cheng 				break;
101580fa343SKaitao Cheng 
102580fa343SKaitao Cheng 			ret = __LINE__;
103580fa343SKaitao Cheng 			goto fail;
104580fa343SKaitao Cheng 		}
105580fa343SKaitao Cheng 
106580fa343SKaitao Cheng 		if (lookup_key < tnode->key)
107580fa343SKaitao Cheng 			rb_n = bpf_rbtree_left(&root, rb_n);
108580fa343SKaitao Cheng 		else
109580fa343SKaitao Cheng 			rb_n = bpf_rbtree_right(&root, rb_n);
110580fa343SKaitao Cheng 	}
111580fa343SKaitao Cheng 	bpf_spin_unlock(&lock);
112580fa343SKaitao Cheng 
113580fa343SKaitao Cheng 	while (can_loop) {
114580fa343SKaitao Cheng 		bpf_spin_lock(&lock);
115580fa343SKaitao Cheng 		rb_n = bpf_rbtree_first(&root);
116580fa343SKaitao Cheng 		if (!rb_n) {
117580fa343SKaitao Cheng 			bpf_spin_unlock(&lock);
118580fa343SKaitao Cheng 			return 0;
119580fa343SKaitao Cheng 		}
120580fa343SKaitao Cheng 
121580fa343SKaitao Cheng 		rb_n = bpf_rbtree_remove(&root, rb_n);
122580fa343SKaitao Cheng 		if (!rb_n) {
123580fa343SKaitao Cheng 			ret = __LINE__;
124580fa343SKaitao Cheng 			goto fail;
125580fa343SKaitao Cheng 		}
126580fa343SKaitao Cheng 		bpf_spin_unlock(&lock);
127580fa343SKaitao Cheng 
128580fa343SKaitao Cheng 		tnode = container_of(rb_n, struct tree_node, node);
129580fa343SKaitao Cheng 
130580fa343SKaitao Cheng 		node_data = bpf_kptr_xchg(&tnode->node_data, NULL);
131580fa343SKaitao Cheng 		if (node_data)
132580fa343SKaitao Cheng 			bpf_obj_drop(node_data);
133580fa343SKaitao Cheng 
134580fa343SKaitao Cheng 		bpf_obj_drop(tnode);
135580fa343SKaitao Cheng 	}
136580fa343SKaitao Cheng 
137580fa343SKaitao Cheng 	return 0;
138580fa343SKaitao Cheng fail:
139580fa343SKaitao Cheng 	bpf_spin_unlock(&lock);
140580fa343SKaitao Cheng 	return ret;
141580fa343SKaitao Cheng }
142580fa343SKaitao Cheng 
143*ed8fa4b8SKaitao Cheng static bool less_r(struct bpf_rb_node *a, const struct bpf_rb_node *b)
144*ed8fa4b8SKaitao Cheng {
145*ed8fa4b8SKaitao Cheng 	struct tree_node_ref *node_a, *node_b;
146*ed8fa4b8SKaitao Cheng 
147*ed8fa4b8SKaitao Cheng 	node_a = container_of(a, struct tree_node_ref, node);
148*ed8fa4b8SKaitao Cheng 	node_b = container_of(b, struct tree_node_ref, node);
149*ed8fa4b8SKaitao Cheng 
150*ed8fa4b8SKaitao Cheng 	return node_a->key < node_b->key;
151*ed8fa4b8SKaitao Cheng }
152*ed8fa4b8SKaitao Cheng 
153*ed8fa4b8SKaitao Cheng SEC("syscall")
154*ed8fa4b8SKaitao Cheng __retval(0)
155*ed8fa4b8SKaitao Cheng long rbtree_search_kptr_ref(void *ctx)
156*ed8fa4b8SKaitao Cheng {
157*ed8fa4b8SKaitao Cheng 	struct tree_node_ref *tnode_r, *tnode_m;
158*ed8fa4b8SKaitao Cheng 	struct bpf_rb_node *rb_n;
159*ed8fa4b8SKaitao Cheng 	struct node_data __kptr * node_data;
160*ed8fa4b8SKaitao Cheng 	int lookup_key  = NR_NODES / 2;
161*ed8fa4b8SKaitao Cheng 	int lookup_data = NR_NODES / 2;
162*ed8fa4b8SKaitao Cheng 	int i, data, ret = 0;
163*ed8fa4b8SKaitao Cheng 
164*ed8fa4b8SKaitao Cheng 	for (i = 0; i < NR_NODES && can_loop; i++) {
165*ed8fa4b8SKaitao Cheng 		tnode_r = bpf_obj_new(typeof(*tnode_r));
166*ed8fa4b8SKaitao Cheng 		if (!tnode_r)
167*ed8fa4b8SKaitao Cheng 			return __LINE__;
168*ed8fa4b8SKaitao Cheng 
169*ed8fa4b8SKaitao Cheng 		node_data = bpf_obj_new(typeof(*node_data));
170*ed8fa4b8SKaitao Cheng 		if (!node_data) {
171*ed8fa4b8SKaitao Cheng 			bpf_obj_drop(tnode_r);
172*ed8fa4b8SKaitao Cheng 			return __LINE__;
173*ed8fa4b8SKaitao Cheng 		}
174*ed8fa4b8SKaitao Cheng 
175*ed8fa4b8SKaitao Cheng 		tnode_r->key = i;
176*ed8fa4b8SKaitao Cheng 		node_data->data = i;
177*ed8fa4b8SKaitao Cheng 
178*ed8fa4b8SKaitao Cheng 		node_data = bpf_kptr_xchg(&tnode_r->node_data, node_data);
179*ed8fa4b8SKaitao Cheng 		if (node_data)
180*ed8fa4b8SKaitao Cheng 			bpf_obj_drop(node_data);
181*ed8fa4b8SKaitao Cheng 
182*ed8fa4b8SKaitao Cheng 		/* Unused reference */
183*ed8fa4b8SKaitao Cheng 		tnode_m = bpf_refcount_acquire(tnode_r);
184*ed8fa4b8SKaitao Cheng 		if (!tnode_m)
185*ed8fa4b8SKaitao Cheng 			return __LINE__;
186*ed8fa4b8SKaitao Cheng 
187*ed8fa4b8SKaitao Cheng 		bpf_spin_lock(&lock_r);
188*ed8fa4b8SKaitao Cheng 		bpf_rbtree_add(&root_r, &tnode_r->node, less_r);
189*ed8fa4b8SKaitao Cheng 		bpf_spin_unlock(&lock_r);
190*ed8fa4b8SKaitao Cheng 
191*ed8fa4b8SKaitao Cheng 		bpf_obj_drop(tnode_m);
192*ed8fa4b8SKaitao Cheng 	}
193*ed8fa4b8SKaitao Cheng 
194*ed8fa4b8SKaitao Cheng 	bpf_spin_lock(&lock_r);
195*ed8fa4b8SKaitao Cheng 	rb_n = bpf_rbtree_root(&root_r);
196*ed8fa4b8SKaitao Cheng 	while (rb_n && can_loop) {
197*ed8fa4b8SKaitao Cheng 		tnode_r = container_of(rb_n, struct tree_node_ref, node);
198*ed8fa4b8SKaitao Cheng 		node_data = bpf_kptr_xchg(&tnode_r->node_data, NULL);
199*ed8fa4b8SKaitao Cheng 		if (!node_data) {
200*ed8fa4b8SKaitao Cheng 			ret = __LINE__;
201*ed8fa4b8SKaitao Cheng 			goto fail;
202*ed8fa4b8SKaitao Cheng 		}
203*ed8fa4b8SKaitao Cheng 
204*ed8fa4b8SKaitao Cheng 		data = node_data->data;
205*ed8fa4b8SKaitao Cheng 		node_data = bpf_kptr_xchg(&tnode_r->node_data, node_data);
206*ed8fa4b8SKaitao Cheng 		if (node_data) {
207*ed8fa4b8SKaitao Cheng 			bpf_spin_unlock(&lock_r);
208*ed8fa4b8SKaitao Cheng 			bpf_obj_drop(node_data);
209*ed8fa4b8SKaitao Cheng 			return __LINE__;
210*ed8fa4b8SKaitao Cheng 		}
211*ed8fa4b8SKaitao Cheng 
212*ed8fa4b8SKaitao Cheng 		if (lookup_key == tnode_r->key) {
213*ed8fa4b8SKaitao Cheng 			if (data == lookup_data)
214*ed8fa4b8SKaitao Cheng 				break;
215*ed8fa4b8SKaitao Cheng 
216*ed8fa4b8SKaitao Cheng 			ret = __LINE__;
217*ed8fa4b8SKaitao Cheng 			goto fail;
218*ed8fa4b8SKaitao Cheng 		}
219*ed8fa4b8SKaitao Cheng 
220*ed8fa4b8SKaitao Cheng 		if (lookup_key < tnode_r->key)
221*ed8fa4b8SKaitao Cheng 			rb_n = bpf_rbtree_left(&root_r, rb_n);
222*ed8fa4b8SKaitao Cheng 		else
223*ed8fa4b8SKaitao Cheng 			rb_n = bpf_rbtree_right(&root_r, rb_n);
224*ed8fa4b8SKaitao Cheng 	}
225*ed8fa4b8SKaitao Cheng 	bpf_spin_unlock(&lock_r);
226*ed8fa4b8SKaitao Cheng 
227*ed8fa4b8SKaitao Cheng 	while (can_loop) {
228*ed8fa4b8SKaitao Cheng 		bpf_spin_lock(&lock_r);
229*ed8fa4b8SKaitao Cheng 		rb_n = bpf_rbtree_first(&root_r);
230*ed8fa4b8SKaitao Cheng 		if (!rb_n) {
231*ed8fa4b8SKaitao Cheng 			bpf_spin_unlock(&lock_r);
232*ed8fa4b8SKaitao Cheng 			return 0;
233*ed8fa4b8SKaitao Cheng 		}
234*ed8fa4b8SKaitao Cheng 
235*ed8fa4b8SKaitao Cheng 		rb_n = bpf_rbtree_remove(&root_r, rb_n);
236*ed8fa4b8SKaitao Cheng 		if (!rb_n) {
237*ed8fa4b8SKaitao Cheng 			ret = __LINE__;
238*ed8fa4b8SKaitao Cheng 			goto fail;
239*ed8fa4b8SKaitao Cheng 		}
240*ed8fa4b8SKaitao Cheng 		bpf_spin_unlock(&lock_r);
241*ed8fa4b8SKaitao Cheng 
242*ed8fa4b8SKaitao Cheng 		tnode_r = container_of(rb_n, struct tree_node_ref, node);
243*ed8fa4b8SKaitao Cheng 
244*ed8fa4b8SKaitao Cheng 		node_data = bpf_kptr_xchg(&tnode_r->node_data, NULL);
245*ed8fa4b8SKaitao Cheng 		if (node_data)
246*ed8fa4b8SKaitao Cheng 			bpf_obj_drop(node_data);
247*ed8fa4b8SKaitao Cheng 
248*ed8fa4b8SKaitao Cheng 		bpf_obj_drop(tnode_r);
249*ed8fa4b8SKaitao Cheng 	}
250*ed8fa4b8SKaitao Cheng 
251*ed8fa4b8SKaitao Cheng 	return 0;
252*ed8fa4b8SKaitao Cheng fail:
253*ed8fa4b8SKaitao Cheng 	bpf_spin_unlock(&lock_r);
254*ed8fa4b8SKaitao Cheng 	return ret;
255*ed8fa4b8SKaitao Cheng }
256580fa343SKaitao Cheng 
257580fa343SKaitao Cheng SEC("syscall")
258580fa343SKaitao Cheng __failure __msg("R1 type=scalar expected=map_value, ptr_, ptr_")
259580fa343SKaitao Cheng long non_own_ref_kptr_xchg_no_lock(void *ctx)
260580fa343SKaitao Cheng {
261580fa343SKaitao Cheng 	struct tree_node *tnode;
262580fa343SKaitao Cheng 	struct bpf_rb_node *rb_n;
263580fa343SKaitao Cheng 	struct node_data __kptr * node_data;
264580fa343SKaitao Cheng 	int data;
265580fa343SKaitao Cheng 
266580fa343SKaitao Cheng 	bpf_spin_lock(&lock);
267580fa343SKaitao Cheng 	rb_n = bpf_rbtree_first(&root);
268580fa343SKaitao Cheng 	if (!rb_n) {
269580fa343SKaitao Cheng 		bpf_spin_unlock(&lock);
270580fa343SKaitao Cheng 		return __LINE__;
271580fa343SKaitao Cheng 	}
272580fa343SKaitao Cheng 	bpf_spin_unlock(&lock);
273580fa343SKaitao Cheng 
274580fa343SKaitao Cheng 	tnode = container_of(rb_n, struct tree_node, node);
275580fa343SKaitao Cheng 	node_data = bpf_kptr_xchg(&tnode->node_data, NULL);
276580fa343SKaitao Cheng 	if (!node_data)
277580fa343SKaitao Cheng 		return __LINE__;
278580fa343SKaitao Cheng 
279580fa343SKaitao Cheng 	data = node_data->data;
280580fa343SKaitao Cheng 	if (data < 0)
281580fa343SKaitao Cheng 		return __LINE__;
282580fa343SKaitao Cheng 
283580fa343SKaitao Cheng 	node_data = bpf_kptr_xchg(&tnode->node_data, node_data);
284580fa343SKaitao Cheng 	if (node_data)
285580fa343SKaitao Cheng 		return __LINE__;
286580fa343SKaitao Cheng 
287580fa343SKaitao Cheng 	return 0;
288580fa343SKaitao Cheng }
289580fa343SKaitao Cheng 
290580fa343SKaitao Cheng char _license[] SEC("license") = "GPL";
291