* [PATCH liburing 0/2] cancellation tests
@ 2021-03-12 16:28 Pavel Begunkov
2021-03-12 16:28 ` [PATCH liburing 1/2] tests: add more IORING_OP_ASYNC_CANCEL tests Pavel Begunkov
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Pavel Begunkov @ 2021-03-12 16:28 UTC (permalink / raw)
To: Jens Axboe, io-uring
resend 2/2 + two IORING_OP_ASYNC_CANCEL tests in 1/2
Pavel Begunkov (2):
tests: add more IORING_OP_ASYNC_CANCEL tests
tests: test that ring exit cancels io-wq
test/io-cancel.c | 179 +++++++++++++++++++++++++++++++++++++++++++++++
test/ring-leak.c | 65 +++++++++++++++++
2 files changed, 244 insertions(+)
--
2.24.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH liburing 1/2] tests: add more IORING_OP_ASYNC_CANCEL tests
2021-03-12 16:28 [PATCH liburing 0/2] cancellation tests Pavel Begunkov
@ 2021-03-12 16:28 ` Pavel Begunkov
2021-03-12 16:28 ` [PATCH liburing 2/2] tests: test that ring exit cancels io-wq Pavel Begunkov
2021-03-18 15:17 ` [PATCH liburing 0/2] cancellation tests Jens Axboe
2 siblings, 0 replies; 4+ messages in thread
From: Pavel Begunkov @ 2021-03-12 16:28 UTC (permalink / raw)
To: Jens Axboe, io-uring
test_dont_cancel_another_ring() makes sure that it doesn't cancel
requests of an unrelated ring, that may happen because of io-wq sharing.
test_cancel_req_across_fork() verifies that IORING_OP_ASYNC_CANCEL io-wq
cancellation isn't limited only to current task.
Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
test/io-cancel.c | 179 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 179 insertions(+)
diff --git a/test/io-cancel.c b/test/io-cancel.c
index 72ac971..9b52c7b 100644
--- a/test/io-cancel.c
+++ b/test/io-cancel.c
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <sys/types.h>
#include <sys/time.h>
+#include <sys/wait.h>
#include "helpers.h"
#include "liburing.h"
@@ -196,6 +197,174 @@ err:
return 1;
}
+static int test_dont_cancel_another_ring(void)
+{
+ struct io_uring ring1, ring2;
+ struct io_uring_cqe *cqe;
+ struct io_uring_sqe *sqe;
+ char buffer[128];
+ int ret, fds[2];
+ struct __kernel_timespec ts = { .tv_sec = 0, .tv_nsec = 100000000, };
+
+ ret = io_uring_queue_init(8, &ring1, 0);
+ if (ret) {
+ fprintf(stderr, "ring create failed: %d\n", ret);
+ return 1;
+ }
+ ret = io_uring_queue_init(8, &ring2, 0);
+ if (ret) {
+ fprintf(stderr, "ring create failed: %d\n", ret);
+ return 1;
+ }
+ if (pipe(fds)) {
+ perror("pipe");
+ return 1;
+ }
+
+ sqe = io_uring_get_sqe(&ring1);
+ if (!sqe) {
+ fprintf(stderr, "%s: failed to get sqe\n", __FUNCTION__);
+ return 1;
+ }
+ io_uring_prep_read(sqe, fds[0], buffer, 10, 0);
+ sqe->flags |= IOSQE_ASYNC;
+ sqe->user_data = 1;
+
+ ret = io_uring_submit(&ring1);
+ if (ret != 1) {
+ fprintf(stderr, "%s: got %d, wanted 1\n", __FUNCTION__, ret);
+ return 1;
+ }
+
+ /* make sure it doesn't cancel requests of the other ctx */
+ sqe = io_uring_get_sqe(&ring2);
+ if (!sqe) {
+ fprintf(stderr, "%s: failed to get sqe\n", __FUNCTION__);
+ return 1;
+ }
+ io_uring_prep_cancel(sqe, (void *) (unsigned long)1, 0);
+ sqe->user_data = 2;
+
+ ret = io_uring_submit(&ring2);
+ if (ret != 1) {
+ fprintf(stderr, "%s: got %d, wanted 1\n", __FUNCTION__, ret);
+ return 1;
+ }
+
+ ret = io_uring_wait_cqe(&ring2, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait_cqe=%d\n", ret);
+ return 1;
+ }
+ if (cqe->user_data != 2 || cqe->res != -ENOENT) {
+ fprintf(stderr, "error: cqe %i: res=%i, but expected -ENOENT\n",
+ (int)cqe->user_data, (int)cqe->res);
+ return 1;
+ }
+ io_uring_cqe_seen(&ring2, cqe);
+
+ ret = io_uring_wait_cqe_timeout(&ring1, &cqe, &ts);
+ if (ret != -ETIME) {
+ fprintf(stderr, "read got cancelled or wait failed\n");
+ return 1;
+ }
+ io_uring_cqe_seen(&ring1, cqe);
+
+ close(fds[0]);
+ close(fds[1]);
+ io_uring_queue_exit(&ring1);
+ io_uring_queue_exit(&ring2);
+ return 0;
+}
+
+static int test_cancel_req_across_fork(void)
+{
+ struct io_uring ring;
+ struct io_uring_cqe *cqe;
+ struct io_uring_sqe *sqe;
+ char buffer[128];
+ int ret, i, fds[2];
+ pid_t p;
+
+ ret = io_uring_queue_init(8, &ring, 0);
+ if (ret) {
+ fprintf(stderr, "ring create failed: %d\n", ret);
+ return 1;
+ }
+ if (pipe(fds)) {
+ perror("pipe");
+ return 1;
+ }
+ sqe = io_uring_get_sqe(&ring);
+ if (!sqe) {
+ fprintf(stderr, "%s: failed to get sqe\n", __FUNCTION__);
+ return 1;
+ }
+ io_uring_prep_read(sqe, fds[0], buffer, 10, 0);
+ sqe->flags |= IOSQE_ASYNC;
+ sqe->user_data = 1;
+
+ ret = io_uring_submit(&ring);
+ if (ret != 1) {
+ fprintf(stderr, "%s: got %d, wanted 1\n", __FUNCTION__, ret);
+ return 1;
+ }
+
+ p = fork();
+ if (p == -1) {
+ fprintf(stderr, "fork() failed\n");
+ return 1;
+ }
+
+ if (p == 0) {
+ sqe = io_uring_get_sqe(&ring);
+ if (!sqe) {
+ fprintf(stderr, "%s: failed to get sqe\n", __FUNCTION__);
+ return 1;
+ }
+ io_uring_prep_cancel(sqe, (void *) (unsigned long)1, 0);
+ sqe->user_data = 2;
+
+ ret = io_uring_submit(&ring);
+ if (ret != 1) {
+ fprintf(stderr, "%s: got %d, wanted 1\n", __FUNCTION__, ret);
+ return 1;
+ }
+
+ for (i = 0; i < 2; ++i) {
+ ret = io_uring_wait_cqe(&ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait_cqe=%d\n", ret);
+ return 1;
+ }
+ if ((cqe->user_data == 1 && cqe->res != -EINTR) ||
+ (cqe->user_data == 2 && cqe->res != -EALREADY)) {
+ fprintf(stderr, "%i %i\n", (int)cqe->user_data, cqe->res);
+ exit(1);
+ }
+
+ io_uring_cqe_seen(&ring, cqe);
+ }
+ exit(0);
+ } else {
+ int wstatus;
+
+ if (waitpid(p, &wstatus, 0) == (pid_t)-1) {
+ perror("waitpid()");
+ return 1;
+ }
+ if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus)) {
+ fprintf(stderr, "child failed %i\n", WEXITSTATUS(wstatus));
+ return 1;
+ }
+ }
+
+ close(fds[0]);
+ close(fds[1]);
+ io_uring_queue_exit(&ring);
+ return 0;
+}
+
int main(int argc, char *argv[])
{
int i, ret;
@@ -203,6 +372,16 @@ int main(int argc, char *argv[])
if (argc > 1)
return 0;
+ if (test_dont_cancel_another_ring()) {
+ fprintf(stderr, "test_dont_cancel_another_ring() failed\n");
+ return 1;
+ }
+
+ if (test_cancel_req_across_fork()) {
+ fprintf(stderr, "test_cancel_req_across_fork() failed\n");
+ return 1;
+ }
+
t_create_file(".basic-rw", FILE_SIZE);
vecs = t_create_buffers(BUFFERS, BS);
--
2.24.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH liburing 2/2] tests: test that ring exit cancels io-wq
2021-03-12 16:28 [PATCH liburing 0/2] cancellation tests Pavel Begunkov
2021-03-12 16:28 ` [PATCH liburing 1/2] tests: add more IORING_OP_ASYNC_CANCEL tests Pavel Begunkov
@ 2021-03-12 16:28 ` Pavel Begunkov
2021-03-18 15:17 ` [PATCH liburing 0/2] cancellation tests Jens Axboe
2 siblings, 0 replies; 4+ messages in thread
From: Pavel Begunkov @ 2021-03-12 16:28 UTC (permalink / raw)
To: Jens Axboe, io-uring
Test that io_uring_queue_exit() does proper cancellation of io-wq.
Note that there are worse cases with multiple tasks that can hang
in the kernel due to failing to do io-wq cancellations properly.
Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
---
test/ring-leak.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 65 insertions(+)
diff --git a/test/ring-leak.c b/test/ring-leak.c
index 4ddc8ff..7ff1d87 100644
--- a/test/ring-leak.c
+++ b/test/ring-leak.c
@@ -73,6 +73,65 @@ static void send_fd(int socket, int fd)
perror("sendmsg");
}
+static int test_iowq_request_cancel(void)
+{
+ char buffer[128];
+ struct io_uring ring;
+ struct io_uring_sqe *sqe;
+ int ret, fds[2];
+
+ ret = io_uring_queue_init(8, &ring, 0);
+ if (ret < 0) {
+ fprintf(stderr, "failed to init io_uring: %s\n", strerror(-ret));
+ return ret;
+ }
+ if (pipe(fds)) {
+ perror("pipe");
+ return -1;
+ }
+ ret = io_uring_register_files(&ring, fds, 2);
+ if (ret) {
+ fprintf(stderr, "file_register: %d\n", ret);
+ return ret;
+ }
+ close(fds[1]);
+
+ sqe = io_uring_get_sqe(&ring);
+ if (!sqe) {
+ fprintf(stderr, "%s: failed to get sqe\n", __FUNCTION__);
+ return 1;
+ }
+ /* potentially sitting in internal polling */
+ io_uring_prep_read(sqe, 0, buffer, 10, 0);
+ sqe->flags |= IOSQE_FIXED_FILE;
+
+ sqe = io_uring_get_sqe(&ring);
+ if (!sqe) {
+ fprintf(stderr, "%s: failed to get sqe\n", __FUNCTION__);
+ return 1;
+ }
+ /* staying in io-wq */
+ io_uring_prep_read(sqe, 0, buffer, 10, 0);
+ sqe->flags |= IOSQE_FIXED_FILE | IOSQE_ASYNC;
+
+ ret = io_uring_submit(&ring);
+ if (ret != 2) {
+ fprintf(stderr, "%s: got %d, wanted 1\n", __FUNCTION__, ret);
+ return 1;
+ }
+
+ /* should unregister files and close the write fd */
+ io_uring_queue_exit(&ring);
+
+ /*
+ * We're trying to wait for the ring to "really" exit, that will be
+ * done async. For that rely on the registered write end to be closed
+ * after ring quiesce, so failing read from the other pipe end.
+ */
+ read(fds[0], buffer, 10);
+ return 0;
+}
+
int main(int argc, char *argv[])
{
int sp[2], pid, ring_fd, ret;
@@ -80,6 +139,12 @@ int main(int argc, char *argv[])
if (argc > 1)
return 0;
+ ret = test_iowq_request_cancel();
+ if (ret) {
+ fprintf(stderr, "test_iowq_request_cancel() failed\n");
+ return 1;
+ }
+
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sp) != 0) {
perror("Failed to create Unix-domain socket pair\n");
return 1;
--
2.24.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH liburing 0/2] cancellation tests
2021-03-12 16:28 [PATCH liburing 0/2] cancellation tests Pavel Begunkov
2021-03-12 16:28 ` [PATCH liburing 1/2] tests: add more IORING_OP_ASYNC_CANCEL tests Pavel Begunkov
2021-03-12 16:28 ` [PATCH liburing 2/2] tests: test that ring exit cancels io-wq Pavel Begunkov
@ 2021-03-18 15:17 ` Jens Axboe
2 siblings, 0 replies; 4+ messages in thread
From: Jens Axboe @ 2021-03-18 15:17 UTC (permalink / raw)
To: Pavel Begunkov, io-uring
On 3/12/21 9:28 AM, Pavel Begunkov wrote:
> resend 2/2 + two IORING_OP_ASYNC_CANCEL tests in 1/2
>
> Pavel Begunkov (2):
> tests: add more IORING_OP_ASYNC_CANCEL tests
> tests: test that ring exit cancels io-wq
>
> test/io-cancel.c | 179 +++++++++++++++++++++++++++++++++++++++++++++++
> test/ring-leak.c | 65 +++++++++++++++++
> 2 files changed, 244 insertions(+)
Applied, thanks.
--
Jens Axboe
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2021-03-18 15:18 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-03-12 16:28 [PATCH liburing 0/2] cancellation tests Pavel Begunkov
2021-03-12 16:28 ` [PATCH liburing 1/2] tests: add more IORING_OP_ASYNC_CANCEL tests Pavel Begunkov
2021-03-12 16:28 ` [PATCH liburing 2/2] tests: test that ring exit cancels io-wq Pavel Begunkov
2021-03-18 15:17 ` [PATCH liburing 0/2] cancellation tests Jens Axboe
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.