xref: /linux/tools/testing/selftests/bpf/progs/test_bpf_ma.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2023. Huawei Technologies Co., Ltd */
3 #include <vmlinux.h>
4 #include <bpf/bpf_tracing.h>
5 #include <bpf/bpf_helpers.h>
6 
7 #include "bpf_experimental.h"
8 #include "bpf_misc.h"
9 
10 struct generic_map_value {
11 	void *data;
12 };
13 
14 char _license[] SEC("license") = "GPL";
15 
16 const unsigned int data_sizes[] = {16, 32, 64, 96, 128, 192, 256, 512, 1024, 2048, 4096};
17 const volatile unsigned int data_btf_ids[ARRAY_SIZE(data_sizes)] = {};
18 
19 const unsigned int percpu_data_sizes[] = {8, 16, 32, 64, 96, 128, 192, 256, 512};
20 const volatile unsigned int percpu_data_btf_ids[ARRAY_SIZE(data_sizes)] = {};
21 
22 int err = 0;
23 u32 pid = 0;
24 
25 #define DEFINE_ARRAY_WITH_KPTR(_size) \
26 	struct bin_data_##_size { \
27 		char data[_size - sizeof(void *)]; \
28 	}; \
29 	/* See Commit 5d8d6634ccc, force btf generation for type bin_data_##_size */	\
30 	struct bin_data_##_size *__bin_data_##_size; \
31 	struct map_value_##_size { \
32 		struct bin_data_##_size __kptr * data; \
33 	}; \
34 	struct { \
35 		__uint(type, BPF_MAP_TYPE_ARRAY); \
36 		__type(key, int); \
37 		__type(value, struct map_value_##_size); \
38 		__uint(max_entries, 128); \
39 	} array_##_size SEC(".maps")
40 
41 #define DEFINE_ARRAY_WITH_PERCPU_KPTR(_size) \
42 	struct percpu_bin_data_##_size { \
43 		char data[_size]; \
44 	}; \
45 	struct percpu_bin_data_##_size *__percpu_bin_data_##_size; \
46 	struct map_value_percpu_##_size { \
47 		struct percpu_bin_data_##_size __percpu_kptr * data; \
48 	}; \
49 	struct { \
50 		__uint(type, BPF_MAP_TYPE_ARRAY); \
51 		__type(key, int); \
52 		__type(value, struct map_value_percpu_##_size); \
53 		__uint(max_entries, 128); \
54 	} array_percpu_##_size SEC(".maps")
55 
batch_alloc(struct bpf_map * map,unsigned int batch,unsigned int idx)56 static __always_inline void batch_alloc(struct bpf_map *map, unsigned int batch, unsigned int idx)
57 {
58 	struct generic_map_value *value;
59 	unsigned int i, key;
60 	void *old, *new;
61 
62 	for (i = 0; i < batch; i++) {
63 		key = i;
64 		value = bpf_map_lookup_elem(map, &key);
65 		if (!value) {
66 			err = 1;
67 			return;
68 		}
69 		new = bpf_obj_new_impl(data_btf_ids[idx], NULL);
70 		if (!new) {
71 			err = 2;
72 			return;
73 		}
74 		old = bpf_kptr_xchg(&value->data, new);
75 		if (old) {
76 			bpf_obj_drop(old);
77 			err = 3;
78 			return;
79 		}
80 	}
81 }
82 
batch_free(struct bpf_map * map,unsigned int batch,unsigned int idx)83 static __always_inline void batch_free(struct bpf_map *map, unsigned int batch, unsigned int idx)
84 {
85 	struct generic_map_value *value;
86 	unsigned int i, key;
87 	void *old;
88 
89 	for (i = 0; i < batch; i++) {
90 		key = i;
91 		value = bpf_map_lookup_elem(map, &key);
92 		if (!value) {
93 			err = 4;
94 			return;
95 		}
96 		old = bpf_kptr_xchg(&value->data, NULL);
97 		if (!old) {
98 			err = 5;
99 			return;
100 		}
101 		bpf_obj_drop(old);
102 	}
103 }
104 
batch_percpu_alloc(struct bpf_map * map,unsigned int batch,unsigned int idx)105 static __always_inline void batch_percpu_alloc(struct bpf_map *map, unsigned int batch,
106 					       unsigned int idx)
107 {
108 	struct generic_map_value *value;
109 	unsigned int i, key;
110 	void *old, *new;
111 
112 	for (i = 0; i < batch; i++) {
113 		key = i;
114 		value = bpf_map_lookup_elem(map, &key);
115 		if (!value) {
116 			err = 1;
117 			return;
118 		}
119 		/* per-cpu allocator may not be able to refill in time */
120 		new = bpf_percpu_obj_new_impl(percpu_data_btf_ids[idx], NULL);
121 		if (!new)
122 			continue;
123 
124 		old = bpf_kptr_xchg(&value->data, new);
125 		if (old) {
126 			bpf_percpu_obj_drop(old);
127 			err = 2;
128 			return;
129 		}
130 	}
131 }
132 
batch_percpu_free(struct bpf_map * map,unsigned int batch,unsigned int idx)133 static __always_inline void batch_percpu_free(struct bpf_map *map, unsigned int batch,
134 					      unsigned int idx)
135 {
136 	struct generic_map_value *value;
137 	unsigned int i, key;
138 	void *old;
139 
140 	for (i = 0; i < batch; i++) {
141 		key = i;
142 		value = bpf_map_lookup_elem(map, &key);
143 		if (!value) {
144 			err = 3;
145 			return;
146 		}
147 		old = bpf_kptr_xchg(&value->data, NULL);
148 		if (!old)
149 			continue;
150 		bpf_percpu_obj_drop(old);
151 	}
152 }
153 
154 #define CALL_BATCH_ALLOC(size, batch, idx) \
155 	batch_alloc((struct bpf_map *)(&array_##size), batch, idx)
156 
157 #define CALL_BATCH_ALLOC_FREE(size, batch, idx) \
158 	do { \
159 		batch_alloc((struct bpf_map *)(&array_##size), batch, idx); \
160 		batch_free((struct bpf_map *)(&array_##size), batch, idx); \
161 	} while (0)
162 
163 #define CALL_BATCH_PERCPU_ALLOC(size, batch, idx) \
164 	batch_percpu_alloc((struct bpf_map *)(&array_percpu_##size), batch, idx)
165 
166 #define CALL_BATCH_PERCPU_ALLOC_FREE(size, batch, idx) \
167 	do { \
168 		batch_percpu_alloc((struct bpf_map *)(&array_percpu_##size), batch, idx); \
169 		batch_percpu_free((struct bpf_map *)(&array_percpu_##size), batch, idx); \
170 	} while (0)
171 
172 /* kptr doesn't support bin_data_8 which is a zero-sized array */
173 DEFINE_ARRAY_WITH_KPTR(16);
174 DEFINE_ARRAY_WITH_KPTR(32);
175 DEFINE_ARRAY_WITH_KPTR(64);
176 DEFINE_ARRAY_WITH_KPTR(96);
177 DEFINE_ARRAY_WITH_KPTR(128);
178 DEFINE_ARRAY_WITH_KPTR(192);
179 DEFINE_ARRAY_WITH_KPTR(256);
180 DEFINE_ARRAY_WITH_KPTR(512);
181 DEFINE_ARRAY_WITH_KPTR(1024);
182 DEFINE_ARRAY_WITH_KPTR(2048);
183 DEFINE_ARRAY_WITH_KPTR(4096);
184 
185 DEFINE_ARRAY_WITH_PERCPU_KPTR(8);
186 DEFINE_ARRAY_WITH_PERCPU_KPTR(16);
187 DEFINE_ARRAY_WITH_PERCPU_KPTR(32);
188 DEFINE_ARRAY_WITH_PERCPU_KPTR(64);
189 DEFINE_ARRAY_WITH_PERCPU_KPTR(96);
190 DEFINE_ARRAY_WITH_PERCPU_KPTR(128);
191 DEFINE_ARRAY_WITH_PERCPU_KPTR(192);
192 DEFINE_ARRAY_WITH_PERCPU_KPTR(256);
193 DEFINE_ARRAY_WITH_PERCPU_KPTR(512);
194 
195 SEC("?fentry/" SYS_PREFIX "sys_nanosleep")
test_batch_alloc_free(void * ctx)196 int test_batch_alloc_free(void *ctx)
197 {
198 	if ((u32)bpf_get_current_pid_tgid() != pid)
199 		return 0;
200 
201 	/* Alloc 128 16-bytes objects in batch to trigger refilling,
202 	 * then free 128 16-bytes objects in batch to trigger freeing.
203 	 */
204 	CALL_BATCH_ALLOC_FREE(16, 128, 0);
205 	CALL_BATCH_ALLOC_FREE(32, 128, 1);
206 	CALL_BATCH_ALLOC_FREE(64, 128, 2);
207 	CALL_BATCH_ALLOC_FREE(96, 128, 3);
208 	CALL_BATCH_ALLOC_FREE(128, 128, 4);
209 	CALL_BATCH_ALLOC_FREE(192, 128, 5);
210 	CALL_BATCH_ALLOC_FREE(256, 128, 6);
211 	CALL_BATCH_ALLOC_FREE(512, 64, 7);
212 	CALL_BATCH_ALLOC_FREE(1024, 32, 8);
213 	CALL_BATCH_ALLOC_FREE(2048, 16, 9);
214 	CALL_BATCH_ALLOC_FREE(4096, 8, 10);
215 
216 	return 0;
217 }
218 
219 SEC("?fentry/" SYS_PREFIX "sys_nanosleep")
test_free_through_map_free(void * ctx)220 int test_free_through_map_free(void *ctx)
221 {
222 	if ((u32)bpf_get_current_pid_tgid() != pid)
223 		return 0;
224 
225 	/* Alloc 128 16-bytes objects in batch to trigger refilling,
226 	 * then free these objects through map free.
227 	 */
228 	CALL_BATCH_ALLOC(16, 128, 0);
229 	CALL_BATCH_ALLOC(32, 128, 1);
230 	CALL_BATCH_ALLOC(64, 128, 2);
231 	CALL_BATCH_ALLOC(96, 128, 3);
232 	CALL_BATCH_ALLOC(128, 128, 4);
233 	CALL_BATCH_ALLOC(192, 128, 5);
234 	CALL_BATCH_ALLOC(256, 128, 6);
235 	CALL_BATCH_ALLOC(512, 64, 7);
236 	CALL_BATCH_ALLOC(1024, 32, 8);
237 	CALL_BATCH_ALLOC(2048, 16, 9);
238 	CALL_BATCH_ALLOC(4096, 8, 10);
239 
240 	return 0;
241 }
242 
243 SEC("?fentry/" SYS_PREFIX "sys_nanosleep")
test_batch_percpu_alloc_free(void * ctx)244 int test_batch_percpu_alloc_free(void *ctx)
245 {
246 	if ((u32)bpf_get_current_pid_tgid() != pid)
247 		return 0;
248 
249 	/* Alloc 128 8-bytes per-cpu objects in batch to trigger refilling,
250 	 * then free 128 8-bytes per-cpu objects in batch to trigger freeing.
251 	 */
252 	CALL_BATCH_PERCPU_ALLOC_FREE(8, 128, 0);
253 	CALL_BATCH_PERCPU_ALLOC_FREE(16, 128, 1);
254 	CALL_BATCH_PERCPU_ALLOC_FREE(32, 128, 2);
255 	CALL_BATCH_PERCPU_ALLOC_FREE(64, 128, 3);
256 	CALL_BATCH_PERCPU_ALLOC_FREE(96, 128, 4);
257 	CALL_BATCH_PERCPU_ALLOC_FREE(128, 128, 5);
258 	CALL_BATCH_PERCPU_ALLOC_FREE(192, 128, 6);
259 	CALL_BATCH_PERCPU_ALLOC_FREE(256, 128, 7);
260 	CALL_BATCH_PERCPU_ALLOC_FREE(512, 64, 8);
261 
262 	return 0;
263 }
264 
265 SEC("?fentry/" SYS_PREFIX "sys_nanosleep")
test_percpu_free_through_map_free(void * ctx)266 int test_percpu_free_through_map_free(void *ctx)
267 {
268 	if ((u32)bpf_get_current_pid_tgid() != pid)
269 		return 0;
270 
271 	/* Alloc 128 8-bytes per-cpu objects in batch to trigger refilling,
272 	 * then free these object through map free.
273 	 */
274 	CALL_BATCH_PERCPU_ALLOC(8, 128, 0);
275 	CALL_BATCH_PERCPU_ALLOC(16, 128, 1);
276 	CALL_BATCH_PERCPU_ALLOC(32, 128, 2);
277 	CALL_BATCH_PERCPU_ALLOC(64, 128, 3);
278 	CALL_BATCH_PERCPU_ALLOC(96, 128, 4);
279 	CALL_BATCH_PERCPU_ALLOC(128, 128, 5);
280 	CALL_BATCH_PERCPU_ALLOC(192, 128, 6);
281 	CALL_BATCH_PERCPU_ALLOC(256, 128, 7);
282 	CALL_BATCH_PERCPU_ALLOC(512, 64, 8);
283 
284 	return 0;
285 }
286