From: Cyril Hrubis <chrubis@suse.cz>
To: ltp@lists.linux.it
Subject: [LTP] [PATCH V8] syscall: Add io_uring related tests
Date: Thu, 16 Jul 2020 16:33:52 +0200 [thread overview]
Message-ID: <20200716143352.GA11713@yuki.lan> (raw)
In-Reply-To: <20200714032408.9201-1-vikas.kumar2@arm.com>
Hi!
I've finished the test code and pushed, thanks.
I've changed it so that it actually reads data and checks the result,
and also properly unmaps the buffers (fixes failures with -i 10 passed
to the test), the diff is attached below.
Also I will have to check if we need the read/write barriers, I guess
that the way we use the interface it's safe, since the syscalls provide
natural boundary between kernel and userspace. But they would be needed
for a different tests anyways.
Also I had to remove the IORING_SETUP_IOPOLL flag since that made all
SQEs fail with EOPNOTSUPP for me.
The diff:
diff --git a/testcases/kernel/syscalls/io_uring/io_uring01.c b/testcases/kernel/syscalls/io_uring/io_uring01.c
index bcfc2fd7b..70151bb85 100644
--- a/testcases/kernel/syscalls/io_uring/io_uring01.c
+++ b/testcases/kernel/syscalls/io_uring/io_uring01.c
@@ -3,6 +3,8 @@
* Copyright (C) 2020 ARM Ltd. All rights reserved.
* Author: Vikas Kumar <vikas.kumar2@arm.com>
*
+ * Copyright (C) 2020 Cyril Hrubis <chrubis@suse.cz>
+ *
* 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
@@ -17,6 +19,8 @@
#include "tst_test.h"
#include "lapi/io_uring.h"
+#define TEST_FILE "test_file"
+
#define QUEUE_DEPTH 1
#define BLOCK_SZ 1024
@@ -25,7 +29,7 @@ static struct tcase {
unsigned int register_opcode;
unsigned int enter_flags;
} tcases[] = {
- {IORING_SETUP_IOPOLL, IORING_REGISTER_BUFFERS, IORING_OP_READ_FIXED},
+ {0, IORING_REGISTER_BUFFERS, IORING_OP_READ_FIXED},
};
struct io_sq_ring {
@@ -52,22 +56,22 @@ struct submitter {
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 = &sub_ring;
-static struct buff_info *bi;
static sigset_t sig;
+static struct iovec *iov;
+
+
+static void *sptr;
+static size_t sptr_size;
+static void *cptr;
+static size_t cptr_size;
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;
@@ -75,24 +79,25 @@ static int setup_io_uring_test(struct submitter *s, struct tcase *tc)
if (s->ring_fd != -1) {
tst_res(TPASS, "io_uring_setup() passed");
} else {
- tst_res(TFAIL | TTERRNO, "io_uring_setup() failed");
+ tst_res(TFAIL | TERRNO, "io_uring_setup() failed");
return 1;
}
+ sptr_size = p.sq_off.array + p.sq_entries * sizeof(unsigned int);
+
/* Submission queue ring buffer mapping */
- ptr = SAFE_MMAP(0, p.sq_off.array +
- p.sq_entries * sizeof(unsigned int),
+ sptr = SAFE_MMAP(0, sptr_size,
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;
+ sring->head = sptr + p.sq_off.head;
+ sring->tail = sptr + p.sq_off.tail;
+ sring->ring_mask = sptr + p.sq_off.ring_mask;
+ sring->ring_entries = sptr + p.sq_off.ring_entries;
+ sring->flags = sptr + p.sq_off.flags;
+ sring->array = sptr + p.sq_off.array;
/* Submission queue entries ring buffer mapping */
s->sqes = SAFE_MMAP(0, p.sq_entries *
@@ -101,59 +106,107 @@ static int setup_io_uring_test(struct submitter *s, struct tcase *tc)
MAP_SHARED | MAP_POPULATE,
s->ring_fd, IORING_OFF_SQES);
+ cptr_size = p.cq_off.cqes + p.cq_entries * sizeof(struct io_uring_cqe);
+
/* Completion queue ring buffer mapping */
- ptr = SAFE_MMAP(0,
- p.cq_off.cqes + p.cq_entries *
- sizeof(struct io_uring_cqe),
+ cptr = SAFE_MMAP(0, cptr_size,
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;
+ cring->head = cptr + p.cq_off.head;
+ cring->tail = cptr + p.cq_off.tail;
+ cring->ring_mask = cptr + p.cq_off.ring_mask;
+ cring->ring_entries = cptr + p.cq_off.ring_entries;
+ cring->cqes = cptr + p.cq_off.cqes;
return 0;
}
+static void check_buffer(char *buffer, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ if (buffer[i] != 'a') {
+ tst_res(TFAIL, "Wrong data@offset %zu", i);
+ break;
+ }
+ }
+
+ if (i == len)
+ tst_res(TPASS, "Buffer filled in correctly");
+}
+
+static void drain_uring_cq(struct submitter *s, unsigned int exp_events)
+{
+ struct io_cq_ring *cring = &s->cq_ring;
+ unsigned int head = *cring->head;
+ unsigned int events = 0;
+
+ for (head = *cring->head; head != *cring->tail; head++) {
+ struct io_uring_cqe *cqe = &cring->cqes[head & *s->cq_ring.ring_mask];
+
+ events++;
+
+ if (cqe->res < 0) {
+ tst_res(TFAIL, "CQE result %s", tst_strerrno(-cqe->res));
+ } else {
+ struct iovec *iovecs = (void*)cqe->user_data;
+
+ if (cqe->res == BLOCK_SZ)
+ tst_res(TPASS, "CQE result %i", cqe->res);
+ else
+ tst_res(TFAIL, "CQE result %i expected %i", cqe->res, BLOCK_SZ);
+
+ check_buffer(iovecs[0].iov_base, cqe->res);
+ }
+ }
+
+ *cring->head = head;
+
+ if (exp_events == events) {
+ tst_res(TPASS, "Got %u completion events", events);
+ return;
+ }
+
+ tst_res(TFAIL, "Got %u completion events expected %u",
+ events, exp_events);
+}
+
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;
+ memset(iov->iov_base, 0, iov->iov_len);
ret = io_uring_register(s->ring_fd, tc->register_opcode,
- bi->iovecs, QUEUE_DEPTH);
+ iov, QUEUE_DEPTH);
if (ret == 0) {
tst_res(TPASS, "io_uring_register() passed");
} else {
- tst_res(TFAIL | TTERRNO, "io_uring_register() failed");
+ tst_res(TFAIL | TERRNO, "io_uring_register() failed");
return 1;
}
+ int fd = SAFE_OPEN(TEST_FILE, O_RDONLY);
+
/* Submission queue entry addition to SQE ring buffer tail */
tail = *sring->tail;
- next_tail = tail;
- next_tail++;
+ next_tail = tail + 1;
index = tail & *s->sq_ring.ring_mask;
sqe = &s->sqes[index];
sqe->flags = 0;
+ sqe->fd = fd;
sqe->opcode = tc->enter_flags;
- sqe->addr = (unsigned long)bi->iovecs;
- sqe->user_data = (unsigned long long)bi;
+ sqe->addr = (unsigned long)iov->iov_base;
+ sqe->len = BLOCK_SZ;
+ sqe->off = 0;
+ sqe->user_data = (unsigned long long)iov;
sring->array[index] = index;
tail = next_tail;
@@ -161,14 +214,16 @@ static int submit_to_uring_sq(struct submitter *s, struct tcase *tc)
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");
+ ret = io_uring_enter(s->ring_fd, 1, 1, IORING_ENTER_GETEVENTS, &sig);
+ if (ret == 1) {
+ tst_res(TPASS, "io_uring_enter() waited for 1 event");
} else {
- tst_res(TFAIL | TTERRNO, "io_uring_enter() failed");
+ tst_res(TFAIL | TERRNO, "io_uring_enter() returned %i", ret);
+ SAFE_CLOSE(fd);
return 1;
}
+ SAFE_CLOSE(fd);
return 0;
}
@@ -177,24 +232,37 @@ 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));
+ SAFE_MUNMAP(cptr, cptr_size);
+ SAFE_MUNMAP(sptr, sptr_size);
+ SAFE_CLOSE(s->ring_fd);
}
static void run(unsigned int n)
{
struct tcase *tc = &tcases[n];
- memset(s, 0, sizeof(*s));
if (setup_io_uring_test(s, tc))
return;
- if (submit_to_uring_sq(s, tc))
- return;
+ if (!submit_to_uring_sq(s, tc))
+ drain_uring_cq(s, 1);
cleanup_io_uring_test();
}
+static void setup(void)
+{
+ io_uring_setup_supported_by_kernel();
+ tst_fill_file(TEST_FILE, 'a', 1024, 1);
+}
+
static struct tst_test test = {
- .setup = io_uring_setup_supported_by_kernel,
+ .setup = setup,
.test = run,
+ .needs_tmpdir = 1,
.tcnt = ARRAY_SIZE(tcases),
+ .bufs = (struct tst_buffers []) {
+ {&iov, .iov_sizes = (int[]){BLOCK_SZ, -1}},
+ {}
+ }
};
--
Cyril Hrubis
chrubis@suse.cz
next prev parent reply other threads:[~2020-07-16 14:33 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-07-14 3:24 [LTP] [PATCH V8] syscall: Add io_uring related tests Vikas Kumar
2020-07-16 14:33 ` Cyril Hrubis [this message]
2020-07-16 20:47 ` Petr Vorel
2020-07-17 4:39 ` Vikas Kumar
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=20200716143352.GA11713@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox