diff mbox series

[liburing,1/1] test/defer: Test deferring with drain and links

Message ID b9509294fde6425b000d71613bd352059334c60d.1571995330.git.asml.silence@gmail.com (mailing list archive)
State New, archived
Headers show
Series [liburing,1/1] test/defer: Test deferring with drain and links | expand

Commit Message

Pavel Begunkov Oct. 25, 2019, 9:48 a.m. UTC
From: Pavel Begunkov <asml.silence@gmail.com>

1. test user_data integrity with cancelled links
2. test the whole link is cancelled by sq_thread
3. hunging io_uring based on koverflow and kdropped

Be aware, that this test may leave unkillable user process, or
unstopped actively polling kthread.

Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
 test/Makefile |   4 +-
 test/defer.c  | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 259 insertions(+), 2 deletions(-)
 create mode 100644 test/defer.c

Comments

Jens Axboe Oct. 25, 2019, 3:13 p.m. UTC | #1
On 10/25/19 3:48 AM, Pavel Begunkov (Silence) wrote:
> From: Pavel Begunkov <asml.silence@gmail.com>
> 
> 1. test user_data integrity with cancelled links
> 2. test the whole link is cancelled by sq_thread
> 3. hunging io_uring based on koverflow and kdropped
> 
> Be aware, that this test may leave unkillable user process, or
> unstopped actively polling kthread.

That's fine, that's what the test suite is for! Thanks, applied.

BTW, you need to update your liburing repo, you're several tests
behind and I need to hand apply the test/Makefile every time.
Pavel Begunkov Oct. 25, 2019, 3:40 p.m. UTC | #2
On 25/10/2019 18:13, Jens Axboe wrote:
> On 10/25/19 3:48 AM, Pavel Begunkov (Silence) wrote:
>> From: Pavel Begunkov <asml.silence@gmail.com>
>>
>> 1. test user_data integrity with cancelled links
>> 2. test the whole link is cancelled by sq_thread
>> 3. hunging io_uring based on koverflow and kdropped
>>
>> Be aware, that this test may leave unkillable user process, or
>> unstopped actively polling kthread.
> 
> That's fine, that's what the test suite is for! Thanks, applied.

Just found it "a bit uncomfortable", that after several runs
my CPU was doing nothing but polling in vain.

> 
> BTW, you need to update your liburing repo, you're several tests
> behind and I need to hand apply the test/Makefile every time.
> 
Sorry for that, will do
Jens Axboe Oct. 25, 2019, 3:47 p.m. UTC | #3
On 10/25/19 9:40 AM, Pavel Begunkov wrote:
> On 25/10/2019 18:13, Jens Axboe wrote:
>> On 10/25/19 3:48 AM, Pavel Begunkov (Silence) wrote:
>>> From: Pavel Begunkov <asml.silence@gmail.com>
>>>
>>> 1. test user_data integrity with cancelled links
>>> 2. test the whole link is cancelled by sq_thread
>>> 3. hunging io_uring based on koverflow and kdropped
>>>
>>> Be aware, that this test may leave unkillable user process, or
>>> unstopped actively polling kthread.
>>
>> That's fine, that's what the test suite is for! Thanks, applied.
> 
> Just found it "a bit uncomfortable", that after several runs
> my CPU was doing nothing but polling in vain.

Looks like it's testing one of the cases that isn't fixed that. We
shouldn't do that until a known fix is available, at least. Basically
the tests should test for things that used to be a problem, but are
now fixed.

But let's just get it fixed :-)
diff mbox series

Patch

diff --git a/test/Makefile b/test/Makefile
index 3ab5f81..250fb0f 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -7,7 +7,7 @@  all_targets += poll poll-cancel ring-leak fsync io_uring_setup io_uring_register
 		917257daa0fe-test b19062a56726-test eeed8b54e0df-test link \
 		send_recvmsg a4c0b3decb33-test 500f9fbadef8-test timeout \
 		sq-space_left stdout cq-ready cq-peek-batch file-register \
