Signed-off-by: Pavel Begunkov <asml.silence@xxxxxxxxx> --- test/Makefile | 5 +- test/splice.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 test/splice.c diff --git a/test/Makefile b/test/Makefile index 09c7aa2..8437f31 100644 --- a/test/Makefile +++ b/test/Makefile @@ -20,7 +20,7 @@ all_targets += poll poll-cancel ring-leak fsync io_uring_setup io_uring_register connect 7ad0e4b2f83c-test submit-reuse fallocate open-close \ file-update statx accept-reuse poll-v-poll fadvise madvise \ short-read openat2 probe shared-wq personality eventfd \ - send_recv eventfd-ring across-fork sq-poll-kthread + send_recv eventfd-ring across-fork sq-poll-kthread splice include ../Makefile.quiet @@ -47,7 +47,8 @@ test_srcs := poll.c poll-cancel.c ring-leak.c fsync.c io_uring_setup.c \ 7ad0e4b2f83c-test.c submit-reuse.c fallocate.c open-close.c \ file-update.c statx.c accept-reuse.c poll-v-poll.c fadvise.c \ madvise.c short-read.c openat2.c probe.c shared-wq.c \ - personality.c eventfd.c eventfd-ring.c across-fork.c sq-poll-kthread.c + personality.c eventfd.c eventfd-ring.c across-fork.c sq-poll-kthread.c \ + splice.c test_objs := $(patsubst %.c,%.ol,$(test_srcs)) diff --git a/test/splice.c b/test/splice.c new file mode 100644 index 0000000..1eaa788 --- /dev/null +++ b/test/splice.c @@ -0,0 +1,148 @@ +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <sys/mman.h> + +#include "liburing.h" + +static int no_splice = 0; + +static int copy_single(struct io_uring *ring, + int fd_in, loff_t off_in, + int fd_out, loff_t off_out, + int pipe_fds[2], + unsigned int len, + unsigned flags1, unsigned flags2) +{ + struct io_uring_cqe *cqe; + struct io_uring_sqe *sqe; + int i, ret = -1; + + sqe = io_uring_get_sqe(ring); + if (!sqe) { + fprintf(stderr, "get sqe failed\n"); + return -1; + } + io_uring_prep_splice(sqe, fd_in, off_in, pipe_fds[1], -1, + len, flags1); + sqe->flags = IOSQE_IO_LINK; + + sqe = io_uring_get_sqe(ring); + if (!sqe) { + fprintf(stderr, "get sqe failed\n"); + return -1; + } + io_uring_prep_splice(sqe, pipe_fds[0], -1, fd_out, off_out, + len, flags2); + + ret = io_uring_submit(ring); + if (ret <= 1) { + fprintf(stderr, "sqe submit failed: %d\n", ret); + return -1; + } + + for (i = 0; i < 2; i++) { + ret = io_uring_wait_cqe(ring, &cqe); + if (ret < 0) { + fprintf(stderr, "wait completion %d\n", cqe->res); + return ret; + } + + ret = cqe->res; + if (ret != len) { + fprintf(stderr, "splice: returned %i, expected %i\n", + cqe->res, len); + return ret < 0 ? ret : -1; + } + io_uring_cqe_seen(ring, cqe); + } + return 0; +} + +static int test_splice(struct io_uring *ring) +{ + int ret = -1, len = 4 * 4096; + int fd_out = -1, fd_in = -1; + int pipe_fds[2] = {-1, -1}; + + if (pipe(pipe_fds) < 0) + goto exit; + fd_in = open("/dev/urandom", O_RDONLY); + if (fd_in < 0) + goto exit; + fd_out = memfd_create("splice_test_out_file", 0); + if (fd_out < 0) + goto exit; + if (ftruncate(fd_out, len) == -1) + goto exit; + + ret = copy_single(ring, fd_in, -1, fd_out, -1, pipe_fds, + len, SPLICE_F_MOVE | SPLICE_F_MORE, 0); + if (ret == -EINVAL) { + no_splice = 1; + goto exit; + } + if (ret) { + fprintf(stderr, "basic splice-copy failed\n"); + goto exit; + } + + ret = copy_single(ring, fd_in, 0, fd_out, 0, pipe_fds, + len, 0, SPLICE_F_MOVE | SPLICE_F_MORE); + if (ret) { + fprintf(stderr, "basic splice with offset failed\n"); + goto exit; + } + + ret = io_uring_register_files(ring, &fd_in, 1); + if (ret) { + fprintf(stderr, "%s: register ret=%d\n", __FUNCTION__, ret); + goto exit; + } + + ret = copy_single(ring, 0, 0, fd_out, 0, pipe_fds, + len, SPLICE_F_FD_IN_FIXED, 0); + if (ret) { + fprintf(stderr, "basic splice with reg files failed\n"); + goto exit; + } + + ret = 0; +exit: + if (fd_out >= 0) + close(fd_out); + if (fd_in >= 0) + close(fd_in); + if (pipe_fds[0] >= 0) { + close(pipe_fds[0]); + close(pipe_fds[1]); + } + return ret; +} + +int main(int argc, char *argv[]) +{ + struct io_uring ring; + int ret; + + ret = io_uring_queue_init(8, &ring, 0); + if (ret) { + fprintf(stderr, "ring setup failed\n"); + return 1; + } + + ret = test_splice(&ring); + if (ret && no_splice) { + fprintf(stderr, "skip, doesn't support splice()\n"); + return 0; + } + if (ret) { + fprintf(stderr, "test_splice failed %i %i\n", ret, errno); + return ret; + } + + return 0; +} -- 2.24.0