xref: /aosp_15_r20/external/liburing/test/splice.c (revision 25da2bea747f3a93b4c30fd9708b0618ef55a0e6)
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