-		cq-size 8a9973408177-test a0908ae19763-test
+		cq-size 8a9973408177-test a0908ae19763-test defer
 
 include ../Makefile.quiet
 
@@ -22,7 +22,7 @@  test_srcs := poll.c poll-cancel.c ring-leak.c fsync.c io_uring_setup.c \
 	eeed8b54e0df-test.c link.c send_recvmsg.c a4c0b3decb33-test.c \
 	500f9fbadef8-test.c timeout.c sq-space_left.c stdout.c cq-ready.c\
 	cq-peek-batch.c file-register.c cq-size.c 8a9973408177-test.c \
-	a0908ae19763-test.c
+	a0908ae19763-test.c defer.c
 
 test_objs := $(patsubst %.c,%.ol,$(test_srcs))
 
diff --git a/test/defer.c b/test/defer.c
new file mode 100644
index 0000000..db0d904
--- /dev/null
+++ b/test/defer.c
@@ -0,0 +1,257 @@ 
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/uio.h>
+#include <stdbool.h>
+
+#include "liburing.h"
+
+struct test_context {
+	struct io_uring *ring;
+	struct io_uring_sqe **sqes;
+	struct io_uring_cqe *cqes;
+	int nr;
+};
+
+static void free_context(struct test_context *ctx)
+{
+	free(ctx->sqes);
+	free(ctx->cqes);
+	memset(ctx, 0, sizeof(*ctx));
+}
+
+static int init_context(struct test_context *ctx, struct io_uring *ring, int nr)
+{
+	struct io_uring_sqe *sqe;
+	int i;
+
+	memset(ctx, 0, sizeof(*ctx));
+	ctx->nr = nr;
+	ctx->ring = ring;
+	ctx->sqes = malloc(nr * sizeof(*ctx->sqes));
+	ctx->cqes = malloc(nr * sizeof(*ctx->cqes));
+
+	if (!ctx->sqes || !ctx->cqes)
+		goto err;
+
+	for (i = 0; i < nr; i++) {
+		sqe = io_uring_get_sqe(ring);
+		if (!sqe)
+			goto err;
+		io_uring_prep_nop(sqe);
+		sqe->user_data = i;
+		ctx->sqes[i] = sqe;
+	}
+
+	return 0;
+err:
+	free_context(ctx);
+	printf("init context failed\n");
+	return 1;
+}
+
+static int wait_cqes(struct test_context *ctx)
+{
+	int ret, i;
+	struct io_uring_cqe *cqe;
+
+	for (i = 0; i < ctx->nr; i++) {
+		ret = io_uring_wait_cqe(ctx->ring, &cqe);
+
+		if (ret < 0) {
+			printf("wait_cqes: wait completion %d\n", ret);
+			return 1;
+		}
+		memcpy(&ctx->cqes[i], cqe, sizeof(*cqe));
+		io_uring_cqe_seen(ctx->ring, cqe);
+	}
+
+	return 0;
+}
+
+static int test_cancelled_userdata(struct io_uring *ring)
+{
+	struct test_context ctx;
+	int ret, i, nr = 100;
+
+	if (init_context(&ctx, ring, nr))
+		return 1;
+
+	for (i = 0; i < nr; i++)
+		ctx.sqes[i]->flags |= IOSQE_IO_LINK;
+
+	ret = io_uring_submit(ring);
+	if (ret <= 0) {
+		printf("sqe submit failed: %d\n", ret);
+		goto err;
+	}
+
+	if (wait_cqes(&ctx))
+		goto err;
+
+	for (int i = 0; i < nr; i++) {
+		if (i != ctx.cqes[i].user_data) {
+			printf("invalid user data\n");
+			goto err;
+		}
+	}
+
+	free_context(&ctx);
+	return 0;
+err:
+	free_context(&ctx);
+	return 1;
+}
+
+static int test_thread_link_cancel(struct io_uring *ring)
+{
+	struct test_context ctx;
+	int ret, i, nr = 100;
+
+	if (init_context(&ctx, ring, nr))
+		return 1;
+
+	for (i = 0; i < nr; i++)
+		ctx.sqes[i]->flags |= IOSQE_IO_LINK;
+
+	ret = io_uring_submit(ring);
+	if (ret <= 0) {
+		printf("sqe submit failed: %d\n", ret);
+		goto err;
+	}
+
+	if (wait_cqes(&ctx))
+		goto err;
+
+	for (int i = 0; i < nr; i++) {
+		bool fail = false;
+
+		if (i == 0)
+			fail = (ctx.cqes[i].res != -EINVAL);
+		else
+			fail = (ctx.cqes[i].res != -ECANCELED);
+
+		if (fail) {
+			printf("invalid status\n");
+			goto err;
+		}
+	}
+
+	free_context(&ctx);
+	return 0;
+err:
+	free_context(&ctx);
+	return 1;
+}
+
+static int run_drained(struct io_uring *ring, int nr)
+{
+	struct test_context ctx;
+	int ret, i;
+
+	if (init_context(&ctx, ring, nr))
+		return 1;
+
+	for (i = 0; i < nr; i++)
+		ctx.sqes[i]->flags |= IOSQE_IO_DRAIN;
+
+	ret = io_uring_submit(ring);
+	if (ret <= 0) {
+		printf("sqe submit failed: %d\n", ret);
+		goto err;
+	}
+
+	if (wait_cqes(&ctx))
+		goto err;
+
+	free_context(&ctx);
+	return 0;
+err:
+	free_context(&ctx);
+	return 1;
+}
+
+static int test_overflow_hung(struct io_uring *ring)
+{
+	struct io_uring_sqe *sqe;
+	int ret, nr = 10;
+
+	while (*ring->cq.koverflow !=  1000) {
+		sqe = io_uring_get_sqe(ring);
+		if (!sqe) {
+			printf("get sqe failed\n");
+			return 1;
+		}
+
+		io_uring_prep_nop(sqe);
+		ret = io_uring_submit(ring);
+		if (ret <= 0) {
+			printf("sqe submit failed: %d\n", ret);
+			return 1;
+		}
+	}
+
+	return run_drained(ring, nr);
+}
+
+static int test_dropped_hung(struct io_uring *ring)
+{
+	int nr = 10;
+
+	*ring->sq.kdropped = 1000;
+	return run_drained(ring, nr);
+}
+
+int main(int argc, char *argv[])
+{
+	struct io_uring ring, poll_ring, sqthread_ring;
+	int ret;
+
+	ret = io_uring_queue_init(1000, &ring, 0);
+	if (ret) {
+		printf("ring setup failed\n");
+		return 1;
+	}
+
+	ret = io_uring_queue_init(1000, &poll_ring, IORING_SETUP_IOPOLL);
+	if (ret) {
+		printf("poll_ring setup failed\n");
+		return 1;
+	}
+
+	ret = io_uring_queue_init(1000, &sqthread_ring,
+				IORING_SETUP_SQPOLL | IORING_SETUP_IOPOLL);
+	if (ret) {
+		printf("poll_ring setup failed\n");
+		return 1;
+	}
+
+	ret = test_cancelled_userdata(&poll_ring);
+	if (ret) {
+		printf("test_cancelled_userdata failed\n");
+		return ret;
+	}
+
+	ret = test_thread_link_cancel(&sqthread_ring);
+	if (ret) {
+		printf("test_thread_link_cancel failed\n");
+		return ret;
+	}
+
+	ret = test_overflow_hung(&ring);
+	if (ret) {
+		printf("test_overflow_hung failed\n");
+		return ret;
+	}
+
+	ret = test_dropped_hung(&ring);
+	if (ret) {
+		printf("test_dropped_hung failed\n");
+		return ret;
+	}
+
+	return 0;
+}