From: Cyril Hrubis <chrubis@suse.cz>
To: ltp@lists.linux.it
Subject: [LTP] [PATCH V7] syscall: Add io_uring related tests
Date: Tue, 30 Jun 2020 17:16:29 +0200 [thread overview]
Message-ID: <20200630151629.GC12948@yuki.lan> (raw)
In-Reply-To: <20200629055956.32677-1-vikas.kumar2@arm.com>
Hi!
> Added asynchronous I/O API tests for io_uring_setup(), io_uring_register()
> and io_uring_enter(). These tests intend to validate io_uring operations.
>
> 1. io_uring_setup() creates submission queue and completion queue to
> perform subsequent operations on the io_uring instance.
> 2. io_uring_register() registers user buffers in kernel for long term
> usese.
> 3. io_uring_enter() initiates I/O operations using the shared SQ and CQ
> queue.
>
> Signed-off-by: Vikas Kumar <vikas.kumar2@arm.com>
> ---
> include/lapi/io_uring.h | 12 ++
> testcases/kernel/syscalls/io_uring/Makefile | 7 +
> .../kernel/syscalls/io_uring/io_uring01.c | 203 ++++++++++++++++++
You are missing runtest entry, I guess at least in runtest/syscalls
> 3 files changed, 222 insertions(+)
> create mode 100644 testcases/kernel/syscalls/io_uring/Makefile
> create mode 100644 testcases/kernel/syscalls/io_uring/io_uring01.c
>
> diff --git a/include/lapi/io_uring.h b/include/lapi/io_uring.h
> index 5fde58e22..8e47501a5 100644
> --- a/include/lapi/io_uring.h
> +++ b/include/lapi/io_uring.h
> @@ -280,4 +280,16 @@ int io_uring_enter(int fd, unsigned int to_submit, unsigned int min_complete,
> }
> #endif /* HAVE_IO_URING_ENTER */
>
> +void io_uring_setup_supported_by_kernel(void)
> +{
> + if ((tst_kvercmp(5, 1, 0)) < 0) {
> + TEST(syscall(__NR_io_uring_setup, NULL, 0));
> + if (TST_RET != -1)
> + SAFE_CLOSE(TST_RET);
> + else if (TST_ERR == ENOSYS)
> + tst_brk(TCONF,
> + "Test not supported on kernel version < v5.1");
> + }
> +}
> +
> #endif /* IO_URING_H__ */
> diff --git a/testcases/kernel/syscalls/io_uring/Makefile b/testcases/kernel/syscalls/io_uring/Makefile
> new file mode 100644
> index 000000000..94a19de2f
> --- /dev/null
> +++ b/testcases/kernel/syscalls/io_uring/Makefile
> @@ -0,0 +1,7 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +# Copyright (C) 2020 ARM Ltd. All rights reserved.
> +
> +top_srcdir ?= ../../../..
> +
> +include $(top_srcdir)/include/mk/testcases.mk
> +include $(top_srcdir)/include/mk/generic_leaf_target.mk
> diff --git a/testcases/kernel/syscalls/io_uring/io_uring01.c b/testcases/kernel/syscalls/io_uring/io_uring01.c
> new file mode 100644
> index 000000000..738a2cb46
> --- /dev/null
> +++ b/testcases/kernel/syscalls/io_uring/io_uring01.c
> @@ -0,0 +1,203 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2020 ARM Ltd. All rights reserved.
> + * Author: Vikas Kumar <vikas.kumar2@arm.com>
> + *
> + * Tests for asynchronous I/O raw API i.e io_uring_setup(), io_uring_register()
> + * and io_uring_enter(). This tests validate basic API operation by creating a
> + * submission queue and a completion queue using io_uring_setup(). User buffer
> + * registered in the kernel for long term operation using io_uring_register().
> + * This tests initiates I/O operations with the help of io_uring_enter().
> + */
> +#include <stdlib.h>
> +#include <errno.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#include "config.h"
> +#include "tst_test.h"
> +#include "lapi/io_uring.h"
> +
> +#define QUEUE_DEPTH 1
> +#define BLOCK_SZ 1024
> +
> +static struct tcase {
> + unsigned int setup_flags;
> + unsigned int register_opcode;
> + unsigned int enter_flags;
> +} tcases[] = {
> + {IORING_SETUP_IOPOLL, IORING_REGISTER_BUFFERS, IORING_OP_READ_FIXED},
> +};
> +
> +struct io_sq_ring {
> + unsigned int *head;
> + unsigned int *tail;
> + unsigned int *ring_mask;
> + unsigned int *ring_entries;
> + unsigned int *flags;
> + unsigned int *array;
> +};
> +
> +struct io_cq_ring {
> + unsigned int *head;
> + unsigned int *tail;
> + unsigned int *ring_mask;
> + unsigned int *ring_entries;
> + struct io_uring_cqe *cqes;
> +};
> +
> +struct submitter {
> + int ring_fd;
> + struct io_sq_ring sq_ring;
> + struct io_uring_sqe *sqes;
> + struct io_cq_ring cq_ring;
> +};
> +
> +struct buff_info {
> + unsigned int buff_sz;
> + struct iovec iovecs[];
> +};
> +
> +static struct submitter sub_ring;
> +static struct submitter *s;
> +static struct buff_info *bi;
> +static sigset_t sig;
> +
> +static int setup_io_uring_test(struct submitter *s, struct tcase *tc)
> +{
> + struct io_sq_ring *sring = &s->sq_ring;
> + struct io_cq_ring *cring = &s->cq_ring;
> + struct io_uring_params p;
> + void *ptr;
> +
> + memset(&p, 0, sizeof(p));
> + p.flags |= tc->setup_flags;
> + s->ring_fd = io_uring_setup(QUEUE_DEPTH, &p);
> + if (s->ring_fd != -1) {
> + tst_res(TPASS, "io_uring_setup() passed");
> + } else {
> + tst_res(TFAIL | TTERRNO, "io_uring_setup() failed");
> + return 1;
> + }
> +
> + /* Submission queue ring buffer mapping */
> + ptr = SAFE_MMAP(0, p.sq_off.array +
> + p.sq_entries * sizeof(unsigned int),
> + PROT_READ | PROT_WRITE,
> + MAP_SHARED | MAP_POPULATE,
> + s->ring_fd, IORING_OFF_SQ_RING);
> +
> + /* Save global submission queue struct info */
> + sring->head = ptr + p.sq_off.head;
> + sring->tail = ptr + p.sq_off.tail;
> + sring->ring_mask = ptr + p.sq_off.ring_mask;
> + sring->ring_entries = ptr + p.sq_off.ring_entries;
> + sring->flags = ptr + p.sq_off.flags;
> + sring->array = ptr + p.sq_off.array;
> +
> + /* Submission queue entries ring buffer mapping */
> + s->sqes = SAFE_MMAP(0, p.sq_entries *
> + sizeof(struct io_uring_sqe),
> + PROT_READ | PROT_WRITE,
> + MAP_SHARED | MAP_POPULATE,
> + s->ring_fd, IORING_OFF_SQES);
> +
> + /* Completion queue ring buffer mapping */
> + ptr = SAFE_MMAP(0,
> + p.cq_off.cqes + p.cq_entries *
> + sizeof(struct io_uring_cqe),
> + PROT_READ | PROT_WRITE,
> + MAP_SHARED | MAP_POPULATE,
> + s->ring_fd, IORING_OFF_CQ_RING);
> +
> + /* Save global completion queue struct info */
> + cring->head = ptr + p.cq_off.head;
> + cring->tail = ptr + p.cq_off.tail;
> + cring->ring_mask = ptr + p.cq_off.ring_mask;
> + cring->ring_entries = ptr + p.cq_off.ring_entries;
> + cring->cqes = ptr + p.cq_off.cqes;
> +
> + return 0;
> +}
> +
> +static int submit_to_uring_sq(struct submitter *s, struct tcase *tc)
> +{
> + unsigned int index = 0, tail = 0, next_tail = 0;
> + struct io_sq_ring *sring = &s->sq_ring;
> + struct io_uring_sqe *sqe;
> + void *iov_base;
> + size_t iov_len;
> + int ret;
> +
> + bi = SAFE_MALLOC(sizeof(*bi));
> + iov_len = BLOCK_SZ;
> + iov_base = SAFE_MALLOC(iov_len);
> + memset(iov_base, 0, iov_len);
> + bi->iovecs[index].iov_base = (void *)iov_base;
> + bi->iovecs[index].iov_len = (size_t)iov_len;
> +
> + ret = io_uring_register(s->ring_fd, tc->register_opcode,
> + bi->iovecs, QUEUE_DEPTH);
> + if (ret == 0) {
> + tst_res(TPASS, "io_uring_register() passed");
> + } else {
> + tst_res(TFAIL | TTERRNO, "io_uring_register() failed");
> + return 1;
> + }
> +
> + /* Submission queue entry addition to SQE ring buffer tail */
> + tail = *sring->tail;
> + next_tail = tail;
> + next_tail++;
> + index = tail & *s->sq_ring.ring_mask;
> + sqe = &s->sqes[index];
> + sqe->flags = 0;
> + sqe->opcode = tc->enter_flags;
> + sqe->addr = (unsigned long)bi->iovecs;
> + sqe->user_data = (unsigned long long)bi;
Shouldn't we set the sqe->fd and sqe->len here?
As far as I can see we request to read 0 bytes from stdin, which is
no-op but I would be happier if we actually read a bytes from a file
here and then checked that we actually read some bytes.
> + sring->array[index] = index;
> + tail = next_tail;
> +
> + /* Kernel to notice the tail update */
> + if (*sring->tail != tail)
> + *sring->tail = tail;
> +
> + ret = io_uring_enter(s->ring_fd, 1, 1, IORING_ENTER_GETEVENTS, &sig);
> + if (ret >= 0) {
> + tst_res(TPASS, "io_uring_enter() passed");
> + } else {
> + tst_res(TFAIL | TTERRNO, "io_uring_enter() failed");
> + return 1;
> + }
> +
> + return 0;
> +}
> +
> +static void cleanup_io_uring_test(void)
> +{
> + io_uring_register(s->ring_fd, IORING_UNREGISTER_BUFFERS,
> + NULL, QUEUE_DEPTH);
> + SAFE_MUNMAP(s->sqes, sizeof(struct io_uring_sqe));
> +}
> +
> +static void run(unsigned int n)
> +{
> + struct tcase *tc = &tcases[n];
> +
> + s = &sub_ring;
Can we please just pass &sub_right to the functions below?
There is no point in defining a pointer to a global variable if we can
easily get the pointer anyways.
> + memset(s, 0, sizeof(*s));
> + if (setup_io_uring_test(s, tc))
> + return;
> +
> + if (submit_to_uring_sq(s, tc))
> + return;
> +
> + cleanup_io_uring_test();
> + tst_res(TPASS, "functionality of io_uring API is correct");
No need to print overall pass message here now that we print pass/fail
for each io_uring opearation we do.
> +}
> +
> +static struct tst_test test = {
> + .setup = io_uring_setup_supported_by_kernel,
> + .test = run,
> + .tcnt = ARRAY_SIZE(tcases),
> +};
> +
Other than these the test looks good now.
--
Cyril Hrubis
chrubis@suse.cz
prev parent reply other threads:[~2020-06-30 15:16 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-06-29 5:59 [LTP] [PATCH V7] syscall: Add io_uring related tests Vikas Kumar
2020-06-30 15:16 ` Cyril Hrubis [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200630151629.GC12948@yuki.lan \
--to=chrubis@suse.cz \
--cc=ltp@lists.linux.it \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.