• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: MIT */
2 #include <errno.h>
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <fcntl.h>
8 #include <sys/types.h>
9 #include <sys/wait.h>
10 
11 #include "liburing.h"
12 #include "test.h"
13 #include "helpers.h"
14 
15 static pid_t pid;
16 
fork_t(void)17 static pid_t fork_t(void)
18 {
19 	pid = fork();
20 	if (pid == -1) {
21 		fprintf(stderr, "fork failed\n");
22 		exit(T_EXIT_FAIL);
23 	}
24 	return pid;
25 }
26 
wait_child_t(void)27 static void wait_child_t(void)
28 {
29 	int wstatus;
30 
31 	if (waitpid(pid, &wstatus, 0) == (pid_t)-1) {
32 		perror("waitpid()");
33 		exit(T_EXIT_FAIL);
34 	}
35 	if (!WIFEXITED(wstatus)) {
36 		fprintf(stderr, "child failed %i\n", WEXITSTATUS(wstatus));
37 		exit(T_EXIT_FAIL);
38 	}
39 	if (WEXITSTATUS(wstatus))
40 		exit(T_EXIT_FAIL);
41 }
42 
try_submit(struct io_uring * ring)43 static int try_submit(struct io_uring *ring)
44 {
45 	struct io_uring_cqe *cqe;
46 	struct io_uring_sqe *sqe;
47 	int ret;
48 
49 	sqe = io_uring_get_sqe(ring);
50 	io_uring_prep_nop(sqe);
51 	sqe->user_data = 42;
52 
53 	ret = io_uring_submit(ring);
54 	if (ret < 0)
55 		return ret;
56 
57 	if (ret != 1)
58 		t_error(1, ret, "submit %i", ret);
59 	ret = io_uring_wait_cqe(ring, &cqe);
60 	if (ret)
61 		t_error(1, ret, "wait fail %i", ret);
62 
63 	if (cqe->res || cqe->user_data != 42)
64 		t_error(1, ret, "invalid cqe");
65 
66 	io_uring_cqe_seen(ring, cqe);
67 	return 0;
68 }
69 
main(int argc,char * argv[])70 int main(int argc, char *argv[])
71 {
72 	struct io_uring ring;
73 	int ret;
74 
75 	if (argc > 1)
76 		return T_EXIT_SKIP;
77 
78 	ret = io_uring_queue_init(8, &ring, IORING_SETUP_SINGLE_ISSUER);
79 	if (ret == -EINVAL) {
80 		return T_EXIT_SKIP;
81 	} else if (ret) {
82 		fprintf(stderr, "io_uring_queue_init() failed %i\n", ret);
83 		return T_EXIT_FAIL;
84 	}
85 
86 	/* test that the creator iw allowed to submit */
87 	ret = try_submit(&ring);
88 	if (ret) {
89 		fprintf(stderr, "the creator can't submit %i\n", ret);
90 		return T_EXIT_FAIL;
91 	}
92 
93 	/* test that a second submitter doesn't succeed */
94 	if (!fork_t()) {
95 		ret = try_submit(&ring);
96 		if (ret != -EEXIST)
97 			fprintf(stderr, "1: not owner child could submit %i\n", ret);
98 		return ret != -EEXIST;
99 	}
100 	wait_child_t();
101 	io_uring_queue_exit(&ring);
102 
103 	/* test that the first submitter but not creator can submit */
104 	ret = io_uring_queue_init(8, &ring, IORING_SETUP_SINGLE_ISSUER |
105 					    IORING_SETUP_R_DISABLED);
106 	if (ret)
107 		t_error(1, ret, "ring init (2) %i", ret);
108 
109 	if (!fork_t()) {
110 		io_uring_enable_rings(&ring);
111 		ret = try_submit(&ring);
112 		if (ret)
113 			fprintf(stderr, "2: not owner child could submit %i\n", ret);
114 		return !!ret;
115 	}
116 	wait_child_t();
117 	io_uring_queue_exit(&ring);
118 
119 	/* test that only the first enabler can submit */
120 	ret = io_uring_queue_init(8, &ring, IORING_SETUP_SINGLE_ISSUER |
121 					    IORING_SETUP_R_DISABLED);
122 	if (ret)
123 		t_error(1, ret, "ring init (3) %i", ret);
124 
125 	io_uring_enable_rings(&ring);
126 	if (!fork_t()) {
127 		ret = try_submit(&ring);
128 		if (ret != -EEXIST)
129 			fprintf(stderr, "3: not owner child could submit %i\n", ret);
130 		return ret != -EEXIST;
131 	}
132 	wait_child_t();
133 	io_uring_queue_exit(&ring);
134 
135 	/* test that anyone can submit to a SQPOLL|SINGLE_ISSUER ring */
136 	ret = io_uring_queue_init(8, &ring, IORING_SETUP_SINGLE_ISSUER|IORING_SETUP_SQPOLL);
137 	if (ret)
138 		t_error(1, ret, "ring init (4) %i", ret);
139 
140 	ret = try_submit(&ring);
141 	if (ret) {
142 		fprintf(stderr, "SQPOLL submit failed (creator) %i\n", ret);
143 		return T_EXIT_FAIL;
144 	}
145 
146 	if (!fork_t()) {
147 		ret = try_submit(&ring);
148 		if (ret)
149 			fprintf(stderr, "SQPOLL submit failed (child) %i\n", ret);
150 		return !!ret;
151 	}
152 	wait_child_t();
153 	io_uring_queue_exit(&ring);
154 
155 	/* test that IORING_ENTER_REGISTERED_RING doesn't break anything */
156 	ret = io_uring_queue_init(8, &ring, IORING_SETUP_SINGLE_ISSUER);
157 	if (ret)
158 		t_error(1, ret, "ring init (5) %i", ret);
159 
160 	if (!fork_t()) {
161 		ret = try_submit(&ring);
162 		if (ret != -EEXIST)
163 			fprintf(stderr, "4: not owner child could submit %i\n", ret);
164 		return ret != -EEXIST;
165 	}
166 	wait_child_t();
167 	io_uring_queue_exit(&ring);
168 	return T_EXIT_PASS;
169 }
170