~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/bpf/progs/linked_list.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 #include <vmlinux.h>
  3 #include <bpf/bpf_tracing.h>
  4 #include <bpf/bpf_helpers.h>
  5 #include <bpf/bpf_core_read.h>
  6 #include "bpf_experimental.h"
  7 #include "bpf_misc.h"
  8 
  9 #include "linked_list.h"
 10 
 11 struct head_nested_inner {
 12         struct bpf_spin_lock lock;
 13         struct bpf_list_head head __contains(foo, node2);
 14 };
 15 
 16 struct head_nested {
 17         int dummy;
 18         struct head_nested_inner inner;
 19 };
 20 
 21 private(C) struct bpf_spin_lock glock_c;
 22 private(C) struct bpf_list_head ghead_array[2] __contains(foo, node2);
 23 private(C) struct bpf_list_head ghead_array_one[1] __contains(foo, node2);
 24 
 25 private(D) struct head_nested ghead_nested;
 26 
 27 static __always_inline
 28 int list_push_pop(struct bpf_spin_lock *lock, struct bpf_list_head *head, bool leave_in_map)
 29 {
 30         struct bpf_list_node *n;
 31         struct foo *f;
 32 
 33         f = bpf_obj_new(typeof(*f));
 34         if (!f)
 35                 return 2;
 36 
 37         bpf_spin_lock(lock);
 38         n = bpf_list_pop_front(head);
 39         bpf_spin_unlock(lock);
 40         if (n) {
 41                 bpf_obj_drop(container_of(n, struct foo, node2));
 42                 bpf_obj_drop(f);
 43                 return 3;
 44         }
 45 
 46         bpf_spin_lock(lock);
 47         n = bpf_list_pop_back(head);
 48         bpf_spin_unlock(lock);
 49         if (n) {
 50                 bpf_obj_drop(container_of(n, struct foo, node2));
 51                 bpf_obj_drop(f);
 52                 return 4;
 53         }
 54 
 55 
 56         bpf_spin_lock(lock);
 57         f->data = 42;
 58         bpf_list_push_front(head, &f->node2);
 59         bpf_spin_unlock(lock);
 60         if (leave_in_map)
 61                 return 0;
 62         bpf_spin_lock(lock);
 63         n = bpf_list_pop_back(head);
 64         bpf_spin_unlock(lock);
 65         if (!n)
 66                 return 5;
 67         f = container_of(n, struct foo, node2);
 68         if (f->data != 42) {
 69                 bpf_obj_drop(f);
 70                 return 6;
 71         }
 72 
 73         bpf_spin_lock(lock);
 74         f->data = 13;
 75         bpf_list_push_front(head, &f->node2);
 76         bpf_spin_unlock(lock);
 77         bpf_spin_lock(lock);
 78         n = bpf_list_pop_front(head);
 79         bpf_spin_unlock(lock);
 80         if (!n)
 81                 return 7;
 82         f = container_of(n, struct foo, node2);
 83         if (f->data != 13) {
 84                 bpf_obj_drop(f);
 85                 return 8;
 86         }
 87         bpf_obj_drop(f);
 88 
 89         bpf_spin_lock(lock);
 90         n = bpf_list_pop_front(head);
 91         bpf_spin_unlock(lock);
 92         if (n) {
 93                 bpf_obj_drop(container_of(n, struct foo, node2));
 94                 return 9;
 95         }
 96 
 97         bpf_spin_lock(lock);
 98         n = bpf_list_pop_back(head);
 99         bpf_spin_unlock(lock);
100         if (n) {
101                 bpf_obj_drop(container_of(n, struct foo, node2));
102                 return 10;
103         }
104         return 0;
105 }
106 
107 
108 static __always_inline
109 int list_push_pop_multiple(struct bpf_spin_lock *lock, struct bpf_list_head *head, bool leave_in_map)
110 {
111         struct bpf_list_node *n;
112         struct foo *f[200], *pf;
113         int i;
114 
115         /* Loop following this check adds nodes 2-at-a-time in order to
116          * validate multiple release_on_unlock release logic
117          */
118         if (ARRAY_SIZE(f) % 2)
119                 return 10;
120 
121         for (i = 0; i < ARRAY_SIZE(f); i += 2) {
122                 f[i] = bpf_obj_new(typeof(**f));
123                 if (!f[i])
124                         return 2;
125                 f[i]->data = i;
126 
127                 f[i + 1] = bpf_obj_new(typeof(**f));
128                 if (!f[i + 1]) {
129                         bpf_obj_drop(f[i]);
130                         return 9;
131                 }
132                 f[i + 1]->data = i + 1;
133 
134                 bpf_spin_lock(lock);
135                 bpf_list_push_front(head, &f[i]->node2);
136                 bpf_list_push_front(head, &f[i + 1]->node2);
137                 bpf_spin_unlock(lock);
138         }
139 
140         for (i = 0; i < ARRAY_SIZE(f); i++) {
141                 bpf_spin_lock(lock);
142                 n = bpf_list_pop_front(head);
143                 bpf_spin_unlock(lock);
144                 if (!n)
145                         return 3;
146                 pf = container_of(n, struct foo, node2);
147                 if (pf->data != (ARRAY_SIZE(f) - i - 1)) {
148                         bpf_obj_drop(pf);
149                         return 4;
150                 }
151                 bpf_spin_lock(lock);
152                 bpf_list_push_back(head, &pf->node2);
153                 bpf_spin_unlock(lock);
154         }
155 
156         if (leave_in_map)
157                 return 0;
158 
159         for (i = 0; i < ARRAY_SIZE(f); i++) {
160                 bpf_spin_lock(lock);
161                 n = bpf_list_pop_back(head);
162                 bpf_spin_unlock(lock);
163                 if (!n)
164                         return 5;
165                 pf = container_of(n, struct foo, node2);
166                 if (pf->data != i) {
167                         bpf_obj_drop(pf);
168                         return 6;
169                 }
170                 bpf_obj_drop(pf);
171         }
172         bpf_spin_lock(lock);
173         n = bpf_list_pop_back(head);
174         bpf_spin_unlock(lock);
175         if (n) {
176                 bpf_obj_drop(container_of(n, struct foo, node2));
177                 return 7;
178         }
179 
180         bpf_spin_lock(lock);
181         n = bpf_list_pop_front(head);
182         bpf_spin_unlock(lock);
183         if (n) {
184                 bpf_obj_drop(container_of(n, struct foo, node2));
185                 return 8;
186         }
187         return 0;
188 }
189 
190 static __always_inline
191 int list_in_list(struct bpf_spin_lock *lock, struct bpf_list_head *head, bool leave_in_map)
192 {
193         struct bpf_list_node *n;
194         struct bar *ba[8], *b;
195         struct foo *f;
196         int i;
197 
198         f = bpf_obj_new(typeof(*f));
199         if (!f)
200                 return 2;
201         for (i = 0; i < ARRAY_SIZE(ba); i++) {
202                 b = bpf_obj_new(typeof(*b));
203                 if (!b) {
204                         bpf_obj_drop(f);
205                         return 3;
206                 }
207                 b->data = i;
208                 bpf_spin_lock(&f->lock);
209                 bpf_list_push_back(&f->head, &b->node);
210                 bpf_spin_unlock(&f->lock);
211         }
212 
213         bpf_spin_lock(lock);
214         f->data = 42;
215         bpf_list_push_front(head, &f->node2);
216         bpf_spin_unlock(lock);
217 
218         if (leave_in_map)
219                 return 0;
220 
221         bpf_spin_lock(lock);
222         n = bpf_list_pop_front(head);
223         bpf_spin_unlock(lock);
224         if (!n)
225                 return 4;
226         f = container_of(n, struct foo, node2);
227         if (f->data != 42) {
228                 bpf_obj_drop(f);
229                 return 5;
230         }
231 
232         for (i = 0; i < ARRAY_SIZE(ba); i++) {
233                 bpf_spin_lock(&f->lock);
234                 n = bpf_list_pop_front(&f->head);
235                 bpf_spin_unlock(&f->lock);
236                 if (!n) {
237                         bpf_obj_drop(f);
238                         return 6;
239                 }
240                 b = container_of(n, struct bar, node);
241                 if (b->data != i) {
242                         bpf_obj_drop(f);
243                         bpf_obj_drop(b);
244                         return 7;
245                 }
246                 bpf_obj_drop(b);
247         }
248         bpf_spin_lock(&f->lock);
249         n = bpf_list_pop_front(&f->head);
250         bpf_spin_unlock(&f->lock);
251         if (n) {
252                 bpf_obj_drop(f);
253                 bpf_obj_drop(container_of(n, struct bar, node));
254                 return 8;
255         }
256         bpf_obj_drop(f);
257         return 0;
258 }
259 
260 static __always_inline
261 int test_list_push_pop(struct bpf_spin_lock *lock, struct bpf_list_head *head)
262 {
263         int ret;
264 
265         ret = list_push_pop(lock, head, false);
266         if (ret)
267                 return ret;
268         return list_push_pop(lock, head, true);
269 }
270 
271 static __always_inline
272 int test_list_push_pop_multiple(struct bpf_spin_lock *lock, struct bpf_list_head *head)
273 {
274         int ret;
275 
276         ret = list_push_pop_multiple(lock, head, false);
277         if (ret)
278                 return ret;
279         return list_push_pop_multiple(lock, head, true);
280 }
281 
282 static __always_inline
283 int test_list_in_list(struct bpf_spin_lock *lock, struct bpf_list_head *head)
284 {
285         int ret;
286 
287         ret = list_in_list(lock, head, false);
288         if (ret)
289                 return ret;
290         return list_in_list(lock, head, true);
291 }
292 
293 SEC("tc")
294 int map_list_push_pop(void *ctx)
295 {
296         struct map_value *v;
297 
298         v = bpf_map_lookup_elem(&array_map, &(int){0});
299         if (!v)
300                 return 1;
301         return test_list_push_pop(&v->lock, &v->head);
302 }
303 
304 SEC("tc")
305 int inner_map_list_push_pop(void *ctx)
306 {
307         struct map_value *v;
308         void *map;
309 
310         map = bpf_map_lookup_elem(&map_of_maps, &(int){0});
311         if (!map)
312                 return 1;
313         v = bpf_map_lookup_elem(map, &(int){0});
314         if (!v)
315                 return 1;
316         return test_list_push_pop(&v->lock, &v->head);
317 }
318 
319 SEC("tc")
320 int global_list_push_pop(void *ctx)
321 {
322         return test_list_push_pop(&glock, &ghead);
323 }
324 
325 SEC("tc")
326 int global_list_push_pop_nested(void *ctx)
327 {
328         return test_list_push_pop(&ghead_nested.inner.lock, &ghead_nested.inner.head);
329 }
330 
331 SEC("tc")
332 int global_list_array_push_pop(void *ctx)
333 {
334         int r;
335 
336         r = test_list_push_pop(&glock_c, &ghead_array[0]);
337         if (r)
338                 return r;
339 
340         r = test_list_push_pop(&glock_c, &ghead_array[1]);
341         if (r)
342                 return r;
343 
344         /* Arrays with only one element is a special case, being treated
345          * just like a bpf_list_head variable by the verifier, not an
346          * array.
347          */
348         return test_list_push_pop(&glock_c, &ghead_array_one[0]);
349 }
350 
351 SEC("tc")
352 int map_list_push_pop_multiple(void *ctx)
353 {
354         struct map_value *v;
355 
356         v = bpf_map_lookup_elem(&array_map, &(int){0});
357         if (!v)
358                 return 1;
359         return test_list_push_pop_multiple(&v->lock, &v->head);
360 }
361 
362 SEC("tc")
363 int inner_map_list_push_pop_multiple(void *ctx)
364 {
365         struct map_value *v;
366         void *map;
367 
368         map = bpf_map_lookup_elem(&map_of_maps, &(int){0});
369         if (!map)
370                 return 1;
371         v = bpf_map_lookup_elem(map, &(int){0});
372         if (!v)
373                 return 1;
374         return test_list_push_pop_multiple(&v->lock, &v->head);
375 }
376 
377 SEC("tc")
378 int global_list_push_pop_multiple(void *ctx)
379 {
380         int ret;
381 
382         ret = list_push_pop_multiple(&glock, &ghead, false);
383         if (ret)
384                 return ret;
385         return list_push_pop_multiple(&glock, &ghead, true);
386 }
387 
388 SEC("tc")
389 int map_list_in_list(void *ctx)
390 {
391         struct map_value *v;
392 
393         v = bpf_map_lookup_elem(&array_map, &(int){0});
394         if (!v)
395                 return 1;
396         return test_list_in_list(&v->lock, &v->head);
397 }
398 
399 SEC("tc")
400 int inner_map_list_in_list(void *ctx)
401 {
402         struct map_value *v;
403         void *map;
404 
405         map = bpf_map_lookup_elem(&map_of_maps, &(int){0});
406         if (!map)
407                 return 1;
408         v = bpf_map_lookup_elem(map, &(int){0});
409         if (!v)
410                 return 1;
411         return test_list_in_list(&v->lock, &v->head);
412 }
413 
414 SEC("tc")
415 int global_list_in_list(void *ctx)
416 {
417         return test_list_in_list(&glock, &ghead);
418 }
419 
420 char _license[] SEC("license") = "GPL";
421 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php