• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * Description: read /proc/kallsyms. Mostly just here so that fops->read() can
4  *		get exercised, with and without registered buffers
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 #include <sys/types.h>
13 #include <poll.h>
14 #include <sys/eventfd.h>
15 #include <sys/resource.h>
16 
17 #include "helpers.h"
18 #include "liburing.h"
19 
20 #define FILE_SIZE	(8 * 1024)
21 #define BS		8192
22 #define BUFFERS		(FILE_SIZE / BS)
23 
24 static struct iovec *vecs;
25 static int warned;
26 
__test_io(const char * file,struct io_uring * ring,int fixed,int nonvec)27 static int __test_io(const char *file, struct io_uring *ring, int fixed, int nonvec)
28 {
29 	struct io_uring_sqe *sqe;
30 	struct io_uring_cqe *cqe;
31 	int open_flags;
32 	int i, fd = -1, ret;
33 	off_t offset;
34 
35 	open_flags = O_RDONLY;
36 	if (fixed) {
37 		ret = t_register_buffers(ring, vecs, BUFFERS);
38 		if (ret == T_SETUP_SKIP)
39 			return 0;
40 		if (ret != T_SETUP_OK) {
41 			fprintf(stderr, "buffer reg failed: %d\n", ret);
42 			goto err;
43 		}
44 	}
45 
46 	fd = open(file, open_flags);
47 	if (fd < 0) {
48 		if (errno == EINVAL || errno == EPERM || errno == ENOENT)
49 			return 0;
50 		perror("file open");
51 		goto err;
52 	}
53 
54 	offset = 0;
55 	for (i = 0; i < BUFFERS; i++) {
56 		int do_fixed = fixed;
57 
58 		sqe = io_uring_get_sqe(ring);
59 		if (!sqe) {
60 			fprintf(stderr, "sqe get failed\n");
61 			goto err;
62 		}
63 		if (fixed && (i & 1))
64 			do_fixed = 0;
65 		if (do_fixed) {
66 			io_uring_prep_read_fixed(sqe, fd, vecs[i].iov_base,
67 						vecs[i].iov_len, offset, i);
68 		} else if (nonvec) {
69 			io_uring_prep_read(sqe, fd, vecs[i].iov_base,
70 							vecs[i].iov_len, offset);
71 		} else {
72 			io_uring_prep_readv(sqe, fd, &vecs[i], 1, offset);
73 		}
74 		sqe->user_data = i;
75 		offset += BS;
76 	}
77 
78 	ret = io_uring_submit(ring);
79 	if (ret != BUFFERS) {
80 		fprintf(stderr, "submit got %d, wanted %d\n", ret, BUFFERS);
81 		goto err;
82 	}
83 
84 	for (i = 0; i < BUFFERS; i++) {
85 		ret = io_uring_wait_cqe(ring, &cqe);
86 		if (ret) {
87 			fprintf(stderr, "wait_cqe=%d\n", ret);
88 			goto err;
89 		}
90 		if (cqe->res == -EINVAL && nonvec) {
91 			if (!warned) {
92 				fprintf(stdout, "Non-vectored IO not "
93 					"supported, skipping\n");
94 				warned = 1;
95 			}
96 		}
97 		io_uring_cqe_seen(ring, cqe);
98 	}
99 
100 	if (fixed) {
101 		ret = io_uring_unregister_buffers(ring);
102 		if (ret) {
103 			fprintf(stderr, "buffer unreg failed: %d\n", ret);
104 			goto err;
105 		}
106 	}
107 
108 	close(fd);
109 	return 0;
110 err:
111 	if (fd != -1)
112 		close(fd);
113 	return 1;
114 }
test_io(const char * file,int fixed,int nonvec)115 static int test_io(const char *file, int fixed, int nonvec)
116 {
117 	struct io_uring ring;
118 	int ret, ring_flags = 0;
119 
120 	ret = t_create_ring(64, &ring, ring_flags);
121 	if (ret == T_SETUP_SKIP)
122 		return 0;
123 	if (ret != T_SETUP_OK) {
124 		fprintf(stderr, "ring create failed: %d\n", ret);
125 		return 1;
126 	}
127 
128 	ret = __test_io(file, &ring, fixed, nonvec);
129 	io_uring_queue_exit(&ring);
130 	return ret;
131 }
132 
has_nonvec_read(void)133 static int has_nonvec_read(void)
134 {
135 	struct io_uring_probe *p;
136 	struct io_uring ring;
137 	int ret;
138 
139 	ret = io_uring_queue_init(1, &ring, 0);
140 	if (ret) {
141 		fprintf(stderr, "queue init failed: %d\n", ret);
142 		exit(ret);
143 	}
144 
145 	p = t_calloc(1, sizeof(*p) + 256 * sizeof(struct io_uring_probe_op));
146 	ret = io_uring_register_probe(&ring, p, 256);
147 	/* if we don't have PROBE_REGISTER, we don't have OP_READ/WRITE */
148 	if (ret == -EINVAL) {
149 out:
150 		io_uring_queue_exit(&ring);
151 		free(p);
152 		return 0;
153 	} else if (ret) {
154 		fprintf(stderr, "register_probe: %d\n", ret);
155 		goto out;
156 	}
157 
158 	if (p->ops_len <= IORING_OP_READ)
159 		goto out;
160 	if (!(p->ops[IORING_OP_READ].flags & IO_URING_OP_SUPPORTED))
161 		goto out;
162 	io_uring_queue_exit(&ring);
163 	free(p);
164 	return 1;
165 }
166 
main(int argc,char * argv[])167 int main(int argc, char *argv[])
168 {
169 	int ret, nonvec;
170 
171 	if (argc > 1)
172 		return T_EXIT_SKIP;
173 
174 	vecs = t_create_buffers(BUFFERS, BS);
175 
176 	/* if we don't have nonvec read, skip testing that */
177 	nonvec = has_nonvec_read();
178 
179 	if (nonvec) {
180 		ret = test_io("/proc/kallsyms", 0, 0);
181 		if (ret)
182 			goto err;
183 	}
184 
185 	ret = test_io("/proc/kallsyms", 0, 1);
186 	if (ret)
187 		goto err;
188 
189 	if (nonvec) {
190 		ret = test_io("/proc/kallsyms", 1, 0);
191 		if (ret)
192 			goto err;
193 	}
194 
195 	ret = test_io("/proc/kallsyms", 1, 1);
196 	if (ret)
197 		goto err;
198 
199 	return 0;
200 err:
201 	fprintf(stderr, "Reading kallsyms failed\n");
202 	return 1;
203 }
204