xref: /linux/tools/testing/selftests/bpf/bpf_arena_list.h (revision cffaefd15a8f423cdee5d8eac15d267bc92de314)
1 /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
2 /* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */
3 #pragma once
4 #include "bpf_arena_common.h"
5 
6 struct arena_list_node;
7 
8 typedef struct arena_list_node __arena arena_list_node_t;
9 
10 struct arena_list_node {
11 	arena_list_node_t *next;
12 	arena_list_node_t * __arena *pprev;
13 };
14 
15 struct arena_list_head {
16 	struct arena_list_node __arena *first;
17 };
18 typedef struct arena_list_head __arena arena_list_head_t;
19 
20 #define list_entry(ptr, type, member) arena_container_of(ptr, type, member)
21 
22 #define list_entry_safe(ptr, type, member) \
23 	({ typeof(*ptr) * ___ptr = (ptr); \
24 	 ___ptr ? ({ cast_kern(___ptr); list_entry(___ptr, type, member); }) : NULL; \
25 	 })
26 
27 #ifndef __BPF__
28 static inline void *bpf_iter_num_new(struct bpf_iter_num *it, int i, int j) { return NULL; }
29 static inline void bpf_iter_num_destroy(struct bpf_iter_num *it) {}
30 static inline bool bpf_iter_num_next(struct bpf_iter_num *it) { return true; }
31 #define cond_break ({})
32 #endif
33 
34 /* Safely walk link list elements. Deletion of elements is allowed. */
35 #define list_for_each_entry(pos, head, member)					\
36 	for (void * ___tmp = (pos = list_entry_safe((head)->first,		\
37 						    typeof(*(pos)), member),	\
38 			      (void *)0);					\
39 	     pos && ({ ___tmp = (void *)pos->member.next; 1; });		\
40 	     cond_break,							\
41 	     pos = list_entry_safe((void __arena *)___tmp, typeof(*(pos)), member))
42 
43 static inline void list_add_head(arena_list_node_t *n, arena_list_head_t *h)
44 {
45 	arena_list_node_t *first = h->first, * __arena *tmp;
46 
47 	cast_user(first);
48 	cast_kern(n);
49 	WRITE_ONCE(n->next, first);
50 	cast_kern(first);
51 	if (first) {
52 		tmp = &n->next;
53 		cast_user(tmp);
54 		WRITE_ONCE(first->pprev, tmp);
55 	}
56 	cast_user(n);
57 	WRITE_ONCE(h->first, n);
58 
59 	tmp = &h->first;
60 	cast_user(tmp);
61 	cast_kern(n);
62 	WRITE_ONCE(n->pprev, tmp);
63 }
64 
65 static inline void __list_del(arena_list_node_t *n)
66 {
67 	arena_list_node_t *next = n->next, *tmp;
68 	arena_list_node_t * __arena *pprev = n->pprev;
69 
70 	cast_user(next);
71 	cast_kern(pprev);
72 	tmp = *pprev;
73 	cast_kern(tmp);
74 	WRITE_ONCE(tmp, next);
75 	if (next) {
76 		cast_user(pprev);
77 		cast_kern(next);
78 		WRITE_ONCE(next->pprev, pprev);
79 	}
80 }
81 
82 #define POISON_POINTER_DELTA 0
83 
84 #define LIST_POISON1  ((void __arena *) 0x100 + POISON_POINTER_DELTA)
85 #define LIST_POISON2  ((void __arena *) 0x122 + POISON_POINTER_DELTA)
86 
87 static inline void list_del(arena_list_node_t *n)
88 {
89 	__list_del(n);
90 	n->next = LIST_POISON1;
91 	n->pprev = LIST_POISON2;
92 }
93