mirror of
https://github.com/openharmony/third_party_liburing.git
synced 2026-08-26 18:26:44 -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>
323 lines
7.5 KiB
C
323 lines
7.5 KiB
C
/* SPDX-License-Identifier: MIT */
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
|
|
#include "liburing.h"
|
|
#include "test.h"
|
|
#include "helpers.h"
|
|
|
|
struct io_uring_query_opcode_short {
|
|
__u32 nr_request_opcodes;
|
|
__u32 nr_register_opcodes;
|
|
};
|
|
|
|
struct io_uring_query_opcode_large {
|
|
__u32 nr_request_opcodes;
|
|
__u32 nr_register_opcodes;
|
|
__u64 feature_flags;
|
|
__u64 ring_setup_flags;
|
|
__u64 enter_flags;
|
|
__u64 sqe_flags;
|
|
__u64 placeholder[8];
|
|
};
|
|
|
|
static struct io_uring_query_opcode sys_ops;
|
|
|
|
static int io_uring_query(struct io_uring *ring, struct io_uring_query_hdr *arg)
|
|
{
|
|
int fd = ring ? ring->ring_fd : -1;
|
|
|
|
return io_uring_register(fd, IORING_REGISTER_QUERY, arg, 0);
|
|
}
|
|
|
|
static int test_basic_query(void)
|
|
{
|
|
struct io_uring_query_opcode op;
|
|
struct io_uring_query_hdr hdr = {
|
|
.query_op = IO_URING_QUERY_OPCODES,
|
|
.query_data = uring_ptr_to_u64(&op),
|
|
.size = sizeof(op),
|
|
};
|
|
int ret;
|
|
|
|
ret = io_uring_query(NULL, &hdr);
|
|
if (ret == -EINVAL)
|
|
return T_EXIT_SKIP;
|
|
|
|
if (ret != 0) {
|
|
fprintf(stderr, "query failed %d\n", ret);
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
if (hdr.size != sizeof(op)) {
|
|
fprintf(stderr, "unexpected size %i vs %i\n",
|
|
(int)hdr.size, (int)sizeof(op));
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
if (hdr.result) {
|
|
fprintf(stderr, "unexpected result %i\n", hdr.result);
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
if (op.nr_register_opcodes <= IORING_REGISTER_QUERY) {
|
|
fprintf(stderr, "too few opcodes (%i)\n", op.nr_register_opcodes);
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
memcpy(&sys_ops, &op, sizeof(sys_ops));
|
|
return T_EXIT_PASS;
|
|
}
|
|
|
|
static int test_invalid(void)
|
|
{
|
|
int ret;
|
|
struct io_uring_query_opcode op;
|
|
struct io_uring_query_hdr invalid_hdr = {
|
|
.query_op = -1U,
|
|
.query_data = uring_ptr_to_u64(&op),
|
|
.size = sizeof(struct io_uring_query_opcode),
|
|
};
|
|
struct io_uring_query_hdr invalid_next_hdr = {
|
|
.query_op = IO_URING_QUERY_OPCODES,
|
|
.query_data = uring_ptr_to_u64(&op),
|
|
.size = sizeof(struct io_uring_query_opcode),
|
|
.next_entry = 0xdeadbeefUL,
|
|
};
|
|
struct io_uring_query_hdr invalid_data_hdr = {
|
|
.query_op = IO_URING_QUERY_OPCODES,
|
|
.query_data = 0xdeadbeefUL,
|
|
.size = sizeof(struct io_uring_query_opcode),
|
|
};
|
|
|
|
ret = io_uring_query(NULL, &invalid_hdr);
|
|
if (ret || invalid_hdr.result != -EOPNOTSUPP) {
|
|
fprintf(stderr, "failed invalid opcode %i (%i)\n",
|
|
ret, invalid_hdr.result);
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
ret = io_uring_query(NULL, &invalid_next_hdr);
|
|
if (ret != -EFAULT) {
|
|
fprintf(stderr, "invalid next %i\n", ret);
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
ret = io_uring_query(NULL, &invalid_data_hdr);
|
|
if (ret != -EFAULT) {
|
|
fprintf(stderr, "invalid next %i\n", ret);
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
return T_EXIT_PASS;
|
|
}
|
|
|
|
static int test_chain(void)
|
|
{
|
|
int ret;
|
|
struct io_uring_query_opcode op1, op2, op3;
|
|
struct io_uring_query_hdr hdr3 = {
|
|
.query_op = IO_URING_QUERY_OPCODES,
|
|
.query_data = uring_ptr_to_u64(&op3),
|
|
.size = sizeof(struct io_uring_query_opcode),
|
|
};
|
|
struct io_uring_query_hdr hdr2 = {
|
|
.query_op = IO_URING_QUERY_OPCODES,
|
|
.query_data = uring_ptr_to_u64(&op2),
|
|
.size = sizeof(struct io_uring_query_opcode),
|
|
.next_entry = uring_ptr_to_u64(&hdr3),
|
|
};
|
|
struct io_uring_query_hdr hdr1 = {
|
|
.query_op = IO_URING_QUERY_OPCODES,
|
|
.query_data = uring_ptr_to_u64(&op1),
|
|
.size = sizeof(struct io_uring_query_opcode),
|
|
.next_entry = uring_ptr_to_u64(&hdr2),
|
|
};
|
|
|
|
ret = io_uring_query(NULL, &hdr1);
|
|
if (ret) {
|
|
fprintf(stderr, "chain failed %i\n", ret);
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
if (hdr1.result || hdr2.result || hdr3.result) {
|
|
fprintf(stderr, "chain invalid result entries %i %i %i\n",
|
|
hdr1.result, hdr2.result, hdr3.result);
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
if (op1.nr_register_opcodes != sys_ops.nr_register_opcodes ||
|
|
op2.nr_register_opcodes != sys_ops.nr_register_opcodes ||
|
|
op3.nr_register_opcodes != sys_ops.nr_register_opcodes) {
|
|
fprintf(stderr, "chain invalid register opcodes\n");
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
return T_EXIT_PASS;
|
|
}
|
|
|
|
static int test_chain_loop(void)
|
|
{
|
|
int ret;
|
|
struct io_uring_query_opcode op1, op2;
|
|
struct io_uring_query_hdr hdr2 = {
|
|
.query_op = IO_URING_QUERY_OPCODES,
|
|
.query_data = uring_ptr_to_u64(&op2),
|
|
.size = sizeof(struct io_uring_query_opcode),
|
|
};
|
|
struct io_uring_query_hdr hdr1 = {
|
|
.query_op = IO_URING_QUERY_OPCODES,
|
|
.query_data = uring_ptr_to_u64(&op1),
|
|
.size = sizeof(struct io_uring_query_opcode),
|
|
};
|
|
struct io_uring_query_hdr hdr_self_circular = {
|
|
.query_op = IO_URING_QUERY_OPCODES,
|
|
.query_data = uring_ptr_to_u64(&op1),
|
|
.size = sizeof(struct io_uring_query_opcode),
|
|
.next_entry = uring_ptr_to_u64(&hdr_self_circular),
|
|
};
|
|
|
|
hdr1.next_entry = uring_ptr_to_u64(&hdr2);
|
|
hdr2.next_entry = uring_ptr_to_u64(&hdr1);
|
|
ret = io_uring_query(NULL, &hdr1);
|
|
if (!ret) {
|
|
fprintf(stderr, "chain loop failed %i\n", ret);
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
ret = io_uring_query(NULL, &hdr_self_circular);
|
|
if (!ret) {
|
|
fprintf(stderr, "chain loop failed %i\n", ret);
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
return T_EXIT_PASS;
|
|
}
|
|
|
|
static int test_compatibile_shorter(void)
|
|
{
|
|
int ret;
|
|
struct io_uring_query_opcode_short op;
|
|
struct io_uring_query_hdr hdr = {
|
|
.query_op = IO_URING_QUERY_OPCODES,
|
|
.query_data = uring_ptr_to_u64(&op),
|
|
.size = sizeof(op),
|
|
};
|
|
|
|
ret = io_uring_query(NULL, &hdr);
|
|
if (ret || hdr.result) {
|
|
fprintf(stderr, "failed invalid short result %i (%i)\n",
|
|
ret, hdr.result);
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
if (hdr.size != sizeof(struct io_uring_query_opcode_short)) {
|
|
fprintf(stderr, "unexpected short query size %i %i\n",
|
|
(int)hdr.size,
|
|
(int)sizeof(struct io_uring_query_opcode_short));
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
if (sys_ops.nr_register_opcodes != op.nr_register_opcodes ||
|
|
sys_ops.nr_request_opcodes != op.nr_request_opcodes) {
|
|
fprintf(stderr, "invalid short data\n");
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
return T_EXIT_PASS;
|
|
}
|
|
|
|
static int test_compatibile_larger(void)
|
|
{
|
|
int ret;
|
|
struct io_uring_query_opcode_large op;
|
|
struct io_uring_query_hdr hdr = {
|
|
.query_op = IO_URING_QUERY_OPCODES,
|
|
.query_data = uring_ptr_to_u64(&op),
|
|
.size = sizeof(op),
|
|
};
|
|
|
|
ret = io_uring_query(NULL, &hdr);
|
|
if (ret || hdr.result) {
|
|
fprintf(stderr, "failed invalid large result %i (%i)\n",
|
|
ret, hdr.result);
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
if (hdr.size < sizeof(struct io_uring_query_opcode)) {
|
|
fprintf(stderr, "unexpected large query size %i %i\n",
|
|
(int)hdr.size,
|
|
(int)sizeof(struct io_uring_query_opcode));
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
if (sys_ops.nr_register_opcodes != op.nr_register_opcodes ||
|
|
sys_ops.nr_request_opcodes != op.nr_request_opcodes ||
|
|
sys_ops.ring_setup_flags != op.ring_setup_flags ||
|
|
sys_ops.feature_flags != op.feature_flags) {
|
|
fprintf(stderr, "invalid large data\n");
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
return T_EXIT_PASS;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
struct io_uring ring;
|
|
int ret;
|
|
|
|
if (argc > 1)
|
|
return T_EXIT_SKIP;
|
|
|
|
ret = test_basic_query();
|
|
if (ret != T_EXIT_PASS) {
|
|
if (ret == T_EXIT_SKIP)
|
|
fprintf(stderr, "ring query not supported, skip\n");
|
|
else
|
|
fprintf(stderr, "test_basic_query failed\n");
|
|
|
|
return T_EXIT_SKIP;
|
|
}
|
|
|
|
ret = io_uring_queue_init(8, &ring, 0);
|
|
if (ret) {
|
|
fprintf(stderr, "init failed\n");
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
ret = test_invalid();
|
|
if (ret)
|
|
return T_EXIT_FAIL;
|
|
|
|
ret = test_chain();
|
|
if (ret) {
|
|
fprintf(stderr, "test_chain failed\n");
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
ret = test_chain_loop();
|
|
if (ret) {
|
|
fprintf(stderr, "test_chain_loop failed\n");
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
ret = test_compatibile_shorter();
|
|
if (ret) {
|
|
fprintf(stderr, "test_compatibile_shorter failed\n");
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
ret = test_compatibile_larger();
|
|
if (ret) {
|
|
fprintf(stderr, "test_compatibile_larger failed\n");
|
|
return T_EXIT_FAIL;
|
|
}
|
|
|
|
return 0;
|
|
}
|