• 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 		perror("open");
63 		return 1;
64 	}
65 
66 	posix_fadvise(fd, 0, FSIZE, POSIX_FADV_DONTNEED);
67 
68 	if (posix_memalign((void **) &buf, 4096, FSIZE))
69 		return 1;
70 
71 	br = io_uring_setup_buf_ring(&ring, NR_BUFS, 1, 0, &ret);
72 	if (!br) {
73 		if (ret == -EINVAL) {
74 			no_buf_ring = 1;
75 			return 0;
76 		}
77 		fprintf(stderr, "Buffer ring register failed %d\n", ret);
78 		return 1;
79 	}
80 
81 	ptr = buf;
82 	for (i = 0; i < NR_BUFS; i++) {
83 		io_uring_buf_ring_add(br, ptr, BUF_SIZE, i + 1, BR_MASK, i);
84 		ptr += BUF_SIZE;
85 	}
86 	io_uring_buf_ring_advance(br, NR_BUFS);
87 
88 	for (i = 0; i < NR_BUFS; i++) {
89 		sqe = io_uring_get_sqe(&ring);
90 		io_uring_prep_read(sqe, fd, NULL, BUF_SIZE, i * BUF_SIZE);
91 		sqe->buf_group = 1;
92 		sqe->flags |= IOSQE_BUFFER_SELECT;
93 		if (async && !(i & 1))
94 			sqe->flags |= IOSQE_ASYNC;
95 		sqe->user_data = i + 1;
96 	}
97 
98 	ret = io_uring_submit(&ring);
99 	if (ret != NR_BUFS) {
100 		fprintf(stderr, "submit: %d\n", ret);
101 		return 1;
102 	}
103 
104 	for (i = 0; i < NR_BUFS; i++) {
105 		int bid, ud;
106 
107 		ret = io_uring_wait_cqe(&ring, &cqe);
108 		if (ret) {
109 			fprintf(stderr, "wait cqe failed %d\n", ret);
110 			return 1;
111 		}
112 		if (cqe->res != BUF_SIZE) {
113 			fprintf(stderr, "cqe res %d\n", cqe->res);
114 			return 1;
115 		}
116 		if (!(cqe->flags & IORING_CQE_F_BUFFER)) {
117 			fprintf(stderr, "no buffer selected\n");
118 			return 1;
119 		}
120 		bid = cqe->flags >> IORING_CQE_BUFFER_SHIFT;
121 		ud = cqe->user_data;
122 		io_uring_cqe_seen(&ring, cqe);
123 		if (verify_buffer(buf + ((bid - 1) * BUF_SIZE), ud))
124 			return 1;
125 	}
126 
127 	return 0;
128 }
129 
main(int argc,char * argv[])130 int main(int argc, char *argv[])
131 {
132 	char buf[BUF_SIZE];
133 	char fname[80];
134 	int ret, fd, i, do_unlink;
135 
136 	if (argc > 1) {
137 		strcpy(fname, argv[1]);
138 		do_unlink = 0;
139 	} else {
140 		sprintf(fname, ".ringbuf-read.%d", getpid());
141 		t_create_file(fname, FSIZE);
142 		do_unlink = 1;
143 	}
144 
145 	fd = open(fname, O_WRONLY);
146 	if (fd < 0) {
147 		perror("open");
148 		goto err;
149 	}
150 	for (i = 0; i < NR_BUFS; i++) {
151 		memset(buf, i + 1, BUF_SIZE);
152 		ret = write(fd, buf, BUF_SIZE);
153 		if (ret != BUF_SIZE) {
154 			fprintf(stderr, "bad file prep write\n");
155 			close(fd);
156 			goto err;
157 		}
158 	}
159 	close(fd);
160 
161 	ret = test(fname, 1, 0);
162 	if (ret == T_EXIT_FAIL) {
163 		fprintf(stderr, "dio test failed\n");
164 		goto err;
165 	}
166 	if (no_buf_ring)
167 		goto pass;
168 
169 	ret = test(fname, 0, 0);
170 	if (ret) {
171 		fprintf(stderr, "buffered test failed\n");
172 		goto err;
173 	}
174 
175 	ret = test(fname, 1, 1);
176 	if (ret == T_EXIT_FAIL) {
177 		fprintf(stderr, "dio async test failed\n");
178 		goto err;
179 	}
180 
181 	ret = test(fname, 0, 1);
182 	if (ret == T_EXIT_FAIL) {
183 		fprintf(stderr, "buffered async test failed\n");
184 		goto err;
185 	}
186 
187 pass:
188 	ret = T_EXIT_PASS;
189 	goto out;
190 err:
191 	ret = T_EXIT_FAIL;
192 out:
193 	if (do_unlink)
194 		unlink(fname);
195 	return ret;
196 }
197