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