Blame test/defer.c

Packit d3489f
/* SPDX-License-Identifier: MIT */
Packit d3489f
#include <errno.h>
Packit d3489f
#include <stdio.h>
Packit d3489f
#include <unistd.h>
Packit d3489f
#include <stdlib.h>
Packit d3489f
#include <string.h>
Packit d3489f
#include <fcntl.h>
Packit d3489f
#include <sys/uio.h>
Packit d3489f
#include <stdbool.h>
Packit d3489f
Packit d3489f
#include "liburing.h"
Packit d3489f
Packit d3489f
struct test_context {
Packit d3489f
	struct io_uring *ring;
Packit d3489f
	struct io_uring_sqe **sqes;
Packit d3489f
	struct io_uring_cqe *cqes;
Packit d3489f
	int nr;
Packit d3489f
};
Packit d3489f
Packit d3489f
static void free_context(struct test_context *ctx)
Packit d3489f
{
Packit d3489f
	free(ctx->sqes);
Packit d3489f
	free(ctx->cqes);
Packit d3489f
	memset(ctx, 0, sizeof(*ctx));
Packit d3489f
}
Packit d3489f
Packit d3489f
static int init_context(struct test_context *ctx, struct io_uring *ring, int nr)
Packit d3489f
{
Packit d3489f
	struct io_uring_sqe *sqe;
Packit d3489f
	int i;
Packit d3489f
Packit d3489f
	memset(ctx, 0, sizeof(*ctx));
Packit d3489f
	ctx->nr = nr;
Packit d3489f
	ctx->ring = ring;
Packit d3489f
	ctx->sqes = malloc(nr * sizeof(*ctx->sqes));
Packit d3489f
	ctx->cqes = malloc(nr * sizeof(*ctx->cqes));
Packit d3489f
Packit d3489f
	if (!ctx->sqes || !ctx->cqes)
Packit d3489f
		goto err;
Packit d3489f
Packit d3489f
	for (i = 0; i < nr; i++) {
Packit d3489f
		sqe = io_uring_get_sqe(ring);
Packit d3489f
		if (!sqe)
Packit d3489f
			goto err;
Packit d3489f
		io_uring_prep_nop(sqe);
Packit d3489f
		sqe->user_data = i;
Packit d3489f
		ctx->sqes[i] = sqe;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	return 0;
Packit d3489f
err:
Packit d3489f
	free_context(ctx);
Packit d3489f
	printf("init context failed\n");
Packit d3489f
	return 1;
Packit d3489f
}
Packit d3489f
Packit d3489f
static int wait_cqes(struct test_context *ctx)
Packit d3489f
{
Packit d3489f
	int ret, i;
Packit d3489f
	struct io_uring_cqe *cqe;
Packit d3489f
Packit d3489f
	for (i = 0; i < ctx->nr; i++) {
Packit d3489f
		ret = io_uring_wait_cqe(ctx->ring, &cqe);
Packit d3489f
Packit d3489f
		if (ret < 0) {
Packit d3489f
			printf("wait_cqes: wait completion %d\n", ret);
Packit d3489f
			return 1;
Packit d3489f
		}
Packit d3489f
		memcpy(&ctx->cqes[i], cqe, sizeof(*cqe));
Packit d3489f
		io_uring_cqe_seen(ctx->ring, cqe);
Packit d3489f
	}
Packit d3489f
Packit d3489f
	return 0;
Packit d3489f
}
Packit d3489f
Packit d3489f
static int test_cancelled_userdata(struct io_uring *ring)
Packit d3489f
{
Packit d3489f
	struct test_context ctx;
Packit d3489f
	int ret, i, nr = 100;
Packit d3489f
Packit d3489f
	if (init_context(&ctx, ring, nr))
Packit d3489f
		return 1;
Packit d3489f
Packit d3489f
	for (i = 0; i < nr; i++)
Packit d3489f
		ctx.sqes[i]->flags |= IOSQE_IO_LINK;
Packit d3489f
Packit d3489f
	ret = io_uring_submit(ring);
Packit d3489f
	if (ret <= 0) {
Packit d3489f
		printf("sqe submit failed: %d\n", ret);
Packit d3489f
		goto err;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	if (wait_cqes(&ctx))
Packit d3489f
		goto err;
Packit d3489f
Packit d3489f
	for (i = 0; i < nr; i++) {
Packit d3489f
		if (i != ctx.cqes[i].user_data) {
Packit d3489f
			printf("invalid user data\n");
Packit d3489f
			goto err;
Packit d3489f
		}
Packit d3489f
	}
Packit d3489f
Packit d3489f
	free_context(&ctx;;
Packit d3489f
	return 0;
Packit d3489f
err:
Packit d3489f
	free_context(&ctx;;
Packit d3489f
	return 1;
Packit d3489f
}
Packit d3489f
Packit d3489f
static int test_thread_link_cancel(struct io_uring *ring)
Packit d3489f
{
Packit d3489f
	struct test_context ctx;
Packit d3489f
	int ret, i, nr = 100;
Packit d3489f
Packit d3489f
	if (init_context(&ctx, ring, nr))
Packit d3489f
		return 1;
Packit d3489f
Packit d3489f
	for (i = 0; i < nr; i++)
Packit d3489f
		ctx.sqes[i]->flags |= IOSQE_IO_LINK;
Packit d3489f
Packit d3489f
	ret = io_uring_submit(ring);
Packit d3489f
	if (ret <= 0) {
Packit d3489f
		printf("sqe submit failed: %d\n", ret);
Packit d3489f
		goto err;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	if (wait_cqes(&ctx))
Packit d3489f
		goto err;
Packit d3489f
Packit d3489f
	for (i = 0; i < nr; i++) {
Packit d3489f
		bool fail = false;
Packit d3489f
Packit d3489f
		if (i == 0)
Packit d3489f
			fail = (ctx.cqes[i].res != -EINVAL);
Packit d3489f
		else
Packit d3489f
			fail = (ctx.cqes[i].res != -ECANCELED);
Packit d3489f
Packit d3489f
		if (fail) {
Packit d3489f
			printf("invalid status\n");
Packit d3489f
			goto err;
Packit d3489f
		}
Packit d3489f
	}
Packit d3489f
Packit d3489f
	free_context(&ctx;;
Packit d3489f
	return 0;
Packit d3489f
err:
Packit d3489f
	free_context(&ctx;;
Packit d3489f
	return 1;
Packit d3489f
}
Packit d3489f
Packit d3489f
static int run_drained(struct io_uring *ring, int nr)
Packit d3489f
{
Packit d3489f
	struct test_context ctx;
Packit d3489f
	int ret, i;
Packit d3489f
Packit d3489f
	if (init_context(&ctx, ring, nr))
Packit d3489f
		return 1;
Packit d3489f
Packit d3489f
	for (i = 0; i < nr; i++)
Packit d3489f
		ctx.sqes[i]->flags |= IOSQE_IO_DRAIN;
Packit d3489f
Packit d3489f
	ret = io_uring_submit(ring);
Packit d3489f
	if (ret <= 0) {
Packit d3489f
		printf("sqe submit failed: %d\n", ret);
Packit d3489f
		goto err;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	if (wait_cqes(&ctx))
Packit d3489f
		goto err;
Packit d3489f
Packit d3489f
	free_context(&ctx;;
Packit d3489f
	return 0;
Packit d3489f
err:
Packit d3489f
	free_context(&ctx;;
Packit d3489f
	return 1;
Packit d3489f
}
Packit d3489f
Packit d3489f
static int test_overflow_hung(struct io_uring *ring)
Packit d3489f
{
Packit d3489f
	struct io_uring_sqe *sqe;
Packit d3489f
	int ret, nr = 10;
Packit d3489f
Packit d3489f
	while (*ring->cq.koverflow != 1000) {
Packit d3489f
		sqe = io_uring_get_sqe(ring);
Packit d3489f
		if (!sqe) {
Packit d3489f
			printf("get sqe failed\n");
Packit d3489f
			return 1;
Packit d3489f
		}
Packit d3489f
Packit d3489f
		io_uring_prep_nop(sqe);
Packit d3489f
		ret = io_uring_submit(ring);
Packit d3489f
		if (ret <= 0) {
Packit d3489f
			printf("sqe submit failed: %d\n", ret);
Packit d3489f
			return 1;
Packit d3489f
		}
Packit d3489f
	}
Packit d3489f
Packit d3489f
	return run_drained(ring, nr);
Packit d3489f
}
Packit d3489f
Packit d3489f
static int test_dropped_hung(struct io_uring *ring)
Packit d3489f
{
Packit d3489f
	int nr = 10;
Packit d3489f
Packit d3489f
	*ring->sq.kdropped = 1000;
Packit d3489f
	return run_drained(ring, nr);
Packit d3489f
}
Packit d3489f
Packit d3489f
int main(int argc, char *argv[])
Packit d3489f
{
Packit d3489f
	struct io_uring ring, poll_ring, sqthread_ring;
Packit d3489f
	struct io_uring_params p;
Packit d3489f
	int ret, no_sqthread = 0;
Packit d3489f
Packit d3489f
	if (argc > 1)
Packit d3489f
		return 0;
Packit d3489f
Packit d3489f
	memset(&p, 0, sizeof(p));
Packit d3489f
	ret = io_uring_queue_init_params(1000, &ring, &p);
Packit d3489f
	if (ret) {
Packit d3489f
		printf("ring setup failed\n");
Packit d3489f
		return 1;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	ret = io_uring_queue_init(1000, &poll_ring, IORING_SETUP_IOPOLL);
Packit d3489f
	if (ret) {
Packit d3489f
		printf("poll_ring setup failed\n");
Packit d3489f
		return 1;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	ret = io_uring_queue_init(1000, &sqthread_ring,
Packit d3489f
				IORING_SETUP_SQPOLL | IORING_SETUP_IOPOLL);
Packit d3489f
	if (ret) {
Packit d3489f
		if (geteuid()) {
Packit d3489f
			no_sqthread = 1;
Packit d3489f
		} else {
Packit d3489f
			printf("poll_ring setup failed\n");
Packit d3489f
			return 1;
Packit d3489f
		}
Packit d3489f
	}
Packit d3489f
Packit d3489f
	ret = test_cancelled_userdata(&poll_ring);
Packit d3489f
	if (ret) {
Packit d3489f
		printf("test_cancelled_userdata failed\n");
Packit d3489f
		return ret;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	if (no_sqthread) {
Packit d3489f
		printf("test_thread_link_cancel: skipped, not root\n");
Packit d3489f
	} else {
Packit d3489f
		ret = test_thread_link_cancel(&sqthread_ring);
Packit d3489f
		if (ret) {
Packit d3489f
			printf("test_thread_link_cancel failed\n");
Packit d3489f
			return ret;
Packit d3489f
		}
Packit d3489f
	}
Packit d3489f
Packit d3489f
	if (!(p.features & IORING_FEAT_NODROP)) {
Packit d3489f
		ret = test_overflow_hung(&ring);
Packit d3489f
		if (ret) {
Packit d3489f
			printf("test_overflow_hung failed\n");
Packit d3489f
			return ret;
Packit d3489f
		}
Packit d3489f
	}
Packit d3489f
Packit d3489f
	ret = test_dropped_hung(&ring);
Packit d3489f
	if (ret) {
Packit d3489f
		printf("test_dropped_hung failed\n");
Packit d3489f
		return ret;
Packit d3489f
	}
Packit d3489f
Packit d3489f
	return 0;
Packit d3489f
}