| /* SPDX-License-Identifier: MIT */ |
| /* |
| * Description: test NOP flags (IORING_NOP_FILE, IORING_NOP_FIXED_FILE, |
| * IORING_NOP_FIXED_BUFFER, IORING_NOP_TW, IORING_NOP_CQE32) |
| * |
| * These flags allow NOP to exercise file lookups, buffer lookups, and |
| * task_work completion paths without real I/O, useful for targeted testing. |
| */ |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <fcntl.h> |
| |
| #include "liburing.h" |
| #include "helpers.h" |
| |
| #ifndef IORING_NOP_INJECT_RESULT |
| #define IORING_NOP_INJECT_RESULT (1U << 0) |
| #endif |
| #ifndef IORING_NOP_FILE |
| #define IORING_NOP_FILE (1U << 1) |
| #endif |
| #ifndef IORING_NOP_FIXED_FILE |
| #define IORING_NOP_FIXED_FILE (1U << 2) |
| #endif |
| #ifndef IORING_NOP_FIXED_BUFFER |
| #define IORING_NOP_FIXED_BUFFER (1U << 3) |
| #endif |
| #ifndef IORING_NOP_TW |
| #define IORING_NOP_TW (1U << 4) |
| #endif |
| #ifndef IORING_NOP_CQE32 |
| #define IORING_NOP_CQE32 (1U << 5) |
| #endif |
| |
| static int no_nop_flags; |
| static int no_nop_file; |
| |
| /* |
| * Detect NOP flags support using INJECT_RESULT. A kernel that supports |
| * NOP flags will return the injected value; one that doesn't will |
| * return 0 (plain NOP) or -EINVAL. |
| */ |
| static int test_nop_detect(struct io_uring *ring) |
| { |
| struct io_uring_sqe *sqe; |
| struct io_uring_cqe *cqe; |
| int ret; |
| |
| sqe = io_uring_get_sqe(ring); |
| io_uring_prep_nop(sqe); |
| sqe->nop_flags = IORING_NOP_INJECT_RESULT; |
| sqe->len = 42; |
| sqe->user_data = 1; |
| |
| ret = io_uring_submit(ring); |
| if (ret != 1) { |
| fprintf(stderr, "submit detect: %d\n", ret); |
| return T_EXIT_FAIL; |
| } |
| |
| ret = io_uring_wait_cqe(ring, &cqe); |
| if (ret) { |
| fprintf(stderr, "wait detect: %d\n", ret); |
| return T_EXIT_FAIL; |
| } |
| |
| if (cqe->res != 42) { |
| /* Kernel doesn't support NOP flags */ |
| no_nop_flags = 1; |
| io_uring_cqe_seen(ring, cqe); |
| return T_EXIT_SKIP; |
| } |
| |
| io_uring_cqe_seen(ring, cqe); |
| return T_EXIT_PASS; |
| } |
| |
| /* |
| * Detect IORING_NOP_FILE support by using it with a bad fd. |
| * If supported, returns -EBADF. If not, returns 0 (NOP succeeds, |
| * kernel ignores the FILE flag). |
| */ |
| static int test_nop_file_bad_fd(struct io_uring *ring) |
| { |
| struct io_uring_sqe *sqe; |
| struct io_uring_cqe *cqe; |
| int ret; |
| |
| if (no_nop_flags) |
| return T_EXIT_SKIP; |
| |
| sqe = io_uring_get_sqe(ring); |
| io_uring_prep_nop(sqe); |
| sqe->nop_flags = IORING_NOP_FILE; |
| sqe->fd = 9999; /* invalid fd */ |
| sqe->user_data = 1; |
| |
| ret = io_uring_submit(ring); |
| if (ret != 1) { |
| fprintf(stderr, "submit: %d\n", ret); |
| return T_EXIT_FAIL; |
| } |
| |
| ret = io_uring_wait_cqe(ring, &cqe); |
| if (ret) { |
| fprintf(stderr, "wait: %d\n", ret); |
| return T_EXIT_FAIL; |
| } |
| |
| if (cqe->res == 0) { |
| /* Kernel doesn't support IORING_NOP_FILE */ |
| no_nop_file = 1; |
| io_uring_cqe_seen(ring, cqe); |
| return T_EXIT_SKIP; |
| } |
| |
| if (cqe->res != -EBADF && cqe->res != -EINVAL) { |
| fprintf(stderr, "nop bad fd res: %d (expected -EBADF)\n", cqe->res); |
| io_uring_cqe_seen(ring, cqe); |
| return T_EXIT_FAIL; |
| } |
| |
| io_uring_cqe_seen(ring, cqe); |
| return T_EXIT_PASS; |
| } |
| |
| /* |
| * Test IORING_NOP_FILE - NOP with a normal fd lookup |
| */ |
| static int test_nop_file(struct io_uring *ring) |
| { |
| struct io_uring_sqe *sqe; |
| struct io_uring_cqe *cqe; |
| int ret, fd; |
| |
| if (no_nop_flags || no_nop_file) |
| return T_EXIT_SKIP; |
| |
| fd = open("/dev/null", O_RDWR); |
| if (fd < 0) { |
| perror("open /dev/null"); |
| return T_EXIT_FAIL; |
| } |
| |
| sqe = io_uring_get_sqe(ring); |
| io_uring_prep_nop(sqe); |
| sqe->nop_flags = IORING_NOP_FILE; |
| sqe->fd = fd; |
| sqe->user_data = 1; |
| |
| ret = io_uring_submit(ring); |
| if (ret != 1) { |
| fprintf(stderr, "submit: %d\n", ret); |
| close(fd); |
| return T_EXIT_FAIL; |
| } |
| |
| ret = io_uring_wait_cqe(ring, &cqe); |
| if (ret) { |
| fprintf(stderr, "wait: %d\n", ret); |
| close(fd); |
| return T_EXIT_FAIL; |
| } |
| |
| if (cqe->res != 0) { |
| if (cqe->res == -EINVAL) { |
| no_nop_file = 1; |
| return T_EXIT_SKIP; |
| } |
| fprintf(stderr, "nop file res: %d\n", cqe->res); |
| io_uring_cqe_seen(ring, cqe); |
| close(fd); |
| return T_EXIT_FAIL; |
| } |
| |
| io_uring_cqe_seen(ring, cqe); |
| close(fd); |
| return T_EXIT_PASS; |
| } |
| |
| /* |
| * Test IORING_NOP_FIXED_FILE - NOP with a fixed file lookup |
| */ |
| static int test_nop_fixed_file(struct io_uring *ring) |
| { |
| struct io_uring_sqe *sqe; |
| struct io_uring_cqe *cqe; |
| int ret, fd; |
| |
| if (no_nop_flags || no_nop_file) |
| return T_EXIT_SKIP; |
| |
| fd = open("/dev/null", O_RDWR); |
| if (fd < 0) { |
| perror("open /dev/null"); |
| return T_EXIT_FAIL; |
| } |
| |
| ret = io_uring_register_files(ring, &fd, 1); |
| if (ret) { |
| fprintf(stderr, "register files: %d\n", ret); |
| close(fd); |
| return T_EXIT_FAIL; |
| } |
| |
| sqe = io_uring_get_sqe(ring); |
| io_uring_prep_nop(sqe); |
| sqe->nop_flags = IORING_NOP_FILE | IORING_NOP_FIXED_FILE; |
| sqe->fd = 0; /* fixed file index */ |
| sqe->user_data = 1; |
| |
| ret = io_uring_submit(ring); |
| if (ret != 1) { |
| fprintf(stderr, "submit: %d\n", ret); |
| goto err; |
| } |
| |
| ret = io_uring_wait_cqe(ring, &cqe); |
| if (ret) { |
| fprintf(stderr, "wait: %d\n", ret); |
| goto err; |
| } |
| |
| if (cqe->res != 0) { |
| fprintf(stderr, "nop fixed file res: %d\n", cqe->res); |
| io_uring_cqe_seen(ring, cqe); |
| goto err; |
| } |
| |
| io_uring_cqe_seen(ring, cqe); |
| |
| /* Test with invalid fixed file index */ |
| sqe = io_uring_get_sqe(ring); |
| io_uring_prep_nop(sqe); |
| sqe->nop_flags = IORING_NOP_FILE | IORING_NOP_FIXED_FILE; |
| sqe->fd = 999; /* invalid index */ |
| sqe->user_data = 2; |
| |
| ret = io_uring_submit(ring); |
| if (ret != 1) { |
| fprintf(stderr, "submit bad index: %d\n", ret); |
| goto err; |
| } |
| |
| ret = io_uring_wait_cqe(ring, &cqe); |
| if (ret) { |
| fprintf(stderr, "wait bad index: %d\n", ret); |
| goto err; |
| } |
| |
| if (cqe->res != -EBADF) { |
| fprintf(stderr, "nop bad fixed file res: %d (expected -EBADF)\n", |
| cqe->res); |
| io_uring_cqe_seen(ring, cqe); |
| goto err; |
| } |
| |
| io_uring_cqe_seen(ring, cqe); |
| io_uring_unregister_files(ring); |
| close(fd); |
| return T_EXIT_PASS; |
| err: |
| io_uring_unregister_files(ring); |
| close(fd); |
| return T_EXIT_FAIL; |
| } |
| |
| /* |
| * Test IORING_NOP_FIXED_BUFFER - NOP with a registered buffer lookup |
| */ |
| static int test_nop_fixed_buffer(struct io_uring *ring) |
| { |
| struct io_uring_sqe *sqe; |
| struct io_uring_cqe *cqe; |
| char buf[4096]; |
| struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf) }; |
| int ret; |
| |
| if (no_nop_flags) |
| return T_EXIT_SKIP; |
| |
| ret = io_uring_register_buffers(ring, &iov, 1); |
| if (ret) { |
| fprintf(stderr, "register buffers: %d\n", ret); |
| return T_EXIT_FAIL; |
| } |
| |
| /* Valid buffer index */ |
| sqe = io_uring_get_sqe(ring); |
| io_uring_prep_nop(sqe); |
| sqe->nop_flags = IORING_NOP_FIXED_BUFFER; |
| sqe->buf_index = 0; |
| sqe->user_data = 1; |
| |
| ret = io_uring_submit(ring); |
| if (ret != 1) { |
| fprintf(stderr, "submit: %d\n", ret); |
| goto err; |
| } |
| |
| ret = io_uring_wait_cqe(ring, &cqe); |
| if (ret) { |
| fprintf(stderr, "wait: %d\n", ret); |
| goto err; |
| } |
| |
| if (cqe->res != 0) { |
| if (cqe->res == -EINVAL) { |
| io_uring_cqe_seen(ring, cqe); |
| return T_EXIT_SKIP; |
| } |
| fprintf(stderr, "nop fixed buffer res: %d\n", cqe->res); |
| io_uring_cqe_seen(ring, cqe); |
| goto err; |
| } |
| io_uring_cqe_seen(ring, cqe); |
| |
| /* Invalid buffer index */ |
| sqe = io_uring_get_sqe(ring); |
| io_uring_prep_nop(sqe); |
| sqe->nop_flags = IORING_NOP_FIXED_BUFFER; |
| sqe->buf_index = 999; |
| sqe->user_data = 2; |
| |
| ret = io_uring_submit(ring); |
| if (ret != 1) { |
| fprintf(stderr, "submit bad buf: %d\n", ret); |
| goto err; |
| } |
| |
| ret = io_uring_wait_cqe(ring, &cqe); |
| if (ret) { |
| fprintf(stderr, "wait bad buf: %d\n", ret); |
| goto err; |
| } |
| |
| if (cqe->res == 0) { |
| /* Kernel doesn't support IORING_NOP_FIXED_BUFFER */ |
| io_uring_cqe_seen(ring, cqe); |
| io_uring_unregister_buffers(ring); |
| return T_EXIT_SKIP; |
| } |
| if (cqe->res != -EFAULT) { |
| fprintf(stderr, "nop bad buffer res: %d (expected -EFAULT)\n", |
| cqe->res); |
| io_uring_cqe_seen(ring, cqe); |
| goto err; |
| } |
| |
| io_uring_cqe_seen(ring, cqe); |
| io_uring_unregister_buffers(ring); |
| return T_EXIT_PASS; |
| err: |
| io_uring_unregister_buffers(ring); |
| return T_EXIT_FAIL; |
| } |
| |
| /* |
| * Test IORING_NOP_TW - NOP completing via task_work |
| */ |
| static int test_nop_tw(struct io_uring *ring) |
| { |
| struct io_uring_sqe *sqe; |
| struct io_uring_cqe *cqe; |
| int ret, i; |
| |
| if (no_nop_flags) |
| return T_EXIT_SKIP; |
| |
| /* Submit several NOPs via task_work path */ |
| for (i = 0; i < 8; i++) { |
| sqe = io_uring_get_sqe(ring); |
| io_uring_prep_nop(sqe); |
| sqe->nop_flags = IORING_NOP_TW; |
| sqe->user_data = i + 1; |
| } |
| |
| ret = io_uring_submit(ring); |
| if (ret != 8) { |
| fprintf(stderr, "submit tw: %d\n", ret); |
| return T_EXIT_FAIL; |
| } |
| |
| for (i = 0; i < 8; i++) { |
| ret = io_uring_wait_cqe(ring, &cqe); |
| if (ret) { |
| fprintf(stderr, "wait tw: %d\n", ret); |
| return T_EXIT_FAIL; |
| } |
| if (cqe->res != 0) { |
| if (cqe->res == -EINVAL) { |
| io_uring_cqe_seen(ring, cqe); |
| return T_EXIT_SKIP; |
| } |
| fprintf(stderr, "nop tw res: %d\n", cqe->res); |
| io_uring_cqe_seen(ring, cqe); |
| return T_EXIT_FAIL; |
| } |
| io_uring_cqe_seen(ring, cqe); |
| } |
| |
| return T_EXIT_PASS; |
| } |
| |
| /* |
| * Test IORING_NOP_TW combined with IORING_NOP_INJECT_RESULT |
| */ |
| static int test_nop_tw_inject(struct io_uring *ring) |
| { |
| struct io_uring_sqe *sqe; |
| struct io_uring_cqe *cqe; |
| int ret; |
| |
| if (no_nop_flags) |
| return T_EXIT_SKIP; |
| |
| sqe = io_uring_get_sqe(ring); |
| io_uring_prep_nop(sqe); |
| sqe->nop_flags = IORING_NOP_TW | IORING_NOP_INJECT_RESULT; |
| sqe->len = 42; |
| sqe->user_data = 1; |
| |
| ret = io_uring_submit(ring); |
| if (ret != 1) { |
| fprintf(stderr, "submit: %d\n", ret); |
| return T_EXIT_FAIL; |
| } |
| |
| ret = io_uring_wait_cqe(ring, &cqe); |
| if (ret) { |
| fprintf(stderr, "wait: %d\n", ret); |
| return T_EXIT_FAIL; |
| } |
| |
| if (cqe->res != 42) { |
| if (cqe->res == -EINVAL) { |
| io_uring_cqe_seen(ring, cqe); |
| return T_EXIT_SKIP; |
| } |
| fprintf(stderr, "nop tw inject res: %d (expected 42)\n", cqe->res); |
| io_uring_cqe_seen(ring, cqe); |
| return T_EXIT_FAIL; |
| } |
| |
| io_uring_cqe_seen(ring, cqe); |
| return T_EXIT_PASS; |
| } |
| |
| /* |
| * Test IORING_NOP_CQE32 - NOP with extra1/extra2 in big CQE |
| */ |
| static int test_nop_cqe32(void) |
| { |
| struct io_uring_sqe *sqe; |
| struct io_uring_cqe *cqe; |
| struct io_uring ring; |
| int ret; |
| |
| if (no_nop_flags) |
| return T_EXIT_SKIP; |
| |
| ret = io_uring_queue_init(8, &ring, IORING_SETUP_CQE32); |
| if (ret) { |
| if (ret == -EINVAL) |
| return T_EXIT_SKIP; |
| fprintf(stderr, "ring setup cqe32: %d\n", ret); |
| return T_EXIT_FAIL; |
| } |
| |
| sqe = io_uring_get_sqe(&ring); |
| io_uring_prep_nop(sqe); |
| sqe->nop_flags = IORING_NOP_CQE32; |
| sqe->off = 0xdeadbeef12345678ULL; /* extra1 */ |
| sqe->addr = 0xabcdef0011223344ULL; /* extra2 */ |
| sqe->user_data = 1; |
| |
| ret = io_uring_submit(&ring); |
| if (ret != 1) { |
| fprintf(stderr, "submit cqe32: %d\n", ret); |
| goto err; |
| } |
| |
| ret = io_uring_wait_cqe(&ring, &cqe); |
| if (ret) { |
| fprintf(stderr, "wait cqe32: %d\n", ret); |
| goto err; |
| } |
| |
| if (cqe->res != 0) { |
| if (cqe->res == -EINVAL) |
| goto skip; |
| fprintf(stderr, "nop cqe32 res: %d\n", cqe->res); |
| io_uring_cqe_seen(&ring, cqe); |
| goto err; |
| } |
| |
| if (cqe->big_cqe[0] != 0xdeadbeef12345678ULL) { |
| fprintf(stderr, "cqe32 extra1: 0x%llx (expected 0xdeadbeef12345678)\n", |
| (unsigned long long) cqe->big_cqe[0]); |
| io_uring_cqe_seen(&ring, cqe); |
| goto err; |
| } |
| |
| if (cqe->big_cqe[1] != 0xabcdef0011223344ULL) { |
| fprintf(stderr, "cqe32 extra2: 0x%llx (expected 0xabcdef0011223344)\n", |
| (unsigned long long) cqe->big_cqe[1]); |
| io_uring_cqe_seen(&ring, cqe); |
| goto err; |
| } |
| |
| io_uring_cqe_seen(&ring, cqe); |
| io_uring_queue_exit(&ring); |
| return T_EXIT_PASS; |
| err: |
| io_uring_queue_exit(&ring); |
| return T_EXIT_FAIL; |
| skip: |
| io_uring_queue_exit(&ring); |
| return T_EXIT_SKIP; |
| } |
| |
| /* |
| * Test IORING_NOP_CQE32 requires CQE32 or CQE_MIXED ring |
| */ |
| static int test_nop_cqe32_no_ring_support(void) |
| { |
| struct io_uring_sqe *sqe; |
| struct io_uring_cqe *cqe; |
| struct io_uring ring; |
| int ret; |
| |
| if (no_nop_flags) |
| return T_EXIT_SKIP; |
| |
| /* Ring without CQE32 */ |
| ret = io_uring_queue_init(8, &ring, 0); |
| if (ret) { |
| fprintf(stderr, "ring setup: %d\n", ret); |
| return T_EXIT_FAIL; |
| } |
| |
| sqe = io_uring_get_sqe(&ring); |
| io_uring_prep_nop(sqe); |
| sqe->nop_flags = IORING_NOP_CQE32; |
| sqe->off = 1; |
| sqe->addr = 2; |
| sqe->user_data = 1; |
| |
| ret = io_uring_submit(&ring); |
| if (ret != 1) { |
| fprintf(stderr, "submit: %d\n", ret); |
| io_uring_queue_exit(&ring); |
| return T_EXIT_FAIL; |
| } |
| |
| ret = io_uring_wait_cqe(&ring, &cqe); |
| if (ret) { |
| fprintf(stderr, "wait: %d\n", ret); |
| io_uring_queue_exit(&ring); |
| return T_EXIT_FAIL; |
| } |
| |
| if (cqe->res != -EINVAL) { |
| fprintf(stderr, "nop cqe32 no support res: %d (expected -EINVAL)\n", |
| cqe->res); |
| io_uring_cqe_seen(&ring, cqe); |
| io_uring_queue_exit(&ring); |
| return T_EXIT_FAIL; |
| } |
| |
| io_uring_cqe_seen(&ring, cqe); |
| io_uring_queue_exit(&ring); |
| return T_EXIT_PASS; |
| } |
| |
| /* |
| * Test combined flags: FILE + FIXED_FILE + FIXED_BUFFER + TW |
| */ |
| static int test_nop_combined(struct io_uring *ring) |
| { |
| struct io_uring_sqe *sqe; |
| struct io_uring_cqe *cqe; |
| char buf[4096]; |
| struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf) }; |
| int ret, fd; |
| |
| if (no_nop_flags || no_nop_file) |
| return T_EXIT_SKIP; |
| |
| fd = open("/dev/null", O_RDWR); |
| if (fd < 0) { |
| perror("open /dev/null"); |
| return T_EXIT_FAIL; |
| } |
| |
| ret = io_uring_register_files(ring, &fd, 1); |
| if (ret) { |
| fprintf(stderr, "register files: %d\n", ret); |
| close(fd); |
| return T_EXIT_FAIL; |
| } |
| |
| ret = io_uring_register_buffers(ring, &iov, 1); |
| if (ret) { |
| fprintf(stderr, "register buffers: %d\n", ret); |
| io_uring_unregister_files(ring); |
| close(fd); |
| return T_EXIT_FAIL; |
| } |
| |
| /* All flags combined */ |
| sqe = io_uring_get_sqe(ring); |
| io_uring_prep_nop(sqe); |
| sqe->nop_flags = IORING_NOP_FILE | IORING_NOP_FIXED_FILE | |
| IORING_NOP_FIXED_BUFFER | IORING_NOP_TW; |
| sqe->fd = 0; |
| sqe->buf_index = 0; |
| sqe->user_data = 1; |
| |
| ret = io_uring_submit(ring); |
| if (ret != 1) { |
| fprintf(stderr, "submit combined: %d\n", ret); |
| goto err; |
| } |
| |
| ret = io_uring_wait_cqe(ring, &cqe); |
| if (ret) { |
| fprintf(stderr, "wait combined: %d\n", ret); |
| goto err; |
| } |
| |
| if (cqe->res != 0) { |
| fprintf(stderr, "nop combined res: %d\n", cqe->res); |
| io_uring_cqe_seen(ring, cqe); |
| goto err; |
| } |
| |
| io_uring_cqe_seen(ring, cqe); |
| io_uring_unregister_buffers(ring); |
| io_uring_unregister_files(ring); |
| close(fd); |
| return T_EXIT_PASS; |
| err: |
| io_uring_unregister_buffers(ring); |
| io_uring_unregister_files(ring); |
| close(fd); |
| return T_EXIT_FAIL; |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| struct io_uring ring; |
| int ret; |
| |
| if (argc > 1) |
| return T_EXIT_SKIP; |
| |
| ret = io_uring_queue_init(8, &ring, IORING_SETUP_SUBMIT_ALL); |
| if (ret) { |
| if (ret == -EINVAL) |
| return T_EXIT_SKIP; |
| fprintf(stderr, "ring setup failed: %d\n", ret); |
| return T_EXIT_FAIL; |
| } |
| |
| ret = test_nop_detect(&ring); |
| if (ret == T_EXIT_SKIP) { |
| printf("NOP flags not supported, skipping\n"); |
| io_uring_queue_exit(&ring); |
| return T_EXIT_SKIP; |
| } else if (ret == T_EXIT_FAIL) { |
| fprintf(stderr, "test_nop_detect failed\n"); |
| return T_EXIT_FAIL; |
| } |
| |
| /* Use bad fd test to detect NOP_FILE support */ |
| ret = test_nop_file_bad_fd(&ring); |
| if (ret == T_EXIT_FAIL) { |
| fprintf(stderr, "test_nop_file_bad_fd failed\n"); |
| return T_EXIT_FAIL; |
| } |
| |
| ret = test_nop_file(&ring); |
| if (ret == T_EXIT_FAIL) { |
| fprintf(stderr, "test_nop_file failed\n"); |
| return T_EXIT_FAIL; |
| } |
| |
| ret = test_nop_fixed_file(&ring); |
| if (ret == T_EXIT_FAIL) { |
| fprintf(stderr, "test_nop_fixed_file failed\n"); |
| return T_EXIT_FAIL; |
| } |
| |
| ret = test_nop_fixed_buffer(&ring); |
| if (ret == T_EXIT_FAIL) { |
| fprintf(stderr, "test_nop_fixed_buffer failed\n"); |
| return T_EXIT_FAIL; |
| } |
| |
| ret = test_nop_tw(&ring); |
| if (ret == T_EXIT_FAIL) { |
| fprintf(stderr, "test_nop_tw failed\n"); |
| return T_EXIT_FAIL; |
| } |
| |
| ret = test_nop_tw_inject(&ring); |
| if (ret == T_EXIT_FAIL) { |
| fprintf(stderr, "test_nop_tw_inject failed\n"); |
| return T_EXIT_FAIL; |
| } |
| |
| io_uring_queue_exit(&ring); |
| |
| ret = test_nop_cqe32(); |
| if (ret == T_EXIT_FAIL) { |
| fprintf(stderr, "test_nop_cqe32 failed\n"); |
| return T_EXIT_FAIL; |
| } |
| |
| ret = test_nop_cqe32_no_ring_support(); |
| if (ret == T_EXIT_FAIL) { |
| fprintf(stderr, "test_nop_cqe32_no_ring_support failed\n"); |
| return T_EXIT_FAIL; |
| } |
| |
| /* New ring for combined test since we need fresh file/buffer tables */ |
| ret = io_uring_queue_init(8, &ring, 0); |
| if (ret) { |
| fprintf(stderr, "ring setup failed: %d\n", ret); |
| return T_EXIT_FAIL; |
| } |
| |
| ret = test_nop_combined(&ring); |
| if (ret == T_EXIT_FAIL) { |
| fprintf(stderr, "test_nop_combined failed\n"); |
| return T_EXIT_FAIL; |
| } |
| |
| io_uring_queue_exit(&ring); |
| return T_EXIT_PASS; |
| } |