mirror of
https://github.com/openharmony/third_party_liburing.git
synced 2026-07-20 22:58:41 -04:00
4b8f3098a5
Co-authored-by: Pavel Begunkov<asml.silence@gmail.com> Co-authored-by: Guillem Jover<guillem@hadrons.org> Co-authored-by: Jens Axboe<axboe@kernel.dk> Co-authored-by: Khem Raj<raj.khem@gmail.com> Co-authored-by: Michael de Lang<kingoipo@gmail.com> Co-authored-by: David Disseldorp<ddiss@suse.de> Co-authored-by: Ming Lei<ming.lei@redhat.com>
270 lines
5.8 KiB
C
270 lines
5.8 KiB
C
/* SPDX-License-Identifier: MIT */
|
|
/*
|
|
* Description: test io_uring_register_sync_cancel()
|
|
*
|
|
*/
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
|
|
#include "liburing.h"
|
|
#include "helpers.h"
|
|
|
|
static int no_sync_cancel, no_sync_cancel_op;
|
|
|
|
static int test_sync_cancel_timeout(struct io_uring *ring, int async, int by_op)
|
|
{
|
|
struct io_uring_sync_cancel_reg reg = { };
|
|
struct io_uring_sqe *sqe;
|
|
struct io_uring_cqe *cqe;
|
|
int ret, fds[2], to_prep;
|
|
char buf[32];
|
|
|
|
if (pipe(fds) < 0) {
|
|
perror("pipe");
|
|
return 1;
|
|
}
|
|
|
|
to_prep = 1;
|
|
sqe = io_uring_get_sqe(ring);
|
|
io_uring_prep_read(sqe, fds[0], buf, sizeof(buf), 0);
|
|
sqe->user_data = 0x89;
|
|
if (async)
|
|
sqe->flags |= IOSQE_ASYNC;
|
|
|
|
ret = io_uring_submit(ring);
|
|
if (ret != to_prep) {
|
|
fprintf(stderr, "submit=%d\n", ret);
|
|
return 1;
|
|
}
|
|
|
|
usleep(10000);
|
|
|
|
reg.flags = IORING_ASYNC_CANCEL_OP;
|
|
reg.opcode = IORING_OP_READ;
|
|
reg.timeout.tv_nsec = 1;
|
|
ret = io_uring_register_sync_cancel(ring, ®);
|
|
/* earlier kernels had sync cancel, but not per-op */
|
|
if (ret == -EINVAL) {
|
|
no_sync_cancel_op = 1;
|
|
return 0;
|
|
}
|
|
if (async) {
|
|
/* we expect -ETIME here, but can race and get 0 */
|
|
if (ret != -ETIME && ret != 0) {
|
|
fprintf(stderr, "sync_cancel=%d\n", ret);
|
|
return 1;
|
|
}
|
|
} else {
|
|
if (ret < 0) {
|
|
fprintf(stderr, "sync_cancel=%d\n", ret);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* we could _almost_ use peek_cqe() here, but there is still
|
|
* a small gap where io-wq is done with the request and on
|
|
* its way to posting a completion, but hasn't done it just
|
|
* yet. the request is canceled and won't be doing any IO
|
|
* to buffers etc, but the cqe may not have quite arrived yet.
|
|
*/
|
|
ret = io_uring_wait_cqe(ring, &cqe);
|
|
if (ret) {
|
|
fprintf(stderr, "peek=%d\n", ret);
|
|
return 1;
|
|
}
|
|
if (cqe->res >= 0) {
|
|
fprintf(stderr, "cqe->res=%d\n", cqe->res);
|
|
return 1;
|
|
}
|
|
io_uring_cqe_seen(ring, cqe);
|
|
return 0;
|
|
}
|
|
|
|
static int test_sync_cancel(struct io_uring *ring, int async, int nr_all,
|
|
int use_fd, int by_op)
|
|
{
|
|
struct io_uring_sync_cancel_reg reg = { };
|
|
struct io_uring_sqe *sqe;
|
|
struct io_uring_cqe *cqe;
|
|
int ret, fds[2], to_prep, i;
|
|
char buf[32];
|
|
|
|
if (pipe(fds) < 0) {
|
|
perror("pipe");
|
|
return 1;
|
|
}
|
|
|
|
to_prep = 1;
|
|
if (nr_all)
|
|
to_prep = 4;
|
|
for (i = 0; i < to_prep; i++) {
|
|
sqe = io_uring_get_sqe(ring);
|
|
io_uring_prep_read(sqe, fds[0], buf, sizeof(buf), 0);
|
|
sqe->user_data = 0x89;
|
|
if (async)
|
|
sqe->flags |= IOSQE_ASYNC;
|
|
}
|
|
|
|
ret = io_uring_submit(ring);
|
|
if (ret != to_prep) {
|
|
fprintf(stderr, "submit=%d\n", ret);
|
|
return 1;
|
|
}
|
|
|
|
usleep(10000);
|
|
|
|
if (!use_fd)
|
|
reg.addr = 0x89;
|
|
else
|
|
reg.fd = fds[0];
|
|
reg.timeout.tv_sec = 200;
|
|
if (nr_all)
|
|
reg.flags |= IORING_ASYNC_CANCEL_ALL;
|
|
if (use_fd)
|
|
reg.flags |= IORING_ASYNC_CANCEL_FD;
|
|
ret = io_uring_register_sync_cancel(ring, ®);
|
|
if (ret < 0) {
|
|
if (ret == -EINVAL && !no_sync_cancel) {
|
|
no_sync_cancel = 1;
|
|
return 0;
|
|
}
|
|
fprintf(stderr, "sync_cancel=%d\n", ret);
|
|
return 1;
|
|
}
|
|
|
|
for (i = 0; i < to_prep; i++) {
|
|
/*
|
|
* we could _almost_ use peek_cqe() here, but there is still
|
|
* a small gap where io-wq is done with the request and on
|
|
* its way to posting a completion, but hasn't done it just
|
|
* yet. the request is canceled and won't be doing any IO
|
|
* to buffers etc, but the cqe may not have quite arrived yet.
|
|
*/
|
|
ret = io_uring_wait_cqe(ring, &cqe);
|
|
if (ret) {
|
|
fprintf(stderr, "peek=%d\n", ret);
|
|
return 1;
|
|
}
|
|
if (cqe->res >= 0) {
|
|
fprintf(stderr, "cqe->res=%d\n", cqe->res);
|
|
return 1;
|
|
}
|
|
io_uring_cqe_seen(ring, cqe);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
struct io_uring ring;
|
|
int ret;
|
|
|
|
if (argc > 1)
|
|
return T_EXIT_SKIP;
|
|
|
|
ret = t_create_ring(7, &ring, 0);
|
|
if (ret == T_SETUP_SKIP)
|
|
return T_EXIT_SKIP;
|
|
else if (ret != T_SETUP_OK)
|
|
return ret;
|
|
|
|
ret = test_sync_cancel(&ring, 0, 0, 0, 0);
|
|
if (ret) {
|
|
fprintf(stderr, "test_sync_cancel 0 0 0 failed\n");
|
|
return T_EXIT_FAIL;
|
|
}
|
|
if (no_sync_cancel)
|
|
return T_EXIT_SKIP;
|
|
|
|
ret = test_sync_cancel(&ring, 0, 0, 0, 1);
|
|
if (ret) {
|
|
fprintf(stderr, "test_sync_cancel 0 0 1 failed\n");
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
ret = test_sync_cancel(&ring, 1, 0, 0, 0);
|
|
if (ret) {
|
|
fprintf(stderr, "test_sync_cancel 1 0 0 0 failed\n");
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
ret = test_sync_cancel(&ring, 1, 0, 0, 1);
|
|
if (ret) {
|
|
fprintf(stderr, "test_sync_cancel 1 0 0 1 failed\n");
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
|
|
ret = test_sync_cancel(&ring, 0, 1, 0, 0);
|
|
if (ret) {
|
|
fprintf(stderr, "test_sync_cancel 0 1 0 0 failed\n");
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
ret = test_sync_cancel(&ring, 0, 1, 0, 1);
|
|
if (ret) {
|
|
fprintf(stderr, "test_sync_cancel 0 1 0 1 failed\n");
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
|
|
ret = test_sync_cancel(&ring, 1, 1, 0, 0);
|
|
if (ret) {
|
|
fprintf(stderr, "test_sync_cancel 1 1 0 0 failed\n");
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
ret = test_sync_cancel(&ring, 0, 0, 1, 0);
|
|
if (ret) {
|
|
fprintf(stderr, "test_sync_cancel 0 0 1 0 failed\n");
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
ret = test_sync_cancel(&ring, 1, 0, 1, 0);
|
|
if (ret) {
|
|
fprintf(stderr, "test_sync_cancel 1 0 1 0 failed\n");
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
ret = test_sync_cancel(&ring, 0, 1, 1, 0);
|
|
if (ret) {
|
|
fprintf(stderr, "test_sync_cancel 0 1 1 0 failed\n");
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
ret = test_sync_cancel(&ring, 1, 1, 1, 0);
|
|
if (ret) {
|
|
fprintf(stderr, "test_sync_cancel 1 1 1 0 failed\n");
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
ret = test_sync_cancel_timeout(&ring, 0, 0);
|
|
if (ret) {
|
|
fprintf(stderr, "test_sync_cancel_timeout 0 0\n");
|
|
return T_EXIT_FAIL;
|
|
}
|
|
if (no_sync_cancel_op)
|
|
return T_EXIT_PASS;
|
|
|
|
ret = test_sync_cancel_timeout(&ring, 0, 1);
|
|
if (ret) {
|
|
fprintf(stderr, "test_sync_cancel_timeout 0 1\n");
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
/* must be last, leaves request */
|
|
ret = test_sync_cancel_timeout(&ring, 1, 0);
|
|
if (ret) {
|
|
fprintf(stderr, "test_sync_cancel_timeout 1\n");
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
return T_EXIT_PASS;
|
|
}
|