Make sure all requests of a going away process are cancelled. Signed-off-by: Pavel Begunkov <asml.silence@xxxxxxxxx> --- test/io-cancel.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/test/io-cancel.c b/test/io-cancel.c index 75fbf43..d8b04d9 100644 --- a/test/io-cancel.c +++ b/test/io-cancel.c @@ -10,6 +10,8 @@ #include <fcntl.h> #include <sys/types.h> #include <sys/time.h> +#include <sys/mman.h> +#include <sys/wait.h> #include "liburing.h" @@ -17,6 +19,8 @@ #define BS 4096 #define BUFFERS (FILE_SIZE / BS) +#define NR_REQS 10 + static struct iovec *vecs; static int create_buffers(void) @@ -228,10 +232,108 @@ err: return 1; } +static void submit_child(struct io_uring *ring, int fds[2]) +{ + struct io_uring_sqe *sqe; + int ret, i; + char buffer[128]; + + for (i = 0; i < NR_REQS; ++i) { + sqe = io_uring_get_sqe(ring); + if (!sqe) { + fprintf(stderr, "get sqe failed\n"); + goto err; + } + io_uring_prep_read(sqe, fds[0], buffer, sizeof(buffer), 0); + sqe->flags |= IOSQE_ASYNC; + } + + ret = io_uring_submit(ring); + if (ret != NR_REQS) { + printf("sqe submit failed: %d\n", ret); + goto err; + } + + exit(0); +err: + exit(-1); +} + +/* make sure requests of a going away task are cancelled */ +static int test_cancel_exiting_task(void) +{ + struct io_uring *ring; + int ret, i; + pid_t p; + int fds[2]; + + ring = mmap(0, sizeof(*ring), PROT_READ|PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, 0, 0); + if (!ring) { + fprintf(stderr, "mmap failed\n"); + return 1; + } + + ret = io_uring_queue_init(NR_REQS * 2, ring, 0); + if (ret < 0) { + fprintf(stderr, "queue init failed\n"); + return 1; + } + + if (pipe(fds)) { + perror("pipe() failed"); + exit(1); + } + + p = fork(); + if (p < 0) { + printf("fork() failed\n"); + return 1; + } + + if (p == 0) { + /* child */ + submit_child(ring, fds); + } else { + int wstatus; + struct io_uring_cqe *cqe; + + waitpid(p, &wstatus, 0); + if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0) { + fprintf(stderr, "child failed\n"); + return 1; + } + + for (i = 0; i < NR_REQS; ++i) { + ret = io_uring_wait_cqe(ring, &cqe); + if (ret < 0) { + printf("wait_cqes: wait completion %d\n", ret); + return 1; + } + if (cqe->res != -ECANCELED && cqe->res != -EINTR) { + fprintf(stderr, "invalid CQE: %i\n", cqe->res); + return 1; + } + io_uring_cqe_seen(ring, cqe); + } + } + + close(fds[0]); + close(fds[1]); + io_uring_queue_exit(ring); + munmap(ring, sizeof(*ring)); + return 0; +} + int main(int argc, char *argv[]) { int i, ret; + if (test_cancel_exiting_task()) { + fprintf(stderr, "test_cancel_exiting_task failed\n"); + return 1; + } + if (create_file(".basic-rw")) { fprintf(stderr, "file creation failed\n"); goto err; -- 2.24.0