1*25da2beaSAndroid Build Coastguard Worker /* SPDX-License-Identifier: MIT */
2*25da2beaSAndroid Build Coastguard Worker #include <errno.h>
3*25da2beaSAndroid Build Coastguard Worker #include <stdio.h>
4*25da2beaSAndroid Build Coastguard Worker #include <unistd.h>
5*25da2beaSAndroid Build Coastguard Worker #include <stdlib.h>
6*25da2beaSAndroid Build Coastguard Worker #include <string.h>
7*25da2beaSAndroid Build Coastguard Worker #include <fcntl.h>
8*25da2beaSAndroid Build Coastguard Worker #include <sys/mman.h>
9*25da2beaSAndroid Build Coastguard Worker
10*25da2beaSAndroid Build Coastguard Worker #include "helpers.h"
11*25da2beaSAndroid Build Coastguard Worker #include "liburing.h"
12*25da2beaSAndroid Build Coastguard Worker
13*25da2beaSAndroid Build Coastguard Worker #define BUF_SIZE (16 * 4096)
14*25da2beaSAndroid Build Coastguard Worker
15*25da2beaSAndroid Build Coastguard Worker struct test_ctx {
16*25da2beaSAndroid Build Coastguard Worker int real_pipe1[2];
17*25da2beaSAndroid Build Coastguard Worker int real_pipe2[2];
18*25da2beaSAndroid Build Coastguard Worker int real_fd_in;
19*25da2beaSAndroid Build Coastguard Worker int real_fd_out;
20*25da2beaSAndroid Build Coastguard Worker
21*25da2beaSAndroid Build Coastguard Worker /* fds or for registered files */
22*25da2beaSAndroid Build Coastguard Worker int pipe1[2];
23*25da2beaSAndroid Build Coastguard Worker int pipe2[2];
24*25da2beaSAndroid Build Coastguard Worker int fd_in;
25*25da2beaSAndroid Build Coastguard Worker int fd_out;
26*25da2beaSAndroid Build Coastguard Worker
27*25da2beaSAndroid Build Coastguard Worker void *buf_in;
28*25da2beaSAndroid Build Coastguard Worker void *buf_out;
29*25da2beaSAndroid Build Coastguard Worker };
30*25da2beaSAndroid Build Coastguard Worker
31*25da2beaSAndroid Build Coastguard Worker static unsigned int splice_flags = 0;
32*25da2beaSAndroid Build Coastguard Worker static unsigned int sqe_flags = 0;
33*25da2beaSAndroid Build Coastguard Worker static int has_splice = 0;
34*25da2beaSAndroid Build Coastguard Worker static int has_tee = 0;
35*25da2beaSAndroid Build Coastguard Worker
read_buf(int fd,void * buf,int len)36*25da2beaSAndroid Build Coastguard Worker static int read_buf(int fd, void *buf, int len)
37*25da2beaSAndroid Build Coastguard Worker {
38*25da2beaSAndroid Build Coastguard Worker int ret;
39*25da2beaSAndroid Build Coastguard Worker
40*25da2beaSAndroid Build Coastguard Worker while (len) {
41*25da2beaSAndroid Build Coastguard Worker ret = read(fd, buf, len);
42*25da2beaSAndroid Build Coastguard Worker if (ret < 0)
43*25da2beaSAndroid Build Coastguard Worker return ret;
44*25da2beaSAndroid Build Coastguard Worker len -= ret;
45*25da2beaSAndroid Build Coastguard Worker buf += ret;
46*25da2beaSAndroid Build Coastguard Worker }
47*25da2beaSAndroid Build Coastguard Worker return 0;
48*25da2beaSAndroid Build Coastguard Worker }
49*25da2beaSAndroid Build Coastguard Worker
write_buf(int fd,const void * buf,int len)50*25da2beaSAndroid Build Coastguard Worker static int write_buf(int fd, const void *buf, int len)
51*25da2beaSAndroid Build Coastguard Worker {
52*25da2beaSAndroid Build Coastguard Worker int ret;
53*25da2beaSAndroid Build Coastguard Worker
54*25da2beaSAndroid Build Coastguard Worker while (len) {
55*25da2beaSAndroid Build Coastguard Worker ret = write(fd, buf, len);
56*25da2beaSAndroid Build Coastguard Worker if (ret < 0)
57*25da2beaSAndroid Build Coastguard Worker return ret;
58*25da2beaSAndroid Build Coastguard Worker len -= ret;
59*25da2beaSAndroid Build Coastguard Worker buf += ret;
60*25da2beaSAndroid Build Coastguard Worker }
61*25da2beaSAndroid Build Coastguard Worker return 0;
62*25da2beaSAndroid Build Coastguard Worker }
63*25da2beaSAndroid Build Coastguard Worker
check_content(int fd,void * buf,int len,const void * src)64*25da2beaSAndroid Build Coastguard Worker static int check_content(int fd, void *buf, int len, const void *src)
65*25da2beaSAndroid Build Coastguard Worker {
66*25da2beaSAndroid Build Coastguard Worker int ret;
67*25da2beaSAndroid Build Coastguard Worker
68*25da2beaSAndroid Build Coastguard Worker ret = read_buf(fd, buf, len);
69*25da2beaSAndroid Build Coastguard Worker if (ret)
70*25da2beaSAndroid Build Coastguard Worker return ret;
71*25da2beaSAndroid Build Coastguard Worker
72*25da2beaSAndroid Build Coastguard Worker ret = memcmp(buf, src, len);
73*25da2beaSAndroid Build Coastguard Worker return (ret != 0) ? -1 : 0;
74*25da2beaSAndroid Build Coastguard Worker }
75*25da2beaSAndroid Build Coastguard Worker
create_file(const char * filename)76*25da2beaSAndroid Build Coastguard Worker static int create_file(const char *filename)
77*25da2beaSAndroid Build Coastguard Worker {
78*25da2beaSAndroid Build Coastguard Worker int fd, save_errno;
79*25da2beaSAndroid Build Coastguard Worker
80*25da2beaSAndroid Build Coastguard Worker fd = open(filename, O_RDWR | O_CREAT, 0644);
81*25da2beaSAndroid Build Coastguard Worker save_errno = errno;
82*25da2beaSAndroid Build Coastguard Worker unlink(filename);
83*25da2beaSAndroid Build Coastguard Worker errno = save_errno;
84*25da2beaSAndroid Build Coastguard Worker return fd;
85*25da2beaSAndroid Build Coastguard Worker }
86*25da2beaSAndroid Build Coastguard Worker
init_splice_ctx(struct test_ctx * ctx)87*25da2beaSAndroid Build Coastguard Worker static int init_splice_ctx(struct test_ctx *ctx)
88*25da2beaSAndroid Build Coastguard Worker {
89*25da2beaSAndroid Build Coastguard Worker int ret, rnd_fd;
90*25da2beaSAndroid Build Coastguard Worker
91*25da2beaSAndroid Build Coastguard Worker ctx->buf_in = t_calloc(BUF_SIZE, 1);
92*25da2beaSAndroid Build Coastguard Worker ctx->buf_out = t_calloc(BUF_SIZE, 1);
93*25da2beaSAndroid Build Coastguard Worker
94*25da2beaSAndroid Build Coastguard Worker ctx->fd_in = create_file(".splice-test-in");
95*25da2beaSAndroid Build Coastguard Worker if (ctx->fd_in < 0) {
96*25da2beaSAndroid Build Coastguard Worker perror("file open");
97*25da2beaSAndroid Build Coastguard Worker return 1;
98*25da2beaSAndroid Build Coastguard Worker }
99*25da2beaSAndroid Build Coastguard Worker
100*25da2beaSAndroid Build Coastguard Worker ctx->fd_out = create_file(".splice-test-out");
101*25da2beaSAndroid Build Coastguard Worker if (ctx->fd_out < 0) {
102*25da2beaSAndroid Build Coastguard Worker perror("file open");
103*25da2beaSAndroid Build Coastguard Worker return 1;
104*25da2beaSAndroid Build Coastguard Worker }
105*25da2beaSAndroid Build Coastguard Worker
106*25da2beaSAndroid Build Coastguard Worker /* get random data */
107*25da2beaSAndroid Build Coastguard Worker rnd_fd = open("/dev/urandom", O_RDONLY);
108*25da2beaSAndroid Build Coastguard Worker if (rnd_fd < 0)
109*25da2beaSAndroid Build Coastguard Worker return 1;
110*25da2beaSAndroid Build Coastguard Worker
111*25da2beaSAndroid Build Coastguard Worker ret = read_buf(rnd_fd, ctx->buf_in, BUF_SIZE);
112*25da2beaSAndroid Build Coastguard Worker if (ret != 0)
113*25da2beaSAndroid Build Coastguard Worker return 1;
114*25da2beaSAndroid Build Coastguard Worker close(rnd_fd);
115*25da2beaSAndroid Build Coastguard Worker
116*25da2beaSAndroid Build Coastguard Worker /* populate file */
117*25da2beaSAndroid Build Coastguard Worker ret = write_buf(ctx->fd_in, ctx->buf_in, BUF_SIZE);
118*25da2beaSAndroid Build Coastguard Worker if (ret)
119*25da2beaSAndroid Build Coastguard Worker return ret;
120*25da2beaSAndroid Build Coastguard Worker
121*25da2beaSAndroid Build Coastguard Worker if (pipe(ctx->pipe1) < 0)
122*25da2beaSAndroid Build Coastguard Worker return 1;
123*25da2beaSAndroid Build Coastguard Worker if (pipe(ctx->pipe2) < 0)
124*25da2beaSAndroid Build Coastguard Worker return 1;
125*25da2beaSAndroid Build Coastguard Worker
126*25da2beaSAndroid Build Coastguard Worker ctx->real_pipe1[0] = ctx->pipe1[0];
127*25da2beaSAndroid Build Coastguard Worker ctx->real_pipe1[1] = ctx->pipe1[1];
128*25da2beaSAndroid Build Coastguard Worker ctx->real_pipe2[0] = ctx->pipe2[0];
129*25da2beaSAndroid Build Coastguard Worker ctx->real_pipe2[1] = ctx->pipe2[1];
130*25da2beaSAndroid Build Coastguard Worker ctx->real_fd_in = ctx->fd_in;
131*25da2beaSAndroid Build Coastguard Worker ctx->real_fd_out = ctx->fd_out;
132*25da2beaSAndroid Build Coastguard Worker return 0;
133*25da2beaSAndroid Build Coastguard Worker }
134*25da2beaSAndroid Build Coastguard Worker
do_splice_op(struct io_uring * ring,int fd_in,loff_t off_in,int fd_out,loff_t off_out,unsigned int len,__u8 opcode)135*25da2beaSAndroid Build Coastguard Worker static int do_splice_op(struct io_uring *ring,
136*25da2beaSAndroid Build Coastguard Worker int fd_in, loff_t off_in,
137*25da2beaSAndroid Build Coastguard Worker int fd_out, loff_t off_out,
138*25da2beaSAndroid Build Coastguard Worker unsigned int len,
139*25da2beaSAndroid Build Coastguard Worker __u8 opcode)
140*25da2beaSAndroid Build Coastguard Worker {
141*25da2beaSAndroid Build Coastguard Worker struct io_uring_cqe *cqe;
142*25da2beaSAndroid Build Coastguard Worker struct io_uring_sqe *sqe;
143*25da2beaSAndroid Build Coastguard Worker int ret = -1;
144*25da2beaSAndroid Build Coastguard Worker
145*25da2beaSAndroid Build Coastguard Worker do {
146*25da2beaSAndroid Build Coastguard Worker sqe = io_uring_get_sqe(ring);
147*25da2beaSAndroid Build Coastguard Worker if (!sqe) {
148*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "get sqe failed\n");
149*25da2beaSAndroid Build Coastguard Worker return -1;
150*25da2beaSAndroid Build Coastguard Worker }
151*25da2beaSAndroid Build Coastguard Worker io_uring_prep_splice(sqe, fd_in, off_in, fd_out, off_out,
152*25da2beaSAndroid Build Coastguard Worker len, splice_flags);
153*25da2beaSAndroid Build Coastguard Worker sqe->flags |= sqe_flags;
154*25da2beaSAndroid Build Coastguard Worker sqe->user_data = 42;
155*25da2beaSAndroid Build Coastguard Worker sqe->opcode = opcode;
156*25da2beaSAndroid Build Coastguard Worker
157*25da2beaSAndroid Build Coastguard Worker ret = io_uring_submit(ring);
158*25da2beaSAndroid Build Coastguard Worker if (ret != 1) {
159*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "sqe submit failed: %d\n", ret);
160*25da2beaSAndroid Build Coastguard Worker return ret;
161*25da2beaSAndroid Build Coastguard Worker }
162*25da2beaSAndroid Build Coastguard Worker
163*25da2beaSAndroid Build Coastguard Worker ret = io_uring_wait_cqe(ring, &cqe);
164*25da2beaSAndroid Build Coastguard Worker if (ret < 0) {
165*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "wait completion %d\n", cqe->res);
166*25da2beaSAndroid Build Coastguard Worker return ret;
167*25da2beaSAndroid Build Coastguard Worker }
168*25da2beaSAndroid Build Coastguard Worker
169*25da2beaSAndroid Build Coastguard Worker if (cqe->res <= 0) {
170*25da2beaSAndroid Build Coastguard Worker io_uring_cqe_seen(ring, cqe);
171*25da2beaSAndroid Build Coastguard Worker return cqe->res;
172*25da2beaSAndroid Build Coastguard Worker }
173*25da2beaSAndroid Build Coastguard Worker
174*25da2beaSAndroid Build Coastguard Worker len -= cqe->res;
175*25da2beaSAndroid Build Coastguard Worker if (off_in != -1)
176*25da2beaSAndroid Build Coastguard Worker off_in += cqe->res;
177*25da2beaSAndroid Build Coastguard Worker if (off_out != -1)
178*25da2beaSAndroid Build Coastguard Worker off_out += cqe->res;
179*25da2beaSAndroid Build Coastguard Worker io_uring_cqe_seen(ring, cqe);
180*25da2beaSAndroid Build Coastguard Worker } while (len);
181*25da2beaSAndroid Build Coastguard Worker
182*25da2beaSAndroid Build Coastguard Worker return 0;
183*25da2beaSAndroid Build Coastguard Worker }
184*25da2beaSAndroid Build Coastguard Worker
do_splice(struct io_uring * ring,int fd_in,loff_t off_in,int fd_out,loff_t off_out,unsigned int len)185*25da2beaSAndroid Build Coastguard Worker static int do_splice(struct io_uring *ring,
186*25da2beaSAndroid Build Coastguard Worker int fd_in, loff_t off_in,
187*25da2beaSAndroid Build Coastguard Worker int fd_out, loff_t off_out,
188*25da2beaSAndroid Build Coastguard Worker unsigned int len)
189*25da2beaSAndroid Build Coastguard Worker {
190*25da2beaSAndroid Build Coastguard Worker return do_splice_op(ring, fd_in, off_in, fd_out, off_out, len,
191*25da2beaSAndroid Build Coastguard Worker IORING_OP_SPLICE);
192*25da2beaSAndroid Build Coastguard Worker }
193*25da2beaSAndroid Build Coastguard Worker
do_tee(struct io_uring * ring,int fd_in,int fd_out,unsigned int len)194*25da2beaSAndroid Build Coastguard Worker static int do_tee(struct io_uring *ring, int fd_in, int fd_out,
195*25da2beaSAndroid Build Coastguard Worker unsigned int len)
196*25da2beaSAndroid Build Coastguard Worker {
197*25da2beaSAndroid Build Coastguard Worker return do_splice_op(ring, fd_in, 0, fd_out, 0, len, IORING_OP_TEE);
198*25da2beaSAndroid Build Coastguard Worker }
199*25da2beaSAndroid Build Coastguard Worker
check_splice_support(struct io_uring * ring,struct test_ctx * ctx)200*25da2beaSAndroid Build Coastguard Worker static void check_splice_support(struct io_uring *ring, struct test_ctx *ctx)
201*25da2beaSAndroid Build Coastguard Worker {
202*25da2beaSAndroid Build Coastguard Worker int ret;
203*25da2beaSAndroid Build Coastguard Worker
204*25da2beaSAndroid Build Coastguard Worker ret = do_splice(ring, -1, 0, -1, 0, BUF_SIZE);
205*25da2beaSAndroid Build Coastguard Worker has_splice = (ret == -EBADF);
206*25da2beaSAndroid Build Coastguard Worker }
207*25da2beaSAndroid Build Coastguard Worker
check_tee_support(struct io_uring * ring,struct test_ctx * ctx)208*25da2beaSAndroid Build Coastguard Worker static void check_tee_support(struct io_uring *ring, struct test_ctx *ctx)
209*25da2beaSAndroid Build Coastguard Worker {
210*25da2beaSAndroid Build Coastguard Worker int ret;
211*25da2beaSAndroid Build Coastguard Worker
212*25da2beaSAndroid Build Coastguard Worker ret = do_tee(ring, -1, -1, BUF_SIZE);
213*25da2beaSAndroid Build Coastguard Worker has_tee = (ret == -EBADF);
214*25da2beaSAndroid Build Coastguard Worker }
215*25da2beaSAndroid Build Coastguard Worker
check_zero_splice(struct io_uring * ring,struct test_ctx * ctx)216*25da2beaSAndroid Build Coastguard Worker static int check_zero_splice(struct io_uring *ring, struct test_ctx *ctx)
217*25da2beaSAndroid Build Coastguard Worker {
218*25da2beaSAndroid Build Coastguard Worker int ret;
219*25da2beaSAndroid Build Coastguard Worker
220*25da2beaSAndroid Build Coastguard Worker ret = do_splice(ring, ctx->fd_in, -1, ctx->pipe1[1], -1, 0);
221*25da2beaSAndroid Build Coastguard Worker if (ret)
222*25da2beaSAndroid Build Coastguard Worker return ret;
223*25da2beaSAndroid Build Coastguard Worker
224*25da2beaSAndroid Build Coastguard Worker ret = do_splice(ring, ctx->pipe2[0], -1, ctx->pipe1[1], -1, 0);
225*25da2beaSAndroid Build Coastguard Worker if (ret)
226*25da2beaSAndroid Build Coastguard Worker return ret;
227*25da2beaSAndroid Build Coastguard Worker
228*25da2beaSAndroid Build Coastguard Worker return 0;
229*25da2beaSAndroid Build Coastguard Worker }
230*25da2beaSAndroid Build Coastguard Worker
splice_to_pipe(struct io_uring * ring,struct test_ctx * ctx)231*25da2beaSAndroid Build Coastguard Worker static int splice_to_pipe(struct io_uring *ring, struct test_ctx *ctx)
232*25da2beaSAndroid Build Coastguard Worker {
233*25da2beaSAndroid Build Coastguard Worker int ret;
234*25da2beaSAndroid Build Coastguard Worker
235*25da2beaSAndroid Build Coastguard Worker ret = lseek(ctx->real_fd_in, 0, SEEK_SET);
236*25da2beaSAndroid Build Coastguard Worker if (ret)
237*25da2beaSAndroid Build Coastguard Worker return ret;
238*25da2beaSAndroid Build Coastguard Worker
239*25da2beaSAndroid Build Coastguard Worker /* implicit file offset */
240*25da2beaSAndroid Build Coastguard Worker ret = do_splice(ring, ctx->fd_in, -1, ctx->pipe1[1], -1, BUF_SIZE);
241*25da2beaSAndroid Build Coastguard Worker if (ret)
242*25da2beaSAndroid Build Coastguard Worker return ret;
243*25da2beaSAndroid Build Coastguard Worker
244*25da2beaSAndroid Build Coastguard Worker ret = check_content(ctx->real_pipe1[0], ctx->buf_out, BUF_SIZE,
245*25da2beaSAndroid Build Coastguard Worker ctx->buf_in);
246*25da2beaSAndroid Build Coastguard Worker if (ret)
247*25da2beaSAndroid Build Coastguard Worker return ret;
248*25da2beaSAndroid Build Coastguard Worker
249*25da2beaSAndroid Build Coastguard Worker /* explicit file offset */
250*25da2beaSAndroid Build Coastguard Worker ret = do_splice(ring, ctx->fd_in, 0, ctx->pipe1[1], -1, BUF_SIZE);
251*25da2beaSAndroid Build Coastguard Worker if (ret)
252*25da2beaSAndroid Build Coastguard Worker return ret;
253*25da2beaSAndroid Build Coastguard Worker
254*25da2beaSAndroid Build Coastguard Worker return check_content(ctx->real_pipe1[0], ctx->buf_out, BUF_SIZE,
255*25da2beaSAndroid Build Coastguard Worker ctx->buf_in);
256*25da2beaSAndroid Build Coastguard Worker }
257*25da2beaSAndroid Build Coastguard Worker
splice_from_pipe(struct io_uring * ring,struct test_ctx * ctx)258*25da2beaSAndroid Build Coastguard Worker static int splice_from_pipe(struct io_uring *ring, struct test_ctx *ctx)
259*25da2beaSAndroid Build Coastguard Worker {
260*25da2beaSAndroid Build Coastguard Worker int ret;
261*25da2beaSAndroid Build Coastguard Worker
262*25da2beaSAndroid Build Coastguard Worker ret = write_buf(ctx->real_pipe1[1], ctx->buf_in, BUF_SIZE);
263*25da2beaSAndroid Build Coastguard Worker if (ret)
264*25da2beaSAndroid Build Coastguard Worker return ret;
265*25da2beaSAndroid Build Coastguard Worker ret = do_splice(ring, ctx->pipe1[0], -1, ctx->fd_out, 0, BUF_SIZE);
266*25da2beaSAndroid Build Coastguard Worker if (ret)
267*25da2beaSAndroid Build Coastguard Worker return ret;
268*25da2beaSAndroid Build Coastguard Worker ret = check_content(ctx->real_fd_out, ctx->buf_out, BUF_SIZE,
269*25da2beaSAndroid Build Coastguard Worker ctx->buf_in);
270*25da2beaSAndroid Build Coastguard Worker if (ret)
271*25da2beaSAndroid Build Coastguard Worker return ret;
272*25da2beaSAndroid Build Coastguard Worker
273*25da2beaSAndroid Build Coastguard Worker ret = ftruncate(ctx->real_fd_out, 0);
274*25da2beaSAndroid Build Coastguard Worker if (ret)
275*25da2beaSAndroid Build Coastguard Worker return ret;
276*25da2beaSAndroid Build Coastguard Worker return lseek(ctx->real_fd_out, 0, SEEK_SET);
277*25da2beaSAndroid Build Coastguard Worker }
278*25da2beaSAndroid Build Coastguard Worker
splice_pipe_to_pipe(struct io_uring * ring,struct test_ctx * ctx)279*25da2beaSAndroid Build Coastguard Worker static int splice_pipe_to_pipe(struct io_uring *ring, struct test_ctx *ctx)
280*25da2beaSAndroid Build Coastguard Worker {
281*25da2beaSAndroid Build Coastguard Worker int ret;
282*25da2beaSAndroid Build Coastguard Worker
283*25da2beaSAndroid Build Coastguard Worker ret = do_splice(ring, ctx->fd_in, 0, ctx->pipe1[1], -1, BUF_SIZE);
284*25da2beaSAndroid Build Coastguard Worker if (ret)
285*25da2beaSAndroid Build Coastguard Worker return ret;
286*25da2beaSAndroid Build Coastguard Worker ret = do_splice(ring, ctx->pipe1[0], -1, ctx->pipe2[1], -1, BUF_SIZE);
287*25da2beaSAndroid Build Coastguard Worker if (ret)
288*25da2beaSAndroid Build Coastguard Worker return ret;
289*25da2beaSAndroid Build Coastguard Worker
290*25da2beaSAndroid Build Coastguard Worker return check_content(ctx->real_pipe2[0], ctx->buf_out, BUF_SIZE,
291*25da2beaSAndroid Build Coastguard Worker ctx->buf_in);
292*25da2beaSAndroid Build Coastguard Worker }
293*25da2beaSAndroid Build Coastguard Worker
fail_splice_pipe_offset(struct io_uring * ring,struct test_ctx * ctx)294*25da2beaSAndroid Build Coastguard Worker static int fail_splice_pipe_offset(struct io_uring *ring, struct test_ctx *ctx)
295*25da2beaSAndroid Build Coastguard Worker {
296*25da2beaSAndroid Build Coastguard Worker int ret;
297*25da2beaSAndroid Build Coastguard Worker
298*25da2beaSAndroid Build Coastguard Worker ret = do_splice(ring, ctx->fd_in, 0, ctx->pipe1[1], 0, BUF_SIZE);
299*25da2beaSAndroid Build Coastguard Worker if (ret != -ESPIPE && ret != -EINVAL)
300*25da2beaSAndroid Build Coastguard Worker return ret;
301*25da2beaSAndroid Build Coastguard Worker
302*25da2beaSAndroid Build Coastguard Worker ret = do_splice(ring, ctx->pipe1[0], 0, ctx->fd_out, 0, BUF_SIZE);
303*25da2beaSAndroid Build Coastguard Worker if (ret != -ESPIPE && ret != -EINVAL)
304*25da2beaSAndroid Build Coastguard Worker return ret;
305*25da2beaSAndroid Build Coastguard Worker
306*25da2beaSAndroid Build Coastguard Worker return 0;
307*25da2beaSAndroid Build Coastguard Worker }
308*25da2beaSAndroid Build Coastguard Worker
fail_tee_nonpipe(struct io_uring * ring,struct test_ctx * ctx)309*25da2beaSAndroid Build Coastguard Worker static int fail_tee_nonpipe(struct io_uring *ring, struct test_ctx *ctx)
310*25da2beaSAndroid Build Coastguard Worker {
311*25da2beaSAndroid Build Coastguard Worker int ret;
312*25da2beaSAndroid Build Coastguard Worker
313*25da2beaSAndroid Build Coastguard Worker ret = do_tee(ring, ctx->fd_in, ctx->pipe1[1], BUF_SIZE);
314*25da2beaSAndroid Build Coastguard Worker if (ret != -ESPIPE && ret != -EINVAL)
315*25da2beaSAndroid Build Coastguard Worker return ret;
316*25da2beaSAndroid Build Coastguard Worker
317*25da2beaSAndroid Build Coastguard Worker return 0;
318*25da2beaSAndroid Build Coastguard Worker }
319*25da2beaSAndroid Build Coastguard Worker
fail_tee_offset(struct io_uring * ring,struct test_ctx * ctx)320*25da2beaSAndroid Build Coastguard Worker static int fail_tee_offset(struct io_uring *ring, struct test_ctx *ctx)
321*25da2beaSAndroid Build Coastguard Worker {
322*25da2beaSAndroid Build Coastguard Worker int ret;
323*25da2beaSAndroid Build Coastguard Worker
324*25da2beaSAndroid Build Coastguard Worker ret = do_splice_op(ring, ctx->pipe2[0], -1, ctx->pipe1[1], 0,
325*25da2beaSAndroid Build Coastguard Worker BUF_SIZE, IORING_OP_TEE);
326*25da2beaSAndroid Build Coastguard Worker if (ret != -ESPIPE && ret != -EINVAL)
327*25da2beaSAndroid Build Coastguard Worker return ret;
328*25da2beaSAndroid Build Coastguard Worker
329*25da2beaSAndroid Build Coastguard Worker ret = do_splice_op(ring, ctx->pipe2[0], 0, ctx->pipe1[1], -1,
330*25da2beaSAndroid Build Coastguard Worker BUF_SIZE, IORING_OP_TEE);
331*25da2beaSAndroid Build Coastguard Worker if (ret != -ESPIPE && ret != -EINVAL)
332*25da2beaSAndroid Build Coastguard Worker return ret;
333*25da2beaSAndroid Build Coastguard Worker
334*25da2beaSAndroid Build Coastguard Worker return 0;
335*25da2beaSAndroid Build Coastguard Worker }
336*25da2beaSAndroid Build Coastguard Worker
check_tee(struct io_uring * ring,struct test_ctx * ctx)337*25da2beaSAndroid Build Coastguard Worker static int check_tee(struct io_uring *ring, struct test_ctx *ctx)
338*25da2beaSAndroid Build Coastguard Worker {
339*25da2beaSAndroid Build Coastguard Worker int ret;
340*25da2beaSAndroid Build Coastguard Worker
341*25da2beaSAndroid Build Coastguard Worker ret = write_buf(ctx->real_pipe1[1], ctx->buf_in, BUF_SIZE);
342*25da2beaSAndroid Build Coastguard Worker if (ret)
343*25da2beaSAndroid Build Coastguard Worker return ret;
344*25da2beaSAndroid Build Coastguard Worker ret = do_tee(ring, ctx->pipe1[0], ctx->pipe2[1], BUF_SIZE);
345*25da2beaSAndroid Build Coastguard Worker if (ret)
346*25da2beaSAndroid Build Coastguard Worker return ret;
347*25da2beaSAndroid Build Coastguard Worker
348*25da2beaSAndroid Build Coastguard Worker ret = check_content(ctx->real_pipe1[0], ctx->buf_out, BUF_SIZE,
349*25da2beaSAndroid Build Coastguard Worker ctx->buf_in);
350*25da2beaSAndroid Build Coastguard Worker if (ret) {
351*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "tee(), invalid src data\n");
352*25da2beaSAndroid Build Coastguard Worker return ret;
353*25da2beaSAndroid Build Coastguard Worker }
354*25da2beaSAndroid Build Coastguard Worker
355*25da2beaSAndroid Build Coastguard Worker ret = check_content(ctx->real_pipe2[0], ctx->buf_out, BUF_SIZE,
356*25da2beaSAndroid Build Coastguard Worker ctx->buf_in);
357*25da2beaSAndroid Build Coastguard Worker if (ret) {
358*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "tee(), invalid dst data\n");
359*25da2beaSAndroid Build Coastguard Worker return ret;
360*25da2beaSAndroid Build Coastguard Worker }
361*25da2beaSAndroid Build Coastguard Worker
362*25da2beaSAndroid Build Coastguard Worker return 0;
363*25da2beaSAndroid Build Coastguard Worker }
364*25da2beaSAndroid Build Coastguard Worker
check_zero_tee(struct io_uring * ring,struct test_ctx * ctx)365*25da2beaSAndroid Build Coastguard Worker static int check_zero_tee(struct io_uring *ring, struct test_ctx *ctx)
366*25da2beaSAndroid Build Coastguard Worker {
367*25da2beaSAndroid Build Coastguard Worker return do_tee(ring, ctx->pipe2[0], ctx->pipe1[1], 0);
368*25da2beaSAndroid Build Coastguard Worker }
369*25da2beaSAndroid Build Coastguard Worker
test_splice(struct io_uring * ring,struct test_ctx * ctx)370*25da2beaSAndroid Build Coastguard Worker static int test_splice(struct io_uring *ring, struct test_ctx *ctx)
371*25da2beaSAndroid Build Coastguard Worker {
372*25da2beaSAndroid Build Coastguard Worker int ret;
373*25da2beaSAndroid Build Coastguard Worker
374*25da2beaSAndroid Build Coastguard Worker if (has_splice) {
375*25da2beaSAndroid Build Coastguard Worker ret = check_zero_splice(ring, ctx);
376*25da2beaSAndroid Build Coastguard Worker if (ret) {
377*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "check_zero_splice failed %i %i\n",
378*25da2beaSAndroid Build Coastguard Worker ret, errno);
379*25da2beaSAndroid Build Coastguard Worker return ret;
380*25da2beaSAndroid Build Coastguard Worker }
381*25da2beaSAndroid Build Coastguard Worker
382*25da2beaSAndroid Build Coastguard Worker ret = splice_to_pipe(ring, ctx);
383*25da2beaSAndroid Build Coastguard Worker if (ret) {
384*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "splice_to_pipe failed %i %i\n",
385*25da2beaSAndroid Build Coastguard Worker ret, errno);
386*25da2beaSAndroid Build Coastguard Worker return ret;
387*25da2beaSAndroid Build Coastguard Worker }
388*25da2beaSAndroid Build Coastguard Worker
389*25da2beaSAndroid Build Coastguard Worker ret = splice_from_pipe(ring, ctx);
390*25da2beaSAndroid Build Coastguard Worker if (ret) {
391*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "splice_from_pipe failed %i %i\n",
392*25da2beaSAndroid Build Coastguard Worker ret, errno);
393*25da2beaSAndroid Build Coastguard Worker return ret;
394*25da2beaSAndroid Build Coastguard Worker }
395*25da2beaSAndroid Build Coastguard Worker
396*25da2beaSAndroid Build Coastguard Worker ret = splice_pipe_to_pipe(ring, ctx);
397*25da2beaSAndroid Build Coastguard Worker if (ret) {
398*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "splice_pipe_to_pipe failed %i %i\n",
399*25da2beaSAndroid Build Coastguard Worker ret, errno);
400*25da2beaSAndroid Build Coastguard Worker return ret;
401*25da2beaSAndroid Build Coastguard Worker }
402*25da2beaSAndroid Build Coastguard Worker
403*25da2beaSAndroid Build Coastguard Worker ret = fail_splice_pipe_offset(ring, ctx);
404*25da2beaSAndroid Build Coastguard Worker if (ret) {
405*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "fail_splice_pipe_offset failed %i %i\n",
406*25da2beaSAndroid Build Coastguard Worker ret, errno);
407*25da2beaSAndroid Build Coastguard Worker return ret;
408*25da2beaSAndroid Build Coastguard Worker }
409*25da2beaSAndroid Build Coastguard Worker }
410*25da2beaSAndroid Build Coastguard Worker
411*25da2beaSAndroid Build Coastguard Worker if (has_tee) {
412*25da2beaSAndroid Build Coastguard Worker ret = check_zero_tee(ring, ctx);
413*25da2beaSAndroid Build Coastguard Worker if (ret) {
414*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "check_zero_tee() failed %i %i\n",
415*25da2beaSAndroid Build Coastguard Worker ret, errno);
416*25da2beaSAndroid Build Coastguard Worker return ret;
417*25da2beaSAndroid Build Coastguard Worker }
418*25da2beaSAndroid Build Coastguard Worker
419*25da2beaSAndroid Build Coastguard Worker ret = fail_tee_nonpipe(ring, ctx);
420*25da2beaSAndroid Build Coastguard Worker if (ret) {
421*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "fail_tee_nonpipe() failed %i %i\n",
422*25da2beaSAndroid Build Coastguard Worker ret, errno);
423*25da2beaSAndroid Build Coastguard Worker return ret;
424*25da2beaSAndroid Build Coastguard Worker }
425*25da2beaSAndroid Build Coastguard Worker
426*25da2beaSAndroid Build Coastguard Worker ret = fail_tee_offset(ring, ctx);
427*25da2beaSAndroid Build Coastguard Worker if (ret) {
428*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "fail_tee_offset failed %i %i\n",
429*25da2beaSAndroid Build Coastguard Worker ret, errno);
430*25da2beaSAndroid Build Coastguard Worker return ret;
431*25da2beaSAndroid Build Coastguard Worker }
432*25da2beaSAndroid Build Coastguard Worker
433*25da2beaSAndroid Build Coastguard Worker ret = check_tee(ring, ctx);
434*25da2beaSAndroid Build Coastguard Worker if (ret) {
435*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "check_tee() failed %i %i\n",
436*25da2beaSAndroid Build Coastguard Worker ret, errno);
437*25da2beaSAndroid Build Coastguard Worker return ret;
438*25da2beaSAndroid Build Coastguard Worker }
439*25da2beaSAndroid Build Coastguard Worker }
440*25da2beaSAndroid Build Coastguard Worker
441*25da2beaSAndroid Build Coastguard Worker return 0;
442*25da2beaSAndroid Build Coastguard Worker }
443*25da2beaSAndroid Build Coastguard Worker
main(int argc,char * argv[])444*25da2beaSAndroid Build Coastguard Worker int main(int argc, char *argv[])
445*25da2beaSAndroid Build Coastguard Worker {
446*25da2beaSAndroid Build Coastguard Worker struct io_uring ring;
447*25da2beaSAndroid Build Coastguard Worker struct io_uring_params p = { };
448*25da2beaSAndroid Build Coastguard Worker struct test_ctx ctx;
449*25da2beaSAndroid Build Coastguard Worker int ret;
450*25da2beaSAndroid Build Coastguard Worker int reg_fds[6];
451*25da2beaSAndroid Build Coastguard Worker
452*25da2beaSAndroid Build Coastguard Worker if (argc > 1)
453*25da2beaSAndroid Build Coastguard Worker return 0;
454*25da2beaSAndroid Build Coastguard Worker
455*25da2beaSAndroid Build Coastguard Worker ret = io_uring_queue_init_params(8, &ring, &p);
456*25da2beaSAndroid Build Coastguard Worker if (ret) {
457*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "ring setup failed\n");
458*25da2beaSAndroid Build Coastguard Worker return 1;
459*25da2beaSAndroid Build Coastguard Worker }
460*25da2beaSAndroid Build Coastguard Worker if (!(p.features & IORING_FEAT_FAST_POLL)) {
461*25da2beaSAndroid Build Coastguard Worker fprintf(stdout, "No splice support, skipping\n");
462*25da2beaSAndroid Build Coastguard Worker return 0;
463*25da2beaSAndroid Build Coastguard Worker }
464*25da2beaSAndroid Build Coastguard Worker
465*25da2beaSAndroid Build Coastguard Worker ret = init_splice_ctx(&ctx);
466*25da2beaSAndroid Build Coastguard Worker if (ret) {
467*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "init failed %i %i\n", ret, errno);
468*25da2beaSAndroid Build Coastguard Worker return 1;
469*25da2beaSAndroid Build Coastguard Worker }
470*25da2beaSAndroid Build Coastguard Worker
471*25da2beaSAndroid Build Coastguard Worker check_splice_support(&ring, &ctx);
472*25da2beaSAndroid Build Coastguard Worker if (!has_splice)
473*25da2beaSAndroid Build Coastguard Worker fprintf(stdout, "skip, doesn't support splice()\n");
474*25da2beaSAndroid Build Coastguard Worker check_tee_support(&ring, &ctx);
475*25da2beaSAndroid Build Coastguard Worker if (!has_tee)
476*25da2beaSAndroid Build Coastguard Worker fprintf(stdout, "skip, doesn't support tee()\n");
477*25da2beaSAndroid Build Coastguard Worker
478*25da2beaSAndroid Build Coastguard Worker ret = test_splice(&ring, &ctx);
479*25da2beaSAndroid Build Coastguard Worker if (ret) {
480*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "basic splice tests failed\n");
481*25da2beaSAndroid Build Coastguard Worker return ret;
482*25da2beaSAndroid Build Coastguard Worker }
483*25da2beaSAndroid Build Coastguard Worker
484*25da2beaSAndroid Build Coastguard Worker reg_fds[0] = ctx.real_pipe1[0];
485*25da2beaSAndroid Build Coastguard Worker reg_fds[1] = ctx.real_pipe1[1];
486*25da2beaSAndroid Build Coastguard Worker reg_fds[2] = ctx.real_pipe2[0];
487*25da2beaSAndroid Build Coastguard Worker reg_fds[3] = ctx.real_pipe2[1];
488*25da2beaSAndroid Build Coastguard Worker reg_fds[4] = ctx.real_fd_in;
489*25da2beaSAndroid Build Coastguard Worker reg_fds[5] = ctx.real_fd_out;
490*25da2beaSAndroid Build Coastguard Worker ret = io_uring_register_files(&ring, reg_fds, 6);
491*25da2beaSAndroid Build Coastguard Worker if (ret) {
492*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "%s: register ret=%d\n", __FUNCTION__, ret);
493*25da2beaSAndroid Build Coastguard Worker return 1;
494*25da2beaSAndroid Build Coastguard Worker }
495*25da2beaSAndroid Build Coastguard Worker
496*25da2beaSAndroid Build Coastguard Worker /* remap fds to registered */
497*25da2beaSAndroid Build Coastguard Worker ctx.pipe1[0] = 0;
498*25da2beaSAndroid Build Coastguard Worker ctx.pipe1[1] = 1;
499*25da2beaSAndroid Build Coastguard Worker ctx.pipe2[0] = 2;
500*25da2beaSAndroid Build Coastguard Worker ctx.pipe2[1] = 3;
501*25da2beaSAndroid Build Coastguard Worker ctx.fd_in = 4;
502*25da2beaSAndroid Build Coastguard Worker ctx.fd_out = 5;
503*25da2beaSAndroid Build Coastguard Worker
504*25da2beaSAndroid Build Coastguard Worker splice_flags = SPLICE_F_FD_IN_FIXED;
505*25da2beaSAndroid Build Coastguard Worker sqe_flags = IOSQE_FIXED_FILE;
506*25da2beaSAndroid Build Coastguard Worker ret = test_splice(&ring, &ctx);
507*25da2beaSAndroid Build Coastguard Worker if (ret) {
508*25da2beaSAndroid Build Coastguard Worker fprintf(stderr, "registered fds splice tests failed\n");
509*25da2beaSAndroid Build Coastguard Worker return ret;
510*25da2beaSAndroid Build Coastguard Worker }
511*25da2beaSAndroid Build Coastguard Worker return 0;
512*25da2beaSAndroid Build Coastguard Worker }
513