aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/liburing/test/fd-install.c
diff options
context:
space:
mode:
authorthegeorg <thegeorg@yandex-team.com>2024-06-09 11:55:21 +0300
committerthegeorg <thegeorg@yandex-team.com>2024-06-09 12:07:55 +0300
commitafd4899380eea1c70e2a68714b5da1c9919ccdbd (patch)
treecd5120708784139bc6a0f8881da1ed8389a065b3 /contrib/libs/liburing/test/fd-install.c
parenta83bd2dd3c21e38c6c0807ec5e679497ab567f24 (diff)
downloadydb-afd4899380eea1c70e2a68714b5da1c9919ccdbd.tar.gz
Update contrib/libs/liburing to 2.6
3b51a9fb14de805208d11f1c077c78bb5d487e0f
Diffstat (limited to 'contrib/libs/liburing/test/fd-install.c')
-rw-r--r--contrib/libs/liburing/test/fd-install.c501
1 files changed, 501 insertions, 0 deletions
diff --git a/contrib/libs/liburing/test/fd-install.c b/contrib/libs/liburing/test/fd-install.c
new file mode 100644
index 0000000000..222eb1de03
--- /dev/null
+++ b/contrib/libs/liburing/test/fd-install.c
@@ -0,0 +1,501 @@
+#include "../config-host.h"
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: test installing a direct descriptor into the regular
+ * file table
+ *
+ */
+#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_fd_install;
+
+/* test that O_CLOEXEC is accepted, and others are not */
+static int test_flags(struct io_uring *ring, int async)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ int ret, fds[2], fd;
+
+ if (pipe(fds) < 0) {
+ perror("pipe");
+ return T_EXIT_FAIL;
+ }
+
+ ret = io_uring_register_files(ring, &fds[0], 1);
+ if (ret) {
+ fprintf(stderr, "failed register files %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ /* check that setting an invalid flag fails */
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_fixed_fd_install(sqe, 0, 1U << 17);
+ io_uring_submit(ring);
+
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait cqe %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ if (cqe->res != -EINVAL) {
+ fprintf(stderr, "unexpected cqe res %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ io_uring_cqe_seen(ring, cqe);
+
+ /* check that IORING_FIXED_FD_NO_CLOEXEC is accepted */
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_fixed_fd_install(sqe, 0, IORING_FIXED_FD_NO_CLOEXEC);
+ if (async)
+ sqe->flags |= IOSQE_ASYNC;
+ io_uring_submit(ring);
+
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait cqe %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ if (cqe->res < 0) {
+ fprintf(stderr, "unexpected cqe res %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ fd = cqe->res;
+ io_uring_cqe_seen(ring, cqe);
+
+ close(fds[0]);
+ close(fds[1]);
+ close(fd);
+ io_uring_unregister_files(ring);
+
+ return T_EXIT_PASS;
+}
+
+static int test_linked(struct io_uring *ring)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ int ret, fds[2], fd, i;
+
+ if (pipe(fds) < 0) {
+ perror("pipe");
+ return T_EXIT_FAIL;
+ }
+
+ ret = io_uring_register_files(ring, &fds[0], 1);
+ if (ret) {
+ fprintf(stderr, "failed register files %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_nop(sqe);
+ sqe->flags |= IOSQE_IO_LINK;
+ sqe->user_data = 1;
+
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_fixed_fd_install(sqe, 0, 0);
+ sqe->user_data = 2;
+
+ ret = io_uring_submit(ring);
+ if (ret != 2) {
+ fprintf(stderr, "submit: %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ fd = -1;
+ for (i = 0; i < 2; i++) {
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait cqe %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ if (cqe->res < 0) {
+ fprintf(stderr, "unexpected cqe res %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ if (cqe->user_data == 2)
+ fd = cqe->res;
+ io_uring_cqe_seen(ring, cqe);
+ }
+
+ close(fds[0]);
+ close(fds[1]);
+ if (fd != -1)
+ close(fd);
+ io_uring_unregister_files(ring);
+ return T_EXIT_PASS;
+}
+
+/* test not setting IOSQE_FIXED_FILE */
+static int test_not_fixed(struct io_uring *ring)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ int ret, fds[2];
+
+ if (pipe(fds) < 0) {
+ perror("pipe");
+ return T_EXIT_FAIL;
+ }
+
+ ret = io_uring_register_files(ring, &fds[0], 1);
+ if (ret) {
+ fprintf(stderr, "failed register files %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_fixed_fd_install(sqe, 0, 0);
+ sqe->flags &= ~IOSQE_FIXED_FILE;
+ io_uring_submit(ring);
+
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait cqe %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ if (cqe->res != -EBADF) {
+ fprintf(stderr, "unexpected cqe res %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+
+ io_uring_cqe_seen(ring, cqe);
+
+ close(fds[0]);
+ close(fds[1]);
+ io_uring_unregister_files(ring);
+
+ return T_EXIT_PASS;
+}
+
+/* test invalid direct descriptor indexes */
+static int test_bad_fd(struct io_uring *ring, int some_fd)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ int ret;
+
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_fixed_fd_install(sqe, some_fd, 0);
+ io_uring_submit(ring);
+
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait cqe %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ if (cqe->res != -EBADF) {
+ fprintf(stderr, "unexpected cqe res %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+
+ io_uring_cqe_seen(ring, cqe);
+ return T_EXIT_PASS;
+}
+
+/* test basic functionality of shifting a direct descriptor to a normal file */
+static int test_working(struct io_uring *ring)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ int ret, fds[2];
+ char buf[32];
+
+ if (pipe(fds) < 0) {
+ perror("pipe");
+ return T_EXIT_FAIL;
+ }
+
+ /* register read side */
+ ret = io_uring_register_files(ring, &fds[0], 1);
+ if (ret) {
+ fprintf(stderr, "failed register files %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ /* close normal descriptor */
+ close(fds[0]);
+
+ /* normal read should fail */
+ ret = read(fds[0], buf, 1);
+ if (ret != -1) {
+ fprintf(stderr, "unexpected read ret %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ if (errno != EBADF) {
+ fprintf(stderr, "unexpected read failure %d\n", errno);
+ return T_EXIT_FAIL;
+ }
+
+ /* verify we can read the data */
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_read(sqe, 0, buf, sizeof(buf), 0);
+ sqe->flags |= IOSQE_FIXED_FILE;
+ io_uring_submit(ring);
+
+ /* put some data in the pipe */
+ ret = write(fds[1], "Hello", 5);
+ if (ret < 0) {
+ perror("write");
+ return T_EXIT_FAIL;
+ } else if (ret != 5) {
+ fprintf(stderr, "short write %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait cqe %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ if (cqe->res != 5) {
+ fprintf(stderr, "weird pipe read ret %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ io_uring_cqe_seen(ring, cqe);
+
+ /* fixed pipe read worked, now re-install as a regular fd */
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_fixed_fd_install(sqe, 0, 0);
+ io_uring_submit(ring);
+
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait cqe %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ if (cqe->res == -EINVAL) {
+ no_fd_install = 1;
+ return T_EXIT_SKIP;
+ }
+ if (cqe->res < 0) {
+ fprintf(stderr, "failed install fd: %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ /* stash new pipe read side fd in old spot */
+ fds[0] = cqe->res;
+ io_uring_cqe_seen(ring, cqe);
+
+ ret = write(fds[1], "Hello", 5);
+ if (ret < 0) {
+ perror("write");
+ return T_EXIT_FAIL;
+ } else if (ret != 5) {
+ fprintf(stderr, "short write %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ /* normal pipe read should now work with new fd */
+ ret = read(fds[0], buf, sizeof(buf));
+ if (ret != 5) {
+ fprintf(stderr, "unexpected read ret %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ /* close fixed file */
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_close_direct(sqe, 0);
+ io_uring_submit(ring);
+
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait cqe %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ if (cqe->res) {
+ fprintf(stderr, "close fixed fd %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ io_uring_cqe_seen(ring, cqe);
+
+ ret = write(fds[1], "Hello", 5);
+ if (ret < 0) {
+ perror("write");
+ return T_EXIT_FAIL;
+ } else if (ret != 5) {
+ fprintf(stderr, "short write %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ /* normal pipe read should still work with new fd */
+ ret = read(fds[0], buf, sizeof(buf));
+ if (ret != 5) {
+ fprintf(stderr, "unexpected read ret %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ /* fixed fd pipe read should now fail */
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_read(sqe, 0, buf, sizeof(buf), 0);
+ sqe->flags = IOSQE_FIXED_FILE;
+ io_uring_submit(ring);
+
+ /* put some data in the pipe */
+ ret = write(fds[1], "Hello", 5);
+ if (ret < 0) {
+ perror("write");
+ return T_EXIT_FAIL;
+ } else if (ret != 5) {
+ fprintf(stderr, "short write %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait cqe %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ if (cqe->res != -EBADF) {
+ fprintf(stderr, "weird pipe read ret %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ io_uring_cqe_seen(ring, cqe);
+
+ close(fds[0]);
+ close(fds[1]);
+ io_uring_unregister_files(ring);
+ return T_EXIT_PASS;
+}
+
+static int test_creds(struct io_uring *ring, int async)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ int cred_id, ret, fds[2];
+
+ if (pipe(fds) < 0) {
+ perror("pipe");
+ return T_EXIT_FAIL;
+ }
+
+ ret = io_uring_register_files(ring, &fds[0], 1);
+ if (ret) {
+ fprintf(stderr, "failed register files %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ cred_id = io_uring_register_personality(ring);
+ if (cred_id < 0) {
+ fprintf(stderr, "Failed registering creds: %d\n", cred_id);
+ return T_EXIT_FAIL;
+ }
+
+ /* check that asking for creds fails */
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_fixed_fd_install(sqe, 0, 0);
+ if (async)
+ sqe->flags |= IOSQE_ASYNC;
+ sqe->personality = cred_id;
+ io_uring_submit(ring);
+
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait cqe %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ if (cqe->res > 0) {
+ fprintf(stderr, "install succeeded with creds\n");
+ return T_EXIT_FAIL;
+ }
+ if (cqe->res != -EPERM) {
+ fprintf(stderr, "unexpected cqe res %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ io_uring_cqe_seen(ring, cqe);
+
+ close(fds[0]);
+ close(fds[1]);
+ io_uring_unregister_files(ring);
+ io_uring_unregister_personality(ring, cred_id);
+ return T_EXIT_PASS;
+}
+
+int main(int argc, char *argv[])
+{
+ struct io_uring ring;
+ int ret;
+
+ if (argc > 1)
+ return T_EXIT_SKIP;
+
+ ret = io_uring_queue_init(4, &ring, 0);
+ if (ret) {
+ fprintf(stderr, "ring setup failed: %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ ret = test_working(&ring);
+ if (ret != T_EXIT_PASS) {
+ if (ret == T_EXIT_FAIL)
+ fprintf(stderr, "test_working failed\n");
+ return ret;
+ }
+ if (no_fd_install)
+ return T_EXIT_SKIP;
+
+ ret = test_bad_fd(&ring, 0);
+ if (ret != T_EXIT_PASS) {
+ if (ret == T_EXIT_FAIL)
+ fprintf(stderr, "test_bad_fd 0 failed\n");
+ return ret;
+ }
+
+ ret = test_bad_fd(&ring, 500);
+ if (ret != T_EXIT_PASS) {
+ if (ret == T_EXIT_FAIL)
+ fprintf(stderr, "test_bad_fd 500 failed\n");
+ return ret;
+ }
+
+ ret = test_not_fixed(&ring);
+ if (ret != T_EXIT_PASS) {
+ if (ret == T_EXIT_FAIL)
+ fprintf(stderr, "test_not_fixed failed\n");
+ return ret;
+ }
+
+ ret = test_flags(&ring, 0);
+ if (ret != T_EXIT_PASS) {
+ if (ret == T_EXIT_FAIL)
+ fprintf(stderr, "test_flags 0 failed\n");
+ return ret;
+ }
+
+ ret = test_flags(&ring, 1);
+ if (ret != T_EXIT_PASS) {
+ if (ret == T_EXIT_FAIL)
+ fprintf(stderr, "test_flags 1 failed\n");
+ return ret;
+ }
+
+ ret = test_creds(&ring, 0);
+ if (ret != T_EXIT_PASS) {
+ if (ret == T_EXIT_FAIL)
+ fprintf(stderr, "test_creds 0 failed\n");
+ return ret;
+ }
+
+ ret = test_creds(&ring, 1);
+ if (ret != T_EXIT_PASS) {
+ if (ret == T_EXIT_FAIL)
+ fprintf(stderr, "test_creds 1 failed\n");
+ return ret;
+ }
+
+ ret = test_linked(&ring);
+ if (ret != T_EXIT_PASS) {
+ if (ret == T_EXIT_FAIL)
+ fprintf(stderr, "test_linked failed\n");
+ return ret;
+ }
+
+ return T_EXIT_PASS;
+}