aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/liburing/test
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
parenta83bd2dd3c21e38c6c0807ec5e679497ab567f24 (diff)
downloadydb-afd4899380eea1c70e2a68714b5da1c9919ccdbd.tar.gz
Update contrib/libs/liburing to 2.6
3b51a9fb14de805208d11f1c077c78bb5d487e0f
Diffstat (limited to 'contrib/libs/liburing/test')
-rw-r--r--contrib/libs/liburing/test/232c93d07b74.c6
-rw-r--r--contrib/libs/liburing/test/a4c0b3decb33.c2
-rw-r--r--contrib/libs/liburing/test/accept-reuse.c2
-rw-r--r--contrib/libs/liburing/test/accept.c23
-rw-r--r--contrib/libs/liburing/test/buf-ring-nommap.c122
-rw-r--r--contrib/libs/liburing/test/buf-ring-nommap.t/ya.make (renamed from contrib/libs/liburing/test/sqpoll-cancel-hang.t/ya.make)2
-rw-r--r--contrib/libs/liburing/test/buf-ring-put.c84
-rw-r--r--contrib/libs/liburing/test/buf-ring-put.t/ya.make33
-rw-r--r--contrib/libs/liburing/test/buf-ring.c49
-rw-r--r--contrib/libs/liburing/test/connect.c57
-rw-r--r--contrib/libs/liburing/test/coredump.c60
-rw-r--r--contrib/libs/liburing/test/coredump.t/ya.make (renamed from contrib/libs/liburing/test/pollfree.t/ya.make)2
-rw-r--r--contrib/libs/liburing/test/defer-tw-timeout.c169
-rw-r--r--contrib/libs/liburing/test/defer-tw-timeout.t/ya.make33
-rw-r--r--contrib/libs/liburing/test/eventfd-reg.c2
-rw-r--r--contrib/libs/liburing/test/fd-install.c501
-rw-r--r--contrib/libs/liburing/test/fd-install.t/ya.make33
-rw-r--r--contrib/libs/liburing/test/file-register.c10
-rw-r--r--contrib/libs/liburing/test/file-verify.c2
-rw-r--r--contrib/libs/liburing/test/fixed-buf-merge.c98
-rw-r--r--contrib/libs/liburing/test/fixed-buf-merge.t/ya.make33
-rw-r--r--contrib/libs/liburing/test/futex.c572
-rw-r--r--contrib/libs/liburing/test/futex.t/ya.make33
-rw-r--r--contrib/libs/liburing/test/hardlink.c108
-rw-r--r--contrib/libs/liburing/test/helpers.c24
-rw-r--r--contrib/libs/liburing/test/helpers.h10
-rw-r--r--contrib/libs/liburing/test/io_uring_enter.c7
-rw-r--r--contrib/libs/liburing/test/io_uring_register.c51
-rw-r--r--contrib/libs/liburing/test/io_uring_setup.c2
-rw-r--r--contrib/libs/liburing/test/msg-ring-fd.c319
-rw-r--r--contrib/libs/liburing/test/msg-ring-fd.t/ya.make33
-rw-r--r--contrib/libs/liburing/test/msg-ring-flags.c32
-rw-r--r--contrib/libs/liburing/test/msg-ring.c52
-rw-r--r--contrib/libs/liburing/test/multicqes_drain.c2
-rw-r--r--contrib/libs/liburing/test/no-mmap-inval.c43
-rw-r--r--contrib/libs/liburing/test/no-mmap-inval.t/ya.make33
-rw-r--r--contrib/libs/liburing/test/nolibc.c8
-rw-r--r--contrib/libs/liburing/test/openat2.c6
-rw-r--r--contrib/libs/liburing/test/poll-cancel-all.c34
-rw-r--r--contrib/libs/liburing/test/pollfree.c427
-rw-r--r--contrib/libs/liburing/test/read-mshot-empty.c154
-rw-r--r--contrib/libs/liburing/test/read-mshot-empty.t/ya.make33
-rw-r--r--contrib/libs/liburing/test/read-mshot.c405
-rw-r--r--contrib/libs/liburing/test/read-mshot.t/ya.make33
-rw-r--r--contrib/libs/liburing/test/recv-multishot.c10
-rw-r--r--contrib/libs/liburing/test/reg-fd-only.c132
-rw-r--r--contrib/libs/liburing/test/reg-fd-only.t/ya.make33
-rw-r--r--contrib/libs/liburing/test/ring-leak.c24
-rw-r--r--contrib/libs/liburing/test/ringbuf-status.c243
-rw-r--r--contrib/libs/liburing/test/ringbuf-status.t/ya.make33
-rw-r--r--contrib/libs/liburing/test/send-zerocopy.c336
-rw-r--r--contrib/libs/liburing/test/send_recv.c7
-rw-r--r--contrib/libs/liburing/test/shutdown.c3
-rw-r--r--contrib/libs/liburing/test/socket-getsetsock-cmd.c333
-rw-r--r--contrib/libs/liburing/test/socket-getsetsock-cmd.t/ya.make33
-rw-r--r--contrib/libs/liburing/test/socket-io-cmd.c238
-rw-r--r--contrib/libs/liburing/test/socket-io-cmd.t/ya.make33
-rw-r--r--contrib/libs/liburing/test/socket-rw-eagain.c3
-rw-r--r--contrib/libs/liburing/test/socket-rw-offset.c3
-rw-r--r--contrib/libs/liburing/test/socket-rw.c3
-rw-r--r--contrib/libs/liburing/test/sqpoll-cancel-hang.c169
-rw-r--r--contrib/libs/liburing/test/truncate.c187
-rw-r--r--contrib/libs/liburing/test/truncate.t/ya.make33
-rw-r--r--contrib/libs/liburing/test/version.c4
-rw-r--r--contrib/libs/liburing/test/waitid.c374
-rw-r--r--contrib/libs/liburing/test/waitid.t/ya.make33
-rw-r--r--contrib/libs/liburing/test/wq-aff.c147
-rw-r--r--contrib/libs/liburing/test/wq-aff.t/ya.make33
-rw-r--r--contrib/libs/liburing/test/xattr.c63
69 files changed, 5360 insertions, 894 deletions
diff --git a/contrib/libs/liburing/test/232c93d07b74.c b/contrib/libs/liburing/test/232c93d07b74.c
index a89e7aebbf..27ed403eec 100644
--- a/contrib/libs/liburing/test/232c93d07b74.c
+++ b/contrib/libs/liburing/test/232c93d07b74.c
@@ -65,8 +65,7 @@ static void *rcv(void *arg)
int res;
if (p->tcp) {
- int val = 1;
-
+ int ret, val = 1;
s0 = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
res = setsockopt(s0, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));
@@ -78,7 +77,8 @@ static void *rcv(void *arg)
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
- assert(t_bind_ephemeral_port(s0, &addr) == 0);
+ ret = t_bind_ephemeral_port(s0, &addr);
+ assert(!ret);
p->bind_port = addr.sin_port;
} else {
s0 = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
diff --git a/contrib/libs/liburing/test/a4c0b3decb33.c b/contrib/libs/liburing/test/a4c0b3decb33.c
index 89a750a471..0e77ba8ee7 100644
--- a/contrib/libs/liburing/test/a4c0b3decb33.c
+++ b/contrib/libs/liburing/test/a4c0b3decb33.c
@@ -110,7 +110,7 @@ static void execute_one(void);
static void loop(void)
{
int iter;
- for (iter = 0; iter < 5000; iter++) {
+ for (iter = 0; iter < 50; iter++) {
int pid = fork();
if (pid < 0)
exit(1);
diff --git a/contrib/libs/liburing/test/accept-reuse.c b/contrib/libs/liburing/test/accept-reuse.c
index 47c1b1361f..f1a42b792d 100644
--- a/contrib/libs/liburing/test/accept-reuse.c
+++ b/contrib/libs/liburing/test/accept-reuse.c
@@ -46,7 +46,7 @@ int main(int argc, char **argv)
return T_EXIT_SKIP;
memset(&params, 0, sizeof(params));
- ret = io_uring_queue_init_params(4, &io_uring, &params);
+ ret = t_io_uring_init_sqarray(4, &io_uring, &params);
if (ret) {
fprintf(stderr, "io_uring_init_failed: %d\n", ret);
return T_EXIT_FAIL;
diff --git a/contrib/libs/liburing/test/accept.c b/contrib/libs/liburing/test/accept.c
index df23eab53f..2208a54708 100644
--- a/contrib/libs/liburing/test/accept.c
+++ b/contrib/libs/liburing/test/accept.c
@@ -196,7 +196,8 @@ static int start_accept_listen(struct sockaddr_in *addr, int port_off,
addr->sin_family = AF_INET;
addr->sin_addr.s_addr = inet_addr("127.0.0.1");
- assert(!t_bind_ephemeral_port(fd, addr));
+ ret = t_bind_ephemeral_port(fd, addr);
+ assert(!ret);
ret = listen(fd, 128);
assert(ret != -1);
@@ -311,6 +312,9 @@ static int test_loop(struct io_uring *ring,
multishot ? "Multishot" : "",
i, s_fd[i]);
goto err;
+ } else if (s_fd[i] == 195 && args.overflow) {
+ fprintf(stderr, "Broken overflow handling\n");
+ goto err;
}
if (multishot && fixed) {
@@ -555,6 +559,9 @@ static int test_accept_cancel(unsigned usecs, unsigned int nr, bool multishot)
fprintf(stderr, "unexpected 0 user data\n");
goto err;
} else if (cqe->user_data <= nr) {
+ /* no multishot */
+ if (cqe->res == -EINVAL)
+ return T_EXIT_SKIP;
if (cqe->res != -EINTR && cqe->res != -ECANCELED) {
fprintf(stderr, "Cancelled accept got %d\n", cqe->res);
goto err;
@@ -679,7 +686,12 @@ static int test_accept_fixed(void)
ret = io_uring_queue_init(32, &m_io_uring, 0);
assert(ret >= 0);
ret = io_uring_register_files(&m_io_uring, &fd, 1);
- assert(ret == 0);
+ if (ret) {
+ /* kernel doesn't support sparse registered files, skip */
+ if (ret == -EBADF || ret == -EINVAL)
+ return T_EXIT_SKIP;
+ return T_EXIT_FAIL;
+ }
ret = test(&m_io_uring, args);
io_uring_queue_exit(&m_io_uring);
return ret;
@@ -701,7 +713,12 @@ static int test_multishot_fixed_accept(void)
ret = io_uring_queue_init(MAX_FDS + 10, &m_io_uring, 0);
assert(ret >= 0);
ret = io_uring_register_files(&m_io_uring, fd, MAX_FDS);
- assert(ret == 0);
+ if (ret) {
+ /* kernel doesn't support sparse registered files, skip */
+ if (ret == -EBADF || ret == -EINVAL)
+ return T_EXIT_SKIP;
+ return T_EXIT_FAIL;
+ }
ret = test(&m_io_uring, args);
io_uring_queue_exit(&m_io_uring);
return ret;
diff --git a/contrib/libs/liburing/test/buf-ring-nommap.c b/contrib/libs/liburing/test/buf-ring-nommap.c
new file mode 100644
index 0000000000..7624c67fa0
--- /dev/null
+++ b/contrib/libs/liburing/test/buf-ring-nommap.c
@@ -0,0 +1,122 @@
+#include "../config-host.h"
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: test IOU_PBUF_RING_MMAP with a ring setup with a ring
+ * setup without mmap'ing sq/cq arrays
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#include "liburing.h"
+#include "helpers.h"
+
+static int bgid = 5;
+static int bid = 89;
+
+int main(int argc, char *argv[])
+{
+ struct io_uring_buf_ring *br;
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ struct io_uring ring;
+ size_t ring_size;
+ int ret, ring_mask, fds[2];
+ struct io_uring_buf_reg reg = {
+ .ring_entries = 1,
+ .bgid = bgid,
+ .flags = IOU_PBUF_RING_MMAP,
+ };
+ struct io_uring_params p = { };
+ void *ring_mem;
+ char buf[32];
+ off_t off;
+
+ if (argc > 1)
+ return T_EXIT_SKIP;
+
+ if (posix_memalign(&ring_mem, 16384, 16384))
+ return T_EXIT_FAIL;
+
+ p.flags = IORING_SETUP_NO_MMAP;
+ ret = io_uring_queue_init_mem(1, &ring, &p, ring_mem, 16384);
+ if (ret < 0) {
+ if (ret == -EINVAL)
+ return T_EXIT_SKIP;
+ fprintf(stderr, "queue init failed %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ if (pipe(fds) < 0) {
+ perror("pipe");
+ return T_EXIT_FAIL;
+ }
+
+ ring_size = sizeof(struct io_uring_buf);
+ ring_mask = io_uring_buf_ring_mask(1);
+
+ ret = io_uring_register_buf_ring(&ring, &reg, 0);
+ if (ret) {
+ if (ret == -EINVAL)
+ return T_EXIT_SKIP;
+ fprintf(stderr, "reg buf ring: %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ off = IORING_OFF_PBUF_RING |
+ (unsigned long long) bgid << IORING_OFF_PBUF_SHIFT;
+ br = mmap(NULL, ring_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_POPULATE, ring.ring_fd, off);
+ if (br == MAP_FAILED) {
+ if (errno == ENOMEM)
+ return T_EXIT_SKIP;
+ perror("mmap");
+ return T_EXIT_FAIL;
+ }
+
+ io_uring_buf_ring_add(br, buf, sizeof(buf), bid, ring_mask, 0);
+ io_uring_buf_ring_advance(br, 1);
+
+ sqe = io_uring_get_sqe(&ring);
+ io_uring_prep_read(sqe, fds[0], NULL, 0, 0);
+ sqe->flags |= IOSQE_BUFFER_SELECT;
+ sqe->buf_group = bgid;
+
+ io_uring_submit(&ring);
+
+ 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 %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ if (cqe->res < 0) {
+ fprintf(stderr, "cqe res %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ if (!(cqe->flags & IORING_CQE_F_BUFFER)) {
+ fprintf(stderr, "buffer not selected in cqe\n");
+ return T_EXIT_FAIL;
+ }
+ if ((cqe->flags >> IORING_CQE_BUFFER_SHIFT) != bid) {
+ fprintf(stderr, "wrong buffer id returned\n");
+ return T_EXIT_FAIL;
+ }
+
+ io_uring_cqe_seen(&ring, cqe);
+
+ io_uring_queue_exit(&ring);
+ return T_EXIT_PASS;
+}
diff --git a/contrib/libs/liburing/test/sqpoll-cancel-hang.t/ya.make b/contrib/libs/liburing/test/buf-ring-nommap.t/ya.make
index 2ce4882281..1d44c5d29c 100644
--- a/contrib/libs/liburing/test/sqpoll-cancel-hang.t/ya.make
+++ b/contrib/libs/liburing/test/buf-ring-nommap.t/ya.make
@@ -26,8 +26,8 @@ CFLAGS(
SRCDIR(contrib/libs/liburing/test)
SRCS(
+ buf-ring-nommap.c
helpers.c
- sqpoll-cancel-hang.c
)
END()
diff --git a/contrib/libs/liburing/test/buf-ring-put.c b/contrib/libs/liburing/test/buf-ring-put.c
new file mode 100644
index 0000000000..6508f87023
--- /dev/null
+++ b/contrib/libs/liburing/test/buf-ring-put.c
@@ -0,0 +1,84 @@
+#include "../config-host.h"
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: test persistence of mmap'ed provided ring buffers. Use a range
+ * of buffer group IDs that puts us into both the lower end array
+ * and higher end xarry.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#include "liburing.h"
+#include "helpers.h"
+
+#define BGID_START 60
+#define BGID_NR 10
+#define ENTRIES 512
+
+int main(int argc, char *argv[])
+{
+ struct io_uring_buf_ring *br[BGID_NR];
+ struct io_uring ring;
+ size_t ring_size;
+ int ret, i, j;
+
+ if (argc > 1)
+ return T_EXIT_SKIP;
+
+ ret = io_uring_queue_init(1, &ring, 0);
+ if (ret) {
+ fprintf(stderr, "queue init failed %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ ring_size = ENTRIES * sizeof(struct io_uring_buf);
+
+ for (i = 0; i < BGID_NR; i++) {
+ int bgid = BGID_START + i;
+ struct io_uring_buf_reg reg = {
+ .ring_entries = ENTRIES,
+ .bgid = bgid,
+ .flags = IOU_PBUF_RING_MMAP,
+ };
+ off_t off;
+
+ ret = io_uring_register_buf_ring(&ring, &reg, 0);
+ if (ret) {
+ if (ret == -EINVAL)
+ return T_EXIT_SKIP;
+ fprintf(stderr, "reg buf ring: %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ off = IORING_OFF_PBUF_RING |
+ (unsigned long long) bgid << IORING_OFF_PBUF_SHIFT;
+ br[i] = mmap(NULL, ring_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_POPULATE, ring.ring_fd, off);
+ if (br[i] == MAP_FAILED) {
+ perror("mmap");
+ return T_EXIT_FAIL;
+ }
+ }
+
+ for (i = 0; i < BGID_NR; i++) {
+ ret = io_uring_unregister_buf_ring(&ring, BGID_START + i);
+ if (ret) {
+ fprintf(stderr, "reg buf ring: %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ }
+
+ for (j = 0; j < 1000; j++) {
+ for (i = 0; i < BGID_NR; i++)
+ memset(br[i], 0x5a, ring_size);
+ usleep(1000);
+ }
+
+ io_uring_queue_exit(&ring);
+ return T_EXIT_PASS;
+}
diff --git a/contrib/libs/liburing/test/buf-ring-put.t/ya.make b/contrib/libs/liburing/test/buf-ring-put.t/ya.make
new file mode 100644
index 0000000000..12318ed718
--- /dev/null
+++ b/contrib/libs/liburing/test/buf-ring-put.t/ya.make
@@ -0,0 +1,33 @@
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
+WITHOUT_LICENSE_TEXTS()
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/liburing
+)
+
+ADDINCL(
+ contrib/libs/liburing/src/include
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_RUNTIME()
+
+CFLAGS(
+ -DLIBURING_BUILD_TEST
+ -D__SANE_USERSPACE_TYPES__
+)
+
+SRCDIR(contrib/libs/liburing/test)
+
+SRCS(
+ buf-ring-put.c
+ helpers.c
+)
+
+END()
diff --git a/contrib/libs/liburing/test/buf-ring.c b/contrib/libs/liburing/test/buf-ring.c
index 08f03f99ec..682a97ec28 100644
--- a/contrib/libs/liburing/test/buf-ring.c
+++ b/contrib/libs/liburing/test/buf-ring.c
@@ -293,7 +293,7 @@ static int test_one_read(int fd, int bgid, struct io_uring *ring)
return cqe->flags >> 16;
}
-static int test_running(int bgid, int entries, int loops)
+static int test_running(int bgid, int entries, int loops, int use_mmap)
{
int ring_mask = io_uring_buf_ring_mask(entries);
struct io_uring_buf_ring *br;
@@ -308,11 +308,37 @@ static int test_running(int bgid, int entries, int loops)
else if (ret != T_SETUP_OK)
return 1;
- br = io_uring_setup_buf_ring(&ring, entries, bgid, 0, &ret);
- if (!br) {
- /* by now should have checked if this is supported or not */
- fprintf(stderr, "Buffer ring register failed %d\n", ret);
- return 1;
+ if (!use_mmap) {
+ br = io_uring_setup_buf_ring(&ring, entries, bgid, 0, &ret);
+ if (!br) {
+ /* by now should have checked if this is supported or not */
+ fprintf(stderr, "Buffer ring register failed %d\n", ret);
+ return 1;
+ }
+ } else {
+ struct io_uring_buf_reg reg = {
+ .ring_entries = entries,
+ .bgid = bgid,
+ .flags = IOU_PBUF_RING_MMAP,
+ };
+ size_t ring_size;
+ off_t off;
+
+ ret = io_uring_register_buf_ring(&ring, &reg, 0);
+ if (ret) {
+ fprintf(stderr, "mmap ring register failed %d\n", ret);
+ return 1;
+ }
+
+ off = IORING_OFF_PBUF_RING |
+ (unsigned long long) bgid << IORING_OFF_PBUF_SHIFT;
+ ring_size = sizeof(struct io_uring_buf) * entries;
+ br = mmap(NULL, ring_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_POPULATE, ring.ring_fd, off);
+ if (br == MAP_FAILED) {
+ perror("mmap");
+ return 1;
+ }
}
buffers = malloc(sizeof(bool) * entries);
@@ -424,12 +450,21 @@ int main(int argc, char *argv[])
}
for (i = 0; !no_buf_ring && entries[i] != -1; i++) {
- ret = test_running(2, entries[i], 3);
+ ret = test_running(2, entries[i], 3, 0);
if (ret) {
fprintf(stderr, "test_running(%d) failed\n", entries[i]);
return T_EXIT_FAIL;
}
}
+ for (i = 0; !no_buf_ring && entries[i] != -1; i++) {
+ ret = test_running(2, entries[i], 3, 1);
+ if (ret) {
+ fprintf(stderr, "test_running(%d) mmap failed\n", entries[i]);
+ return T_EXIT_FAIL;
+ }
+ }
+
+
return T_EXIT_PASS;
}
diff --git a/contrib/libs/liburing/test/connect.c b/contrib/libs/liburing/test/connect.c
index f1b7d941f4..cabf3599eb 100644
--- a/contrib/libs/liburing/test/connect.c
+++ b/contrib/libs/liburing/test/connect.c
@@ -134,7 +134,7 @@ static int configure_connect(int fd, struct sockaddr_in* addr)
return ret;
}
-static int connect_socket(struct io_uring *ring, int fd, int *code)
+static int connect_socket(struct io_uring *ring, int fd, int *code, int async)
{
struct sockaddr_in addr;
int ret, res;
@@ -151,6 +151,8 @@ static int connect_socket(struct io_uring *ring, int fd, int *code)
}
io_uring_prep_connect(sqe, fd, (struct sockaddr*)&addr, sizeof(addr));
+ if (async)
+ sqe->flags |= IOSQE_ASYNC;
sqe->user_data = 1;
ret = submit_and_wait(ring, &res);
@@ -187,7 +189,7 @@ static int test_connect_with_no_peer(struct io_uring *ring)
if (connect_fd == -1)
return -1;
- ret = connect_socket(ring, connect_fd, &code);
+ ret = connect_socket(ring, connect_fd, &code, 0);
if (ret == -1)
goto err;
@@ -210,7 +212,7 @@ err:
return -1;
}
-static int test_connect(struct io_uring *ring)
+static int test_connect(struct io_uring *ring, int async)
{
int accept_fd;
int connect_fd;
@@ -228,7 +230,7 @@ static int test_connect(struct io_uring *ring)
if (connect_fd == -1)
goto err1;
- ret = connect_socket(ring, connect_fd, &code);
+ ret = connect_socket(ring, connect_fd, &code, async);
if (ret == -1)
goto err2;
@@ -297,7 +299,7 @@ static int test_connect_timeout(struct io_uring *ring)
}
// We first connect with one client socket in order to fill the accept queue.
- ret = connect_socket(ring, connect_fd[0], &code);
+ ret = connect_socket(ring, connect_fd[0], &code, 0);
if (ret == -1 || code != 0) {
fprintf(stderr, "unable to connect\n");
goto err;
@@ -364,15 +366,12 @@ err:
return -1;
}
-int main(int argc, char *argv[])
+static int test(int flags)
{
struct io_uring ring;
int ret;
- if (argc > 1)
- return T_EXIT_SKIP;
-
- ret = io_uring_queue_init(8, &ring, 0);
+ ret = io_uring_queue_init(8, &ring, flags);
if (ret) {
fprintf(stderr, "io_uring_queue_setup() = %d\n", ret);
return T_EXIT_FAIL;
@@ -391,7 +390,13 @@ int main(int argc, char *argv[])
if (no_connect)
return T_EXIT_SKIP;
- ret = test_connect(&ring);
+ ret = test_connect(&ring, 0);
+ if (ret == -1) {
+ fprintf(stderr, "test_connect(): failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test_connect(&ring, 1);
if (ret == -1) {
fprintf(stderr, "test_connect(): failed\n");
return T_EXIT_FAIL;
@@ -406,3 +411,33 @@ int main(int argc, char *argv[])
io_uring_queue_exit(&ring);
return T_EXIT_PASS;
}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+
+ if (argc > 1)
+ return T_EXIT_SKIP;
+
+ ret = test(0);
+ if (ret == -1) {
+ fprintf(stderr, "test 0 failed\n");
+ return T_EXIT_FAIL;
+ }
+ if (no_connect)
+ return T_EXIT_SKIP;
+
+ ret = test(IORING_SETUP_SQPOLL);
+ if (ret == -1) {
+ fprintf(stderr, "test SQPOLL failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test(IORING_SETUP_SINGLE_ISSUER|IORING_SETUP_DEFER_TASKRUN);
+ if (ret == -1) {
+ fprintf(stderr, "test DEFER failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ return T_EXIT_PASS;
+}
diff --git a/contrib/libs/liburing/test/coredump.c b/contrib/libs/liburing/test/coredump.c
new file mode 100644
index 0000000000..44e2817897
--- /dev/null
+++ b/contrib/libs/liburing/test/coredump.c
@@ -0,0 +1,60 @@
+#include "../config-host.h"
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: trigger segfault. A recent 6.4-rc kernel introduced a bug
+ * via vhost where segfaults for applications using io_uring
+ * would hang in D state forever upon trying to generate the
+ * core file. Perform a trivial test where a child process
+ * generates a NULL pointer dereference and ensure that we don't
+ * hang.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include "liburing.h"
+#include "helpers.h"
+
+static void test(void)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring ring;
+ int *ptr = NULL;
+ int fds[2];
+ char r1;
+
+ if (pipe(fds) < 0) {
+ perror("pipe");
+ exit(0);
+ }
+
+ io_uring_queue_init(8, &ring, 0);
+
+ sqe = io_uring_get_sqe(&ring);
+ io_uring_prep_read(sqe, fds[0], &r1, sizeof(r1), 0);
+ sqe->flags = IOSQE_ASYNC;
+ sqe->user_data = 1;
+
+ io_uring_submit(&ring);
+ *ptr = 0;
+ exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+ pid_t pid;
+ int wstat;
+
+ pid = fork();
+ if (pid < 0) {
+ perror("fork");
+ return T_EXIT_SKIP;
+ } else if (!pid) {
+ test();
+ }
+
+ wait(&wstat);
+ return T_EXIT_PASS;
+}
diff --git a/contrib/libs/liburing/test/pollfree.t/ya.make b/contrib/libs/liburing/test/coredump.t/ya.make
index 10e4570b18..c57a92c1b6 100644
--- a/contrib/libs/liburing/test/pollfree.t/ya.make
+++ b/contrib/libs/liburing/test/coredump.t/ya.make
@@ -26,8 +26,8 @@ CFLAGS(
SRCDIR(contrib/libs/liburing/test)
SRCS(
+ coredump.c
helpers.c
- pollfree.c
)
END()
diff --git a/contrib/libs/liburing/test/defer-tw-timeout.c b/contrib/libs/liburing/test/defer-tw-timeout.c
new file mode 100644
index 0000000000..ea06e19243
--- /dev/null
+++ b/contrib/libs/liburing/test/defer-tw-timeout.c
@@ -0,0 +1,169 @@
+#include "../config-host.h"
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: test waiting for more events than what will be posted with
+ * a timeout with DEFER_TASKRUN. All kernels should time out,
+ * but a non-buggy kernel will end up with one CQE available
+ * for reaping. Buggy kernels will not have processed the
+ * task_work and will have 0 events.
+ *
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+#include "liburing.h"
+#include "helpers.h"
+
+struct d {
+ int fd;
+};
+
+static void *thread_fn(void *data)
+{
+ struct d *d = data;
+ int ret;
+
+ usleep(100000);
+ ret = write(d->fd, "Hello", 5);
+ if (ret < 0)
+ perror("write");
+ return NULL;
+}
+
+static int test_poll(struct io_uring *ring)
+{
+ struct io_uring_cqe *cqe;
+ struct io_uring_sqe *sqe;
+ struct __kernel_timespec ts;
+ int ret, fds[2], i;
+ pthread_t thread;
+ char buf[32];
+ struct d d;
+ void *tret;
+
+ if (pipe(fds) < 0) {
+ perror("pipe");
+ return 1;
+ }
+ d.fd = fds[1];
+
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_read(sqe, fds[0], buf, sizeof(buf), 0);
+
+ pthread_create(&thread, NULL, thread_fn, &d);
+
+ ts.tv_sec = 1;
+ ts.tv_nsec = 0;
+
+ ret = io_uring_submit_and_wait_timeout(ring, &cqe, 2, &ts, NULL);
+ if (ret != 1) {
+ fprintf(stderr, "unexpected wait ret %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ for (i = 0; i < 2; i++) {
+ ret = io_uring_peek_cqe(ring, &cqe);
+ if (ret)
+ break;
+ io_uring_cqe_seen(ring, cqe);
+ }
+
+ if (i != 1) {
+ fprintf(stderr, "Got %d request, expected 1\n", i);
+ return T_EXIT_FAIL;
+ }
+
+ pthread_join(thread, &tret);
+ return T_EXIT_PASS;
+}
+
+static int test_file(struct io_uring *ring, char *__fname)
+{
+ struct io_uring_cqe *cqe;
+ struct io_uring_sqe *sqe;
+ struct __kernel_timespec ts;
+ char filename[64], *fname;
+ int fd, ret, i;
+ void *buf;
+
+ if (!__fname) {
+ fname = filename;
+ sprintf(fname, ".defer-tw-timeout.%d", getpid());
+ t_create_file(fname, 128*1024);
+ } else {
+ fname = __fname;
+ }
+
+ fd = open(fname, O_RDONLY | O_DIRECT);
+ if (fd < 0) {
+ perror("open");
+ if (!__fname)
+ unlink(fname);
+ return T_EXIT_FAIL;
+ }
+
+ if (!__fname)
+ unlink(fname);
+
+ if (posix_memalign(&buf, 4096, 4096)) {
+ close(fd);
+ return T_EXIT_FAIL;
+ }
+
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_read(sqe, fd, buf, 4096, 0);
+
+ ts.tv_sec = 1;
+ ts.tv_nsec = 0;
+
+ ret = io_uring_submit_and_wait_timeout(ring, &cqe, 2, &ts, NULL);
+ if (ret != 1) {
+ fprintf(stderr, "unexpected wait ret %d\n", ret);
+ close(fd);
+ return T_EXIT_FAIL;
+ }
+
+ for (i = 0; i < 2; i++) {
+ ret = io_uring_peek_cqe(ring, &cqe);
+ if (ret)
+ break;
+ io_uring_cqe_seen(ring, cqe);
+ }
+
+ if (i != 1) {
+ fprintf(stderr, "Got %d request, expected 1\n", i);
+ close(fd);
+ return T_EXIT_FAIL;
+ }
+
+ close(fd);
+ return T_EXIT_PASS;
+}
+
+int main(int argc, char *argv[])
+{
+ struct io_uring ring;
+ char *fname = NULL;
+ int ret;
+
+ ret = io_uring_queue_init(8, &ring, IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN);
+ if (ret == -EINVAL)
+ return T_EXIT_SKIP;
+
+ if (argc > 1)
+ fname = argv[1];
+
+ ret = test_file(&ring, fname);
+ if (ret != T_EXIT_PASS)
+ return ret;
+
+ ret = test_poll(&ring);
+ if (ret != T_EXIT_PASS)
+ return ret;
+
+ return T_EXIT_PASS;
+}
diff --git a/contrib/libs/liburing/test/defer-tw-timeout.t/ya.make b/contrib/libs/liburing/test/defer-tw-timeout.t/ya.make
new file mode 100644
index 0000000000..f742bd6e16
--- /dev/null
+++ b/contrib/libs/liburing/test/defer-tw-timeout.t/ya.make
@@ -0,0 +1,33 @@
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
+WITHOUT_LICENSE_TEXTS()
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/liburing
+)
+
+ADDINCL(
+ contrib/libs/liburing/src/include
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_RUNTIME()
+
+CFLAGS(
+ -DLIBURING_BUILD_TEST
+ -D__SANE_USERSPACE_TYPES__
+)
+
+SRCDIR(contrib/libs/liburing/test)
+
+SRCS(
+ defer-tw-timeout.c
+ helpers.c
+)
+
+END()
diff --git a/contrib/libs/liburing/test/eventfd-reg.c b/contrib/libs/liburing/test/eventfd-reg.c
index a1655267ab..b1efb17383 100644
--- a/contrib/libs/liburing/test/eventfd-reg.c
+++ b/contrib/libs/liburing/test/eventfd-reg.c
@@ -44,7 +44,7 @@ int main(int argc, char *argv[])
return T_EXIT_FAIL;
}
- /* Check that registrering again will get -EBUSY */
+ /* Check that registering again will get -EBUSY */
ret = io_uring_register_eventfd(&ring, evfd[1]);
if (ret != -EBUSY) {
fprintf(stderr, "unexpected 2nd register: %d\n", ret);
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;
+}
diff --git a/contrib/libs/liburing/test/fd-install.t/ya.make b/contrib/libs/liburing/test/fd-install.t/ya.make
new file mode 100644
index 0000000000..0f41ccec34
--- /dev/null
+++ b/contrib/libs/liburing/test/fd-install.t/ya.make
@@ -0,0 +1,33 @@
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
+WITHOUT_LICENSE_TEXTS()
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/liburing
+)
+
+ADDINCL(
+ contrib/libs/liburing/src/include
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_RUNTIME()
+
+CFLAGS(
+ -DLIBURING_BUILD_TEST
+ -D__SANE_USERSPACE_TYPES__
+)
+
+SRCDIR(contrib/libs/liburing/test)
+
+SRCS(
+ fd-install.c
+ helpers.c
+)
+
+END()
diff --git a/contrib/libs/liburing/test/file-register.c b/contrib/libs/liburing/test/file-register.c
index ee30b3e4f8..ce51022632 100644
--- a/contrib/libs/liburing/test/file-register.c
+++ b/contrib/libs/liburing/test/file-register.c
@@ -306,7 +306,7 @@ static int test_sparse(struct io_uring *ring)
files = open_files(100, 100, 0);
ret = io_uring_register_files(ring, files, 200);
if (ret) {
- if (ret == -EBADF) {
+ if (ret == -EBADF || ret == -EINVAL) {
fprintf(stdout, "Sparse files not supported, skipping\n");
no_update = 1;
goto done;
@@ -353,10 +353,14 @@ err:
static int test_basic(struct io_uring *ring, int fail)
{
int *files;
- int ret;
+ int ret, i;
int nr_files = fail ? 10 : 100;
- files = open_files(nr_files, 0, 0);
+ files = open_files(nr_files, fail ? 90 : 0, 0);
+ if (fail) {
+ for (i = nr_files; i < nr_files + 90; i++)
+ files[i] = -2;
+ }
ret = io_uring_register_files(ring, files, 100);
if (ret) {
if (fail) {
diff --git a/contrib/libs/liburing/test/file-verify.c b/contrib/libs/liburing/test/file-verify.c
index fd192ec272..0014236f5c 100644
--- a/contrib/libs/liburing/test/file-verify.c
+++ b/contrib/libs/liburing/test/file-verify.c
@@ -29,7 +29,7 @@
#define MAX_VECS 16
/*
- * Can be anything, let's just do something for a bit of parallellism
+ * Can be anything, let's just do something for a bit of parallelism
*/
#define READ_BATCH 16
diff --git a/contrib/libs/liburing/test/fixed-buf-merge.c b/contrib/libs/liburing/test/fixed-buf-merge.c
new file mode 100644
index 0000000000..e75948fa79
--- /dev/null
+++ b/contrib/libs/liburing/test/fixed-buf-merge.c
@@ -0,0 +1,98 @@
+#include "../config-host.h"
+/* SPDX-License-Identifier: MIT */
+/*
+ * Test fixed buffer merging/skipping
+ *
+ * Taken from: https://github.com/axboe/liburing/issues/994
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "liburing.h"
+#include "helpers.h"
+
+int main(int argc, char *argv[])
+{
+ int ret, i, fd, initial_offset = 4096, num_requests = 3;
+ struct io_uring ring;
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ struct iovec iov;
+ char *buffer, *to_free;
+ unsigned head;
+ char filename[64];
+
+ ret = io_uring_queue_init(4, &ring, 0);
+ if (ret) {
+ fprintf(stderr, "queue_init: %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ sprintf(filename, ".fixed-buf-%d", getpid());
+ t_create_file(filename, 4 * 4096);
+
+ fd = open(filename, O_RDONLY | O_DIRECT, 0644);
+ if (fd < 0) {
+ perror("open");
+ goto err_unlink;
+ }
+
+ to_free = buffer = aligned_alloc(4096, 128 * 4096);
+ if (!buffer) {
+ perror("aligned_alloc");
+ goto err_unlink;
+ }
+
+ /* Register buffer */
+ iov.iov_base = buffer;
+ iov.iov_len = 128 * 4096;
+
+ ret = io_uring_register_buffers(&ring, &iov, 1);
+ if (ret) {
+ fprintf(stderr, "buf register: %d\n", ret);
+ goto err_unlink;
+ }
+
+ /* Prepare read requests */
+ buffer += initial_offset;
+ for (i = 0; i < num_requests; i++) {
+ sqe = io_uring_get_sqe(&ring);
+ io_uring_prep_read_fixed(sqe, fd, buffer, 4096, 4096 * i, 0);
+ buffer += 4096;
+ }
+
+ /* Submit requests and reap completions */
+ ret = io_uring_submit_and_wait(&ring, num_requests);
+ if (ret != num_requests) {
+ fprintf(stderr, "Submit and wait: %d\n", ret);
+ goto err_unlink;
+ }
+
+ i = 0;
+ io_uring_for_each_cqe(&ring, head, cqe) {
+ if (cqe->res != 4096) {
+ fprintf(stderr, "cqe: %d\n", cqe->res);
+ goto err_unlink;
+ }
+ i++;
+ }
+
+ if (i != num_requests) {
+ fprintf(stderr, "Got %d completions\n", i);
+ goto err_unlink;
+ }
+
+ io_uring_cq_advance(&ring, i);
+ io_uring_queue_exit(&ring);
+ close(fd);
+ free(to_free);
+ unlink(filename);
+ return T_EXIT_PASS;
+err_unlink:
+ unlink(filename);
+ return T_EXIT_FAIL;
+}
diff --git a/contrib/libs/liburing/test/fixed-buf-merge.t/ya.make b/contrib/libs/liburing/test/fixed-buf-merge.t/ya.make
new file mode 100644
index 0000000000..c988deecdb
--- /dev/null
+++ b/contrib/libs/liburing/test/fixed-buf-merge.t/ya.make
@@ -0,0 +1,33 @@
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
+WITHOUT_LICENSE_TEXTS()
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/liburing
+)
+
+ADDINCL(
+ contrib/libs/liburing/src/include
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_RUNTIME()
+
+CFLAGS(
+ -DLIBURING_BUILD_TEST
+ -D__SANE_USERSPACE_TYPES__
+)
+
+SRCDIR(contrib/libs/liburing/test)
+
+SRCS(
+ fixed-buf-merge.c
+ helpers.c
+)
+
+END()
diff --git a/contrib/libs/liburing/test/futex.c b/contrib/libs/liburing/test/futex.c
new file mode 100644
index 0000000000..7a7f0c235c
--- /dev/null
+++ b/contrib/libs/liburing/test/futex.c
@@ -0,0 +1,572 @@
+#include "../config-host.h"
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: exercise futex wait/wake/waitv
+ *
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <errno.h>
+#include <linux/futex.h>
+
+#include "liburing.h"
+#include "helpers.h"
+
+#define LOOPS 500
+#define NFUTEX 8
+
+#ifndef FUTEX2_SIZE_U8
+#define FUTEX2_SIZE_U8 0x00
+#define FUTEX2_SIZE_U16 0x01
+#define FUTEX2_SIZE_U32 0x02
+#define FUTEX2_SIZE_U64 0x03
+#define FUTEX2_NUMA 0x04
+ /* 0x08 */
+ /* 0x10 */
+ /* 0x20 */
+ /* 0x40 */
+#define FUTEX2_PRIVATE FUTEX_PRIVATE_FLAG
+
+#define FUTEX2_SIZE_MASK 0x03
+#endif
+
+static int no_futex;
+
+static void *fwake(void *data)
+{
+ unsigned int *futex = data;
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ struct io_uring ring;
+ int ret;
+
+ ret = io_uring_queue_init(1, &ring, 0);
+ if (ret) {
+ fprintf(stderr, "queue init: %d\n", ret);
+ return NULL;
+ }
+
+ *futex = 1;
+ sqe = io_uring_get_sqe(&ring);
+ io_uring_prep_futex_wake(sqe, futex, 1, FUTEX_BITSET_MATCH_ANY,
+ FUTEX2_SIZE_U32, 0);
+ sqe->user_data = 3;
+
+ io_uring_submit(&ring);
+
+ ret = io_uring_wait_cqe(&ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait: %d\n", ret);
+ return NULL;
+ }
+ io_uring_cqe_seen(&ring, cqe);
+ io_uring_queue_exit(&ring);
+ return NULL;
+}
+
+static int __test(struct io_uring *ring, int vectored, int async,
+ int async_cancel)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ struct futex_waitv fw[NFUTEX];
+ unsigned int *futex;
+ pthread_t threads[NFUTEX];
+ void *tret;
+ int ret, i, nfutex;
+
+ nfutex = NFUTEX;
+ if (!vectored)
+ nfutex = 1;
+
+ futex = calloc(nfutex, sizeof(*futex));
+ for (i = 0; i < nfutex; i++) {
+ fw[i].val = 0;
+ fw[i].uaddr = (unsigned long) &futex[i];
+ fw[i].flags = FUTEX2_SIZE_U32;
+ fw[i].__reserved = 0;
+ }
+
+ sqe = io_uring_get_sqe(ring);
+ if (vectored)
+ io_uring_prep_futex_waitv(sqe, fw, nfutex, 0);
+ else
+ io_uring_prep_futex_wait(sqe, futex, 0, FUTEX_BITSET_MATCH_ANY,
+ FUTEX2_SIZE_U32, 0);
+ if (async)
+ sqe->flags |= IOSQE_ASYNC;
+ sqe->user_data = 1;
+
+ io_uring_submit(ring);
+
+ for (i = 0; i < nfutex; i++)
+ pthread_create(&threads[i], NULL, fwake, &futex[i]);
+
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_cancel64(sqe, 1, 0);
+ if (async_cancel)
+ sqe->flags |= IOSQE_ASYNC;
+ sqe->user_data = 2;
+
+ io_uring_submit(ring);
+
+ for (i = 0; i < 2; i++) {
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "parent wait %d\n", ret);
+ return 1;
+ }
+
+ if (cqe->res == -EINVAL || cqe->res == -EOPNOTSUPP) {
+ no_futex = 1;
+ return 0;
+ }
+ io_uring_cqe_seen(ring, cqe);
+ }
+
+ ret = io_uring_peek_cqe(ring, &cqe);
+ if (!ret) {
+ fprintf(stderr, "peek found cqe!\n");
+ return 1;
+ }
+
+ for (i = 0; i < nfutex; i++)
+ pthread_join(threads[i], &tret);
+
+ return 0;
+}
+
+static int test(int flags, int vectored)
+{
+ struct io_uring ring;
+ int ret, i;
+
+ ret = io_uring_queue_init(8, &ring, flags);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < LOOPS; i++) {
+ int async_cancel = (!i % 2);
+ int async_wait = !(i % 3);
+ ret = __test(&ring, vectored, async_wait, async_cancel);
+ if (ret) {
+ fprintf(stderr, "flags=%x, failed=%d\n", flags, i);
+ break;
+ }
+ if (no_futex)
+ break;
+ }
+
+ io_uring_queue_exit(&ring);
+ return ret;
+}
+
+static int test_order(int vectored, int async)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ struct futex_waitv fw;
+ struct io_uring ring;
+ unsigned int *futex;
+ int ret, i;
+
+ ret = io_uring_queue_init(8, &ring, 0);
+ if (ret)
+ return ret;
+
+ futex = malloc(sizeof(*futex));
+ *futex = 0;
+
+ fw.val = 0;
+ fw.uaddr = (unsigned long) futex;
+ fw.flags = FUTEX2_SIZE_U32;
+ fw.__reserved = 0;
+
+ /*
+ * Submit two futex waits
+ */
+ sqe = io_uring_get_sqe(&ring);
+ if (!vectored)
+ io_uring_prep_futex_wait(sqe, futex, 0, FUTEX_BITSET_MATCH_ANY,
+ FUTEX2_SIZE_U32, 0);
+ else
+ io_uring_prep_futex_waitv(sqe, &fw, 1, 0);
+ sqe->user_data = 1;
+
+ sqe = io_uring_get_sqe(&ring);
+ if (!vectored)
+ io_uring_prep_futex_wait(sqe, futex, 0, FUTEX_BITSET_MATCH_ANY,
+ FUTEX2_SIZE_U32, 0);
+ else
+ io_uring_prep_futex_waitv(sqe, &fw, 1, 0);
+ sqe->user_data = 2;
+
+ io_uring_submit(&ring);
+
+ /*
+ * Now submit wake for just one futex
+ */
+ *futex = 1;
+ sqe = io_uring_get_sqe(&ring);
+ io_uring_prep_futex_wake(sqe, futex, 1, FUTEX_BITSET_MATCH_ANY,
+ FUTEX2_SIZE_U32, 0);
+ sqe->user_data = 100;
+ if (async)
+ sqe->flags |= IOSQE_ASYNC;
+
+ io_uring_submit(&ring);
+
+ /*
+ * We expect to find completions for the first futex wait, and
+ * the futex wake. We should not see the last futex wait.
+ */
+ for (i = 0; i < 2; i++) {
+ ret = io_uring_wait_cqe(&ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait %d\n", ret);
+ return 1;
+ }
+ if (cqe->user_data == 1 || cqe->user_data == 100) {
+ io_uring_cqe_seen(&ring, cqe);
+ continue;
+ }
+ fprintf(stderr, "unexpected cqe %lu, res %d\n", (unsigned long) cqe->user_data, cqe->res);
+ return 1;
+ }
+
+ ret = io_uring_peek_cqe(&ring, &cqe);
+ if (ret != -EAGAIN) {
+ fprintf(stderr, "Unexpected cqe available: %d\n", cqe->res);
+ return 1;
+ }
+
+ io_uring_queue_exit(&ring);
+ return 0;
+}
+
+static int test_multi_wake(int vectored)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ struct futex_waitv fw;
+ struct io_uring ring;
+ unsigned int *futex;
+ int ret, i;
+
+ ret = io_uring_queue_init(8, &ring, 0);
+ if (ret)
+ return ret;
+
+ futex = malloc(sizeof(*futex));
+ *futex = 0;
+
+ fw.val = 0;
+ fw.uaddr = (unsigned long) futex;
+ fw.flags = FUTEX2_SIZE_U32;
+ fw.__reserved = 0;
+
+ /*
+ * Submit two futex waits
+ */
+ sqe = io_uring_get_sqe(&ring);
+ if (!vectored)
+ io_uring_prep_futex_wait(sqe, futex, 0, FUTEX_BITSET_MATCH_ANY,
+ FUTEX2_SIZE_U32, 0);
+ else
+ io_uring_prep_futex_waitv(sqe, &fw, 1, 0);
+ sqe->user_data = 1;
+
+ sqe = io_uring_get_sqe(&ring);
+ if (!vectored)
+ io_uring_prep_futex_wait(sqe, futex, 0, FUTEX_BITSET_MATCH_ANY,
+ FUTEX2_SIZE_U32, 0);
+ else
+ io_uring_prep_futex_waitv(sqe, &fw, 1, 0);
+ sqe->user_data = 2;
+
+ io_uring_submit(&ring);
+
+ /*
+ * Now submit wake for both futexes
+ */
+ *futex = 1;
+ sqe = io_uring_get_sqe(&ring);
+ io_uring_prep_futex_wake(sqe, futex, 2, FUTEX_BITSET_MATCH_ANY,
+ FUTEX2_SIZE_U32, 0);
+ sqe->user_data = 100;
+
+ io_uring_submit(&ring);
+
+ /*
+ * We expect to find completions for the both futex waits, and
+ * the futex wake.
+ */
+ for (i = 0; i < 3; i++) {
+ ret = io_uring_wait_cqe(&ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait %d\n", ret);
+ return 1;
+ }
+ if (cqe->res < 0) {
+ fprintf(stderr, "cqe error %d\n", cqe->res);
+ return 1;
+ }
+ io_uring_cqe_seen(&ring, cqe);
+ }
+
+ ret = io_uring_peek_cqe(&ring, &cqe);
+ if (!ret) {
+ fprintf(stderr, "peek found cqe!\n");
+ return 1;
+ }
+
+ io_uring_queue_exit(&ring);
+ return 0;
+}
+
+/*
+ * Test that waking 0 futexes returns 0
+ */
+static int test_wake_zero(void)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ struct io_uring ring;
+ unsigned int *futex;
+ int ret;
+
+ ret = io_uring_queue_init(8, &ring, 0);
+ if (ret)
+ return ret;
+
+ futex = malloc(sizeof(*futex));
+ *futex = 0;
+
+ sqe = io_uring_get_sqe(&ring);
+ sqe->user_data = 1;
+ io_uring_prep_futex_wait(sqe, futex, 0, FUTEX_BITSET_MATCH_ANY,
+ FUTEX2_SIZE_U32, 0);
+
+ io_uring_submit(&ring);
+
+ sqe = io_uring_get_sqe(&ring);
+ sqe->user_data = 2;
+ io_uring_prep_futex_wake(sqe, futex, 0, FUTEX_BITSET_MATCH_ANY,
+ FUTEX2_SIZE_U32, 0);
+
+ io_uring_submit(&ring);
+
+ ret = io_uring_wait_cqe(&ring, &cqe);
+
+ /*
+ * Should get zero res and it should be the wake
+ */
+ if (cqe->res || cqe->user_data != 2) {
+ fprintf(stderr, "cqe res %d, data %ld\n", cqe->res, (long) cqe->user_data);
+ return 1;
+ }
+ io_uring_cqe_seen(&ring, cqe);
+
+ /*
+ * Should not have the wait complete
+ */
+ ret = io_uring_peek_cqe(&ring, &cqe);
+ if (!ret) {
+ fprintf(stderr, "peek found cqe!\n");
+ return 1;
+ }
+
+ io_uring_queue_exit(&ring);
+ return 0;
+}
+
+/*
+ * Test invalid wait/wake/waitv flags
+ */
+static int test_invalid(void)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ struct futex_waitv fw;
+ struct io_uring ring;
+ unsigned int *futex;
+ int ret;
+
+ ret = io_uring_queue_init(8, &ring, 0);
+ if (ret)
+ return ret;
+
+ futex = malloc(sizeof(*futex));
+ *futex = 0;
+
+ sqe = io_uring_get_sqe(&ring);
+ sqe->user_data = 1;
+ io_uring_prep_futex_wait(sqe, futex, 0, FUTEX_BITSET_MATCH_ANY, 0x1000,
+ 0);
+
+ io_uring_submit(&ring);
+
+ ret = io_uring_wait_cqe(&ring, &cqe);
+
+ /*
+ * Should get zero res and it should be the wake
+ */
+ if (cqe->res != -EINVAL) {
+ fprintf(stderr, "wait cqe res %d\n", cqe->res);
+ return 1;
+ }
+ io_uring_cqe_seen(&ring, cqe);
+
+ sqe = io_uring_get_sqe(&ring);
+ sqe->user_data = 1;
+ io_uring_prep_futex_wake(sqe, futex, 0, FUTEX_BITSET_MATCH_ANY, 0x1000,
+ 0);
+
+ io_uring_submit(&ring);
+
+ ret = io_uring_wait_cqe(&ring, &cqe);
+
+ /*
+ * Should get zero res and it should be the wake
+ */
+ if (cqe->res != -EINVAL) {
+ fprintf(stderr, "wake cqe res %d\n", cqe->res);
+ return 1;
+ }
+ io_uring_cqe_seen(&ring, cqe);
+
+ fw.val = 0;
+ fw.uaddr = (unsigned long) futex;
+ fw.flags = FUTEX2_SIZE_U32 | 0x1000;
+ fw.__reserved = 0;
+
+ sqe = io_uring_get_sqe(&ring);
+ sqe->user_data = 1;
+ io_uring_prep_futex_waitv(sqe, &fw, 1, 0);
+
+ io_uring_submit(&ring);
+
+ ret = io_uring_wait_cqe(&ring, &cqe);
+
+ /*
+ * Should get zero res and it should be the wake
+ */
+ if (cqe->res != -EINVAL) {
+ fprintf(stderr, "waitv cqe res %d\n", cqe->res);
+ return 1;
+ }
+ io_uring_cqe_seen(&ring, cqe);
+
+ io_uring_queue_exit(&ring);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+
+ if (argc > 1)
+ return T_EXIT_SKIP;
+
+ ret = test(0, 0);
+ if (ret) {
+ fprintf(stderr, "test 0 0 failed\n");
+ return T_EXIT_FAIL;
+ }
+ if (no_futex)
+ return T_EXIT_SKIP;
+
+ ret = test(0, 1);
+ if (ret) {
+ fprintf(stderr, "test 0 1 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test_wake_zero();
+ if (ret) {
+ fprintf(stderr, "wake 0 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test_invalid();
+ if (ret) {
+ fprintf(stderr, "test invalid failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test(IORING_SETUP_SQPOLL, 0);
+ if (ret) {
+ fprintf(stderr, "test sqpoll 0 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test(IORING_SETUP_SQPOLL, 1);
+ if (ret) {
+ fprintf(stderr, "test sqpoll 1 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test(IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN, 0);
+ if (ret) {
+ fprintf(stderr, "test single coop 0 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test(IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN, 1);
+ if (ret) {
+ fprintf(stderr, "test single coop 1 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test(IORING_SETUP_COOP_TASKRUN, 0);
+ if (ret) {
+ fprintf(stderr, "test taskrun 0 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test(IORING_SETUP_COOP_TASKRUN, 1);
+ if (ret) {
+ fprintf(stderr, "test taskrun 1 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test_order(0, 0);
+ if (ret) {
+ fprintf(stderr, "test_order 0 0 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test_order(1, 0);
+ if (ret) {
+ fprintf(stderr, "test_order 1 0 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test_order(0, 1);
+ if (ret) {
+ fprintf(stderr, "test_order 0 1 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test_order(1, 1);
+ if (ret) {
+ fprintf(stderr, "test_order 1 1 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test_multi_wake(0);
+ if (ret) {
+ fprintf(stderr, "multi_wake 0 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test_multi_wake(1);
+ if (ret) {
+ fprintf(stderr, "multi_wake 1 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ return T_EXIT_PASS;
+}
diff --git a/contrib/libs/liburing/test/futex.t/ya.make b/contrib/libs/liburing/test/futex.t/ya.make
new file mode 100644
index 0000000000..1f35661353
--- /dev/null
+++ b/contrib/libs/liburing/test/futex.t/ya.make
@@ -0,0 +1,33 @@
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
+WITHOUT_LICENSE_TEXTS()
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/liburing
+)
+
+ADDINCL(
+ contrib/libs/liburing/src/include
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_RUNTIME()
+
+CFLAGS(
+ -DLIBURING_BUILD_TEST
+ -D__SANE_USERSPACE_TYPES__
+)
+
+SRCDIR(contrib/libs/liburing/test)
+
+SRCS(
+ futex.c
+ helpers.c
+)
+
+END()
diff --git a/contrib/libs/liburing/test/hardlink.c b/contrib/libs/liburing/test/hardlink.c
index 1bd7a1c882..6ac5f39f98 100644
--- a/contrib/libs/liburing/test/hardlink.c
+++ b/contrib/libs/liburing/test/hardlink.c
@@ -13,36 +13,34 @@
#include "liburing.h"
#include "helpers.h"
-
-static int do_linkat(struct io_uring *ring, const char *oldname, const char *newname)
+static int do_linkat(struct io_uring *ring, int olddirfd, const char *oldname,
+ const char *newname, int flags)
{
- int ret;
struct io_uring_sqe *sqe;
struct io_uring_cqe *cqe;
+ int ret;
sqe = io_uring_get_sqe(ring);
if (!sqe) {
fprintf(stderr, "sqe get failed\n");
- goto err;
+ return 1;
}
- io_uring_prep_linkat(sqe, AT_FDCWD, oldname, AT_FDCWD, newname, 0);
+ io_uring_prep_linkat(sqe, olddirfd, oldname, AT_FDCWD, newname, flags);
ret = io_uring_submit(ring);
if (ret != 1) {
fprintf(stderr, "submit failed: %d\n", ret);
- goto err;
+ return 1;
}
ret = io_uring_wait_cqes(ring, &cqe, 1, 0, 0);
if (ret) {
fprintf(stderr, "wait_cqe failed: %d\n", ret);
- goto err;
+ return 1;
}
ret = cqe->res;
io_uring_cqe_seen(ring, cqe);
return ret;
-err:
- return 1;
}
static int files_linked_ok(const char* fn1, const char *fn2)
@@ -71,9 +69,11 @@ static int files_linked_ok(const char* fn1, const char *fn2)
int main(int argc, char *argv[])
{
static const char target[] = "io_uring-linkat-test-target";
+ static const char emptyname[] = "io_uring-linkat-test-empty";
static const char linkname[] = "io_uring-linkat-test-link";
- int ret;
+ static const char symlinkname[] = "io_uring-linkat-test-symlink";
struct io_uring ring;
+ int ret, fd, exit_status = T_EXIT_FAIL;
if (argc > 1)
return T_EXIT_SKIP;
@@ -84,58 +84,88 @@ int main(int argc, char *argv[])
return ret;
}
- ret = open(target, O_CREAT | O_RDWR | O_EXCL, 0600);
+ ret = fd = open(target, O_CREAT | O_RDWR | O_EXCL, 0600);
if (ret < 0) {
perror("open");
- goto err;
+ goto out;
+ }
+ if (write(fd, "linktest", 8) != 8) {
+ close(fd);
+ goto out;
}
- if (write(ret, "linktest", 8) != 8) {
- close(ret);
- goto err1;
+ if(geteuid()) {
+ fprintf(stdout, "not root, skipping AT_EMPTY_PATH test\n");
+ } else {
+ ret = do_linkat(&ring, fd, "", emptyname, AT_EMPTY_PATH);
+ if (ret < 0) {
+ if (ret == -EBADF || ret == -EINVAL) {
+ fprintf(stdout, "linkat not supported, skipping\n");
+ exit_status = T_EXIT_SKIP;
+ goto out;
+ }
+ fprintf(stderr, "linkat: %s\n", strerror(-ret));
+ goto out;
+ } else if (ret) {
+ goto out;
+ }
+ if (!files_linked_ok(emptyname, target))
+ goto out;
+ unlinkat(AT_FDCWD, emptyname, 0);
}
- close(ret);
+ close(fd);
- ret = do_linkat(&ring, target, linkname);
+ ret = symlink(target, symlinkname);
+ if (ret < 0) {
+ perror("open");
+ goto out;
+ }
+
+ ret = do_linkat(&ring, AT_FDCWD, target, linkname, 0);
if (ret < 0) {
if (ret == -EBADF || ret == -EINVAL) {
fprintf(stdout, "linkat not supported, skipping\n");
- goto skip;
+ exit_status = T_EXIT_SKIP;
+ goto out;
}
fprintf(stderr, "linkat: %s\n", strerror(-ret));
- goto err1;
+ goto out;
} else if (ret) {
- goto err1;
+ goto out;
}
if (!files_linked_ok(linkname, target))
- goto err2;
+ goto out;
+
+ unlinkat(AT_FDCWD, linkname, 0);
- ret = do_linkat(&ring, target, linkname);
+ ret = do_linkat(&ring, AT_FDCWD, symlinkname, linkname, AT_SYMLINK_FOLLOW);
+ if (ret < 0) {
+ fprintf(stderr, "linkat: %s\n", strerror(-ret));
+ goto out;
+ } else if (ret) {
+ goto out;
+ }
+
+ if (!files_linked_ok(symlinkname, target))
+ goto out;
+
+ ret = do_linkat(&ring, AT_FDCWD, target, linkname, 0);
if (ret != -EEXIST) {
fprintf(stderr, "test_linkat linkname already exists failed: %d\n", ret);
- goto err2;
+ goto out;
}
- ret = do_linkat(&ring, target, "surely/this/does/not/exist");
+ ret = do_linkat(&ring, AT_FDCWD, target, "surely/this/does/not/exist", 0);
if (ret != -ENOENT) {
fprintf(stderr, "test_linkat no parent failed: %d\n", ret);
- goto err2;
+ goto out;
}
-
- unlinkat(AT_FDCWD, linkname, 0);
- unlinkat(AT_FDCWD, target, 0);
- io_uring_queue_exit(&ring);
- return T_EXIT_PASS;
-skip:
- unlinkat(AT_FDCWD, linkname, 0);
- unlinkat(AT_FDCWD, target, 0);
- io_uring_queue_exit(&ring);
- return T_EXIT_SKIP;
-err2:
+ exit_status = T_EXIT_PASS;
+out:
+ unlinkat(AT_FDCWD, symlinkname, 0);
unlinkat(AT_FDCWD, linkname, 0);
-err1:
+ unlinkat(AT_FDCWD, emptyname, 0);
unlinkat(AT_FDCWD, target, 0);
-err:
io_uring_queue_exit(&ring);
- return T_EXIT_FAIL;
+ return exit_status;
}
diff --git a/contrib/libs/liburing/test/helpers.c b/contrib/libs/liburing/test/helpers.c
index 7133b00b91..0d897271d8 100644
--- a/contrib/libs/liburing/test/helpers.c
+++ b/contrib/libs/liburing/test/helpers.c
@@ -37,13 +37,15 @@ void *t_malloc(size_t size)
int t_bind_ephemeral_port(int fd, struct sockaddr_in *addr)
{
socklen_t addrlen;
+ int ret;
addr->sin_port = 0;
if (bind(fd, (struct sockaddr *)addr, sizeof(*addr)))
return -errno;
addrlen = sizeof(*addr);
- assert(!getsockname(fd, (struct sockaddr *)addr, &addrlen));
+ ret = getsockname(fd, (struct sockaddr *)addr, &addrlen);
+ assert(!ret);
assert(addr->sin_port != 0);
return 0;
}
@@ -285,22 +287,18 @@ unsigned __io_uring_flush_sq(struct io_uring *ring)
* Ensure kernel sees the SQE updates before the tail update.
*/
if (!(ring->flags & IORING_SETUP_SQPOLL))
- IO_URING_WRITE_ONCE(*sq->ktail, tail);
+ *sq->ktail = tail;
else
io_uring_smp_store_release(sq->ktail, tail);
}
/*
- * This _may_ look problematic, as we're not supposed to be reading
- * SQ->head without acquire semantics. When we're in SQPOLL mode, the
- * kernel submitter could be updating this right now. For non-SQPOLL,
- * task itself does it, and there's no potential race. But even for
- * SQPOLL, the load is going to be potentially out-of-date the very
- * instant it's done, regardless or whether or not it's done
- * atomically. Worst case, we're going to be over-estimating what
- * we can submit. The point is, we need to be able to deal with this
- * situation regardless of any perceived atomicity.
- */
- return tail - *sq->khead;
+ * This load needs to be atomic, since sq->khead is written concurrently
+ * by the kernel, but it doesn't need to be load_acquire, since the
+ * kernel doesn't store to the submission queue; it advances khead just
+ * to indicate that it's finished reading the submission queue entries
+ * so they're available for us to write to.
+ */
+ return tail - IO_URING_READ_ONCE(*sq->khead);
}
/*
diff --git a/contrib/libs/liburing/test/helpers.h b/contrib/libs/liburing/test/helpers.h
index 530732422c..9f62a5f63f 100644
--- a/contrib/libs/liburing/test/helpers.h
+++ b/contrib/libs/liburing/test/helpers.h
@@ -10,6 +10,7 @@ extern "C" {
#endif
#include "liburing.h"
+#include "../src/setup.h"
#include <arpa/inet.h>
enum t_setup_ret {
@@ -87,6 +88,15 @@ bool t_probe_defer_taskrun(void);
unsigned __io_uring_flush_sq(struct io_uring *ring);
+static inline int t_io_uring_init_sqarray(unsigned entries, struct io_uring *ring,
+ struct io_uring_params *p)
+{
+ int ret;
+
+ ret = __io_uring_queue_init_params(entries, ring, p, NULL, 0);
+ return ret >= 0 ? 0 : ret;
+}
+
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
void t_error(int status, int errnum, const char *format, ...);
diff --git a/contrib/libs/liburing/test/io_uring_enter.c b/contrib/libs/liburing/test/io_uring_enter.c
index 7f87f0cf55..7c73d0a403 100644
--- a/contrib/libs/liburing/test/io_uring_enter.c
+++ b/contrib/libs/liburing/test/io_uring_enter.c
@@ -184,13 +184,16 @@ int main(int argc, char **argv)
unsigned ktail, mask, index;
unsigned sq_entries;
unsigned completed, dropped;
+ struct io_uring_params p;
if (argc > 1)
return T_EXIT_SKIP;
- ret = io_uring_queue_init(IORING_MAX_ENTRIES, &ring, 0);
+ memset(&p, 0, sizeof(p));
+ ret = t_io_uring_init_sqarray(IORING_MAX_ENTRIES, &ring, &p);
if (ret == -ENOMEM)
- ret = io_uring_queue_init(IORING_MAX_ENTRIES_FALLBACK, &ring, 0);
+ ret = t_io_uring_init_sqarray(IORING_MAX_ENTRIES_FALLBACK,
+ &ring, &p);
if (ret < 0) {
perror("io_uring_queue_init");
exit(T_EXIT_FAIL);
diff --git a/contrib/libs/liburing/test/io_uring_register.c b/contrib/libs/liburing/test/io_uring_register.c
index 1201ffb2dc..c315750adc 100644
--- a/contrib/libs/liburing/test/io_uring_register.c
+++ b/contrib/libs/liburing/test/io_uring_register.c
@@ -33,7 +33,7 @@ static rlim_t mlock_limit;
static int devnull;
static int expect_fail(int fd, unsigned int opcode, void *arg,
- unsigned int nr_args, int error)
+ unsigned int nr_args, int error, int error2)
{
int ret;
@@ -56,8 +56,8 @@ static int expect_fail(int fd, unsigned int opcode, void *arg,
return 1;
}
- if (ret != error) {
- fprintf(stderr, "expected %d, got %d\n", error, ret);
+ if (ret != error && (error2 && ret != error2)) {
+ fprintf(stderr, "expected %d/%d, got %d\n", error, error2, ret);
return 1;
}
return 0;
@@ -196,8 +196,7 @@ static int test_max_fds(int uring_fd)
status = 0;
ret = io_uring_register(uring_fd, IORING_UNREGISTER_FILES, 0, 0);
if (ret < 0) {
- ret = errno;
- errno = ret;
+ errno = -ret;
perror("io_uring_register UNREGISTER_FILES");
exit(1);
}
@@ -231,22 +230,20 @@ static int test_memlock_exceeded(int fd)
while (iov.iov_len) {
ret = io_uring_register(fd, IORING_REGISTER_BUFFERS, &iov, 1);
- if (ret < 0) {
- if (errno == ENOMEM) {
- iov.iov_len /= 2;
- continue;
- }
- if (errno == EFAULT) {
- free(buf);
- return 0;
- }
- fprintf(stderr, "expected success or EFAULT, got %d\n", errno);
+ if (ret == -ENOMEM) {
+ iov.iov_len /= 2;
+ continue;
+ } else if (ret == -EFAULT) {
+ free(buf);
+ return 0;
+ } else if (ret) {
+ fprintf(stderr, "expected success or EFAULT, got %d\n", ret);
free(buf);
return 1;
}
ret = io_uring_register(fd, IORING_UNREGISTER_BUFFERS, NULL, 0);
if (ret != 0) {
- fprintf(stderr, "error: unregister failed with %d\n", errno);
+ fprintf(stderr, "error: unregister failed with %d\n", ret);
free(buf);
return 1;
}
@@ -278,15 +275,15 @@ static int test_iovec_nr(int fd)
iovs[i].iov_len = pagesize;
}
- status |= expect_fail(fd, IORING_REGISTER_BUFFERS, iovs, nr, -EINVAL);
+ status |= expect_fail(fd, IORING_REGISTER_BUFFERS, iovs, nr, -EINVAL, 0);
/* reduce to UIO_MAXIOV */
nr = UIO_MAXIOV;
ret = io_uring_register(fd, IORING_REGISTER_BUFFERS, iovs, nr);
- if (ret && (errno == ENOMEM || errno == EPERM) && geteuid()) {
+ if ((ret == -ENOMEM || ret == -EPERM) && geteuid()) {
fprintf(stderr, "can't register large iovec for regular users, skip\n");
} else if (ret != 0) {
- fprintf(stderr, "expected success, got %d\n", errno);
+ fprintf(stderr, "expected success, got %d\n", ret);
status = 1;
} else {
io_uring_register(fd, IORING_UNREGISTER_BUFFERS, 0, 0);
@@ -309,12 +306,12 @@ static int test_iovec_size(int fd)
/* NULL pointer for base */
iov.iov_base = 0;
iov.iov_len = 4096;
- status |= expect_fail(fd, IORING_REGISTER_BUFFERS, &iov, 1, -EFAULT);
+ status |= expect_fail(fd, IORING_REGISTER_BUFFERS, &iov, 1, -EFAULT, 0);
/* valid base, 0 length */
iov.iov_base = &buf;
iov.iov_len = 0;
- status |= expect_fail(fd, IORING_REGISTER_BUFFERS, &iov, 1, -EFAULT);
+ status |= expect_fail(fd, IORING_REGISTER_BUFFERS, &iov, 1, -EFAULT, 0);
/* valid base, length exceeds size */
/* this requires an unampped page directly after buf */
@@ -325,7 +322,7 @@ static int test_iovec_size(int fd)
assert(ret == 0);
iov.iov_base = buf;
iov.iov_len = 2 * pagesize;
- status |= expect_fail(fd, IORING_REGISTER_BUFFERS, &iov, 1, -EFAULT);
+ status |= expect_fail(fd, IORING_REGISTER_BUFFERS, &iov, 1, -EFAULT, 0);
munmap(buf, pagesize);
/* huge page */
@@ -373,7 +370,7 @@ static int test_iovec_size(int fd)
status = 1;
iov.iov_base = buf;
iov.iov_len = 2*1024*1024;
- status |= expect_fail(fd, IORING_REGISTER_BUFFERS, &iov, 1, -EOPNOTSUPP);
+ status |= expect_fail(fd, IORING_REGISTER_BUFFERS, &iov, 1, -EFAULT, -EOPNOTSUPP);
munmap(buf, 2*1024*1024);
/* bump up against the soft limit and make sure we get EFAULT
@@ -443,7 +440,7 @@ static int test_poll_ringfd(void)
* fail, because the kernel does not allow registering of the
* ring_fd.
*/
- status |= expect_fail(fd, IORING_REGISTER_FILES, &fd, 1, -EBADF);
+ status |= expect_fail(fd, IORING_REGISTER_FILES, &fd, 1, -EBADF, 0);
/* tear down queue */
io_uring_queue_exit(&ring);
@@ -476,14 +473,14 @@ int main(int argc, char **argv)
}
/* invalid fd */
- status |= expect_fail(-1, 0, NULL, 0, -EBADF);
+ status |= expect_fail(-1, 0, NULL, 0, -EBADF, 0);
/* valid fd that is not an io_uring fd */
- status |= expect_fail(devnull, 0, NULL, 0, -EOPNOTSUPP);
+ status |= expect_fail(devnull, 0, NULL, 0, -EOPNOTSUPP, 0);
/* invalid opcode */
memset(&p, 0, sizeof(p));
fd = new_io_uring(1, &p);
- ret = expect_fail(fd, ~0U, NULL, 0, -EINVAL);
+ ret = expect_fail(fd, ~0U, NULL, 0, -EINVAL, 0);
if (ret) {
/* if this succeeds, tear down the io_uring instance
* and start clean for the next test. */
diff --git a/contrib/libs/liburing/test/io_uring_setup.c b/contrib/libs/liburing/test/io_uring_setup.c
index e0c6bcb519..84f4573700 100644
--- a/contrib/libs/liburing/test/io_uring_setup.c
+++ b/contrib/libs/liburing/test/io_uring_setup.c
@@ -18,7 +18,7 @@
#include "liburing.h"
#include "helpers.h"
-#include "../syscall.h"
+#include "../src/syscall.h"
/* bogus: setup returns a valid fd on success... expect can't predict the
fd we'll get, so this really only takes 1 parameter: error */
diff --git a/contrib/libs/liburing/test/msg-ring-fd.c b/contrib/libs/liburing/test/msg-ring-fd.c
new file mode 100644
index 0000000000..84a7d24f5c
--- /dev/null
+++ b/contrib/libs/liburing/test/msg-ring-fd.c
@@ -0,0 +1,319 @@
+#include "../config-host.h"
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: test fd passing with MSG_RING
+ *
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <pthread.h>
+
+#include "liburing.h"
+#include "helpers.h"
+
+static int no_msg;
+static int no_sparse;
+
+struct data {
+ pthread_t thread;
+ pthread_barrier_t barrier;
+ int ring_flags;
+ int ring_fd;
+ char buf[32];
+};
+
+static void *thread_fn(void *__data)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ struct data *d = __data;
+ struct io_uring ring;
+ int ret, fd = -1;
+
+ io_uring_queue_init(8, &ring, d->ring_flags);
+ ret = io_uring_register_files(&ring, &fd, 1);
+ if (ret) {
+ if (ret != -EINVAL && ret != -EBADF)
+ fprintf(stderr, "thread file register: %d\n", ret);
+ no_sparse = 1;
+ pthread_barrier_wait(&d->barrier);
+ return NULL;
+ }
+
+ d->ring_fd = ring.ring_fd;
+ pthread_barrier_wait(&d->barrier);
+
+ /* wait for MSG */
+ ret = io_uring_wait_cqe(&ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait_cqe dst: %d\n", ret);
+ return NULL;
+ }
+ if (cqe->res < 0) {
+ fprintf(stderr, "cqe error dst: %d\n", cqe->res);
+ return NULL;
+ }
+
+ fd = cqe->res;
+ io_uring_cqe_seen(&ring, cqe);
+ sqe = io_uring_get_sqe(&ring);
+ io_uring_prep_read(sqe, fd, d->buf, sizeof(d->buf), 0);
+ sqe->flags |= IOSQE_FIXED_FILE;
+ io_uring_submit(&ring);
+
+ ret = io_uring_wait_cqe(&ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait_cqe dst: %d\n", ret);
+ return NULL;
+ }
+ if (cqe->res < 0) {
+ fprintf(stderr, "cqe error dst: %d\n", cqe->res);
+ return NULL;
+ }
+
+ io_uring_queue_exit(&ring);
+ return NULL;
+}
+
+static int test_remote(struct io_uring *src, int ring_flags)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ int fds[2], fd, ret;
+ struct data d;
+ char buf[32];
+ void *tret;
+ int i;
+
+ pthread_barrier_init(&d.barrier, NULL, 2);
+ d.ring_flags = ring_flags;
+ pthread_create(&d.thread, NULL, thread_fn, &d);
+ pthread_barrier_wait(&d.barrier);
+ memset(d.buf, 0, sizeof(d.buf));
+
+ if (no_sparse)
+ return 0;
+
+ if (pipe(fds) < 0) {
+ perror("pipe");
+ return 1;
+ }
+
+ fd = fds[0];
+ ret = io_uring_register_files(src, &fd, 1);
+ if (ret) {
+ fprintf(stderr, "register files failed: %d\n", ret);
+ return 1;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(buf); i++)
+ buf[i] = rand();
+
+ sqe = io_uring_get_sqe(src);
+ io_uring_prep_write(sqe, fds[1], buf, sizeof(buf), 0);
+ sqe->user_data = 1;
+
+ sqe = io_uring_get_sqe(src);
+ io_uring_prep_msg_ring_fd(sqe, d.ring_fd, 0, 0, 0, 0);
+ sqe->user_data = 2;
+
+ io_uring_submit(src);
+
+ for (i = 0; i < 2; i++) {
+ ret = io_uring_wait_cqe(src, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait_cqe: %d\n", ret);
+ return 1;
+ }
+ if (cqe->res < 0) {
+ fprintf(stderr, "cqe res %d\n", cqe->res);
+ return 1;
+ }
+ if (cqe->user_data == 1 && cqe->res != sizeof(buf)) {
+ fprintf(stderr, "short write %d\n", cqe->res);
+ return 1;
+ }
+ io_uring_cqe_seen(src, cqe);
+ }
+
+ pthread_join(d.thread, &tret);
+
+ if (memcmp(buf, d.buf, sizeof(buf))) {
+ fprintf(stderr, "buffers differ\n");
+ return 1;
+ }
+
+ close(fds[0]);
+ close(fds[1]);
+ io_uring_unregister_files(src);
+ return 0;
+}
+
+static int test_local(struct io_uring *src, struct io_uring *dst)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ int fds[2], fd, ret;
+ char buf[32], dst_buf[32];
+ int i;
+
+ fd = -1;
+ ret = io_uring_register_files(dst, &fd, 1);
+ if (ret) {
+ if (ret == -EBADF || ret == -EINVAL)
+ return 0;
+ fprintf(stderr, "register files failed: %d\n", ret);
+ return 1;
+ }
+
+ if (pipe(fds) < 0) {
+ perror("pipe");
+ return 1;
+ }
+
+ fd = fds[0];
+ ret = io_uring_register_files(src, &fd, 1);
+ if (ret) {
+ fprintf(stderr, "register files failed: %d\n", ret);
+ return 1;
+ }
+
+ memset(dst_buf, 0, sizeof(dst_buf));
+ for (i = 0; i < ARRAY_SIZE(buf); i++)
+ buf[i] = rand();
+
+ sqe = io_uring_get_sqe(src);
+ io_uring_prep_write(sqe, fds[1], buf, sizeof(buf), 0);
+ sqe->user_data = 1;
+
+ sqe = io_uring_get_sqe(src);
+ io_uring_prep_msg_ring_fd(sqe, dst->ring_fd, 0, 0, 10, 0);
+ sqe->user_data = 2;
+
+ io_uring_submit(src);
+
+ fd = -1;
+ for (i = 0; i < 2; i++) {
+ ret = io_uring_wait_cqe(src, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait_cqe: %d\n", ret);
+ return 1;
+ }
+ if (cqe->res < 0) {
+ fprintf(stderr, "cqe res %d\n", cqe->res);
+ return 1;
+ }
+ if (cqe->user_data == 1 && cqe->res != sizeof(buf)) {
+ fprintf(stderr, "short write %d\n", cqe->res);
+ return 1;
+ }
+ io_uring_cqe_seen(src, cqe);
+ }
+
+ ret = io_uring_wait_cqe(dst, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait_cqe dst: %d\n", ret);
+ return 1;
+ }
+ if (cqe->res < 0) {
+ fprintf(stderr, "cqe error dst: %d\n", cqe->res);
+ return 1;
+ }
+
+ fd = cqe->res;
+ io_uring_cqe_seen(dst, cqe);
+ sqe = io_uring_get_sqe(dst);
+ io_uring_prep_read(sqe, fd, dst_buf, sizeof(dst_buf), 0);
+ sqe->flags |= IOSQE_FIXED_FILE;
+ sqe->user_data = 3;
+ io_uring_submit(dst);
+
+ ret = io_uring_wait_cqe(dst, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait_cqe dst: %d\n", ret);
+ return 1;
+ }
+ if (cqe->res < 0) {
+ fprintf(stderr, "cqe error dst: %d\n", cqe->res);
+ return 1;
+ }
+ if (cqe->res != sizeof(dst_buf)) {
+ fprintf(stderr, "short read %d\n", cqe->res);
+ return 1;
+ }
+ if (memcmp(buf, dst_buf, sizeof(buf))) {
+ fprintf(stderr, "buffers differ\n");
+ return 1;
+ }
+
+ close(fds[0]);
+ close(fds[1]);
+ io_uring_unregister_files(src);
+ io_uring_unregister_files(dst);
+ return 0;
+}
+
+static int test(int ring_flags)
+{
+ struct io_uring ring, ring2;
+ int ret;
+
+ ret = io_uring_queue_init(8, &ring, ring_flags);
+ if (ret) {
+ if (ret == -EINVAL)
+ return 0;
+ fprintf(stderr, "ring setup failed: %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ ret = io_uring_queue_init(8, &ring2, ring_flags);
+ if (ret) {
+ fprintf(stderr, "ring setup failed: %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ ret = test_local(&ring, &ring2);
+ if (ret) {
+ fprintf(stderr, "test local failed\n");
+ return T_EXIT_FAIL;
+ }
+ if (no_msg)
+ return T_EXIT_SKIP;
+
+ ret = test_remote(&ring, ring_flags);
+ if (ret) {
+ fprintf(stderr, "test_remote failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ io_uring_queue_exit(&ring);
+ io_uring_queue_exit(&ring2);
+ return T_EXIT_PASS;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+
+ if (argc > 1)
+ return T_EXIT_SKIP;
+
+ ret = test(0);
+ if (ret != T_EXIT_PASS) {
+ fprintf(stderr, "ring flags 0 failed\n");
+ return ret;
+ }
+ if (no_msg)
+ return T_EXIT_SKIP;
+
+ ret = test(IORING_SETUP_SINGLE_ISSUER|IORING_SETUP_DEFER_TASKRUN);
+ if (ret != T_EXIT_PASS) {
+ fprintf(stderr, "ring flags defer failed\n");
+ return ret;
+ }
+
+ return ret;
+}
diff --git a/contrib/libs/liburing/test/msg-ring-fd.t/ya.make b/contrib/libs/liburing/test/msg-ring-fd.t/ya.make
new file mode 100644
index 0000000000..55b1db64bb
--- /dev/null
+++ b/contrib/libs/liburing/test/msg-ring-fd.t/ya.make
@@ -0,0 +1,33 @@
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
+WITHOUT_LICENSE_TEXTS()
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/liburing
+)
+
+ADDINCL(
+ contrib/libs/liburing/src/include
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_RUNTIME()
+
+CFLAGS(
+ -DLIBURING_BUILD_TEST
+ -D__SANE_USERSPACE_TYPES__
+)
+
+SRCDIR(contrib/libs/liburing/test)
+
+SRCS(
+ helpers.c
+ msg-ring-fd.c
+)
+
+END()
diff --git a/contrib/libs/liburing/test/msg-ring-flags.c b/contrib/libs/liburing/test/msg-ring-flags.c
index d533b8f72d..c1e8abb8aa 100644
--- a/contrib/libs/liburing/test/msg-ring-flags.c
+++ b/contrib/libs/liburing/test/msg-ring-flags.c
@@ -118,7 +118,7 @@ static void *thread_fn(void *data)
return NULL;
}
-int main(int argc, char *argv[])
+static int test(int ring_flags)
{
struct io_uring ring, ring2;
pthread_t thread;
@@ -126,16 +126,13 @@ int main(int argc, char *argv[])
void *ret2;
int ret, i;
- if (argc > 1)
- return T_EXIT_SKIP;
-
- ret = io_uring_queue_init(2, &ring, 0);
+ ret = io_uring_queue_init(2, &ring, ring_flags);
if (ret) {
fprintf(stderr, "io_uring_queue_init failed for ring1: %d\n", ret);
return T_EXIT_FAIL;
}
- ret = io_uring_queue_init(2, &ring2, 0);
+ ret = io_uring_queue_init(2, &ring2, ring_flags);
if (ret) {
fprintf(stderr, "io_uring_queue_init failed for ring2: %d\n", ret);
return T_EXIT_FAIL;
@@ -191,3 +188,26 @@ int main(int argc, char *argv[])
return T_EXIT_PASS;
}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+
+ if (argc > 1)
+ return T_EXIT_SKIP;
+
+ ret = test(0);
+ if (ret == T_EXIT_FAIL) {
+ fprintf(stderr, "test ring_flags 0 failed\n");
+ return ret;
+ } else if (ret == T_EXIT_SKIP)
+ return ret;
+
+ ret = test(IORING_SETUP_SINGLE_ISSUER|IORING_SETUP_DEFER_TASKRUN);
+ if (ret == T_EXIT_FAIL) {
+ fprintf(stderr, "test ring_flags defer failed\n");
+ return ret;
+ }
+
+ return ret;
+}
diff --git a/contrib/libs/liburing/test/msg-ring.c b/contrib/libs/liburing/test/msg-ring.c
index 221fb7895a..ef9e3b1f85 100644
--- a/contrib/libs/liburing/test/msg-ring.c
+++ b/contrib/libs/liburing/test/msg-ring.c
@@ -73,12 +73,20 @@ err:
return 1;
}
-static void *wait_cqe_fn(void *data)
+struct data {
+ struct io_uring *ring;
+ pthread_barrier_t barrier;
+};
+
+static void *wait_cqe_fn(void *__data)
{
- struct io_uring *ring = data;
+ struct data *d = __data;
+ struct io_uring *ring = d->ring;
struct io_uring_cqe *cqe;
int ret;
+ pthread_barrier_wait(&d->barrier);
+
ret = io_uring_wait_cqe(ring, &cqe);
if (ret) {
fprintf(stderr, "wait cqe %d\n", ret);
@@ -107,9 +115,12 @@ static int test_remote(struct io_uring *ring, struct io_uring *target)
void *tret;
struct io_uring_cqe *cqe;
struct io_uring_sqe *sqe;
+ struct data d;
int ret;
- pthread_create(&thread, NULL, wait_cqe_fn, target);
+ d.ring = target;
+ pthread_barrier_init(&d.barrier, NULL, 2);
+ pthread_create(&thread, NULL, wait_cqe_fn, &d);
sqe = io_uring_get_sqe(ring);
if (!sqe) {
@@ -126,6 +137,8 @@ static int test_remote(struct io_uring *ring, struct io_uring *target)
goto err;
}
+ pthread_barrier_wait(&d.barrier);
+
ret = io_uring_wait_cqe(ring, &cqe);
if (ret < 0) {
fprintf(stderr, "wait completion %d\n", ret);
@@ -315,25 +328,22 @@ static int test_disabled_ring(struct io_uring *ring, int flags)
return 0;
}
-int main(int argc, char *argv[])
+static int test(int ring_flags)
{
struct io_uring ring, ring2, pring;
int ret, i;
- if (argc > 1)
- return T_EXIT_SKIP;
-
- ret = io_uring_queue_init(8, &ring, 0);
+ ret = io_uring_queue_init(8, &ring, ring_flags);
if (ret) {
fprintf(stderr, "ring setup failed: %d\n", ret);
return T_EXIT_FAIL;
}
- ret = io_uring_queue_init(8, &ring2, 0);
+ ret = io_uring_queue_init(8, &ring2, ring_flags);
if (ret) {
fprintf(stderr, "ring setup failed: %d\n", ret);
return T_EXIT_FAIL;
}
- ret = io_uring_queue_init(8, &pring, IORING_SETUP_IOPOLL);
+ ret = io_uring_queue_init(8, &pring, ring_flags | IORING_SETUP_IOPOLL);
if (ret) {
fprintf(stderr, "ring setup failed: %d\n", ret);
return T_EXIT_FAIL;
@@ -419,3 +429,25 @@ int main(int argc, char *argv[])
io_uring_queue_exit(&ring2);
return T_EXIT_PASS;
}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+
+ if (argc > 1)
+ return T_EXIT_SKIP;
+
+ ret = test(0);
+ if (ret != T_EXIT_PASS) {
+ fprintf(stderr, "ring flags 0 failed\n");
+ return ret;
+ }
+
+ ret = test(IORING_SETUP_SINGLE_ISSUER|IORING_SETUP_DEFER_TASKRUN);
+ if (ret != T_EXIT_PASS) {
+ fprintf(stderr, "ring flags defer failed\n");
+ return ret;
+ }
+
+ return ret;
+}
diff --git a/contrib/libs/liburing/test/multicqes_drain.c b/contrib/libs/liburing/test/multicqes_drain.c
index fb83441219..43880c0b18 100644
--- a/contrib/libs/liburing/test/multicqes_drain.c
+++ b/contrib/libs/liburing/test/multicqes_drain.c
@@ -234,7 +234,7 @@ static int test_generic_drain(struct io_uring *ring)
}
sleep(1);
- // TODO: randomize event triggerring order
+ // TODO: randomize event triggering order
for (i = 0; i < max_entry; i++) {
if (si[i].op != multi && si[i].op != single)
continue;
diff --git a/contrib/libs/liburing/test/no-mmap-inval.c b/contrib/libs/liburing/test/no-mmap-inval.c
new file mode 100644
index 0000000000..e340311ac3
--- /dev/null
+++ b/contrib/libs/liburing/test/no-mmap-inval.c
@@ -0,0 +1,43 @@
+#include "../config-host.h"
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: test that using SETUP_NO_MMAP with an invalid SQ ring
+ * address fails.
+ *
+ */
+#include <stdlib.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "liburing.h"
+#include "helpers.h"
+
+int main(int argc, char *argv[])
+{
+ struct io_uring_params p = {
+ .sq_entries = 2,
+ .cq_entries = 4,
+ .flags = IORING_SETUP_NO_MMAP,
+ };
+ struct io_uring ring;
+ void *addr;
+ int ret;
+
+ if (argc > 1)
+ return T_EXIT_SKIP;
+
+ t_posix_memalign(&addr, sysconf(_SC_PAGESIZE), 8192);
+ p.cq_off.user_addr = (unsigned long long) (uintptr_t) addr;
+
+ ret = io_uring_queue_init_params(2, &ring, &p);
+ if (ret == -EINVAL) {
+ /* kernel doesn't support SETUP_NO_MMAP */
+ return T_EXIT_SKIP;
+ } else if (ret && ret != -EFAULT) {
+ fprintf(stderr, "Got %d, wanted -EFAULT\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ return T_EXIT_PASS;
+}
diff --git a/contrib/libs/liburing/test/no-mmap-inval.t/ya.make b/contrib/libs/liburing/test/no-mmap-inval.t/ya.make
new file mode 100644
index 0000000000..2dd5080da5
--- /dev/null
+++ b/contrib/libs/liburing/test/no-mmap-inval.t/ya.make
@@ -0,0 +1,33 @@
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
+WITHOUT_LICENSE_TEXTS()
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/liburing
+)
+
+ADDINCL(
+ contrib/libs/liburing/src/include
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_RUNTIME()
+
+CFLAGS(
+ -DLIBURING_BUILD_TEST
+ -D__SANE_USERSPACE_TYPES__
+)
+
+SRCDIR(contrib/libs/liburing/test)
+
+SRCS(
+ helpers.c
+ no-mmap-inval.c
+)
+
+END()
diff --git a/contrib/libs/liburing/test/nolibc.c b/contrib/libs/liburing/test/nolibc.c
index fd07fa13cd..e6ae6057bc 100644
--- a/contrib/libs/liburing/test/nolibc.c
+++ b/contrib/libs/liburing/test/nolibc.c
@@ -7,11 +7,13 @@
* 1) x86
* 2) x86-64
* 3) aarch64
+ * 4) riscv64
*
*/
#include "helpers.h"
-#if !defined(__x86_64__) && !defined(__i386__) && !defined(__aarch64__)
+#if !defined(__x86_64__) && !defined(__i386__) && !defined(__aarch64__) && (!defined(__riscv) && __riscv_xlen != 64)
+
/*
* This arch doesn't support nolibc.
@@ -21,7 +23,7 @@ int main(void)
return T_EXIT_SKIP;
}
-#else /* #if !defined(__x86_64__) && !defined(__i386__) && !defined(__aarch64__) */
+#else /* #if !defined(__x86_64__) && !defined(__i386__) && !defined(__aarch64__) && (!defined(__riscv) && __riscv_xlen != 64) */
#ifndef CONFIG_NOLIBC
#define CONFIG_NOLIBC
@@ -58,4 +60,4 @@ int main(int argc, char *argv[])
return T_EXIT_PASS;
}
-#endif /* #if !defined(__x86_64__) && !defined(__i386__) && !defined(__aarch64__) */
+#endif /* #if !defined(__x86_64__) && !defined(__i386__) && !defined(__aarch64__) && (!defined(__riscv) && __riscv_xlen != 64) */
diff --git a/contrib/libs/liburing/test/openat2.c b/contrib/libs/liburing/test/openat2.c
index a3ad70e143..5206b73f3a 100644
--- a/contrib/libs/liburing/test/openat2.c
+++ b/contrib/libs/liburing/test/openat2.c
@@ -1,7 +1,7 @@
#include "../config-host.h"
/* SPDX-License-Identifier: MIT */
/*
- * Description: run various openat(2) tests
+ * Description: run various openat2(2) tests
*
*/
#include <errno.h>
@@ -73,6 +73,8 @@ static int test_open_fixed(const char *path, int dfd)
}
ret = io_uring_register_files(&ring, &fd, 1);
if (ret) {
+ if (ret == -EINVAL || ret == -EBADF)
+ return 0;
fprintf(stderr, "%s: register ret=%d\n", __FUNCTION__, ret);
return -1;
}
@@ -142,6 +144,8 @@ static int test_open_fixed_fail(const char *path, int dfd)
ret = io_uring_register_files(&ring, &fd, 1);
if (ret) {
+ if (ret == -EINVAL || ret == -EBADF)
+ return 0;
fprintf(stderr, "%s: register ret=%d\n", __FUNCTION__, ret);
return -1;
}
diff --git a/contrib/libs/liburing/test/poll-cancel-all.c b/contrib/libs/liburing/test/poll-cancel-all.c
index 83c48abeea..dd830b44c7 100644
--- a/contrib/libs/liburing/test/poll-cancel-all.c
+++ b/contrib/libs/liburing/test/poll-cancel-all.c
@@ -15,11 +15,22 @@
static int no_cancel_flags;
-static int test1(struct io_uring *ring, int *fd)
+static int test1(struct io_uring *ring, int *fd, int fixed)
{
struct io_uring_sqe *sqe;
struct io_uring_cqe *cqe;
- int ret, i;
+ int ret, i, __fd = fd[0];
+
+ if (fixed)
+ __fd = 0;
+
+ if (fixed) {
+ ret = io_uring_register_files(ring, fd, 1);
+ if (ret) {
+ fprintf(stderr, "failed file register %d\n", ret);
+ return 1;
+ }
+ }
for (i = 0; i < 8; i++) {
sqe = io_uring_get_sqe(ring);
@@ -28,8 +39,10 @@ static int test1(struct io_uring *ring, int *fd)
return 1;
}
- io_uring_prep_poll_add(sqe, fd[0], POLLIN);
+ io_uring_prep_poll_add(sqe, __fd, POLLIN);
sqe->user_data = i + 1;
+ if (fixed)
+ sqe->flags |= IOSQE_FIXED_FILE;
}
ret = io_uring_submit(ring);
@@ -52,7 +65,9 @@ static int test1(struct io_uring *ring, int *fd)
*/
io_uring_prep_cancel(sqe, 0, IORING_ASYNC_CANCEL_ALL);
sqe->cancel_flags |= IORING_ASYNC_CANCEL_FD;
- sqe->fd = fd[0];
+ if (fixed)
+ sqe->cancel_flags |= IORING_ASYNC_CANCEL_FD_FIXED;
+ sqe->fd = __fd;
sqe->user_data = 100;
ret = io_uring_submit(ring);
@@ -94,6 +109,9 @@ static int test1(struct io_uring *ring, int *fd)
io_uring_cqe_seen(ring, cqe);
}
+ if (fixed)
+ io_uring_unregister_files(ring);
+
return 0;
}
@@ -443,7 +461,7 @@ int main(int argc, char *argv[])
return 1;
}
- ret = test1(&ring, fd);
+ ret = test1(&ring, fd, 0);
if (ret) {
fprintf(stderr, "test1 failed\n");
return ret;
@@ -451,6 +469,12 @@ int main(int argc, char *argv[])
if (no_cancel_flags)
return 0;
+ ret = test1(&ring, fd, 1);
+ if (ret) {
+ fprintf(stderr, "test1 fixed failed\n");
+ return ret;
+ }
+
ret = test2(&ring, fd);
if (ret) {
fprintf(stderr, "test2 failed\n");
diff --git a/contrib/libs/liburing/test/pollfree.c b/contrib/libs/liburing/test/pollfree.c
deleted file mode 100644
index 20a8bec60b..0000000000
--- a/contrib/libs/liburing/test/pollfree.c
+++ /dev/null
@@ -1,427 +0,0 @@
-#include "../config-host.h"
-/* SPDX-License-Identifier: MIT */
-// https://syzkaller.appspot.com/bug?id=5f5a44abb4cba056fe24255c4fcb7e7bbe13de7a
-// autogenerated by syzkaller (https://github.com/google/syzkaller)
-
-#include <dirent.h>
-#include <endian.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/prctl.h>
-#include <sys/stat.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <linux/futex.h>
-
-#ifdef __NR_futex
-
-static void sleep_ms(uint64_t ms)
-{
- usleep(ms * 1000);
-}
-
-static uint64_t current_time_ms(void)
-{
- struct timespec ts;
- if (clock_gettime(CLOCK_MONOTONIC, &ts))
- exit(1);
- return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
-}
-
-static void thread_start(void* (*fn)(void*), void* arg)
-{
- pthread_t th;
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setstacksize(&attr, 128 << 10);
- int i = 0;
- for (; i < 100; i++) {
- if (pthread_create(&th, &attr, fn, arg) == 0) {
- pthread_attr_destroy(&attr);
- return;
- }
- if (errno == EAGAIN) {
- usleep(50);
- continue;
- }
- break;
- }
- exit(1);
-}
-
-typedef struct {
- int state;
-} event_t;
-
-static void event_init(event_t* ev)
-{
- ev->state = 0;
-}
-
-static void event_reset(event_t* ev)
-{
- ev->state = 0;
-}
-
-static void event_set(event_t* ev)
-{
- if (ev->state)
- exit(1);
- __atomic_store_n(&ev->state, 1, __ATOMIC_RELEASE);
- syscall(__NR_futex, &ev->state, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1000000);
-}
-
-static void event_wait(event_t* ev)
-{
- while (!__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
- syscall(__NR_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, 0);
-}
-
-static int event_isset(event_t* ev)
-{
- return __atomic_load_n(&ev->state, __ATOMIC_ACQUIRE);
-}
-
-static int event_timedwait(event_t* ev, uint64_t timeout)
-{
- uint64_t start = current_time_ms();
- uint64_t now = start;
- for (;;) {
- uint64_t remain = timeout - (now - start);
- struct timespec ts;
- ts.tv_sec = remain / 1000;
- ts.tv_nsec = (remain % 1000) * 1000 * 1000;
- syscall(__NR_futex, &ev->state, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, &ts);
- if (__atomic_load_n(&ev->state, __ATOMIC_ACQUIRE))
- return 1;
- now = current_time_ms();
- if (now - start > timeout)
- return 0;
- }
-}
-
-#define SIZEOF_IO_URING_SQE 64
-#define SIZEOF_IO_URING_CQE 16
-#define SQ_HEAD_OFFSET 0
-#define SQ_TAIL_OFFSET 64
-#define SQ_RING_MASK_OFFSET 256
-#define SQ_RING_ENTRIES_OFFSET 264
-#define SQ_FLAGS_OFFSET 276
-#define SQ_DROPPED_OFFSET 272
-#define CQ_HEAD_OFFSET 128
-#define CQ_TAIL_OFFSET 192
-#define CQ_RING_MASK_OFFSET 260
-#define CQ_RING_ENTRIES_OFFSET 268
-#define CQ_RING_OVERFLOW_OFFSET 284
-#define CQ_FLAGS_OFFSET 280
-#define CQ_CQES_OFFSET 320
-
-struct io_sqring_offsets {
- uint32_t head;
- uint32_t tail;
- uint32_t ring_mask;
- uint32_t ring_entries;
- uint32_t flags;
- uint32_t dropped;
- uint32_t array;
- uint32_t resv1;
- uint64_t resv2;
-};
-
-struct io_cqring_offsets {
- uint32_t head;
- uint32_t tail;
- uint32_t ring_mask;
- uint32_t ring_entries;
- uint32_t overflow;
- uint32_t cqes;
- uint64_t resv[2];
-};
-
-struct io_uring_params {
- uint32_t sq_entries;
- uint32_t cq_entries;
- uint32_t flags;
- uint32_t sq_thread_cpu;
- uint32_t sq_thread_idle;
- uint32_t features;
- uint32_t resv[4];
- struct io_sqring_offsets sq_off;
- struct io_cqring_offsets cq_off;
-};
-
-#define IORING_OFF_SQ_RING 0
-#define IORING_OFF_SQES 0x10000000ULL
-
-#define sys_io_uring_setup 425
-static long syz_io_uring_setup(volatile long a0, volatile long a1,
- volatile long a2, volatile long a3,
- volatile long a4, volatile long a5)
-{
- uint32_t entries = (uint32_t)a0;
- struct io_uring_params* setup_params = (struct io_uring_params*)a1;
- void* vma1 = (void*)a2;
- void* vma2 = (void*)a3;
- void** ring_ptr_out = (void**)a4;
- void** sqes_ptr_out = (void**)a5;
- uint32_t fd_io_uring = syscall(sys_io_uring_setup, entries, setup_params);
- uint32_t sq_ring_sz =
- setup_params->sq_off.array + setup_params->sq_entries * sizeof(uint32_t);
- uint32_t cq_ring_sz = setup_params->cq_off.cqes +
- setup_params->cq_entries * SIZEOF_IO_URING_CQE;
- uint32_t ring_sz = sq_ring_sz > cq_ring_sz ? sq_ring_sz : cq_ring_sz;
- *ring_ptr_out = mmap(vma1, ring_sz, PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_POPULATE | MAP_FIXED, fd_io_uring,
- IORING_OFF_SQ_RING);
- uint32_t sqes_sz = setup_params->sq_entries * SIZEOF_IO_URING_SQE;
- *sqes_ptr_out =
- mmap(vma2, sqes_sz, PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_POPULATE | MAP_FIXED, fd_io_uring, IORING_OFF_SQES);
- return fd_io_uring;
-}
-
-static long syz_io_uring_submit(volatile long a0, volatile long a1,
- volatile long a2, volatile long a3)
-{
- char* ring_ptr = (char*)a0;
- char* sqes_ptr = (char*)a1;
- char* sqe = (char*)a2;
- uint32_t sqes_index = (uint32_t)a3;
- uint32_t sq_ring_entries = *(uint32_t*)(ring_ptr + SQ_RING_ENTRIES_OFFSET);
- uint32_t cq_ring_entries = *(uint32_t*)(ring_ptr + CQ_RING_ENTRIES_OFFSET);
- uint32_t sq_array_off =
- (CQ_CQES_OFFSET + cq_ring_entries * SIZEOF_IO_URING_CQE + 63) & ~63;
- if (sq_ring_entries)
- sqes_index %= sq_ring_entries;
- char* sqe_dest = sqes_ptr + sqes_index * SIZEOF_IO_URING_SQE;
- memcpy(sqe_dest, sqe, SIZEOF_IO_URING_SQE);
- uint32_t sq_ring_mask = *(uint32_t*)(ring_ptr + SQ_RING_MASK_OFFSET);
- uint32_t* sq_tail_ptr = (uint32_t*)(ring_ptr + SQ_TAIL_OFFSET);
- uint32_t sq_tail = *sq_tail_ptr & sq_ring_mask;
- uint32_t sq_tail_next = *sq_tail_ptr + 1;
- uint32_t* sq_array = (uint32_t*)(ring_ptr + sq_array_off);
- *(sq_array + sq_tail) = sqes_index;
- __atomic_store_n(sq_tail_ptr, sq_tail_next, __ATOMIC_RELEASE);
- return 0;
-}
-
-static void kill_and_wait(int pid, int* status)
-{
- kill(-pid, SIGKILL);
- kill(pid, SIGKILL);
- for (int i = 0; i < 100; i++) {
- if (waitpid(-1, status, WNOHANG | __WALL) == pid)
- return;
- usleep(1000);
- }
- DIR* dir = opendir("/sys/fs/fuse/connections");
- if (dir) {
- for (;;) {
- struct dirent* ent = readdir(dir);
- if (!ent)
- break;
- if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
- continue;
- char abort[300];
- snprintf(abort, sizeof(abort), "/sys/fs/fuse/connections/%s/abort",
- ent->d_name);
- int fd = open(abort, O_WRONLY);
- if (fd == -1) {
- continue;
- }
- if (write(fd, abort, 1) < 0) {
- }
- close(fd);
- }
- closedir(dir);
- } else {
- }
- while (waitpid(-1, status, __WALL) != pid) {
- }
-}
-
-static void setup_test(void)
-{
- prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
- setpgrp();
-}
-
-struct thread_t {
- int created, call;
- event_t ready, done;
-};
-
-static struct thread_t threads[16];
-static void execute_call(int call);
-static int running;
-
-static void* thr(void* arg)
-{
- struct thread_t* th = (struct thread_t*)arg;
- for (;;) {
- event_wait(&th->ready);
- event_reset(&th->ready);
- execute_call(th->call);
- __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
- event_set(&th->done);
- }
- return 0;
-}
-
-static void execute_one(void)
-{
- int i, call, thread;
- for (call = 0; call < 4; call++) {
- for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
- thread++) {
- struct thread_t* th = &threads[thread];
- if (!th->created) {
- th->created = 1;
- event_init(&th->ready);
- event_init(&th->done);
- event_set(&th->done);
- thread_start(thr, th);
- }
- if (!event_isset(&th->done))
- continue;
- event_reset(&th->done);
- th->call = call;
- __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
- event_set(&th->ready);
- event_timedwait(&th->done, 50);
- break;
- }
- }
- for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
- sleep_ms(1);
-}
-
-static void execute_one(void);
-
-#define WAIT_FLAGS __WALL
-
-static void loop(void)
-{
- int iter = 0;
- for (; iter < 5000; iter++) {
- int pid = fork();
- if (pid < 0)
- exit(1);
- if (pid == 0) {
- setup_test();
- execute_one();
- exit(0);
- }
- int status = 0;
- uint64_t start = current_time_ms();
- for (;;) {
- if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
- break;
- sleep_ms(1);
- if (current_time_ms() - start < 5000)
- continue;
- kill_and_wait(pid, &status);
- break;
- }
- }
-}
-
-#ifndef __NR_io_uring_enter
-#define __NR_io_uring_enter 426
-#endif
-
-static uint64_t r[4] = {0xffffffffffffffff, 0xffffffffffffffff, 0x0, 0x0};
-
-void execute_call(int call)
-{
- intptr_t res = 0;
- switch (call) {
- case 0:
- *(uint64_t*)0x200000c0 = 0;
- res = syscall(__NR_signalfd4, -1, 0x200000c0ul, 8ul, 0ul);
- if (res != -1)
- r[0] = res;
- break;
- case 1:
- *(uint32_t*)0x20000a84 = 0;
- *(uint32_t*)0x20000a88 = 0;
- *(uint32_t*)0x20000a8c = 0;
- *(uint32_t*)0x20000a90 = 0;
- *(uint32_t*)0x20000a98 = -1;
- memset((void*)0x20000a9c, 0, 12);
- res = -1;
- res = syz_io_uring_setup(0x87, 0x20000a80, 0x206d6000, 0x206d7000,
- 0x20000000, 0x20000040);
- if (res != -1) {
- r[1] = res;
- r[2] = *(uint64_t*)0x20000000;
- r[3] = *(uint64_t*)0x20000040;
- }
- break;
- case 2:
- *(uint8_t*)0x20002240 = 6;
- *(uint8_t*)0x20002241 = 0;
- *(uint16_t*)0x20002242 = 0;
- *(uint32_t*)0x20002244 = r[0];
- *(uint64_t*)0x20002248 = 0;
- *(uint64_t*)0x20002250 = 0;
- *(uint32_t*)0x20002258 = 0;
- *(uint16_t*)0x2000225c = 0;
- *(uint16_t*)0x2000225e = 0;
- *(uint64_t*)0x20002260 = 0;
- *(uint16_t*)0x20002268 = 0;
- *(uint16_t*)0x2000226a = 0;
- memset((void*)0x2000226c, 0, 20);
- syz_io_uring_submit(r[2], r[3], 0x20002240, 0);
- break;
- case 3:
- syscall(__NR_io_uring_enter, r[1], 0x1523a, 0, 0ul, 0ul, 0xaul);
- break;
- }
-}
-
-int main(int argc, char *argv[])
-{
- void *ret;
-
-#if !defined(__i386) && !defined(__x86_64__)
- return 0;
-#endif
-
- if (argc > 1)
- return 0;
-
- ret = mmap((void *)0x1ffff000ul, 0x1000ul, 0ul, MAP_ANON|MAP_PRIVATE, -1, 0ul);
- if (ret == MAP_FAILED)
- return 0;
- ret = mmap((void *)0x20000000ul, 0x1000000ul, 7ul, MAP_ANON|MAP_PRIVATE, -1, 0ul);
- if (ret == MAP_FAILED)
- return 0;
- ret = mmap((void *)0x21000000ul, 0x1000ul, 0ul, MAP_ANON|MAP_PRIVATE, -1, 0ul);
- if (ret == MAP_FAILED)
- return 0;
- loop();
- return 0;
-}
-
-#else /* __NR_futex */
-
-int main(int argc, char *argv[])
-{
- return 0;
-}
-
-#endif /* __NR_futex */
diff --git a/contrib/libs/liburing/test/read-mshot-empty.c b/contrib/libs/liburing/test/read-mshot-empty.c
new file mode 100644
index 0000000000..2fc5a63184
--- /dev/null
+++ b/contrib/libs/liburing/test/read-mshot-empty.c
@@ -0,0 +1,154 @@
+#include "../config-host.h"
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: test that multishot read correctly keeps reading until all
+ * data has been emptied. the original implementation failed
+ * to do so, if the available buffer size was less than what
+ * was available, hence requiring multiple reads to empty the
+ * file buffer.
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <pthread.h>
+#include <sys/time.h>
+
+#include "liburing.h"
+#include "helpers.h"
+
+#define BGID 17
+#define NR_BUFS 4
+#define BR_MASK (NR_BUFS - 1)
+#define BUF_SIZE 32
+
+static int do_write(int fd, void *buf, int buf_size)
+{
+ int ret;
+
+ ret = write(fd, buf, buf_size);
+ if (ret < 0) {
+ perror("write");
+ return 0;
+ } else if (ret != buf_size) {
+ fprintf(stderr, "bad write size %d\n", ret);
+ return 0;
+ }
+
+ return 1;
+}
+
+static void *thread_fn(void *data)
+{
+ char w1[BUF_SIZE], w2[BUF_SIZE];
+ int *fds = data;
+
+ memset(w1, 0x11, BUF_SIZE);
+ memset(w2, 0x22, BUF_SIZE);
+
+ if (!do_write(fds[1], w1, BUF_SIZE))
+ return NULL;
+ if (!do_write(fds[1], w2, BUF_SIZE))
+ return NULL;
+
+ usleep(100000);
+
+ if (!do_write(fds[1], w1, BUF_SIZE))
+ return NULL;
+ if (!do_write(fds[1], w2, BUF_SIZE))
+ return NULL;
+
+ return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+ struct io_uring_buf_ring *br;
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ struct io_uring ring;
+ pthread_t thread;
+ int i, ret, fds[2];
+ void *buf, *tret;
+
+ if (argc > 1)
+ return T_EXIT_SKIP;
+
+ if (pipe(fds) < 0) {
+ perror("pipe");
+ return T_EXIT_FAIL;
+ }
+
+ ret = io_uring_queue_init(8, &ring, 0);
+ if (ret) {
+ fprintf(stderr, "queue_init: %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ br = io_uring_setup_buf_ring(&ring, NR_BUFS, BGID, 0, &ret);
+ if (!br) {
+ if (ret == -EINVAL)
+ return T_EXIT_SKIP;
+ fprintf(stderr, "failed buffer ring %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ buf = malloc(NR_BUFS * BUF_SIZE);
+ for (i = 0; i < NR_BUFS; i++) {
+ void *this_buf = buf + i * BUF_SIZE;
+
+ io_uring_buf_ring_add(br, this_buf, BUF_SIZE, i, BR_MASK, i);
+ }
+ io_uring_buf_ring_advance(br, NR_BUFS);
+
+ sqe = io_uring_get_sqe(&ring);
+ io_uring_prep_read_multishot(sqe, fds[0], 0, 0, BGID);
+
+ ret = io_uring_submit(&ring);
+ if (ret != 1) {
+ fprintf(stderr, "bad submit %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ /*
+ * read multishot not available would be ready as a cqe when
+ * submission returns, check and skip if not.
+ */
+ ret = io_uring_peek_cqe(&ring, &cqe);
+ if (!ret) {
+ if (cqe->res == -EINVAL || cqe->res == -EBADF)
+ return T_EXIT_SKIP;
+ }
+
+ pthread_create(&thread, NULL, thread_fn, fds);
+
+ for (i = 0; i < 4; i++) {
+ int buf_index;
+
+ ret = io_uring_wait_cqe(&ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait %d\n", ret);
+ break;
+ }
+
+ if (cqe->res != BUF_SIZE) {
+ fprintf(stderr, "size %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ if (!(cqe->flags & IORING_CQE_F_BUFFER)) {
+ fprintf(stderr, "buffer not set\n");
+ return T_EXIT_FAIL;
+ }
+ if (!(cqe->flags & IORING_CQE_F_MORE)) {
+ fprintf(stderr, "more not set\n");
+ return T_EXIT_FAIL;
+ }
+ buf_index = cqe->flags >> 16;
+ assert(buf_index >= 0 && buf_index <= NR_BUFS);
+ io_uring_cqe_seen(&ring, cqe);
+ }
+
+ pthread_join(thread, &tret);
+ return T_EXIT_PASS;
+}
diff --git a/contrib/libs/liburing/test/read-mshot-empty.t/ya.make b/contrib/libs/liburing/test/read-mshot-empty.t/ya.make
new file mode 100644
index 0000000000..b72fbc2cb8
--- /dev/null
+++ b/contrib/libs/liburing/test/read-mshot-empty.t/ya.make
@@ -0,0 +1,33 @@
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
+WITHOUT_LICENSE_TEXTS()
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/liburing
+)
+
+ADDINCL(
+ contrib/libs/liburing/src/include
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_RUNTIME()
+
+CFLAGS(
+ -DLIBURING_BUILD_TEST
+ -D__SANE_USERSPACE_TYPES__
+)
+
+SRCDIR(contrib/libs/liburing/test)
+
+SRCS(
+ helpers.c
+ read-mshot-empty.c
+)
+
+END()
diff --git a/contrib/libs/liburing/test/read-mshot.c b/contrib/libs/liburing/test/read-mshot.c
new file mode 100644
index 0000000000..681a306ad4
--- /dev/null
+++ b/contrib/libs/liburing/test/read-mshot.c
@@ -0,0 +1,405 @@
+#include "../config-host.h"
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: test multishot read (IORING_OP_READ_MULTISHOT) on pipes,
+ * using ring provided buffers
+ *
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "liburing.h"
+#include "helpers.h"
+
+#define BUF_SIZE 32
+#define BUF_SIZE_FIRST 17
+#define NR_BUFS 64
+#define BUF_BGID 1
+
+#define BR_MASK (NR_BUFS - 1)
+
+#define NR_OVERFLOW (NR_BUFS / 4)
+
+static int no_buf_ring, no_read_mshot;
+
+static int test_clamp(void)
+{
+ struct io_uring_buf_ring *br;
+ struct io_uring_params p = { };
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ struct io_uring ring;
+ int ret, fds[2], i;
+ char tmp[32];
+ char *buf;
+ void *ptr;
+
+ ret = io_uring_queue_init_params(4, &ring, &p);
+ if (ret) {
+ fprintf(stderr, "ring setup failed: %d\n", ret);
+ return 1;
+ }
+
+ if (pipe(fds) < 0) {
+ perror("pipe");
+ return 1;
+ }
+
+ if (posix_memalign((void **) &buf, 4096, NR_BUFS * BUF_SIZE))
+ return 1;
+
+ br = io_uring_setup_buf_ring(&ring, NR_BUFS, BUF_BGID, 0, &ret);
+ if (!br) {
+ if (ret == -EINVAL) {
+ no_buf_ring = 1;
+ return 0;
+ }
+ fprintf(stderr, "Buffer ring register failed %d\n", ret);
+ return 1;
+ }
+
+ ptr = buf;
+ io_uring_buf_ring_add(br, buf, 16, 1, BR_MASK, 0);
+ buf += 16;
+ io_uring_buf_ring_add(br, buf, 32, 2, BR_MASK, 1);
+ buf += 32;
+ io_uring_buf_ring_add(br, buf, 32, 3, BR_MASK, 2);
+ buf += 32;
+ io_uring_buf_ring_add(br, buf, 32, 4, BR_MASK, 3);
+ buf += 32;
+ io_uring_buf_ring_advance(br, 4);
+
+ memset(tmp, 0xaa, sizeof(tmp));
+
+ sqe = io_uring_get_sqe(&ring);
+ io_uring_prep_read_multishot(sqe, fds[0], 0, 0, BUF_BGID);
+
+ ret = io_uring_submit(&ring);
+ if (ret != 1) {
+ fprintf(stderr, "submit: %d\n", ret);
+ return 1;
+ }
+
+ /* prevent pipe buffer merging */
+ usleep(1000);
+ ret = write(fds[1], tmp, 16);
+
+ usleep(1000);
+ ret = write(fds[1], tmp, sizeof(tmp));
+
+ /* prevent pipe buffer merging */
+ usleep(1000);
+ ret = write(fds[1], tmp, 16);
+
+ usleep(1000);
+ ret = write(fds[1], tmp, sizeof(tmp));
+
+ /*
+ * We should see a 16 byte completion, then a 32 byte, then a 16 byte,
+ * and finally a 32 byte again.
+ */
+ for (i = 0; i < 4; i++) {
+ ret = io_uring_wait_cqe(&ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait cqe failed %d\n", ret);
+ return 1;
+ }
+ if (cqe->res < 0) {
+ fprintf(stderr, "cqe res: %d\n", cqe->res);
+ return 1;
+ }
+ if (!(cqe->flags & IORING_CQE_F_MORE)) {
+ fprintf(stderr, "no more cqes\n");
+ return 1;
+ }
+ if (i == 0 || i == 2) {
+ if (cqe->res != 16) {
+ fprintf(stderr, "%d cqe got %d\n", i, cqe->res);
+ return 1;
+ }
+ } else if (i == 1 || i == 3) {
+ if (cqe->res != 32) {
+ fprintf(stderr, "%d cqe got %d\n", i, cqe->res);
+ return 1;
+ }
+ }
+ io_uring_cqe_seen(&ring, cqe);
+ }
+
+ io_uring_queue_exit(&ring);
+ free(ptr);
+ return 0;
+}
+
+static int test(int first_good, int async, int overflow)
+{
+ struct io_uring_buf_ring *br;
+ struct io_uring_params p = { };
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ struct io_uring ring;
+ int ret, fds[2], i;
+ char tmp[32];
+ void *ptr[NR_BUFS];
+
+ p.flags = IORING_SETUP_CQSIZE;
+ if (!overflow)
+ p.cq_entries = NR_BUFS + 1;
+ else
+ p.cq_entries = NR_OVERFLOW;
+ ret = io_uring_queue_init_params(1, &ring, &p);
+ if (ret) {
+ fprintf(stderr, "ring setup failed: %d\n", ret);
+ return 1;
+ }
+
+ if (pipe(fds) < 0) {
+ perror("pipe");
+ return 1;
+ }
+
+ br = io_uring_setup_buf_ring(&ring, NR_BUFS, BUF_BGID, 0, &ret);
+ if (!br) {
+ if (ret == -EINVAL) {
+ no_buf_ring = 1;
+ return 0;
+ }
+ fprintf(stderr, "Buffer ring register failed %d\n", ret);
+ return 1;
+ }
+
+ for (i = 0; i < NR_BUFS; i++) {
+ unsigned size = i <= 1 ? BUF_SIZE_FIRST : BUF_SIZE;
+ ptr[i] = malloc(size);
+ if (!ptr[i])
+ return 1;
+ io_uring_buf_ring_add(br, ptr[i], size, i + 1, BR_MASK, i);
+ }
+ io_uring_buf_ring_advance(br, NR_BUFS);
+
+ if (first_good) {
+ sprintf(tmp, "this is buffer %d\n", 0);
+ ret = write(fds[1], tmp, strlen(tmp));
+ }
+
+ sqe = io_uring_get_sqe(&ring);
+ /* len == 0 means just use the defined provided buffer length */
+ io_uring_prep_read_multishot(sqe, fds[0], 0, 0, BUF_BGID);
+ if (async)
+ sqe->flags |= IOSQE_ASYNC;
+
+ ret = io_uring_submit(&ring);
+ if (ret != 1) {
+ fprintf(stderr, "submit: %d\n", ret);
+ return 1;
+ }
+
+ /* write NR_BUFS + 1, or if first_good is set, NR_BUFS */
+ for (i = 0; i < NR_BUFS + !first_good; i++) {
+ /* prevent pipe buffer merging */
+ usleep(1000);
+ sprintf(tmp, "this is buffer %d\n", i + 1);
+ ret = write(fds[1], tmp, strlen(tmp));
+ if (ret != strlen(tmp)) {
+ fprintf(stderr, "write ret %d\n", ret);
+ return 1;
+ }
+ }
+
+ for (i = 0; i < NR_BUFS + 1; i++) {
+ ret = io_uring_wait_cqe(&ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait cqe failed %d\n", ret);
+ return 1;
+ }
+ if (cqe->res < 0) {
+ /* expected failure as we try to read one too many */
+ if (cqe->res == -ENOBUFS && i == NR_BUFS)
+ break;
+ if (!i && cqe->res == -EINVAL) {
+ no_read_mshot = 1;
+ break;
+ }
+ fprintf(stderr, "%d: cqe res %d\n", i, cqe->res);
+ return 1;
+ } else if (i > 9 && cqe->res <= 17) {
+ fprintf(stderr, "truncated message %d %d\n", i, cqe->res);
+ return 1;
+ }
+
+ if (!(cqe->flags & IORING_CQE_F_BUFFER)) {
+ fprintf(stderr, "no buffer selected\n");
+ return 1;
+ }
+ if (!(cqe->flags & IORING_CQE_F_MORE)) {
+ /* we expect this on overflow */
+ if (overflow && i >= NR_OVERFLOW)
+ break;
+ fprintf(stderr, "no more cqes\n");
+ return 1;
+ }
+ /* should've overflown! */
+ if (overflow && i > NR_OVERFLOW) {
+ fprintf(stderr, "Expected overflow!\n");
+ return 1;
+ }
+ io_uring_cqe_seen(&ring, cqe);
+ }
+
+ io_uring_queue_exit(&ring);
+ for (i = 0; i < NR_BUFS; i++)
+ free(ptr[i]);
+ return 0;
+}
+
+static int test_invalid(int async)
+{
+ struct io_uring_buf_ring *br;
+ struct io_uring_params p = { };
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ struct io_uring ring;
+ char fname[32] = ".mshot.%d.XXXXXX";
+ int ret, fd;
+ char *buf;
+
+ p.flags = IORING_SETUP_CQSIZE;
+ p.cq_entries = NR_BUFS;
+ ret = io_uring_queue_init_params(1, &ring, &p);
+ if (ret) {
+ fprintf(stderr, "ring setup failed: %d\n", ret);
+ return 1;
+ }
+
+ fd = mkstemp(fname);
+ if (fd < 0) {
+ perror("mkstemp");
+ return 1;
+ }
+ unlink(fname);
+
+ if (posix_memalign((void **) &buf, 4096, BUF_SIZE))
+ return 1;
+
+ br = io_uring_setup_buf_ring(&ring, 1, BUF_BGID, 0, &ret);
+ if (!br) {
+ fprintf(stderr, "Buffer ring register failed %d\n", ret);
+ return 1;
+ }
+
+ io_uring_buf_ring_add(br, buf, BUF_SIZE, 1, BR_MASK, 0);
+ io_uring_buf_ring_advance(br, 1);
+
+ sqe = io_uring_get_sqe(&ring);
+ /* len == 0 means just use the defined provided buffer length */
+ io_uring_prep_read_multishot(sqe, fd, 0, 0, BUF_BGID);
+ if (async)
+ sqe->flags |= IOSQE_ASYNC;
+
+ ret = io_uring_submit(&ring);
+ if (ret != 1) {
+ fprintf(stderr, "submit: %d\n", ret);
+ return 1;
+ }
+
+ ret = io_uring_wait_cqe(&ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait cqe failed %d\n", ret);
+ return 1;
+ }
+ if (cqe->flags & IORING_CQE_F_MORE) {
+ fprintf(stderr, "MORE flag set unexpected %d\n", cqe->flags);
+ return 1;
+ }
+ if (cqe->res != -EBADFD) {
+ fprintf(stderr, "Got cqe res %d, wanted -EBADFD\n", cqe->res);
+ return 1;
+ }
+
+ io_uring_cqe_seen(&ring, cqe);
+ io_uring_queue_exit(&ring);
+ free(buf);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+
+ if (argc > 1)
+ return T_EXIT_SKIP;
+
+ ret = test(0, 0, 0);
+ if (ret) {
+ fprintf(stderr, "test 0 0 0 failed\n");
+ return T_EXIT_FAIL;
+ }
+ if (no_buf_ring || no_read_mshot)
+ return T_EXIT_SKIP;
+
+ ret = test(0, 1, 0);
+ if (ret) {
+ fprintf(stderr, "test 0 1 0, failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test(1, 0, 0);
+ if (ret) {
+ fprintf(stderr, "test 1 0 0 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test(0, 0, 1);
+ if (ret) {
+ fprintf(stderr, "test 0 0 1 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test(0, 1, 1);
+ if (ret) {
+ fprintf(stderr, "test 0 1 1 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test(1, 0, 1);
+ if (ret) {
+ fprintf(stderr, "test 1 0 1, failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test(1, 0, 1);
+ if (ret) {
+ fprintf(stderr, "test 1 0 1 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test(1, 1, 1);
+ if (ret) {
+ fprintf(stderr, "test 1 1 1 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test_invalid(0);
+ if (ret) {
+ fprintf(stderr, "test_invalid 0 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test_invalid(1);
+ if (ret) {
+ fprintf(stderr, "test_invalid 1 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test_clamp();
+ if (ret) {
+ fprintf(stderr, "test_clamp failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ return T_EXIT_PASS;
+}
diff --git a/contrib/libs/liburing/test/read-mshot.t/ya.make b/contrib/libs/liburing/test/read-mshot.t/ya.make
new file mode 100644
index 0000000000..ba64db60ba
--- /dev/null
+++ b/contrib/libs/liburing/test/read-mshot.t/ya.make
@@ -0,0 +1,33 @@
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
+WITHOUT_LICENSE_TEXTS()
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/liburing
+)
+
+ADDINCL(
+ contrib/libs/liburing/src/include
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_RUNTIME()
+
+CFLAGS(
+ -DLIBURING_BUILD_TEST
+ -D__SANE_USERSPACE_TYPES__
+)
+
+SRCDIR(contrib/libs/liburing/test)
+
+SRCS(
+ helpers.c
+ read-mshot.c
+)
+
+END()
diff --git a/contrib/libs/liburing/test/recv-multishot.c b/contrib/libs/liburing/test/recv-multishot.c
index c80fa18547..de07809f0d 100644
--- a/contrib/libs/liburing/test/recv-multishot.c
+++ b/contrib/libs/liburing/test/recv-multishot.c
@@ -58,7 +58,7 @@ static int test(struct args *args)
int const N = 8;
int const N_BUFFS = N * 64;
int const N_CQE_OVERFLOW = 4;
- int const min_cqes = 2;
+ int const min_cqes = args->early_error ? 2 : 8;
int const NAME_LEN = sizeof(struct sockaddr_storage);
int const CONTROL_LEN = CMSG_ALIGN(sizeof(struct sockaddr_storage))
+ sizeof(struct cmsghdr);
@@ -238,7 +238,11 @@ static int test(struct args *args)
usleep(1000);
if ((args->stream && !early_error) || recv_cqes < min_cqes) {
- ret = io_uring_wait_cqes(&ring, &cqe, 1, &timeout, NULL);
+ unsigned int to_wait = 1;
+
+ if (recv_cqes < min_cqes)
+ to_wait = min_cqes - recv_cqes;
+ ret = io_uring_wait_cqes(&ring, &cqe, to_wait, &timeout, NULL);
if (ret && ret != -ETIME) {
fprintf(stderr, "wait final failed: %d\n", ret);
ret = -1;
@@ -272,7 +276,7 @@ static int test(struct args *args)
*/
bool const early_last = args->early_error == ERROR_EARLY_OVERFLOW &&
!args->wait_each &&
- i == N_CQE_OVERFLOW &&
+ i >= N_CQE_OVERFLOW &&
!(cqe->flags & IORING_CQE_F_MORE);
bool const should_be_last =
diff --git a/contrib/libs/liburing/test/reg-fd-only.c b/contrib/libs/liburing/test/reg-fd-only.c
new file mode 100644
index 0000000000..1ff6ea250e
--- /dev/null
+++ b/contrib/libs/liburing/test/reg-fd-only.c
@@ -0,0 +1,132 @@
+#include "../config-host.h"
+/* SPDX-License-Identifier: MIT */
+/*
+ * Test io_uring_setup with IORING_SETUP_REGISTERED_FD_ONLY
+ *
+ */
+#include <stdio.h>
+
+#include "helpers.h"
+
+#define NORMAL_PAGE_ENTRIES 8
+#define HUGE_PAGE_ENTRIES 512
+
+static int no_mmap;
+
+static int test_nops(struct io_uring *ring, int sq_size, int nr_nops)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ int i, ret;
+
+ do {
+ int todo = nr_nops;
+
+ if (todo > sq_size)
+ todo = sq_size;
+
+ for (i = 0; i < todo; i++) {
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_nop(sqe);
+ }
+
+ ret = io_uring_submit(ring);
+ if (ret != todo) {
+ fprintf(stderr, "short submit %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ for (i = 0; i < todo; i++) {
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait err %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ io_uring_cqe_seen(ring, cqe);
+ }
+ nr_nops -= todo;
+ } while (nr_nops);
+
+ return T_EXIT_PASS;
+}
+
+static int test(int nentries)
+{
+ struct io_uring ring;
+ unsigned values[2];
+ int ret;
+
+ ret = io_uring_queue_init(nentries, &ring,
+ IORING_SETUP_REGISTERED_FD_ONLY | IORING_SETUP_NO_MMAP);
+ if (ret == -EINVAL) {
+ no_mmap = 1;
+ return T_EXIT_SKIP;
+ } else if (ret == -ENOMEM) {
+ fprintf(stdout, "Enable huge pages to test big rings\n");
+ return T_EXIT_SKIP;
+ } else if (ret) {
+ fprintf(stderr, "ring setup failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = io_uring_register_ring_fd(&ring);
+ if (ret != -EEXIST) {
+ fprintf(stderr, "registering already-registered ring fd should fail\n");
+ goto err;
+ }
+
+ ret = io_uring_close_ring_fd(&ring);
+ if (ret != -EBADF) {
+ fprintf(stderr, "closing already-closed ring fd should fail\n");
+ goto err;
+ }
+
+ /* Test a simple io_uring_register operation expected to work.
+ * io_uring_register_iowq_max_workers is arbitrary.
+ */
+ values[0] = values[1] = 0;
+ ret = io_uring_register_iowq_max_workers(&ring, values);
+ if (ret || (values[0] == 0 && values[1] == 0)) {
+ fprintf(stderr, "io_uring_register operation failed after closing ring fd\n");
+ goto err;
+ }
+
+ ret = test_nops(&ring, nentries, nentries * 4);
+ if (ret)
+ goto err;
+
+ io_uring_queue_exit(&ring);
+ return T_EXIT_PASS;
+
+err:
+ io_uring_queue_exit(&ring);
+ return T_EXIT_FAIL;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+
+ if (argc > 1)
+ return T_EXIT_SKIP;
+
+ /* test single normal page */
+ ret = test(NORMAL_PAGE_ENTRIES);
+ if (ret == T_EXIT_SKIP || no_mmap) {
+ return T_EXIT_SKIP;
+ } else if (ret != T_EXIT_PASS) {
+ fprintf(stderr, "test 8 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ /* test with entries requiring a huge page */
+ ret = test(HUGE_PAGE_ENTRIES);
+ if (ret == T_EXIT_SKIP) {
+ return T_EXIT_SKIP;
+ } else if (ret != T_EXIT_PASS) {
+ fprintf(stderr, "test 512 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ return T_EXIT_PASS;
+}
diff --git a/contrib/libs/liburing/test/reg-fd-only.t/ya.make b/contrib/libs/liburing/test/reg-fd-only.t/ya.make
new file mode 100644
index 0000000000..f2975eddd3
--- /dev/null
+++ b/contrib/libs/liburing/test/reg-fd-only.t/ya.make
@@ -0,0 +1,33 @@
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
+WITHOUT_LICENSE_TEXTS()
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/liburing
+)
+
+ADDINCL(
+ contrib/libs/liburing/src/include
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_RUNTIME()
+
+CFLAGS(
+ -DLIBURING_BUILD_TEST
+ -D__SANE_USERSPACE_TYPES__
+)
+
+SRCDIR(contrib/libs/liburing/test)
+
+SRCS(
+ helpers.c
+ reg-fd-only.c
+)
+
+END()
diff --git a/contrib/libs/liburing/test/ring-leak.c b/contrib/libs/liburing/test/ring-leak.c
index e052802314..6b8237fdc4 100644
--- a/contrib/libs/liburing/test/ring-leak.c
+++ b/contrib/libs/liburing/test/ring-leak.c
@@ -24,6 +24,7 @@
#include <linux/fs.h>
#include "liburing.h"
+#include "helpers.h"
#include "../src/syscall.h"
static int __io_uring_register_files(int ring_fd, int fd1, int fd2)
@@ -49,7 +50,7 @@ static int get_ring_fd(void)
return fd;
}
-static void send_fd(int socket, int fd)
+static int send_fd(int socket, int fd)
{
char buf[CMSG_SPACE(sizeof(fd))];
struct cmsghdr *cmsg;
@@ -70,8 +71,14 @@ static void send_fd(int socket, int fd)
msg.msg_controllen = CMSG_SPACE(sizeof(fd));
- if (sendmsg(socket, &msg, 0) < 0)
+ if (sendmsg(socket, &msg, 0) < 0) {
+ if (errno == EINVAL)
+ return T_EXIT_SKIP;
perror("sendmsg");
+ return T_EXIT_FAIL;
+ }
+
+ return T_EXIT_PASS;
}
static int test_iowq_request_cancel(void)
@@ -167,7 +174,9 @@ static int test_scm_cycles(bool update)
perror("pipe");
return -1;
}
- send_fd(sp[0], ring.ring_fd);
+ ret = send_fd(sp[0], ring.ring_fd);
+ if (ret != T_EXIT_PASS)
+ return ret;
/* register an empty set for updates */
if (update) {
@@ -237,6 +246,8 @@ int main(int argc, char *argv[])
bool update = !!(i & 1);
ret = test_scm_cycles(update);
+ if (ret == T_EXIT_SKIP)
+ return T_EXIT_SKIP;
if (ret) {
fprintf(stderr, "test_scm_cycles() failed %i\n",
update);
@@ -260,8 +271,11 @@ int main(int argc, char *argv[])
}
pid = fork();
- if (pid)
- send_fd(sp[0], ring_fd);
+ if (pid) {
+ ret = send_fd(sp[0], ring_fd);
+ if (ret != T_EXIT_PASS)
+ return ret;
+ }
close(ring_fd);
close(sp[0]);
diff --git a/contrib/libs/liburing/test/ringbuf-status.c b/contrib/libs/liburing/test/ringbuf-status.c
new file mode 100644
index 0000000000..d4a56c7473
--- /dev/null
+++ b/contrib/libs/liburing/test/ringbuf-status.c
@@ -0,0 +1,243 @@
+#include "../config-host.h"
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: test reading provided ring buf head
+ *
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "liburing.h"
+#include "helpers.h"
+
+#define BUF_SIZE 32
+#define NR_BUFS 8
+#define FSIZE (BUF_SIZE * NR_BUFS)
+
+#define BR_MASK (NR_BUFS - 1)
+#define BGID 1
+
+static int no_buf_ring;
+static int no_buf_ring_status;
+
+static int test_max(void)
+{
+ struct io_uring_buf_ring *br;
+ struct io_uring ring;
+ int nr_bufs = 32768;
+ int ret, i;
+ char *buf;
+
+ ret = io_uring_queue_init(1, &ring, 0);
+ if (ret) {
+ fprintf(stderr, "ring setup failed: %d\n", ret);
+ return 1;
+ }
+
+ if (posix_memalign((void **) &buf, 4096, FSIZE))
+ return 1;
+
+ br = io_uring_setup_buf_ring(&ring, nr_bufs, BGID, 0, &ret);
+ if (!br) {
+ fprintf(stderr, "Buffer ring register failed %d\n", ret);
+ return 1;
+ }
+
+ ret = io_uring_buf_ring_available(&ring, br, BGID);
+ if (ret) {
+ fprintf(stderr, "Bad available count %d\n", ret);
+ return 1;
+ }
+
+ for (i = 0; i < nr_bufs / 2; i++)
+ io_uring_buf_ring_add(br, buf, BUF_SIZE, i + 1, nr_bufs - 1, i);
+ io_uring_buf_ring_advance(br, nr_bufs / 2);
+
+ ret = io_uring_buf_ring_available(&ring, br, BGID);
+ if (ret != nr_bufs / 2) {
+ fprintf(stderr, "Bad half full available count %d\n", ret);
+ return 1;
+ }
+
+ for (i = 0; i < nr_bufs / 2; i++)
+ io_uring_buf_ring_add(br, buf, BUF_SIZE, i + 1, nr_bufs - 1, i);
+ io_uring_buf_ring_advance(br, nr_bufs / 2);
+
+ ret = io_uring_buf_ring_available(&ring, br, BGID);
+ if (ret != nr_bufs) {
+ fprintf(stderr, "Bad half full available count %d\n", ret);
+ return 1;
+ }
+
+ free(buf);
+ io_uring_queue_exit(&ring);
+ return T_EXIT_PASS;
+}
+
+static int test(int invalid)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ struct io_uring ring;
+ struct io_uring_buf_ring *br;
+ int ret, i, fds[2];
+ uint16_t head;
+ char *buf;
+ void *ptr;
+ char output[16];
+
+ memset(output, 0x55, sizeof(output));
+
+ ret = io_uring_queue_init(NR_BUFS, &ring, 0);
+ if (ret) {
+ fprintf(stderr, "ring setup failed: %d\n", ret);
+ return 1;
+ }
+
+ if (pipe(fds) < 0) {
+ perror("pipe");
+ return T_EXIT_FAIL;
+ }
+
+ if (posix_memalign((void **) &buf, 4096, FSIZE))
+ return 1;
+
+ br = io_uring_setup_buf_ring(&ring, NR_BUFS, BGID, 0, &ret);
+ if (!br) {
+ if (ret == -EINVAL) {
+ no_buf_ring = 1;
+ return 0;
+ }
+ fprintf(stderr, "Buffer ring register failed %d\n", ret);
+ return 1;
+ }
+
+ ptr = buf;
+ for (i = 0; i < NR_BUFS; i++) {
+ io_uring_buf_ring_add(br, ptr, BUF_SIZE, i + 1, BR_MASK, i);
+ ptr += BUF_SIZE;
+ }
+ io_uring_buf_ring_advance(br, NR_BUFS);
+
+ /* head should be zero at this point */
+ head = 1;
+ if (!invalid)
+ ret = io_uring_buf_ring_head(&ring, BGID, &head);
+ else
+ ret = io_uring_buf_ring_head(&ring, BGID + 10, &head);
+ if (ret) {
+ if (ret == -EINVAL) {
+ no_buf_ring_status = 1;
+ return T_EXIT_SKIP;
+ }
+ if (invalid && ret == -ENOENT)
+ return T_EXIT_PASS;
+ fprintf(stderr, "buf_ring_head: %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ if (invalid) {
+ fprintf(stderr, "lookup of bad group id succeeded\n");
+ return T_EXIT_FAIL;
+ }
+ if (head != 0) {
+ fprintf(stderr, "bad head %d\n", head);
+ return T_EXIT_FAIL;
+ }
+
+ ret = io_uring_buf_ring_available(&ring, br, BGID);
+ if (ret != NR_BUFS) {
+ fprintf(stderr, "ring available %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ sqe = io_uring_get_sqe(&ring);
+ io_uring_prep_read(sqe, fds[0], NULL, BUF_SIZE, i * BUF_SIZE);
+ sqe->buf_group = BGID;
+ sqe->flags |= IOSQE_BUFFER_SELECT;
+ sqe->user_data = 1;
+
+ ret = io_uring_submit(&ring);
+ if (ret != 1) {
+ fprintf(stderr, "submit: %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ /* head should still be zero at this point, no buffers consumed */
+ head = 1;
+ ret = io_uring_buf_ring_head(&ring, BGID, &head);
+ if (head != 0) {
+ fprintf(stderr, "bad head after submit %d\n", head);
+ return T_EXIT_FAIL;
+ }
+
+ ret = write(fds[1], output, sizeof(output));
+ if (ret != sizeof(output)) {
+ fprintf(stderr, "pipe buffer write %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ ret = io_uring_wait_cqe(&ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "wait cqe failed %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ if (cqe->res != sizeof(output)) {
+ fprintf(stderr, "cqe res %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ if (!(cqe->flags & IORING_CQE_F_BUFFER)) {
+ fprintf(stderr, "no buffer selected\n");
+ return T_EXIT_FAIL;
+ }
+ io_uring_cqe_seen(&ring, cqe);
+
+ /* head should now be one, we consumed a buffer */
+ ret = io_uring_buf_ring_head(&ring, BGID, &head);
+ if (head != 1) {
+ fprintf(stderr, "bad head after cqe %d\n", head);
+ return T_EXIT_FAIL;
+ }
+
+ ret = io_uring_buf_ring_available(&ring, br, BGID);
+ if (ret != NR_BUFS - 1) {
+ fprintf(stderr, "ring available %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ close(fds[0]);
+ close(fds[1]);
+ free(buf);
+ io_uring_queue_exit(&ring);
+ return T_EXIT_PASS;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+
+ ret = test(0);
+ if (ret == T_EXIT_FAIL) {
+ fprintf(stderr, "test 0 failed\n");
+ return T_EXIT_FAIL;
+ }
+ if (no_buf_ring || no_buf_ring_status)
+ return T_EXIT_SKIP;
+
+ ret = test(1);
+ if (ret == T_EXIT_FAIL) {
+ fprintf(stderr, "test 1 failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test_max();
+ if (ret == T_EXIT_FAIL) {
+ fprintf(stderr, "test_max failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ return T_EXIT_PASS;
+}
diff --git a/contrib/libs/liburing/test/ringbuf-status.t/ya.make b/contrib/libs/liburing/test/ringbuf-status.t/ya.make
new file mode 100644
index 0000000000..9eaa5a50b9
--- /dev/null
+++ b/contrib/libs/liburing/test/ringbuf-status.t/ya.make
@@ -0,0 +1,33 @@
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
+WITHOUT_LICENSE_TEXTS()
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/liburing
+)
+
+ADDINCL(
+ contrib/libs/liburing/src/include
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_RUNTIME()
+
+CFLAGS(
+ -DLIBURING_BUILD_TEST
+ -D__SANE_USERSPACE_TYPES__
+)
+
+SRCDIR(contrib/libs/liburing/test)
+
+SRCS(
+ helpers.c
+ ringbuf-status.c
+)
+
+END()
diff --git a/contrib/libs/liburing/test/send-zerocopy.c b/contrib/libs/liburing/test/send-zerocopy.c
index 27300f9209..dab707d1e5 100644
--- a/contrib/libs/liburing/test/send-zerocopy.c
+++ b/contrib/libs/liburing/test/send-zerocopy.c
@@ -69,8 +69,37 @@ enum {
static size_t page_sz;
static char *tx_buffer, *rx_buffer;
static struct iovec buffers_iov[__BUF_NR];
+
+static bool has_sendzc;
static bool has_sendmsg;
+static int probe_zc_support(void)
+{
+ struct io_uring ring;
+ struct io_uring_probe *p;
+ int ret;
+
+ has_sendzc = has_sendmsg = false;
+
+ ret = io_uring_queue_init(1, &ring, 0);
+ if (ret)
+ return -1;
+
+ p = t_calloc(1, sizeof(*p) + 256 * sizeof(struct io_uring_probe_op));
+ if (!p)
+ return -1;
+
+ ret = io_uring_register_probe(&ring, p, 256);
+ if (ret)
+ return -1;
+
+ has_sendzc = p->ops_len > IORING_OP_SEND_ZC;
+ has_sendmsg = p->ops_len > IORING_OP_SENDMSG_ZC;
+ io_uring_queue_exit(&ring);
+ free(p);
+ return 0;
+}
+
static bool check_cq_empty(struct io_uring *ring)
{
struct io_uring_cqe *cqe = NULL;
@@ -99,10 +128,7 @@ static int test_basic_send(struct io_uring *ring, int sock_tx, int sock_rx)
ret = io_uring_wait_cqe(ring, &cqe);
assert(!ret && cqe->user_data == 1);
- if (cqe->res == -EINVAL) {
- assert(!(cqe->flags & IORING_CQE_F_MORE));
- return T_EXIT_SKIP;
- } else if (cqe->res != payload_size) {
+ if (cqe->res != payload_size) {
fprintf(stderr, "send failed %i\n", cqe->res);
return T_EXIT_FAIL;
}
@@ -123,17 +149,60 @@ static int test_basic_send(struct io_uring *ring, int sock_tx, int sock_rx)
return T_EXIT_PASS;
}
+static int test_send_faults_check(struct io_uring *ring, int expected)
+{
+ struct io_uring_cqe *cqe;
+ int ret, nr_cqes = 0;
+ bool more = true;
+
+ while (more) {
+ nr_cqes++;
+ ret = io_uring_wait_cqe(ring, &cqe);
+ assert(!ret);
+ assert(cqe->user_data == 1);
+
+ if (nr_cqes == 1 && (cqe->flags & IORING_CQE_F_NOTIF)) {
+ fprintf(stderr, "test_send_faults_check notif came first\n");
+ return -1;
+ }
+
+ if (!(cqe->flags & IORING_CQE_F_NOTIF)) {
+ if (cqe->res != expected) {
+ fprintf(stderr, "invalid cqe res %i vs expected %i, "
+ "user_data %i\n",
+ cqe->res, expected, (int)cqe->user_data);
+ return -1;
+ }
+ } else {
+ if (cqe->res != 0 || cqe->flags != IORING_CQE_F_NOTIF) {
+ fprintf(stderr, "invalid notif cqe %i %i\n",
+ cqe->res, cqe->flags);
+ return -1;
+ }
+ }
+
+ more = cqe->flags & IORING_CQE_F_MORE;
+ io_uring_cqe_seen(ring, cqe);
+ }
+
+ if (nr_cqes > 2) {
+ fprintf(stderr, "test_send_faults_check() too many CQEs %i\n",
+ nr_cqes);
+ return -1;
+ }
+ assert(check_cq_empty(ring));
+ return 0;
+}
+
static int test_send_faults(int sock_tx, int sock_rx)
{
struct io_uring_sqe *sqe;
- struct io_uring_cqe *cqe;
int msg_flags = 0;
unsigned zc_flags = 0;
- int payload_size = 100;
- int ret, i, nr_cqes, nr_reqs = 3;
+ int ret, payload_size = 100;
struct io_uring ring;
- ret = io_uring_queue_init(32, &ring, IORING_SETUP_SUBMIT_ALL);
+ ret = io_uring_queue_init(32, &ring, 0);
if (ret) {
fprintf(stderr, "queue init failed: %d\n", ret);
return -1;
@@ -144,6 +213,14 @@ static int test_send_faults(int sock_tx, int sock_rx)
io_uring_prep_send_zc(sqe, sock_tx, (void *)1UL, payload_size,
msg_flags, zc_flags);
sqe->user_data = 1;
+ ret = io_uring_submit(&ring);
+ assert(ret == 1);
+
+ ret = test_send_faults_check(&ring, -EFAULT);
+ if (ret) {
+ fprintf(stderr, "test_send_faults with invalid buf failed\n");
+ return -1;
+ }
/* invalid address */
sqe = io_uring_get_sqe(&ring);
@@ -151,44 +228,30 @@ static int test_send_faults(int sock_tx, int sock_rx)
msg_flags, zc_flags);
io_uring_prep_send_set_addr(sqe, (const struct sockaddr *)1UL,
sizeof(struct sockaddr_in6));
- sqe->user_data = 2;
+ sqe->user_data = 1;
+ ret = io_uring_submit(&ring);
+ assert(ret == 1);
+
+ ret = test_send_faults_check(&ring, -EFAULT);
+ if (ret) {
+ fprintf(stderr, "test_send_faults with invalid addr failed\n");
+ return -1;
+ }
/* invalid send/recv flags */
sqe = io_uring_get_sqe(&ring);
io_uring_prep_send_zc(sqe, sock_tx, tx_buffer, payload_size,
msg_flags, ~0U);
- sqe->user_data = 3;
-
+ sqe->user_data = 1;
ret = io_uring_submit(&ring);
- assert(ret == nr_reqs);
-
- nr_cqes = nr_reqs;
- for (i = 0; i < nr_cqes; i++) {
- ret = io_uring_wait_cqe(&ring, &cqe);
- assert(!ret);
- assert(cqe->user_data <= nr_reqs);
-
- if (!(cqe->flags & IORING_CQE_F_NOTIF)) {
- int expected = (cqe->user_data == 3) ? -EINVAL : -EFAULT;
+ assert(ret == 1);
- if (cqe->res != expected) {
- fprintf(stderr, "invalid cqe res %i vs expected %i, "
- "user_data %i\n",
- cqe->res, expected, (int)cqe->user_data);
- return -1;
- }
- if (cqe->flags & IORING_CQE_F_MORE)
- nr_cqes++;
- } else {
- if (cqe->res != 0 || cqe->flags != IORING_CQE_F_NOTIF) {
- fprintf(stderr, "invalid notif cqe %i %i\n",
- cqe->res, cqe->flags);
- return -1;
- }
- }
- io_uring_cqe_seen(&ring, cqe);
+ ret = test_send_faults_check(&ring, -EINVAL);
+ if (ret) {
+ fprintf(stderr, "test_send_faults with invalid flags failed\n");
+ return -1;
}
- assert(check_cq_empty(&ring));
+
return T_EXIT_PASS;
}
@@ -279,6 +342,10 @@ static int create_socketpair_ip(struct sockaddr_storage *addr,
#ifdef SO_ZEROCOPY
int val = 1;
+ /*
+ * NOTE: apps must not set SO_ZEROCOPY when using io_uring zc.
+ * It's only here to test interactions with MSG_ZEROCOPY.
+ */
if (setsockopt(*sock_client, SOL_SOCKET, SO_ZEROCOPY, &val, sizeof(val))) {
perror("setsockopt zc");
return 1;
@@ -660,22 +727,6 @@ static int test_async_addr(struct io_uring *ring)
return 0;
}
-static bool io_check_zc_sendmsg(struct io_uring *ring)
-{
- struct io_uring_probe *p;
- int ret;
-
- p = t_calloc(1, sizeof(*p) + 256 * sizeof(struct io_uring_probe_op));
- if (!p) {
- fprintf(stderr, "probe allocation failed\n");
- return false;
- }
- ret = io_uring_register_probe(ring, p, 256);
- if (ret)
- return false;
- return p->ops_len > IORING_OP_SENDMSG_ZC;
-}
-
/* see also send_recv.c:test_invalid */
static int test_invalid_zc(int fds[2])
{
@@ -719,24 +770,84 @@ static int test_invalid_zc(int fds[2])
return 0;
}
-int main(int argc, char *argv[])
+static int run_basic_tests(void)
{
struct sockaddr_storage addr;
- struct io_uring ring;
- int i, ret, sp[2];
+ int ret, i, sp[2];
+
+ /* create TCP IPv6 pair */
+ ret = create_socketpair_ip(&addr, &sp[0], &sp[1], true, true, false, true);
+ if (ret) {
+ fprintf(stderr, "sock prep failed %d\n", ret);
+ return -1;
+ }
+
+ for (i = 0; i < 2; i++) {
+ struct io_uring ring;
+ unsigned ring_flags = 0;
+
+ if (i & 1)
+ ring_flags |= IORING_SETUP_DEFER_TASKRUN;
+
+ ret = io_uring_queue_init(32, &ring, ring_flags);
+ if (ret) {
+ if (ret == -EINVAL)
+ continue;
+ fprintf(stderr, "queue init failed: %d\n", ret);
+ return -1;
+ }
+
+ ret = test_basic_send(&ring, sp[0], sp[1]);
+ if (ret) {
+ fprintf(stderr, "test_basic_send() failed\n");
+ return -1;
+ }
+
+ ret = test_send_faults(sp[0], sp[1]);
+ if (ret) {
+ fprintf(stderr, "test_send_faults() failed\n");
+ return -1;
+ }
+
+ ret = test_invalid_zc(sp);
+ if (ret) {
+ fprintf(stderr, "test_invalid_zc() failed\n");
+ return -1;
+ }
+
+ ret = test_async_addr(&ring);
+ if (ret) {
+ fprintf(stderr, "test_async_addr() failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ io_uring_queue_exit(&ring);
+ }
+
+ close(sp[0]);
+ close(sp[1]);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
size_t len;
+ int ret, i;
if (argc > 1)
return T_EXIT_SKIP;
- page_sz = sysconf(_SC_PAGESIZE);
-
- /* create TCP IPv6 pair */
- ret = create_socketpair_ip(&addr, &sp[0], &sp[1], true, true, false, true);
+ ret = probe_zc_support();
if (ret) {
- fprintf(stderr, "sock prep failed %d\n", ret);
+ printf("probe failed\n");
return T_EXIT_FAIL;
}
+ if (!has_sendzc) {
+ printf("no IORING_OP_SEND_ZC support, skip\n");
+ return T_EXIT_SKIP;
+ }
+
+ page_sz = sysconf(_SC_PAGESIZE);
len = LARGE_BUF_SIZE;
tx_buffer = aligned_alloc(page_sz, len);
@@ -787,69 +898,62 @@ int main(int argc, char *argv[])
}
}
- ret = io_uring_queue_init(32, &ring, 0);
- if (ret) {
- fprintf(stderr, "queue init failed: %d\n", ret);
- return T_EXIT_FAIL;
- }
-
- ret = test_basic_send(&ring, sp[0], sp[1]);
- if (ret == T_EXIT_SKIP)
- return ret;
- if (ret) {
- fprintf(stderr, "test_basic_send() failed\n");
+ ret = run_basic_tests();
+ if (ret)
return T_EXIT_FAIL;
- }
- has_sendmsg = io_check_zc_sendmsg(&ring);
+ for (i = 0; i < 2; i++) {
+ struct io_uring ring;
+ unsigned ring_flags = 0;
- ret = test_send_faults(sp[0], sp[1]);
- if (ret) {
- fprintf(stderr, "test_send_faults() failed\n");
- return T_EXIT_FAIL;
- }
+ if (i & 1)
+ ring_flags |= IORING_SETUP_SINGLE_ISSUER |
+ IORING_SETUP_DEFER_TASKRUN;
- ret = test_invalid_zc(sp);
- if (ret) {
- fprintf(stderr, "test_invalid_zc() failed\n");
- return T_EXIT_FAIL;
- }
+ ret = io_uring_queue_init(32, &ring, ring_flags);
+ if (ret) {
+ if (ret == -EINVAL)
+ continue;
+ fprintf(stderr, "queue init failed: %d\n", ret);
+ return -1;
+ }
- close(sp[0]);
- close(sp[1]);
+ ret = t_register_buffers(&ring, buffers_iov, ARRAY_SIZE(buffers_iov));
+ if (ret == T_SETUP_SKIP) {
+ fprintf(stderr, "can't register bufs, skip\n");
+ goto out;
+ } else if (ret != T_SETUP_OK) {
+ fprintf(stderr, "buffer registration failed %i\n", ret);
+ return T_EXIT_FAIL;
+ }
- ret = test_async_addr(&ring);
- if (ret) {
- fprintf(stderr, "test_async_addr() failed\n");
- return T_EXIT_FAIL;
- }
+ if (buffers_iov[BUF_T_HUGETLB].iov_base) {
+ buffers_iov[BUF_T_HUGETLB].iov_base += 13;
+ buffers_iov[BUF_T_HUGETLB].iov_len -= 26;
+ }
+ if (buffers_iov[BUF_T_LARGE].iov_base) {
+ buffers_iov[BUF_T_LARGE].iov_base += 13;
+ buffers_iov[BUF_T_LARGE].iov_len -= 26;
+ }
- ret = t_register_buffers(&ring, buffers_iov, ARRAY_SIZE(buffers_iov));
- if (ret == T_SETUP_SKIP) {
- fprintf(stderr, "can't register bufs, skip\n");
- goto out;
- } else if (ret != T_SETUP_OK) {
- fprintf(stderr, "buffer registration failed %i\n", ret);
- return T_EXIT_FAIL;
- }
+ ret = test_inet_send(&ring);
+ if (ret) {
+ fprintf(stderr, "test_inet_send() failed (defer_taskrun %i)\n",
+ ring_flags & IORING_SETUP_DEFER_TASKRUN);
+ return T_EXIT_FAIL;
+ }
- if (buffers_iov[BUF_T_HUGETLB].iov_base) {
- buffers_iov[BUF_T_HUGETLB].iov_base += 13;
- buffers_iov[BUF_T_HUGETLB].iov_len -= 26;
- }
- if (buffers_iov[BUF_T_LARGE].iov_base) {
- buffers_iov[BUF_T_LARGE].iov_base += 13;
- buffers_iov[BUF_T_LARGE].iov_len -= 26;
+ if (buffers_iov[BUF_T_HUGETLB].iov_base) {
+ buffers_iov[BUF_T_HUGETLB].iov_base -= 13;
+ buffers_iov[BUF_T_HUGETLB].iov_len += 26;
+ }
+ if (buffers_iov[BUF_T_LARGE].iov_base) {
+ buffers_iov[BUF_T_LARGE].iov_base -= 13;
+ buffers_iov[BUF_T_LARGE].iov_len += 26;
+ }
+out:
+ io_uring_queue_exit(&ring);
}
- ret = test_inet_send(&ring);
- if (ret) {
- fprintf(stderr, "test_inet_send() failed\n");
- return T_EXIT_FAIL;
- }
-out:
- io_uring_queue_exit(&ring);
- close(sp[0]);
- close(sp[1]);
return T_EXIT_PASS;
}
diff --git a/contrib/libs/liburing/test/send_recv.c b/contrib/libs/liburing/test/send_recv.c
index 05b2ffa902..5bf929ba16 100644
--- a/contrib/libs/liburing/test/send_recv.c
+++ b/contrib/libs/liburing/test/send_recv.c
@@ -269,9 +269,12 @@ static int test_invalid(void)
struct io_uring_cqe *cqe;
struct io_uring_sqe *sqe;
- ret = t_create_ring(8, &ring, 0);
- if (ret)
+ ret = t_create_ring(8, &ring, IORING_SETUP_SUBMIT_ALL);
+ if (ret) {
+ if (ret == -EINVAL)
+ return 0;
return ret;
+ }
ret = t_create_socket_pair(fds, true);
if (ret)
diff --git a/contrib/libs/liburing/test/shutdown.c b/contrib/libs/liburing/test/shutdown.c
index e2c59c7666..d7f2f603b0 100644
--- a/contrib/libs/liburing/test/shutdown.c
+++ b/contrib/libs/liburing/test/shutdown.c
@@ -48,7 +48,8 @@ int main(int argc, char *argv[])
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
- assert(!t_bind_ephemeral_port(recv_s0, &addr));
+ ret = t_bind_ephemeral_port(recv_s0, &addr);
+ assert(!ret);
ret = listen(recv_s0, 128);
assert(ret != -1);
diff --git a/contrib/libs/liburing/test/socket-getsetsock-cmd.c b/contrib/libs/liburing/test/socket-getsetsock-cmd.c
new file mode 100644
index 0000000000..275ac66537
--- /dev/null
+++ b/contrib/libs/liburing/test/socket-getsetsock-cmd.c
@@ -0,0 +1,333 @@
+#include "../config-host.h"
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: Check that {g,s}etsockopt CMD operations on sockets are
+ * consistent.
+ *
+ * The tests basically do the same socket operation using regular system calls
+ * and io_uring commands, and then compare the results.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <unistd.h>
+#include <linux/tcp.h>
+
+#include "liburing.h"
+#include "helpers.h"
+
+#define USERDATA 0xff42ff
+#define MSG "foobarbaz"
+
+static int no_sock_opt;
+
+struct fds {
+ int tx;
+ int rx;
+};
+
+static struct fds create_sockets(void)
+{
+ struct fds retval;
+ int fd[2];
+
+ t_create_socket_pair(fd, true);
+
+ retval.tx = fd[0];
+ retval.rx = fd[1];
+
+ return retval;
+}
+
+static struct io_uring create_ring(void)
+{
+ struct io_uring ring;
+ int ring_flags = 0;
+ int err;
+
+ err = io_uring_queue_init(32, &ring, ring_flags);
+ assert(err == 0);
+
+ return ring;
+}
+
+static int submit_cmd_sqe(struct io_uring *ring, int32_t fd,
+ int op, int level, int optname,
+ void *optval, int optlen)
+{
+ struct io_uring_sqe *sqe;
+ int err;
+
+ assert(fd > 0);
+
+ sqe = io_uring_get_sqe(ring);
+ assert(sqe != NULL);
+
+ io_uring_prep_cmd_sock(sqe, op, fd, level, optname, optval, optlen);
+ sqe->user_data = USERDATA;
+
+ /* Submitting SQE */
+ err = io_uring_submit_and_wait(ring, 1);
+ if (err != 1)
+ fprintf(stderr, "Failure: io_uring_submit_and_wait returned %d\n", err);
+
+ return err;
+}
+
+static int receive_cqe(struct io_uring *ring)
+{
+ struct io_uring_cqe *cqe;
+ int err;
+
+ err = io_uring_wait_cqe(ring, &cqe);
+ assert(err == 0);
+ assert(cqe->user_data == USERDATA);
+ io_uring_cqe_seen(ring, cqe);
+
+ /* Return the result of the operation */
+ return cqe->res;
+}
+
+/*
+ * Run getsock operation using SO_RCVBUF using io_uring cmd operation and
+ * getsockopt(2) and compare the results.
+ */
+static int run_get_rcvbuf(struct io_uring *ring, struct fds *sockfds)
+{
+ int sval, uval, ulen, err;
+ unsigned int slen;
+
+ /* System call values */
+ slen = sizeof(sval);
+ /* io_uring values */
+ ulen = sizeof(uval);
+
+ /* get through io_uring cmd */
+ err = submit_cmd_sqe(ring, sockfds->rx, SOCKET_URING_OP_GETSOCKOPT,
+ SOL_SOCKET, SO_RCVBUF, &uval, ulen);
+ assert(err == 1);
+
+ /* Wait for the CQE */
+ err = receive_cqe(ring);
+ if (err == -EOPNOTSUPP)
+ return T_EXIT_SKIP;
+ if (err < 0) {
+ fprintf(stderr, "Error received. %d\n", err);
+ return T_EXIT_FAIL;
+ }
+ /* The output of CQE->res contains the length */
+ ulen = err;
+
+ /* Executes the same operation using system call */
+ err = getsockopt(sockfds->rx, SOL_SOCKET, SO_RCVBUF, &sval, &slen);
+ assert(err == 0);
+
+ /* Make sure that io_uring operation returns the same value as the systemcall */
+ assert(ulen == slen);
+ assert(uval == sval);
+
+ return T_EXIT_PASS;
+}
+
+/*
+ * Run getsock operation using SO_PEERNAME using io_uring cmd operation
+ * and getsockopt(2) and compare the results.
+ */
+static int run_get_peername(struct io_uring *ring, struct fds *sockfds)
+{
+ struct sockaddr sval, uval = {};
+ socklen_t slen = sizeof(sval);
+ socklen_t ulen = sizeof(uval);
+ int err;
+
+ /* Get values from the systemcall */
+ err = getsockopt(sockfds->tx, SOL_SOCKET, SO_PEERNAME, &sval, &slen);
+ assert(err == 0);
+
+ /* Getting SO_PEERNAME */
+ err = submit_cmd_sqe(ring, sockfds->rx, SOCKET_URING_OP_GETSOCKOPT,
+ SOL_SOCKET, SO_PEERNAME, &uval, ulen);
+ assert(err == 1);
+
+ /* Wait for the CQE */
+ err = receive_cqe(ring);
+ if (err == -EOPNOTSUPP || err == -EINVAL) {
+ no_sock_opt = 1;
+ return T_EXIT_SKIP;
+ }
+
+ if (err < 0) {
+ fprintf(stderr, "%s: Error in the CQE: %d\n", __func__, err);
+ return T_EXIT_FAIL;
+ }
+
+ /* The length comes from cqe->res, which is returned from receive_cqe() */
+ ulen = err;
+
+ /* Make sure that io_uring operation returns the same values as the systemcall */
+ assert(sval.sa_family == uval.sa_family);
+ assert(slen == ulen);
+
+ return T_EXIT_PASS;
+}
+
+/*
+ * Run getsockopt tests. Basically comparing io_uring output and systemcall results
+ */
+static int run_getsockopt_test(struct io_uring *ring, struct fds *sockfds)
+{
+ int err;
+
+ fprintf(stderr, "Testing getsockopt SO_PEERNAME\n");
+ err = run_get_peername(ring, sockfds);
+ if (err)
+ return err;
+
+ fprintf(stderr, "Testing getsockopt SO_RCVBUF\n");
+ return run_get_rcvbuf(ring, sockfds);
+}
+
+/*
+ * Given a `val` value, set it in SO_REUSEPORT using io_uring cmd, and read using
+ * getsockopt(2), and make sure they match.
+ */
+static int run_setsockopt_reuseport(struct io_uring *ring, struct fds *sockfds, int val)
+{
+ unsigned int slen, ulen;
+ int sval, uval = val;
+ int err;
+
+ slen = sizeof(sval);
+ ulen = sizeof(uval);
+
+ /* Setting SO_REUSEPORT */
+ err = submit_cmd_sqe(ring, sockfds->rx, SOCKET_URING_OP_SETSOCKOPT,
+ SOL_SOCKET, SO_REUSEPORT, &uval, ulen);
+ assert(err == 1);
+
+ err = receive_cqe(ring);
+ if (err == -EOPNOTSUPP)
+ return T_EXIT_SKIP;
+
+ /* Get values from the systemcall */
+ err = getsockopt(sockfds->rx, SOL_SOCKET, SO_REUSEPORT, &sval, &slen);
+ assert(err == 0);
+
+ /* Make sure the set using io_uring cmd matches what systemcall returns */
+ assert(uval == sval);
+ assert(ulen == slen);
+
+ return T_EXIT_PASS;
+}
+
+/*
+ * Given a `val` value, set the TCP_USER_TIMEOUT using io_uring and read using
+ * getsockopt(2). Make sure they match
+ */
+static int run_setsockopt_usertimeout(struct io_uring *ring, struct fds *sockfds, int val)
+{
+ int optname = TCP_USER_TIMEOUT;
+ int level = IPPROTO_TCP;
+ unsigned int slen, ulen;
+ int sval, uval, err;
+
+ slen = sizeof(uval);
+ ulen = sizeof(uval);
+
+ uval = val;
+
+ /* Setting timeout */
+ err = submit_cmd_sqe(ring, sockfds->rx, SOCKET_URING_OP_SETSOCKOPT,
+ level, optname, &uval, ulen);
+ assert(err == 1);
+
+ err = receive_cqe(ring);
+ if (err == -EOPNOTSUPP)
+ return T_EXIT_SKIP;
+ if (err < 0) {
+ fprintf(stderr, "%s: Got an error: %d\n", __func__, err);
+ return T_EXIT_FAIL;
+ }
+
+ /* Get the value from the systemcall, to make sure it was set */
+ err = getsockopt(sockfds->rx, level, optname, &sval, &slen);
+ assert(err == 0);
+ assert(uval == sval);
+
+ return T_EXIT_PASS;
+}
+
+/* Test setsockopt() for SOL_SOCKET */
+static int run_setsockopt_test(struct io_uring *ring, struct fds *sockfds)
+{
+ int err, i;
+
+ fprintf(stderr, "Testing setsockopt SOL_SOCKET/SO_REUSEPORT\n");
+ for (i = 0; i <= 1; i++) {
+ err = run_setsockopt_reuseport(ring, sockfds, i);
+ if (err)
+ return err;
+ }
+
+ fprintf(stderr, "Testing setsockopt IPPROTO_TCP/TCP_FASTOPEN\n");
+ for (i = 1; i <= 10; i++) {
+ err = run_setsockopt_usertimeout(ring, sockfds, i);
+ if (err)
+ return err;
+ }
+
+ return err;
+}
+
+/* Send data through the sockets */
+static void send_data(struct fds *s)
+{
+ int written_bytes;
+ /* Send data sing the sockstruct->send */
+ written_bytes = write(s->tx, MSG, strlen(MSG));
+ assert(written_bytes == strlen(MSG));
+}
+
+int main(int argc, char *argv[])
+{
+ struct fds sockfds;
+ struct io_uring ring;
+ int err;
+
+ if (argc > 1)
+ return T_EXIT_SKIP;
+
+ /* Simply io_uring ring creation */
+ ring = create_ring();
+
+ /* Create sockets */
+ sockfds = create_sockets();
+
+ send_data(&sockfds);
+
+ err = run_getsockopt_test(&ring, &sockfds);
+ if (err) {
+ if (err == T_EXIT_SKIP) {
+ fprintf(stderr, "Skipping tests.\n");
+ return T_EXIT_SKIP;
+ }
+ fprintf(stderr, "Failed to run test: %d\n", err);
+ return err;
+ }
+ if (no_sock_opt)
+ return T_EXIT_SKIP;
+
+ err = run_setsockopt_test(&ring, &sockfds);
+ if (err) {
+ if (err == T_EXIT_SKIP) {
+ fprintf(stderr, "Skipping tests.\n");
+ return T_EXIT_SKIP;
+ }
+ fprintf(stderr, "Failed to run test: %d\n", err);
+ return err;
+ }
+
+ io_uring_queue_exit(&ring);
+ return err;
+}
diff --git a/contrib/libs/liburing/test/socket-getsetsock-cmd.t/ya.make b/contrib/libs/liburing/test/socket-getsetsock-cmd.t/ya.make
new file mode 100644
index 0000000000..3d0c645c78
--- /dev/null
+++ b/contrib/libs/liburing/test/socket-getsetsock-cmd.t/ya.make
@@ -0,0 +1,33 @@
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
+WITHOUT_LICENSE_TEXTS()
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/liburing
+)
+
+ADDINCL(
+ contrib/libs/liburing/src/include
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_RUNTIME()
+
+CFLAGS(
+ -DLIBURING_BUILD_TEST
+ -D__SANE_USERSPACE_TYPES__
+)
+
+SRCDIR(contrib/libs/liburing/test)
+
+SRCS(
+ helpers.c
+ socket-getsetsock-cmd.c
+)
+
+END()
diff --git a/contrib/libs/liburing/test/socket-io-cmd.c b/contrib/libs/liburing/test/socket-io-cmd.c
new file mode 100644
index 0000000000..c4dd3bb8be
--- /dev/null
+++ b/contrib/libs/liburing/test/socket-io-cmd.c
@@ -0,0 +1,238 @@
+#include "../config-host.h"
+/* SPDX-License-Identifier: MIT */
+/*
+ * Check that CMD operations on sockets are consistent.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+#include <string.h>
+#include <unistd.h>
+#include <linux/sockios.h>
+#include <sys/ioctl.h>
+
+#include "liburing.h"
+#include "helpers.h"
+
+#define USERDATA 0x1234
+#define MSG "foobarbaz"
+
+static int no_io_cmd;
+
+struct fds {
+ int tx;
+ int rx;
+};
+
+/* Create 2 sockets (tx, rx) given the socket type */
+static struct fds create_sockets(bool stream)
+{
+ struct fds retval;
+ int fd[2];
+
+ t_create_socket_pair(fd, stream);
+
+ retval.tx = fd[0];
+ retval.rx = fd[1];
+
+ return retval;
+}
+
+static int create_sqe_and_submit(struct io_uring *ring, int32_t fd, int op)
+{
+ struct io_uring_sqe *sqe;
+ int ret;
+
+ assert(fd > 0);
+ sqe = io_uring_get_sqe(ring);
+ assert(sqe != NULL);
+
+ io_uring_prep_cmd_sock(sqe, op, fd, 0, 0, NULL, 0);
+ sqe->user_data = USERDATA;
+
+ /* Submitting SQE */
+ ret = io_uring_submit_and_wait(ring, 1);
+ if (ret <= 0)
+ return ret;
+
+ return 0;
+}
+
+static int receive_cqe(struct io_uring *ring)
+{
+ struct io_uring_cqe *cqe;
+ int err;
+
+ err = io_uring_wait_cqe(ring, &cqe);
+ assert(err == 0);
+ assert(cqe->user_data == USERDATA);
+ err = cqe->res;
+ io_uring_cqe_seen(ring, cqe);
+
+ /* Return the result of the operation */
+ return err;
+}
+
+static ssize_t send_data(struct fds *s, char *str)
+{
+ size_t written_bytes;
+
+ written_bytes = write(s->tx, str, strlen(str));
+ assert(written_bytes == strlen(MSG));
+
+ return written_bytes;
+}
+
+static int run_test(bool stream)
+{
+ struct fds sockfds;
+ ssize_t bytes_in, bytes_out;
+ struct io_uring ring;
+ size_t written_bytes;
+ int error;
+
+ /* Create three sockets */
+ sockfds = create_sockets(stream);
+ assert(sockfds.tx > 0);
+ assert(sockfds.rx > 0);
+ /* Send data sing the sockfds->send */
+ written_bytes = send_data(&sockfds, MSG);
+
+ /* Simply io_uring ring creation */
+ error = t_create_ring(1, &ring, 0);
+ if (error == T_SETUP_SKIP)
+ return error;
+ else if (error != T_SETUP_OK)
+ return T_EXIT_FAIL;
+
+ error = create_sqe_and_submit(&ring, sockfds.rx,
+ SOCKET_URING_OP_SIOCINQ);
+ if (error)
+ return T_EXIT_FAIL;
+ bytes_in = receive_cqe(&ring);
+ if (bytes_in < 0) {
+ if (bytes_in == -EINVAL || bytes_in == -EOPNOTSUPP) {
+ no_io_cmd = 1;
+ return T_EXIT_SKIP;
+ }
+ fprintf(stderr, "Bad return value %ld\n", (long) bytes_in);
+ return T_EXIT_FAIL;
+ }
+
+ error = create_sqe_and_submit(&ring, sockfds.tx,
+ SOCKET_URING_OP_SIOCOUTQ);
+ if (error)
+ return T_EXIT_FAIL;
+
+ bytes_out = receive_cqe(&ring);
+ if (bytes_in == -ENOTSUP || bytes_out == -ENOTSUP) {
+ fprintf(stderr, "Skipping tests. -ENOTSUP returned\n");
+ return T_EXIT_SKIP;
+ }
+
+ /*
+ * Assert the number of written bytes are either in the socket buffer
+ * or on the receive side
+ */
+ if (bytes_in + bytes_out != written_bytes) {
+ fprintf(stderr, "values does not match: %zu+%zu != %zu\n",
+ bytes_in, bytes_out, written_bytes);
+ return T_EXIT_FAIL;
+ }
+
+ io_uring_queue_exit(&ring);
+
+ return T_EXIT_PASS;
+}
+
+/*
+ * Make sure that siocoutq and siocinq returns the same value
+ * using ioctl(2) and uring commands for raw sockets
+ */
+static int run_test_raw(void)
+{
+ int ioctl_siocoutq, ioctl_siocinq;
+ int uring_siocoutq, uring_siocinq;
+ struct io_uring ring;
+ int retry = 0, sock, error;
+
+ sock = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
+ if (sock == -1) {
+ /* You need root to create raw socket */
+ perror("Not able to create a raw socket");
+ return T_EXIT_SKIP;
+ }
+
+ /* Get the same operation using uring cmd */
+ error = t_create_ring(1, &ring, 0);
+ if (error == T_SETUP_SKIP)
+ return error;
+ else if (error != T_SETUP_OK)
+ return T_EXIT_FAIL;
+
+again:
+ /* Simple SIOCOUTQ using ioctl */
+ error = ioctl(sock, SIOCOUTQ, &ioctl_siocoutq);
+ if (error < 0) {
+ fprintf(stderr, "Failed to run ioctl(SIOCOUTQ): %d\n", error);
+ return T_EXIT_FAIL;
+ }
+
+ error = ioctl(sock, SIOCINQ, &ioctl_siocinq);
+ if (error < 0) {
+ fprintf(stderr, "Failed to run ioctl(SIOCINQ): %d\n", error);
+ return T_EXIT_FAIL;
+ }
+
+ create_sqe_and_submit(&ring, sock, SOCKET_URING_OP_SIOCOUTQ);
+ uring_siocoutq = receive_cqe(&ring);
+
+ create_sqe_and_submit(&ring, sock, SOCKET_URING_OP_SIOCINQ);
+ uring_siocinq = receive_cqe(&ring);
+
+ /* Compare that both values (ioctl and uring CMD) should be similar */
+ if (uring_siocoutq != ioctl_siocoutq) {
+ if (!retry) {
+ retry = 1;
+ goto again;
+ }
+ fprintf(stderr, "values does not match: %d != %d\n",
+ uring_siocoutq, ioctl_siocoutq);
+ return T_EXIT_FAIL;
+ }
+ if (uring_siocinq != ioctl_siocinq) {
+ if (!retry) {
+ retry = 1;
+ goto again;
+ }
+ fprintf(stderr, "values does not match: %d != %d\n",
+ uring_siocinq, ioctl_siocinq);
+ return T_EXIT_FAIL;
+ }
+
+ return T_EXIT_PASS;
+}
+
+int main(int argc, char *argv[])
+{
+ int err;
+
+ if (argc > 1)
+ return 0;
+
+ /* Test SOCK_STREAM */
+ err = run_test(true);
+ if (err)
+ return err;
+ if (no_io_cmd)
+ return T_EXIT_SKIP;
+
+ /* Test SOCK_DGRAM */
+ err = run_test(false);
+ if (err)
+ return err;
+
+ /* Test raw sockets */
+ return run_test_raw();
+}
diff --git a/contrib/libs/liburing/test/socket-io-cmd.t/ya.make b/contrib/libs/liburing/test/socket-io-cmd.t/ya.make
new file mode 100644
index 0000000000..b03d5f0ea0
--- /dev/null
+++ b/contrib/libs/liburing/test/socket-io-cmd.t/ya.make
@@ -0,0 +1,33 @@
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
+WITHOUT_LICENSE_TEXTS()
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/liburing
+)
+
+ADDINCL(
+ contrib/libs/liburing/src/include
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_RUNTIME()
+
+CFLAGS(
+ -DLIBURING_BUILD_TEST
+ -D__SANE_USERSPACE_TYPES__
+)
+
+SRCDIR(contrib/libs/liburing/test)
+
+SRCS(
+ helpers.c
+ socket-io-cmd.c
+)
+
+END()
diff --git a/contrib/libs/liburing/test/socket-rw-eagain.c b/contrib/libs/liburing/test/socket-rw-eagain.c
index e762da531f..9fe9517e56 100644
--- a/contrib/libs/liburing/test/socket-rw-eagain.c
+++ b/contrib/libs/liburing/test/socket-rw-eagain.c
@@ -43,7 +43,8 @@ int main(int argc, char *argv[])
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
- assert(!t_bind_ephemeral_port(recv_s0, &addr));
+ ret = t_bind_ephemeral_port(recv_s0, &addr);
+ assert(!ret);
ret = listen(recv_s0, 128);
assert(ret != -1);
diff --git a/contrib/libs/liburing/test/socket-rw-offset.c b/contrib/libs/liburing/test/socket-rw-offset.c
index 26173876ef..21681bfaab 100644
--- a/contrib/libs/liburing/test/socket-rw-offset.c
+++ b/contrib/libs/liburing/test/socket-rw-offset.c
@@ -45,7 +45,8 @@ int main(int argc, char *argv[])
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
- assert(!t_bind_ephemeral_port(recv_s0, &addr));
+ ret = t_bind_ephemeral_port(recv_s0, &addr);
+ assert(!ret);
ret = listen(recv_s0, 128);
assert(ret != -1);
diff --git a/contrib/libs/liburing/test/socket-rw.c b/contrib/libs/liburing/test/socket-rw.c
index 5546714e65..b50e0427b3 100644
--- a/contrib/libs/liburing/test/socket-rw.c
+++ b/contrib/libs/liburing/test/socket-rw.c
@@ -45,7 +45,8 @@ int main(int argc, char *argv[])
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
- assert(!t_bind_ephemeral_port(recv_s0, &addr));
+ ret = t_bind_ephemeral_port(recv_s0, &addr);
+ assert(!ret);
ret = listen(recv_s0, 128);
assert(ret != -1);
diff --git a/contrib/libs/liburing/test/sqpoll-cancel-hang.c b/contrib/libs/liburing/test/sqpoll-cancel-hang.c
deleted file mode 100644
index 302a662bcd..0000000000
--- a/contrib/libs/liburing/test/sqpoll-cancel-hang.c
+++ /dev/null
@@ -1,169 +0,0 @@
-#include "../config-host.h"
-/* SPDX-License-Identifier: MIT */
-#include <fcntl.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/wait.h>
-#include <time.h>
-#include <unistd.h>
-#include "liburing.h"
-#include "helpers.h"
-#include "../src/syscall.h"
-
-/*
- * This syzbot test is known broken on some archs, just allow the ones that
- * are regularly tested.
- */
-#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || \
- defined(__aarch64__)
-
-static uint64_t current_time_ms(void)
-{
- struct timespec ts;
- if (clock_gettime(CLOCK_MONOTONIC, &ts))
- exit(1);
- return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
-}
-
-#define SIZEOF_IO_URING_SQE 64
-#define SIZEOF_IO_URING_CQE 16
-#define SQ_TAIL_OFFSET 64
-#define SQ_RING_MASK_OFFSET 256
-#define SQ_RING_ENTRIES_OFFSET 264
-#define CQ_RING_ENTRIES_OFFSET 268
-#define CQ_CQES_OFFSET 320
-
-#define IORING_OFF_SQES 0x10000000ULL
-
-static void kill_and_wait(int pid, int* status)
-{
- kill(-pid, SIGKILL);
- kill(pid, SIGKILL);
- while (waitpid(-1, status, __WALL) != pid) {
- }
-}
-
-#define WAIT_FLAGS __WALL
-
-static uint64_t r[3] = {0xffffffffffffffff, 0x0, 0x0};
-
-static long syz_io_uring_setup(volatile long a0, volatile long a1,
-volatile long a2, volatile long a3, volatile long a4, volatile long
-a5)
-{
- uint32_t entries = (uint32_t)a0;
- struct io_uring_params* setup_params = (struct io_uring_params*)a1;
- void* vma1 = (void*)a2;
- void* vma2 = (void*)a3;
- void** ring_ptr_out = (void**)a4;
- void** sqes_ptr_out = (void**)a5;
- uint32_t fd_io_uring = __sys_io_uring_setup(entries, setup_params);
- uint32_t sq_ring_sz = setup_params->sq_off.array +
-setup_params->sq_entries * sizeof(uint32_t);
- uint32_t cq_ring_sz = setup_params->cq_off.cqes +
-setup_params->cq_entries * SIZEOF_IO_URING_CQE;
- uint32_t ring_sz = sq_ring_sz > cq_ring_sz ? sq_ring_sz : cq_ring_sz;
- *ring_ptr_out = mmap(vma1, ring_sz, PROT_READ | PROT_WRITE,
-MAP_SHARED | MAP_POPULATE | MAP_FIXED, fd_io_uring,
-IORING_OFF_SQ_RING);
- uint32_t sqes_sz = setup_params->sq_entries * SIZEOF_IO_URING_SQE;
- *sqes_ptr_out = mmap(vma2, sqes_sz, PROT_READ | PROT_WRITE,
-MAP_SHARED | MAP_POPULATE | MAP_FIXED, fd_io_uring, IORING_OFF_SQES);
- return fd_io_uring;
-}
-
-static long syz_io_uring_submit(volatile long a0, volatile long a1,
-volatile long a2, volatile long a3)
-{
- char* ring_ptr = (char*)a0;
- char* sqes_ptr = (char*)a1;
- char* sqe = (char*)a2;
- uint32_t sqes_index = (uint32_t)a3;
- uint32_t sq_ring_entries = *(uint32_t*)(ring_ptr + SQ_RING_ENTRIES_OFFSET);
- uint32_t cq_ring_entries = *(uint32_t*)(ring_ptr + CQ_RING_ENTRIES_OFFSET);
- uint32_t sq_array_off = (CQ_CQES_OFFSET + cq_ring_entries *
-SIZEOF_IO_URING_CQE + 63) & ~63;
- if (sq_ring_entries)
- sqes_index %= sq_ring_entries;
- char* sqe_dest = sqes_ptr + sqes_index * SIZEOF_IO_URING_SQE;
- memcpy(sqe_dest, sqe, SIZEOF_IO_URING_SQE);
- uint32_t sq_ring_mask = *(uint32_t*)(ring_ptr + SQ_RING_MASK_OFFSET);
- uint32_t* sq_tail_ptr = (uint32_t*)(ring_ptr + SQ_TAIL_OFFSET);
- uint32_t sq_tail = *sq_tail_ptr & sq_ring_mask;
- uint32_t sq_tail_next = *sq_tail_ptr + 1;
- uint32_t* sq_array = (uint32_t*)(ring_ptr + sq_array_off);
- *(sq_array + sq_tail) = sqes_index;
- __atomic_store_n(sq_tail_ptr, sq_tail_next, __ATOMIC_RELEASE);
- return 0;
-}
-
-
-static void trigger_bug(void)
-{
- intptr_t res = 0;
- *(uint32_t*)0x20000204 = 0;
- *(uint32_t*)0x20000208 = 2;
- *(uint32_t*)0x2000020c = 0;
- *(uint32_t*)0x20000210 = 0;
- *(uint32_t*)0x20000218 = -1;
- memset((void*)0x2000021c, 0, 12);
- res = -1;
- res = syz_io_uring_setup(0x7987, 0x20000200, 0x20400000, 0x20ffd000, 0x200000c0, 0x200001c0);
- if (res != -1) {
- r[0] = res;
- r[1] = *(uint64_t*)0x200000c0;
- r[2] = *(uint64_t*)0x200001c0;
- }
- *(uint8_t*)0x20000180 = 0xb;
- *(uint8_t*)0x20000181 = 1;
- *(uint16_t*)0x20000182 = 0;
- *(uint32_t*)0x20000184 = 0;
- *(uint64_t*)0x20000188 = 4;
- *(uint64_t*)0x20000190 = 0x20000140;
- *(uint64_t*)0x20000140 = 0x77359400;
- *(uint64_t*)0x20000148 = 0;
- *(uint32_t*)0x20000198 = 1;
- *(uint32_t*)0x2000019c = 0;
- *(uint64_t*)0x200001a0 = 0;
- *(uint16_t*)0x200001a8 = 0;
- *(uint16_t*)0x200001aa = 0;
- memset((void*)0x200001ac, 0, 20);
- syz_io_uring_submit(r[1], r[2], 0x20000180, 1);
- *(uint32_t*)0x20000544 = 0;
- *(uint32_t*)0x20000548 = 0x36;
- *(uint32_t*)0x2000054c = 0;
- *(uint32_t*)0x20000550 = 0;
- *(uint32_t*)0x20000558 = r[0];
- memset((void*)0x2000055c, 0, 12);
-
-}
-int main(void)
-{
- mmap((void *)0x20000000ul, 0x1000000ul, 7ul, MAP_ANON|MAP_PRIVATE, -1, 0ul);
- int pid = fork();
- if (pid < 0)
- exit(1);
- if (pid == 0) {
- trigger_bug();
- exit(0);
- }
- int status = 0;
- uint64_t start = current_time_ms();
- for (;;) {
- if (current_time_ms() - start < 1000) {
- continue;
- }
- kill_and_wait(pid, &status);
- break;
- }
- return 0;
-}
-#else
-int main(void)
-{
- return T_EXIT_SKIP;
-}
-#endif
diff --git a/contrib/libs/liburing/test/truncate.c b/contrib/libs/liburing/test/truncate.c
new file mode 100644
index 0000000000..395d09e70d
--- /dev/null
+++ b/contrib/libs/liburing/test/truncate.c
@@ -0,0 +1,187 @@
+#include "../config-host.h"
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: run various truncate tests
+ *
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include "liburing.h"
+#include "helpers.h"
+
+#define TWO_GIG_SIZE ((loff_t)2 * 1024 * 1024 * 1024)
+#define ONE_GIG_SIZE ((loff_t)1024 * 1024 * 1024)
+#define HALF_GIG_SIZE ((loff_t)512 * 1024 * 1024)
+
+static int test_truncate(struct io_uring *ring, int fd)
+{
+ struct io_uring_cqe *cqe;
+ struct io_uring_sqe *sqe;
+ int ret = -1;
+
+ sqe = io_uring_get_sqe(ring);
+ if (!sqe) {
+ fprintf(stderr, "get sqe failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ memset(sqe, 0, sizeof(*sqe));
+
+ io_uring_prep_rw(IORING_OP_FTRUNCATE, sqe, fd, "fail", 0, 4);
+
+ ret = io_uring_submit(ring);
+ if (ret <= 0) {
+ fprintf(stderr, "sqe submit failed: %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret < 0) {
+ fprintf(stderr, "wait completion %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ ret = cqe->res;
+ io_uring_cqe_seen(ring, cqe);
+ if (ret == -EINVAL)
+ return T_EXIT_PASS;
+
+ fprintf(stderr, "unexpected truncate res %d\n", ret);
+ return T_EXIT_FAIL;
+}
+
+static int test_ftruncate(struct io_uring *ring, int fd, loff_t len)
+{
+ struct io_uring_cqe *cqe;
+ struct io_uring_sqe *sqe;
+ int ret;
+
+ sqe = io_uring_get_sqe(ring);
+ if (!sqe) {
+ fprintf(stderr, "get sqe failed\n");
+ goto err;
+ }
+
+ memset(sqe, 0, sizeof(*sqe));
+
+ io_uring_prep_ftruncate(sqe, fd, len);
+
+ ret = io_uring_submit(ring);
+ if (ret <= 0) {
+ fprintf(stderr, "sqe submit failed: %d\n", ret);
+ goto err;
+ }
+
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret < 0) {
+ fprintf(stderr, "wait completion %d\n", ret);
+ goto err;
+ }
+ ret = cqe->res;
+ io_uring_cqe_seen(ring, cqe);
+ return ret;
+err:
+ return 1;
+}
+
+static int get_file_size(int fd, loff_t *size)
+{
+ struct stat st;
+
+ if (fstat(fd, &st) < 0) {
+ perror("fstat");
+ return -1;
+ }
+ if (S_ISREG(st.st_mode)) {
+ *size = st.st_size;
+ return 0;
+ } else if (S_ISBLK(st.st_mode)) {
+ unsigned long long bytes;
+
+ if (ioctl(fd, BLKGETSIZE64, &bytes) != 0) {
+ perror("ioctl");
+ return -1;
+ }
+
+ *size = bytes;
+ return 0;
+ }
+
+ return -1;
+}
+
+int main(int argc, char *argv[])
+{
+ struct io_uring ring;
+ char path[32] = ".truncate.XXXXXX";
+ int ret;
+ int fd;
+ int i;
+ loff_t size;
+ loff_t test_sizes[3];
+
+ if (argc > 1)
+ return T_EXIT_SKIP;
+
+ ret = io_uring_queue_init(1, &ring, 0);
+ if (ret) {
+ fprintf(stderr, "ring setup failed: %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ fd = mkostemp(path, O_WRONLY | O_CREAT | O_TRUNC);
+ if (fd < 0) {
+ perror("mkostemp");
+ return T_EXIT_FAIL;
+ }
+
+ test_sizes[0] = TWO_GIG_SIZE;
+ test_sizes[1] = ONE_GIG_SIZE;
+ test_sizes[2] = HALF_GIG_SIZE;
+
+ for (i = 0; i < 3; i++) {
+ ret = test_ftruncate(&ring, fd, test_sizes[i]);
+ if (ret < 0) {
+ if (ret == -EBADF || ret == -EINVAL) {
+ if (i == 0) {
+ fprintf(stdout, "Ftruncate not supported, skipping\n");
+ ret = T_EXIT_SKIP;
+ goto out;
+ }
+ goto err;
+ }
+ fprintf(stderr, "ftruncate: %s\n", strerror(-ret));
+ goto err;
+ } else if (ret) {
+ fprintf(stderr, "unexpected cqe->res %d\n", ret);
+ goto err;
+ }
+ if (get_file_size(fd, &size))
+ goto err;
+ if (size != test_sizes[i]) {
+ fprintf(stderr, "fail %d size=%llu, %llu\n", i,
+ (unsigned long long) size,
+ (unsigned long long) test_sizes[i]);
+ goto err;
+ }
+ }
+
+ ret = test_truncate(&ring, fd);
+ if (ret != T_EXIT_PASS)
+ goto err;
+
+out:
+ unlink(path);
+ close(fd);
+ return T_EXIT_PASS;
+err:
+ unlink(path);
+ close(fd);
+ return T_EXIT_FAIL;
+}
diff --git a/contrib/libs/liburing/test/truncate.t/ya.make b/contrib/libs/liburing/test/truncate.t/ya.make
new file mode 100644
index 0000000000..e360ea5773
--- /dev/null
+++ b/contrib/libs/liburing/test/truncate.t/ya.make
@@ -0,0 +1,33 @@
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
+WITHOUT_LICENSE_TEXTS()
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/liburing
+)
+
+ADDINCL(
+ contrib/libs/liburing/src/include
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_RUNTIME()
+
+CFLAGS(
+ -DLIBURING_BUILD_TEST
+ -D__SANE_USERSPACE_TYPES__
+)
+
+SRCDIR(contrib/libs/liburing/test)
+
+SRCS(
+ helpers.c
+ truncate.c
+)
+
+END()
diff --git a/contrib/libs/liburing/test/version.c b/contrib/libs/liburing/test/version.c
index b7fbd8420b..9ffe7a6c49 100644
--- a/contrib/libs/liburing/test/version.c
+++ b/contrib/libs/liburing/test/version.c
@@ -9,7 +9,7 @@
int main(int argc, char *argv[])
{
- if (!IO_URING_CHECK_VERSION(io_uring_major_version(), io_uring_minor_version()))
+ if (IO_URING_CHECK_VERSION(io_uring_major_version(), io_uring_minor_version()))
return T_EXIT_FAIL;
if (io_uring_major_version() != IO_URING_VERSION_MAJOR)
@@ -18,7 +18,7 @@ int main(int argc, char *argv[])
if (io_uring_minor_version() != IO_URING_VERSION_MINOR)
return T_EXIT_FAIL;
-#if !IO_URING_CHECK_VERSION(IO_URING_VERSION_MAJOR, IO_URING_VERSION_MINOR)
+#if IO_URING_CHECK_VERSION(IO_URING_VERSION_MAJOR, IO_URING_VERSION_MINOR)
return T_EXIT_FAIL;
#endif
diff --git a/contrib/libs/liburing/test/waitid.c b/contrib/libs/liburing/test/waitid.c
new file mode 100644
index 0000000000..f7ebe55ac7
--- /dev/null
+++ b/contrib/libs/liburing/test/waitid.c
@@ -0,0 +1,374 @@
+#include "../config-host.h"
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: test waitid functionality
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "liburing.h"
+#include "helpers.h"
+
+static bool no_waitid;
+
+static void child(long usleep_time)
+{
+ if (usleep_time)
+ usleep(usleep_time);
+ exit(0);
+}
+
+/*
+ * Test linked timeout with child not exiting in time
+ */
+static int test_noexit(struct io_uring *ring)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ struct __kernel_timespec ts;
+ siginfo_t si;
+ pid_t pid;
+ int ret, i;
+
+ pid = fork();
+ if (!pid) {
+ child(200000);
+ exit(0);
+ }
+
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_waitid(sqe, P_PID, pid, &si, WEXITED, 0);
+ sqe->flags |= IOSQE_IO_LINK;
+ sqe->user_data = 1;
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 100 * 1000 * 1000ULL;
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_link_timeout(sqe, &ts, 0);
+ sqe->user_data = 2;
+
+ io_uring_submit(ring);
+
+ for (i = 0; i < 2; i++) {
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "cqe wait: %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ if (cqe->user_data == 2 && cqe->res != 1) {
+ fprintf(stderr, "timeout res: %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ if (cqe->user_data == 1 && cqe->res != -ECANCELED) {
+ fprintf(stderr, "waitid res: %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ io_uring_cqe_seen(ring, cqe);
+ }
+
+ return T_EXIT_PASS;
+}
+
+/*
+ * Test one child exiting, but not the one we were looking for
+ */
+static int test_double(struct io_uring *ring)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ siginfo_t si;
+ pid_t p1, p2;
+ int ret;
+
+ /* p1 will exit shortly */
+ p1 = fork();
+ if (!p1) {
+ child(100000);
+ exit(0);
+ }
+
+ /* p2 will linger */
+ p2 = fork();
+ if (!p2) {
+ child(200000);
+ exit(0);
+ }
+
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_waitid(sqe, P_PID, p2, &si, WEXITED, 0);
+
+ io_uring_submit(ring);
+
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "cqe wait: %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ if (cqe->res < 0) {
+ fprintf(stderr, "cqe res: %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ if (si.si_pid != p2) {
+ fprintf(stderr, "expected pid %d, got %d\n", p2, si.si_pid);
+ return T_EXIT_FAIL;
+ }
+
+ io_uring_cqe_seen(ring, cqe);
+ return T_EXIT_PASS;
+}
+
+/*
+ * Test reaping of an already exited task
+ */
+static int test_ready(struct io_uring *ring)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ siginfo_t si;
+ pid_t pid;
+ int ret;
+
+ pid = fork();
+ if (!pid) {
+ child(0);
+ exit(0);
+ }
+
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_waitid(sqe, P_PID, pid, &si, WEXITED, 0);
+
+ io_uring_submit(ring);
+
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "cqe wait: %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ if (cqe->res < 0) {
+ fprintf(stderr, "cqe res: %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ if (si.si_pid != pid) {
+ fprintf(stderr, "expected pid %d, got %d\n", pid, si.si_pid);
+ return T_EXIT_FAIL;
+ }
+
+ io_uring_cqe_seen(ring, cqe);
+ return T_EXIT_PASS;
+}
+
+/*
+ * Test cancelation of pending waitid
+ */
+static int test_cancel(struct io_uring *ring)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ int ret, i;
+ pid_t pid;
+
+ pid = fork();
+ if (!pid) {
+ child(20000);
+ exit(0);
+ }
+
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_waitid(sqe, P_PID, pid, NULL, WEXITED, 0);
+ sqe->user_data = 1;
+
+ io_uring_submit(ring);
+
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_cancel64(sqe, 1, 0);
+ sqe->user_data = 2;
+
+ io_uring_submit(ring);
+
+ for (i = 0; i < 2; i++) {
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "cqe wait: %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ if (cqe->user_data == 1 && cqe->res != -ECANCELED) {
+ fprintf(stderr, "cqe res: %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ if (cqe->user_data == 2 && cqe->res != 1) {
+ fprintf(stderr, "cqe res: %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ io_uring_cqe_seen(ring, cqe);
+ }
+
+ return T_EXIT_PASS;
+}
+
+/*
+ * Test cancelation of pending waitid, with expected races that either
+ * waitid trigger or cancelation will win.
+ */
+static int test_cancel_race(struct io_uring *ring, int async)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ int ret, i;
+ pid_t pid;
+
+ for (i = 0; i < 10; i++) {
+ pid = fork();
+ if (!pid) {
+ child(getpid() & 1);
+ exit(0);
+ }
+ }
+
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_waitid(sqe, P_ALL, -1, NULL, WEXITED, 0);
+ if (async)
+ sqe->flags |= IOSQE_ASYNC;
+ sqe->user_data = 1;
+
+ io_uring_submit(ring);
+
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_cancel64(sqe, 1, 0);
+ sqe->user_data = 2;
+
+ usleep(1);
+
+ io_uring_submit(ring);
+
+ for (i = 0; i < 2; i++) {
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "cqe wait: %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+ if (cqe->user_data == 1 && !(cqe->res == -ECANCELED ||
+ cqe->res == 0)) {
+ fprintf(stderr, "cqe1 res: %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ if (cqe->user_data == 2 &&
+ !(cqe->res == 1 || cqe->res == 0 || cqe->res == -ENOENT ||
+ cqe->res == -EALREADY)) {
+ fprintf(stderr, "cqe2 res: %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ io_uring_cqe_seen(ring, cqe);
+ }
+
+ return T_EXIT_PASS;
+}
+
+/*
+ * Test basic reap of child exit
+ */
+static int test(struct io_uring *ring)
+{
+ struct io_uring_sqe *sqe;
+ struct io_uring_cqe *cqe;
+ siginfo_t si;
+ pid_t pid;
+ int ret;
+
+ pid = fork();
+ if (!pid) {
+ child(100);
+ exit(0);
+ }
+
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_waitid(sqe, P_PID, pid, &si, WEXITED, 0);
+
+ io_uring_submit(ring);
+
+ ret = io_uring_wait_cqe(ring, &cqe);
+ if (ret) {
+ fprintf(stderr, "cqe wait: %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ /* no waitid support */
+ if (cqe->res == -EINVAL) {
+ no_waitid = true;
+ return T_EXIT_SKIP;
+ }
+ if (cqe->res < 0) {
+ fprintf(stderr, "cqe res: %d\n", cqe->res);
+ return T_EXIT_FAIL;
+ }
+ if (si.si_pid != pid) {
+ fprintf(stderr, "expected pid %d, got %d\n", pid, si.si_pid);
+ return T_EXIT_FAIL;
+ }
+
+ io_uring_cqe_seen(ring, cqe);
+ return T_EXIT_PASS;
+}
+
+int main(int argc, char *argv[])
+{
+ struct io_uring ring;
+ int ret, i;
+
+ if (argc > 1)
+ return T_EXIT_SKIP;
+
+ io_uring_queue_init(8, &ring, 0);
+
+ ret = test(&ring);
+ if (ret == T_EXIT_FAIL) {
+ fprintf(stderr, "test failed\n");
+ return T_EXIT_FAIL;
+ }
+ if (no_waitid)
+ return T_EXIT_SKIP;
+
+ ret = test_noexit(&ring);
+ if (ret == T_EXIT_FAIL) {
+ fprintf(stderr, "test_noexit failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test_noexit(&ring);
+ if (ret == T_EXIT_FAIL) {
+ fprintf(stderr, "test_noexit failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test_double(&ring);
+ if (ret == T_EXIT_FAIL) {
+ fprintf(stderr, "test_double failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test_ready(&ring);
+ if (ret == T_EXIT_FAIL) {
+ fprintf(stderr, "test_ready failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ ret = test_cancel(&ring);
+ if (ret == T_EXIT_FAIL) {
+ fprintf(stderr, "test_cancel failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ for (i = 0; i < 1000; i++) {
+ ret = test_cancel_race(&ring, i & 1);
+ if (ret == T_EXIT_FAIL) {
+ fprintf(stderr, "test_cancel_race failed\n");
+ return T_EXIT_FAIL;
+ }
+ }
+
+ io_uring_queue_exit(&ring);
+ return T_EXIT_PASS;
+}
diff --git a/contrib/libs/liburing/test/waitid.t/ya.make b/contrib/libs/liburing/test/waitid.t/ya.make
new file mode 100644
index 0000000000..f7f2ef1773
--- /dev/null
+++ b/contrib/libs/liburing/test/waitid.t/ya.make
@@ -0,0 +1,33 @@
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
+WITHOUT_LICENSE_TEXTS()
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/liburing
+)
+
+ADDINCL(
+ contrib/libs/liburing/src/include
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_RUNTIME()
+
+CFLAGS(
+ -DLIBURING_BUILD_TEST
+ -D__SANE_USERSPACE_TYPES__
+)
+
+SRCDIR(contrib/libs/liburing/test)
+
+SRCS(
+ helpers.c
+ waitid.c
+)
+
+END()
diff --git a/contrib/libs/liburing/test/wq-aff.c b/contrib/libs/liburing/test/wq-aff.c
new file mode 100644
index 0000000000..0548d6a698
--- /dev/null
+++ b/contrib/libs/liburing/test/wq-aff.c
@@ -0,0 +1,147 @@
+#include "../config-host.h"
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: test that io-wq affinity is correctly set for SQPOLL
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "liburing.h"
+#include "helpers.h"
+
+#define IOWQ_CPU 0
+#define SQPOLL_CPU 1
+
+static int verify_comm(pid_t pid, const char *name, int cpu)
+{
+ char comm[64], buf[64];
+ cpu_set_t set;
+ int fd, ret;
+
+ sprintf(comm, "/proc/%d/comm", pid);
+ fd = open(comm, O_RDONLY);
+ if (fd < 0) {
+ perror("open");
+ return T_EXIT_SKIP;
+ }
+
+ ret = read(fd, buf, sizeof(buf));
+ if (ret < 0) {
+ close(fd);
+ return T_EXIT_SKIP;
+ }
+
+ if (strncmp(buf, name, strlen(name) - 1)) {
+ close(fd);
+ return T_EXIT_SKIP;
+ }
+
+ close(fd);
+
+ ret = sched_getaffinity(pid, sizeof(set), &set);
+ if (ret < 0) {
+ perror("sched_getaffinity");
+ return T_EXIT_SKIP;
+ }
+
+ if (CPU_COUNT(&set) != 1) {
+ fprintf(stderr, "More than one CPU set in mask\n");
+ return T_EXIT_FAIL;
+ }
+ if (!CPU_ISSET(cpu, &set)) {
+ fprintf(stderr, "Wrong CPU set in mask\n");
+ return T_EXIT_FAIL;
+ }
+
+ return T_EXIT_PASS;
+}
+
+static int verify_affinity(pid_t pid, int sqpoll)
+{
+ pid_t wq_pid, sqpoll_pid = -1;
+ char name[64];
+ int ret;
+
+ wq_pid = pid + 2;
+ if (sqpoll)
+ sqpoll_pid = pid + 1;
+
+ /* verify we had the pids right */
+ sprintf(name, "iou-wrk-%d", pid);
+ ret = verify_comm(wq_pid, name, IOWQ_CPU);
+ if (ret != T_EXIT_PASS)
+ return ret;
+
+ if (sqpoll_pid != -1) {
+ sprintf(name, "iou-sqp-%d", pid);
+ ret = verify_comm(sqpoll_pid, name, SQPOLL_CPU);
+ if (ret != T_EXIT_PASS)
+ return ret;
+ }
+
+ return T_EXIT_PASS;
+}
+
+static int test(int sqpoll)
+{
+ struct io_uring_params p = { };
+ struct io_uring ring;
+ struct io_uring_sqe *sqe;
+ char buf[64];
+ int fds[2], ret;
+ cpu_set_t set;
+
+ if (sqpoll) {
+ p.flags = IORING_SETUP_SQPOLL | IORING_SETUP_SQ_AFF;
+ p.sq_thread_cpu = SQPOLL_CPU;
+ }
+
+ io_uring_queue_init_params(8, &ring, &p);
+
+ CPU_ZERO(&set);
+ CPU_SET(IOWQ_CPU, &set);
+
+ ret = io_uring_register_iowq_aff(&ring, sizeof(set), &set);
+ if (ret) {
+ fprintf(stderr, "register aff: %d\n", ret);
+ return T_EXIT_FAIL;
+ }
+
+ if (pipe(fds) < 0) {
+ perror("pipe");
+ return T_EXIT_FAIL;
+ }
+
+ sqe = io_uring_get_sqe(&ring);
+ io_uring_prep_read(sqe, fds[0], buf, sizeof(buf), 0);
+ sqe->flags |= IOSQE_ASYNC;
+
+ io_uring_submit(&ring);
+
+ usleep(10000);
+
+ ret = verify_affinity(getpid(), sqpoll);
+ io_uring_queue_exit(&ring);
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+
+ if (argc > 1)
+ return T_EXIT_SKIP;
+
+ ret = test(1);
+ if (ret == T_EXIT_SKIP) {
+ return T_EXIT_SKIP;
+ } else if (ret != T_EXIT_PASS) {
+ fprintf(stderr, "test sqpoll failed\n");
+ return T_EXIT_FAIL;
+ }
+
+ return T_EXIT_PASS;
+}
diff --git a/contrib/libs/liburing/test/wq-aff.t/ya.make b/contrib/libs/liburing/test/wq-aff.t/ya.make
new file mode 100644
index 0000000000..78b9a860e2
--- /dev/null
+++ b/contrib/libs/liburing/test/wq-aff.t/ya.make
@@ -0,0 +1,33 @@
+# Generated by devtools/yamaker.
+
+PROGRAM()
+
+WITHOUT_LICENSE_TEXTS()
+
+LICENSE(MIT)
+
+PEERDIR(
+ contrib/libs/liburing
+)
+
+ADDINCL(
+ contrib/libs/liburing/src/include
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_RUNTIME()
+
+CFLAGS(
+ -DLIBURING_BUILD_TEST
+ -D__SANE_USERSPACE_TYPES__
+)
+
+SRCDIR(contrib/libs/liburing/test)
+
+SRCS(
+ helpers.c
+ wq-aff.c
+)
+
+END()
diff --git a/contrib/libs/liburing/test/xattr.c b/contrib/libs/liburing/test/xattr.c
index 0c5870d33d..fe2c9ee9ad 100644
--- a/contrib/libs/liburing/test/xattr.c
+++ b/contrib/libs/liburing/test/xattr.c
@@ -295,7 +295,6 @@ Exit:
/* Test driver for failure cases of fsetxattr and fgetxattr. */
static int test_failure_fxattr(void)
{
- int rc = 0;
struct io_uring ring;
char value[XATTR_SIZE];
@@ -314,31 +313,36 @@ static int test_failure_fxattr(void)
}
/* Test writing attributes. */
- assert(io_uring_fsetxattr(&ring, -1, KEY1, VALUE1, strlen(VALUE1), 0) < 0);
- assert(io_uring_fsetxattr(&ring, fd, NULL, VALUE1, strlen(VALUE1), 0) < 0);
- assert(io_uring_fsetxattr(&ring, fd, KEY1, NULL, strlen(VALUE1), 0) < 0);
- assert(io_uring_fsetxattr(&ring, fd, KEY1, VALUE1, 0, 0) == 0);
- assert(io_uring_fsetxattr(&ring, fd, KEY1, VALUE1, -1, 0) < 0);
+ if (io_uring_fsetxattr(&ring, -1, KEY1, VALUE1, strlen(VALUE1), 0) >= 0)
+ return 1;
+ if (io_uring_fsetxattr(&ring, fd, NULL, VALUE1, strlen(VALUE1), 0) >= 0)
+ return 1;
+ if (io_uring_fsetxattr(&ring, fd, KEY1, NULL, strlen(VALUE1), 0) >= 0)
+ return 1;
+ if (io_uring_fsetxattr(&ring, fd, KEY1, VALUE1, 0, 0) != 0)
+ return 1;
+ if (io_uring_fsetxattr(&ring, fd, KEY1, VALUE1, -1, 0) >= 0)
+ return 1;
/* Test reading attributes. */
- assert(io_uring_fgetxattr(&ring, -1, KEY1, value, XATTR_SIZE) < 0);
- assert(io_uring_fgetxattr(&ring, fd, NULL, value, XATTR_SIZE) < 0);
- assert(io_uring_fgetxattr(&ring, fd, KEY1, value, 0) == 0);
+ if (io_uring_fgetxattr(&ring, -1, KEY1, value, XATTR_SIZE) >= 0)
+ return 1;
+ if (io_uring_fgetxattr(&ring, fd, NULL, value, XATTR_SIZE) >= 0)
+ return 1;
+ if (io_uring_fgetxattr(&ring, fd, KEY1, value, 0) != 0)
+ return 1;
/* Cleanup. */
close(fd);
unlink(FILENAME);
-
io_uring_queue_exit(&ring);
-
- return rc;
+ return 0;
}
/* Test driver for failure cases for setxattr and getxattr. */
static int test_failure_xattr(void)
{
- int rc = 0;
struct io_uring ring;
char value[XATTR_SIZE];
@@ -353,24 +357,33 @@ static int test_failure_xattr(void)
t_create_file(FILENAME, 0);
/* Test writing attributes. */
- assert(io_uring_setxattr(&ring, "complete garbage", KEY1, VALUE1, strlen(VALUE1), 0) < 0);
- assert(io_uring_setxattr(&ring, NULL, KEY1, VALUE1, strlen(VALUE1), 0) < 0);
- assert(io_uring_setxattr(&ring, FILENAME, NULL, VALUE1, strlen(VALUE1), 0) < 0);
- assert(io_uring_setxattr(&ring, FILENAME, KEY1, NULL, strlen(VALUE1), 0) < 0);
- assert(io_uring_setxattr(&ring, FILENAME, KEY1, VALUE1, 0, 0) == 0);
+ if (io_uring_setxattr(&ring, "complete garbage", KEY1, VALUE1, strlen(VALUE1), 0) >= 0)
+ return 1;
+ if (io_uring_setxattr(&ring, NULL, KEY1, VALUE1, strlen(VALUE1), 0) >= 0)
+ return 1;
+ if (io_uring_setxattr(&ring, FILENAME, NULL, VALUE1, strlen(VALUE1), 0) >= 0)
+ return 1;
+ if (io_uring_setxattr(&ring, FILENAME, KEY1, NULL, strlen(VALUE1), 0) >= 0)
+ return 1;
+ if (io_uring_setxattr(&ring, FILENAME, KEY1, VALUE1, 0, 0) != 0)
+ return 1;
/* Test reading attributes. */
- assert(io_uring_getxattr(&ring, "complete garbage", KEY1, value, XATTR_SIZE) < 0);
- assert(io_uring_getxattr(&ring, NULL, KEY1, value, XATTR_SIZE) < 0);
- assert(io_uring_getxattr(&ring, FILENAME, NULL, value, XATTR_SIZE) < 0);
- assert(io_uring_getxattr(&ring, FILENAME, KEY1, NULL, XATTR_SIZE) == 0);
- assert(io_uring_getxattr(&ring, FILENAME, KEY1, value, 0) == 0);
+ if (io_uring_getxattr(&ring, "complete garbage", KEY1, value, XATTR_SIZE) >= 0)
+ return 1;
+ if (io_uring_getxattr(&ring, NULL, KEY1, value, XATTR_SIZE) >= 0)
+ return 1;
+ if (io_uring_getxattr(&ring, FILENAME, NULL, value, XATTR_SIZE) >= 0)
+ return 1;
+ if (io_uring_getxattr(&ring, FILENAME, KEY1, NULL, XATTR_SIZE) != 0)
+ return 1;
+ if (io_uring_getxattr(&ring, FILENAME, KEY1, value, 0) != 0)
+ return 1;
/* Cleanup. */
io_uring_queue_exit(&ring);
unlink(FILENAME);
-
- return rc;
+ return 0;
}
/* Test for invalid SQE, this will cause a segmentation fault if enabled. */