Add tee() tests with pipe data validation Signed-off-by: Pavel Begunkov <asml.silence@xxxxxxxxx> --- test/splice.c | 184 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 157 insertions(+), 27 deletions(-) diff --git a/test/splice.c b/test/splice.c index 50a1feb..b084d04 100644 --- a/test/splice.c +++ b/test/splice.c @@ -29,6 +29,8 @@ struct test_ctx { static int splice_flags = 0; static int sqe_flags = 0; static int no_op = 0; +static int has_splice = 0; +static int has_tee = 0; static int read_buf(int fd, void *buf, int len) { @@ -133,10 +135,11 @@ static int init_splice_ctx(struct test_ctx *ctx) return 0; } -static int do_splice(struct io_uring *ring, - int fd_in, loff_t off_in, - int fd_out, loff_t off_out, - unsigned int len) +static int 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) { struct io_uring_cqe *cqe; struct io_uring_sqe *sqe; @@ -152,6 +155,7 @@ static int do_splice(struct io_uring *ring, len, splice_flags); sqe->flags |= sqe_flags; sqe->user_data = 42; + sqe->opcode = opcode; ret = io_uring_submit(ring); if (ret != 1) { @@ -183,18 +187,59 @@ static int do_splice(struct io_uring *ring, return 0; } -static int check_splice(struct io_uring *ring, struct test_ctx *ctx) +static int do_splice(struct io_uring *ring, + int fd_in, loff_t off_in, + int fd_out, loff_t off_out, + unsigned int len) +{ + return do_splice_op(ring, fd_in, off_in, fd_out, off_out, len, + IORING_OP_SPLICE); +} + +static int do_tee(struct io_uring *ring, + int fd_in, loff_t off_in, + int fd_out, loff_t off_out, + unsigned int len) +{ + if (off_in == -1) + off_in = 0; + if (off_out == -1) + off_out = 0; + + return do_splice_op(ring, fd_in, off_in, fd_out, off_out, len, + IORING_OP_TEE); +} + +static void check_splice_support(struct io_uring *ring, struct test_ctx *ctx) { int fds[2]; if (pipe(fds) < 0) - return -1; + return; no_op = 0; do_splice(ring, ctx->fd_in, 0, fds[1], -1, BUF_SIZE); close(fds[0]); close(fds[1]); - return no_op; + has_splice = !no_op; +} + +static void check_tee_support(struct io_uring *ring, struct test_ctx *ctx) +{ + int pipe1[2], pipe2[2]; + + if (pipe(pipe1) < 0) + return; + if (pipe(pipe2) < 0) + return; + + no_op = 0; + do_tee(ring, pipe1[0], -1, pipe2[1], -1, 0); + close(pipe1[0]); + close(pipe1[1]); + close(pipe2[0]); + close(pipe2[1]); + has_tee = !no_op; } static int splice_to_pipe(struct io_uring *ring, struct test_ctx *ctx) @@ -275,37 +320,120 @@ static int fail_splice_pipe_offset(struct io_uring *ring, struct test_ctx *ctx) return 0; } -static int test_splice(struct io_uring *ring, struct test_ctx *ctx) +static int fail_tee_with_file(struct io_uring *ring, struct test_ctx *ctx) { int ret; - ret = splice_to_pipe(ring, ctx); - if (ret) { - fprintf(stderr, "splice_to_pipe failed %i %i\n", - ret, errno); + ret = do_tee(ring, ctx->fd_in, 0, ctx->pipe1[1], 0, BUF_SIZE); + if (ret != -ESPIPE && ret != -EINVAL) return ret; - } - ret = splice_from_pipe(ring, ctx); - if (ret) { - fprintf(stderr, "splice_from_pipe failed %i %i\n", - ret, errno); + return 0; +} + +static int fail_tee_offset(struct io_uring *ring, struct test_ctx *ctx) +{ + int ret; + + ret = do_splice_op(ring, ctx->pipe2[0], -1, ctx->pipe1[1], 0, + BUF_SIZE, IORING_OP_TEE); + if (ret != -ESPIPE && ret != -EINVAL) return ret; - } - ret = splice_pipe_to_pipe(ring, ctx); + ret = do_splice_op(ring, ctx->pipe2[0], 0, ctx->pipe1[1], -1, + BUF_SIZE, IORING_OP_TEE); + if (ret != -ESPIPE && ret != -EINVAL) + return ret; + + return 0; +} + +static int check_tee(struct io_uring *ring, struct test_ctx *ctx) +{ + int ret; + + ret = write_buf(ctx->real_pipe1[1], ctx->buf_in, BUF_SIZE); + if (ret) + return ret; + ret = do_tee(ring, ctx->pipe1[0], -1, ctx->pipe2[1], -1, BUF_SIZE); + if (ret) + return ret; + + ret = check_content(ctx->real_pipe1[0], ctx->buf_out, BUF_SIZE, + ctx->buf_in); if (ret) { - fprintf(stderr, "splice_pipe_to_pipe failed %i %i\n", - ret, errno); + fprintf(stderr, "tee(), invalid src data\n"); return ret; } - ret = fail_splice_pipe_offset(ring, ctx); + ret = check_content(ctx->real_pipe2[0], ctx->buf_out, BUF_SIZE, + ctx->buf_in); if (ret) { - fprintf(stderr, "fail_splice_pipe_offset failed %i %i\n", - ret, errno); + fprintf(stderr, "tee(), invalid dst data\n"); return ret; } + + return 0; +} + + +static int test_splice(struct io_uring *ring, struct test_ctx *ctx) +{ + int ret; + + if (has_splice) { + ret = splice_to_pipe(ring, ctx); + if (ret) { + fprintf(stderr, "splice_to_pipe failed %i %i\n", + ret, errno); + return ret; + } + + ret = splice_from_pipe(ring, ctx); + if (ret) { + fprintf(stderr, "splice_from_pipe failed %i %i\n", + ret, errno); + return ret; + } + + ret = splice_pipe_to_pipe(ring, ctx); + if (ret) { + fprintf(stderr, "splice_pipe_to_pipe failed %i %i\n", + ret, errno); + return ret; + } + + ret = fail_splice_pipe_offset(ring, ctx); + if (ret) { + fprintf(stderr, "fail_splice_pipe_offset failed %i %i\n", + ret, errno); + return ret; + } + } + + if (has_tee) { + ret = fail_tee_with_file(ring, ctx); + if (ret) { + fprintf(stderr, "fail_tee_with_file() failed %i %i\n", + ret, errno); + return ret; + } + + ret = fail_tee_offset(ring, ctx); + if (ret) { + fprintf(stderr, "fail_tee_offset failed %i %i\n", + ret, errno); + return ret; + } + + ret = check_tee(ring, ctx); + if (ret) { + fprintf(stderr, "check_tee() failed %i %i\n", + ret, errno); + return ret; + } + } + return 0; } @@ -328,10 +456,12 @@ int main(int argc, char *argv[]) return 1; } - if (check_splice(&ring, &ctx)) { + check_splice_support(&ring, &ctx); + if (!has_splice) fprintf(stdout, "skip, doesn't support splice()\n"); - return 0; - } + check_tee_support(&ring, &ctx); + if (!has_tee) + fprintf(stdout, "skip, doesn't support tee()\n"); ret = test_splice(&ring, &ctx); if (ret) { -- 2.24.0