• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Description: ring mapped provided buffers with reads
4  *
5  */
6 #include <errno.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <fcntl.h>
12 
13 #include "liburing.h"
14 #include "helpers.h"
15 
16 #define BUF_SIZE	4096
17 #define NR_BUFS		64
18 #define FSIZE		(BUF_SIZE * NR_BUFS)
19 
20 #define BR_MASK		(NR_BUFS - 1)
21 
22 static int no_buf_ring;
23 
verify_buffer(char * buf,char val)24 static int verify_buffer(char *buf, char val)
25 {
26 	int i;
27 
28 	for (i = 0; i < BUF_SIZE; i++) {
29 		if (buf[i] != val) {
30 			fprintf(stderr, "got %d, wanted %d\n", buf[i], val);
31 			return 1;
32 		}
33 	}
34 
35 	return 0;
36 }
37 
test(const char * filename,int dio,int async)38 static int test(const char *filename, int dio, int async)
39 {
40 	struct io_uring_sqe *sqe;
41 	struct io_uring_cqe *cqe;
42 	struct io_uring ring;
43 	struct io_uring_buf_ring *br;
44 	int ret, fd, i;
45 	char *buf;
46 	void *ptr;
47 
48 	ret = io_uring_queue_init(NR_BUFS, &ring, 0);
49 	if (ret) {
50 		fprintf(stderr, "ring setup failed: %d\n", ret);
51 		return 1;
52 	}
53 
54 	if (dio) {
55 		fd = open(filename, O_DIRECT | O_RDONLY);
56 		if (fd < 0 && errno == EINVAL)
57 			return T_EXIT_SKIP;
58 	} else {
59 		fd = open(filename, O_RDONLY);
60 	}
61 	if (fd < 0) {
62 		if (errno == EPERM || errno == EACCES)
63 			return T_EXIT_SKIP;
64 		perror("open");
65 		return 1;
66 	}
67 
68 	posix_fadvise(fd, 0, FSIZE, POSIX_FADV_DONTNEED);
69 
70 	if (posix_memalign((void **) &buf, 4096, FSIZE))
71 		return 1;
72 
73 	br = io_uring_setup_buf_ring(&ring, NR_BUFS, 1, 0, &ret);
74 	if (!br) {
75 		if (ret == -EINVAL) {
76 			no_buf_ring = 1;
77 			return 0;
78 		}
79 		fprintf(stderr, "Buffer ring register failed %d\n", ret);
80 		return 1;
81 	}
82 
83 	ptr = buf;
84 	for (i = 0; i < NR_BUFS; i++) {
85 		io_uring_buf_ring_add(br, ptr, BUF_SIZE, i + 1, BR_MASK, i);
86 		ptr += BUF_SIZE;
87 	}
88 	io_uring_buf_ring_advance(br, NR_BUFS);
89 
90 	for (i = 0; i < NR_BUFS; i++) {
91 		sqe = io_uring_get_sqe(&ring);
92 		io_uring_prep_read(sqe, fd, NULL, BUF_SIZE, i * BUF_SIZE);
93 		sqe->buf_group = 1;
94 		sqe->flags |= IOSQE_BUFFER_SELECT;
95 		if (async && !(i & 1))
96 			sqe->flags |= IOSQE_ASYNC;
97 		sqe->user_data = i + 1;
98 	}
99 
100 	ret = io_uring_submit(&ring);
101 	if (ret != NR_BUFS) {
102 		fprintf(stderr, "submit: %d\n", ret);
103 		return 1;
104 	}
105 
106 	for (i = 0; i < NR_BUFS; i++) {
107 		int bid, ud;
108 
109 		ret = io_uring_wait_cqe(&ring, &cqe);
110 		if (ret) {
111 			fprintf(stderr, "wait cqe failed %d\n", ret);
112 			return 1;
113 		}
114 		if (cqe->res != BUF_SIZE) {
115 			fprintf(stderr, "cqe res %d\n", cqe->res);
116 			return 1;
117 		}
118 		if (!(cqe->flags & IORING_CQE_F_BUFFER)) {
119 			fprintf(stderr, "no buffer selected\n");
120 			return 1;
121 		}
122 		bid = cqe->flags >> IORING_CQE_BUFFER_SHIFT;
123 		ud = cqe->user_data;
124 		io_uring_cqe_seen(&ring, cqe);
125 		if (verify_buffer(buf + ((bid - 1) * BUF_SIZE), ud))
126 			return 1;
127 	}
128 	free(buf);
129 
130 	return 0;
131 }
132 
main(int argc,char * argv[])133 int main(int argc, char *argv[])
134 {
135 	char buf[BUF_SIZE];
136 	char fname[80];
137 	int ret, fd, i, do_unlink;
138 
139 	if (argc > 1) {
140 		strcpy(fname, argv[1]);
141 		do_unlink = 0;
142 	} else {
143 		sprintf(fname, ".ringbuf-read.%d", getpid());
144 		t_create_file(fname, FSIZE);
145 		do_unlink = 1;
146 	}
147 
148 	fd = open(fname, O_WRONLY);
149 	if (fd < 0) {
150 		if (errno == EPERM || errno == EACCES)
151 			return T_EXIT_SKIP;
152 		perror("open");
153 		goto err;
154 	}
155 	for (i = 0; i < NR_BUFS; i++) {
156 		memset(buf, i + 1, BUF_SIZE);
157 		ret = write(fd, buf, BUF_SIZE);
158 		if (ret != BUF_SIZE) {
159 			fprintf(stderr, "bad file prep write\n");
160 			close(fd);
161 			goto err;
162 		}
163 	}
164 	close(fd);
165 
166 	ret = test(fname, 1, 0);
167 	if (ret == T_EXIT_FAIL) {
168 		fprintf(stderr, "dio test failed\n");
169 		goto err;
170 	}
171 	if (no_buf_ring)
172 		goto pass;
173 
174 	ret = test(fname, 0, 0);
175 	if (ret) {
176 		fprintf(stderr, "buffered test failed\n");
177 		goto err;
178 	}
179 
180 	ret = test(fname, 1, 1);
181 	if (ret == T_EXIT_FAIL) {
182 		fprintf(stderr, "dio async test failed\n");
183 		goto err;
184 	}
185 
186 	ret = test(fname, 0, 1);
187 	if (ret == T_EXIT_FAIL) {
188 		fprintf(stderr, "buffered async test failed\n");
189 		goto err;
190 	}
191 
192 pass:
193 	ret = T_EXIT_PASS;
194 	goto out;
195 err:
196 	ret = T_EXIT_FAIL;
197 out:
198 	if (do_unlink)
199 		unlink(fname);
200 	return ret;
201 }
202