1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
3 
4 #define _GNU_SOURCE
5 #include <linux/compiler.h>
6 #include <linux/ring_buffer.h>
7 #include <linux/build_bug.h>
8 #include <pthread.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <sys/mman.h>
12 #include <sys/syscall.h>
13 #include <sys/sysinfo.h>
14 #include <test_progs.h>
15 #include <uapi/linux/bpf.h>
16 #include <unistd.h>
17 
18 #include "user_ringbuf_fail.skel.h"
19 #include "user_ringbuf_success.skel.h"
20 
21 #include "../progs/test_user_ringbuf.h"
22 
23 static const long c_sample_size = sizeof(struct sample) + BPF_RINGBUF_HDR_SZ;
24 static const long c_ringbuf_size = 1 << 12; /* 1 small page */
25 static const long c_max_entries = c_ringbuf_size / c_sample_size;
26 
drain_current_samples(void)27 static void drain_current_samples(void)
28 {
29 	syscall(__NR_getpgid);
30 }
31 
write_samples(struct user_ring_buffer * ringbuf,uint32_t num_samples)32 static int write_samples(struct user_ring_buffer *ringbuf, uint32_t num_samples)
33 {
34 	int i, err = 0;
35 
36 	/* Write some number of samples to the ring buffer. */
37 	for (i = 0; i < num_samples; i++) {
38 		struct sample *entry;
39 		int read;
40 
41 		entry = user_ring_buffer__reserve(ringbuf, sizeof(*entry));
42 		if (!entry) {
43 			err = -errno;
44 			goto done;
45 		}
46 
47 		entry->pid = getpid();
48 		entry->seq = i;
49 		entry->value = i * i;
50 
51 		read = snprintf(entry->comm, sizeof(entry->comm), "%u", i);
52 		if (read <= 0) {
53 			/* Assert on the error path to avoid spamming logs with
54 			 * mostly success messages.
55 			 */
56 			ASSERT_GT(read, 0, "snprintf_comm");
57 			err = read;
58 			user_ring_buffer__discard(ringbuf, entry);
59 			goto done;
60 		}
61 
62 		user_ring_buffer__submit(ringbuf, entry);
63 	}
64 
65 done:
66 	drain_current_samples();
67 
68 	return err;
69 }
70 
open_load_ringbuf_skel(void)71 static struct user_ringbuf_success *open_load_ringbuf_skel(void)
72 {
73 	struct user_ringbuf_success *skel;
74 	int err;
75 
76 	skel = user_ringbuf_success__open();
77 	if (!ASSERT_OK_PTR(skel, "skel_open"))
78 		return NULL;
79 
80 	err = bpf_map__set_max_entries(skel->maps.user_ringbuf, c_ringbuf_size);
81 	if (!ASSERT_OK(err, "set_max_entries"))
82 		goto cleanup;
83 
84 	err = bpf_map__set_max_entries(skel->maps.kernel_ringbuf, c_ringbuf_size);
85 	if (!ASSERT_OK(err, "set_max_entries"))
86 		goto cleanup;
87 
88 	err = user_ringbuf_success__load(skel);
89 	if (!ASSERT_OK(err, "skel_load"))
90 		goto cleanup;
91 
92 	return skel;
93 
94 cleanup:
95 	user_ringbuf_success__destroy(skel);
96 	return NULL;
97 }
98 
test_user_ringbuf_mappings(void)99 static void test_user_ringbuf_mappings(void)
100 {
101 	int err, rb_fd;
102 	int page_size = getpagesize();
103 	void *mmap_ptr;
104 	struct user_ringbuf_success *skel;
105 
106 	skel = open_load_ringbuf_skel();
107 	if (!skel)
108 		return;
109 
110 	rb_fd = bpf_map__fd(skel->maps.user_ringbuf);
111 	/* cons_pos can be mapped R/O, can't add +X with mprotect. */
112 	mmap_ptr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, rb_fd, 0);
113 	ASSERT_OK_PTR(mmap_ptr, "ro_cons_pos");
114 	ASSERT_ERR(mprotect(mmap_ptr, page_size, PROT_WRITE), "write_cons_pos_protect");
115 	ASSERT_ERR(mprotect(mmap_ptr, page_size, PROT_EXEC), "exec_cons_pos_protect");
116 	ASSERT_ERR_PTR(mremap(mmap_ptr, 0, 4 * page_size, MREMAP_MAYMOVE), "wr_prod_pos");
117 	err = -errno;
118 	ASSERT_ERR(err, "wr_prod_pos_err");
119 	ASSERT_OK(munmap(mmap_ptr, page_size), "unmap_ro_cons");
120 
121 	/* prod_pos can be mapped RW, can't add +X with mprotect. */
122 	mmap_ptr = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED,
123 			rb_fd, page_size);
124 	ASSERT_OK_PTR(mmap_ptr, "rw_prod_pos");
125 	ASSERT_ERR(mprotect(mmap_ptr, page_size, PROT_EXEC), "exec_prod_pos_protect");
126 	err = -errno;
127 	ASSERT_ERR(err, "wr_prod_pos_err");
128 	ASSERT_OK(munmap(mmap_ptr, page_size), "unmap_rw_prod");
129 
130 	/* data pages can be mapped RW, can't add +X with mprotect. */
131 	mmap_ptr = mmap(NULL, page_size, PROT_WRITE, MAP_SHARED, rb_fd,
132 			2 * page_size);
133 	ASSERT_OK_PTR(mmap_ptr, "rw_data");
134 	ASSERT_ERR(mprotect(mmap_ptr, page_size, PROT_EXEC), "exec_data_protect");
135 	err = -errno;
136 	ASSERT_ERR(err, "exec_data_err");
137 	ASSERT_OK(munmap(mmap_ptr, page_size), "unmap_rw_data");
138 
139 	user_ringbuf_success__destroy(skel);
140 }
141 
load_skel_create_ringbufs(struct user_ringbuf_success ** skel_out,struct ring_buffer ** kern_ringbuf_out,ring_buffer_sample_fn callback,struct user_ring_buffer ** user_ringbuf_out)142 static int load_skel_create_ringbufs(struct user_ringbuf_success **skel_out,
143 				     struct ring_buffer **kern_ringbuf_out,
144 				     ring_buffer_sample_fn callback,
145 				     struct user_ring_buffer **user_ringbuf_out)
146 {
147 	struct user_ringbuf_success *skel;
148 	struct ring_buffer *kern_ringbuf = NULL;
149 	struct user_ring_buffer *user_ringbuf = NULL;
150 	int err = -ENOMEM, rb_fd;
151 
152 	skel = open_load_ringbuf_skel();
153 	if (!skel)
154 		return err;
155 
156 	/* only trigger BPF program for current process */
157 	skel->bss->pid = getpid();
158 
159 	if (kern_ringbuf_out) {
160 		rb_fd = bpf_map__fd(skel->maps.kernel_ringbuf);
161 		kern_ringbuf = ring_buffer__new(rb_fd, callback, skel, NULL);
162 		if (!ASSERT_OK_PTR(kern_ringbuf, "kern_ringbuf_create"))
163 			goto cleanup;
164 
165 		*kern_ringbuf_out = kern_ringbuf;
166 	}
167 
168 	if (user_ringbuf_out) {
169 		rb_fd = bpf_map__fd(skel->maps.user_ringbuf);
170 		user_ringbuf = user_ring_buffer__new(rb_fd, NULL);
171 		if (!ASSERT_OK_PTR(user_ringbuf, "user_ringbuf_create"))
172 			goto cleanup;
173 
174 		*user_ringbuf_out = user_ringbuf;
175 		ASSERT_EQ(skel->bss->read, 0, "no_reads_after_load");
176 	}
177 
178 	err = user_ringbuf_success__attach(skel);
179 	if (!ASSERT_OK(err, "skel_attach"))
180 		goto cleanup;
181 
182 	*skel_out = skel;
183 	return 0;
184 
185 cleanup:
186 	if (kern_ringbuf_out)
187 		*kern_ringbuf_out = NULL;
188 	if (user_ringbuf_out)
189 		*user_ringbuf_out = NULL;
190 	ring_buffer__free(kern_ringbuf);
191 	user_ring_buffer__free(user_ringbuf);
192 	user_ringbuf_success__destroy(skel);
193 	return err;
194 }
195 
load_skel_create_user_ringbuf(struct user_ringbuf_success ** skel_out,struct user_ring_buffer ** ringbuf_out)196 static int load_skel_create_user_ringbuf(struct user_ringbuf_success **skel_out,
197 					 struct user_ring_buffer **ringbuf_out)
198 {
199 	return load_skel_create_ringbufs(skel_out, NULL, NULL, ringbuf_out);
200 }
201 
manually_write_test_invalid_sample(struct user_ringbuf_success * skel,__u32 size,__u64 producer_pos,int err)202 static void manually_write_test_invalid_sample(struct user_ringbuf_success *skel,
203 					       __u32 size, __u64 producer_pos, int err)
204 {
205 	void *data_ptr;
206 	__u64 *producer_pos_ptr;
207 	int rb_fd, page_size = getpagesize();
208 
209 	rb_fd = bpf_map__fd(skel->maps.user_ringbuf);
210 
211 	ASSERT_EQ(skel->bss->read, 0, "num_samples_before_bad_sample");
212 
213 	/* Map the producer_pos as RW. */
214 	producer_pos_ptr = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
215 				MAP_SHARED, rb_fd, page_size);
216 	ASSERT_OK_PTR(producer_pos_ptr, "producer_pos_ptr");
217 
218 	/* Map the data pages as RW. */
219 	data_ptr = mmap(NULL, page_size, PROT_WRITE, MAP_SHARED, rb_fd, 2 * page_size);
220 	ASSERT_OK_PTR(data_ptr, "rw_data");
221 
222 	memset(data_ptr, 0, BPF_RINGBUF_HDR_SZ);
223 	*(__u32 *)data_ptr = size;
224 
225 	/* Synchronizes with smp_load_acquire() in __bpf_user_ringbuf_peek() in the kernel. */
226 	smp_store_release(producer_pos_ptr, producer_pos + BPF_RINGBUF_HDR_SZ);
227 
228 	drain_current_samples();
229 	ASSERT_EQ(skel->bss->read, 0, "num_samples_after_bad_sample");
230 	ASSERT_EQ(skel->bss->err, err, "err_after_bad_sample");
231 
232 	ASSERT_OK(munmap(producer_pos_ptr, page_size), "unmap_producer_pos");
233 	ASSERT_OK(munmap(data_ptr, page_size), "unmap_data_ptr");
234 }
235 
test_user_ringbuf_post_misaligned(void)236 static void test_user_ringbuf_post_misaligned(void)
237 {
238 	struct user_ringbuf_success *skel;
239 	struct user_ring_buffer *ringbuf;
240 	int err;
241 	__u32 size = (1 << 5) + 7;
242 
243 	err = load_skel_create_user_ringbuf(&skel, &ringbuf);
244 	if (!ASSERT_OK(err, "misaligned_skel"))
245 		return;
246 
247 	manually_write_test_invalid_sample(skel, size, size, -EINVAL);
248 	user_ring_buffer__free(ringbuf);
249 	user_ringbuf_success__destroy(skel);
250 }
251 
test_user_ringbuf_post_producer_wrong_offset(void)252 static void test_user_ringbuf_post_producer_wrong_offset(void)
253 {
254 	struct user_ringbuf_success *skel;
255 	struct user_ring_buffer *ringbuf;
256 	int err;
257 	__u32 size = (1 << 5);
258 
259 	err = load_skel_create_user_ringbuf(&skel, &ringbuf);
260 	if (!ASSERT_OK(err, "wrong_offset_skel"))
261 		return;
262 
263 	manually_write_test_invalid_sample(skel, size, size - 8, -EINVAL);
264 	user_ring_buffer__free(ringbuf);
265 	user_ringbuf_success__destroy(skel);
266 }
267 
test_user_ringbuf_post_larger_than_ringbuf_sz(void)268 static void test_user_ringbuf_post_larger_than_ringbuf_sz(void)
269 {
270 	struct user_ringbuf_success *skel;
271 	struct user_ring_buffer *ringbuf;
272 	int err;
273 	__u32 size = c_ringbuf_size;
274 
275 	err = load_skel_create_user_ringbuf(&skel, &ringbuf);
276 	if (!ASSERT_OK(err, "huge_sample_skel"))
277 		return;
278 
279 	manually_write_test_invalid_sample(skel, size, size, -E2BIG);
280 	user_ring_buffer__free(ringbuf);
281 	user_ringbuf_success__destroy(skel);
282 }
283 
test_user_ringbuf_basic(void)284 static void test_user_ringbuf_basic(void)
285 {
286 	struct user_ringbuf_success *skel;
287 	struct user_ring_buffer *ringbuf;
288 	int err;
289 
290 	err = load_skel_create_user_ringbuf(&skel, &ringbuf);
291 	if (!ASSERT_OK(err, "ringbuf_basic_skel"))
292 		return;
293 
294 	ASSERT_EQ(skel->bss->read, 0, "num_samples_read_before");
295 
296 	err = write_samples(ringbuf, 2);
297 	if (!ASSERT_OK(err, "write_samples"))
298 		goto cleanup;
299 
300 	ASSERT_EQ(skel->bss->read, 2, "num_samples_read_after");
301 
302 cleanup:
303 	user_ring_buffer__free(ringbuf);
304 	user_ringbuf_success__destroy(skel);
305 }
306 
test_user_ringbuf_sample_full_ring_buffer(void)307 static void test_user_ringbuf_sample_full_ring_buffer(void)
308 {
309 	struct user_ringbuf_success *skel;
310 	struct user_ring_buffer *ringbuf;
311 	int err;
312 	void *sample;
313 
314 	err = load_skel_create_user_ringbuf(&skel, &ringbuf);
315 	if (!ASSERT_OK(err, "ringbuf_full_sample_skel"))
316 		return;
317 
318 	sample = user_ring_buffer__reserve(ringbuf, c_ringbuf_size - BPF_RINGBUF_HDR_SZ);
319 	if (!ASSERT_OK_PTR(sample, "full_sample"))
320 		goto cleanup;
321 
322 	user_ring_buffer__submit(ringbuf, sample);
323 	ASSERT_EQ(skel->bss->read, 0, "num_samples_read_before");
324 	drain_current_samples();
325 	ASSERT_EQ(skel->bss->read, 1, "num_samples_read_after");
326 
327 cleanup:
328 	user_ring_buffer__free(ringbuf);
329 	user_ringbuf_success__destroy(skel);
330 }
331 
test_user_ringbuf_post_alignment_autoadjust(void)332 static void test_user_ringbuf_post_alignment_autoadjust(void)
333 {
334 	struct user_ringbuf_success *skel;
335 	struct user_ring_buffer *ringbuf;
336 	struct sample *sample;
337 	int err;
338 
339 	err = load_skel_create_user_ringbuf(&skel, &ringbuf);
340 	if (!ASSERT_OK(err, "ringbuf_align_autoadjust_skel"))
341 		return;
342 
343 	/* libbpf should automatically round any sample up to an 8-byte alignment. */
344 	sample = user_ring_buffer__reserve(ringbuf, sizeof(*sample) + 1);
345 	ASSERT_OK_PTR(sample, "reserve_autoaligned");
346 	user_ring_buffer__submit(ringbuf, sample);
347 
348 	ASSERT_EQ(skel->bss->read, 0, "num_samples_read_before");
349 	drain_current_samples();
350 	ASSERT_EQ(skel->bss->read, 1, "num_samples_read_after");
351 
352 	user_ring_buffer__free(ringbuf);
353 	user_ringbuf_success__destroy(skel);
354 }
355 
test_user_ringbuf_overfill(void)356 static void test_user_ringbuf_overfill(void)
357 {
358 	struct user_ringbuf_success *skel;
359 	struct user_ring_buffer *ringbuf;
360 	int err;
361 
362 	err = load_skel_create_user_ringbuf(&skel, &ringbuf);
363 	if (err)
364 		return;
365 
366 	err = write_samples(ringbuf, c_max_entries * 5);
367 	ASSERT_ERR(err, "write_samples");
368 	ASSERT_EQ(skel->bss->read, c_max_entries, "max_entries");
369 
370 	user_ring_buffer__free(ringbuf);
371 	user_ringbuf_success__destroy(skel);
372 }
373 
test_user_ringbuf_discards_properly_ignored(void)374 static void test_user_ringbuf_discards_properly_ignored(void)
375 {
376 	struct user_ringbuf_success *skel;
377 	struct user_ring_buffer *ringbuf;
378 	int err, num_discarded = 0;
379 	__u64 *token;
380 
381 	err = load_skel_create_user_ringbuf(&skel, &ringbuf);
382 	if (err)
383 		return;
384 
385 	ASSERT_EQ(skel->bss->read, 0, "num_samples_read_before");
386 
387 	while (1) {
388 		/* Write samples until the buffer is full. */
389 		token = user_ring_buffer__reserve(ringbuf, sizeof(*token));
390 		if (!token)
391 			break;
392 
393 		user_ring_buffer__discard(ringbuf, token);
394 		num_discarded++;
395 	}
396 
397 	if (!ASSERT_GE(num_discarded, 0, "num_discarded"))
398 		goto cleanup;
399 
400 	/* Should not read any samples, as they are all discarded. */
401 	ASSERT_EQ(skel->bss->read, 0, "num_pre_kick");
402 	drain_current_samples();
403 	ASSERT_EQ(skel->bss->read, 0, "num_post_kick");
404 
405 	/* Now that the ring buffer has been drained, we should be able to
406 	 * reserve another token.
407 	 */
408 	token = user_ring_buffer__reserve(ringbuf, sizeof(*token));
409 
410 	if (!ASSERT_OK_PTR(token, "new_token"))
411 		goto cleanup;
412 
413 	user_ring_buffer__discard(ringbuf, token);
414 cleanup:
415 	user_ring_buffer__free(ringbuf);
416 	user_ringbuf_success__destroy(skel);
417 }
418 
test_user_ringbuf_loop(void)419 static void test_user_ringbuf_loop(void)
420 {
421 	struct user_ringbuf_success *skel;
422 	struct user_ring_buffer *ringbuf;
423 	uint32_t total_samples = 8192;
424 	uint32_t remaining_samples = total_samples;
425 	int err;
426 
427 	BUILD_BUG_ON(total_samples <= c_max_entries);
428 	err = load_skel_create_user_ringbuf(&skel, &ringbuf);
429 	if (err)
430 		return;
431 
432 	do  {
433 		uint32_t curr_samples;
434 
435 		curr_samples = remaining_samples > c_max_entries
436 			? c_max_entries : remaining_samples;
437 		err = write_samples(ringbuf, curr_samples);
438 		if (err != 0) {
439 			/* Assert inside of if statement to avoid flooding logs
440 			 * on the success path.
441 			 */
442 			ASSERT_OK(err, "write_samples");
443 			goto cleanup;
444 		}
445 
446 		remaining_samples -= curr_samples;
447 		ASSERT_EQ(skel->bss->read, total_samples - remaining_samples,
448 			  "current_batched_entries");
449 	} while (remaining_samples > 0);
450 	ASSERT_EQ(skel->bss->read, total_samples, "total_batched_entries");
451 
452 cleanup:
453 	user_ring_buffer__free(ringbuf);
454 	user_ringbuf_success__destroy(skel);
455 }
456 
send_test_message(struct user_ring_buffer * ringbuf,enum test_msg_op op,s64 operand_64,s32 operand_32)457 static int send_test_message(struct user_ring_buffer *ringbuf,
458 			     enum test_msg_op op, s64 operand_64,
459 			     s32 operand_32)
460 {
461 	struct test_msg *msg;
462 
463 	msg = user_ring_buffer__reserve(ringbuf, sizeof(*msg));
464 	if (!msg) {
465 		/* Assert on the error path to avoid spamming logs with mostly
466 		 * success messages.
467 		 */
468 		ASSERT_OK_PTR(msg, "reserve_msg");
469 		return -ENOMEM;
470 	}
471 
472 	msg->msg_op = op;
473 
474 	switch (op) {
475 	case TEST_MSG_OP_INC64:
476 	case TEST_MSG_OP_MUL64:
477 		msg->operand_64 = operand_64;
478 		break;
479 	case TEST_MSG_OP_INC32:
480 	case TEST_MSG_OP_MUL32:
481 		msg->operand_32 = operand_32;
482 		break;
483 	default:
484 		PRINT_FAIL("Invalid operand %d\n", op);
485 		user_ring_buffer__discard(ringbuf, msg);
486 		return -EINVAL;
487 	}
488 
489 	user_ring_buffer__submit(ringbuf, msg);
490 
491 	return 0;
492 }
493 
kick_kernel_read_messages(void)494 static void kick_kernel_read_messages(void)
495 {
496 	syscall(__NR_prctl);
497 }
498 
handle_kernel_msg(void * ctx,void * data,size_t len)499 static int handle_kernel_msg(void *ctx, void *data, size_t len)
500 {
501 	struct user_ringbuf_success *skel = ctx;
502 	struct test_msg *msg = data;
503 
504 	switch (msg->msg_op) {
505 	case TEST_MSG_OP_INC64:
506 		skel->bss->user_mutated += msg->operand_64;
507 		return 0;
508 	case TEST_MSG_OP_INC32:
509 		skel->bss->user_mutated += msg->operand_32;
510 		return 0;
511 	case TEST_MSG_OP_MUL64:
512 		skel->bss->user_mutated *= msg->operand_64;
513 		return 0;
514 	case TEST_MSG_OP_MUL32:
515 		skel->bss->user_mutated *= msg->operand_32;
516 		return 0;
517 	default:
518 		fprintf(stderr, "Invalid operand %d\n", msg->msg_op);
519 		return -EINVAL;
520 	}
521 }
522 
drain_kernel_messages_buffer(struct ring_buffer * kern_ringbuf,struct user_ringbuf_success * skel)523 static void drain_kernel_messages_buffer(struct ring_buffer *kern_ringbuf,
524 					 struct user_ringbuf_success *skel)
525 {
526 	int cnt;
527 
528 	cnt = ring_buffer__consume(kern_ringbuf);
529 	ASSERT_EQ(cnt, 8, "consume_kern_ringbuf");
530 	ASSERT_OK(skel->bss->err, "consume_kern_ringbuf_err");
531 }
532 
test_user_ringbuf_msg_protocol(void)533 static void test_user_ringbuf_msg_protocol(void)
534 {
535 	struct user_ringbuf_success *skel;
536 	struct user_ring_buffer *user_ringbuf;
537 	struct ring_buffer *kern_ringbuf;
538 	int err, i;
539 	__u64 expected_kern = 0;
540 
541 	err = load_skel_create_ringbufs(&skel, &kern_ringbuf, handle_kernel_msg, &user_ringbuf);
542 	if (!ASSERT_OK(err, "create_ringbufs"))
543 		return;
544 
545 	for (i = 0; i < 64; i++) {
546 		enum test_msg_op op = i % TEST_MSG_OP_NUM_OPS;
547 		__u64 operand_64 = TEST_OP_64;
548 		__u32 operand_32 = TEST_OP_32;
549 
550 		err = send_test_message(user_ringbuf, op, operand_64, operand_32);
551 		if (err) {
552 			/* Only assert on a failure to avoid spamming success logs. */
553 			ASSERT_OK(err, "send_test_message");
554 			goto cleanup;
555 		}
556 
557 		switch (op) {
558 		case TEST_MSG_OP_INC64:
559 			expected_kern += operand_64;
560 			break;
561 		case TEST_MSG_OP_INC32:
562 			expected_kern += operand_32;
563 			break;
564 		case TEST_MSG_OP_MUL64:
565 			expected_kern *= operand_64;
566 			break;
567 		case TEST_MSG_OP_MUL32:
568 			expected_kern *= operand_32;
569 			break;
570 		default:
571 			PRINT_FAIL("Unexpected op %d\n", op);
572 			goto cleanup;
573 		}
574 
575 		if (i % 8 == 0) {
576 			kick_kernel_read_messages();
577 			ASSERT_EQ(skel->bss->kern_mutated, expected_kern, "expected_kern");
578 			ASSERT_EQ(skel->bss->err, 0, "bpf_prog_err");
579 			drain_kernel_messages_buffer(kern_ringbuf, skel);
580 		}
581 	}
582 
583 cleanup:
584 	ring_buffer__free(kern_ringbuf);
585 	user_ring_buffer__free(user_ringbuf);
586 	user_ringbuf_success__destroy(skel);
587 }
588 
kick_kernel_cb(void * arg)589 static void *kick_kernel_cb(void *arg)
590 {
591 	/* Kick the kernel, causing it to drain the ring buffer and then wake
592 	 * up the test thread waiting on epoll.
593 	 */
594 	syscall(__NR_prlimit64);
595 
596 	return NULL;
597 }
598 
spawn_kick_thread_for_poll(void)599 static int spawn_kick_thread_for_poll(void)
600 {
601 	pthread_t thread;
602 
603 	return pthread_create(&thread, NULL, kick_kernel_cb, NULL);
604 }
605 
test_user_ringbuf_blocking_reserve(void)606 static void test_user_ringbuf_blocking_reserve(void)
607 {
608 	struct user_ringbuf_success *skel;
609 	struct user_ring_buffer *ringbuf;
610 	int err, num_written = 0;
611 	__u64 *token;
612 
613 	err = load_skel_create_user_ringbuf(&skel, &ringbuf);
614 	if (err)
615 		return;
616 
617 	ASSERT_EQ(skel->bss->read, 0, "num_samples_read_before");
618 
619 	while (1) {
620 		/* Write samples until the buffer is full. */
621 		token = user_ring_buffer__reserve(ringbuf, sizeof(*token));
622 		if (!token)
623 			break;
624 
625 		*token = 0xdeadbeef;
626 
627 		user_ring_buffer__submit(ringbuf, token);
628 		num_written++;
629 	}
630 
631 	if (!ASSERT_GE(num_written, 0, "num_written"))
632 		goto cleanup;
633 
634 	/* Should not have read any samples until the kernel is kicked. */
635 	ASSERT_EQ(skel->bss->read, 0, "num_pre_kick");
636 
637 	/* We correctly time out after 1 second, without a sample. */
638 	token = user_ring_buffer__reserve_blocking(ringbuf, sizeof(*token), 1000);
639 	if (!ASSERT_EQ(token, NULL, "pre_kick_timeout_token"))
640 		goto cleanup;
641 
642 	err = spawn_kick_thread_for_poll();
643 	if (!ASSERT_EQ(err, 0, "deferred_kick_thread\n"))
644 		goto cleanup;
645 
646 	/* After spawning another thread that asychronously kicks the kernel to
647 	 * drain the messages, we're able to block and successfully get a
648 	 * sample once we receive an event notification.
649 	 */
650 	token = user_ring_buffer__reserve_blocking(ringbuf, sizeof(*token), 10000);
651 
652 	if (!ASSERT_OK_PTR(token, "block_token"))
653 		goto cleanup;
654 
655 	ASSERT_GT(skel->bss->read, 0, "num_post_kill");
656 	ASSERT_LE(skel->bss->read, num_written, "num_post_kill");
657 	ASSERT_EQ(skel->bss->err, 0, "err_post_poll");
658 	user_ring_buffer__discard(ringbuf, token);
659 
660 cleanup:
661 	user_ring_buffer__free(ringbuf);
662 	user_ringbuf_success__destroy(skel);
663 }
664 
665 #define SUCCESS_TEST(_func) { _func, #_func }
666 
667 static struct {
668 	void (*test_callback)(void);
669 	const char *test_name;
670 } success_tests[] = {
671 	SUCCESS_TEST(test_user_ringbuf_mappings),
672 	SUCCESS_TEST(test_user_ringbuf_post_misaligned),
673 	SUCCESS_TEST(test_user_ringbuf_post_producer_wrong_offset),
674 	SUCCESS_TEST(test_user_ringbuf_post_larger_than_ringbuf_sz),
675 	SUCCESS_TEST(test_user_ringbuf_basic),
676 	SUCCESS_TEST(test_user_ringbuf_sample_full_ring_buffer),
677 	SUCCESS_TEST(test_user_ringbuf_post_alignment_autoadjust),
678 	SUCCESS_TEST(test_user_ringbuf_overfill),
679 	SUCCESS_TEST(test_user_ringbuf_discards_properly_ignored),
680 	SUCCESS_TEST(test_user_ringbuf_loop),
681 	SUCCESS_TEST(test_user_ringbuf_msg_protocol),
682 	SUCCESS_TEST(test_user_ringbuf_blocking_reserve),
683 };
684 
test_user_ringbuf(void)685 void test_user_ringbuf(void)
686 {
687 	int i;
688 
689 	for (i = 0; i < ARRAY_SIZE(success_tests); i++) {
690 		if (!test__start_subtest(success_tests[i].test_name))
691 			continue;
692 
693 		success_tests[i].test_callback();
694 	}
695 
696 	RUN_TESTS(user_ringbuf_fail);
697 }
698