diff options
author | robot-contrib <robot-contrib@yandex-team.com> | 2024-11-09 19:14:48 +0300 |
---|---|---|
committer | robot-contrib <robot-contrib@yandex-team.com> | 2024-11-09 19:25:43 +0300 |
commit | 9ade466e8683a2e3b45dacf45f74fcf4a3c40cee (patch) | |
tree | 5386d43454d677cb1239ed7a889dfcf101e99136 /contrib/libs/liburing | |
parent | 1f59ab019232ff97a73c7c13736b254925fa8b0b (diff) | |
download | ydb-9ade466e8683a2e3b45dacf45f74fcf4a3c40cee.tar.gz |
Update contrib/libs/liburing to 2.8
commit_hash:761e2e80642a3d32073f0261b3f5b1992e54a74f
Diffstat (limited to 'contrib/libs/liburing')
308 files changed, 7966 insertions, 847 deletions
diff --git a/contrib/libs/liburing/.yandex_meta/devtools.licenses.report b/contrib/libs/liburing/.yandex_meta/devtools.licenses.report index 94c6020f32..5677bdabba 100644 --- a/contrib/libs/liburing/.yandex_meta/devtools.licenses.report +++ b/contrib/libs/liburing/.yandex_meta/devtools.licenses.report @@ -87,6 +87,7 @@ BELONGS ya.make src/include/liburing/barrier.h [1:1] src/include/liburing/compat.h [1:1] src/include/liburing/io_uring_version.h [1:1] + src/include/liburing/sanitize.h [1:1] src/int_flags.h [1:1] src/lib.h [1:1] src/nolibc.c [2:2] @@ -118,6 +119,7 @@ BELONGS ya.make test/buf-ring-put.c [2:2] test/buf-ring.c [2:2] test/ce593a6c480a.c [2:2] + test/cmd-discard.c [2:2] test/connect-rep.c [2:2] test/connect.c [2:2] test/coredump.c [2:2] @@ -147,6 +149,8 @@ BELONGS ya.make test/fc2a85cb02ef.c [2:2] test/fd-install.c [2:2] test/fd-pass.c [2:2] + test/fdinfo.c [2:2] + test/fifo-nonblock-read.c [2:2] test/file-register.c [2:2] test/file-update.c [2:2] test/file-verify.c [2:2] @@ -173,18 +177,23 @@ BELONGS ya.make test/iopoll-leak.c [2:2] test/iopoll-overflow.c [2:2] test/iopoll.c [2:2] + test/kallsyms.c [2:2] test/lfs-openat-write.c [2:2] test/lfs-openat.c [2:2] test/link-timeout.c [2:2] test/link.c [2:2] test/link_drain.c [2:2] + test/linked-defer-close.c [2:2] test/madvise.c [2:2] + test/min-timeout-wait.c [2:2] + test/min-timeout.c [2:2] test/mkdir.c [2:2] test/msg-ring-fd.c [2:2] test/msg-ring-flags.c [2:2] test/msg-ring-overflow.c [2:2] test/msg-ring.c [2:2] test/multicqes_drain.c [2:2] + test/napi-test.c [2:2] test/no-mmap-inval.c [2:2] test/nolibc.c [2:2] test/nop-all-sizes.c [2:2] @@ -209,17 +218,21 @@ BELONGS ya.make test/poll-ring.c [2:2] test/poll-v-poll.c [2:2] test/poll.c [2:2] + test/pollfree.c [2:2] test/probe.c [2:2] test/read-before-exit.c [2:2] test/read-mshot-empty.c [2:2] + test/read-mshot-stdin.c [2:2] test/read-mshot.c [2:2] test/read-write.c [2:2] test/recv-msgall-stream.c [2:2] test/recv-msgall.c [2:2] + test/recvsend_bundle-inc.c [2:2] test/recvsend_bundle.c [2:2] test/reg-fd-only.c [2:2] test/reg-hint.c [2:2] test/reg-reg-ring.c [2:2] + test/regbuf-clone.c [2:2] test/regbuf-merge.c [2:2] test/register-restrictions.c [2:2] test/rename.c [2:2] @@ -256,6 +269,7 @@ BELONGS ya.make test/sqpoll-exec.c [2:2] test/sqpoll-exit-hang.c [2:2] test/sqpoll-sleep.c [2:2] + test/sqwait.c [2:2] test/stdout.c [2:2] test/submit-and-wait.c [2:2] test/submit-link-fail.c [2:2] @@ -270,7 +284,9 @@ BELONGS ya.make test/truncate.c [2:2] test/tty-write-dpoll.c [2:2] test/unlink.c [2:2] + test/uring_cmd_ublk.c [2:2] test/version.c [2:2] + test/wait-timeout.c [2:2] test/waitid.c [2:2] test/wakeup-hang.c [2:2] test/wq-aff.c [2:2] diff --git a/contrib/libs/liburing/.yandex_meta/override.nix b/contrib/libs/liburing/.yandex_meta/override.nix index afc13140e3..7118b3c759 100644 --- a/contrib/libs/liburing/.yandex_meta/override.nix +++ b/contrib/libs/liburing/.yandex_meta/override.nix @@ -1,12 +1,12 @@ pkgs: attrs: with pkgs; with attrs; rec { name = "liburing"; - version = "2.7"; + version = "2.8"; src = fetchFromGitHub { owner = "axboe"; repo = "liburing"; rev = "liburing-${version}"; - hash = "sha256-WhNlO2opPM7v4LOLWpmzPv31++zmn5Hmb6Su9IQBDH8="; + hash = "sha256-10zmoMDzO41oNRVXE/6FzDGPVRVJTJTARVUmc1b7f+o="; }; buildPhase = '' diff --git a/contrib/libs/liburing/CHANGELOG b/contrib/libs/liburing/CHANGELOG index 4eb15f38a4..ca1056ed4f 100644 --- a/contrib/libs/liburing/CHANGELOG +++ b/contrib/libs/liburing/CHANGELOG @@ -1,3 +1,19 @@ +liburing-2.8 release +- Add support for incrementally/partially consumed provided buffers, + usable with the provided buffer ring support. +- Add support for foo_and_wait_min_timeout(), where it's possible to + define a minimum timeout for waiting to get batches of completions, + but if that fails, extend for a longer timeout without having any + extra context switches. +- Add support for using different clock sources for completion waiting. +- Great increase coverage of test cases, test case improvements and + fixes. +- Man page updates +- Don't leak _GNU_SOURCE via pkb-config --cflags +- Support for address sanitizer +- Add examples/kdigest sample program +- Add discard helper, test, and man page + liburing-2.7 release - Man page updates diff --git a/contrib/libs/liburing/CONTRIBUTING.md b/contrib/libs/liburing/CONTRIBUTING.md new file mode 100644 index 0000000000..8bbce78a6c --- /dev/null +++ b/contrib/libs/liburing/CONTRIBUTING.md @@ -0,0 +1,165 @@ +Introduction +============ + +liburing welcomes contributions, whether they be bug fixes, features, or +documentation additions/updates. However, we do have some rules in place +to govern the sanity of the project, and all contributions should follow +the guidelines in this document. The main reasons for the rules are: + +1) Keep the code consistent +2) Keep the git repository consistent +3) Maintain bisectability + +Coding style +============ + +Generally, all the code in liburing should follow the same style. A few +known exceptions exist, like syzbot test cases that got committed rather +than re-writing them in a saner format. Any change you make, please +follow the style of the code around you. + +Commit format +============= + +Each commit should do one thing, and one thing only. If you find yourself, +in the commit message, adding phrases like "Also do [...]" or "While in +here [...]", then that's a sign that the change should have been split +into multiple commits. If your change includes some refactoring of code to +make your change possible, then that refactoring should be a separate +commit, done first. That means this preparatory commit won't have any +functional changes, and hence should be a no-op. It also means that your +main commit, with the change that you actually care about, will be smaller +and easier to review. + +Each commit must stand on its own in terms of what it provides, and how it +works. Lots of changes are just a single commit, but for something a bit +more involved, it's not uncommon to have a pull request contain multiple +commits. Make each commit as simple as possible, and not any simpler. We'd +much rather see 10 simple commits than 2 more complicated ones. If you +stumble across something that needs fixing while making an unrelated +change, then please make that change as a separate commit, explaining why +it's being made. + +Each commit in a series must be buildable, it's not enough that the end +result is buildable. See reason 3 in the introduction for why that's the +case. + +No fixup commits! Sometimes people post a change and errors are pointed +out in the commit, and the author then does a followup fix for that +error. This isn't acceptable, please squash fixup commits into the +commit that introduced the problem in the first place. This is done by +amending the fix into the original commit that caused the issue. You can +do that with git rebase -i <sha> and arrange the commit order such that +the fixup is right after the original commit, and then use 's' (for +squash) to squash the fixup into the original commit. Don't forget to +edit the commit message while doing that, as git will combine the two +commit messages into one. Or you can do it manually. Once done, force +push your rewritten git history. See reasons 1-3 in the introduction +series for why that is. + +Commit message +============== + +A good commit explains the WHY of a commit - explain the reason for this +commit to exist. Don't explain what the code in commit does, that should +be readily apparent from just reading the code. If that isn't the case, +then a comment in the code is going to be more useful than a lengthy +explanation in the commit message. liburing commits use the following +format: + +Title + +Body of commit + +Signed-off-by: ```My Identity <my@email.com>``` + +That is, a descriptive title on the first line, then an empty line, then +the body of the commit message, then an empty line, and finally an SOB +tag. The signed-off-by exists to provide proof of origin, see the +[DCO](https://developercertificate.org/). + +Example commit: + +``` +commit 0fe5c09195c0918f89582dd6ff098a58a0bdf62a +Author: Jens Axboe <axboe@kernel.dk> +Date: Fri Sep 6 15:54:04 2024 -0600 + + configure: fix ublk_cmd header check + + The previous commit is mixing private structures and defines with public + uapi ones. Testing for UBLK_U_CMD_START_DEV is fine, CTRL_CMD_HAS_DATA + is not. And struct ublk_ctrl_cmd_data is not a public struct. + + Fixes: 83bc535a3118 ("configure: don't enable ublk if modern commands not available") + Signed-off-by: Jens Axboe <axboe@kernel.dk> +``` + +Since this change is pretty trivial, a huge explanation need not be given +as to the reasonings for the change. However, for more complicated +changes, better reasonings should be given. + +A Fixes line can be added if this commit fixes an issue in a previous +commit. That kind of meta data can be useful down the line for finding +dependencies between commits. Adding the following to your .gitconfig: + +``` +[pretty] + fixes = Fixes: %h (\"%s\") +``` + +and running ```git fixes <sha>``` will then generate the correctly +formatted Fixes line for the commit. Likewise, other meta data can be: + +Link: https://somesite/somewhere + +can be useful to link to a discussion around the issue that led to this +commit, perhaps a bug report. This can be a GitHub issue as well. If a +commit closes/solves a GitHub issue, than: + +Closes: https://github.com/axboe/liburing/issues/XXXX + +can also be used. + +Each commit message should be formatted so each full line is 72-74 chars +wide. For many of us, GitHub is not the primary location, and git log is +often used in a terminal to browse the repo. Breaking lines at 72-74 +characters retains readability in an xterm/terminal. + +Pull Requests +============= + +The git repository itself is the canonical location for information. It's +quite fine to provide a lengthy explanation for a pull request on GitHub, +however please ensure that this doesn't come at the expense of the commit +messages themselves being lacking. The commit messages should stand on +their own and contain everything that you'd otherwise put in the PR +message. If you've worked on projects that send patches before, consider +the PR message similar to the cover letter for a series of patches. + +Most contributors seem to use GH for sending patches, which is fine. If +you prefer using email, then patches can also be sent to the io_uring +mailing list: io-uring@vger.kernel.org. + +liburing doesn't squash/rebase-on-merge, or other heinous practices +sometimes seen elsewhere. Whatever sha your commit has in your tree is +what it'll have in the upstream tree. Patches are applied directly, and +pull requests are merged with a merge commit. If meta data needs to go +into the merge commit, then it will go into the merge commit message. +This means that you don't need to continually rebase your changes on top +of the master branch. + +Testing changes +=============== + +You should ALWAYS test your changes, no matter how trivial or obviously +correct they may seem. Nobody is infallible, and making mistakes is only +human. + +liburing contains a wide variety of functional tests. If you make changes +to liburing, then you should run the test cases. This is done by building +the repo and running ```make runtests```. Note that some of the liburing +tests test for defects in older kernels, and hence it's possible that they +will crash on an outdated kernel that doesn't contain fixes from the +stable kernel tree. If in doubt, building and running the tests in a vm is +encouraged. diff --git a/contrib/libs/liburing/src/include/liburing.h b/contrib/libs/liburing/src/include/liburing.h index 1092f3b10b..6eae138975 100644 --- a/contrib/libs/liburing/src/include/liburing.h +++ b/contrib/libs/liburing/src/include/liburing.h @@ -19,6 +19,7 @@ #include "liburing/io_uring_version.h" #include "liburing/barrier.h" + #ifndef uring_unlikely #define uring_unlikely(cond) __builtin_expect(!!(cond), 0) #endif @@ -173,6 +174,12 @@ unsigned io_uring_peek_batch_cqe(struct io_uring *ring, int io_uring_wait_cqes(struct io_uring *ring, struct io_uring_cqe **cqe_ptr, unsigned wait_nr, struct __kernel_timespec *ts, sigset_t *sigmask); +int io_uring_wait_cqes_min_timeout(struct io_uring *ring, + struct io_uring_cqe **cqe_ptr, + unsigned wait_nr, + struct __kernel_timespec *ts, + unsigned int min_ts_usec, + sigset_t *sigmask); int io_uring_wait_cqe_timeout(struct io_uring *ring, struct io_uring_cqe **cqe_ptr, struct __kernel_timespec *ts); @@ -183,7 +190,14 @@ int io_uring_submit_and_wait_timeout(struct io_uring *ring, unsigned wait_nr, struct __kernel_timespec *ts, sigset_t *sigmask); +int io_uring_submit_and_wait_min_timeout(struct io_uring *ring, + struct io_uring_cqe **cqe_ptr, + unsigned wait_nr, + struct __kernel_timespec *ts, + unsigned min_wait, + sigset_t *sigmask); +int io_uring_clone_buffers(struct io_uring *dst, struct io_uring *src); int io_uring_register_buffers(struct io_uring *ring, const struct iovec *iovecs, unsigned nr_iovecs); int io_uring_register_buffers_tags(struct io_uring *ring, @@ -220,8 +234,10 @@ int io_uring_register_restrictions(struct io_uring *ring, unsigned int nr_res); int io_uring_enable_rings(struct io_uring *ring); int __io_uring_sqring_wait(struct io_uring *ring); +#ifdef _GNU_SOURCE int io_uring_register_iowq_aff(struct io_uring *ring, size_t cpusz, const cpu_set_t *mask); +#endif int io_uring_unregister_iowq_aff(struct io_uring *ring); int io_uring_register_iowq_max_workers(struct io_uring *ring, unsigned int *values); @@ -241,6 +257,9 @@ int io_uring_register_file_alloc_range(struct io_uring *ring, int io_uring_register_napi(struct io_uring *ring, struct io_uring_napi *napi); int io_uring_unregister_napi(struct io_uring *ring, struct io_uring_napi *napi); +int io_uring_register_clock(struct io_uring *ring, + struct io_uring_clock_register *arg); + int io_uring_get_events(struct io_uring *ring); int io_uring_submit_and_get_events(struct io_uring *ring); @@ -262,7 +281,7 @@ int io_uring_register(unsigned int fd, unsigned int opcode, const void *arg, struct io_uring_buf_ring *io_uring_setup_buf_ring(struct io_uring *ring, unsigned int nentries, int bgid, unsigned int flags, - int *ret); + int *err); int io_uring_free_buf_ring(struct io_uring *ring, struct io_uring_buf_ring *br, unsigned int nentries, int bgid); @@ -286,15 +305,22 @@ int __io_uring_get_cqe(struct io_uring *ring, #define io_uring_cqe_index(ring,ptr,mask) \ (((ptr) & (mask)) << io_uring_cqe_shift(ring)) +/* + * NOTE: we should just get rid of the 'head' being passed in here, it doesn't + * serve a purpose anymore. The below is a bit of a work-around to ensure that + * the compiler doesn't complain about 'head' being unused (or only written, + * never read), as we use a local iterator for both the head and tail tracking. + */ #define io_uring_for_each_cqe(ring, head, cqe) \ /* \ * io_uring_smp_load_acquire() enforces the order of tail \ * and CQE reads. \ */ \ - for (head = *(ring)->cq.khead; \ - (cqe = (head != io_uring_smp_load_acquire((ring)->cq.ktail) ? \ - &(ring)->cq.cqes[io_uring_cqe_index(ring, head, (ring)->cq.ring_mask)] : NULL)); \ - head++) \ + for (__u32 __HEAD__ = (head) = *(ring)->cq.khead, \ + __TAIL__ = io_uring_smp_load_acquire((ring)->cq.ktail); \ + (cqe = ((head) != __TAIL__ ? \ + &(ring)->cq.cqes[io_uring_cqe_index(ring, __HEAD__, (ring)->cq.ring_mask)] : NULL)); \ + (head) = ++__HEAD__) /* * Must be called after io_uring_for_each_cqe() @@ -719,6 +745,20 @@ IOURINGINLINE void io_uring_prep_openat_direct(struct io_uring_sqe *sqe, __io_uring_set_target_fixed_file(sqe, file_index); } +IOURINGINLINE void io_uring_prep_open(struct io_uring_sqe *sqe, + const char *path, int flags, mode_t mode) +{ + io_uring_prep_openat(sqe, AT_FDCWD, path, flags, mode); +} + +/* open directly into the fixed file table */ +IOURINGINLINE void io_uring_prep_open_direct(struct io_uring_sqe *sqe, + const char *path, int flags, mode_t mode, + unsigned file_index) +{ + io_uring_prep_openat_direct(sqe, AT_FDCWD, path, flags, mode, file_index); +} + IOURINGINLINE void io_uring_prep_close(struct io_uring_sqe *sqe, int fd) { io_uring_prep_rw(IORING_OP_CLOSE, sqe, fd, NULL, 0, 0); @@ -1244,11 +1284,23 @@ IOURINGINLINE void io_uring_prep_fixed_fd_install(struct io_uring_sqe *sqe, sqe->install_fd_flags = flags; } +#ifdef _GNU_SOURCE IOURINGINLINE void io_uring_prep_ftruncate(struct io_uring_sqe *sqe, int fd, loff_t len) { io_uring_prep_rw(IORING_OP_FTRUNCATE, sqe, fd, 0, 0, len); } +#endif + +IOURINGINLINE void io_uring_prep_cmd_discard(struct io_uring_sqe *sqe, + int fd, + uint64_t offset, uint64_t nbytes) +{ + io_uring_prep_rw(IORING_OP_URING_CMD, sqe, fd, 0, 0, 0); + sqe->cmd_op = BLOCK_URING_CMD_DISCARD; + sqe->addr = offset; + sqe->addr3 = nbytes; +} /* * Returns number of unconsumed (if SQPOLL) or unsubmitted entries exist in diff --git a/contrib/libs/liburing/src/include/liburing/compat.h b/contrib/libs/liburing/src/include/liburing/compat.h index 717f81cb7f..6a5678beae 100644 --- a/contrib/libs/liburing/src/include/liburing/compat.h +++ b/contrib/libs/liburing/src/include/liburing/compat.h @@ -8,4 +8,11 @@ #include <linux/openat2.h> + +#include <linux/ioctl.h> + +#ifndef BLOCK_URING_CMD_DISCARD +#define BLOCK_URING_CMD_DISCARD _IO(0x12, 0) +#endif + #endif diff --git a/contrib/libs/liburing/src/include/liburing/io_uring.h b/contrib/libs/liburing/src/include/liburing/io_uring.h index 01c36a83f3..4ac13f7327 100644 --- a/contrib/libs/liburing/src/include/liburing/io_uring.h +++ b/contrib/libs/liburing/src/include/liburing/io_uring.h @@ -116,7 +116,7 @@ struct io_uring_sqe { */ #define IORING_FILE_INDEX_ALLOC (~0U) -enum { +enum io_uring_sqe_flags_bit { IOSQE_FIXED_FILE_BIT, IOSQE_IO_DRAIN_BIT, IOSQE_IO_LINK_BIT, @@ -184,7 +184,7 @@ enum { #define IORING_SETUP_DEFER_TASKRUN (1U << 13) /* - * Application provides ring memory + * Application provides the memory for the rings */ #define IORING_SETUP_NO_MMAP (1U << 14) @@ -265,11 +265,12 @@ enum io_uring_op { }; /* - * sqe->uring_cmd_flags + * sqe->uring_cmd_flags top 8bits aren't available for userspace * IORING_URING_CMD_FIXED use registered buffer; pass this flag * along with setting sqe->buf_index. */ #define IORING_URING_CMD_FIXED (1U << 0) +#define IORING_URING_CMD_MASK IORING_URING_CMD_FIXED /* @@ -317,15 +318,19 @@ enum io_uring_op { * ASYNC_CANCEL flags. * * IORING_ASYNC_CANCEL_ALL Cancel all requests that match the given key - * IORING_ASYNC_CANCEL_FD Key off 'fd' for cancelation rather than the + * IORING_ASYNC_CANCEL_FD Key off 'fd' for cancelation rather than the * request 'user_data' * IORING_ASYNC_CANCEL_ANY Match any request * IORING_ASYNC_CANCEL_FD_FIXED 'fd' passed in is a fixed descriptor + * IORING_ASYNC_CANCEL_USERDATA Match on user_data, default for no other key + * IORING_ASYNC_CANCEL_OP Match request based on opcode */ #define IORING_ASYNC_CANCEL_ALL (1U << 0) #define IORING_ASYNC_CANCEL_FD (1U << 1) #define IORING_ASYNC_CANCEL_ANY (1U << 2) #define IORING_ASYNC_CANCEL_FD_FIXED (1U << 3) +#define IORING_ASYNC_CANCEL_USERDATA (1U << 4) +#define IORING_ASYNC_CANCEL_OP (1U << 5) /* * send/sendmsg and recv/recvmsg flags (sqe->ioprio) @@ -350,13 +355,13 @@ enum io_uring_op { * IORING_NOTIF_USAGE_ZC_COPIED if data was copied * (at least partially). * - * IORING_RECVSEND_BUNDLE Used with IOSQE_BUFFER_SELECT. If set, send wil - * grab as many buffers from the buffer group ID - * given and send them all. The completion result - * will be the number of buffers send, with the - * starting buffer ID in cqe->flags as per usual - * for provided buffer usage. The buffers will be - * contigious from the starting buffer ID. + * IORING_RECVSEND_BUNDLE Used with IOSQE_BUFFER_SELECT. If set, send or + * recv will grab as many buffers from the buffer + * group ID given and send them all. The completion + * result will be the number of buffers send, with + * the starting buffer ID in cqe->flags as per + * usual for provided buffer usage. The buffers + * will be contiguous from the starting buffer ID. */ #define IORING_RECVSEND_POLL_FIRST (1U << 0) #define IORING_RECV_MULTISHOT (1U << 1) @@ -383,7 +388,7 @@ enum io_uring_op { /* * IORING_OP_MSG_RING command types, stored in sqe->addr */ -enum { +enum io_uring_msg_ring_flags { IORING_MSG_DATA, /* pass sqe->len as 'res' and off as user_data */ IORING_MSG_SEND_FD, /* send a registered fd to another ring */ }; @@ -416,7 +421,7 @@ enum { * IO completion data structure (Completion Queue Entry) */ struct io_uring_cqe { - __u64 user_data; /* sqe->user_data value passed back */ + __u64 user_data; /* sqe->user_data submission passed back */ __s32 res; /* result code for this event */ __u32 flags; @@ -435,15 +440,23 @@ struct io_uring_cqe { * IORING_CQE_F_SOCK_NONEMPTY If set, more data to read after socket recv * IORING_CQE_F_NOTIF Set for notification CQEs. Can be used to distinct * them from sends. + * IORING_CQE_F_BUF_MORE If set, the buffer ID set in the completion will get + * more completions. In other words, the buffer is being + * partially consumed, and will be used by the kernel for + * more completions. This is only set for buffers used via + * the incremental buffer consumption, as provided by + * a ring buffer setup with IOU_PBUF_RING_INC. For any + * other provided buffer type, all completions with a + * buffer passed back is automatically returned to the + * application. */ #define IORING_CQE_F_BUFFER (1U << 0) #define IORING_CQE_F_MORE (1U << 1) #define IORING_CQE_F_SOCK_NONEMPTY (1U << 2) #define IORING_CQE_F_NOTIF (1U << 3) +#define IORING_CQE_F_BUF_MORE (1U << 4) -enum { - IORING_CQE_BUFFER_SHIFT = 16, -}; +#define IORING_CQE_BUFFER_SHIFT 16 /* * Magic offsets for the application to mmap the data it needs @@ -504,6 +517,7 @@ struct io_cqring_offsets { #define IORING_ENTER_SQ_WAIT (1U << 2) #define IORING_ENTER_EXT_ARG (1U << 3) #define IORING_ENTER_REGISTERED_RING (1U << 4) +#define IORING_ENTER_ABS_TIMER (1U << 5) /* * Passed in for io_uring_setup(2). Copied back with updated info on success @@ -539,11 +553,12 @@ struct io_uring_params { #define IORING_FEAT_LINKED_FILE (1U << 12) #define IORING_FEAT_REG_REG_RING (1U << 13) #define IORING_FEAT_RECVSEND_BUNDLE (1U << 14) +#define IORING_FEAT_MIN_TIMEOUT (1U << 15) /* * io_uring_register(2) opcodes and arguments */ -enum { +enum io_uring_register_op { IORING_REGISTER_BUFFERS = 0, IORING_UNREGISTER_BUFFERS = 1, IORING_REGISTER_FILES = 2, @@ -592,6 +607,11 @@ enum { IORING_REGISTER_NAPI = 27, IORING_UNREGISTER_NAPI = 28, + IORING_REGISTER_CLOCK = 29, + + /* clone registered buffers from source ring to current ring */ + IORING_REGISTER_CLONE_BUFFERS = 30, + /* this goes last */ IORING_REGISTER_LAST, @@ -600,7 +620,7 @@ enum { }; /* io-wq worker categories */ -enum { +enum io_wq_type { IO_WQ_BOUND, IO_WQ_UNBOUND, }; @@ -672,6 +692,21 @@ struct io_uring_restriction { __u32 resv2[3]; }; +struct io_uring_clock_register { + __u32 clockid; + __u32 __resv[3]; +}; + +enum { + IORING_REGISTER_SRC_REGISTERED = 1, +}; + +struct io_uring_clone_buffers { + __u32 src_fd; + __u32 flags; + __u32 pad[6]; +}; + struct io_uring_buf { __u64 addr; __u32 len; @@ -704,9 +739,17 @@ struct io_uring_buf_ring { * mmap(2) with the offset set as: * IORING_OFF_PBUF_RING | (bgid << IORING_OFF_PBUF_SHIFT) * to get a virtual mapping for the ring. - */ -enum { + * IOU_PBUF_RING_INC: If set, buffers consumed from this buffer ring can be + * consumed incrementally. Normally one (or more) buffers + * are fully consumed. With incremental consumptions, it's + * feasible to register big ranges of buffers, and each + * use of it will consume only as much as it needs. This + * requires that both the kernel and application keep + * track of where the current read/recv index is at. + */ +enum io_uring_register_pbuf_ring_flags { IOU_PBUF_RING_MMAP = 1, + IOU_PBUF_RING_INC = 2, }; /* argument for IORING_(UN)REGISTER_PBUF_RING */ @@ -727,16 +770,16 @@ struct io_uring_buf_status { /* argument for IORING_(UN)REGISTER_NAPI */ struct io_uring_napi { - __u32 busy_poll_to; - __u8 prefer_busy_poll; - __u8 pad[3]; - __u64 resv; + __u32 busy_poll_to; + __u8 prefer_busy_poll; + __u8 pad[3]; + __u64 resv; }; /* * io_uring_restriction->opcode values */ -enum { +enum io_uring_register_restriction_op { /* Allow an io_uring_register(2) opcode */ IORING_RESTRICTION_REGISTER_OP = 0, @@ -755,7 +798,7 @@ enum { struct io_uring_getevents_arg { __u64 sigmask; __u32 sigmask_sz; - __u32 pad; + __u32 min_wait_usec; __u64 ts; }; @@ -767,7 +810,9 @@ struct io_uring_sync_cancel_reg { __s32 fd; __u32 flags; struct __kernel_timespec timeout; - __u64 pad[4]; + __u8 opcode; + __u8 pad[7]; + __u64 pad2[3]; }; /* @@ -790,7 +835,7 @@ struct io_uring_recvmsg_out { /* * Argument for IORING_OP_URING_CMD when file is a socket */ -enum { +enum io_uring_socket_op { SOCKET_URING_OP_SIOCINQ = 0, SOCKET_URING_OP_SIOCOUTQ, SOCKET_URING_OP_GETSOCKOPT, diff --git a/contrib/libs/liburing/src/include/liburing/io_uring_version.h b/contrib/libs/liburing/src/include/liburing/io_uring_version.h index 37aba1d0b4..6705e52610 100644 --- a/contrib/libs/liburing/src/include/liburing/io_uring_version.h +++ b/contrib/libs/liburing/src/include/liburing/io_uring_version.h @@ -3,6 +3,6 @@ #define LIBURING_VERSION_H #define IO_URING_VERSION_MAJOR 2 -#define IO_URING_VERSION_MINOR 7 +#define IO_URING_VERSION_MINOR 8 #endif diff --git a/contrib/libs/liburing/src/include/liburing/sanitize.h b/contrib/libs/liburing/src/include/liburing/sanitize.h new file mode 100644 index 0000000000..9a539613d7 --- /dev/null +++ b/contrib/libs/liburing/src/include/liburing/sanitize.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: MIT */ +#ifndef LIBURING_SANITIZE_H +#define LIBURING_SANITIZE_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct io_uring; +struct iovec; + +#if defined(CONFIG_USE_SANITIZER) +void liburing_sanitize_ring(struct io_uring *ring); +void liburing_sanitize_address(const void *addr); +void liburing_sanitize_region(const void *addr, unsigned int len); +void liburing_sanitize_iovecs(const struct iovec *iovecs, unsigned nr); +#else +#define __maybe_unused __attribute__((__unused__)) +static inline void liburing_sanitize_ring(struct io_uring __maybe_unused *ring) +{ +} +static inline void liburing_sanitize_address(const void __maybe_unused *addr) +{ +} +static inline void liburing_sanitize_region(const void __maybe_unused *addr, + unsigned int __maybe_unused len) +{ +} +static inline void liburing_sanitize_iovecs(const struct iovec __maybe_unused *iovecs, + unsigned __maybe_unused nr) +{ +} +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/libs/liburing/src/int_flags.h b/contrib/libs/liburing/src/int_flags.h index 548dd1094c..7cfdd3c4d8 100644 --- a/contrib/libs/liburing/src/int_flags.h +++ b/contrib/libs/liburing/src/int_flags.h @@ -2,10 +2,17 @@ #ifndef LIBURING_INT_FLAGS #define LIBURING_INT_FLAGS +#define INT_FLAGS_MASK (IORING_ENTER_REGISTERED_RING) + enum { - INT_FLAG_REG_RING = 1, - INT_FLAG_REG_REG_RING = 2, - INT_FLAG_APP_MEM = 4, + INT_FLAG_REG_RING = IORING_ENTER_REGISTERED_RING, + INT_FLAG_REG_REG_RING = 1, + INT_FLAG_APP_MEM = 2, }; +static inline int ring_enter_flags(struct io_uring *ring) +{ + return ring->int_flags & INT_FLAGS_MASK; +} + #endif diff --git a/contrib/libs/liburing/src/liburing.map b/contrib/libs/liburing/src/liburing.map index 28e35c889a..c13cd36ece 100644 --- a/contrib/libs/liburing/src/liburing.map +++ b/contrib/libs/liburing/src/liburing.map @@ -95,3 +95,11 @@ LIBURING_2.6 { LIBURING_2.7 { } LIBURING_2.6; + +LIBURING_2.8 { + global: + io_uring_register_clock; + io_uring_submit_and_wait_min_timeout; + io_uring_wait_cqes_min_timeout; + io_uring_clone_buffers; +} LIBURING_2.7; diff --git a/contrib/libs/liburing/src/queue.c b/contrib/libs/liburing/src/queue.c index 79457c35ae..6e855a2d3d 100644 --- a/contrib/libs/liburing/src/queue.c +++ b/contrib/libs/liburing/src/queue.c @@ -6,6 +6,7 @@ #include "syscall.h" #include "liburing.h" #include "int_flags.h" +#include "liburing/sanitize.h" #include "liburing/compat.h" #include "liburing/io_uring.h" @@ -70,7 +71,7 @@ static int _io_uring_get_cqe(struct io_uring *ring, do { bool need_enter = false; - unsigned flags = 0; + unsigned flags = ring_enter_flags(ring); unsigned nr_available; int ret; @@ -94,7 +95,7 @@ static int _io_uring_get_cqe(struct io_uring *ring, need_enter = true; } if (data->wait_nr > nr_available || need_enter) { - flags = IORING_ENTER_GETEVENTS | data->get_flags; + flags |= IORING_ENTER_GETEVENTS | data->get_flags; need_enter = true; } if (sq_ring_needs_enter(ring, data->submit, &flags)) @@ -109,8 +110,6 @@ static int _io_uring_get_cqe(struct io_uring *ring, break; } - if (ring->int_flags & INT_FLAG_REG_RING) - flags |= IORING_ENTER_REGISTERED_RING; ret = __sys_io_uring_enter2(ring->enter_ring_fd, data->submit, data->wait_nr, flags, data->arg, data->sz); @@ -149,10 +148,8 @@ int __io_uring_get_cqe(struct io_uring *ring, struct io_uring_cqe **cqe_ptr, int io_uring_get_events(struct io_uring *ring) { - int flags = IORING_ENTER_GETEVENTS; + int flags = IORING_ENTER_GETEVENTS | ring_enter_flags(ring); - if (ring->int_flags & INT_FLAG_REG_RING) - flags |= IORING_ENTER_REGISTERED_RING; return __sys_io_uring_enter(ring->enter_ring_fd, 0, 0, flags, NULL); } @@ -235,6 +232,7 @@ static int io_uring_wait_cqes_new(struct io_uring *ring, struct io_uring_cqe **cqe_ptr, unsigned wait_nr, struct __kernel_timespec *ts, + unsigned int min_wait_usec, sigset_t *sigmask) { struct io_uring_getevents_arg arg = { @@ -250,6 +248,9 @@ static int io_uring_wait_cqes_new(struct io_uring *ring, .arg = &arg }; + if (min_wait_usec && ring->features & IORING_FEAT_MIN_TIMEOUT) + arg.min_wait_usec = min_wait_usec; + return _io_uring_get_cqe(ring, cqe_ptr, &data); } @@ -302,7 +303,7 @@ int io_uring_wait_cqes(struct io_uring *ring, struct io_uring_cqe **cqe_ptr, if (ts) { if (ring->features & IORING_FEAT_EXT_ARG) return io_uring_wait_cqes_new(ring, cqe_ptr, wait_nr, - ts, sigmask); + ts, 0, sigmask); to_submit = __io_uring_submit_timeout(ring, wait_nr, ts); if (to_submit < 0) return to_submit; @@ -311,11 +312,20 @@ int io_uring_wait_cqes(struct io_uring *ring, struct io_uring_cqe **cqe_ptr, return __io_uring_get_cqe(ring, cqe_ptr, to_submit, wait_nr, sigmask); } -int io_uring_submit_and_wait_timeout(struct io_uring *ring, - struct io_uring_cqe **cqe_ptr, - unsigned wait_nr, - struct __kernel_timespec *ts, - sigset_t *sigmask) +int io_uring_wait_cqes_min_timeout(struct io_uring *ring, + struct io_uring_cqe **cqe_ptr, + unsigned wait_nr, + struct __kernel_timespec *ts, + unsigned int min_wait_usec, sigset_t *sigmask) +{ + return io_uring_wait_cqes_new(ring, cqe_ptr, wait_nr, ts, min_wait_usec, + sigmask); +} + +static int __io_uring_submit_and_wait_timeout(struct io_uring *ring, + struct io_uring_cqe **cqe_ptr, unsigned wait_nr, + struct __kernel_timespec *ts, + unsigned int min_wait, sigset_t *sigmask) { int to_submit; @@ -324,6 +334,7 @@ int io_uring_submit_and_wait_timeout(struct io_uring *ring, struct io_uring_getevents_arg arg = { .sigmask = (unsigned long) sigmask, .sigmask_sz = _NSIG / 8, + .min_wait_usec = min_wait, .ts = (unsigned long) ts }; struct get_data data = { @@ -346,6 +357,29 @@ int io_uring_submit_and_wait_timeout(struct io_uring *ring, return __io_uring_get_cqe(ring, cqe_ptr, to_submit, wait_nr, sigmask); } +int io_uring_submit_and_wait_min_timeout(struct io_uring *ring, + struct io_uring_cqe **cqe_ptr, + unsigned wait_nr, + struct __kernel_timespec *ts, + unsigned min_wait, + sigset_t *sigmask) +{ + if (!(ring->features & IORING_FEAT_MIN_TIMEOUT)) + return -EINVAL; + return __io_uring_submit_and_wait_timeout(ring, cqe_ptr, wait_nr, ts, + min_wait, sigmask); +} + +int io_uring_submit_and_wait_timeout(struct io_uring *ring, + struct io_uring_cqe **cqe_ptr, + unsigned wait_nr, + struct __kernel_timespec *ts, + sigset_t *sigmask) +{ + return __io_uring_submit_and_wait_timeout(ring, cqe_ptr, wait_nr, ts, 0, + sigmask); +} + /* * See io_uring_wait_cqes() - this function is the same, it just always uses * '1' as the wait_nr. @@ -366,15 +400,14 @@ static int __io_uring_submit(struct io_uring *ring, unsigned submitted, unsigned wait_nr, bool getevents) { bool cq_needs_enter = getevents || wait_nr || cq_ring_needs_enter(ring); - unsigned flags; + unsigned flags = ring_enter_flags(ring); int ret; - flags = 0; + liburing_sanitize_ring(ring); + if (sq_ring_needs_enter(ring, submitted, &flags) || cq_needs_enter) { if (cq_needs_enter) flags |= IORING_ENTER_GETEVENTS; - if (ring->int_flags & INT_FLAG_REG_RING) - flags |= IORING_ENTER_REGISTERED_RING; ret = __sys_io_uring_enter(ring->enter_ring_fd, submitted, wait_nr, flags, NULL); @@ -423,10 +456,7 @@ struct io_uring_sqe *io_uring_get_sqe(struct io_uring *ring) int __io_uring_sqring_wait(struct io_uring *ring) { - int flags = IORING_ENTER_SQ_WAIT; - - if (ring->int_flags & INT_FLAG_REG_RING) - flags |= IORING_ENTER_REGISTERED_RING; + int flags = IORING_ENTER_SQ_WAIT | ring_enter_flags(ring); return __sys_io_uring_enter(ring->enter_ring_fd, 0, 0, flags, NULL); } diff --git a/contrib/libs/liburing/src/register.c b/contrib/libs/liburing/src/register.c index 7a97303a0e..c215da7f21 100644 --- a/contrib/libs/liburing/src/register.c +++ b/contrib/libs/liburing/src/register.c @@ -8,12 +8,15 @@ #include "int_flags.h" #include "liburing/compat.h" #include "liburing/io_uring.h" +#include "liburing/sanitize.h" static inline int do_register(struct io_uring *ring, unsigned int opcode, const void *arg, unsigned int nr_args) { int fd; + liburing_sanitize_address(arg); + if (ring->int_flags & INT_FLAG_REG_REG_RING) { opcode |= IORING_REGISTER_USE_REGISTERED_RING; fd = ring->enter_ring_fd; @@ -29,6 +32,8 @@ int io_uring_register_buffers_update_tag(struct io_uring *ring, unsigned off, const __u64 *tags, unsigned nr) { + liburing_sanitize_iovecs(iovecs, nr); + struct io_uring_rsrc_update2 up = { .offset = off, .data = (unsigned long)iovecs, @@ -44,6 +49,8 @@ int io_uring_register_buffers_tags(struct io_uring *ring, const __u64 *tags, unsigned nr) { + liburing_sanitize_iovecs(iovecs, nr); + struct io_uring_rsrc_register reg = { .nr = nr, .data = (unsigned long)iovecs, @@ -66,6 +73,8 @@ int io_uring_register_buffers_sparse(struct io_uring *ring, unsigned nr) int io_uring_register_buffers(struct io_uring *ring, const struct iovec *iovecs, unsigned nr_iovecs) { + liburing_sanitize_iovecs(iovecs, nr_iovecs); + return do_register(ring, IORING_REGISTER_BUFFERS, iovecs, nr_iovecs); } @@ -78,6 +87,9 @@ int io_uring_register_files_update_tag(struct io_uring *ring, unsigned off, const int *files, const __u64 *tags, unsigned nr_files) { + liburing_sanitize_address(files); + liburing_sanitize_address(tags); + struct io_uring_rsrc_update2 up = { .offset = off, .data = (unsigned long)files, @@ -98,6 +110,8 @@ int io_uring_register_files_update_tag(struct io_uring *ring, unsigned off, int io_uring_register_files_update(struct io_uring *ring, unsigned off, const int *files, unsigned nr_files) { + liburing_sanitize_address(files); + struct io_uring_files_update up = { .offset = off, .fds = (unsigned long) files, @@ -149,6 +163,9 @@ int io_uring_register_files_sparse(struct io_uring *ring, unsigned nr) int io_uring_register_files_tags(struct io_uring *ring, const int *files, const __u64 *tags, unsigned nr) { + liburing_sanitize_address(files); + liburing_sanitize_address(tags); + struct io_uring_rsrc_register reg = { .nr = nr, .data = (unsigned long)files, @@ -176,6 +193,8 @@ int io_uring_register_files(struct io_uring *ring, const int *files, { int ret, did_increase = 0; + liburing_sanitize_address(files); + do { ret = do_register(ring, IORING_REGISTER_FILES, files, nr_files); if (ret >= 0) @@ -317,6 +336,7 @@ int io_uring_register_buf_ring(struct io_uring *ring, struct io_uring_buf_reg *reg, unsigned int __maybe_unused flags) { + reg->flags |= flags; return do_register(ring, IORING_REGISTER_PBUF_RING, reg, 1); } @@ -329,6 +349,8 @@ int io_uring_unregister_buf_ring(struct io_uring *ring, int bgid) int io_uring_buf_ring_head(struct io_uring *ring, int buf_group, uint16_t *head) { + liburing_sanitize_address(head); + struct io_uring_buf_status buf_status = { .buf_group = buf_group, }; @@ -367,3 +389,23 @@ int io_uring_unregister_napi(struct io_uring *ring, struct io_uring_napi *napi) { return do_register(ring, IORING_UNREGISTER_NAPI, napi, 1); } + +int io_uring_register_clock(struct io_uring *ring, + struct io_uring_clock_register *arg) +{ + return do_register(ring, IORING_REGISTER_CLOCK, arg, 0); +} + +int io_uring_clone_buffers(struct io_uring *dst, struct io_uring *src) +{ + struct io_uring_clone_buffers buf = { .src_fd = src->ring_fd, }; + + if (src->int_flags & INT_FLAG_REG_REG_RING) { + buf.src_fd = src->enter_ring_fd; + buf.flags = IORING_REGISTER_SRC_REGISTERED; + } else { + buf.src_fd = src->ring_fd; + } + + return do_register(dst, IORING_REGISTER_CLONE_BUFFERS, &buf, 1); +} diff --git a/contrib/libs/liburing/src/setup.c b/contrib/libs/liburing/src/setup.c index aa0fcaaaa5..fef92dbd48 100644 --- a/contrib/libs/liburing/src/setup.c +++ b/contrib/libs/liburing/src/setup.c @@ -223,9 +223,9 @@ static int io_uring_alloc_huge(unsigned entries, struct io_uring_params *p, ring_mem = KRING_SIZE; sqes_mem = sq_entries * sizeof(struct io_uring_sqe); - sqes_mem = (sqes_mem + page_size - 1) & ~(page_size - 1); if (!(p->flags & IORING_SETUP_NO_SQARRAY)) sqes_mem += sq_entries * sizeof(unsigned); + sqes_mem = (sqes_mem + page_size - 1) & ~(page_size - 1); cqes_mem = cq_entries * sizeof(struct io_uring_cqe); if (p->flags & IORING_SETUP_CQE32) @@ -434,7 +434,7 @@ __cold void io_uring_queue_exit(struct io_uring *ring) struct io_uring_cq *cq = &ring->cq; size_t sqe_size; - if (!sq->ring_sz) { + if (!sq->ring_sz && !(ring->int_flags & INT_FLAG_APP_MEM)) { sqe_size = sizeof(struct io_uring_sqe); if (ring->flags & IORING_SETUP_SQE128) sqe_size += 64; @@ -596,7 +596,7 @@ __cold ssize_t io_uring_mlock_size(unsigned entries, unsigned flags) #if defined(__hppa__) static struct io_uring_buf_ring *br_setup(struct io_uring *ring, unsigned int nentries, int bgid, - unsigned int flags, int *ret) + unsigned int flags, int *err) { struct io_uring_buf_ring *br; struct io_uring_buf_reg reg; @@ -609,10 +609,10 @@ static struct io_uring_buf_ring *br_setup(struct io_uring *ring, reg.bgid = bgid; reg.flags = IOU_PBUF_RING_MMAP; - *ret = 0; + *err = 0; lret = io_uring_register_buf_ring(ring, ®, flags); if (lret) { - *ret = lret; + *err = lret; return NULL; } @@ -621,7 +621,7 @@ static struct io_uring_buf_ring *br_setup(struct io_uring *ring, br = __sys_mmap(NULL, ring_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, ring->ring_fd, off); if (IS_ERR(br)) { - *ret = PTR_ERR(br); + *err = PTR_ERR(br); return NULL; } @@ -630,7 +630,7 @@ static struct io_uring_buf_ring *br_setup(struct io_uring *ring, #else static struct io_uring_buf_ring *br_setup(struct io_uring *ring, unsigned int nentries, int bgid, - unsigned int flags, int *ret) + unsigned int flags, int *err) { struct io_uring_buf_ring *br; struct io_uring_buf_reg reg; @@ -642,7 +642,7 @@ static struct io_uring_buf_ring *br_setup(struct io_uring *ring, br = __sys_mmap(NULL, ring_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); if (IS_ERR(br)) { - *ret = PTR_ERR(br); + *err = PTR_ERR(br); return NULL; } @@ -650,11 +650,11 @@ static struct io_uring_buf_ring *br_setup(struct io_uring *ring, reg.ring_entries = nentries; reg.bgid = bgid; - *ret = 0; + *err = 0; lret = io_uring_register_buf_ring(ring, ®, flags); if (lret) { __sys_munmap(br, ring_size); - *ret = lret; + *err = lret; br = NULL; } @@ -665,11 +665,11 @@ static struct io_uring_buf_ring *br_setup(struct io_uring *ring, struct io_uring_buf_ring *io_uring_setup_buf_ring(struct io_uring *ring, unsigned int nentries, int bgid, unsigned int flags, - int *ret) + int *err) { struct io_uring_buf_ring *br; - br = br_setup(ring, nentries, bgid, flags, ret); + br = br_setup(ring, nentries, bgid, flags, err); if (br) io_uring_buf_ring_init(br); diff --git a/contrib/libs/liburing/test/232c93d07b74.t/ya.make b/contrib/libs/liburing/test/232c93d07b74.t/ya.make index b1d0260eef..c8a2631965 100644 --- a/contrib/libs/liburing/test/232c93d07b74.t/ya.make +++ b/contrib/libs/liburing/test/232c93d07b74.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/35fa71a030ca.c b/contrib/libs/liburing/test/35fa71a030ca.c index b21f95a54e..a6b964bada 100644 --- a/contrib/libs/liburing/test/35fa71a030ca.c +++ b/contrib/libs/liburing/test/35fa71a030ca.c @@ -29,6 +29,7 @@ #include "helpers.h" #include "../src/syscall.h" +#ifndef CONFIG_USE_SANITIZER #if !defined(SYS_futex) && defined(SYS_futex_time64) # define SYS_futex SYS_futex_time64 #endif @@ -328,3 +329,9 @@ int main(int argc, char *argv[]) loop(); return T_EXIT_PASS; } +#else +int main(int argc, char *argv[]) +{ + return T_EXIT_SKIP; +} +#endif diff --git a/contrib/libs/liburing/test/35fa71a030ca.t/ya.make b/contrib/libs/liburing/test/35fa71a030ca.t/ya.make index 38988d083d..158d478ea4 100644 --- a/contrib/libs/liburing/test/35fa71a030ca.t/ya.make +++ b/contrib/libs/liburing/test/35fa71a030ca.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/500f9fbadef8.c b/contrib/libs/liburing/test/500f9fbadef8.c index 5306d09431..25e7533ca7 100644 --- a/contrib/libs/liburing/test/500f9fbadef8.c +++ b/contrib/libs/liburing/test/500f9fbadef8.c @@ -79,10 +79,12 @@ int main(int argc, char *argv[]) close(fd); unlink(buf); + free(iov.iov_base); return T_EXIT_PASS; err: close(fd); unlink(buf); + free(iov.iov_base); return T_EXIT_FAIL; skipped: fprintf(stderr, "Polling not supported in current dir, test skipped\n"); diff --git a/contrib/libs/liburing/test/500f9fbadef8.t/ya.make b/contrib/libs/liburing/test/500f9fbadef8.t/ya.make index f4f3bdc390..fd66f1bf0b 100644 --- a/contrib/libs/liburing/test/500f9fbadef8.t/ya.make +++ b/contrib/libs/liburing/test/500f9fbadef8.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/7ad0e4b2f83c.c b/contrib/libs/liburing/test/7ad0e4b2f83c.c index 067def169a..f063708bc5 100644 --- a/contrib/libs/liburing/test/7ad0e4b2f83c.c +++ b/contrib/libs/liburing/test/7ad0e4b2f83c.c @@ -6,31 +6,6 @@ #include "liburing.h" #include "helpers.h" -static unsigned long long mtime_since(const struct timeval *s, - const struct timeval *e) -{ - long long sec, usec; - - sec = e->tv_sec - s->tv_sec; - usec = (e->tv_usec - s->tv_usec); - if (sec > 0 && usec < 0) { - sec--; - usec += 1000000; - } - - sec *= 1000; - usec /= 1000; - return sec + usec; -} - -static unsigned long long mtime_since_now(struct timeval *tv) -{ - struct timeval end; - - gettimeofday(&end, NULL); - return mtime_since(tv, &end); -} - int main(int argc, char *argv[]) { struct __kernel_timespec ts1, ts2; diff --git a/contrib/libs/liburing/test/7ad0e4b2f83c.t/ya.make b/contrib/libs/liburing/test/7ad0e4b2f83c.t/ya.make index 681c052f9f..fc918253a0 100644 --- a/contrib/libs/liburing/test/7ad0e4b2f83c.t/ya.make +++ b/contrib/libs/liburing/test/7ad0e4b2f83c.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/8a9973408177.t/ya.make b/contrib/libs/liburing/test/8a9973408177.t/ya.make index fdab64253a..8ebec8a2a8 100644 --- a/contrib/libs/liburing/test/8a9973408177.t/ya.make +++ b/contrib/libs/liburing/test/8a9973408177.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/917257daa0fe.c b/contrib/libs/liburing/test/917257daa0fe.c index 0fc8e57178..8e5ec96398 100644 --- a/contrib/libs/liburing/test/917257daa0fe.c +++ b/contrib/libs/liburing/test/917257daa0fe.c @@ -15,6 +15,7 @@ #include "helpers.h" #include "../src/syscall.h" +#ifndef CONFIG_USE_SANITIZER int main(int argc, char *argv[]) { if (argc > 1) @@ -53,3 +54,9 @@ int main(int argc, char *argv[]) __sys_io_uring_setup(0x7a6, (struct io_uring_params *) 0x20000000UL); return T_EXIT_PASS; } +#else +int main(int argc, char *argv[]) +{ + return T_EXIT_SKIP; +} +#endif diff --git a/contrib/libs/liburing/test/917257daa0fe.t/ya.make b/contrib/libs/liburing/test/917257daa0fe.t/ya.make index b7cf6b187d..cc31d0b3fe 100644 --- a/contrib/libs/liburing/test/917257daa0fe.t/ya.make +++ b/contrib/libs/liburing/test/917257daa0fe.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/a0908ae19763.c b/contrib/libs/liburing/test/a0908ae19763.c index 0b0f6a0eac..0ffd422bb0 100644 --- a/contrib/libs/liburing/test/a0908ae19763.c +++ b/contrib/libs/liburing/test/a0908ae19763.c @@ -15,6 +15,7 @@ #include "helpers.h" #include "../src/syscall.h" +#ifndef CONFIG_USE_SANITIZER static uint64_t r[1] = {0xffffffffffffffff}; int main(int argc, char *argv[]) @@ -58,3 +59,9 @@ int main(int argc, char *argv[]) __sys_io_uring_register(r[0], 2, (const void *) 0x20000280, 1); return T_EXIT_PASS; } +#else +int main(int argc, char *argv[]) +{ + return T_EXIT_SKIP; +} +#endif diff --git a/contrib/libs/liburing/test/a0908ae19763.t/ya.make b/contrib/libs/liburing/test/a0908ae19763.t/ya.make index c6aca489f1..1d5a693e2b 100644 --- a/contrib/libs/liburing/test/a0908ae19763.t/ya.make +++ b/contrib/libs/liburing/test/a0908ae19763.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/a4c0b3decb33.c b/contrib/libs/liburing/test/a4c0b3decb33.c index 0e77ba8ee7..0207f4946b 100644 --- a/contrib/libs/liburing/test/a4c0b3decb33.c +++ b/contrib/libs/liburing/test/a4c0b3decb33.c @@ -25,6 +25,7 @@ #include "helpers.h" #include "../src/syscall.h" +#ifndef CONFIG_USE_SANITIZER static void sleep_ms(uint64_t ms) { usleep(ms * 1000); @@ -180,3 +181,9 @@ int main(int argc, char *argv[]) loop(); return T_EXIT_PASS; } +#else +int main(int argc, char *argv[]) +{ + return T_EXIT_SKIP; +} +#endif diff --git a/contrib/libs/liburing/test/a4c0b3decb33.t/ya.make b/contrib/libs/liburing/test/a4c0b3decb33.t/ya.make index f73ec56c45..176165931b 100644 --- a/contrib/libs/liburing/test/a4c0b3decb33.t/ya.make +++ b/contrib/libs/liburing/test/a4c0b3decb33.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/accept-link.t/ya.make b/contrib/libs/liburing/test/accept-link.t/ya.make index 9a7e139107..e110bf5975 100644 --- a/contrib/libs/liburing/test/accept-link.t/ya.make +++ b/contrib/libs/liburing/test/accept-link.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/accept-non-empty.c b/contrib/libs/liburing/test/accept-non-empty.c index f85f30ca87..ff92c8a79c 100644 --- a/contrib/libs/liburing/test/accept-non-empty.c +++ b/contrib/libs/liburing/test/accept-non-empty.c @@ -60,6 +60,46 @@ static int start_accept_listen(int port_off, int extra_flags) return fd; } +static void *connect_fn(void *data) +{ + struct sockaddr_in addr = { }; + struct data *d = data; + int i; + + pthread_barrier_wait(&d->barrier); + + addr.sin_family = AF_INET; + addr.sin_port = htons(0x1235); + addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + + for (i = 0; i < d->connects; i++) { + int s; + + s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (s < 0) { + perror("socket"); + break; + } + if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + perror("connect"); + break; + } + } + + if (i) + pthread_barrier_wait(&d->conn_barrier); + + return NULL; +} + +static void setup_thread(struct data *d, int nconns) +{ + d->connects = nconns; + pthread_barrier_init(&d->barrier, NULL, 2); + pthread_barrier_init(&d->conn_barrier, NULL, 2); + pthread_create(&d->thread, NULL, connect_fn, d); +} + static int test_maccept(struct data *d, int flags, int fixed) { struct io_uring_params p = { }; @@ -82,6 +122,8 @@ static int test_maccept(struct data *d, int flags, int fixed) return 0; } + setup_thread(d, MAX_ACCEPTS); + fds = malloc(MAX_ACCEPTS * sizeof(int)); memset(fds, -1, MAX_ACCEPTS * sizeof(int)); @@ -152,53 +194,12 @@ static int test_maccept(struct data *d, int flags, int fixed) return err; } -static void *connect_fn(void *data) -{ - struct sockaddr_in addr = { }; - struct data *d = data; - int i; - - pthread_barrier_wait(&d->barrier); - - addr.sin_family = AF_INET; - addr.sin_port = htons(0x1235); - addr.sin_addr.s_addr = inet_addr("127.0.0.1"); - - for (i = 0; i < d->connects; i++) { - int s; - - s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (s < 0) { - perror("socket"); - break; - } - if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - perror("connect"); - break; - } - } - - if (d->connects > 1) - pthread_barrier_wait(&d->conn_barrier); - - return NULL; -} - -static void setup_thread(struct data *d, int nconns) -{ - d->connects = nconns; - pthread_barrier_init(&d->barrier, NULL, 2); - pthread_barrier_init(&d->conn_barrier, NULL, 2); - pthread_create(&d->thread, NULL, connect_fn, d); -} - static int test(int flags, int fixed) { struct data d; void *tret; int ret; - setup_thread(&d, 1); ret = test_maccept(&d, flags, fixed); if (ret) { fprintf(stderr, "test conns=1 failed\n"); @@ -209,7 +210,6 @@ static int test(int flags, int fixed) pthread_join(d.thread, &tret); - setup_thread(&d, MAX_ACCEPTS); ret = test_maccept(&d, flags, fixed); if (ret) { fprintf(stderr, "test conns=MAX failed\n"); diff --git a/contrib/libs/liburing/test/accept-non-empty.t/ya.make b/contrib/libs/liburing/test/accept-non-empty.t/ya.make index c6df3eb032..27ec536d0d 100644 --- a/contrib/libs/liburing/test/accept-non-empty.t/ya.make +++ b/contrib/libs/liburing/test/accept-non-empty.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/accept-reuse.t/ya.make b/contrib/libs/liburing/test/accept-reuse.t/ya.make index 6624289a0e..d2ef8e2bd6 100644 --- a/contrib/libs/liburing/test/accept-reuse.t/ya.make +++ b/contrib/libs/liburing/test/accept-reuse.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/accept-test.t/ya.make b/contrib/libs/liburing/test/accept-test.t/ya.make index c82e260ee9..26bf93d787 100644 --- a/contrib/libs/liburing/test/accept-test.t/ya.make +++ b/contrib/libs/liburing/test/accept-test.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/accept.c b/contrib/libs/liburing/test/accept.c index 49b1ca1345..279e739290 100644 --- a/contrib/libs/liburing/test/accept.c +++ b/contrib/libs/liburing/test/accept.c @@ -61,7 +61,7 @@ static void close_sock_fds(int s_fd[], int c_fd[], int nr, bool fixed) close_fds(c_fd, nr); } -static void queue_send(struct io_uring *ring, int fd) +static void *queue_send(struct io_uring *ring, int fd) { struct io_uring_sqe *sqe; struct data *d; @@ -73,9 +73,11 @@ static void queue_send(struct io_uring *ring, int fd) sqe = io_uring_get_sqe(ring); io_uring_prep_writev(sqe, fd, &d->iov, 1, 0); sqe->user_data = 1; + + return d; } -static void queue_recv(struct io_uring *ring, int fd, bool fixed) +static void *queue_recv(struct io_uring *ring, int fd, bool fixed) { struct io_uring_sqe *sqe; struct data *d; @@ -89,6 +91,8 @@ static void queue_recv(struct io_uring *ring, int fd, bool fixed) sqe->user_data = 2; if (fixed) sqe->flags |= IOSQE_FIXED_FILE; + + return d; } static void queue_accept_multishot(struct io_uring *ring, int fd, @@ -275,6 +279,8 @@ static int test_loop(struct io_uring *ring, int nr_fds = multishot ? MAX_FDS : 1; int multishot_idx = multishot ? INITIAL_USER_DATA : 0; int err_ret = T_EXIT_FAIL; + void* send_d = 0; + void* recv_d = 0; if (args.overflow) cause_overflow(ring); @@ -341,8 +347,8 @@ static int test_loop(struct io_uring *ring, goto out; } - queue_send(ring, c_fd[0]); - queue_recv(ring, s_fd[0], fixed); + send_d = queue_send(ring, c_fd[0]); + recv_d = queue_recv(ring, s_fd[0], fixed); ret = io_uring_submit_and_wait(ring, 2); assert(ret != -1); @@ -366,9 +372,13 @@ static int test_loop(struct io_uring *ring, } out: + free(send_d); + free(recv_d); close_sock_fds(s_fd, c_fd, nr_fds, fixed); return T_EXIT_PASS; err: + free(send_d); + free(recv_d); close_sock_fds(s_fd, c_fd, nr_fds, fixed); return err_ret; } diff --git a/contrib/libs/liburing/test/accept.t/ya.make b/contrib/libs/liburing/test/accept.t/ya.make index 95bb00c414..294a2c4213 100644 --- a/contrib/libs/liburing/test/accept.t/ya.make +++ b/contrib/libs/liburing/test/accept.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/across-fork.t/ya.make b/contrib/libs/liburing/test/across-fork.t/ya.make index 1b12588baf..c233f57ffb 100644 --- a/contrib/libs/liburing/test/across-fork.t/ya.make +++ b/contrib/libs/liburing/test/across-fork.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/b19062a56726.c b/contrib/libs/liburing/test/b19062a56726.c index 9356769818..b0683c5837 100644 --- a/contrib/libs/liburing/test/b19062a56726.c +++ b/contrib/libs/liburing/test/b19062a56726.c @@ -15,6 +15,7 @@ #include "helpers.h" #include "../src/syscall.h" +#ifndef CONFIG_USE_SANITIZER int main(int argc, char *argv[]) { if (argc > 1) @@ -53,3 +54,9 @@ int main(int argc, char *argv[]) __sys_io_uring_setup(0xc9f, (struct io_uring_params *) 0x20000200); return T_EXIT_PASS; } +#else +int main(int argc, char *argv[]) +{ + return T_EXIT_SKIP; +} +#endif diff --git a/contrib/libs/liburing/test/b19062a56726.t/ya.make b/contrib/libs/liburing/test/b19062a56726.t/ya.make index 5c7a8603ad..5b5cad9153 100644 --- a/contrib/libs/liburing/test/b19062a56726.t/ya.make +++ b/contrib/libs/liburing/test/b19062a56726.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/b5837bd5311d.t/ya.make b/contrib/libs/liburing/test/b5837bd5311d.t/ya.make index 74e7ca4d07..9e44b2fbcd 100644 --- a/contrib/libs/liburing/test/b5837bd5311d.t/ya.make +++ b/contrib/libs/liburing/test/b5837bd5311d.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/bind-listen.c b/contrib/libs/liburing/test/bind-listen.c index 25f41b48b5..5ed4a2d1da 100644 --- a/contrib/libs/liburing/test/bind-listen.c +++ b/contrib/libs/liburing/test/bind-listen.c @@ -55,7 +55,7 @@ static int connect_client(struct io_uring *ring, unsigned short peer_port) sqe = io_uring_get_sqe(ring); io_uring_prep_send(sqe, CLI_INDEX, magic, strlen(magic), 0); - sqe->flags |= IOSQE_FIXED_FILE | IOSQE_IO_LINK; + sqe->flags |= IOSQE_FIXED_FILE; submitted = ret = io_uring_submit(ring); if (ret < 0) @@ -181,7 +181,7 @@ static int test_good_server(unsigned int ring_flags) io_uring_cqe_seen(&ring, cqe); sqe = io_uring_get_sqe(&ring); - io_uring_prep_recv(sqe, CONN_INDEX, buf, BUFSIZ, 0); + io_uring_prep_recv(sqe, CONN_INDEX, buf, sizeof(buf), 0); sqe->flags |= IOSQE_FIXED_FILE; io_uring_submit(&ring); diff --git a/contrib/libs/liburing/test/bind-listen.t/ya.make b/contrib/libs/liburing/test/bind-listen.t/ya.make index 06ac130345..25e4ebe79e 100644 --- a/contrib/libs/liburing/test/bind-listen.t/ya.make +++ b/contrib/libs/liburing/test/bind-listen.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/buf-ring-nommap.c b/contrib/libs/liburing/test/buf-ring-nommap.c index ac4f199c8b..ee9ebd1601 100644 --- a/contrib/libs/liburing/test/buf-ring-nommap.c +++ b/contrib/libs/liburing/test/buf-ring-nommap.c @@ -47,8 +47,10 @@ int main(int argc, char *argv[]) p.flags = IORING_SETUP_NO_MMAP; ret = io_uring_queue_init_mem(1, &ring, &p, ring_mem, 16384); if (ret < 0) { - if (ret == -EINVAL || ret == -ENOMEM) + if (ret == -EINVAL || ret == -ENOMEM) { + free(ring_mem); return T_EXIT_SKIP; + } fprintf(stderr, "queue init failed %d\n", ret); return T_EXIT_FAIL; } @@ -63,8 +65,10 @@ int main(int argc, char *argv[]) ret = io_uring_register_buf_ring(&ring, ®, 0); if (ret) { - if (ret == -EINVAL) + if (ret == -EINVAL) { + free(ring_mem); return T_EXIT_SKIP; + } fprintf(stderr, "reg buf ring: %d\n", ret); return T_EXIT_FAIL; } @@ -74,8 +78,10 @@ int main(int argc, char *argv[]) br = mmap(NULL, ring_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, ring.ring_fd, off); if (br == MAP_FAILED) { - if (errno == ENOMEM) + if (errno == ENOMEM) { + free(ring_mem); return T_EXIT_SKIP; + } perror("mmap"); return T_EXIT_FAIL; } @@ -120,5 +126,6 @@ int main(int argc, char *argv[]) io_uring_cqe_seen(&ring, cqe); io_uring_queue_exit(&ring); + free(ring_mem); return T_EXIT_PASS; } diff --git a/contrib/libs/liburing/test/buf-ring-nommap.t/ya.make b/contrib/libs/liburing/test/buf-ring-nommap.t/ya.make index 1acf0938dc..645e84c91d 100644 --- a/contrib/libs/liburing/test/buf-ring-nommap.t/ya.make +++ b/contrib/libs/liburing/test/buf-ring-nommap.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/buf-ring-put.t/ya.make b/contrib/libs/liburing/test/buf-ring-put.t/ya.make index f8f026e2a2..5dba623a0a 100644 --- a/contrib/libs/liburing/test/buf-ring-put.t/ya.make +++ b/contrib/libs/liburing/test/buf-ring-put.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/buf-ring.c b/contrib/libs/liburing/test/buf-ring.c index 526dddaddc..44da27f619 100644 --- a/contrib/libs/liburing/test/buf-ring.c +++ b/contrib/libs/liburing/test/buf-ring.c @@ -58,6 +58,7 @@ static int test_mixed_reg2(int bgid) io_uring_free_buf_ring(&ring, br, 32, bgid); io_uring_queue_exit(&ring); + free(bufs); return 0; } @@ -100,6 +101,7 @@ static int test_mixed_reg(int bgid) } io_uring_queue_exit(&ring); + free(bufs); return 0; } diff --git a/contrib/libs/liburing/test/buf-ring.t/ya.make b/contrib/libs/liburing/test/buf-ring.t/ya.make index 63b3bac811..131f914b8b 100644 --- a/contrib/libs/liburing/test/buf-ring.t/ya.make +++ b/contrib/libs/liburing/test/buf-ring.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/ce593a6c480a.t/ya.make b/contrib/libs/liburing/test/ce593a6c480a.t/ya.make index 2a1a37f183..ecb3520c84 100644 --- a/contrib/libs/liburing/test/ce593a6c480a.t/ya.make +++ b/contrib/libs/liburing/test/ce593a6c480a.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/close-opath.t/ya.make b/contrib/libs/liburing/test/close-opath.t/ya.make index 0f156c6373..71f3acf824 100644 --- a/contrib/libs/liburing/test/close-opath.t/ya.make +++ b/contrib/libs/liburing/test/close-opath.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/cmd-discard.c b/contrib/libs/liburing/test/cmd-discard.c new file mode 100644 index 0000000000..864791754c --- /dev/null +++ b/contrib/libs/liburing/test/cmd-discard.c @@ -0,0 +1,426 @@ +#include "../config-host.h" +/* SPDX-License-Identifier: MIT */ + +#include <stdio.h> +#include <assert.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <linux/fs.h> + +#include "liburing.h" +#include "helpers.h" + +#define MAX_TEST_LBAS 1024 + +static const char *filename; +struct opcode { + int op; + bool test; + bool not_supported; +}; + +#define TEST_BLOCK_URING_CMD_MAX 3 + +static struct opcode opcodes[TEST_BLOCK_URING_CMD_MAX] = { + { .op = BLOCK_URING_CMD_DISCARD, .test = true, }, + { .test = false, }, + { .test = false, }, +}; + +static int lba_size; +static uint64_t bdev_size; +static uint64_t bdev_size_lbas; +static char *buffer; + +static void prep_blk_cmd(struct io_uring_sqe *sqe, int fd, + uint64_t from, uint64_t len, + int cmd_op) +{ + assert(cmd_op == BLOCK_URING_CMD_DISCARD); + + io_uring_prep_cmd_discard(sqe, fd, from, len); +} + +static int queue_cmd_range(struct io_uring *ring, int bdev_fd, + uint64_t from, uint64_t len, int cmd_op) +{ + struct io_uring_sqe *sqe; + struct io_uring_cqe *cqe; + int err; + + sqe = io_uring_get_sqe(ring); + assert(sqe != NULL); + prep_blk_cmd(sqe, bdev_fd, from, len, cmd_op); + + err = io_uring_submit_and_wait(ring, 1); + if (err != 1) { + fprintf(stderr, "io_uring_submit_and_wait failed %d\n", err); + exit(1); + } + + err = io_uring_wait_cqe(ring, &cqe); + if (err) { + fprintf(stderr, "io_uring_wait_cqe failed %d (op %i)\n", + err, cmd_op); + exit(1); + } + + err = cqe->res; + io_uring_cqe_seen(ring, cqe); + return err; +} + +static int queue_cmd_lba(struct io_uring *ring, int bdev_fd, + uint64_t from, uint64_t nr_lba, int cmd_op) +{ + return queue_cmd_range(ring, bdev_fd, from * lba_size, + nr_lba * lba_size, cmd_op); +} + +static int queue_discard_lba(struct io_uring *ring, int bdev_fd, + uint64_t from, uint64_t nr_lba) +{ + return queue_cmd_lba(ring, bdev_fd, from, nr_lba, + BLOCK_URING_CMD_DISCARD); +} + +static int test_parallel(struct io_uring *ring, int fd, int cmd_op) +{ + struct io_uring_sqe *sqe; + struct io_uring_cqe *cqe; + int inflight = 0; + int max_inflight = 16; + int left = 1000; + int ret; + + while (left || inflight) { + int queued = 0; + unsigned head, nr_cqes = 0; + int lba_len = 8; + + while (inflight < max_inflight && left) { + int off = rand() % (MAX_TEST_LBAS - lba_len); + sqe = io_uring_get_sqe(ring); + assert(sqe != NULL); + + prep_blk_cmd(sqe, fd, off * lba_size, + lba_len * lba_size, cmd_op); + if (rand() & 1) + sqe->flags |= IOSQE_ASYNC; + + queued++; + left--; + inflight++; + } + if (queued) { + ret = io_uring_submit(ring); + if (ret != queued) { + fprintf(stderr, "io_uring_submit failed %d\n", ret); + return T_EXIT_FAIL; + } + } + + ret = io_uring_wait_cqe(ring, &cqe); + if (ret) { + fprintf(stderr, "io_uring_wait_cqe failed %d\n", ret); + exit(1); + } + + io_uring_for_each_cqe(ring, head, cqe) { + nr_cqes++; + inflight--; + if (cqe->res != 0) { + fprintf(stderr, "cmd %i failed %i\n", cmd_op, + cqe->res); + return T_EXIT_FAIL; + } + } + io_uring_cq_advance(ring, nr_cqes); + } + + return 0; +} + +static int cmd_issue_verify(struct io_uring *ring, int fd, int lba, int len, + int cmd_op) +{ + int verify = (cmd_op != BLOCK_URING_CMD_DISCARD); + int ret, i; + ssize_t res; + + if (verify) { + for (i = 0; i < len; i++) { + size_t off = (i + lba) * lba_size; + + res = pwrite(fd, buffer, lba_size, off); + if (res == -1) { + fprintf(stderr, "pwrite failed\n"); + return T_EXIT_FAIL; + } + } + } + + ret = queue_cmd_lba(ring, fd, lba, len, cmd_op); + if (ret) { + if (ret == -EINVAL || ret == -EOPNOTSUPP) + return T_EXIT_SKIP; + + fprintf(stderr, "cmd_issue_verify %i fail lba %i len %i ret %i\n", + cmd_op, lba, len, ret); + return T_EXIT_FAIL; + } + + if (verify) { + for (i = 0; i < len; i++) { + size_t off = (i + lba) * lba_size; + + res = pread(fd, buffer, lba_size, off); + if (res == -1) { + fprintf(stderr, "pread failed\n"); + return T_EXIT_FAIL; + } + if (!memchr(buffer, 0, lba_size)) { + fprintf(stderr, "mem cmp failed, lba %i\n", lba + i); + return T_EXIT_FAIL; + } + } + } + return 0; +} + +static int basic_cmd_test(struct io_uring *ring, int op) +{ + int cmd_op = opcodes[op].op; + int ret, fd; + + if (!opcodes[op].test) + return T_EXIT_SKIP; + + fd = open(filename, O_DIRECT | O_RDWR | O_EXCL); + if (fd < 0) { + fprintf(stderr, "open failed %i\n", errno); + return T_EXIT_FAIL; + } + + ret = cmd_issue_verify(ring, fd, 0, 1, cmd_op); + if (ret == T_EXIT_SKIP) { + printf("cmd %i not supported, skip\n", cmd_op); + opcodes[op].not_supported = 1; + close(fd); + return T_EXIT_SKIP; + } else if (ret) { + fprintf(stderr, "cmd %i fail 0 1\n", cmd_op); + return T_EXIT_FAIL; + } + + ret = cmd_issue_verify(ring, fd, 7, 15, cmd_op); + if (ret) { + fprintf(stderr, "cmd %i fail 7 15 %i\n", cmd_op, ret); + return T_EXIT_FAIL; + } + + ret = cmd_issue_verify(ring, fd, 1, MAX_TEST_LBAS - 1, cmd_op); + if (ret) { + fprintf(stderr, "large cmd %i failed %i\n", cmd_op, ret); + return T_EXIT_FAIL; + } + + ret = test_parallel(ring, fd, cmd_op); + if (ret) { + fprintf(stderr, "test_parallel() %i failed %i\n", cmd_op, ret); + return T_EXIT_FAIL; + } + + close(fd); + return 0; +} + +static int test_fail_edge_cases(struct io_uring *ring, int op) +{ + int cmd_op = opcodes[op].op; + int ret, fd; + + if (!opcodes[op].test) + return T_EXIT_SKIP; + + fd = open(filename, O_DIRECT | O_RDWR | O_EXCL); + if (fd < 0) { + fprintf(stderr, "open failed %i\n", errno); + return T_EXIT_FAIL; + } + + ret = queue_cmd_lba(ring, fd, bdev_size_lbas, 1, cmd_op); + if (ret >= 0) { + fprintf(stderr, "cmd %i beyond capacity %i\n", + cmd_op, ret); + return 1; + } + + ret = queue_cmd_lba(ring, fd, bdev_size_lbas - 1, 2, cmd_op); + if (ret >= 0) { + fprintf(stderr, "cmd %i beyond capacity with overlap %i\n", + cmd_op, ret); + return 1; + } + + ret = queue_cmd_range(ring, fd, (uint64_t)-lba_size, lba_size + 2, + cmd_op); + if (ret >= 0) { + fprintf(stderr, "cmd %i range overflow %i\n", + cmd_op, ret); + return 1; + } + + ret = queue_cmd_range(ring, fd, lba_size / 2, lba_size, cmd_op); + if (ret >= 0) { + fprintf(stderr, "cmd %i unaligned offset %i\n", + cmd_op, ret); + return 1; + } + + ret = queue_cmd_range(ring, fd, 0, lba_size / 2, cmd_op); + if (ret >= 0) { + fprintf(stderr, "cmd %i unaligned size %i\n", + cmd_op, ret); + return 1; + } + + close(fd); + return 0; +} + +static int test_rdonly(struct io_uring *ring, int op) +{ + int ret, fd; + int ro; + + if (!opcodes[op].test) + return T_EXIT_SKIP; + + fd = open(filename, O_DIRECT | O_RDONLY | O_EXCL); + if (fd < 0) { + fprintf(stderr, "open failed %i\n", errno); + return T_EXIT_FAIL; + } + + ret = queue_discard_lba(ring, fd, 0, 1); + if (ret >= 0) { + fprintf(stderr, "discarded with O_RDONLY %i\n", ret); + return 1; + } + close(fd); + + fd = open(filename, O_DIRECT | O_RDWR | O_EXCL); + if (fd < 0) { + fprintf(stderr, "open failed %i\n", errno); + return T_EXIT_FAIL; + } + + ro = 1; + ret = ioctl(fd, BLKROSET, &ro); + if (ret) { + fprintf(stderr, "BLKROSET 1 failed %i\n", errno); + return T_EXIT_FAIL; + } + + ret = queue_discard_lba(ring, fd, 0, 1); + if (ret >= 0) { + fprintf(stderr, "discarded with O_RDONLY %i\n", ret); + return 1; + } + + ro = 0; + ret = ioctl(fd, BLKROSET, &ro); + if (ret) { + fprintf(stderr, "BLKROSET 0 failed %i\n", errno); + return T_EXIT_FAIL; + } + close(fd); + return 0; +} + +int main(int argc, char *argv[]) +{ + struct io_uring ring; + int fd, ret, i, fret; + int cmd_op; + + if (argc != 2) + return T_EXIT_SKIP; + filename = argv[1]; + + fd = open(filename, O_DIRECT | O_RDONLY | O_EXCL); + if (fd < 0) { + fprintf(stderr, "open failed %i\n", errno); + return T_EXIT_FAIL; + } + + ret = ioctl(fd, BLKGETSIZE64, &bdev_size); + if (ret < 0) { + fprintf(stderr, "BLKGETSIZE64 failed %i\n", errno); + return T_EXIT_FAIL; + } + ret = ioctl(fd, BLKSSZGET, &lba_size); + if (ret < 0) { + fprintf(stderr, "BLKSSZGET failed %i\n", errno); + return T_EXIT_FAIL; + } + assert(bdev_size % lba_size == 0); + bdev_size_lbas = bdev_size / lba_size; + close(fd); + + buffer = aligned_alloc(lba_size, lba_size); + if (!buffer) { + fprintf(stderr, "aligned_alloc failed\n"); + return T_EXIT_FAIL; + } + for (i = 0; i < lba_size; i++) + buffer[i] = i ^ 0xA7; + + if (bdev_size_lbas < MAX_TEST_LBAS) { + fprintf(stderr, "the device is too small, skip\n"); + return T_EXIT_SKIP; + } + + ret = io_uring_queue_init(16, &ring, 0); + if (ret) { + fprintf(stderr, "queue init failed: %d\n", ret); + return T_EXIT_FAIL; + } + + fret = T_EXIT_SKIP; + for (cmd_op = 0; cmd_op < TEST_BLOCK_URING_CMD_MAX; cmd_op++) { + if (!opcodes[cmd_op].test) + continue; + ret = basic_cmd_test(&ring, cmd_op); + if (ret) { + if (ret == T_EXIT_SKIP) + continue; + + fprintf(stderr, "basic_cmd_test() failed, cmd %i\n", + cmd_op); + return T_EXIT_FAIL; + } + + ret = test_rdonly(&ring, cmd_op); + if (ret) { + fprintf(stderr, "test_rdonly() failed, cmd %i\n", + cmd_op); + return T_EXIT_FAIL; + } + + ret = test_fail_edge_cases(&ring, cmd_op); + if (ret) { + fprintf(stderr, "test_fail_edge_cases() failed, cmd %i\n", + cmd_op); + return T_EXIT_FAIL; + } + fret = T_EXIT_PASS; + } + + io_uring_queue_exit(&ring); + free(buffer); + return fret; +} diff --git a/contrib/libs/liburing/test/cmd-discard.t/ya.make b/contrib/libs/liburing/test/cmd-discard.t/ya.make new file mode 100644 index 0000000000..4c39cb59bd --- /dev/null +++ b/contrib/libs/liburing/test/cmd-discard.t/ya.make @@ -0,0 +1,35 @@ +# Generated by devtools/yamaker. + +PROGRAM() + +WITHOUT_LICENSE_TEXTS() + +VERSION(2.8) + +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( + cmd-discard.c + helpers.c +) + +END() diff --git a/contrib/libs/liburing/test/connect-rep.t/ya.make b/contrib/libs/liburing/test/connect-rep.t/ya.make index 4a22b223ac..bed485eb58 100644 --- a/contrib/libs/liburing/test/connect-rep.t/ya.make +++ b/contrib/libs/liburing/test/connect-rep.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/connect.t/ya.make b/contrib/libs/liburing/test/connect.t/ya.make index 15d4aeedae..761dfdedbc 100644 --- a/contrib/libs/liburing/test/connect.t/ya.make +++ b/contrib/libs/liburing/test/connect.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/coredump.c b/contrib/libs/liburing/test/coredump.c index d390b78be9..fc29e61e1c 100644 --- a/contrib/libs/liburing/test/coredump.c +++ b/contrib/libs/liburing/test/coredump.c @@ -17,6 +17,7 @@ #include "liburing.h" #include "helpers.h" +#ifndef CONFIG_USE_SANITIZER static void test(void) { struct io_uring_sqe *sqe; @@ -59,3 +60,9 @@ int main(int argc, char *argv[]) unlink("core"); return T_EXIT_PASS; } +#else +int main(int argc, char *argv[]) +{ + return T_EXIT_SKIP; +} +#endif diff --git a/contrib/libs/liburing/test/coredump.t/ya.make b/contrib/libs/liburing/test/coredump.t/ya.make index cad32c9a7b..f4df921c4a 100644 --- a/contrib/libs/liburing/test/coredump.t/ya.make +++ b/contrib/libs/liburing/test/coredump.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/cq-full.t/ya.make b/contrib/libs/liburing/test/cq-full.t/ya.make index 3ac0b9d38b..b968925073 100644 --- a/contrib/libs/liburing/test/cq-full.t/ya.make +++ b/contrib/libs/liburing/test/cq-full.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/cq-overflow.c b/contrib/libs/liburing/test/cq-overflow.c index 569c733752..b43bf69131 100644 --- a/contrib/libs/liburing/test/cq-overflow.c +++ b/contrib/libs/liburing/test/cq-overflow.c @@ -89,8 +89,10 @@ static int test_io(const char *file, unsigned long usecs, unsigned *drops, goto err; } offset = BS * (rand() % BUFFERS); - if (fault && i == ENTRIES + 4) + if (fault && i == ENTRIES + 4) { + free(vecs[i].iov_base); vecs[i].iov_base = NULL; + } io_uring_prep_readv(sqe, fd, &vecs[i], 1, offset); ret = io_uring_submit(&ring); @@ -524,8 +526,18 @@ int main(int argc, char *argv[]) } unlink(fname); + if(vecs != NULL) { + for (i = 0; i < BUFFERS; i++) + free(vecs[i].iov_base); + } + free(vecs); return T_EXIT_PASS; err: unlink(fname); + if(vecs != NULL) { + for (i = 0; i < BUFFERS; i++) + free(vecs[i].iov_base); + } + free(vecs); return T_EXIT_FAIL; } diff --git a/contrib/libs/liburing/test/cq-overflow.t/ya.make b/contrib/libs/liburing/test/cq-overflow.t/ya.make index 4d67475587..d1ef4cab6f 100644 --- a/contrib/libs/liburing/test/cq-overflow.t/ya.make +++ b/contrib/libs/liburing/test/cq-overflow.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/cq-peek-batch.t/ya.make b/contrib/libs/liburing/test/cq-peek-batch.t/ya.make index 608e643c84..ce3845ab9e 100644 --- a/contrib/libs/liburing/test/cq-peek-batch.t/ya.make +++ b/contrib/libs/liburing/test/cq-peek-batch.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/cq-ready.t/ya.make b/contrib/libs/liburing/test/cq-ready.t/ya.make index e3ec30727e..02f8f754b8 100644 --- a/contrib/libs/liburing/test/cq-ready.t/ya.make +++ b/contrib/libs/liburing/test/cq-ready.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/cq-size.t/ya.make b/contrib/libs/liburing/test/cq-size.t/ya.make index 5f6423089a..199bddbcd3 100644 --- a/contrib/libs/liburing/test/cq-size.t/ya.make +++ b/contrib/libs/liburing/test/cq-size.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/d4ae271dfaae.c b/contrib/libs/liburing/test/d4ae271dfaae.c index af47047be8..2a95b844db 100644 --- a/contrib/libs/liburing/test/d4ae271dfaae.c +++ b/contrib/libs/liburing/test/d4ae271dfaae.c @@ -20,10 +20,10 @@ int main(int argc, char *argv[]) { struct io_uring ring; - int i, fd, ret; + int i, fd, ret, __e; struct io_uring_sqe *sqe; struct io_uring_cqe *cqe; - struct iovec *iovecs; + struct iovec *iovecs = NULL; struct io_uring_params p; char *fname; void *buf; @@ -44,10 +44,13 @@ int main(int argc, char *argv[]) } fd = open(fname, O_RDONLY | O_DIRECT); + __e = errno; if (fname != argv[1]) unlink(fname); if (fd < 0) { - perror("open"); + if (__e == EINVAL || __e == EPERM || __e == EACCES) + return T_EXIT_SKIP; + fprintf(stderr, "open: %s\n", strerror(__e)); goto out; } @@ -93,5 +96,10 @@ int main(int argc, char *argv[]) close(fd); out: io_uring_queue_exit(&ring); + if (iovecs != NULL) { // + for (i = 0; i < 10; i++) + free(iovecs[i].iov_base); + free(iovecs); + } return ret; } diff --git a/contrib/libs/liburing/test/d4ae271dfaae.t/ya.make b/contrib/libs/liburing/test/d4ae271dfaae.t/ya.make index 30095cf271..28e901964b 100644 --- a/contrib/libs/liburing/test/d4ae271dfaae.t/ya.make +++ b/contrib/libs/liburing/test/d4ae271dfaae.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/d77a67ed5f27.t/ya.make b/contrib/libs/liburing/test/d77a67ed5f27.t/ya.make index d8eac8b261..6e1723d53f 100644 --- a/contrib/libs/liburing/test/d77a67ed5f27.t/ya.make +++ b/contrib/libs/liburing/test/d77a67ed5f27.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/defer-taskrun.c b/contrib/libs/liburing/test/defer-taskrun.c index c2543f4b26..82dfa2eef3 100644 --- a/contrib/libs/liburing/test/defer-taskrun.c +++ b/contrib/libs/liburing/test/defer-taskrun.c @@ -197,12 +197,12 @@ static int test_exec(const char *filename) if (filename) { fd = open(filename, O_RDONLY | O_DIRECT); - if (fd < 0 && errno == EINVAL) + if (fd < 0 && (errno == EINVAL || errno == EPERM || errno == EACCES)) return T_EXIT_SKIP; } else { t_create_file(EXEC_FILENAME, EXEC_FILESIZE); fd = open(EXEC_FILENAME, O_RDONLY | O_DIRECT); - if (fd < 0 && errno == EINVAL) { + if (fd < 0 && (errno == EINVAL || errno == EPERM || errno == EACCES)) { unlink(EXEC_FILENAME); return T_EXIT_SKIP; } diff --git a/contrib/libs/liburing/test/defer-taskrun.t/ya.make b/contrib/libs/liburing/test/defer-taskrun.t/ya.make index a4303270da..9ed40ffc04 100644 --- a/contrib/libs/liburing/test/defer-taskrun.t/ya.make +++ b/contrib/libs/liburing/test/defer-taskrun.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/defer-tw-timeout.c b/contrib/libs/liburing/test/defer-tw-timeout.c index b3489abe62..b521823d92 100644 --- a/contrib/libs/liburing/test/defer-tw-timeout.c +++ b/contrib/libs/liburing/test/defer-tw-timeout.c @@ -100,7 +100,7 @@ static int test_file(struct io_uring *ring, char *__fname) fd = open(fname, O_RDONLY | O_DIRECT); if (fd < 0) { - if (errno == EINVAL) { + if (errno == EINVAL || errno == EPERM || errno == EACCES) { if (!__fname) unlink(fname); return T_EXIT_SKIP; @@ -129,6 +129,7 @@ static int test_file(struct io_uring *ring, char *__fname) if (ret != 1) { fprintf(stderr, "unexpected wait ret %d\n", ret); close(fd); + free(buf); return T_EXIT_FAIL; } @@ -142,10 +143,12 @@ static int test_file(struct io_uring *ring, char *__fname) if (i != 1) { fprintf(stderr, "Got %d request, expected 1\n", i); close(fd); + free(buf); return T_EXIT_FAIL; } close(fd); + free(buf); 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 index e255116361..fd56a7f4b5 100644 --- a/contrib/libs/liburing/test/defer-tw-timeout.t/ya.make +++ b/contrib/libs/liburing/test/defer-tw-timeout.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/defer.c b/contrib/libs/liburing/test/defer.c index 1e52dcbf4e..dbad205d8f 100644 --- a/contrib/libs/liburing/test/defer.c +++ b/contrib/libs/liburing/test/defer.c @@ -97,7 +97,7 @@ static int test_canceled_userdata(struct io_uring *ring) if (init_context(&ctx, ring, nr, OP_NOP)) return 1; - for (i = 0; i < nr; i++) + for (i = 0; i < nr - 1; i++) ctx.sqes[i]->flags |= IOSQE_IO_LINK; ret = io_uring_submit(ring); @@ -131,7 +131,7 @@ static int test_thread_link_cancel(struct io_uring *ring) if (init_context(&ctx, ring, nr, OP_REMOVE_BUFFERS)) return 1; - for (i = 0; i < nr; i++) + for (i = 0; i < nr - 1; i++) ctx.sqes[i]->flags |= IOSQE_IO_LINK; ret = io_uring_submit(ring); diff --git a/contrib/libs/liburing/test/defer.t/ya.make b/contrib/libs/liburing/test/defer.t/ya.make index 1a043bd93a..dd18ffdd04 100644 --- a/contrib/libs/liburing/test/defer.t/ya.make +++ b/contrib/libs/liburing/test/defer.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/double-poll-crash.c b/contrib/libs/liburing/test/double-poll-crash.c index 67be0682c4..ef636c0072 100644 --- a/contrib/libs/liburing/test/double-poll-crash.c +++ b/contrib/libs/liburing/test/double-poll-crash.c @@ -115,7 +115,7 @@ static uint64_t r[4] = {0xffffffffffffffff, 0x0, 0x0, 0xffffffffffffffff}; int main(int argc, char *argv[]) { void *mmap_ret; -#if !defined(__i386) && !defined(__x86_64__) +#if (!defined(__i386) && !defined(__x86_64__)) || defined(CONFIG_USE_SANITIZER) return T_EXIT_SKIP; #endif diff --git a/contrib/libs/liburing/test/double-poll-crash.t/ya.make b/contrib/libs/liburing/test/double-poll-crash.t/ya.make index 69683beddc..d3480d8b17 100644 --- a/contrib/libs/liburing/test/double-poll-crash.t/ya.make +++ b/contrib/libs/liburing/test/double-poll-crash.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/drop-submit.t/ya.make b/contrib/libs/liburing/test/drop-submit.t/ya.make index 709c282398..829e75c6b7 100644 --- a/contrib/libs/liburing/test/drop-submit.t/ya.make +++ b/contrib/libs/liburing/test/drop-submit.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/eeed8b54e0df.c b/contrib/libs/liburing/test/eeed8b54e0df.c index 6b73a35db6..bdb91235e9 100644 --- a/contrib/libs/liburing/test/eeed8b54e0df.c +++ b/contrib/libs/liburing/test/eeed8b54e0df.c @@ -114,8 +114,10 @@ int main(int argc, char *argv[]) } close(fd); + free(iov.iov_base); return ret; err: close(fd); + free(iov.iov_base); return T_EXIT_FAIL; } diff --git a/contrib/libs/liburing/test/eeed8b54e0df.t/ya.make b/contrib/libs/liburing/test/eeed8b54e0df.t/ya.make index a602da28d2..957ea0974b 100644 --- a/contrib/libs/liburing/test/eeed8b54e0df.t/ya.make +++ b/contrib/libs/liburing/test/eeed8b54e0df.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/empty-eownerdead.t/ya.make b/contrib/libs/liburing/test/empty-eownerdead.t/ya.make index 412814da83..0a5793fc38 100644 --- a/contrib/libs/liburing/test/empty-eownerdead.t/ya.make +++ b/contrib/libs/liburing/test/empty-eownerdead.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/eploop.t/ya.make b/contrib/libs/liburing/test/eploop.t/ya.make index 6461e6be2c..68badedcda 100644 --- a/contrib/libs/liburing/test/eploop.t/ya.make +++ b/contrib/libs/liburing/test/eploop.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/eventfd-disable.t/ya.make b/contrib/libs/liburing/test/eventfd-disable.t/ya.make index 01b42db6c5..c1a4ac6945 100644 --- a/contrib/libs/liburing/test/eventfd-disable.t/ya.make +++ b/contrib/libs/liburing/test/eventfd-disable.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/eventfd-reg.t/ya.make b/contrib/libs/liburing/test/eventfd-reg.t/ya.make index 193586f9bc..8564f783bb 100644 --- a/contrib/libs/liburing/test/eventfd-reg.t/ya.make +++ b/contrib/libs/liburing/test/eventfd-reg.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/eventfd-ring.t/ya.make b/contrib/libs/liburing/test/eventfd-ring.t/ya.make index 45d2e55520..fb4c4ffce2 100644 --- a/contrib/libs/liburing/test/eventfd-ring.t/ya.make +++ b/contrib/libs/liburing/test/eventfd-ring.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/eventfd.c b/contrib/libs/liburing/test/eventfd.c index 081987f520..392eebe414 100644 --- a/contrib/libs/liburing/test/eventfd.c +++ b/contrib/libs/liburing/test/eventfd.c @@ -61,7 +61,6 @@ int main(int argc, char *argv[]) sqe = io_uring_get_sqe(&ring); io_uring_prep_readv(sqe, evfd, &vec, 1, 0); - sqe->flags |= IOSQE_IO_LINK; sqe->user_data = 2; ret = io_uring_submit(&ring); diff --git a/contrib/libs/liburing/test/eventfd.t/ya.make b/contrib/libs/liburing/test/eventfd.t/ya.make index b64217ee96..f8b1939032 100644 --- a/contrib/libs/liburing/test/eventfd.t/ya.make +++ b/contrib/libs/liburing/test/eventfd.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/evloop.t/ya.make b/contrib/libs/liburing/test/evloop.t/ya.make index a5c92be9ca..084615c89e 100644 --- a/contrib/libs/liburing/test/evloop.t/ya.make +++ b/contrib/libs/liburing/test/evloop.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/exec-target.t/ya.make b/contrib/libs/liburing/test/exec-target.t/ya.make index b47e7f3a0f..bc92a41119 100644 --- a/contrib/libs/liburing/test/exec-target.t/ya.make +++ b/contrib/libs/liburing/test/exec-target.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/exit-no-cleanup.c b/contrib/libs/liburing/test/exit-no-cleanup.c index abf63ab2b0..8b1346ffbe 100644 --- a/contrib/libs/liburing/test/exit-no-cleanup.c +++ b/contrib/libs/liburing/test/exit-no-cleanup.c @@ -20,6 +20,11 @@ #include "liburing.h" #include "helpers.h" +// on fast enough machines with enough cores, the first few threads will post +// enough sem's to cause the main thread to exit while some threads are half way +// initialization. This causes a null deference somewhere in thread cleanup, +// which trips ASAN. +#ifndef CONFIG_USE_SANITIZER #define IORING_ENTRIES 8 static pthread_t *threads; @@ -116,3 +121,9 @@ int main(int argc, char *argv[]) // Exit without resource cleanup exit(EXIT_SUCCESS); } +#else +int main(int argc, char *argv[]) +{ + return T_EXIT_SKIP; +} +#endif diff --git a/contrib/libs/liburing/test/exit-no-cleanup.t/ya.make b/contrib/libs/liburing/test/exit-no-cleanup.t/ya.make index 6043dd7ec9..e068bc8fd0 100644 --- a/contrib/libs/liburing/test/exit-no-cleanup.t/ya.make +++ b/contrib/libs/liburing/test/exit-no-cleanup.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/fadvise.c b/contrib/libs/liburing/test/fadvise.c index 12b7ffd912..41ba0b6930 100644 --- a/contrib/libs/liburing/test/fadvise.c +++ b/contrib/libs/liburing/test/fadvise.c @@ -19,30 +19,6 @@ #define LOOPS 100 #define MIN_LOOPS 10 -static unsigned long long utime_since(const struct timeval *s, - const struct timeval *e) -{ - long long sec, usec; - - sec = e->tv_sec - s->tv_sec; - usec = (e->tv_usec - s->tv_usec); - if (sec > 0 && usec < 0) { - sec--; - usec += 1000000; - } - - sec *= 1000000; - return sec + usec; -} - -static unsigned long long utime_since_now(struct timeval *tv) -{ - struct timeval end; - - gettimeofday(&end, NULL); - return utime_since(tv, &end); -} - static int do_fadvise(struct io_uring *ring, int fd, off_t offset, off_t len, int advice) { @@ -93,7 +69,7 @@ static long do_read(int fd, char *buf) perror("lseek"); return -1; } - + gettimeofday(&tv, NULL); ret = read(fd, buf, FILE_SIZE); t = utime_since_now(&tv); @@ -116,6 +92,8 @@ static int test_fadvise(struct io_uring *ring, const char *filename) fd = open(filename, O_RDONLY); if (fd < 0) { + if (errno == EPERM || errno == EACCES) + return T_EXIT_SKIP; perror("open"); return 1; } @@ -149,9 +127,12 @@ static int test_fadvise(struct io_uring *ring, const char *filename) return 1; if (cached_read < uncached_read && - cached_read2 < uncached_read) + cached_read2 < uncached_read) { + free(buf); return 0; + } + free(buf); return 2; } @@ -175,6 +156,8 @@ int main(int argc, char *argv[]) good = bad = 0; for (i = 0; i < LOOPS; i++) { ret = test_fadvise(&ring, fname); + if (ret == T_EXIT_SKIP) + return T_EXIT_SKIP; if (ret == 1) { fprintf(stderr, "read_fadvise failed\n"); goto err; diff --git a/contrib/libs/liburing/test/fadvise.t/ya.make b/contrib/libs/liburing/test/fadvise.t/ya.make index 05e6a24928..38376037fd 100644 --- a/contrib/libs/liburing/test/fadvise.t/ya.make +++ b/contrib/libs/liburing/test/fadvise.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/fallocate.t/ya.make b/contrib/libs/liburing/test/fallocate.t/ya.make index 93b93c9d99..ecba017172 100644 --- a/contrib/libs/liburing/test/fallocate.t/ya.make +++ b/contrib/libs/liburing/test/fallocate.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/fc2a85cb02ef.t/ya.make b/contrib/libs/liburing/test/fc2a85cb02ef.t/ya.make index 96ffd42829..ab94c228da 100644 --- a/contrib/libs/liburing/test/fc2a85cb02ef.t/ya.make +++ b/contrib/libs/liburing/test/fc2a85cb02ef.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/fd-install.t/ya.make b/contrib/libs/liburing/test/fd-install.t/ya.make index 55f72f4d28..714c7d216c 100644 --- a/contrib/libs/liburing/test/fd-install.t/ya.make +++ b/contrib/libs/liburing/test/fd-install.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/fd-pass.t/ya.make b/contrib/libs/liburing/test/fd-pass.t/ya.make index d7cf684aab..913a1e7929 100644 --- a/contrib/libs/liburing/test/fd-pass.t/ya.make +++ b/contrib/libs/liburing/test/fd-pass.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/fdinfo.c b/contrib/libs/liburing/test/fdinfo.c new file mode 100644 index 0000000000..ffd82b5133 --- /dev/null +++ b/contrib/libs/liburing/test/fdinfo.c @@ -0,0 +1,428 @@ +#include "../config-host.h" +/* SPDX-License-Identifier: MIT */ +/* + * Description: basic read/write tests with buffered, O_DIRECT, and SQPOLL + */ +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <sys/types.h> +#include <poll.h> +#include <sys/eventfd.h> +#include <sys/resource.h> + +#include "helpers.h" +#include "liburing.h" + +#define FILE_SIZE (256 * 1024) +#define BS 8192 +#define BUFFERS (FILE_SIZE / BS) + +static struct iovec *vecs; +static int no_read; +static int warned; + +static void fdinfo_read(struct io_uring *ring) +{ + char fd_name[128]; + char *buf; + int fd; + + buf = malloc(4096); + + sprintf(fd_name, "/proc/self/fdinfo/%d", ring->ring_fd); + fd = open(fd_name, O_RDONLY); + if (fd < 0) { + perror("open"); + return; + } + + do { + int ret = read(fd, buf, 4096); + + if (ret < 0) { + perror("fdinfo read"); + break; + } else if (ret == 4096) { + continue; + } + break; + } while (1); + + close(fd); + free(buf); +} + +static int __test_io(const char *file, struct io_uring *ring, int write, + int buffered, int sqthread, int fixed, int nonvec, + int buf_select, int seq, int exp_len) +{ + struct io_uring_sqe *sqe; + struct io_uring_cqe *cqe; + int open_flags; + int i, fd = -1, ret; + off_t offset; + +#ifdef VERBOSE + fprintf(stdout, "%s: start %d/%d/%d/%d/%d: ", __FUNCTION__, write, + buffered, sqthread, + fixed, nonvec); +#endif + if (write) + open_flags = O_WRONLY; + else + open_flags = O_RDONLY; + if (!buffered) + open_flags |= O_DIRECT; + + if (fixed) { + ret = t_register_buffers(ring, vecs, BUFFERS); + if (ret == T_SETUP_SKIP) + return T_EXIT_SKIP; + if (ret != T_SETUP_OK) { + fprintf(stderr, "buffer reg failed: %d\n", ret); + goto err; + } + } + + fd = open(file, open_flags); + if (fd < 0) { + if (errno == EINVAL) + return 0; + if (errno == EPERM || errno == EACCES) + return T_EXIT_SKIP; + perror("file open"); + goto err; + } + + if (sqthread) { + ret = io_uring_register_files(ring, &fd, 1); + if (ret) { + fprintf(stderr, "file reg failed: %d\n", ret); + goto err; + } + } + + offset = 0; + for (i = 0; i < BUFFERS; i++) { + sqe = io_uring_get_sqe(ring); + if (!sqe) { + fprintf(stderr, "sqe get failed\n"); + goto err; + } + if (!seq) + offset = BS * (rand() % BUFFERS); + if (write) { + int do_fixed = fixed; + int use_fd = fd; + + if (sqthread) + use_fd = 0; + if (fixed && (i & 1)) + do_fixed = 0; + if (do_fixed) { + io_uring_prep_write_fixed(sqe, use_fd, vecs[i].iov_base, + vecs[i].iov_len, + offset, i); + } else if (nonvec) { + io_uring_prep_write(sqe, use_fd, vecs[i].iov_base, + vecs[i].iov_len, offset); + } else { + io_uring_prep_writev(sqe, use_fd, &vecs[i], 1, + offset); + } + } else { + int do_fixed = fixed; + int use_fd = fd; + + if (sqthread) + use_fd = 0; + if (fixed && (i & 1)) + do_fixed = 0; + if (do_fixed) { + io_uring_prep_read_fixed(sqe, use_fd, vecs[i].iov_base, + vecs[i].iov_len, + offset, i); + } else if (nonvec) { + io_uring_prep_read(sqe, use_fd, vecs[i].iov_base, + vecs[i].iov_len, offset); + } else { + io_uring_prep_readv(sqe, use_fd, &vecs[i], 1, + offset); + } + + } + sqe->user_data = i; + if (sqthread) + sqe->flags |= IOSQE_FIXED_FILE; + if (buf_select) { + if (nonvec) + sqe->addr = 0; + sqe->flags |= IOSQE_BUFFER_SELECT; + sqe->buf_group = buf_select; + } + if (seq) + offset += BS; + } + + fdinfo_read(ring); + + ret = io_uring_submit(ring); + if (ret != BUFFERS) { + fprintf(stderr, "submit got %d, wanted %d\n", ret, BUFFERS); + goto err; + } + + for (i = 0; i < 10; i++) { + fdinfo_read(ring); + usleep(2); + } + + for (i = 0; i < BUFFERS; i++) { + ret = io_uring_wait_cqe(ring, &cqe); + if (ret) { + fprintf(stderr, "wait_cqe=%d\n", ret); + goto err; + } + if (cqe->res == -EINVAL && nonvec) { + if (!warned) { + fprintf(stdout, "Non-vectored IO not " + "supported, skipping\n"); + warned = 1; + no_read = 1; + } + } else if (exp_len == -1) { + int iov_len = vecs[cqe->user_data].iov_len; + + if (cqe->res != iov_len) { + fprintf(stderr, "cqe res %d, wanted %d\n", + cqe->res, iov_len); + goto err; + } + } else if (cqe->res != exp_len) { + fprintf(stderr, "cqe res %d, wanted %d\n", cqe->res, exp_len); + goto err; + } + if (buf_select && exp_len == BS) { + int bid = cqe->flags >> 16; + unsigned char *ptr = vecs[bid].iov_base; + int j; + + for (j = 0; j < BS; j++) { + if (ptr[j] == cqe->user_data) + continue; + + fprintf(stderr, "Data mismatch! bid=%d, " + "wanted=%d, got=%d\n", bid, + (int)cqe->user_data, ptr[j]); + return 1; + } + } + io_uring_cqe_seen(ring, cqe); + } + + if (fixed) { + ret = io_uring_unregister_buffers(ring); + if (ret) { + fprintf(stderr, "buffer unreg failed: %d\n", ret); + goto err; + } + } + if (sqthread) { + ret = io_uring_unregister_files(ring); + if (ret) { + fprintf(stderr, "file unreg failed: %d\n", ret); + goto err; + } + } + + close(fd); +#ifdef VERBOSE + fprintf(stdout, "PASS\n"); +#endif + return 0; +err: +#ifdef VERBOSE + fprintf(stderr, "FAILED\n"); +#endif + if (fd != -1) + close(fd); + return 1; +} +static int test_io(const char *file, int write, int buffered, int sqthread, + int fixed, int nonvec, int exp_len) +{ + struct io_uring ring; + int ret, ring_flags = 0; + + if (sqthread) + ring_flags = IORING_SETUP_SQPOLL; + + ret = t_create_ring(64, &ring, ring_flags); + if (ret == T_SETUP_SKIP) + return 0; + if (ret != T_SETUP_OK) { + fprintf(stderr, "ring create failed: %d\n", ret); + return 1; + } + + ret = __test_io(file, &ring, write, buffered, sqthread, fixed, nonvec, + 0, 0, exp_len); + io_uring_queue_exit(&ring); + return ret; +} + +static int has_nonvec_read(void) +{ + struct io_uring_probe *p; + struct io_uring ring; + int ret; + + ret = io_uring_queue_init(1, &ring, 0); + if (ret) { + fprintf(stderr, "queue init failed: %d\n", ret); + exit(ret); + } + + p = t_calloc(1, sizeof(*p) + 256 * sizeof(struct io_uring_probe_op)); + ret = io_uring_register_probe(&ring, p, 256); + /* if we don't have PROBE_REGISTER, we don't have OP_READ/WRITE */ + if (ret == -EINVAL) { +out: + io_uring_queue_exit(&ring); + free(p); + return 0; + } else if (ret) { + fprintf(stderr, "register_probe: %d\n", ret); + goto out; + } + + if (p->ops_len <= IORING_OP_READ) + goto out; + if (!(p->ops[IORING_OP_READ].flags & IO_URING_OP_SUPPORTED)) + goto out; + io_uring_queue_exit(&ring); + free(p); + return 1; +} + +static int test_eventfd_read(int flags) +{ + struct io_uring ring; + int fd, ret; + eventfd_t event; + struct io_uring_sqe *sqe; + struct io_uring_cqe *cqe; + + if (no_read) + return 0; + ret = t_create_ring(64, &ring, flags); + if (ret == T_SETUP_SKIP) + return 0; + if (ret != T_SETUP_OK) { + if (ret == -EINVAL) + return 0; + fprintf(stderr, "ring create failed: %d\n", ret); + return 1; + } + + fd = eventfd(1, 0); + if (fd < 0) { + perror("eventfd"); + return 1; + } + sqe = io_uring_get_sqe(&ring); + io_uring_prep_read(sqe, fd, &event, sizeof(eventfd_t), 0); + ret = io_uring_submit(&ring); + if (ret != 1) { + fprintf(stderr, "submitted %d\n", ret); + return 1; + } + fdinfo_read(&ring); + eventfd_write(fd, 1); + ret = io_uring_wait_cqe(&ring, &cqe); + if (ret) { + fprintf(stderr, "wait_cqe=%d\n", ret); + return 1; + } + if (cqe->res == -EINVAL) { + fprintf(stdout, "eventfd IO not supported, skipping\n"); + } else if (cqe->res != sizeof(eventfd_t)) { + fprintf(stderr, "cqe res %d, wanted %d\n", cqe->res, + (int) sizeof(eventfd_t)); + return 1; + } + io_uring_cqe_seen(&ring, cqe); + return 0; +} + +int main(int argc, char *argv[]) +{ + int i, ret, nr; + char buf[256]; + char *fname; + + if (argc > 1) { + fname = argv[1]; + } else { + srand((unsigned)time(NULL)); + snprintf(buf, sizeof(buf), ".basic-rw-%u-%u", + (unsigned)rand(), (unsigned)getpid()); + fname = buf; + t_create_file(fname, FILE_SIZE); + } + + signal(SIGXFSZ, SIG_IGN); + + vecs = t_create_buffers(BUFFERS, BS); + + /* if we don't have nonvec read, skip testing that */ + nr = has_nonvec_read() ? 32 : 16; + + for (i = 0; i < nr; i++) { + int write = (i & 1) != 0; + int buffered = (i & 2) != 0; + int sqthread = (i & 4) != 0; + int fixed = (i & 8) != 0; + int nonvec = (i & 16) != 0; + + ret = test_io(fname, write, buffered, sqthread, fixed, nonvec, + BS); + if (ret == T_EXIT_SKIP) + continue; + if (ret) { + fprintf(stderr, "test_io failed %d/%d/%d/%d/%d\n", + write, buffered, sqthread, fixed, nonvec); + goto err; + } + } + + ret = test_eventfd_read(0); + if (ret) { + fprintf(stderr, "eventfd read 0 failed\n"); + goto err; + } + + ret = test_eventfd_read(IORING_SETUP_DEFER_TASKRUN|IORING_SETUP_SINGLE_ISSUER); + if (ret) { + fprintf(stderr, "eventfd read defer failed\n"); + goto err; + } + + ret = test_eventfd_read(IORING_SETUP_SQPOLL); + if (ret) { + fprintf(stderr, "eventfd read sqpoll failed\n"); + goto err; + } + + if (fname != argv[1]) + unlink(fname); + return 0; +err: + if (fname != argv[1]) + unlink(fname); + return 1; +} diff --git a/contrib/libs/liburing/test/fdinfo.t/ya.make b/contrib/libs/liburing/test/fdinfo.t/ya.make new file mode 100644 index 0000000000..6dc3cfe9e9 --- /dev/null +++ b/contrib/libs/liburing/test/fdinfo.t/ya.make @@ -0,0 +1,35 @@ +# Generated by devtools/yamaker. + +PROGRAM() + +WITHOUT_LICENSE_TEXTS() + +VERSION(2.8) + +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( + fdinfo.c + helpers.c +) + +END() diff --git a/contrib/libs/liburing/test/fifo-nonblock-read.c b/contrib/libs/liburing/test/fifo-nonblock-read.c new file mode 100644 index 0000000000..4f135c696d --- /dev/null +++ b/contrib/libs/liburing/test/fifo-nonblock-read.c @@ -0,0 +1,70 @@ +#include "../config-host.h" +/* SPDX-License-Identifier: MIT */ +/* + * Description: Test O_NONBLOCK reading from fifo, should result in proper + * retry and a positive read results. Buggy result would be + * -EAGAIN being returned to the user. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "liburing.h" +#include "helpers.h" + +int main(int argc, char *argv[]) +{ + struct io_uring_sqe *sqe; + struct io_uring_cqe *cqe; + struct io_uring ring; + char buf[32]; + int fds[2]; + int flags; + int ret; + + io_uring_queue_init(1, &ring, 0); + + if (pipe(fds) < 0) { + perror("pipe"); + return T_EXIT_FAIL; + } + + flags = fcntl(fds[0], F_GETFL, 0); + if (flags < 0) { + perror("fcntl get"); + return T_EXIT_FAIL; + } + flags |= O_NONBLOCK; + ret = fcntl(fds[0], F_SETFL, flags); + if (ret < 0) { + perror("fcntl set"); + return T_EXIT_FAIL; + } + + sqe = io_uring_get_sqe(&ring); + io_uring_prep_read(sqe, fds[0], buf, sizeof(buf), 0); + io_uring_submit(&ring); + + usleep(10000); + + ret = write(fds[1], "Hello\n", 6); + if (ret < 0) { + perror("pipe write"); + return T_EXIT_FAIL; + } + + ret = io_uring_wait_cqe(&ring, &cqe); + if (ret < 0) { + 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; + } + + io_uring_cqe_seen(&ring, cqe); + io_uring_queue_exit(&ring); + return T_EXIT_PASS; +} diff --git a/contrib/libs/liburing/test/fifo-nonblock-read.t/ya.make b/contrib/libs/liburing/test/fifo-nonblock-read.t/ya.make new file mode 100644 index 0000000000..497262e908 --- /dev/null +++ b/contrib/libs/liburing/test/fifo-nonblock-read.t/ya.make @@ -0,0 +1,35 @@ +# Generated by devtools/yamaker. + +PROGRAM() + +WITHOUT_LICENSE_TEXTS() + +VERSION(2.8) + +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( + fifo-nonblock-read.c + helpers.c +) + +END() diff --git a/contrib/libs/liburing/test/file-register.c b/contrib/libs/liburing/test/file-register.c index ce51022632..de35d16d2d 100644 --- a/contrib/libs/liburing/test/file-register.c +++ b/contrib/libs/liburing/test/file-register.c @@ -121,16 +121,21 @@ static int test_grow(struct io_uring *ring) fds = open_files(1, 0, off); ret = io_uring_register_files_update(ring, off, fds, 1); if (ret != 1) { - if (off == 300 && ret == -EINVAL) + if (off == 300 && ret == -EINVAL) { + free(fds); break; + } fprintf(stderr, "%s: update ret=%d\n", __FUNCTION__, ret); + free(fds); break; } if (off >= 300) { fprintf(stderr, "%s: Succeeded beyond end-of-list?\n", __FUNCTION__); + free(fds); goto err; } off++; + free(fds); } while (1); ret = io_uring_unregister_files(ring); @@ -364,8 +369,10 @@ static int test_basic(struct io_uring *ring, int fail) ret = io_uring_register_files(ring, files, 100); if (ret) { if (fail) { - if (ret == -EBADF || ret == -EFAULT) + if (ret == -EBADF || ret == -EFAULT) { + close_files(files, nr_files, 0); return 0; + } } fprintf(stderr, "%s: register %d\n", __FUNCTION__, ret); goto err; @@ -632,6 +639,7 @@ static int test_sparse_updates(void) ret = io_uring_register_files(&ring, fds, 256); if (ret) { fprintf(stderr, "file_register: %d\n", ret); + free(fds); return ret; } @@ -640,6 +648,7 @@ static int test_sparse_updates(void) ret = io_uring_register_files_update(&ring, i, &newfd, 1); if (ret != 1) { fprintf(stderr, "file_update: %d\n", ret); + free(fds); return ret; } } @@ -651,6 +660,7 @@ static int test_sparse_updates(void) ret = io_uring_register_files(&ring, fds, 256); if (ret) { fprintf(stderr, "file_register: %d\n", ret); + free(fds); return ret; } @@ -659,12 +669,14 @@ static int test_sparse_updates(void) ret = io_uring_register_files_update(&ring, i, &newfd, 1); if (ret != 1) { fprintf(stderr, "file_update: %d\n", ret); + free(fds); return ret; } } io_uring_unregister_files(&ring); io_uring_queue_exit(&ring); + free(fds); return 0; } diff --git a/contrib/libs/liburing/test/file-register.t/ya.make b/contrib/libs/liburing/test/file-register.t/ya.make index f7bc1cd23d..4961fbeb84 100644 --- a/contrib/libs/liburing/test/file-register.t/ya.make +++ b/contrib/libs/liburing/test/file-register.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/file-update.c b/contrib/libs/liburing/test/file-update.c index 0896807ddf..39bb8ae99c 100644 --- a/contrib/libs/liburing/test/file-update.c +++ b/contrib/libs/liburing/test/file-update.c @@ -175,7 +175,7 @@ static int test_update_no_table(void) ret = cqe->res; io_uring_cqe_seen(&ring, cqe); if (ret != -EMFILE && ret != -EINVAL && ret != -EOVERFLOW && - ret != -ENXIO) { + ret != -ENXIO && ret != -EBADF) { fprintf(stderr, "Bad cqe res: %d\n", ret); goto fail; } diff --git a/contrib/libs/liburing/test/file-update.t/ya.make b/contrib/libs/liburing/test/file-update.t/ya.make index 67491db91c..3c305603b6 100644 --- a/contrib/libs/liburing/test/file-update.t/ya.make +++ b/contrib/libs/liburing/test/file-update.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/file-verify.c b/contrib/libs/liburing/test/file-verify.c index 0014236f5c..a2b4b00397 100644 --- a/contrib/libs/liburing/test/file-verify.c +++ b/contrib/libs/liburing/test/file-verify.c @@ -91,6 +91,8 @@ static int test_truncate(struct io_uring *ring, const char *fname, int buffered, else fd = open(fname, O_DIRECT | O_RDWR); if (fd < 0) { + if (!buffered && errno == EINVAL) + return T_EXIT_SKIP; perror("open"); return 1; } @@ -347,6 +349,8 @@ static int test(struct io_uring *ring, const char *fname, int buffered, flags |= O_DIRECT; fd = open(fname, flags); if (fd < 0) { + if (errno == EINVAL || errno == EPERM || errno == EACCES) + return T_EXIT_SKIP; perror("open"); return 1; } @@ -506,6 +510,8 @@ static int fill_pattern(const char *fname) fd = open(fname, O_WRONLY); if (fd < 0) { + if (errno == EPERM || errno == EACCES) + return T_EXIT_SKIP; perror("open"); return 1; } @@ -558,89 +564,94 @@ int main(int argc, char *argv[]) goto err; } - if (fill_pattern(fname)) + ret = fill_pattern(fname); + if (ret == T_EXIT_SKIP) + return T_EXIT_SKIP; + else if (ret) goto err; ret = test(&ring, fname, 1, 0, 0, 0, 0); + if (ret == T_EXIT_SKIP) + return T_EXIT_SKIP; if (ret) { fprintf(stderr, "Buffered novec test failed\n"); goto err; } ret = test(&ring, fname, 1, 0, 0, 1, 0); - if (ret) { + if (ret == T_EXIT_FAIL) { fprintf(stderr, "Buffered novec reg test failed\n"); goto err; } ret = test(&ring, fname, 1, 0, 0, 0, 1); - if (ret) { + if (ret == T_EXIT_FAIL) { fprintf(stderr, "Buffered novec provide test failed\n"); goto err; } ret = test(&ring, fname, 1, 1, 0, 0, 0); - if (ret) { + if (ret == T_EXIT_FAIL) { fprintf(stderr, "Buffered vec test failed\n"); goto err; } ret = test(&ring, fname, 1, 1, 1, 0, 0); - if (ret) { + if (ret == T_EXIT_FAIL) { fprintf(stderr, "Buffered small vec test failed\n"); goto err; } ret = test(&ring, fname, 0, 0, 0, 0, 0); - if (ret) { + if (ret == T_EXIT_FAIL) { fprintf(stderr, "O_DIRECT novec test failed\n"); goto err; } ret = test(&ring, fname, 0, 0, 0, 1, 0); - if (ret) { + if (ret == T_EXIT_FAIL) { fprintf(stderr, "O_DIRECT novec reg test failed\n"); goto err; } ret = test(&ring, fname, 0, 0, 0, 0, 1); - if (ret) { + if (ret == T_EXIT_FAIL) { fprintf(stderr, "O_DIRECT novec provide test failed\n"); goto err; } ret = test(&ring, fname, 0, 1, 0, 0, 0); - if (ret) { + if (ret == T_EXIT_FAIL) { fprintf(stderr, "O_DIRECT vec test failed\n"); goto err; } ret = test(&ring, fname, 0, 1, 1, 0, 0); - if (ret) { + if (ret == T_EXIT_FAIL) { fprintf(stderr, "O_DIRECT small vec test failed\n"); goto err; } ret = test_truncate(&ring, fname, 1, 0, 0); - if (ret) { + if (ret == T_EXIT_FAIL) { fprintf(stderr, "Buffered end truncate read failed\n"); goto err; } ret = test_truncate(&ring, fname, 1, 1, 0); - if (ret) { + if (ret == T_EXIT_FAIL) { fprintf(stderr, "Buffered end truncate vec read failed\n"); goto err; } ret = test_truncate(&ring, fname, 1, 0, 1); - if (ret) { + if (ret == T_EXIT_FAIL) { fprintf(stderr, "Buffered end truncate pbuf read failed\n"); goto err; } ret = test_truncate(&ring, fname, 0, 0, 0); - if (ret) { + if (ret == T_EXIT_FAIL) { fprintf(stderr, "O_DIRECT end truncate read failed\n"); goto err; } ret = test_truncate(&ring, fname, 0, 1, 0); - if (ret) { + if (ret == T_EXIT_FAIL) { fprintf(stderr, "O_DIRECT end truncate vec read failed\n"); goto err; } ret = test_truncate(&ring, fname, 0, 0, 1); - if (ret) { + if (ret == T_EXIT_FAIL) { fprintf(stderr, "O_DIRECT end truncate pbuf read failed\n"); goto err; } diff --git a/contrib/libs/liburing/test/file-verify.t/ya.make b/contrib/libs/liburing/test/file-verify.t/ya.make index 263b811e95..0d3a52d017 100644 --- a/contrib/libs/liburing/test/file-verify.t/ya.make +++ b/contrib/libs/liburing/test/file-verify.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/files-exit-hang-poll.t/ya.make b/contrib/libs/liburing/test/files-exit-hang-poll.t/ya.make index cf7bf1f7b9..499443de7f 100644 --- a/contrib/libs/liburing/test/files-exit-hang-poll.t/ya.make +++ b/contrib/libs/liburing/test/files-exit-hang-poll.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/files-exit-hang-timeout.c b/contrib/libs/liburing/test/files-exit-hang-timeout.c index a549e92cdb..18c45eda81 100644 --- a/contrib/libs/liburing/test/files-exit-hang-timeout.c +++ b/contrib/libs/liburing/test/files-exit-hang-timeout.c @@ -44,13 +44,12 @@ static void add_accept(struct io_uring *ring, int fd) sqe = io_uring_get_sqe(ring); io_uring_prep_accept(sqe, fd, 0, 0, SOCK_NONBLOCK | SOCK_CLOEXEC); - sqe->flags |= IOSQE_IO_LINK; } static int setup_io_uring(void) { int ret; - + ret = io_uring_queue_init(16, &ring, 0); if (ret) { fprintf(stderr, "Unable to setup io_uring: %s\n", strerror(-ret)); diff --git a/contrib/libs/liburing/test/files-exit-hang-timeout.t/ya.make b/contrib/libs/liburing/test/files-exit-hang-timeout.t/ya.make index e91c801769..96e4f2eb03 100644 --- a/contrib/libs/liburing/test/files-exit-hang-timeout.t/ya.make +++ b/contrib/libs/liburing/test/files-exit-hang-timeout.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/fixed-buf-iter.c b/contrib/libs/liburing/test/fixed-buf-iter.c index 1cdb327166..d4df6cad9a 100644 --- a/contrib/libs/liburing/test/fixed-buf-iter.c +++ b/contrib/libs/liburing/test/fixed-buf-iter.c @@ -64,7 +64,7 @@ static int test(struct io_uring *ring) return 1; } - if (cqe->res < 0) { + if (cqe->res < 0) { fprintf(stderr, "Error in async operation: %s\n", strerror(-cqe->res)); return 1; } @@ -88,6 +88,8 @@ static int test(struct io_uring *ring) return 1; } io_uring_cqe_seen(ring, cqe); + for (i = 0; i < BUFFERS; i++) + free(iov[i].iov_base); return 0; } diff --git a/contrib/libs/liburing/test/fixed-buf-iter.t/ya.make b/contrib/libs/liburing/test/fixed-buf-iter.t/ya.make index f4ea025d7f..bf3a2a7618 100644 --- a/contrib/libs/liburing/test/fixed-buf-iter.t/ya.make +++ b/contrib/libs/liburing/test/fixed-buf-iter.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/fixed-buf-merge.t/ya.make b/contrib/libs/liburing/test/fixed-buf-merge.t/ya.make index 78178231cc..ad58a01cf8 100644 --- a/contrib/libs/liburing/test/fixed-buf-merge.t/ya.make +++ b/contrib/libs/liburing/test/fixed-buf-merge.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/fixed-hugepage.c b/contrib/libs/liburing/test/fixed-hugepage.c index bbc28bb8a6..b95169fdaa 100644 --- a/contrib/libs/liburing/test/fixed-hugepage.c +++ b/contrib/libs/liburing/test/fixed-hugepage.c @@ -247,7 +247,8 @@ static int register_submit(struct io_uring *ring, struct iovec *iov, ret = io_uring_register_buffers(ring, iov, nr_bufs); if (ret) { - fprintf(stderr, "Error registering buffers: %s\n", strerror(-ret)); + if (ret != -ENOMEM) + fprintf(stderr, "Error registering buffers: %s\n", strerror(-ret)); return ret; } @@ -283,6 +284,8 @@ static int test_one_hugepage(struct io_uring *ring, int fd_in, int fd_out) ret = register_submit(ring, iov, NR_BUFS, fd_in, fd_out); unmap(iov, NR_BUFS, 0); + if (ret == -ENOMEM) + return T_EXIT_SKIP; return ret ? T_EXIT_FAIL : T_EXIT_PASS; } @@ -297,6 +300,8 @@ static int test_multi_hugepages(struct io_uring *ring, int fd_in, int fd_out) ret = register_submit(ring, iov, NR_BUFS, fd_in, fd_out); unmap(iov, NR_BUFS, 0); + if (ret == -ENOMEM) + return T_EXIT_SKIP; return ret ? T_EXIT_FAIL : T_EXIT_PASS; } @@ -312,6 +317,8 @@ static int test_unaligned_hugepage(struct io_uring *ring, int fd_in, int fd_out) ret = register_submit(ring, iov, NR_BUFS, fd_in, fd_out); unmap(iov, NR_BUFS, offset); + if (ret == -ENOMEM) + return T_EXIT_SKIP; return ret ? T_EXIT_FAIL : T_EXIT_PASS; } @@ -327,6 +334,8 @@ static int test_multi_unaligned_mthps(struct io_uring *ring, int fd_in, int fd_o ret = register_submit(ring, iov, NR_BUFS, fd_in, fd_out); free_bufs(iov, NR_BUFS, offset); + if (ret == -ENOMEM) + return T_EXIT_SKIP; return ret ? T_EXIT_FAIL : T_EXIT_PASS; } @@ -342,6 +351,8 @@ static int test_page_mixture(struct io_uring *ring, int fd_in, int fd_out, int h ret = register_submit(ring, iov, NR_BUFS, fd_in, fd_out); unmap(iov, NR_BUFS, 0); + if (ret == -ENOMEM) + return T_EXIT_SKIP; return ret ? T_EXIT_FAIL : T_EXIT_PASS; } diff --git a/contrib/libs/liburing/test/fixed-hugepage.t/ya.make b/contrib/libs/liburing/test/fixed-hugepage.t/ya.make index 9c4ef3dbe4..ad560a9a58 100644 --- a/contrib/libs/liburing/test/fixed-hugepage.t/ya.make +++ b/contrib/libs/liburing/test/fixed-hugepage.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/fixed-link.t/ya.make b/contrib/libs/liburing/test/fixed-link.t/ya.make index afc5190ea1..1e788313a8 100644 --- a/contrib/libs/liburing/test/fixed-link.t/ya.make +++ b/contrib/libs/liburing/test/fixed-link.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/fixed-reuse.t/ya.make b/contrib/libs/liburing/test/fixed-reuse.t/ya.make index 711704cf4d..d0379a8966 100644 --- a/contrib/libs/liburing/test/fixed-reuse.t/ya.make +++ b/contrib/libs/liburing/test/fixed-reuse.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/fpos.t/ya.make b/contrib/libs/liburing/test/fpos.t/ya.make index f9faf5bee7..2ad48f2c07 100644 --- a/contrib/libs/liburing/test/fpos.t/ya.make +++ b/contrib/libs/liburing/test/fpos.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/fsync.t/ya.make b/contrib/libs/liburing/test/fsync.t/ya.make index c3be5c5b45..5c383794b0 100644 --- a/contrib/libs/liburing/test/fsync.t/ya.make +++ b/contrib/libs/liburing/test/fsync.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/futex.c b/contrib/libs/liburing/test/futex.c index 7a7f0c235c..7b2d36ac98 100644 --- a/contrib/libs/liburing/test/futex.c +++ b/contrib/libs/liburing/test/futex.c @@ -121,6 +121,7 @@ static int __test(struct io_uring *ring, int vectored, int async, if (cqe->res == -EINVAL || cqe->res == -EOPNOTSUPP) { no_futex = 1; + free(futex); return 0; } io_uring_cqe_seen(ring, cqe); @@ -135,6 +136,7 @@ static int __test(struct io_uring *ring, int vectored, int async, for (i = 0; i < nfutex; i++) pthread_join(threads[i], &tret); + free(futex); return 0; } @@ -146,7 +148,7 @@ static int test(int flags, int vectored) 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); @@ -167,7 +169,8 @@ static int test_order(int vectored, int async) { struct io_uring_sqe *sqe; struct io_uring_cqe *cqe; - struct futex_waitv fw; + struct futex_waitv fw = { }; + struct io_uring_sync_cancel_reg reg = { }; struct io_uring ring; unsigned int *futex; int ret, i; @@ -179,10 +182,8 @@ static int test_order(int vectored, int async) 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 @@ -242,7 +243,15 @@ static int test_order(int vectored, int async) return 1; } + reg.addr = 2; + ret = io_uring_register_sync_cancel(&ring, ®); + if (ret != 1) { + fprintf(stderr, "Failed to cancel pending futex wait: %d\n", ret); + return 1; + } + io_uring_queue_exit(&ring); + free(futex); return 0; } @@ -323,6 +332,7 @@ static int test_multi_wake(int vectored) } io_uring_queue_exit(&ring); + free(futex); return 0; } @@ -379,6 +389,7 @@ static int test_wake_zero(void) } io_uring_queue_exit(&ring); + free(futex); return 0; } @@ -460,6 +471,7 @@ static int test_invalid(void) io_uring_cqe_seen(&ring, cqe); io_uring_queue_exit(&ring); + free(futex); return 0; } diff --git a/contrib/libs/liburing/test/futex.t/ya.make b/contrib/libs/liburing/test/futex.t/ya.make index 66ce3413c2..6dcd421f49 100644 --- a/contrib/libs/liburing/test/futex.t/ya.make +++ b/contrib/libs/liburing/test/futex.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/hardlink.t/ya.make b/contrib/libs/liburing/test/hardlink.t/ya.make index 970e1a324c..0c4c74ed38 100644 --- a/contrib/libs/liburing/test/hardlink.t/ya.make +++ b/contrib/libs/liburing/test/hardlink.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/helpers.c b/contrib/libs/liburing/test/helpers.c index 0d897271d8..2f09df4f23 100644 --- a/contrib/libs/liburing/test/helpers.c +++ b/contrib/libs/liburing/test/helpers.c @@ -317,3 +317,50 @@ void t_error(int status, int errnum, const char *format, ...) va_end(args); exit(status); } + +unsigned long long mtime_since(const struct timeval *s, const struct timeval *e) +{ + long long sec, usec; + + sec = e->tv_sec - s->tv_sec; + usec = (e->tv_usec - s->tv_usec); + if (sec > 0 && usec < 0) { + sec--; + usec += 1000000; + } + + sec *= 1000; + usec /= 1000; + return sec + usec; +} + +unsigned long long mtime_since_now(struct timeval *tv) +{ + struct timeval end; + + gettimeofday(&end, NULL); + return mtime_since(tv, &end); +} + +unsigned long long utime_since(const struct timeval *s, const struct timeval *e) +{ + long long sec, usec; + + sec = e->tv_sec - s->tv_sec; + usec = (e->tv_usec - s->tv_usec); + if (sec > 0 && usec < 0) { + sec--; + usec += 1000000; + } + + sec *= 1000000; + return sec + usec; +} + +unsigned long long utime_since_now(struct timeval *tv) +{ + struct timeval end; + + gettimeofday(&end, NULL); + return utime_since(tv, &end); +} diff --git a/contrib/libs/liburing/test/helpers.h b/contrib/libs/liburing/test/helpers.h index 9f62a5f63f..9e1cdf5ec0 100644 --- a/contrib/libs/liburing/test/helpers.h +++ b/contrib/libs/liburing/test/helpers.h @@ -12,6 +12,7 @@ extern "C" { #include "liburing.h" #include "../src/setup.h" #include <arpa/inet.h> +#include <sys/time.h> enum t_setup_ret { T_SETUP_OK = 0, @@ -101,6 +102,11 @@ static inline int t_io_uring_init_sqarray(unsigned entries, struct io_uring *rin void t_error(int status, int errnum, const char *format, ...); +unsigned long long mtime_since(const struct timeval *s, const struct timeval *e); +unsigned long long mtime_since_now(struct timeval *tv); +unsigned long long utime_since(const struct timeval *s, const struct timeval *e); +unsigned long long utime_since_now(struct timeval *tv); + #ifdef __cplusplus } #endif diff --git a/contrib/libs/liburing/test/ignore-single-mmap.c b/contrib/libs/liburing/test/ignore-single-mmap.c index 2790b871d3..4b772e3327 100644 --- a/contrib/libs/liburing/test/ignore-single-mmap.c +++ b/contrib/libs/liburing/test/ignore-single-mmap.c @@ -3,7 +3,7 @@ /* * 6.10-rc merge window had a bug where the rewritten mmap support caused * rings allocated with > 1 page, but asking for smaller mappings, would - * cause -EFAULT to be returned rather than a succesful map. This hit + * cause -EFAULT to be returned rather than a successful map. This hit * applications either using an ancient liburing with IORING_FEAT_SINGLE_MMAP * support, or application just ignoring that feature flag and still doing * 3 mmap operations to map the ring. diff --git a/contrib/libs/liburing/test/ignore-single-mmap.t/ya.make b/contrib/libs/liburing/test/ignore-single-mmap.t/ya.make index 3942706db9..82fc501ee6 100644 --- a/contrib/libs/liburing/test/ignore-single-mmap.t/ya.make +++ b/contrib/libs/liburing/test/ignore-single-mmap.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/init-mem.c b/contrib/libs/liburing/test/init-mem.c index 1909e2ac5f..ad71e8278b 100644 --- a/contrib/libs/liburing/test/init-mem.c +++ b/contrib/libs/liburing/test/init-mem.c @@ -14,7 +14,6 @@ #include <netinet/udp.h> #include <arpa/inet.h> #include <net/if.h> -#include <error.h> #include "liburing.h" #include "helpers.h" @@ -43,7 +42,7 @@ static int setup_ctx(struct ctx *ctx, struct q_entries *q) if (posix_memalign(&ctx->mem, 4096, 2*1024*1024)) return T_EXIT_FAIL; - ctx->pre = ctx->mem + 4096 - sizeof(unsigned long); + ctx->pre = ctx->mem + 4096 - sizeof(unsigned long long); *ctx->pre = PRE_RED; ctx->ring_mem = ctx->mem + 4096; @@ -69,6 +68,7 @@ static int setup_ctx(struct ctx *ctx, struct q_entries *q) static void clean_ctx(struct ctx *ctx) { io_uring_queue_exit(&ctx->ring); + free(ctx->mem); } static int check_red(struct ctx *ctx, unsigned long i) @@ -95,10 +95,12 @@ static int test(struct q_entries *q) int j, ret, batch; ret = setup_ctx(&ctx, q); - if (ret == T_EXIT_SKIP) + if (ret == T_EXIT_SKIP) { + clean_ctx(&ctx); return T_EXIT_SKIP; - else if (ret != T_EXIT_PASS) + } else if (ret != T_EXIT_PASS) { return ret; + } batch = 64; if (batch > q->sqes) diff --git a/contrib/libs/liburing/test/init-mem.t/ya.make b/contrib/libs/liburing/test/init-mem.t/ya.make index c60cfe5615..0cd8d18352 100644 --- a/contrib/libs/liburing/test/init-mem.t/ya.make +++ b/contrib/libs/liburing/test/init-mem.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/io-cancel.c b/contrib/libs/liburing/test/io-cancel.c index 16a385f44b..64725a7c6b 100644 --- a/contrib/libs/liburing/test/io-cancel.c +++ b/contrib/libs/liburing/test/io-cancel.c @@ -23,30 +23,6 @@ static struct iovec *vecs; -static unsigned long long utime_since(const struct timeval *s, - const struct timeval *e) -{ - long long sec, usec; - - sec = e->tv_sec - s->tv_sec; - usec = (e->tv_usec - s->tv_usec); - if (sec > 0 && usec < 0) { - sec--; - usec += 1000000; - } - - sec *= 1000000; - return sec + usec; -} - -static unsigned long long utime_since_now(struct timeval *tv) -{ - struct timeval end; - - gettimeofday(&end, NULL); - return utime_since(tv, &end); -} - static int start_io(struct io_uring *ring, int fd, int do_write) { struct io_uring_sqe *sqe; diff --git a/contrib/libs/liburing/test/io-cancel.t/ya.make b/contrib/libs/liburing/test/io-cancel.t/ya.make index 12379a4a76..ef2974bef4 100644 --- a/contrib/libs/liburing/test/io-cancel.t/ya.make +++ b/contrib/libs/liburing/test/io-cancel.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/io_uring_enter.t/ya.make b/contrib/libs/liburing/test/io_uring_enter.t/ya.make index 83a0199127..ea11807c30 100644 --- a/contrib/libs/liburing/test/io_uring_enter.t/ya.make +++ b/contrib/libs/liburing/test/io_uring_enter.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/io_uring_passthrough.c b/contrib/libs/liburing/test/io_uring_passthrough.c index ad6b6d3e5f..e08b220d88 100644 --- a/contrib/libs/liburing/test/io_uring_passthrough.c +++ b/contrib/libs/liburing/test/io_uring_passthrough.c @@ -96,6 +96,8 @@ static int __test_io(const char *file, struct io_uring *ring, int tc, int read, fd = open(file, open_flags); if (fd < 0) { + if (errno == EACCES || errno == EPERM) + return T_EXIT_SKIP; perror("file open"); goto err; } @@ -166,6 +168,8 @@ static int __test_io(const char *file, struct io_uring *ring, int tc, int read, } } sqe->opcode = IORING_OP_URING_CMD; + if (do_fixed) + sqe->uring_cmd_flags |= IORING_URING_CMD_FIXED; sqe->user_data = ((uint64_t)offset << 32) | i; if (sqthread) sqe->flags |= IOSQE_FIXED_FILE; diff --git a/contrib/libs/liburing/test/io_uring_passthrough.t/ya.make b/contrib/libs/liburing/test/io_uring_passthrough.t/ya.make index 63a2078929..5e3b4fc961 100644 --- a/contrib/libs/liburing/test/io_uring_passthrough.t/ya.make +++ b/contrib/libs/liburing/test/io_uring_passthrough.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/io_uring_register.c b/contrib/libs/liburing/test/io_uring_register.c index c315750adc..e5d65b18ec 100644 --- a/contrib/libs/liburing/test/io_uring_register.c +++ b/contrib/libs/liburing/test/io_uring_register.c @@ -22,6 +22,7 @@ #include <linux/mman.h> #include <sys/time.h> #include <sys/resource.h> +#include <sys/vfs.h> #include <limits.h> #include "helpers.h" @@ -77,8 +78,13 @@ static int new_io_uring(int entries, struct io_uring_params *p) #define MAXFDS (UINT_MAX * sizeof(int)) +#define OFS_MAGIC 0x794c7630 +#define TMPFS_MAGIC 0x01021994 +#define RAMFS_MAGIC 0x858458f6 + static void *map_filebacked(size_t size) { + struct statfs buf; int fd, ret; void *addr; char template[32] = "io_uring_register-test-XXXXXXXX"; @@ -88,8 +94,21 @@ static void *map_filebacked(size_t size) perror("mkstemp"); return NULL; } + if (statfs(template, &buf) < 0) { + perror("statfs"); + unlink(template); + close(fd); + return NULL; + } unlink(template); + /* virtual file systems may not present as file mapped */ + if (buf.f_type == OFS_MAGIC || buf.f_type == RAMFS_MAGIC || + buf.f_type == TMPFS_MAGIC) { + close(fd); + return NULL; + } + ret = ftruncate(fd, size); if (ret < 0) { perror("ftruncate"); @@ -366,12 +385,12 @@ static int test_iovec_size(int fd) /* file-backed buffers -- not supported */ buf = map_filebacked(2*1024*1024); - if (!buf) - status = 1; - iov.iov_base = buf; - iov.iov_len = 2*1024*1024; - status |= expect_fail(fd, IORING_REGISTER_BUFFERS, &iov, 1, -EFAULT, -EOPNOTSUPP); - munmap(buf, 2*1024*1024); + if (buf) { + iov.iov_base = buf; + iov.iov_len = 2*1024*1024; + 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 * or whatever we're supposed to get. NOTE: this requires @@ -418,14 +437,14 @@ static int ioring_poll(struct io_uring *ring, int fd, int fixed) return ret; } -static int test_poll_ringfd(void) +static int __test_poll_ringfd(int ring_flags) { int status = 0; int ret; int fd; struct io_uring ring; - ret = io_uring_queue_init(1, &ring, 0); + ret = io_uring_queue_init(2, &ring, ring_flags); if (ret) { perror("io_uring_queue_init"); return 1; @@ -448,6 +467,17 @@ static int test_poll_ringfd(void) return status; } +static int test_poll_ringfd(void) +{ + int ret; + + ret = __test_poll_ringfd(0); + if (ret) + return ret; + + return __test_poll_ringfd(IORING_SETUP_SQPOLL); +} + int main(int argc, char **argv) { int fd, ret; diff --git a/contrib/libs/liburing/test/io_uring_register.t/ya.make b/contrib/libs/liburing/test/io_uring_register.t/ya.make index 1d46c47686..ab97e7faba 100644 --- a/contrib/libs/liburing/test/io_uring_register.t/ya.make +++ b/contrib/libs/liburing/test/io_uring_register.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/io_uring_setup.t/ya.make b/contrib/libs/liburing/test/io_uring_setup.t/ya.make index e98edd9af6..04d49debbc 100644 --- a/contrib/libs/liburing/test/io_uring_setup.t/ya.make +++ b/contrib/libs/liburing/test/io_uring_setup.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/iopoll-leak.c b/contrib/libs/liburing/test/iopoll-leak.c index 01b98fb64a..53b92426d6 100644 --- a/contrib/libs/liburing/test/iopoll-leak.c +++ b/contrib/libs/liburing/test/iopoll-leak.c @@ -27,6 +27,8 @@ static int do_iopoll(const char *fname) fd = open(fname, O_RDONLY | O_DIRECT); if (fd < 0) { + if (errno == EINVAL || errno == EPERM || errno == EACCES) + return T_EXIT_SKIP; perror("open"); return T_EXIT_SKIP; } @@ -40,6 +42,8 @@ static int do_iopoll(const char *fname) io_uring_submit(&ring); close(fd); + free(iov->iov_base); + free(iov); return T_EXIT_PASS; } diff --git a/contrib/libs/liburing/test/iopoll-leak.t/ya.make b/contrib/libs/liburing/test/iopoll-leak.t/ya.make index f6c3268667..6d067a1f63 100644 --- a/contrib/libs/liburing/test/iopoll-leak.t/ya.make +++ b/contrib/libs/liburing/test/iopoll-leak.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/iopoll-overflow.c b/contrib/libs/liburing/test/iopoll-overflow.c index 96152fcfe4..aa6db71735 100644 --- a/contrib/libs/liburing/test/iopoll-overflow.c +++ b/contrib/libs/liburing/test/iopoll-overflow.c @@ -96,7 +96,7 @@ int main(int argc, char *argv[]) fd = open(fname, O_RDONLY | O_DIRECT); if (fd < 0) { - if (errno == EINVAL) { + if (errno == EINVAL || errno == EACCES || errno == EPERM) { if (fname != argv[1]) unlink(fname); return T_EXIT_SKIP; diff --git a/contrib/libs/liburing/test/iopoll-overflow.t/ya.make b/contrib/libs/liburing/test/iopoll-overflow.t/ya.make index ee34ce968d..f363fa5cb2 100644 --- a/contrib/libs/liburing/test/iopoll-overflow.t/ya.make +++ b/contrib/libs/liburing/test/iopoll-overflow.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/iopoll.c b/contrib/libs/liburing/test/iopoll.c index b77b82d945..6de0e9b78b 100644 --- a/contrib/libs/liburing/test/iopoll.c +++ b/contrib/libs/liburing/test/iopoll.c @@ -88,7 +88,7 @@ static int __test_io(const char *file, struct io_uring *ring, int write, int sqt } fd = open(file, open_flags); if (fd < 0) { - if (errno == EINVAL) + if (errno == EINVAL || errno == EPERM || errno == EACCES) return 0; perror("file open"); goto err; @@ -231,7 +231,7 @@ static int test_io_uring_cqe_peek(const char *file) fd = open(file, O_RDONLY | O_DIRECT); if (fd < 0) { - if (errno == EINVAL) { + if (errno == EINVAL || errno == EPERM || errno == EACCES) { io_uring_queue_exit(&ring); return T_EXIT_SKIP; } @@ -303,7 +303,7 @@ static int test_io_uring_submit_enters(const char *file) open_flags = O_WRONLY | O_DIRECT; fd = open(file, open_flags); if (fd < 0) { - if (errno == EINVAL) + if (errno == EINVAL || errno == EPERM || errno == EACCES) return T_EXIT_SKIP; perror("file open"); goto err; diff --git a/contrib/libs/liburing/test/iopoll.t/ya.make b/contrib/libs/liburing/test/iopoll.t/ya.make index fd11b7ce20..dadb9691e0 100644 --- a/contrib/libs/liburing/test/iopoll.t/ya.make +++ b/contrib/libs/liburing/test/iopoll.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/kallsyms.c b/contrib/libs/liburing/test/kallsyms.c new file mode 100644 index 0000000000..f4229b8771 --- /dev/null +++ b/contrib/libs/liburing/test/kallsyms.c @@ -0,0 +1,204 @@ +#include "../config-host.h" +/* SPDX-License-Identifier: MIT */ +/* + * Description: read /proc/kallsyms. Mostly just here so that fops->read() can + * get exercised, with and without registered buffers + */ +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <sys/types.h> +#include <poll.h> +#include <sys/eventfd.h> +#include <sys/resource.h> + +#include "helpers.h" +#include "liburing.h" + +#define FILE_SIZE (8 * 1024) +#define BS 8192 +#define BUFFERS (FILE_SIZE / BS) + +static struct iovec *vecs; +static int warned; + +static int __test_io(const char *file, struct io_uring *ring, int fixed, int nonvec) +{ + struct io_uring_sqe *sqe; + struct io_uring_cqe *cqe; + int open_flags; + int i, fd = -1, ret; + off_t offset; + + open_flags = O_RDONLY; + if (fixed) { + ret = t_register_buffers(ring, vecs, BUFFERS); + if (ret == T_SETUP_SKIP) + return 0; + if (ret != T_SETUP_OK) { + fprintf(stderr, "buffer reg failed: %d\n", ret); + goto err; + } + } + + fd = open(file, open_flags); + if (fd < 0) { + if (errno == EINVAL || errno == EPERM || errno == ENOENT) + return 0; + perror("file open"); + goto err; + } + + offset = 0; + for (i = 0; i < BUFFERS; i++) { + int do_fixed = fixed; + + sqe = io_uring_get_sqe(ring); + if (!sqe) { + fprintf(stderr, "sqe get failed\n"); + goto err; + } + if (fixed && (i & 1)) + do_fixed = 0; + if (do_fixed) { + io_uring_prep_read_fixed(sqe, fd, vecs[i].iov_base, + vecs[i].iov_len, offset, i); + } else if (nonvec) { + io_uring_prep_read(sqe, fd, vecs[i].iov_base, + vecs[i].iov_len, offset); + } else { + io_uring_prep_readv(sqe, fd, &vecs[i], 1, offset); + } + sqe->user_data = i; + offset += BS; + } + + ret = io_uring_submit(ring); + if (ret != BUFFERS) { + fprintf(stderr, "submit got %d, wanted %d\n", ret, BUFFERS); + goto err; + } + + for (i = 0; i < BUFFERS; i++) { + ret = io_uring_wait_cqe(ring, &cqe); + if (ret) { + fprintf(stderr, "wait_cqe=%d\n", ret); + goto err; + } + if (cqe->res == -EINVAL && nonvec) { + if (!warned) { + fprintf(stdout, "Non-vectored IO not " + "supported, skipping\n"); + warned = 1; + } + } + io_uring_cqe_seen(ring, cqe); + } + + if (fixed) { + ret = io_uring_unregister_buffers(ring); + if (ret) { + fprintf(stderr, "buffer unreg failed: %d\n", ret); + goto err; + } + } + + close(fd); + return 0; +err: + if (fd != -1) + close(fd); + return 1; +} +static int test_io(const char *file, int fixed, int nonvec) +{ + struct io_uring ring; + int ret, ring_flags = 0; + + ret = t_create_ring(64, &ring, ring_flags); + if (ret == T_SETUP_SKIP) + return 0; + if (ret != T_SETUP_OK) { + fprintf(stderr, "ring create failed: %d\n", ret); + return 1; + } + + ret = __test_io(file, &ring, fixed, nonvec); + io_uring_queue_exit(&ring); + return ret; +} + +static int has_nonvec_read(void) +{ + struct io_uring_probe *p; + struct io_uring ring; + int ret; + + ret = io_uring_queue_init(1, &ring, 0); + if (ret) { + fprintf(stderr, "queue init failed: %d\n", ret); + exit(ret); + } + + p = t_calloc(1, sizeof(*p) + 256 * sizeof(struct io_uring_probe_op)); + ret = io_uring_register_probe(&ring, p, 256); + /* if we don't have PROBE_REGISTER, we don't have OP_READ/WRITE */ + if (ret == -EINVAL) { +out: + io_uring_queue_exit(&ring); + free(p); + return 0; + } else if (ret) { + fprintf(stderr, "register_probe: %d\n", ret); + goto out; + } + + if (p->ops_len <= IORING_OP_READ) + goto out; + if (!(p->ops[IORING_OP_READ].flags & IO_URING_OP_SUPPORTED)) + goto out; + io_uring_queue_exit(&ring); + free(p); + return 1; +} + +int main(int argc, char *argv[]) +{ + int ret, nonvec; + + if (argc > 1) + return T_EXIT_SKIP; + + vecs = t_create_buffers(BUFFERS, BS); + + /* if we don't have nonvec read, skip testing that */ + nonvec = has_nonvec_read(); + + if (nonvec) { + ret = test_io("/proc/kallsyms", 0, 0); + if (ret) + goto err; + } + + ret = test_io("/proc/kallsyms", 0, 1); + if (ret) + goto err; + + if (nonvec) { + ret = test_io("/proc/kallsyms", 1, 0); + if (ret) + goto err; + } + + ret = test_io("/proc/kallsyms", 1, 1); + if (ret) + goto err; + + return 0; +err: + fprintf(stderr, "Reading kallsyms failed\n"); + return 1; +} diff --git a/contrib/libs/liburing/test/kallsyms.t/ya.make b/contrib/libs/liburing/test/kallsyms.t/ya.make new file mode 100644 index 0000000000..03d83ab90c --- /dev/null +++ b/contrib/libs/liburing/test/kallsyms.t/ya.make @@ -0,0 +1,35 @@ +# Generated by devtools/yamaker. + +PROGRAM() + +WITHOUT_LICENSE_TEXTS() + +VERSION(2.8) + +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 + kallsyms.c +) + +END() diff --git a/contrib/libs/liburing/test/lfs-openat-write.t/ya.make b/contrib/libs/liburing/test/lfs-openat-write.t/ya.make index f577ca7b03..ce246ac97a 100644 --- a/contrib/libs/liburing/test/lfs-openat-write.t/ya.make +++ b/contrib/libs/liburing/test/lfs-openat-write.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/lfs-openat.t/ya.make b/contrib/libs/liburing/test/lfs-openat.t/ya.make index f0bc0c2b73..1e110f9554 100644 --- a/contrib/libs/liburing/test/lfs-openat.t/ya.make +++ b/contrib/libs/liburing/test/lfs-openat.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/link-timeout.c b/contrib/libs/liburing/test/link-timeout.c index c59543c53f..4d4f5d4c69 100644 --- a/contrib/libs/liburing/test/link-timeout.c +++ b/contrib/libs/liburing/test/link-timeout.c @@ -11,6 +11,7 @@ #include <string.h> #include <fcntl.h> #include <poll.h> +#include <sys/time.h> #include "liburing.h" #include "helpers.h" @@ -538,6 +539,139 @@ err: return 1; } +static int test_link_timeout_update(struct io_uring *ring, int async) +{ + struct __kernel_timespec ts; + struct io_uring_cqe *cqe; + struct io_uring_sqe *sqe; + struct timeval start; + unsigned long msec; + int fds[2], ret, i; + struct iovec iov; + char buffer[128]; + + if (pipe(fds)) { + perror("pipe"); + return 1; + } + + sqe = io_uring_get_sqe(ring); + if (!sqe) { + printf("get sqe failed\n"); + goto err; + } + iov.iov_base = buffer; + iov.iov_len = sizeof(buffer); + io_uring_prep_readv(sqe, fds[0], &iov, 1, 0); + sqe->flags |= IOSQE_IO_LINK; + sqe->user_data = 1; + + sqe = io_uring_get_sqe(ring); + if (!sqe) { + printf("get sqe failed\n"); + goto err; + } + ts.tv_sec = 5; + ts.tv_nsec = 0; + io_uring_prep_link_timeout(sqe, &ts, 0); + sqe->user_data = 2; + + ret = io_uring_submit(ring); + if (ret != 2) { + printf("sqe submit failed: %d\n", ret); + goto err; + } + + ts.tv_sec = 0; + ts.tv_nsec = 100000000LL; + sqe = io_uring_get_sqe(ring); + io_uring_prep_timeout_update(sqe, &ts, 2, IORING_LINK_TIMEOUT_UPDATE); + if (async) + sqe->flags |= IOSQE_ASYNC; + sqe->user_data = 3; + + io_uring_submit(ring); + + gettimeofday(&start, NULL); + for (i = 0; i < 3; i++) { + ret = io_uring_wait_cqe(ring, &cqe); + if (ret < 0) { + printf("wait completion %d\n", ret); + goto err; + } + switch (cqe->user_data) { + case 1: + if (cqe->res != -EINTR && cqe->res != -ECANCELED) { + fprintf(stderr, "Req %" PRIu64 " got %d\n", (uint64_t) cqe->user_data, + cqe->res); + goto err; + } + break; + case 2: + /* FASTPOLL kernels can cancel successfully */ + if (cqe->res != -EALREADY && cqe->res != -ETIME) { + fprintf(stderr, "Req %" PRIu64 " got %d\n", (uint64_t) cqe->user_data, + cqe->res); + goto err; + } + break; + case 3: + if (cqe->res) { + fprintf(stderr, "Req %" PRIu64 " got %d\n", (uint64_t) cqe->user_data, + cqe->res); + goto err; + } + break; + } + + io_uring_cqe_seen(ring, cqe); + } + + msec = mtime_since_now(&start); + if (msec < 10 || msec > 200) { + fprintf(stderr, "Timeout appears incorrect: %lu\n", msec); + goto err; + } + + close(fds[0]); + close(fds[1]); + return 0; +err: + return 1; +} + +static int test_link_timeout_update_invalid(struct io_uring *ring, int async) +{ + struct __kernel_timespec ts; + struct io_uring_cqe *cqe; + struct io_uring_sqe *sqe; + int ret; + + ts.tv_sec = 0; + ts.tv_nsec = 100000000LL; + sqe = io_uring_get_sqe(ring); + io_uring_prep_timeout_update(sqe, &ts, 2, IORING_LINK_TIMEOUT_UPDATE); + sqe->user_data = 0xcafe0000; + if (async) + sqe->flags |= IOSQE_ASYNC; + + io_uring_submit(ring); + + ret = io_uring_wait_cqe(ring, &cqe); + if (ret < 0) { + printf("wait completion %d\n", ret); + goto err; + } + if (cqe->res != -ENOENT) { + fprintf(stderr, "bad timeout update: %d\n", cqe->res); + goto err; + } + io_uring_cqe_seen(ring, cqe); + return 0; +err: + return 1; +} + static int test_timeout_link_chain1(struct io_uring *ring) { struct __kernel_timespec ts; @@ -1105,5 +1239,30 @@ int main(int argc, char *argv[]) return ret; } + ret = test_link_timeout_update(&ring, 0); + if (ret) { + printf("test_link_timeout_update 0 failed\n"); + return ret; + } + + ret = test_link_timeout_update(&ring, 1); + if (ret) { + printf("test_link_timeout_update 1 failed\n"); + return ret; + } + + ret = test_link_timeout_update_invalid(&ring, 0); + if (ret) { + printf("test_link_timeout_update_invalid 0 failed\n"); + return ret; + } + + ret = test_link_timeout_update_invalid(&ring, 1); + if (ret) { + printf("test_link_timeout_update_invalid 1 failed\n"); + return ret; + } + + return T_EXIT_PASS; } diff --git a/contrib/libs/liburing/test/link-timeout.t/ya.make b/contrib/libs/liburing/test/link-timeout.t/ya.make index 31f04f1799..947a3f1e2c 100644 --- a/contrib/libs/liburing/test/link-timeout.t/ya.make +++ b/contrib/libs/liburing/test/link-timeout.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/link.t/ya.make b/contrib/libs/liburing/test/link.t/ya.make index 31a9afdcfc..783e8bed46 100644 --- a/contrib/libs/liburing/test/link.t/ya.make +++ b/contrib/libs/liburing/test/link.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/link_drain.t/ya.make b/contrib/libs/liburing/test/link_drain.t/ya.make index 8951552fda..3f1d96ca1a 100644 --- a/contrib/libs/liburing/test/link_drain.t/ya.make +++ b/contrib/libs/liburing/test/link_drain.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/linked-defer-close.c b/contrib/libs/liburing/test/linked-defer-close.c new file mode 100644 index 0000000000..600887398f --- /dev/null +++ b/contrib/libs/liburing/test/linked-defer-close.c @@ -0,0 +1,225 @@ +#include "../config-host.h" +/* SPDX-License-Identifier: MIT */ +/* + * Test that the final close of a file does indeed get it closed, if the + * ring is setup with DEFER_TASKRUN and the task is waiting in cqring_wait() + * during. Also see: + * + * https://github.com/axboe/liburing/issues/1235 + * + * for a bug report, and the zig code on which this test program is based. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <arpa/inet.h> +#include <sys/socket.h> +#include <signal.h> +#include <pthread.h> + +#include "liburing.h" +#include "helpers.h" + +enum { + IS_ACCEPT = 0, + IS_SEND = 0x100, + IS_SEND2 = 0x101, + IS_SEND3 = 0x102, + IS_CLOSE = 0x200, +}; + +struct thread_data { + int parent_pid; +}; + +static void *thread_fn(void *__data) +{ + struct thread_data *data = __data; + struct sockaddr_in saddr; + int sockfd, ret; + char msg[64]; + + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_port = htons(9999); + inet_pton(AF_INET, "127.0.0.1", &saddr.sin_addr); + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + perror("socket"); + goto done; + } + + ret = connect(sockfd, (struct sockaddr *) &saddr, sizeof(saddr)); + if (ret < 0) { + perror("connect"); + close(sockfd); + goto done; + } + + do { + memset(msg, 0, sizeof(msg)); + ret = recv(sockfd, msg, sizeof(msg), 0); + } while (ret > 0); + + close(sockfd); +done: + kill(data->parent_pid, SIGUSR1); + return NULL; +} + +/* we got SIGUSR1, exit normally */ +static void sig_usr1(int sig) +{ + exit(T_EXIT_PASS); +} + +/* timed out, failure */ +static void sig_timeout(int sig) +{ + exit(T_EXIT_FAIL); +} + +int main(int argc, char *argv[]) +{ + struct io_uring ring; + struct io_uring_sqe *sqe; + struct io_uring_cqe *cqe; + struct sockaddr_in saddr; + char *msg1 = "message number 1\n"; + char *msg2 = "message number 2\n"; + char *msg3 = "message number 3\n"; + int val, send_fd, ret, sockfd; + struct sigaction act[2] = { }; + struct thread_data td; + pthread_t thread; + + if (argc > 1) + return T_EXIT_SKIP; + + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_addr.s_addr = htonl(INADDR_ANY); + saddr.sin_port = htons(9999); + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + perror("socket"); + return T_EXIT_FAIL; + } + + val = 1; + setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val)); + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); + + ret = bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)); + if (ret < 0) { + perror("bind"); + close(sockfd); + return T_EXIT_FAIL; + } + + ret = listen(sockfd, 1); + if (ret < 0) { + perror("listen"); + close(sockfd); + return T_EXIT_FAIL; + } + + ret = io_uring_queue_init(8, &ring, IORING_SETUP_SINGLE_ISSUER | + IORING_SETUP_DEFER_TASKRUN); + if (ret == -EINVAL) { + close(sockfd); + return T_EXIT_SKIP; + } + + sqe = io_uring_get_sqe(&ring); + io_uring_prep_multishot_accept(sqe, sockfd, NULL, NULL, 0); + sqe->user_data = IS_ACCEPT; + io_uring_submit(&ring); + + /* check for no multishot accept */ + ret = io_uring_peek_cqe(&ring, &cqe); + if (!ret && cqe->res == -EINVAL) { + close(sockfd); + return T_EXIT_SKIP; + } + + /* expected exit */ + act[0].sa_handler = sig_usr1; + sigaction(SIGUSR1, &act[0], NULL); + + /* if this hits, we have failed */ + act[1].sa_handler = sig_timeout; + sigaction(SIGALRM, &act[1], NULL); + alarm(5); + + /* start receiver */ + td.parent_pid = getpid(); + pthread_create(&thread, NULL, thread_fn, &td); + + do { + ret = io_uring_submit_and_wait(&ring, 1); + if (ret < 0) { + fprintf(stderr, "submit: %d\n", ret); + return T_EXIT_FAIL; + } + ret = io_uring_peek_cqe(&ring, &cqe); + if (ret) { + fprintf(stderr, "peek: %d\n", ret); + return T_EXIT_FAIL; + } + + switch (cqe->user_data) { + case IS_ACCEPT: + send_fd = cqe->res; + io_uring_cqe_seen(&ring, cqe); + + /* + * prep two sends, with the 2nd linked to a close + * operation. Once the close has been completed, that + * will terminate the receiving thread and that will + * in turn send this task a SIGUSR1 signal. If the + * kernel is buggy, then we never get SIGUSR1 and we + * will sit forever waiting and be timed out. + */ + sqe = io_uring_get_sqe(&ring); + io_uring_prep_send(sqe, send_fd, msg1, strlen(msg1), 0); + sqe->user_data = IS_SEND; + sqe->flags = IOSQE_CQE_SKIP_SUCCESS | IOSQE_IO_LINK; + + sqe = io_uring_get_sqe(&ring); + io_uring_prep_send(sqe, send_fd, msg2, strlen(msg2), 0); + sqe->user_data = IS_SEND2; + sqe->flags = IOSQE_CQE_SKIP_SUCCESS | IOSQE_IO_LINK; + + sqe = io_uring_get_sqe(&ring); + io_uring_prep_send(sqe, send_fd, msg3, strlen(msg3), 0); + sqe->user_data = IS_SEND3; + sqe->flags = IOSQE_CQE_SKIP_SUCCESS | IOSQE_IO_LINK; + + sqe = io_uring_get_sqe(&ring); + io_uring_prep_close(sqe, send_fd); + sqe->user_data = IS_CLOSE; + sqe->flags = IOSQE_CQE_SKIP_SUCCESS; + break; + case IS_SEND: + case IS_SEND2: + fprintf(stderr, "Should not see send response\n"); + io_uring_cqe_seen(&ring, cqe); + return T_EXIT_FAIL; + case IS_CLOSE: + fprintf(stderr, "Should not see close response\n"); + io_uring_cqe_seen(&ring, cqe); + return T_EXIT_FAIL; + default: + fprintf(stderr, "got unknown cqe\n"); + return T_EXIT_FAIL; + } + } while (1); + + /* will never get here */ + return T_EXIT_FAIL; +} diff --git a/contrib/libs/liburing/test/linked-defer-close.t/ya.make b/contrib/libs/liburing/test/linked-defer-close.t/ya.make new file mode 100644 index 0000000000..810d4104ea --- /dev/null +++ b/contrib/libs/liburing/test/linked-defer-close.t/ya.make @@ -0,0 +1,35 @@ +# Generated by devtools/yamaker. + +PROGRAM() + +WITHOUT_LICENSE_TEXTS() + +VERSION(2.8) + +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 + linked-defer-close.c +) + +END() diff --git a/contrib/libs/liburing/test/madvise.c b/contrib/libs/liburing/test/madvise.c index 20c452c4a6..a6dc23a858 100644 --- a/contrib/libs/liburing/test/madvise.c +++ b/contrib/libs/liburing/test/madvise.c @@ -21,30 +21,6 @@ #define LOOPS 100 #define MIN_LOOPS 10 -static unsigned long long utime_since(const struct timeval *s, - const struct timeval *e) -{ - long long sec, usec; - - sec = e->tv_sec - s->tv_sec; - usec = (e->tv_usec - s->tv_usec); - if (sec > 0 && usec < 0) { - sec--; - usec += 1000000; - } - - sec *= 1000000; - return sec + usec; -} - -static unsigned long long utime_since_now(struct timeval *tv) -{ - struct timeval end; - - gettimeofday(&end, NULL); - return utime_since(tv, &end); -} - static int do_madvise(struct io_uring *ring, void *addr, off_t len, int advice) { struct io_uring_sqe *sqe; @@ -101,6 +77,8 @@ static int test_madvise(struct io_uring *ring, const char *filename) fd = open(filename, O_RDONLY); if (fd < 0) { + if (errno == EACCES || errno == EPERM) + return T_EXIT_SKIP; perror("open"); return 1; } @@ -144,9 +122,12 @@ static int test_madvise(struct io_uring *ring, const char *filename) return 1; if (cached_read < uncached_read && - cached_read2 < uncached_read) + cached_read2 < uncached_read) { + free(buf); return 0; + } + free(buf); return 2; } @@ -171,6 +152,8 @@ int main(int argc, char *argv[]) good = bad = 0; for (i = 0; i < LOOPS; i++) { ret = test_madvise(&ring, fname); + if (ret == T_EXIT_SKIP) + goto skip; if (ret == 1) { fprintf(stderr, "test_madvise failed\n"); goto err; @@ -193,4 +176,8 @@ err: if (fname != argv[1]) unlink(fname); return T_EXIT_FAIL; +skip: + if (fname != argv[1]) + unlink(fname); + return T_EXIT_SKIP; } diff --git a/contrib/libs/liburing/test/madvise.t/ya.make b/contrib/libs/liburing/test/madvise.t/ya.make index d0ac4fdc9f..d007a067eb 100644 --- a/contrib/libs/liburing/test/madvise.t/ya.make +++ b/contrib/libs/liburing/test/madvise.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/min-timeout-wait.c b/contrib/libs/liburing/test/min-timeout-wait.c new file mode 100644 index 0000000000..217864cdbc --- /dev/null +++ b/contrib/libs/liburing/test/min-timeout-wait.c @@ -0,0 +1,330 @@ +#include "../config-host.h" +/* SPDX-License-Identifier: MIT */ +/* + * Description: run various min_timeout tests + * + */ +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <sys/time.h> +#include <pthread.h> + +#include "liburing.h" +#include "helpers.h" + +struct data { + pthread_barrier_t startup; + unsigned long usec_sleep; + int out_fds[8]; + int nr_fds; +}; + +static int time_pass(struct timeval *start, unsigned long min_t, + unsigned long max_t, const char *name) +{ + unsigned long elapsed; + + elapsed = mtime_since_now(start); + if (elapsed < min_t || elapsed > max_t) { + fprintf(stderr, "%s fails time check\n", name); + fprintf(stderr, " elapsed=%lu, min=%lu, max=%lu\n", elapsed, + min_t, max_t); + return T_EXIT_FAIL; + } + return T_EXIT_PASS; +} + +static void *pipe_write(void *data) +{ + struct data *d = data; + char buf[32]; + int i; + + memset(buf, 0x55, sizeof(buf)); + + pthread_barrier_wait(&d->startup); + + if (d->usec_sleep) + usleep(d->usec_sleep); + + for (i = 0; i < d->nr_fds; i++) { + int ret; + + ret = write(d->out_fds[i], buf, sizeof(buf)); + if (ret < 0) { + perror("write"); + return NULL; + } + } + + return NULL; +} + +static int __test_writes(struct io_uring *ring, int npipes, int usec_sleep, + int usec_wait, int min_t, int max_t, const char *name) +{ + struct __kernel_timespec ts; + struct io_uring_cqe *cqe; + struct io_uring_sqe *sqe; + struct timeval tv; + int ret, i, fds[4][2]; + pthread_t thread; + struct data d; + char buf[32]; + void *tret; + + for (i = 0; i < npipes; i++) { + if (pipe(fds[i]) < 0) { + perror("pipe"); + return T_EXIT_FAIL; + } + d.out_fds[i] = fds[i][1]; + } + d.nr_fds = npipes; + + pthread_barrier_init(&d.startup, NULL, 2); + d.usec_sleep = usec_sleep; + + pthread_create(&thread, NULL, pipe_write, &d); + pthread_barrier_wait(&d.startup); + + for (i = 0; i < npipes; i++) { + sqe = io_uring_get_sqe(ring); + io_uring_prep_read(sqe, fds[i][0], buf, sizeof(buf), 0); + } + + io_uring_submit(ring); + + ts.tv_sec = 1; + ts.tv_nsec = 0; + gettimeofday(&tv, NULL); + ret = io_uring_wait_cqes_min_timeout(ring, &cqe, 4, &ts, usec_wait, NULL); + if (ret) { + fprintf(stderr, "wait_cqes: %d\n", ret); + return T_EXIT_FAIL; + } + + ret = time_pass(&tv, min_t, max_t, name); + + io_uring_cq_advance(ring, npipes); + + pthread_join(thread, &tret); + for (i = 0; i < npipes; i++) { + close(fds[i][0]); + close(fds[i][1]); + } + return ret; +} +/* + * Test doing min_wait for N events, where 0 events are already available + * on wait enter but N/2 are posted within the min_wait window. We'll expect to + * return when the min_wait window expires. + */ +static int test_some_wait(struct io_uring *ring) +{ + return __test_writes(ring, 2, 1000, 100000, 95, 120, __FUNCTION__); +} + +/* + * Test doing min_wait for N events, where 0 events are already available + * on wait enter but N are posted within the min_wait window. We'll expect to + * return upon arrival of the N events, not the full min_wait window. + */ +static int test_post_wait(struct io_uring *ring) +{ + return __test_writes(ring, 4, 10000, 200000, 9, 12, __FUNCTION__); +} + +/* + * Test doing min_wait for N events, where 0 events are already available + * on wait enter and one is posted after the min_wait timeout has expired. + * That first event should cause wait to abort, even if the task has asked + * for more to wait on. + */ +static int test_late(struct io_uring *ring) +{ + return __test_writes(ring, 1, 100000, 10000, 95, 120, __FUNCTION__); +} + +static int __test_nop(struct io_uring *ring, int nr_nops, int min_t, int max_t, + unsigned long long_wait, const char *name) +{ + struct __kernel_timespec ts; + struct io_uring_cqe *cqe; + struct timeval tv; + int i, ret; + + for (i = 0; i < nr_nops; i++) { + struct io_uring_sqe *sqe; + + sqe = io_uring_get_sqe(ring); + io_uring_prep_nop(sqe); + } + + if (nr_nops) + io_uring_submit(ring); + + ts.tv_sec = 0; + ts.tv_nsec = long_wait * 1000; + gettimeofday(&tv, NULL); + ret = io_uring_wait_cqes_min_timeout(ring, &cqe, 4, &ts, 50000, NULL); + io_uring_cq_advance(ring, nr_nops); + if (nr_nops) { + if (ret) { + fprintf(stderr, "wait_cqes: %d\n", ret); + return T_EXIT_FAIL; + } + } else { + if (ret != -ETIME) { + fprintf(stderr, "wait_cqes: %d\n", ret); + return T_EXIT_FAIL; + } + } + + return time_pass(&tv, min_t, max_t, name); +} + +/* + * Test doing min_wait for N events, where N/2 events are already available + * on wait enter. This should abort waiting after min_wait, not do the full + * wait. + */ +static int test_some(struct io_uring *ring) +{ + return __test_nop(ring, 2, 45, 55, 100000, __FUNCTION__); +} + +/* + * Test doing min_wait for N events, where N events are already available + * on wait enter. + */ +static int test_already(struct io_uring *ring) +{ + return __test_nop(ring, 4, 0, 1, 100000, __FUNCTION__); +} + +/* + * Test doing min_wait for N events, and nothing ever gets posted. We'd + * expect the time to be the normal wait time, not the min_wait time. + */ +static int test_nothing(struct io_uring *ring) +{ + return __test_nop(ring, 0, 95, 110, 100000, __FUNCTION__); +} + +/* + * Test doing min_wait for N events, and nothing ever gets posted, and use + * a min_wait time that's bigger than the total wait. We only expect the + * min_wait to elapse. + */ +static int test_min_wait_biggest(struct io_uring *ring) +{ + return __test_nop(ring, 0, 45, 55, 20000, __FUNCTION__); +} + +/* + * Test doing min_wait for N events, and nothing ever gets posted, and use + * a min_wait time that's roughly equal to the total wait. We only expect the + * min_wait to elapse. + */ +static int test_min_wait_equal(struct io_uring *ring) +{ + return __test_nop(ring, 0, 45, 55, 50001, __FUNCTION__); +} + +int main(int argc, char *argv[]) +{ + struct io_uring ring1, ring2; + struct io_uring_params p = { }; + int ret; + + if (argc > 1) + return 0; + + ret = t_create_ring_params(8, &ring1, &p); + if (ret == T_SETUP_SKIP) + return T_EXIT_SKIP; + else if (ret != T_SETUP_OK) + return ret; + if (!(p.features & IORING_FEAT_MIN_TIMEOUT)) + return T_EXIT_SKIP; + + p.flags = IORING_SETUP_SINGLE_ISSUER|IORING_SETUP_DEFER_TASKRUN; + ret = t_create_ring_params(8, &ring2, &p); + if (ret == T_SETUP_SKIP) + return T_EXIT_SKIP; + else if (ret != T_SETUP_OK) + return ret; + + ret = test_already(&ring1); + if (ret == T_EXIT_FAIL || ret == T_EXIT_SKIP) + return ret; + + ret = test_already(&ring2); + if (ret == T_EXIT_FAIL) + return T_EXIT_FAIL; + + ret = test_some(&ring1); + if (ret == T_EXIT_FAIL || ret == T_EXIT_SKIP) + return ret; + + ret = test_some(&ring2); + if (ret == T_EXIT_FAIL) + return T_EXIT_FAIL; + + ret = test_late(&ring1); + if (ret == T_EXIT_FAIL || ret == T_EXIT_SKIP) + return ret; + + ret = test_late(&ring2); + if (ret == T_EXIT_FAIL) + return T_EXIT_FAIL; + + ret = test_post_wait(&ring1); + if (ret == T_EXIT_FAIL || ret == T_EXIT_SKIP) + return ret; + + ret = test_post_wait(&ring2); + if (ret == T_EXIT_FAIL) + return T_EXIT_FAIL; + + ret = test_some_wait(&ring1); + if (ret == T_EXIT_FAIL || ret == T_EXIT_SKIP) + return ret; + + ret = test_some_wait(&ring2); + if (ret == T_EXIT_FAIL) + return T_EXIT_FAIL; + + ret = test_nothing(&ring1); + if (ret == T_EXIT_FAIL || ret == T_EXIT_SKIP) + return ret; + + ret = test_nothing(&ring2); + if (ret == T_EXIT_FAIL) + return T_EXIT_FAIL; + + ret = test_min_wait_biggest(&ring1); + if (ret == T_EXIT_FAIL || ret == T_EXIT_SKIP) + return ret; + + ret = test_min_wait_biggest(&ring2); + if (ret == T_EXIT_FAIL) + return T_EXIT_FAIL; + + ret = test_min_wait_equal(&ring1); + if (ret == T_EXIT_FAIL || ret == T_EXIT_SKIP) + return ret; + + ret = test_min_wait_equal(&ring2); + if (ret == T_EXIT_FAIL) + return T_EXIT_FAIL; + + io_uring_queue_exit(&ring1); + io_uring_queue_exit(&ring2); + return T_EXIT_PASS; +} diff --git a/contrib/libs/liburing/test/min-timeout-wait.t/ya.make b/contrib/libs/liburing/test/min-timeout-wait.t/ya.make new file mode 100644 index 0000000000..ec59ad065d --- /dev/null +++ b/contrib/libs/liburing/test/min-timeout-wait.t/ya.make @@ -0,0 +1,35 @@ +# Generated by devtools/yamaker. + +PROGRAM() + +WITHOUT_LICENSE_TEXTS() + +VERSION(2.8) + +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 + min-timeout-wait.c +) + +END() diff --git a/contrib/libs/liburing/test/min-timeout.c b/contrib/libs/liburing/test/min-timeout.c new file mode 100644 index 0000000000..a5abd6152e --- /dev/null +++ b/contrib/libs/liburing/test/min-timeout.c @@ -0,0 +1,209 @@ +#include "../config-host.h" +/* SPDX-License-Identifier: MIT */ +/* + * Description: test min timeout handling + * + */ +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <sys/resource.h> +#include <sys/time.h> +#include <pthread.h> + +#include "liburing.h" +#include "helpers.h" + +#define NPIPES 8 +#define NWRITES 6 + +#define WAIT_USEC (250000) + +static int no_min_timeout; + +struct d { + int fd[NPIPES]; + long delay; +}; + +static void *thread_fn(void *data) +{ + struct d *d = data; + char buf[32]; + int i; + + memset(buf, 0x55, sizeof(buf)); + + for (i = 0; i < NWRITES; i++) { + int ret; + + usleep(d->delay); + ret = write(d->fd[i], buf, sizeof(buf)); + if (ret != sizeof(buf)) { + fprintf(stderr, "bad write %d\n", ret); + break; + } + } + return NULL; +} + +/* + * Allow 25% tolerance + */ +static int within_range(unsigned int target, unsigned int msec) +{ + unsigned int high, low; + + low = (target * 3) / 4; + high = (target * 5) / 4; + return (msec >= low && msec <= high); +} + +static int test(int flags, int expected_ctx, int min_wait, int write_delay, + int nr_cqes, int msec_target) +{ + struct io_uring_cqe *cqe; + struct io_uring_sqe *sqe; + struct io_uring ring; + struct __kernel_timespec ts; + struct rusage s, e; + pthread_t thread; + struct d d; + struct io_uring_params p = { .flags = flags, }; + int ret, fds[NPIPES][2], i; + struct timeval start_time; + char buf[32]; + void *tret; + long ttime; + + ret = io_uring_queue_init_params(NPIPES, &ring, &p); + if (ret == -EINVAL) + return T_EXIT_SKIP; + if (!(p.features & IORING_FEAT_MIN_TIMEOUT)) { + no_min_timeout = 1; + return T_EXIT_SKIP; + } + + for (i = 0; i < NPIPES; i++) { + if (pipe(fds[i]) < 0) { + perror("pipe"); + return 1; + } + d.fd[i] = fds[i][1]; + } + + d.delay = write_delay; + pthread_create(&thread, NULL, thread_fn, &d); + + for (i = 0; i < NPIPES; i++) { + sqe = io_uring_get_sqe(&ring); + io_uring_prep_read(sqe, fds[i][0], buf, sizeof(buf), 0); + } + + ts.tv_sec = 0; + ts.tv_nsec = WAIT_USEC * 1000LL; + + gettimeofday(&start_time, NULL); + getrusage(RUSAGE_THREAD, &s); + ret = io_uring_submit_and_wait_min_timeout(&ring, &cqe, 8, &ts, min_wait, NULL); + if (ret != NPIPES) + fprintf(stderr, "submit_and_wait=%d\n", ret); + + getrusage(RUSAGE_THREAD, &e); + e.ru_nvcsw -= s.ru_nvcsw; + ttime = mtime_since_now(&start_time); + if (!within_range(msec_target, ttime)) { + fprintf(stderr, "Expected %d msec, got %ld msec\n", msec_target, + ttime); + fprintf(stderr, "flags=%x, min_wait=%d, write_delay=%d\n", + flags, min_wait, write_delay); + } + /* will usually be accurate, but allow for offset of 1 */ + if (e.ru_nvcsw != expected_ctx && + (e.ru_nvcsw - expected_ctx > 1)) + fprintf(stderr, "%ld ctx switches, expected %d\n", e.ru_nvcsw, + expected_ctx); + + for (i = 0; i < NPIPES; i++) { + ret = io_uring_peek_cqe(&ring, &cqe); + if (ret) + break; + io_uring_cqe_seen(&ring, cqe); + } + + if (i != nr_cqes) + fprintf(stderr, "Got %d CQEs, expected %d\n", i, nr_cqes); + + pthread_join(thread, &tret); + + for (i = 0; i < NPIPES; i++) { + close(fds[i][0]); + close(fds[i][1]); + } + + return T_EXIT_PASS; +} + +int main(int argc, char *argv[]) +{ + int ret; + + if (argc > 1) + return T_EXIT_SKIP; + + ret = test(0, NWRITES + 1, 0, 2000, NWRITES, WAIT_USEC / 1000); + if (ret == T_EXIT_FAIL) + return T_EXIT_FAIL; + if (no_min_timeout) + return T_EXIT_SKIP; + + ret = test(0, NWRITES + 1, 50000, 2000, NWRITES, 50); + if (ret == T_EXIT_FAIL) + return T_EXIT_FAIL; + + ret = test(0, NWRITES + 1, 500000, 2000, NWRITES, 500); + if (ret == T_EXIT_FAIL) + return T_EXIT_FAIL; + + /* no writes within min timeout, but it's given. expect 1 cqe */ + ret = test(0, 1, 10000, 20000, 1, 20); + if (ret == T_EXIT_FAIL) + return T_EXIT_FAIL; + + /* same as above, but no min timeout. should time out and we get 6 */ + ret = test(0, NWRITES + 1, 0, 20000, NWRITES, WAIT_USEC / 1000); + if (ret == T_EXIT_FAIL) + return T_EXIT_FAIL; + + ret = test(IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN, 1, + 0, 2000, NWRITES, WAIT_USEC / 1000); + if (ret == T_EXIT_FAIL) + return T_EXIT_FAIL; + + ret = test(IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN, 1, + 50000, 2000, NWRITES, 50); + if (ret == T_EXIT_FAIL) + return T_EXIT_FAIL; + + ret = test(IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN, 1, + 500000, 2000, NWRITES, 500); + if (ret == T_EXIT_FAIL) + return T_EXIT_FAIL; + + /* no writes within min timeout, but it's given. expect 1 cqe */ + ret = test(IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN, 1, + 10000, 20000, 1, 20); + if (ret == T_EXIT_FAIL) + return T_EXIT_FAIL; + + /* same as above, but no min timeout. should time out and we get 6 */ + ret = test(IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN, 1, + 0, 20000, NWRITES, WAIT_USEC / 1000); + if (ret == T_EXIT_FAIL) + return T_EXIT_FAIL; + + return ret; +} diff --git a/contrib/libs/liburing/test/min-timeout.t/ya.make b/contrib/libs/liburing/test/min-timeout.t/ya.make new file mode 100644 index 0000000000..344cff1526 --- /dev/null +++ b/contrib/libs/liburing/test/min-timeout.t/ya.make @@ -0,0 +1,35 @@ +# Generated by devtools/yamaker. + +PROGRAM() + +WITHOUT_LICENSE_TEXTS() + +VERSION(2.8) + +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 + min-timeout.c +) + +END() diff --git a/contrib/libs/liburing/test/mkdir.c b/contrib/libs/liburing/test/mkdir.c index 630672cc93..33e0bea772 100644 --- a/contrib/libs/liburing/test/mkdir.c +++ b/contrib/libs/liburing/test/mkdir.c @@ -98,6 +98,12 @@ int main(int argc, char *argv[]) goto err1; } + ret = do_mkdirat(&ring, (const char *) (uintptr_t) 0x1234); + if (ret != -EFAULT) { + fprintf(stderr, "do_mkdirat bad address: %d\n", ret); + goto err1; + } + unlinkat(AT_FDCWD, fn, AT_REMOVEDIR); io_uring_queue_exit(&ring); return T_EXIT_PASS; diff --git a/contrib/libs/liburing/test/mkdir.t/ya.make b/contrib/libs/liburing/test/mkdir.t/ya.make index 87fefb42d5..2c5a72cd17 100644 --- a/contrib/libs/liburing/test/mkdir.t/ya.make +++ b/contrib/libs/liburing/test/mkdir.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/msg-ring-fd.t/ya.make b/contrib/libs/liburing/test/msg-ring-fd.t/ya.make index e62d69d037..103941320c 100644 --- a/contrib/libs/liburing/test/msg-ring-fd.t/ya.make +++ b/contrib/libs/liburing/test/msg-ring-fd.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/msg-ring-flags.t/ya.make b/contrib/libs/liburing/test/msg-ring-flags.t/ya.make index ba23560940..75337d35df 100644 --- a/contrib/libs/liburing/test/msg-ring-flags.t/ya.make +++ b/contrib/libs/liburing/test/msg-ring-flags.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/msg-ring-overflow.t/ya.make b/contrib/libs/liburing/test/msg-ring-overflow.t/ya.make index cb95daef71..b92b8004e9 100644 --- a/contrib/libs/liburing/test/msg-ring-overflow.t/ya.make +++ b/contrib/libs/liburing/test/msg-ring-overflow.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/msg-ring.c b/contrib/libs/liburing/test/msg-ring.c index 843ba1f8ef..e87ee6d92a 100644 --- a/contrib/libs/liburing/test/msg-ring.c +++ b/contrib/libs/liburing/test/msg-ring.c @@ -310,6 +310,8 @@ static int test_disabled_ring(struct io_uring *ring, int flags) flags |= IORING_SETUP_R_DISABLED; ret = io_uring_queue_init(8, &disabled_ring, flags); if (ret) { + if (ret == -EINVAL) + return T_EXIT_SKIP; fprintf(stderr, "ring setup failed: %d\n", ret); return 1; } @@ -350,6 +352,8 @@ static int test(int ring_flags) ret = io_uring_queue_init(8, &ring, ring_flags); if (ret) { + if (ret == -EINVAL) + return T_EXIT_SKIP; fprintf(stderr, "ring setup failed: %d\n", ret); return T_EXIT_FAIL; } @@ -453,13 +457,15 @@ int main(int argc, char *argv[]) return T_EXIT_SKIP; ret = test(0); - if (ret != T_EXIT_PASS) { + if (ret == T_EXIT_FAIL) { fprintf(stderr, "ring flags 0 failed\n"); return ret; + } else if (ret == T_EXIT_SKIP) { + return T_EXIT_SKIP; } ret = test(IORING_SETUP_SINGLE_ISSUER|IORING_SETUP_DEFER_TASKRUN); - if (ret != T_EXIT_PASS) { + if (ret == T_EXIT_FAIL) { fprintf(stderr, "ring flags defer failed\n"); return ret; } diff --git a/contrib/libs/liburing/test/msg-ring.t/ya.make b/contrib/libs/liburing/test/msg-ring.t/ya.make index a1038229eb..f2c1ed0c82 100644 --- a/contrib/libs/liburing/test/msg-ring.t/ya.make +++ b/contrib/libs/liburing/test/msg-ring.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/multicqes_drain.t/ya.make b/contrib/libs/liburing/test/multicqes_drain.t/ya.make index f14f880b47..604fb73e84 100644 --- a/contrib/libs/liburing/test/multicqes_drain.t/ya.make +++ b/contrib/libs/liburing/test/multicqes_drain.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/napi-test.c b/contrib/libs/liburing/test/napi-test.c new file mode 100644 index 0000000000..00a7204618 --- /dev/null +++ b/contrib/libs/liburing/test/napi-test.c @@ -0,0 +1,229 @@ +#include "../config-host.h" +/* SPDX-License-Identifier: MIT */ +/* + * Description: run NAPI receive test. Meant to be run from the associated + * script, napi-test.sh. That will invoke this test program + * as either a sender or receiver, with the queue flags passed + * in for testing. + * + */ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <arpa/inet.h> +#include <linux/if_packet.h> +#include <linux/socket.h> +#include <sys/socket.h> +#include <sys/stat.h> + +#include "liburing.h" +#include "helpers.h" + +static const char receiver_address[] = "10.10.10.20"; +static const int port = 9999; +#define BUF_SIZE 4096 + +static char buffer[BUF_SIZE]; +static unsigned current_byte = 0; + +static void do_setsockopt(int fd, int level, int optname, int val) +{ + int ret = setsockopt(fd, level, optname, &val, sizeof(val)); + + assert(ret == 0); +} + +static int sender(int queue_flags) +{ + unsigned long long written = 0; + struct sockaddr_in addr; + struct io_uring ring; + int i, ret, fd; + + /* + * Sender doesn't use the ring, but try and set one up with the same + * flags that the receiver will use. If that fails, we know the + * receiver will have failed too - just skip the test in that case. + */ + ret = io_uring_queue_init(1, &ring, queue_flags); + if (ret) + return T_EXIT_SKIP; + io_uring_queue_exit(&ring); + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + ret = inet_pton(AF_INET, receiver_address, &addr.sin_addr); + assert(ret == 1); + + fd = socket(PF_INET, SOCK_STREAM, 0); + assert(fd >= 0); + + /* don't race with receiver, give it 1 second to connect */ + i = 0; + do { + ret = connect(fd, (void *)&addr, sizeof(addr)); + if (!ret) + break; + if (ret == -1 && errno == ECONNREFUSED) { + if (i >= 10000) { + fprintf(stderr, "Gave up trying to connect\n"); + return 1; + } + usleep(100); + continue; + } + i++; + } while (1); + + while (written < 8 * 1024 * 1024) { + for (i = 0; i < BUF_SIZE; i++) + buffer[i] = current_byte + i; + + ret = write(fd, buffer, BUF_SIZE); + if (ret <= 0) { + if (!ret || errno == ECONNRESET) + break; + fprintf(stderr, "write failed %i %i\n", ret, errno); + return 1; + } + written += ret; + current_byte += ret; + } + + close(fd); + return 0; +} + +static int receiver(int queue_flags) +{ + struct io_uring_sqe *sqe; + struct io_uring_cqe *cqe; + struct io_uring ring; + struct io_uring_napi napi = { }; + struct sockaddr_in addr; + int fd, listen_fd; + int i, ret; + + ret = io_uring_queue_init(8, &ring, queue_flags); + if (ret < 0) { + if (ret == -EINVAL) + return T_EXIT_SKIP; + fprintf(stderr, "queue_init: %s\n", strerror(-ret)); + return 1; + } + + napi.prefer_busy_poll = 1; + napi.busy_poll_to = 50; + io_uring_register_napi(&ring, &napi); + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = INADDR_ANY; + + listen_fd = socket(AF_INET, SOCK_STREAM, 0); + assert(listen_fd >= 0); + + do_setsockopt(listen_fd, SOL_SOCKET, SO_REUSEPORT, 1); + ret = bind(listen_fd, (void *)&addr, sizeof(addr)); + if (ret) { + fprintf(stderr, "bind failed %i %i\n", ret, errno); + return 1; + } + + ret = listen(listen_fd, 8); + assert(ret == 0); + + fd = accept(listen_fd, NULL, NULL); + assert(fd >= 0); + + while (1) { + sqe = io_uring_get_sqe(&ring); + io_uring_prep_recv(sqe, fd, buffer, BUF_SIZE, 0); + + ret = io_uring_submit(&ring); + if (ret != 1) { + fprintf(stderr, "io_uring_submit: %i\n", ret); + return 1; + } + + ret = io_uring_wait_cqe(&ring, &cqe); + if (ret < 0) { + fprintf(stderr, "io_uring_wait_cqe: %i\n", ret); + return 1; + } + + ret = cqe->res; + if (ret <= 0) { + if (!ret) + break; + fprintf(stderr, "recv failed %i %i\n", ret, errno); + return 1; + } + + for (i = 0; i < ret; i++) { + char expected = current_byte + i; + + if (buffer[i] != expected) { + fprintf(stderr, "data mismatch: idx %i, %c vs %c\n", + i, buffer[i], expected); + return 1; + } + } + + current_byte += ret; + io_uring_cqe_seen(&ring, cqe); + } + + close(fd); + io_uring_queue_exit(&ring); + return 0; +} + +int main(int argc, char **argv) +{ + int queue_flags; + int is_rx; + + if (geteuid()) { + fprintf(stdout, "NAPI test requires root\n"); + return T_EXIT_SKIP; + } + + if (argc == 1) { + struct stat sb; + + if (!stat("napi-test.sh", &sb)) { + return system("bash napi-test.sh"); + } else if (!stat("test/napi-test.sh", &sb)) { + return system("bash test/napi-test.sh"); + } else { + fprintf(stderr, "Can't find napi-test.sh\n"); + return T_EXIT_SKIP; + } + } else if (argc == 2) { + return T_EXIT_SKIP; + } else if (argc != 3) { + return T_EXIT_SKIP; + } + + if (!strcmp(argv[1], "receive")) + is_rx = 1; + else if (!strcmp(argv[1], "send")) + is_rx = 0; + else + return T_EXIT_FAIL; + + queue_flags = strtoul(argv[2], NULL, 16); + + if (is_rx) + return receiver(queue_flags); + + return sender(queue_flags); +} diff --git a/contrib/libs/liburing/test/napi-test.t/ya.make b/contrib/libs/liburing/test/napi-test.t/ya.make new file mode 100644 index 0000000000..dd4a327f04 --- /dev/null +++ b/contrib/libs/liburing/test/napi-test.t/ya.make @@ -0,0 +1,35 @@ +# Generated by devtools/yamaker. + +PROGRAM() + +WITHOUT_LICENSE_TEXTS() + +VERSION(2.8) + +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 + napi-test.c +) + +END() diff --git a/contrib/libs/liburing/test/no-mmap-inval.c b/contrib/libs/liburing/test/no-mmap-inval.c index 44d3be97d5..1d31688b27 100644 --- a/contrib/libs/liburing/test/no-mmap-inval.c +++ b/contrib/libs/liburing/test/no-mmap-inval.c @@ -33,11 +33,13 @@ int main(int argc, char *argv[]) ret = io_uring_queue_init_params(2, &ring, &p); if (ret == -EINVAL) { /* kernel doesn't support SETUP_NO_MMAP */ + free(addr); return T_EXIT_SKIP; } else if (ret && (ret != -EFAULT && ret != -ENOMEM)) { fprintf(stderr, "Got %d, wanted -EFAULT\n", ret); return T_EXIT_FAIL; } + free(addr); 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 index 9ec20bebad..5b03396796 100644 --- a/contrib/libs/liburing/test/no-mmap-inval.t/ya.make +++ b/contrib/libs/liburing/test/no-mmap-inval.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/nolibc.t/ya.make b/contrib/libs/liburing/test/nolibc.t/ya.make index 7f57ccae4b..17806776d3 100644 --- a/contrib/libs/liburing/test/nolibc.t/ya.make +++ b/contrib/libs/liburing/test/nolibc.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/nop-all-sizes.t/ya.make b/contrib/libs/liburing/test/nop-all-sizes.t/ya.make index 35fc683f9f..5b8e16ec68 100644 --- a/contrib/libs/liburing/test/nop-all-sizes.t/ya.make +++ b/contrib/libs/liburing/test/nop-all-sizes.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/nop.c b/contrib/libs/liburing/test/nop.c index a701b3d8ed..52810a1ae4 100644 --- a/contrib/libs/liburing/test/nop.c +++ b/contrib/libs/liburing/test/nop.c @@ -16,6 +16,45 @@ static int seq; +static int test_nop_inject(struct io_uring *ring, unsigned req_flags) +{ + 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; + } + + io_uring_prep_nop(sqe); + sqe->user_data = ++seq; + sqe->nop_flags = IORING_NOP_INJECT_RESULT; + sqe->flags |= req_flags; + sqe->len = -EFAULT; + + 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; + } + if (cqe->res != -EINVAL && cqe->res != -EFAULT) { + fprintf(stderr, "expected injected result, got %d\n", cqe->res); + goto err; + } + io_uring_cqe_seen(ring, cqe); + return 0; +err: + return 1; +} + static int test_single_nop(struct io_uring *ring, unsigned req_flags) { struct io_uring_cqe *cqe; @@ -152,6 +191,11 @@ static int test_ring(unsigned flags) fprintf(stderr, "test_barrier_nop failed\n"); goto err; } + ret = test_nop_inject(&ring, req_flags); + if (ret) { + fprintf(stderr, "test_nop_inject failed\n"); + goto err; + } } err: io_uring_queue_exit(&ring); diff --git a/contrib/libs/liburing/test/nop.t/ya.make b/contrib/libs/liburing/test/nop.t/ya.make index df373fd678..71170256b6 100644 --- a/contrib/libs/liburing/test/nop.t/ya.make +++ b/contrib/libs/liburing/test/nop.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/ooo-file-unreg.c b/contrib/libs/liburing/test/ooo-file-unreg.c index ee5faaf4f8..90f5375cfe 100644 --- a/contrib/libs/liburing/test/ooo-file-unreg.c +++ b/contrib/libs/liburing/test/ooo-file-unreg.c @@ -10,7 +10,7 @@ #include <sys/socket.h> #include <unistd.h> #include <stdlib.h> -#include <sys/poll.h> +#include <poll.h> #include "liburing.h" #include "helpers.h" diff --git a/contrib/libs/liburing/test/ooo-file-unreg.t/ya.make b/contrib/libs/liburing/test/ooo-file-unreg.t/ya.make index 8df08c00b9..1e28dabbaa 100644 --- a/contrib/libs/liburing/test/ooo-file-unreg.t/ya.make +++ b/contrib/libs/liburing/test/ooo-file-unreg.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/open-close.c b/contrib/libs/liburing/test/open-close.c index 6b236e463a..bca8475f6d 100644 --- a/contrib/libs/liburing/test/open-close.c +++ b/contrib/libs/liburing/test/open-close.c @@ -36,6 +36,36 @@ static int submit_wait(struct io_uring *ring) return ret; } +static int test_close_flush(void) +{ + struct io_uring ring; + struct io_uring_sqe *sqe; + char buf[128]; + int ret, fd; + + sprintf(buf, "/sys/kernel/debug/tracing/per_cpu/cpu0/trace_pipe_raw"); + fd = open(buf, O_RDONLY); + if (fd < 0) + return 0; + + ret = io_uring_queue_init(8, &ring, 0); + if (ret) { + fprintf(stderr, "ring setup failed\n"); + return -1; + } + + sqe = io_uring_get_sqe(&ring); + io_uring_prep_close(sqe, fd); + ret = submit_wait(&ring); + if (ret) { + fprintf(stderr, "closefailed %i\n", ret); + return -1; + } + + io_uring_queue_exit(&ring); + return 0; +} + static inline int try_close(struct io_uring *ring, int fd, int slot) { struct io_uring_sqe *sqe; @@ -221,12 +251,16 @@ int main(int argc, char *argv[]) fprintf(stdout, "Open not supported, skipping\n"); goto done; } + if (ret == -EPERM || ret == -EACCES) + return T_EXIT_SKIP; fprintf(stderr, "test_openat absolute failed: %d\n", ret); goto err; } ret = test_openat(&ring, path_rel, AT_FDCWD); if (ret < 0) { + if (ret == -EPERM || ret == -EACCES) + return T_EXIT_SKIP; fprintf(stderr, "test_openat relative failed: %d\n", ret); goto err; } @@ -249,6 +283,12 @@ int main(int argc, char *argv[]) goto err; } + ret = test_close_flush(); + if (ret) { + fprintf(stderr, "test_close_flush failed\n"); + goto err; + } + done: unlink(path); if (do_unlink) diff --git a/contrib/libs/liburing/test/open-close.t/ya.make b/contrib/libs/liburing/test/open-close.t/ya.make index 1c96f6a744..306ecf4323 100644 --- a/contrib/libs/liburing/test/open-close.t/ya.make +++ b/contrib/libs/liburing/test/open-close.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/open-direct-link.t/ya.make b/contrib/libs/liburing/test/open-direct-link.t/ya.make index a526297eca..ef284c507a 100644 --- a/contrib/libs/liburing/test/open-direct-link.t/ya.make +++ b/contrib/libs/liburing/test/open-direct-link.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/open-direct-pick.t/ya.make b/contrib/libs/liburing/test/open-direct-pick.t/ya.make index 385643a111..2c3e6f496f 100644 --- a/contrib/libs/liburing/test/open-direct-pick.t/ya.make +++ b/contrib/libs/liburing/test/open-direct-pick.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/openat2.c b/contrib/libs/liburing/test/openat2.c index 5206b73f3a..833026d31c 100644 --- a/contrib/libs/liburing/test/openat2.c +++ b/contrib/libs/liburing/test/openat2.c @@ -16,25 +16,32 @@ #include "liburing.h" static int test_openat2(struct io_uring *ring, const char *path, int dfd, - bool direct, int fixed_index) + bool direct, int fixed_index, int bad_how) { struct io_uring_cqe *cqe; struct io_uring_sqe *sqe; - struct open_how how; + struct open_how __how, *how; int ret; + if (bad_how) + how = (struct open_how *) (uintptr_t) 0x1234; + else + how = &__how; + sqe = io_uring_get_sqe(ring); if (!sqe) { fprintf(stderr, "get sqe failed\n"); return -1; } - memset(&how, 0, sizeof(how)); - how.flags = O_RDWR; + if (!bad_how) { + memset(how, 0, sizeof(*how)); + how->flags = O_RDWR; + } if (!direct) - io_uring_prep_openat2(sqe, dfd, path, &how); + io_uring_prep_openat2(sqe, dfd, path, how); else - io_uring_prep_openat2_direct(sqe, dfd, path, &how, fixed_index); + io_uring_prep_openat2_direct(sqe, dfd, path, how, fixed_index); ret = io_uring_submit(ring); if (ret <= 0) { @@ -79,7 +86,7 @@ static int test_open_fixed(const char *path, int dfd) return -1; } - ret = test_openat2(&ring, path, dfd, true, 0); + ret = test_openat2(&ring, path, dfd, true, 0, 0); if (ret == -EINVAL) { printf("fixed open isn't supported\n"); return 1; @@ -136,7 +143,7 @@ static int test_open_fixed_fail(const char *path, int dfd) return -1; } - ret = test_openat2(&ring, path, dfd, true, 0); + ret = test_openat2(&ring, path, dfd, true, 0, 0); if (ret != -ENXIO) { fprintf(stderr, "install into not existing table, %i\n", ret); return 1; @@ -150,19 +157,19 @@ static int test_open_fixed_fail(const char *path, int dfd) return -1; } - ret = test_openat2(&ring, path, dfd, true, 1); + ret = test_openat2(&ring, path, dfd, true, 1, 0); if (ret != -EINVAL) { fprintf(stderr, "install out of bounds, %i\n", ret); return -1; } - ret = test_openat2(&ring, path, dfd, true, (1u << 16)); + ret = test_openat2(&ring, path, dfd, true, (1u << 16), 0); if (ret != -EINVAL) { fprintf(stderr, "install out of bounds or u16 overflow, %i\n", ret); return -1; } - ret = test_openat2(&ring, path, dfd, true, (1u << 16) + 1); + ret = test_openat2(&ring, path, dfd, true, (1u << 16) + 1, 0); if (ret != -EINVAL) { fprintf(stderr, "install out of bounds or u16 overflow, %i\n", ret); return -1; @@ -197,7 +204,7 @@ static int test_direct_reinstall(const char *path, int dfd) } /* reinstall into the second slot */ - ret = test_openat2(&ring, path, dfd, true, 1); + ret = test_openat2(&ring, path, dfd, true, 1, 0); if (ret != 0) { fprintf(stderr, "reinstall failed, %i\n", ret); return -1; @@ -265,18 +272,22 @@ int main(int argc, char *argv[]) if (do_unlink) t_create_file(path_rel, 4096); - ret = test_openat2(&ring, path, -1, false, 0); + ret = test_openat2(&ring, path, -1, false, 0, 0); if (ret < 0) { if (ret == -EINVAL) { fprintf(stdout, "openat2 not supported, skipping\n"); goto done; } + if (ret == -EPERM || ret == -EACCES) + return T_EXIT_SKIP; fprintf(stderr, "test_openat2 absolute failed: %d\n", ret); goto err; } - ret = test_openat2(&ring, path_rel, AT_FDCWD, false, 0); + ret = test_openat2(&ring, path_rel, AT_FDCWD, false, 0, 0); if (ret < 0) { + if (ret == -EPERM || ret == -EACCES) + return T_EXIT_SKIP; fprintf(stderr, "test_openat2 relative failed: %d\n", ret); goto err; } @@ -300,6 +311,18 @@ int main(int argc, char *argv[]) goto err; } + ret = test_openat2(&ring, (const char *) (uintptr_t) 0x1234, AT_FDCWD, false, 0, 0); + if (ret != -EFAULT) { + fprintf(stderr, "test_openat2 bad address failed: %d\n", ret); + goto err; + } + + ret = test_openat2(&ring, path_rel, AT_FDCWD, false, 0, 1); + if (ret != -EFAULT) { + fprintf(stderr, "test_openat2 bad how failed: %d\n", ret); + goto err; + } + done: unlink(path); if (do_unlink) diff --git a/contrib/libs/liburing/test/openat2.t/ya.make b/contrib/libs/liburing/test/openat2.t/ya.make index b7c98e6e2e..f6755732e2 100644 --- a/contrib/libs/liburing/test/openat2.t/ya.make +++ b/contrib/libs/liburing/test/openat2.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/personality.t/ya.make b/contrib/libs/liburing/test/personality.t/ya.make index 5d2750936e..3a58beb172 100644 --- a/contrib/libs/liburing/test/personality.t/ya.make +++ b/contrib/libs/liburing/test/personality.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/pipe-bug.t/ya.make b/contrib/libs/liburing/test/pipe-bug.t/ya.make index b4a71cf37e..8b44cb7a62 100644 --- a/contrib/libs/liburing/test/pipe-bug.t/ya.make +++ b/contrib/libs/liburing/test/pipe-bug.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/pipe-eof.t/ya.make b/contrib/libs/liburing/test/pipe-eof.t/ya.make index b53c087814..27e716bc4f 100644 --- a/contrib/libs/liburing/test/pipe-eof.t/ya.make +++ b/contrib/libs/liburing/test/pipe-eof.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/pipe-reuse.t/ya.make b/contrib/libs/liburing/test/pipe-reuse.t/ya.make index f393155c37..cb99dbb937 100644 --- a/contrib/libs/liburing/test/pipe-reuse.t/ya.make +++ b/contrib/libs/liburing/test/pipe-reuse.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/poll-cancel-all.t/ya.make b/contrib/libs/liburing/test/poll-cancel-all.t/ya.make index d868fa9fb5..817d72989f 100644 --- a/contrib/libs/liburing/test/poll-cancel-all.t/ya.make +++ b/contrib/libs/liburing/test/poll-cancel-all.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/poll-cancel-ton.t/ya.make b/contrib/libs/liburing/test/poll-cancel-ton.t/ya.make index 254f5d774b..967cf70af1 100644 --- a/contrib/libs/liburing/test/poll-cancel-ton.t/ya.make +++ b/contrib/libs/liburing/test/poll-cancel-ton.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/poll-cancel.t/ya.make b/contrib/libs/liburing/test/poll-cancel.t/ya.make index 7f35cc137e..bb71bf99a0 100644 --- a/contrib/libs/liburing/test/poll-cancel.t/ya.make +++ b/contrib/libs/liburing/test/poll-cancel.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/poll-link.t/ya.make b/contrib/libs/liburing/test/poll-link.t/ya.make index 9d6b445155..9e13c1959f 100644 --- a/contrib/libs/liburing/test/poll-link.t/ya.make +++ b/contrib/libs/liburing/test/poll-link.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/poll-many.c b/contrib/libs/liburing/test/poll-many.c index fb00cf6327..12be9d8568 100644 --- a/contrib/libs/liburing/test/poll-many.c +++ b/contrib/libs/liburing/test/poll-many.c @@ -23,6 +23,8 @@ #define RING_SIZE 512 +static int nfiles = NFILES; + struct p { int fd[2]; int triggered; @@ -92,7 +94,7 @@ static int trigger_polls(void) int off; do { - off = rand() % NFILES; + off = rand() % nfiles; if (!p[off].triggered) break; } while (1); @@ -110,7 +112,7 @@ static int trigger_polls(void) static int arm_polls(struct io_uring *ring) { - int ret, to_arm = NFILES, i, off; + int ret, to_arm = nfiles, i, off; off = 0; while (to_arm) { @@ -162,7 +164,7 @@ int main(int argc, char *argv[]) int i, ret; if (argc > 1) - return 0; + return T_EXIT_SKIP; if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) { perror("getrlimit"); @@ -170,8 +172,12 @@ int main(int argc, char *argv[]) } if (rlim.rlim_cur < (2 * NFILES + 5)) { - rlim.rlim_cur = (2 * NFILES + 5); - rlim.rlim_max = rlim.rlim_cur; + rlim.rlim_cur = rlim.rlim_max; + nfiles = (rlim.rlim_cur / 2) - 5; + if (nfiles > NFILES) + nfiles = NFILES; + if (nfiles <= 0) + goto err_nofail; if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) { if (errno == EPERM) goto err_nofail; @@ -180,7 +186,7 @@ int main(int argc, char *argv[]) } } - for (i = 0; i < NFILES; i++) { + for (i = 0; i < nfiles; i++) { if (pipe(p[i].fd) < 0) { perror("pipe"); return T_EXIT_FAIL; @@ -227,5 +233,5 @@ int main(int argc, char *argv[]) err_nofail: fprintf(stderr, "poll-many: not enough files available (and not root), " "skipped\n"); - return 0; + return T_EXIT_SKIP; } diff --git a/contrib/libs/liburing/test/poll-many.t/ya.make b/contrib/libs/liburing/test/poll-many.t/ya.make index 67d9a682f6..88050fbf26 100644 --- a/contrib/libs/liburing/test/poll-many.t/ya.make +++ b/contrib/libs/liburing/test/poll-many.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/poll-mshot-overflow.t/ya.make b/contrib/libs/liburing/test/poll-mshot-overflow.t/ya.make index ccc141a99b..a2a5ae3931 100644 --- a/contrib/libs/liburing/test/poll-mshot-overflow.t/ya.make +++ b/contrib/libs/liburing/test/poll-mshot-overflow.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/poll-mshot-update.c b/contrib/libs/liburing/test/poll-mshot-update.c index c3b687260c..2014560f05 100644 --- a/contrib/libs/liburing/test/poll-mshot-update.c +++ b/contrib/libs/liburing/test/poll-mshot-update.c @@ -16,11 +16,14 @@ #include <pthread.h> #include "liburing.h" +#include "helpers.h" #define NFILES 5000 #define BATCH 500 #define NLOOPS 1000 +static int nfiles = NFILES; + #define RING_SIZE 512 struct p { @@ -161,7 +164,7 @@ static int trigger_polls(void) int off; do { - off = rand() % NFILES; + off = rand() % nfiles; if (!p[off].triggered) break; } while (1); @@ -185,7 +188,7 @@ static void *trigger_polls_fn(void *data) static int arm_polls(struct io_uring *ring) { - int ret, to_arm = NFILES, i, off; + int ret, to_arm = nfiles, i, off; off = 0; while (to_arm) { @@ -221,7 +224,7 @@ static int run(int cqe) pthread_t thread; int i, j, ret; - for (i = 0; i < NFILES; i++) { + for (i = 0; i < nfiles; i++) { if (pipe(p[i].fd) < 0) { perror("pipe"); return 1; @@ -253,12 +256,12 @@ static int run(int cqe) goto err; pthread_join(thread, NULL); - for (j = 0; j < NFILES; j++) + for (j = 0; j < nfiles; j++) p[j].triggered = 0; } io_uring_queue_exit(&ring); - for (i = 0; i < NFILES; i++) { + for (i = 0; i < nfiles; i++) { close(p[i].fd[0]); close(p[i].fd[1]); } @@ -274,7 +277,7 @@ int main(int argc, char *argv[]) int ret; if (argc > 1) - return 0; + return T_EXIT_SKIP; ret = has_poll_update(); if (ret < 0) { @@ -291,13 +294,17 @@ int main(int argc, char *argv[]) } if (rlim.rlim_cur < (2 * NFILES + 5)) { - rlim.rlim_cur = (2 * NFILES + 5); - rlim.rlim_max = rlim.rlim_cur; + rlim.rlim_cur = rlim.rlim_max; + nfiles = (rlim.rlim_cur / 2) - 5; + if (nfiles > NFILES) + nfiles = NFILES; + if (nfiles <= 0) + goto err_nofail; if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) { if (errno == EPERM) goto err_nofail; perror("setrlimit"); - goto err; + return T_EXIT_FAIL; } } @@ -320,5 +327,5 @@ err: err_nofail: fprintf(stderr, "poll-many: not enough files available (and not root), " "skipped\n"); - return 0; + return T_EXIT_SKIP; } diff --git a/contrib/libs/liburing/test/poll-mshot-update.t/ya.make b/contrib/libs/liburing/test/poll-mshot-update.t/ya.make index 3453c214ee..87a58460d0 100644 --- a/contrib/libs/liburing/test/poll-mshot-update.t/ya.make +++ b/contrib/libs/liburing/test/poll-mshot-update.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/poll-race-mshot.t/ya.make b/contrib/libs/liburing/test/poll-race-mshot.t/ya.make index 6fdf2c8491..130b4e495b 100644 --- a/contrib/libs/liburing/test/poll-race-mshot.t/ya.make +++ b/contrib/libs/liburing/test/poll-race-mshot.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/poll-race.t/ya.make b/contrib/libs/liburing/test/poll-race.t/ya.make index 1fdc2798b0..decdc37fef 100644 --- a/contrib/libs/liburing/test/poll-race.t/ya.make +++ b/contrib/libs/liburing/test/poll-race.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/poll-ring.t/ya.make b/contrib/libs/liburing/test/poll-ring.t/ya.make index 248be1c132..0b41888d72 100644 --- a/contrib/libs/liburing/test/poll-ring.t/ya.make +++ b/contrib/libs/liburing/test/poll-ring.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/poll-v-poll.c b/contrib/libs/liburing/test/poll-v-poll.c index 207f7bd5da..91362780e9 100644 --- a/contrib/libs/liburing/test/poll-v-poll.c +++ b/contrib/libs/liburing/test/poll-v-poll.c @@ -18,6 +18,7 @@ #include <sys/epoll.h> #include "liburing.h" +#include "helpers.h" struct thread_data { struct io_uring *ring; @@ -175,6 +176,8 @@ static int do_fd_test(struct io_uring *ring, const char *fname, int events) fd = open(fname, O_RDONLY); if (fd < 0) { + if (errno == EPERM || errno == EACCES) + return T_EXIT_SKIP; perror("open"); return 1; } @@ -332,19 +335,19 @@ int main(int argc, char *argv[]) fname = argv[0]; ret = do_fd_test(&ring, fname, POLLIN); - if (ret) { + if (ret == T_EXIT_FAIL) { fprintf(stderr, "fd test IN failed\n"); return ret; } ret = do_fd_test(&ring, fname, POLLOUT); - if (ret) { + if (ret == T_EXIT_FAIL) { fprintf(stderr, "fd test OUT failed\n"); return ret; } ret = do_fd_test(&ring, fname, POLLOUT | POLLIN); - if (ret) { + if (ret == T_EXIT_FAIL) { fprintf(stderr, "fd test IN|OUT failed\n"); return ret; } diff --git a/contrib/libs/liburing/test/poll-v-poll.t/ya.make b/contrib/libs/liburing/test/poll-v-poll.t/ya.make index b48c0ff287..5f4c049f11 100644 --- a/contrib/libs/liburing/test/poll-v-poll.t/ya.make +++ b/contrib/libs/liburing/test/poll-v-poll.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/poll.t/ya.make b/contrib/libs/liburing/test/poll.t/ya.make index 809283fd40..5b2f985766 100644 --- a/contrib/libs/liburing/test/poll.t/ya.make +++ b/contrib/libs/liburing/test/poll.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/pollfree.c b/contrib/libs/liburing/test/pollfree.c new file mode 100644 index 0000000000..0ba3ce390d --- /dev/null +++ b/contrib/libs/liburing/test/pollfree.c @@ -0,0 +1,149 @@ +#include "../config-host.h" +/* SPDX-License-Identifier: MIT */ +/* + * Description: test pollfree wakeups + */ +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/signalfd.h> +#include <unistd.h> +#include <stdlib.h> + +#include "liburing.h" +#include "helpers.h" + +static int no_signalfd; + +static int child(int flags) +{ + struct io_uring_sqe *sqe; + struct io_uring ring; + struct signalfd_siginfo si; + static unsigned long index; + sigset_t mask; + int ret, fd; + + ret = io_uring_queue_init(4, &ring, flags); + if (ret) { + if (ret == -EINVAL) + return 0; + fprintf(stderr, "queue init failed %d\n", ret); + return ret; + } + + sigemptyset(&mask); + sigaddset(&mask, SIGINT); + + fd = signalfd(-1, &mask, SFD_NONBLOCK); + if (fd < 0) { + no_signalfd = 1; + perror("signalfd"); + return 1; + } + + sqe = io_uring_get_sqe(&ring); + io_uring_prep_read(sqe, fd, &si, sizeof(si), 0); + sqe->user_data = 1; + io_uring_submit(&ring); + + sqe = io_uring_get_sqe(&ring); + io_uring_prep_read(sqe, fd, &si, sizeof(si), 0); + sqe->user_data = 2; + sqe->flags |= IOSQE_ASYNC; + io_uring_submit(&ring); + + sqe = io_uring_get_sqe(&ring); + io_uring_prep_read(sqe, fd, &si, sizeof(si), 0); + sqe->user_data = 3; + io_uring_submit(&ring); + + if (!(++index & 7)) + usleep(100); + + return 0; +} + +static int run_test(int flags) +{ + pid_t pid; + int ret; + + pid = fork(); + if (pid < 0) { + perror("fork"); + return 1; + } else if (!pid) { + ret = child(flags); + _exit(ret); + } else { + int wstatus; + pid_t childpid; + + do { + childpid = waitpid(pid, &wstatus, 0); + } while (childpid == (pid_t) -1 && (errno == EINTR)); + + if (errno == ECHILD) + wstatus = 0; + return wstatus; + } +} + +static int test(int flags) +{ + struct timeval start; + int ret; + + gettimeofday(&start, NULL); + do { + ret = run_test(flags); + if (ret) { + fprintf(stderr, "test failed with flags %x\n", flags); + return 1; + } + if (no_signalfd) + break; + } while (mtime_since_now(&start) < 2500); + + return 0; +} + +int main(int argc, char *argv[]) +{ + int ret; + + if (argc > 1) + return T_EXIT_SKIP; + + ret = test(0); + if (ret) { + fprintf(stderr, "test 0 failed: %d\n", ret); + return ret; + } + + if (no_signalfd) + return T_EXIT_SKIP; + + ret = test(IORING_SETUP_SQPOLL); + if (ret) { + fprintf(stderr, "test SQPOLL failed: %d\n", ret); + return ret; + } + + ret = test(IORING_SETUP_COOP_TASKRUN); + if (ret) { + fprintf(stderr, "test COOP failed: %d\n", ret); + return ret; + } + + ret = test(IORING_SETUP_DEFER_TASKRUN|IORING_SETUP_SINGLE_ISSUER); + if (ret) { + fprintf(stderr, "test DEFER failed: %d\n", ret); + return ret; + } + + return T_EXIT_PASS; +} diff --git a/contrib/libs/liburing/test/pollfree.t/ya.make b/contrib/libs/liburing/test/pollfree.t/ya.make new file mode 100644 index 0000000000..250c998824 --- /dev/null +++ b/contrib/libs/liburing/test/pollfree.t/ya.make @@ -0,0 +1,35 @@ +# Generated by devtools/yamaker. + +PROGRAM() + +WITHOUT_LICENSE_TEXTS() + +VERSION(2.8) + +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 + pollfree.c +) + +END() diff --git a/contrib/libs/liburing/test/probe.t/ya.make b/contrib/libs/liburing/test/probe.t/ya.make index abc6c4a41e..6ca9e5b012 100644 --- a/contrib/libs/liburing/test/probe.t/ya.make +++ b/contrib/libs/liburing/test/probe.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/read-before-exit.t/ya.make b/contrib/libs/liburing/test/read-before-exit.t/ya.make index d762a60d86..e063ffe60c 100644 --- a/contrib/libs/liburing/test/read-before-exit.t/ya.make +++ b/contrib/libs/liburing/test/read-before-exit.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/read-mshot-empty.c b/contrib/libs/liburing/test/read-mshot-empty.c index 2fc5a63184..66ed02d973 100644 --- a/contrib/libs/liburing/test/read-mshot-empty.c +++ b/contrib/libs/liburing/test/read-mshot-empty.c @@ -117,8 +117,10 @@ int main(int argc, char *argv[]) */ ret = io_uring_peek_cqe(&ring, &cqe); if (!ret) { - if (cqe->res == -EINVAL || cqe->res == -EBADF) + if (cqe->res == -EINVAL || cqe->res == -EBADF) { + free(buf); return T_EXIT_SKIP; + } } pthread_create(&thread, NULL, thread_fn, fds); @@ -150,5 +152,8 @@ int main(int argc, char *argv[]) } pthread_join(thread, &tret); + io_uring_free_buf_ring(&ring, br, NR_BUFS, BGID); + io_uring_queue_exit(&ring); + free(buf); 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 index bf50a15474..5c846118f3 100644 --- a/contrib/libs/liburing/test/read-mshot-empty.t/ya.make +++ b/contrib/libs/liburing/test/read-mshot-empty.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/read-mshot-stdin.c b/contrib/libs/liburing/test/read-mshot-stdin.c new file mode 100644 index 0000000000..9ac602204a --- /dev/null +++ b/contrib/libs/liburing/test/read-mshot-stdin.c @@ -0,0 +1,122 @@ +#include "../config-host.h" +/* SPDX-License-Identifier: MIT */ +/* + * Description: test multishot read on stdin. Not that this REQUIRES input + * to be received on stdin, and hence if invoked with no + * arguments, or without the single argument being 'stdin', + * the test will just return SKIPPED. Can't be run from the + * standard test harness, as it's interactive. + * + * To run, do run "test/read-mshot-stdin.t stdin" and then input text on + * the console, followed by enter / line feed. If it works as it should, + * it'll output the received CQE data. If an error is detected, it'll + * abort with an error. + */ +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <sys/stat.h> + +#include "liburing.h" +#include "helpers.h" + +#define BUF_SIZE 32 +#define NR_BUFS 64 +#define BUF_BGID 1 + +#define BR_MASK (NR_BUFS - 1) + +static int test_stdin(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, i, last_bid; + char *buf, *ptr; + + p.flags = IORING_SETUP_CQSIZE; + p.cq_entries = NR_BUFS; + ret = io_uring_queue_init_params(1, &ring, &p); + if (ret) { + if (ret == -EINVAL) + return T_EXIT_SKIP; + fprintf(stderr, "ring setup failed: %d\n", ret); + return T_EXIT_FAIL; + } + + if (posix_memalign((void **) &buf, 4096, NR_BUFS * BUF_SIZE)) + return T_EXIT_FAIL; + + br = io_uring_setup_buf_ring(&ring, NR_BUFS, BUF_BGID, 0, &ret); + if (!br) { + if (ret == -EINVAL) + return T_EXIT_SKIP; + fprintf(stderr, "Buffer ring register failed %d\n", ret); + return T_EXIT_FAIL; + } + + 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); + + sqe = io_uring_get_sqe(&ring); + io_uring_prep_read_multishot(sqe, STDIN_FILENO, 0, 0, BUF_BGID); + + ret = io_uring_submit(&ring); + if (ret != 1) { + fprintf(stderr, "submit: %d\n", ret); + return T_EXIT_FAIL; + } + + last_bid = -1; + do { + int bid; + + ret = io_uring_wait_cqe(&ring, &cqe); + if (ret) { + fprintf(stderr, "wait cqe failed %d\n", ret); + return T_EXIT_FAIL; + } + if (cqe->res && !(cqe->flags & IORING_CQE_F_BUFFER)) { + fprintf(stderr, "BUF flag not set %x\n", cqe->flags); + return T_EXIT_FAIL; + } + bid = cqe->flags >> 16; + printf("CQE res %d, bid %d, flags %x\n", cqe->res, bid, cqe->flags); + if (cqe->res > 0 && last_bid != -1 && last_bid + 1 != bid) { + fprintf(stderr, "Got bid %d, wanted %d\n", bid, last_bid + 1); + return T_EXIT_FAIL; + } + if (!(cqe->flags & IORING_CQE_F_MORE)) { + io_uring_cqe_seen(&ring, cqe); + break; + } + + last_bid = bid; + io_uring_cqe_seen(&ring, cqe); + }while (1); + + io_uring_free_buf_ring(&ring, br, NR_BUFS, BUF_BGID); + io_uring_queue_exit(&ring); + free(buf); + return T_EXIT_PASS; +} + +int main(int argc, char *argv[]) +{ + if (argc == 1) + return T_EXIT_SKIP; + else if (argc > 2) + return T_EXIT_SKIP; + if (!strcmp(argv[1], "stdin")) + return test_stdin(); + return T_EXIT_SKIP; +} diff --git a/contrib/libs/liburing/test/read-mshot-stdin.t/ya.make b/contrib/libs/liburing/test/read-mshot-stdin.t/ya.make new file mode 100644 index 0000000000..66267bf515 --- /dev/null +++ b/contrib/libs/liburing/test/read-mshot-stdin.t/ya.make @@ -0,0 +1,35 @@ +# Generated by devtools/yamaker. + +PROGRAM() + +WITHOUT_LICENSE_TEXTS() + +VERSION(2.8) + +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-stdin.c +) + +END() diff --git a/contrib/libs/liburing/test/read-mshot.c b/contrib/libs/liburing/test/read-mshot.c index 681a306ad4..fe063d03f3 100644 --- a/contrib/libs/liburing/test/read-mshot.c +++ b/contrib/libs/liburing/test/read-mshot.c @@ -24,7 +24,134 @@ #define NR_OVERFLOW (NR_BUFS / 4) -static int no_buf_ring, no_read_mshot; +static int no_buf_ring, no_read_mshot, no_buf_ring_inc; + +static void arm_read(struct io_uring *ring, int fd, int use_mshot) +{ + struct io_uring_sqe *sqe; + + sqe = io_uring_get_sqe(ring); + if (use_mshot) { + io_uring_prep_read_multishot(sqe, fd, 0, 0, BUF_BGID); + } else { + io_uring_prep_read(sqe, fd, NULL, 0, 0); + sqe->flags = IOSQE_BUFFER_SELECT; + sqe->buf_group = BUF_BGID; + } + + io_uring_submit(ring); +} + +static int test_inc(int use_mshot, int flags) +{ + struct io_uring_buf_ring *br; + struct io_uring_params p = { }; + struct io_uring_cqe *cqe; + struct io_uring ring; + int nbytes = 65536; + int ret, fds[2], i; + char tmp[31]; + char *buf; + void *ptr; + int bid = -1; + int bid_bytes; + + if (no_buf_ring) + return 0; + + p.flags = flags; + ret = io_uring_queue_init_params(64, &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, 65536)) + return 1; + + br = io_uring_setup_buf_ring(&ring, 32, BUF_BGID, IOU_PBUF_RING_INC, &ret); + if (!br) { + if (ret == -EINVAL) { + no_buf_ring_inc = 1; + free(buf); + return 0; + } + fprintf(stderr, "Buffer ring register failed %d\n", ret); + return 1; + } + + ptr = buf; + buf = ptr + 65536 - 2048; + for (i = 0; i < 32; i++) { + io_uring_buf_ring_add(br, buf, 2048, i, 31, i); + buf -= 2048; + } + io_uring_buf_ring_advance(br, 32); + + memset(tmp, 0x5a, sizeof(tmp)); + + arm_read(&ring, fds[0], use_mshot); + + bid_bytes = 0; + do { + int write_size = sizeof(tmp); + + if (write_size > nbytes) + write_size = nbytes; + + io_uring_get_events(&ring); + ret = io_uring_peek_cqe(&ring, &cqe); + if (!ret) { + int this_bid = cqe->flags >> IORING_CQE_BUFFER_SHIFT; + if (bid == -1) { + bid = this_bid; + } else if (bid != this_bid) { + if (bid_bytes != 2048) { + fprintf(stderr, "unexpected bid bytes %d\n", + bid_bytes); + return 1; + } + bid = this_bid; + bid_bytes = 0; + } + bid_bytes += cqe->res; + nbytes -= cqe->res; + if (!(cqe->flags & IORING_CQE_F_MORE)) + arm_read(&ring, fds[0], use_mshot); + io_uring_cqe_seen(&ring, cqe); + if (!nbytes) + break; + } + usleep(1000); + ret = write(fds[1], tmp, write_size); + if (ret < 0) { + perror("write"); + return 1; + } else if (ret != write_size) { + printf("short write %d\n", ret); + return 1; + } + } while (nbytes); + + if (bid_bytes) { + if (bid_bytes != 2048) { + fprintf(stderr, "unexpected bid bytes %d\n", bid_bytes); + return 1; + } + } + + io_uring_free_buf_ring(&ring, br, 32, BUF_BGID); + io_uring_queue_exit(&ring); + free(ptr); + close(fds[0]); + close(fds[1]); + return 0; +} static int test_clamp(void) { @@ -130,21 +257,24 @@ static int test_clamp(void) io_uring_cqe_seen(&ring, cqe); } + io_uring_free_buf_ring(&ring, br, NR_BUFS, BUF_BGID); io_uring_queue_exit(&ring); free(ptr); return 0; } -static int test(int first_good, int async, int overflow) +static int test(int first_good, int async, int overflow, int incremental) { 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; + int ret, fds[2], i, start_msg = 0; + int br_flags = 0; char tmp[32]; void *ptr[NR_BUFS]; + char *inc_index; p.flags = IORING_SETUP_CQSIZE; if (!overflow) @@ -157,14 +287,19 @@ static int test(int first_good, int async, int overflow) return 1; } - if (pipe(fds) < 0) { - perror("pipe"); - return 1; + if (incremental) { + if (no_buf_ring_inc) + return 0; + br_flags |= IOU_PBUF_RING_INC; } - br = io_uring_setup_buf_ring(&ring, NR_BUFS, BUF_BGID, 0, &ret); + br = io_uring_setup_buf_ring(&ring, NR_BUFS, BUF_BGID, br_flags, &ret); if (!br) { if (ret == -EINVAL) { + if (incremental) { + no_buf_ring_inc = 1; + return 0; + } no_buf_ring = 1; return 0; } @@ -172,17 +307,30 @@ static int test(int first_good, int async, int overflow) 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); + if (pipe(fds) < 0) { + perror("pipe"); + return 1; + } + + if (!incremental) { + 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); + } + inc_index = NULL; + io_uring_buf_ring_advance(br, NR_BUFS); + } else { + inc_index = ptr[0] = malloc(NR_BUFS * BUF_SIZE); + memset(inc_index, 0, NR_BUFS * BUF_SIZE); + io_uring_buf_ring_add(br, ptr[0], NR_BUFS * BUF_SIZE, 1, BR_MASK, 0); + io_uring_buf_ring_advance(br, 1); } - io_uring_buf_ring_advance(br, NR_BUFS); if (first_good) { - sprintf(tmp, "this is buffer %d\n", 0); + sprintf(tmp, "this is buffer %d\n", start_msg++); ret = write(fds[1], tmp, strlen(tmp)); } @@ -202,7 +350,7 @@ static int test(int first_good, int async, int overflow) for (i = 0; i < NR_BUFS + !first_good; i++) { /* prevent pipe buffer merging */ usleep(1000); - sprintf(tmp, "this is buffer %d\n", i + 1); + sprintf(tmp, "this is buffer %d\n", i + start_msg); ret = write(fds[1], tmp, strlen(tmp)); if (ret != strlen(tmp)) { fprintf(stderr, "write ret %d\n", ret); @@ -211,6 +359,8 @@ static int test(int first_good, int async, int overflow) } for (i = 0; i < NR_BUFS + 1; i++) { + int bid; + ret = io_uring_wait_cqe(&ring, &cqe); if (ret) { fprintf(stderr, "wait cqe failed %d\n", ret); @@ -235,6 +385,18 @@ static int test(int first_good, int async, int overflow) fprintf(stderr, "no buffer selected\n"); return 1; } + bid = cqe->flags >> IORING_CQE_BUFFER_SHIFT; + if (incremental && bid != 1) { + fprintf(stderr, "bid %d for incremental\n", bid); + return 1; + } + if (incremental && !first_good) { + char out_buf[64]; + sprintf(out_buf, "this is buffer %d\n", i + start_msg); + if (strncmp(inc_index, out_buf, strlen(out_buf))) + return 1; + inc_index += cqe->res; + } if (!(cqe->flags & IORING_CQE_F_MORE)) { /* we expect this on overflow */ if (overflow && i >= NR_OVERFLOW) @@ -250,9 +412,15 @@ static int test(int first_good, int async, int overflow) io_uring_cqe_seen(&ring, cqe); } + + io_uring_free_buf_ring(&ring, br, NR_BUFS, BUF_BGID); io_uring_queue_exit(&ring); - for (i = 0; i < NR_BUFS; i++) - free(ptr[i]); + if (incremental) { + free(ptr[0]); + } else { + for (i = 0; i < NR_BUFS; i++) + free(ptr[i]); + } return 0; } @@ -321,6 +489,7 @@ static int test_invalid(int async) } io_uring_cqe_seen(&ring, cqe); + io_uring_free_buf_ring(&ring, br, 1, BUF_BGID); io_uring_queue_exit(&ring); free(buf); return 0; @@ -333,56 +502,106 @@ int main(int argc, char *argv[]) if (argc > 1) return T_EXIT_SKIP; - ret = test(0, 0, 0); + ret = test(0, 0, 0, 0); if (ret) { fprintf(stderr, "test 0 0 0 failed\n"); return T_EXIT_FAIL; } - if (no_buf_ring || no_read_mshot) + if (no_buf_ring || no_read_mshot) { + printf("skip\n"); return T_EXIT_SKIP; + } - ret = test(0, 1, 0); + ret = test(0, 1, 0, 0); if (ret) { fprintf(stderr, "test 0 1 0, failed\n"); return T_EXIT_FAIL; } - ret = test(1, 0, 0); + ret = test(1, 0, 0, 0); if (ret) { fprintf(stderr, "test 1 0 0 failed\n"); return T_EXIT_FAIL; } - ret = test(0, 0, 1); + ret = test(0, 0, 1, 0); if (ret) { fprintf(stderr, "test 0 0 1 failed\n"); return T_EXIT_FAIL; } - ret = test(0, 1, 1); + ret = test(0, 1, 1, 0); if (ret) { fprintf(stderr, "test 0 1 1 failed\n"); return T_EXIT_FAIL; } - ret = test(1, 0, 1); + ret = test(1, 0, 1, 0); if (ret) { fprintf(stderr, "test 1 0 1, failed\n"); return T_EXIT_FAIL; } - ret = test(1, 0, 1); + ret = test(1, 0, 1, 0); if (ret) { fprintf(stderr, "test 1 0 1 failed\n"); return T_EXIT_FAIL; } - ret = test(1, 1, 1); + ret = test(1, 1, 1, 0); if (ret) { fprintf(stderr, "test 1 1 1 failed\n"); return T_EXIT_FAIL; } + ret = test(0, 0, 0, 1); + if (ret) { + fprintf(stderr, "test 0 0 0 1 failed\n"); + return T_EXIT_FAIL; + } + + ret = test(0, 0, 1, 1); + if (ret) { + fprintf(stderr, "test 0 0 1 1 failed\n"); + return T_EXIT_FAIL; + } + + ret = test(0, 1, 0, 1); + if (ret) { + fprintf(stderr, "test 0 1 0 1 failed\n"); + return T_EXIT_FAIL; + } + + ret = test(0, 1, 1, 1); + if (ret) { + fprintf(stderr, "test 0 1 1 1 failed\n"); + return T_EXIT_FAIL; + } + + ret = test(1, 0, 0, 1); + if (ret) { + fprintf(stderr, "test 1 0 0 1 failed\n"); + return T_EXIT_FAIL; + } + + ret = test(1, 0, 1, 1); + if (ret) { + fprintf(stderr, "test 1 0 1 1 failed\n"); + return T_EXIT_FAIL; + } + + ret = test(1, 1, 0, 1); + if (ret) { + fprintf(stderr, "test 1 1 0 1 failed\n"); + return T_EXIT_FAIL; + } + + ret = test(1, 1, 1, 1); + if (ret) { + fprintf(stderr, "test 1 1 1 1 failed\n"); + return T_EXIT_FAIL; + } + ret = test_invalid(0); if (ret) { fprintf(stderr, "test_invalid 0 failed\n"); @@ -401,5 +620,41 @@ int main(int argc, char *argv[]) return T_EXIT_FAIL; } + ret = test_inc(0, 0); + if (ret) { + fprintf(stderr, "test_inc 0 0 failed\n"); + return T_EXIT_FAIL; + } + + ret = test_inc(0, IORING_SETUP_SQPOLL); + if (ret) { + fprintf(stderr, "test_inc 0 sqpoll failed\n"); + return T_EXIT_FAIL; + } + + ret = test_inc(0, IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN); + if (ret) { + fprintf(stderr, "test_inc 0 defer failed\n"); + return T_EXIT_FAIL; + } + + ret = test_inc(1, 0); + if (ret) { + fprintf(stderr, "test_inc 1 0 failed\n"); + return T_EXIT_FAIL; + } + + ret = test_inc(1, IORING_SETUP_SQPOLL); + if (ret) { + fprintf(stderr, "test_inc 1 sqpoll failed\n"); + return T_EXIT_FAIL; + } + + ret = test_inc(1, IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN); + if (ret) { + fprintf(stderr, "test_inc 1 defer 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 index a760a7efbd..44f536e7bb 100644 --- a/contrib/libs/liburing/test/read-mshot.t/ya.make +++ b/contrib/libs/liburing/test/read-mshot.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/read-write.c b/contrib/libs/liburing/test/read-write.c index 2ca1fde1a4..dd4dddff34 100644 --- a/contrib/libs/liburing/test/read-write.c +++ b/contrib/libs/liburing/test/read-write.c @@ -16,6 +16,7 @@ #include "helpers.h" #include "liburing.h" +#include "../src/syscall.h" #define FILE_SIZE (256 * 1024) #define BS 8192 @@ -24,6 +25,7 @@ static struct iovec *vecs; static int no_read; static int no_buf_select; +static int no_buf_copy; static int warned; static int create_nonaligned_buffers(void) @@ -43,9 +45,9 @@ static int create_nonaligned_buffers(void) return 0; } -static int __test_io(const char *file, struct io_uring *ring, int write, - int buffered, int sqthread, int fixed, int nonvec, - int buf_select, int seq, int exp_len) +static int _test_io(const char *file, struct io_uring *ring, int write, + int buffered, int sqthread, int fixed, int nonvec, + int buf_select, int seq, int exp_len) { struct io_uring_sqe *sqe; struct io_uring_cqe *cqe; @@ -65,7 +67,7 @@ static int __test_io(const char *file, struct io_uring *ring, int write, if (!buffered) open_flags |= O_DIRECT; - if (fixed) { + if (fixed == 1) { ret = t_register_buffers(ring, vecs, BUFFERS); if (ret == T_SETUP_SKIP) return 0; @@ -77,7 +79,7 @@ static int __test_io(const char *file, struct io_uring *ring, int write, fd = open(file, open_flags); if (fd < 0) { - if (errno == EINVAL) + if (errno == EINVAL || errno == EPERM || errno == EACCES) return 0; perror("file open"); goto err; @@ -202,13 +204,6 @@ static int __test_io(const char *file, struct io_uring *ring, int write, io_uring_cqe_seen(ring, cqe); } - if (fixed) { - ret = io_uring_unregister_buffers(ring); - if (ret) { - fprintf(stderr, "buffer unreg failed: %d\n", ret); - goto err; - } - } if (sqthread) { ret = io_uring_unregister_files(ring); if (ret) { @@ -230,6 +225,65 @@ err: close(fd); return 1; } + +static int __test_io(const char *file, struct io_uring *ring, int write, + int buffered, int sqthread, int fixed, int nonvec, + int buf_select, int seq, int exp_len) +{ + int ret; + + ret = _test_io(file, ring, write, buffered, sqthread, fixed, nonvec, + buf_select, seq, exp_len); + if (ret) + return ret; + + if (fixed) { + struct io_uring ring2; + int ring_flags = 0; + + if (no_buf_copy) + return 0; + if (sqthread) + ring_flags = IORING_SETUP_SQPOLL; + ret = t_create_ring(64, &ring2, ring_flags); + if (ret == T_SETUP_SKIP) + return 0; + if (ret != T_SETUP_OK) { + fprintf(stderr, "ring create failed: %d\n", ret); + return 1; + } + + ret = io_uring_clone_buffers(&ring2, ring); + if (ret) { + if (ret == -EINVAL) { + no_buf_copy = 1; + io_uring_queue_exit(&ring2); + return 0; + } + fprintf(stderr, "copy buffers: %d\n", ret); + return ret; + } + ret = _test_io(file, &ring2, write, buffered, sqthread, 2, + nonvec, buf_select, seq, exp_len); + if (ret) + return ret; + + ret = io_uring_unregister_buffers(ring); + if (ret) { + fprintf(stderr, "buffer unreg failed: %d\n", ret); + return ret; + } + ret = io_uring_unregister_buffers(&ring2); + if (ret) { + fprintf(stderr, "buffer copy unreg failed: %d\n", ret); + return ret; + } + io_uring_queue_exit(&ring2); + } + + return ret; +} + static int test_io(const char *file, int write, int buffered, int sqthread, int fixed, int nonvec, int exp_len) { @@ -267,6 +321,8 @@ static int read_poll_link(const char *file) fd = open(file, O_WRONLY); if (fd < 0) { + if (errno == EACCES || errno == EPERM) + return T_EXIT_SKIP; perror("open"); return 1; } @@ -339,6 +395,7 @@ out: if (!(p->ops[IORING_OP_READ].flags & IO_URING_OP_SUPPORTED)) goto out; io_uring_queue_exit(&ring); + free(p); return 1; } @@ -697,6 +754,8 @@ static int test_io_link(const char *file) fd = open(file, O_WRONLY); if (fd < 0) { + if (errno == EPERM || errno == EACCES) + return 0; perror("file open"); goto err; } @@ -930,7 +989,7 @@ int main(int argc, char *argv[]) } ret = read_poll_link(fname); - if (ret) { + if (ret == T_EXIT_FAIL) { fprintf(stderr, "read_poll_link failed\n"); goto err; } @@ -971,6 +1030,12 @@ int main(int argc, char *argv[]) goto err; } + if(vecs != NULL) { + for (i = 0; i < BUFFERS; i++) + free(vecs[i].iov_base); + } + free(vecs); + srand((unsigned)time(NULL)); if (create_nonaligned_buffers()) { fprintf(stderr, "file creation failed\n"); diff --git a/contrib/libs/liburing/test/read-write.t/ya.make b/contrib/libs/liburing/test/read-write.t/ya.make index 25de751b18..7d887f6898 100644 --- a/contrib/libs/liburing/test/read-write.t/ya.make +++ b/contrib/libs/liburing/test/read-write.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/recv-msgall-stream.c b/contrib/libs/liburing/test/recv-msgall-stream.c index 355b1f5cfe..77eb45d86e 100644 --- a/contrib/libs/liburing/test/recv-msgall-stream.c +++ b/contrib/libs/liburing/test/recv-msgall-stream.c @@ -318,6 +318,7 @@ static int do_send(struct recv_data *rd) if (cqe->res == -EINVAL) { fprintf(stdout, "send not supported, skipping\n"); close(sockfd); + free(buf); return 0; } if (cqe->res != iov.iov_len) { @@ -329,10 +330,12 @@ static int do_send(struct recv_data *rd) shutdown(sockfd, SHUT_RDWR); close(sockfd); + free(buf); return 0; err: shutdown(sockfd, SHUT_RDWR); close(sockfd); + free(buf); return 1; } diff --git a/contrib/libs/liburing/test/recv-msgall-stream.t/ya.make b/contrib/libs/liburing/test/recv-msgall-stream.t/ya.make index 428cb35d61..414c410945 100644 --- a/contrib/libs/liburing/test/recv-msgall-stream.t/ya.make +++ b/contrib/libs/liburing/test/recv-msgall-stream.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/recv-msgall.c b/contrib/libs/liburing/test/recv-msgall.c index e0d94f33b1..c95ab7f914 100644 --- a/contrib/libs/liburing/test/recv-msgall.c +++ b/contrib/libs/liburing/test/recv-msgall.c @@ -172,12 +172,14 @@ static int do_send(void) sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { perror("socket"); + free(buf); return 1; } ret = connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)); if (ret < 0) { perror("connect"); + free(buf); return 1; } @@ -202,6 +204,7 @@ static int do_send(void) if (cqe->res == -EINVAL) { fprintf(stdout, "send not supported, skipping\n"); close(sockfd); + free(buf); return 0; } if (cqe->res != iov.iov_len) { @@ -212,9 +215,11 @@ static int do_send(void) } close(sockfd); + free(buf); return 0; err: close(sockfd); + free(buf); return 1; } diff --git a/contrib/libs/liburing/test/recv-msgall.t/ya.make b/contrib/libs/liburing/test/recv-msgall.t/ya.make index 6a779b4378..f8c6f883aa 100644 --- a/contrib/libs/liburing/test/recv-msgall.t/ya.make +++ b/contrib/libs/liburing/test/recv-msgall.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/recv-multishot.t/ya.make b/contrib/libs/liburing/test/recv-multishot.t/ya.make index 4196930356..97c41c11e5 100644 --- a/contrib/libs/liburing/test/recv-multishot.t/ya.make +++ b/contrib/libs/liburing/test/recv-multishot.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/recvsend_bundle-inc.c b/contrib/libs/liburing/test/recvsend_bundle-inc.c new file mode 100644 index 0000000000..3e10ce4b64 --- /dev/null +++ b/contrib/libs/liburing/test/recvsend_bundle-inc.c @@ -0,0 +1,681 @@ +#include "../config-host.h" +/* SPDX-License-Identifier: MIT */ +/* + * Simple test case showing using send and recv bundles with incremental + * buffer ring usage + */ +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <arpa/inet.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <pthread.h> + +#define MSG_SIZE 128 +#define NR_MIN_MSGS 4 +#define NR_MAX_MSGS 32 +#define SEQ_SIZE (MSG_SIZE / sizeof(unsigned long)) + +static int nr_msgs; + +#define RECV_BIDS 8192 +#define RECV_BID_MASK (RECV_BIDS - 1) + +#include <liburing.h> + +enum t_test_result { + T_EXIT_PASS = 0, + T_EXIT_FAIL = 1, + T_EXIT_SKIP = 77, +}; + +#define PORT 10202 +#define HOST "127.0.0.1" + +static int use_port = PORT; + +#define SEND_BGID 7 +#define RECV_BGID 8 + +static int no_send_mshot; + +struct recv_data { + pthread_barrier_t connect; + pthread_barrier_t startup; + pthread_barrier_t barrier; + pthread_barrier_t finish; + unsigned long seq; + int recv_bytes; + int accept_fd; + int abort; + unsigned int max_sends; + int to_eagain; + void *recv_buf; + + int send_bundle; + int recv_bundle; +}; + +static int arm_recv(struct io_uring *ring, struct recv_data *rd) +{ + struct io_uring_sqe *sqe; + int ret; + + sqe = io_uring_get_sqe(ring); + io_uring_prep_recv_multishot(sqe, rd->accept_fd, NULL, 0, 0); + if (rd->recv_bundle) + sqe->ioprio |= IORING_RECVSEND_BUNDLE; + sqe->buf_group = RECV_BGID; + sqe->flags |= IOSQE_BUFFER_SELECT; + sqe->user_data = 2; + + ret = io_uring_submit(ring); + if (ret != 1) { + fprintf(stderr, "submit failed: %d\n", ret); + return 1; + } + + return 0; +} + +static int recv_prep(struct io_uring *ring, struct recv_data *rd, int *sock) +{ + struct sockaddr_in saddr; + int sockfd, ret, val, use_fd; + socklen_t socklen; + + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_addr.s_addr = htonl(INADDR_ANY); + saddr.sin_port = htons(use_port); + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + perror("socket"); + return 1; + } + + val = 1; + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); + + ret = bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)); + if (ret < 0) { + perror("bind"); + goto err; + } + + ret = listen(sockfd, 1); + if (ret < 0) { + perror("listen"); + goto err; + } + + pthread_barrier_wait(&rd->connect); + + socklen = sizeof(saddr); + use_fd = accept(sockfd, (struct sockaddr *)&saddr, &socklen); + if (use_fd < 0) { + perror("accept"); + goto err; + } + + rd->accept_fd = use_fd; + pthread_barrier_wait(&rd->startup); + pthread_barrier_wait(&rd->barrier); + + if (arm_recv(ring, rd)) + goto err; + + *sock = sockfd; + return 0; +err: + close(sockfd); + return 1; +} + +static int verify_seq(struct recv_data *rd, void *verify_ptr, int verify_sz, + int start_bid) +{ + unsigned long *seqp; + int seq_size = verify_sz / sizeof(unsigned long); + int i; + + seqp = verify_ptr; + for (i = 0; i < seq_size; i++) { + if (rd->seq != *seqp) { + fprintf(stderr, "bid=%d, got seq %lu, wanted %lu, offset %d\n", start_bid, *seqp, rd->seq, i); + return 0; + } + seqp++; + rd->seq++; + } + + return 1; +} + +static int recv_get_cqe(struct io_uring *ring, struct recv_data *rd, + struct io_uring_cqe **cqe) +{ + struct __kernel_timespec ts = { .tv_sec = 0, .tv_nsec = 100000000LL }; + int ret; + + do { + ret = io_uring_wait_cqe_timeout(ring, cqe, &ts); + if (!ret) + return 0; + if (ret == -ETIME) { + if (rd->abort) + break; + continue; + } + fprintf(stderr, "wait recv: %d\n", ret); + break; + } while (1); + + return 1; +} + +static int do_recv(struct io_uring *ring, struct recv_data *rd) +{ + struct io_uring_cqe *cqe; + void *verify_ptr; + int verify_sz = 0; + int verify_bid = 0; + int bid; + + verify_ptr = malloc(rd->recv_bytes); + + do { + if (recv_get_cqe(ring, rd, &cqe)) + break; + if (cqe->res == -EINVAL) { + fprintf(stdout, "recv not supported, skipping\n"); + return 0; + } + if (cqe->res < 0) { + fprintf(stderr, "failed recv cqe: %d\n", cqe->res); + goto err; + } + if (!(cqe->flags & IORING_CQE_F_BUFFER)) { + fprintf(stderr, "no buffer set in recv\n"); + goto err; + } + if (!(cqe->flags & IORING_CQE_F_BUF_MORE)) { + fprintf(stderr, "CQE_F_BUF_MORE not set\n"); + goto err; + } + bid = cqe->flags >> IORING_CQE_BUFFER_SHIFT; + if (bid != 0) { + fprintf(stderr, "got bid %d\n", bid); + goto err; + } + if (!(verify_sz % MSG_SIZE)) { + if (!verify_seq(rd, verify_ptr, verify_sz, verify_bid)) + goto err; + verify_bid += verify_sz / MSG_SIZE; + verify_bid &= RECV_BID_MASK; + verify_sz = 0; + } else { + memcpy(verify_ptr + verify_sz, rd->recv_buf + (bid * MSG_SIZE), cqe->res); + verify_sz += cqe->res; + } + rd->recv_bytes -= cqe->res; + io_uring_cqe_seen(ring, cqe); + if (!(cqe->flags & IORING_CQE_F_MORE) && rd->recv_bytes) { + if (arm_recv(ring, rd)) + goto err; + } + } while (rd->recv_bytes); + + if (verify_sz && !(verify_sz % MSG_SIZE) && + !verify_seq(rd, verify_ptr, verify_sz, verify_bid)) + goto err; + + pthread_barrier_wait(&rd->finish); + return 0; +err: + pthread_barrier_wait(&rd->finish); + return 1; +} + +static void *recv_fn(void *data) +{ + struct recv_data *rd = data; + struct io_uring_params p = { }; + struct io_uring ring; + struct io_uring_buf_ring *br; + void *buf, *ptr; + int ret, sock; + + p.cq_entries = 4096; + p.flags = IORING_SETUP_CQSIZE; + io_uring_queue_init_params(16, &ring, &p); + + ret = 0; + if (posix_memalign(&buf, 4096, MSG_SIZE * RECV_BIDS)) + goto err; + + br = io_uring_setup_buf_ring(&ring, RECV_BIDS, RECV_BGID, IOU_PBUF_RING_INC, &ret); + if (!br) { + fprintf(stderr, "failed setting up recv ring %d\n", ret); + goto err; + } + + ptr = buf; + io_uring_buf_ring_add(br, ptr, MSG_SIZE * RECV_BIDS, 0, RECV_BID_MASK, 0); + io_uring_buf_ring_advance(br, 1); + rd->recv_buf = buf; + + ret = recv_prep(&ring, rd, &sock); + if (ret) { + fprintf(stderr, "recv_prep failed: %d\n", ret); + goto err; + } + + ret = do_recv(&ring, rd); + + close(sock); + close(rd->accept_fd); + free(buf); + io_uring_queue_exit(&ring); +err: + return (void *)(intptr_t)ret; +} + +static int __do_send_bundle(struct recv_data *rd, struct io_uring *ring, int sockfd) +{ + struct io_uring_cqe *cqe; + struct io_uring_sqe *sqe; + int bytes_needed = MSG_SIZE * nr_msgs; + int i, ret; + + sqe = io_uring_get_sqe(ring); + io_uring_prep_send_bundle(sqe, sockfd, 0, 0); + sqe->flags |= IOSQE_BUFFER_SELECT; + sqe->buf_group = SEND_BGID; + sqe->user_data = 1; + + ret = io_uring_submit(ring); + if (ret != 1) + return 1; + + pthread_barrier_wait(&rd->barrier); + + for (i = 0; i < nr_msgs; i++) { + ret = io_uring_wait_cqe(ring, &cqe); + if (ret) { + fprintf(stderr, "wait send: %d\n", ret); + return 1; + } + if (!i && cqe->res == -EINVAL) { + rd->abort = 1; + no_send_mshot = 1; + break; + } + if (cqe->res < 0) { + fprintf(stderr, "bad send cqe res: %d\n", cqe->res); + return 1; + } + bytes_needed -= cqe->res; + if (!bytes_needed) { + io_uring_cqe_seen(ring, cqe); + break; + } + if (!(cqe->flags & IORING_CQE_F_MORE)) { + fprintf(stderr, "expected more, but MORE not set\n"); + return 1; + } + io_uring_cqe_seen(ring, cqe); + } + + return 0; +} + +static int __do_send(struct recv_data *rd, struct io_uring *ring, int sockfd) +{ + struct io_uring_cqe *cqe; + struct io_uring_sqe *sqe; + int bytes_needed = MSG_SIZE * nr_msgs; + int i, ret; + + for (i = 0; i < nr_msgs; i++) { + sqe = io_uring_get_sqe(ring); + io_uring_prep_send(sqe, sockfd, NULL, 0, 0); + sqe->user_data = 10 + i; + sqe->flags |= IOSQE_BUFFER_SELECT; + sqe->buf_group = SEND_BGID; + + ret = io_uring_submit(ring); + if (ret != 1) + return 1; + + if (!i) + pthread_barrier_wait(&rd->barrier); + ret = io_uring_wait_cqe(ring, &cqe); + if (ret) { + fprintf(stderr, "send wait cqe %d\n", ret); + return 1; + } + + if (!i && cqe->res == -EINVAL) { + rd->abort = 1; + no_send_mshot = 1; + break; + } + if (cqe->res != MSG_SIZE) { + fprintf(stderr, "send failed cqe: %d\n", cqe->res); + return 1; + } + if (cqe->res < 0) { + fprintf(stderr, "bad send cqe res: %d\n", cqe->res); + return 1; + } + bytes_needed -= cqe->res; + io_uring_cqe_seen(ring, cqe); + if (!bytes_needed) + break; + } + + return 0; +} + +static int do_send(struct recv_data *rd) +{ + struct sockaddr_in saddr; + struct io_uring ring; + unsigned long seq_buf[SEQ_SIZE], send_seq; + struct io_uring_params p = { }; + struct io_uring_buf_ring *br; + int sockfd, ret, len, i; + socklen_t optlen; + void *buf, *ptr; + + ret = io_uring_queue_init_params(16, &ring, &p); + if (ret) { + fprintf(stderr, "queue init failed: %d\n", ret); + return 1; + } + if (!(p.features & IORING_FEAT_RECVSEND_BUNDLE)) { + no_send_mshot = 1; + return 0; + } + + if (posix_memalign(&buf, 4096, MSG_SIZE * nr_msgs)) + return 1; + + br = io_uring_setup_buf_ring(&ring, nr_msgs, SEND_BGID, 0, &ret); + if (!br) { + if (ret == -EINVAL) { + fprintf(stderr, "einval on br setup\n"); + return 0; + } + fprintf(stderr, "failed setting up send ring %d\n", ret); + return 1; + } + + ptr = buf; + for (i = 0; i < nr_msgs; i++) { + io_uring_buf_ring_add(br, ptr, MSG_SIZE, i, nr_msgs - 1, i); + ptr += MSG_SIZE; + } + io_uring_buf_ring_advance(br, nr_msgs); + + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; + saddr.sin_port = htons(use_port); + inet_pton(AF_INET, HOST, &saddr.sin_addr); + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + perror("socket"); + goto err2; + } + + pthread_barrier_wait(&rd->connect); + + ret = connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)); + if (ret < 0) { + perror("connect"); + goto err; + } + + pthread_barrier_wait(&rd->startup); + + optlen = sizeof(len); + len = 1024 * MSG_SIZE; + setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &len, optlen); + + /* almost fill queue, leave room for one message */ + send_seq = 0; + rd->to_eagain = 0; + while (rd->max_sends && rd->max_sends--) { + for (i = 0; i < SEQ_SIZE; i++) + seq_buf[i] = send_seq++; + + ret = send(sockfd, seq_buf, sizeof(seq_buf), MSG_DONTWAIT); + if (ret < 0) { + if (errno == EAGAIN) { + send_seq -= SEQ_SIZE; + break; + } + perror("send"); + return 1; + } else if (ret != sizeof(seq_buf)) { + fprintf(stderr, "short %d send\n", ret); + return 1; + } + + rd->to_eagain++; + rd->recv_bytes += sizeof(seq_buf); + } + + ptr = buf; + for (i = 0; i < nr_msgs; i++) { + unsigned long *pseq = ptr; + int j; + + for (j = 0; j < SEQ_SIZE; j++) + pseq[j] = send_seq++; + ptr += MSG_SIZE; + } + + /* prepare more messages, sending with bundle */ + rd->recv_bytes += (nr_msgs * MSG_SIZE); + if (rd->send_bundle) + ret = __do_send_bundle(rd, &ring, sockfd); + else + ret = __do_send(rd, &ring, sockfd); + if (ret) + goto err; + + pthread_barrier_wait(&rd->finish); + + close(sockfd); + free(buf); + io_uring_queue_exit(&ring); + return 0; + +err: + close(sockfd); +err2: + io_uring_queue_exit(&ring); + pthread_barrier_wait(&rd->finish); + return 1; +} + +static int test(int backlog, unsigned int max_sends, int *to_eagain, + int send_bundle, int recv_bundle) +{ + pthread_t recv_thread; + struct recv_data rd; + int ret; + void *retval; + + memset(&rd, 0, sizeof(rd)); + pthread_barrier_init(&rd.connect, NULL, 2); + pthread_barrier_init(&rd.startup, NULL, 2); + pthread_barrier_init(&rd.barrier, NULL, 2); + pthread_barrier_init(&rd.finish, NULL, 2); + rd.max_sends = max_sends; + if (to_eagain) + *to_eagain = 0; + + rd.send_bundle = send_bundle; + rd.recv_bundle = recv_bundle; + + ret = pthread_create(&recv_thread, NULL, recv_fn, &rd); + if (ret) { + fprintf(stderr, "Thread create failed: %d\n", ret); + return 1; + } + + ret = do_send(&rd); + if (no_send_mshot) + return 0; + + if (ret) + return ret; + + pthread_join(recv_thread, &retval); + if (to_eagain) + *to_eagain = rd.to_eagain; + return (intptr_t)retval; +} + +static int run_tests(void) +{ + int ret, eagain_hit; + + nr_msgs = NR_MIN_MSGS; + + /* test basic send bundle first */ + ret = test(0, 0, NULL, 0, 0); + if (ret) { + fprintf(stderr, "test a failed\n"); + return T_EXIT_FAIL; + } + if (no_send_mshot) + return T_EXIT_SKIP; + + /* test recv bundle */ + ret = test(0, 0, NULL, 0, 1); + if (ret) { + fprintf(stderr, "test b failed\n"); + return T_EXIT_FAIL; + } + + /* test bundling recv and send */ + ret = test(0, 0, NULL, 1, 1); + if (ret) { + fprintf(stderr, "test c failed\n"); + return T_EXIT_FAIL; + } + + /* test bundling with full socket */ + ret = test(1, 1000000, &eagain_hit, 1, 1); + if (ret) { + fprintf(stderr, "test d failed\n"); + return T_EXIT_FAIL; + } + + /* test bundling with almost full socket */ + ret = test(1, eagain_hit - (nr_msgs / 2), NULL, 1, 1); + if (ret) { + fprintf(stderr, "test e failed\n"); + return T_EXIT_FAIL; + } + + /* test recv bundle with almost full socket */ + ret = test(1, eagain_hit - (nr_msgs / 2), NULL, 0, 1); + if (ret) { + fprintf(stderr, "test f failed\n"); + return T_EXIT_FAIL; + } + + /* test send bundle with almost full socket */ + ret = test(1, eagain_hit - (nr_msgs / 2), &eagain_hit, 1, 0); + if (ret) { + fprintf(stderr, "test g failed\n"); + return T_EXIT_FAIL; + } + + /* now repeat the last three tests, but with > FAST_UIOV segments */ + nr_msgs = NR_MAX_MSGS; + + /* test bundling with almost full socket */ + ret = test(1, eagain_hit - (nr_msgs / 2), NULL, 1, 1); + if (ret) { + fprintf(stderr, "test h failed\n"); + return T_EXIT_FAIL; + } + + /* test recv bundle with almost full socket */ + ret = test(1, eagain_hit - (nr_msgs / 2), NULL, 0, 1); + if (ret) { + fprintf(stderr, "test i failed\n"); + return T_EXIT_FAIL; + } + + /* test send bundle with almost full socket */ + ret = test(1, eagain_hit - (nr_msgs / 2), &eagain_hit, 1, 0); + if (ret) { + fprintf(stderr, "test j failed\n"); + return T_EXIT_FAIL; + } + + return T_EXIT_PASS; +} + +static int test_tcp(void) +{ + int ret; + + ret = run_tests(); + if (ret == T_EXIT_FAIL) + fprintf(stderr, "TCP test case failed\n"); + return ret; +} + +static bool has_pbuf_ring_inc(void) +{ + struct io_uring_buf_ring *br; + bool has_pbuf_inc = false; + struct io_uring ring; + void *buf; + int ret; + + ret = io_uring_queue_init(1, &ring, 0); + if (ret) + return false; + + if (posix_memalign(&buf, 4096, MSG_SIZE * RECV_BIDS)) + return false; + + br = io_uring_setup_buf_ring(&ring, RECV_BIDS, RECV_BGID, IOU_PBUF_RING_INC, &ret); + if (br) { + has_pbuf_inc = true; + io_uring_unregister_buf_ring(&ring, RECV_BGID); + } + io_uring_queue_exit(&ring); + free(buf); + return has_pbuf_inc; +} + +int main(int argc, char *argv[]) +{ + int ret; + + if (argc > 1) + return T_EXIT_SKIP; + if (!has_pbuf_ring_inc()) + return T_EXIT_SKIP; + + ret = test_tcp(); + if (ret != T_EXIT_PASS) + return ret; + + return T_EXIT_PASS; +} diff --git a/contrib/libs/liburing/test/recvsend_bundle-inc.t/ya.make b/contrib/libs/liburing/test/recvsend_bundle-inc.t/ya.make new file mode 100644 index 0000000000..35c4f17c72 --- /dev/null +++ b/contrib/libs/liburing/test/recvsend_bundle-inc.t/ya.make @@ -0,0 +1,35 @@ +# Generated by devtools/yamaker. + +PROGRAM() + +WITHOUT_LICENSE_TEXTS() + +VERSION(2.8) + +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 + recvsend_bundle-inc.c +) + +END() diff --git a/contrib/libs/liburing/test/recvsend_bundle.c b/contrib/libs/liburing/test/recvsend_bundle.c index 8d4305e847..b1ed5b947a 100644 --- a/contrib/libs/liburing/test/recvsend_bundle.c +++ b/contrib/libs/liburing/test/recvsend_bundle.c @@ -20,6 +20,7 @@ static int nr_msgs; static int use_tcp; +static int classic_buffers; #define RECV_BIDS 8192 #define RECV_BID_MASK (RECV_BIDS - 1) @@ -114,6 +115,9 @@ static int recv_prep(struct io_uring *ring, struct recv_data *rd, int *sock) pthread_barrier_wait(&rd->connect); + if (rd->abort) + goto err; + socklen = sizeof(saddr); use_fd = accept(sockfd, (struct sockaddr *)&saddr, &socklen); if (use_fd < 0) { @@ -211,7 +215,7 @@ static int do_recv(struct io_uring *ring, struct recv_data *rd) fprintf(stderr, "got bid %d, wanted %d\n", bid, next_bid); goto err; } - if (!rd->recv_bundle && cqe->res != MSG_SIZE) { + if (!rd->recv_bundle && cqe->res > MSG_SIZE) { fprintf(stderr, "recv got wrong length: %d\n", cqe->res); goto err; } @@ -246,13 +250,36 @@ err: return 1; } +static int provide_classic_buffers(struct io_uring *ring, void *buf, int nbufs, int bgid) +{ + struct io_uring_sqe *sqe; + struct io_uring_cqe *cqe; + int ret; + + sqe = io_uring_get_sqe(ring); + io_uring_prep_provide_buffers(sqe, buf, MSG_SIZE, nbufs, bgid, 0); + io_uring_submit(ring); + + ret = io_uring_wait_cqe(ring, &cqe); + if (ret) { + fprintf(stderr, "provide buffer wait: %d\n", ret); + return 1; + } + if (cqe->res) { + fprintf(stderr, "provide buffers fail: %d\n", cqe->res); + return 1; + } + io_uring_cqe_seen(ring, cqe); + return 0; +} + static void *recv_fn(void *data) { struct recv_data *rd = data; struct io_uring_params p = { }; struct io_uring ring; struct io_uring_buf_ring *br; - void *buf, *ptr; + void *buf = NULL, *ptr; int ret, sock, i; p.cq_entries = 4096; @@ -268,19 +295,28 @@ static void *recv_fn(void *data) if (posix_memalign(&buf, 4096, MSG_SIZE * RECV_BIDS)) goto err; - br = io_uring_setup_buf_ring(&ring, RECV_BIDS, RECV_BGID, 0, &ret); - if (!br) { - fprintf(stderr, "failed setting up recv ring %d\n", ret); - goto err; - } + if (!classic_buffers) { + br = io_uring_setup_buf_ring(&ring, RECV_BIDS, RECV_BGID, 0, &ret); + if (!br) { + if (ret != -EINVAL) + fprintf(stderr, "failed setting up recv ring %d\n", ret); + goto err; + } - ptr = buf; - for (i = 0; i < RECV_BIDS; i++) { - io_uring_buf_ring_add(br, ptr, MSG_SIZE, i, RECV_BID_MASK, i); - ptr += MSG_SIZE; + ptr = buf; + for (i = 0; i < RECV_BIDS; i++) { + io_uring_buf_ring_add(br, ptr, MSG_SIZE, i, RECV_BID_MASK, i); + ptr += MSG_SIZE; + } + io_uring_buf_ring_advance(br, RECV_BIDS); + rd->recv_buf = buf; + } else { + ret = provide_classic_buffers(&ring, buf, RECV_BIDS, RECV_BGID); + if (ret) { + fprintf(stderr, "failed providing classic buffers\n"); + goto err; + } } - io_uring_buf_ring_advance(br, RECV_BIDS); - rd->recv_buf = buf; ret = recv_prep(&ring, rd, &sock); if (ret) { @@ -294,6 +330,7 @@ static void *recv_fn(void *data) close(rd->accept_fd); io_uring_queue_exit(&ring); err: + free(buf); return (void *)(intptr_t)ret; } @@ -403,7 +440,7 @@ static int do_send(struct recv_data *rd) struct io_uring_buf_ring *br; int sockfd, ret, len, i; socklen_t optlen; - void *buf, *ptr; + void *buf = NULL, *ptr; ret = io_uring_queue_init_params(16, &ring, &p); if (ret) { @@ -411,29 +448,39 @@ static int do_send(struct recv_data *rd) return 1; } if (!(p.features & IORING_FEAT_RECVSEND_BUNDLE)) { + rd->abort = 1; no_send_mshot = 1; + pthread_barrier_wait(&rd->connect); return 0; } if (posix_memalign(&buf, 4096, MSG_SIZE * nr_msgs)) return 1; - br = io_uring_setup_buf_ring(&ring, nr_msgs, SEND_BGID, 0, &ret); - if (!br) { - if (ret == -EINVAL) { - fprintf(stderr, "einval on br setup\n"); - return 0; + if (!classic_buffers) { + br = io_uring_setup_buf_ring(&ring, nr_msgs, SEND_BGID, 0, &ret); + if (!br) { + if (ret == -EINVAL) { + fprintf(stderr, "einval on br setup\n"); + return 0; + } + fprintf(stderr, "failed setting up send ring %d\n", ret); + return 1; } - fprintf(stderr, "failed setting up send ring %d\n", ret); - return 1; - } - ptr = buf; - for (i = 0; i < nr_msgs; i++) { - io_uring_buf_ring_add(br, ptr, MSG_SIZE, i, nr_msgs - 1, i); - ptr += MSG_SIZE; + ptr = buf; + for (i = 0; i < nr_msgs; i++) { + io_uring_buf_ring_add(br, ptr, MSG_SIZE, i, nr_msgs - 1, i); + ptr += MSG_SIZE; + } + io_uring_buf_ring_advance(br, nr_msgs); + } else { + ret = provide_classic_buffers(&ring, buf, nr_msgs, SEND_BGID); + if (ret) { + fprintf(stderr, "failed providing classic buffers\n"); + return ret; + } } - io_uring_buf_ring_advance(br, nr_msgs); memset(&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; @@ -510,6 +557,7 @@ static int do_send(struct recv_data *rd) close(sockfd); io_uring_queue_exit(&ring); + free(buf); return 0; err: @@ -517,6 +565,7 @@ err: err2: io_uring_queue_exit(&ring); pthread_barrier_wait(&rd->finish); + free(buf); return 1; } @@ -551,8 +600,12 @@ static int test(int backlog, unsigned int max_sends, int *to_eagain, } ret = do_send(&rd); - if (no_send_mshot) + if (no_send_mshot) { + fprintf(stderr, "no_send_mshot, aborting (ignore other errors)\n"); + rd.abort = 1; + pthread_join(recv_thread, &retval); return 0; + } if (ret) return ret; @@ -657,7 +710,7 @@ static int test_tcp(void) use_tcp = 1; ret = run_tests(false); if (ret == T_EXIT_FAIL) - fprintf(stderr, "TCP test case failed\n"); + fprintf(stderr, "TCP test case (classic=%d) failed\n", classic_buffers); return ret; } @@ -669,7 +722,7 @@ static int test_udp(void) use_port++; ret = run_tests(true); if (ret == T_EXIT_FAIL) - fprintf(stderr, "UDP test case failed\n"); + fprintf(stderr, "UDP test case (classic=%d) failed\n", classic_buffers); return ret; } @@ -688,5 +741,15 @@ int main(int argc, char *argv[]) if (ret != T_EXIT_PASS) return ret; + classic_buffers = 1; + + ret = test_tcp(); + if (ret != T_EXIT_PASS) + return ret; + + ret = test_udp(); + if (ret != T_EXIT_PASS) + return ret; + return T_EXIT_PASS; } diff --git a/contrib/libs/liburing/test/recvsend_bundle.t/ya.make b/contrib/libs/liburing/test/recvsend_bundle.t/ya.make index d4928a810d..81dadbb159 100644 --- a/contrib/libs/liburing/test/recvsend_bundle.t/ya.make +++ b/contrib/libs/liburing/test/recvsend_bundle.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/reg-fd-only.c b/contrib/libs/liburing/test/reg-fd-only.c index 1ff6ea250e..1c795e316c 100644 --- a/contrib/libs/liburing/test/reg-fd-only.c +++ b/contrib/libs/liburing/test/reg-fd-only.c @@ -50,14 +50,15 @@ static int test_nops(struct io_uring *ring, int sq_size, int nr_nops) return T_EXIT_PASS; } -static int test(int nentries) +static int test(int nentries, int ring_flags) { 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); + IORING_SETUP_REGISTERED_FD_ONLY | IORING_SETUP_NO_MMAP | + ring_flags); if (ret == -EINVAL) { no_mmap = 1; return T_EXIT_SKIP; @@ -65,7 +66,7 @@ static int test(int nentries) fprintf(stdout, "Enable huge pages to test big rings\n"); return T_EXIT_SKIP; } else if (ret) { - fprintf(stderr, "ring setup failed\n"); + fprintf(stderr, "ring setup failed: %d\n", ret); return T_EXIT_FAIL; } @@ -111,7 +112,16 @@ int main(int argc, char *argv[]) return T_EXIT_SKIP; /* test single normal page */ - ret = test(NORMAL_PAGE_ENTRIES); + ret = test(NORMAL_PAGE_ENTRIES, 0); + 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 single normal page */ + ret = test(NORMAL_PAGE_ENTRIES, IORING_SETUP_SQPOLL); if (ret == T_EXIT_SKIP || no_mmap) { return T_EXIT_SKIP; } else if (ret != T_EXIT_PASS) { @@ -120,7 +130,7 @@ int main(int argc, char *argv[]) } /* test with entries requiring a huge page */ - ret = test(HUGE_PAGE_ENTRIES); + ret = test(HUGE_PAGE_ENTRIES, 0); if (ret == T_EXIT_SKIP) { return T_EXIT_SKIP; } else if (ret != 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 index 373599e6c3..3d84cb51e0 100644 --- a/contrib/libs/liburing/test/reg-fd-only.t/ya.make +++ b/contrib/libs/liburing/test/reg-fd-only.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/reg-hint.t/ya.make b/contrib/libs/liburing/test/reg-hint.t/ya.make index 1aaaff7170..1c4788b6fd 100644 --- a/contrib/libs/liburing/test/reg-hint.t/ya.make +++ b/contrib/libs/liburing/test/reg-hint.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/reg-reg-ring.t/ya.make b/contrib/libs/liburing/test/reg-reg-ring.t/ya.make index 09fb918298..3eb7a743a1 100644 --- a/contrib/libs/liburing/test/reg-reg-ring.t/ya.make +++ b/contrib/libs/liburing/test/reg-reg-ring.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/regbuf-clone.c b/contrib/libs/liburing/test/regbuf-clone.c new file mode 100644 index 0000000000..9e49989554 --- /dev/null +++ b/contrib/libs/liburing/test/regbuf-clone.c @@ -0,0 +1,248 @@ +#include "../config-host.h" +/* SPDX-License-Identifier: MIT */ +/* + * Description: test buffer cloning between rings + * + */ +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/uio.h> + +#include "liburing.h" +#include "helpers.h" + +#define NR_VECS 64 +#define BUF_SIZE 8192 + +static int no_buf_clone; + +static int test(int reg_src, int reg_dst) +{ + struct iovec vecs[NR_VECS]; + struct io_uring src, dst; + int ret, i; + + ret = io_uring_queue_init(1, &src, 0); + if (ret) { + fprintf(stderr, "ring_init: %d\n", ret); + return T_EXIT_FAIL; + } + ret = io_uring_queue_init(1, &dst, 0); + if (ret) { + fprintf(stderr, "ring_init: %d\n", ret); + return T_EXIT_FAIL; + } + if (reg_src) { + ret = io_uring_register_ring_fd(&src); + if (ret < 0) { + if (ret == -EINVAL) + return T_EXIT_SKIP; + fprintf(stderr, "register ring: %d\n", ret); + return T_EXIT_FAIL; + } + } + if (reg_dst) { + ret = io_uring_register_ring_fd(&dst); + if (ret < 0) { + if (ret == -EINVAL) + return T_EXIT_SKIP; + fprintf(stderr, "register ring: %d\n", ret); + return T_EXIT_FAIL; + } + } + + /* test fail with no buffers in src */ + ret = io_uring_clone_buffers(&dst, &src); + if (ret == -EINVAL) { + /* no buffer copy support */ + no_buf_clone = true; + return T_EXIT_SKIP; + } else if (ret != -ENXIO) { + fprintf(stderr, "empty copy: %d\n", ret); + return T_EXIT_FAIL; + } + + for (i = 0; i < NR_VECS; i++) { + if (posix_memalign(&vecs[i].iov_base, 4096, BUF_SIZE)) + return T_EXIT_FAIL; + vecs[i].iov_len = BUF_SIZE; + } + + ret = io_uring_register_buffers(&src, vecs, NR_VECS); + if (ret < 0) { + if (ret == -ENOMEM) + return T_EXIT_SKIP; + return T_EXIT_FAIL; + } + + /* copy should work now */ + ret = io_uring_clone_buffers(&dst, &src); + if (ret) { + fprintf(stderr, "buffer copy: %d\n", ret); + return T_EXIT_FAIL; + } + + /* try copy again, should get -EBUSY */ + ret = io_uring_clone_buffers(&dst, &src); + if (ret != -EBUSY) { + fprintf(stderr, "busy copy: %d\n", ret); + return T_EXIT_FAIL; + } + + ret = io_uring_unregister_buffers(&dst); + if (ret) { + fprintf(stderr, "dst unregister buffers: %d\n", ret); + return T_EXIT_FAIL; + } + + ret = io_uring_unregister_buffers(&dst); + if (ret != -ENXIO) { + fprintf(stderr, "dst unregister empty buffers: %d\n", ret); + return T_EXIT_FAIL; + } + + ret = io_uring_unregister_buffers(&src); + if (ret) { + fprintf(stderr, "src unregister buffers: %d\n", ret); + return T_EXIT_FAIL; + } + + ret = io_uring_register_buffers(&dst, vecs, NR_VECS); + if (ret < 0) { + fprintf(stderr, "register buffers dst; %d\n", ret); + return T_EXIT_FAIL; + } + + ret = io_uring_clone_buffers(&src, &dst); + if (ret) { + fprintf(stderr, "buffer copy reverse: %d\n", ret); + return T_EXIT_FAIL; + } + + ret = io_uring_unregister_buffers(&dst); + if (ret) { + fprintf(stderr, "dst unregister buffers: %d\n", ret); + return T_EXIT_FAIL; + } + + ret = io_uring_unregister_buffers(&dst); + if (ret != -ENXIO) { + fprintf(stderr, "dst unregister empty buffers: %d\n", ret); + return T_EXIT_FAIL; + } + + ret = io_uring_unregister_buffers(&src); + if (ret) { + fprintf(stderr, "src unregister buffers: %d\n", ret); + return T_EXIT_FAIL; + } + + io_uring_queue_exit(&src); + io_uring_queue_exit(&dst); + + for (i = 0; i < NR_VECS; i++) + free(vecs[i].iov_base); + + return T_EXIT_PASS; +} + +static int test_dummy(void) +{ + struct iovec vec = { }; + struct io_uring src, dst; + int ret; + + ret = io_uring_queue_init(1, &src, 0); + if (ret) { + fprintf(stderr, "ring_init: %d\n", ret); + return T_EXIT_FAIL; + } + ret = io_uring_queue_init(1, &dst, 0); + if (ret) { + fprintf(stderr, "ring_init: %d\n", ret); + return T_EXIT_FAIL; + } + + ret = io_uring_register_buffers(&src, &vec, 1); + if (ret < 0) { + fprintf(stderr, "failed to register dummy buffer: %d\n", ret); + return T_EXIT_FAIL; + } + + ret = io_uring_clone_buffers(&dst, &src); + if (ret) { + fprintf(stderr, "clone dummy buf: %d\n", ret); + return T_EXIT_FAIL; + } + + ret = io_uring_unregister_buffers(&src); + if (ret) { + fprintf(stderr, "rsc unregister buffers: %d\n", ret); + return T_EXIT_FAIL; + } + + ret = io_uring_unregister_buffers(&dst); + if (ret) { + fprintf(stderr, "dst unregister buffers: %d\n", ret); + return T_EXIT_FAIL; + } + + io_uring_queue_exit(&src); + io_uring_queue_exit(&dst); + + return T_EXIT_PASS; +} + +int main(int argc, char *argv[]) +{ + int ret; + + if (argc > 1) + return T_EXIT_SKIP; + + ret = test(0, 0); + if (ret == T_EXIT_SKIP) { + return T_EXIT_SKIP; + } else if (ret != T_EXIT_PASS) { + fprintf(stderr, "test 0 0 failed\n"); + return T_EXIT_FAIL; + } + if (no_buf_clone) + return T_EXIT_SKIP; + + ret = test(0, 1); + if (ret == T_EXIT_SKIP) { + return T_EXIT_SKIP; + } else if (ret != T_EXIT_PASS) { + fprintf(stderr, "test 0 1 failed\n"); + return T_EXIT_FAIL; + } + + ret = test(1, 0); + if (ret == T_EXIT_SKIP) { + return T_EXIT_SKIP; + } else if (ret != T_EXIT_PASS) { + fprintf(stderr, "test 1 0 failed\n"); + return T_EXIT_FAIL; + } + + ret = test(1, 1); + if (ret == T_EXIT_SKIP) { + return T_EXIT_SKIP; + } else if (ret != T_EXIT_PASS) { + fprintf(stderr, "test 1 1 failed\n"); + return T_EXIT_FAIL; + } + + ret = test_dummy(); + if (ret == T_EXIT_SKIP) { + return T_EXIT_SKIP; + } else if (ret != T_EXIT_PASS) { + fprintf(stderr, "test_dummy failed\n"); + return T_EXIT_FAIL; + } + + return T_EXIT_PASS; +} diff --git a/contrib/libs/liburing/test/regbuf-clone.t/ya.make b/contrib/libs/liburing/test/regbuf-clone.t/ya.make new file mode 100644 index 0000000000..016640dcce --- /dev/null +++ b/contrib/libs/liburing/test/regbuf-clone.t/ya.make @@ -0,0 +1,35 @@ +# Generated by devtools/yamaker. + +PROGRAM() + +WITHOUT_LICENSE_TEXTS() + +VERSION(2.8) + +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 + regbuf-clone.c +) + +END() diff --git a/contrib/libs/liburing/test/regbuf-merge.c b/contrib/libs/liburing/test/regbuf-merge.c index bb2e1286cb..942d383a68 100644 --- a/contrib/libs/liburing/test/regbuf-merge.c +++ b/contrib/libs/liburing/test/regbuf-merge.c @@ -14,6 +14,7 @@ #include "helpers.h" +#ifndef CONFIG_USE_SANITIZER #ifndef __NR_io_uring_register #define __NR_io_uring_register 427 #endif @@ -90,3 +91,9 @@ int main(int argc, char *argv[]) syscall(__NR_io_uring_register, r[0], 0ul, 0x20002840ul, 2ul); return T_EXIT_PASS; } +#else +int main(int argc, char *argv[]) +{ + return T_EXIT_SKIP; +} +#endif diff --git a/contrib/libs/liburing/test/regbuf-merge.t/ya.make b/contrib/libs/liburing/test/regbuf-merge.t/ya.make index 1a108c6c3e..ee4f314adc 100644 --- a/contrib/libs/liburing/test/regbuf-merge.t/ya.make +++ b/contrib/libs/liburing/test/regbuf-merge.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/register-restrictions.c b/contrib/libs/liburing/test/register-restrictions.c index af35db4b4a..974daa2961 100644 --- a/contrib/libs/liburing/test/register-restrictions.c +++ b/contrib/libs/liburing/test/register-restrictions.c @@ -14,12 +14,7 @@ #include <sys/eventfd.h> #include "liburing.h" - -enum { - TEST_OK, - TEST_SKIPPED, - TEST_FAILED -}; +#include "helpers.h" static int test_restrictions_sqe_op(void) { @@ -37,15 +32,15 @@ static int test_restrictions_sqe_op(void) if (pipe(pipe1) != 0) { perror("pipe"); - return TEST_FAILED; + return T_EXIT_FAIL; } ret = io_uring_queue_init(8, &ring, IORING_SETUP_R_DISABLED); if (ret) { if (ret == -EINVAL) - return TEST_SKIPPED; + return T_EXIT_SKIP; fprintf(stderr, "ring setup failed: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } res[0].opcode = IORING_RESTRICTION_SQE_OP; @@ -57,16 +52,16 @@ static int test_restrictions_sqe_op(void) ret = io_uring_register_restrictions(&ring, res, 2); if (ret) { if (ret == -EINVAL) - return TEST_SKIPPED; + return T_EXIT_SKIP; fprintf(stderr, "failed to register restrictions: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } ret = io_uring_enable_rings(&ring); if (ret) { fprintf(stderr, "ring enabling failed: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } sqe = io_uring_get_sqe(&ring); @@ -80,28 +75,28 @@ static int test_restrictions_sqe_op(void) ret = io_uring_submit(&ring); if (ret != 2) { fprintf(stderr, "submit: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } for (int i = 0; i < 2; i++) { ret = io_uring_wait_cqe(&ring, &cqe); if (ret) { fprintf(stderr, "wait: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } switch (cqe->user_data) { case 1: /* writev */ if (cqe->res != sizeof(ptr)) { fprintf(stderr, "write res: %d\n", cqe->res); - return TEST_FAILED; + return T_EXIT_FAIL; } break; case 2: /* readv should be denied */ if (cqe->res != -EACCES) { fprintf(stderr, "read res: %d\n", cqe->res); - return TEST_FAILED; + return T_EXIT_FAIL; } break; } @@ -109,7 +104,7 @@ static int test_restrictions_sqe_op(void) } io_uring_queue_exit(&ring); - return TEST_OK; + return T_EXIT_PASS; } static int test_restrictions_register_op(void) @@ -126,13 +121,13 @@ static int test_restrictions_register_op(void) if (pipe(pipe1) != 0) { perror("pipe"); - return TEST_FAILED; + return T_EXIT_FAIL; } ret = io_uring_queue_init(8, &ring, IORING_SETUP_R_DISABLED); if (ret) { fprintf(stderr, "ring setup failed: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } res[0].opcode = IORING_RESTRICTION_REGISTER_OP; @@ -141,32 +136,32 @@ static int test_restrictions_register_op(void) ret = io_uring_register_restrictions(&ring, res, 1); if (ret) { if (ret == -EINVAL) - return TEST_SKIPPED; + return T_EXIT_SKIP; fprintf(stderr, "failed to register restrictions: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } ret = io_uring_enable_rings(&ring); if (ret) { fprintf(stderr, "ring enabling failed: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } ret = io_uring_register_buffers(&ring, &vec, 1); if (ret) { fprintf(stderr, "io_uring_register_buffers failed: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } ret = io_uring_register_files(&ring, pipe1, 2); if (ret != -EACCES) { fprintf(stderr, "io_uring_register_files ret: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } io_uring_queue_exit(&ring); - return TEST_OK; + return T_EXIT_PASS; } static int test_restrictions_fixed_file(void) @@ -185,13 +180,13 @@ static int test_restrictions_fixed_file(void) if (pipe(pipe1) != 0) { perror("pipe"); - return TEST_FAILED; + return T_EXIT_FAIL; } ret = io_uring_queue_init(8, &ring, IORING_SETUP_R_DISABLED); if (ret) { fprintf(stderr, "ring setup failed: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } res[0].opcode = IORING_RESTRICTION_SQE_OP; @@ -209,22 +204,22 @@ static int test_restrictions_fixed_file(void) ret = io_uring_register_restrictions(&ring, res, 4); if (ret) { if (ret == -EINVAL) - return TEST_SKIPPED; + return T_EXIT_SKIP; fprintf(stderr, "failed to register restrictions: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } ret = io_uring_enable_rings(&ring); if (ret) { fprintf(stderr, "ring enabling failed: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } ret = io_uring_register_files(&ring, pipe1, 2); if (ret) { fprintf(stderr, "io_uring_register_files ret: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } sqe = io_uring_get_sqe(&ring); @@ -244,34 +239,34 @@ static int test_restrictions_fixed_file(void) ret = io_uring_submit(&ring); if (ret != 3) { fprintf(stderr, "submit: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } for (int i = 0; i < 3; i++) { ret = io_uring_wait_cqe(&ring, &cqe); if (ret) { fprintf(stderr, "wait: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } switch (cqe->user_data) { case 1: /* writev */ if (cqe->res != sizeof(ptr)) { fprintf(stderr, "write res: %d\n", cqe->res); - return TEST_FAILED; + return T_EXIT_FAIL; } break; case 2: /* readv */ if (cqe->res != sizeof(ptr)) { fprintf(stderr, "read res: %d\n", cqe->res); - return TEST_FAILED; + return T_EXIT_FAIL; } break; case 3: /* writev without fixed_file should be denied */ if (cqe->res != -EACCES) { fprintf(stderr, "write res: %d\n", cqe->res); - return TEST_FAILED; + return T_EXIT_FAIL; } break; } @@ -279,7 +274,7 @@ static int test_restrictions_fixed_file(void) } io_uring_queue_exit(&ring); - return TEST_OK; + return T_EXIT_PASS; } static int test_restrictions_flags(void) @@ -298,13 +293,13 @@ static int test_restrictions_flags(void) if (pipe(pipe1) != 0) { perror("pipe"); - return TEST_FAILED; + return T_EXIT_FAIL; } ret = io_uring_queue_init(8, &ring, IORING_SETUP_R_DISABLED); if (ret) { fprintf(stderr, "ring setup failed: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } res[0].opcode = IORING_RESTRICTION_SQE_OP; @@ -319,22 +314,22 @@ static int test_restrictions_flags(void) ret = io_uring_register_restrictions(&ring, res, 3); if (ret) { if (ret == -EINVAL) - return TEST_SKIPPED; + return T_EXIT_SKIP; fprintf(stderr, "failed to register restrictions: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } ret = io_uring_register_files(&ring, pipe1, 2); if (ret) { fprintf(stderr, "io_uring_register_files ret: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } ret = io_uring_enable_rings(&ring); if (ret) { fprintf(stderr, "ring enabling failed: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } sqe = io_uring_get_sqe(&ring); @@ -355,7 +350,7 @@ static int test_restrictions_flags(void) ret = io_uring_submit(&ring); if (ret != 3) { fprintf(stderr, "submit: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } sqe = io_uring_get_sqe(&ring); @@ -366,7 +361,7 @@ static int test_restrictions_flags(void) ret = io_uring_submit(&ring); if (ret != 1) { fprintf(stderr, "submit: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } sqe = io_uring_get_sqe(&ring); @@ -377,7 +372,7 @@ static int test_restrictions_flags(void) ret = io_uring_submit(&ring); if (ret != 1) { fprintf(stderr, "submit: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } sqe = io_uring_get_sqe(&ring); @@ -388,7 +383,7 @@ static int test_restrictions_flags(void) ret = io_uring_submit(&ring); if (ret != 1) { fprintf(stderr, "submit: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } sqe = io_uring_get_sqe(&ring); @@ -398,14 +393,14 @@ static int test_restrictions_flags(void) ret = io_uring_submit(&ring); if (ret != 1) { fprintf(stderr, "submit: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } for (int i = 0; i < 7; i++) { ret = io_uring_wait_cqe(&ring, &cqe); if (ret) { fprintf(stderr, "wait: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } switch (cqe->user_data) { @@ -415,7 +410,7 @@ static int test_restrictions_flags(void) if (cqe->res != sizeof(ptr)) { fprintf(stderr, "write res: %d user_data %" PRIu64 "\n", cqe->res, (uint64_t) cqe->user_data); - return TEST_FAILED; + return T_EXIT_FAIL; } break; @@ -426,7 +421,7 @@ static int test_restrictions_flags(void) if (cqe->res != -EACCES) { fprintf(stderr, "write res: %d user_data %" PRIu64 "\n", cqe->res, (uint64_t) cqe->user_data); - return TEST_FAILED; + return T_EXIT_FAIL; } break; } @@ -434,7 +429,7 @@ static int test_restrictions_flags(void) } io_uring_queue_exit(&ring); - return TEST_OK; + return T_EXIT_PASS; } static int test_restrictions_empty(void) @@ -453,40 +448,40 @@ static int test_restrictions_empty(void) if (pipe(pipe1) != 0) { perror("pipe"); - return TEST_FAILED; + return T_EXIT_FAIL; } ret = io_uring_queue_init(8, &ring, IORING_SETUP_R_DISABLED); if (ret) { fprintf(stderr, "ring setup failed: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } ret = io_uring_register_restrictions(&ring, res, 0); if (ret) { if (ret == -EINVAL) - return TEST_SKIPPED; + return T_EXIT_SKIP; fprintf(stderr, "failed to register restrictions: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } ret = io_uring_enable_rings(&ring); if (ret) { fprintf(stderr, "ring enabling failed: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } ret = io_uring_register_buffers(&ring, &vec, 1); if (ret != -EACCES) { fprintf(stderr, "io_uring_register_buffers ret: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } ret = io_uring_register_files(&ring, pipe1, 2); if (ret != -EACCES) { fprintf(stderr, "io_uring_register_files ret: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } sqe = io_uring_get_sqe(&ring); @@ -495,24 +490,24 @@ static int test_restrictions_empty(void) ret = io_uring_submit(&ring); if (ret != 1) { fprintf(stderr, "submit: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } ret = io_uring_wait_cqe(&ring, &cqe); if (ret) { fprintf(stderr, "wait: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } if (cqe->res != -EACCES) { fprintf(stderr, "write res: %d\n", cqe->res); - return TEST_FAILED; + return T_EXIT_FAIL; } io_uring_cqe_seen(&ring, cqe); io_uring_queue_exit(&ring); - return TEST_OK; + return T_EXIT_PASS; } static int test_restrictions_rings_not_disabled(void) @@ -524,7 +519,7 @@ static int test_restrictions_rings_not_disabled(void) ret = io_uring_queue_init(8, &ring, 0); if (ret) { fprintf(stderr, "ring setup failed: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } res[0].opcode = IORING_RESTRICTION_SQE_OP; @@ -534,11 +529,11 @@ static int test_restrictions_rings_not_disabled(void) if (ret != -EBADFD) { fprintf(stderr, "io_uring_register_restrictions ret: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } io_uring_queue_exit(&ring); - return TEST_OK; + return T_EXIT_PASS; } static int test_restrictions_rings_disabled(void) @@ -550,7 +545,7 @@ static int test_restrictions_rings_disabled(void) ret = io_uring_queue_init(8, &ring, IORING_SETUP_R_DISABLED); if (ret) { fprintf(stderr, "ring setup failed: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } sqe = io_uring_get_sqe(&ring); @@ -559,11 +554,11 @@ static int test_restrictions_rings_disabled(void) ret = io_uring_submit(&ring); if (ret != -EBADFD) { fprintf(stderr, "submit: %d\n", ret); - return TEST_FAILED; + return T_EXIT_FAIL; } io_uring_queue_exit(&ring); - return TEST_OK; + return T_EXIT_PASS; } int main(int argc, char *argv[]) @@ -574,61 +569,67 @@ int main(int argc, char *argv[]) return 0; ret = test_restrictions_sqe_op(); - if (ret == TEST_SKIPPED) { + if (ret == T_EXIT_SKIP) { printf("test_restrictions_sqe_op: skipped\n"); - return 0; - } else if (ret == TEST_FAILED) { + return T_EXIT_SKIP; + } else if (ret == T_EXIT_FAIL) { fprintf(stderr, "test_restrictions_sqe_op failed\n"); return ret; } ret = test_restrictions_register_op(); - if (ret == TEST_SKIPPED) { + if (ret == T_EXIT_SKIP) { printf("test_restrictions_register_op: skipped\n"); - } else if (ret == TEST_FAILED) { + return T_EXIT_SKIP; + } else if (ret == T_EXIT_FAIL) { fprintf(stderr, "test_restrictions_register_op failed\n"); return ret; } ret = test_restrictions_fixed_file(); - if (ret == TEST_SKIPPED) { + if (ret == T_EXIT_SKIP) { printf("test_restrictions_fixed_file: skipped\n"); - } else if (ret == TEST_FAILED) { + return T_EXIT_SKIP; + } else if (ret == T_EXIT_FAIL) { fprintf(stderr, "test_restrictions_fixed_file failed\n"); return ret; } ret = test_restrictions_flags(); - if (ret == TEST_SKIPPED) { + if (ret == T_EXIT_SKIP) { printf("test_restrictions_flags: skipped\n"); - } else if (ret == TEST_FAILED) { + return T_EXIT_SKIP; + } else if (ret == T_EXIT_FAIL) { fprintf(stderr, "test_restrictions_flags failed\n"); return ret; } ret = test_restrictions_empty(); - if (ret == TEST_SKIPPED) { + if (ret == T_EXIT_SKIP) { printf("test_restrictions_empty: skipped\n"); - } else if (ret == TEST_FAILED) { + return T_EXIT_SKIP; + } else if (ret == T_EXIT_FAIL) { fprintf(stderr, "test_restrictions_empty failed\n"); return ret; } ret = test_restrictions_rings_not_disabled(); - if (ret == TEST_SKIPPED) { + if (ret == T_EXIT_SKIP) { printf("test_restrictions_rings_not_disabled: skipped\n"); - } else if (ret == TEST_FAILED) { + return T_EXIT_SKIP; + } else if (ret == T_EXIT_FAIL) { fprintf(stderr, "test_restrictions_rings_not_disabled failed\n"); return ret; } ret = test_restrictions_rings_disabled(); - if (ret == TEST_SKIPPED) { + if (ret == T_EXIT_SKIP) { printf("test_restrictions_rings_disabled: skipped\n"); - } else if (ret == TEST_FAILED) { + return T_EXIT_SKIP; + } else if (ret == T_EXIT_FAIL) { fprintf(stderr, "test_restrictions_rings_disabled failed\n"); return ret; } - return 0; + return T_EXIT_PASS; } diff --git a/contrib/libs/liburing/test/register-restrictions.t/ya.make b/contrib/libs/liburing/test/register-restrictions.t/ya.make index 6e5e8b92ee..cb64fc0194 100644 --- a/contrib/libs/liburing/test/register-restrictions.t/ya.make +++ b/contrib/libs/liburing/test/register-restrictions.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/rename.c b/contrib/libs/liburing/test/rename.c index d11ad17b33..230eb466f5 100644 --- a/contrib/libs/liburing/test/rename.c +++ b/contrib/libs/liburing/test/rename.c @@ -14,6 +14,51 @@ #include "liburing.h" +/* test using a bad address for either old or new path */ +static int test_rename_badaddr(struct io_uring *ring, bool bad_old) +{ + struct io_uring_cqe *cqe; + struct io_uring_sqe *sqe; + const char *path = ".foo.bar"; + const char *old, *new; + int ret; + + if (bad_old) { + old = (void *) (uintptr_t) 0x1234; + new = path; + } else { + old = path; + new = (void *) (uintptr_t) 0x1234; + } + + sqe = io_uring_get_sqe(ring); + if (!sqe) { + fprintf(stderr, "get sqe failed\n"); + goto err; + } + + memset(sqe, 0, sizeof(*sqe)); + + io_uring_prep_rename(sqe, old, new); + + 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 test_rename(struct io_uring *ring, const char *old, const char *new) { struct io_uring_cqe *cqe; @@ -29,7 +74,7 @@ static int test_rename(struct io_uring *ring, const char *old, const char *new) memset(sqe, 0, sizeof(*sqe)); io_uring_prep_rename(sqe, old, new); - + ret = io_uring_submit(ring); if (ret <= 0) { fprintf(stderr, "sqe submit failed: %d\n", ret); @@ -123,6 +168,19 @@ int main(int argc, char *argv[]) fprintf(stderr, "test_rename invalid failed: %d\n", ret); return ret; } + + ret = test_rename_badaddr(&ring, 0); + if (ret != -EFAULT) { + fprintf(stderr, "test_badaddr 0 failed: %d\n", ret); + return ret; + } + + ret = test_rename_badaddr(&ring, 1); + if (ret != -EFAULT) { + fprintf(stderr, "test_badaddr 1 failed: %d\n", ret); + return ret; + } + out: unlink(dst); return 0; diff --git a/contrib/libs/liburing/test/rename.t/ya.make b/contrib/libs/liburing/test/rename.t/ya.make index 2c782d7d0a..eea4a265ae 100644 --- a/contrib/libs/liburing/test/rename.t/ya.make +++ b/contrib/libs/liburing/test/rename.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/ring-leak.t/ya.make b/contrib/libs/liburing/test/ring-leak.t/ya.make index bb0c0ded49..c0230f3efa 100644 --- a/contrib/libs/liburing/test/ring-leak.t/ya.make +++ b/contrib/libs/liburing/test/ring-leak.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/ring-leak2.t/ya.make b/contrib/libs/liburing/test/ring-leak2.t/ya.make index 720bef28bc..e35f5e3c10 100644 --- a/contrib/libs/liburing/test/ring-leak2.t/ya.make +++ b/contrib/libs/liburing/test/ring-leak2.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/ringbuf-read.c b/contrib/libs/liburing/test/ringbuf-read.c index 5ff6738b04..7cec7b5a57 100644 --- a/contrib/libs/liburing/test/ringbuf-read.c +++ b/contrib/libs/liburing/test/ringbuf-read.c @@ -60,6 +60,8 @@ static int test(const char *filename, int dio, int async) fd = open(filename, O_RDONLY); } if (fd < 0) { + if (errno == EPERM || errno == EACCES) + return T_EXIT_SKIP; perror("open"); return 1; } @@ -124,6 +126,7 @@ static int test(const char *filename, int dio, int async) if (verify_buffer(buf + ((bid - 1) * BUF_SIZE), ud)) return 1; } + free(buf); return 0; } @@ -145,6 +148,8 @@ int main(int argc, char *argv[]) fd = open(fname, O_WRONLY); if (fd < 0) { + if (errno == EPERM || errno == EACCES) + return T_EXIT_SKIP; perror("open"); goto err; } diff --git a/contrib/libs/liburing/test/ringbuf-read.t/ya.make b/contrib/libs/liburing/test/ringbuf-read.t/ya.make index 894e741045..a04fed0d1a 100644 --- a/contrib/libs/liburing/test/ringbuf-read.t/ya.make +++ b/contrib/libs/liburing/test/ringbuf-read.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/ringbuf-status.c b/contrib/libs/liburing/test/ringbuf-status.c index d4a56c7473..88b6e8a47a 100644 --- a/contrib/libs/liburing/test/ringbuf-status.c +++ b/contrib/libs/liburing/test/ringbuf-status.c @@ -110,6 +110,7 @@ static int test(int invalid) if (!br) { if (ret == -EINVAL) { no_buf_ring = 1; + free(buf); return 0; } fprintf(stderr, "Buffer ring register failed %d\n", ret); @@ -132,10 +133,13 @@ static int test(int invalid) if (ret) { if (ret == -EINVAL) { no_buf_ring_status = 1; + free(buf); return T_EXIT_SKIP; } - if (invalid && ret == -ENOENT) + if (invalid && ret == -ENOENT) { + free(buf); return T_EXIT_PASS; + } fprintf(stderr, "buf_ring_head: %d\n", ret); return T_EXIT_FAIL; } diff --git a/contrib/libs/liburing/test/ringbuf-status.t/ya.make b/contrib/libs/liburing/test/ringbuf-status.t/ya.make index 5c45952a94..854af2e2ae 100644 --- a/contrib/libs/liburing/test/ringbuf-status.t/ya.make +++ b/contrib/libs/liburing/test/ringbuf-status.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/rsrc_tags.t/ya.make b/contrib/libs/liburing/test/rsrc_tags.t/ya.make index 7ad3a073e8..58c661f865 100644 --- a/contrib/libs/liburing/test/rsrc_tags.t/ya.make +++ b/contrib/libs/liburing/test/rsrc_tags.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/rw_merge_test.t/ya.make b/contrib/libs/liburing/test/rw_merge_test.t/ya.make index 408f4de290..25088065c8 100644 --- a/contrib/libs/liburing/test/rw_merge_test.t/ya.make +++ b/contrib/libs/liburing/test/rw_merge_test.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/self.t/ya.make b/contrib/libs/liburing/test/self.t/ya.make index d5a5f0ddc6..fb2ee7c203 100644 --- a/contrib/libs/liburing/test/self.t/ya.make +++ b/contrib/libs/liburing/test/self.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/send-zerocopy.c b/contrib/libs/liburing/test/send-zerocopy.c index 75149d55d3..4cc7e813e6 100644 --- a/contrib/libs/liburing/test/send-zerocopy.c +++ b/contrib/libs/liburing/test/send-zerocopy.c @@ -647,7 +647,8 @@ static int test_inet_send(struct io_uring *ring) if (!buffers_iov[buf_index].iov_base) continue; - if (!tcp && len > 4 * page_sz) + /* UDP IPv4 max datagram size is under 64K */ + if (!tcp && len > (1U << 15)) continue; conf.buf_index = buf_index; @@ -739,6 +740,59 @@ static int test_async_addr(struct io_uring *ring) return 0; } +static int test_sendzc_report(struct io_uring *ring) +{ + struct io_uring_sqe *sqe; + struct io_uring_cqe *cqe; + struct sockaddr_storage addr; + int sock_tx, sock_rx; + int ret; + + ret = create_socketpair_ip(&addr, &sock_tx, &sock_rx, true, true, false, true); + if (ret) { + fprintf(stderr, "sock prep failed %d\n", ret); + return 1; + } + + sqe = io_uring_get_sqe(ring); + io_uring_prep_send_zc(sqe, sock_tx, tx_buffer, 1, 0, + IORING_SEND_ZC_REPORT_USAGE); + ret = io_uring_submit(ring); + if (ret != 1) { + fprintf(stderr, "io_uring_submit failed %i\n", ret); + return 1; + } + ret = io_uring_wait_cqe(ring, &cqe); + if (ret) { + fprintf(stderr, "io_uring_wait_cqe failed %i\n", ret); + return 1; + } + if (cqe->res != 1 && cqe->res != -EINVAL) { + fprintf(stderr, "sendzc report failed %u\n", cqe->res); + return 1; + } + if (!(cqe->flags & IORING_CQE_F_MORE)) { + fprintf(stderr, "expected notification %i\n", cqe->res); + return 1; + } + io_uring_cqe_seen(ring, cqe); + + ret = io_uring_wait_cqe(ring, &cqe); + if (ret) { + fprintf(stderr, "io_uring_wait_cqe failed %i\n", ret); + return 1; + } + if (cqe->flags & IORING_CQE_F_MORE) { + fprintf(stderr, "F_MORE after notification\n"); + return 1; + } + io_uring_cqe_seen(ring, cqe); + + close(sock_tx); + close(sock_rx); + return 0; +} + /* see also send_recv.c:test_invalid */ static int test_invalid_zc(int fds[2]) { @@ -833,6 +887,12 @@ static int run_basic_tests(void) return T_EXIT_FAIL; } + ret = test_sendzc_report(&ring); + if (ret) { + fprintf(stderr, "test_sendzc_report() failed\n"); + return T_EXIT_FAIL; + } + io_uring_queue_exit(&ring); } diff --git a/contrib/libs/liburing/test/send-zerocopy.t/ya.make b/contrib/libs/liburing/test/send-zerocopy.t/ya.make index 8488fd09ad..d6af232525 100644 --- a/contrib/libs/liburing/test/send-zerocopy.t/ya.make +++ b/contrib/libs/liburing/test/send-zerocopy.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/send_recv.t/ya.make b/contrib/libs/liburing/test/send_recv.t/ya.make index 9ebfd4beb7..45a35c05a2 100644 --- a/contrib/libs/liburing/test/send_recv.t/ya.make +++ b/contrib/libs/liburing/test/send_recv.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/send_recvmsg.t/ya.make b/contrib/libs/liburing/test/send_recvmsg.t/ya.make index 819cfe1e8f..91263afd59 100644 --- a/contrib/libs/liburing/test/send_recvmsg.t/ya.make +++ b/contrib/libs/liburing/test/send_recvmsg.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/shared-wq.t/ya.make b/contrib/libs/liburing/test/shared-wq.t/ya.make index 7d6ec12f79..f1d0979e8e 100644 --- a/contrib/libs/liburing/test/shared-wq.t/ya.make +++ b/contrib/libs/liburing/test/shared-wq.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/short-read.c b/contrib/libs/liburing/test/short-read.c index cd8c1644f8..e9b4b20827 100644 --- a/contrib/libs/liburing/test/short-read.c +++ b/contrib/libs/liburing/test/short-read.c @@ -72,5 +72,6 @@ int main(int argc, char *argv[]) } io_uring_cqe_seen(&ring, cqe); + free(vec.iov_base); return 0; } diff --git a/contrib/libs/liburing/test/short-read.t/ya.make b/contrib/libs/liburing/test/short-read.t/ya.make index 20b7807f6a..254e93b6d3 100644 --- a/contrib/libs/liburing/test/short-read.t/ya.make +++ b/contrib/libs/liburing/test/short-read.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/shutdown.t/ya.make b/contrib/libs/liburing/test/shutdown.t/ya.make index 4f388e64a6..8ddc04ac60 100644 --- a/contrib/libs/liburing/test/shutdown.t/ya.make +++ b/contrib/libs/liburing/test/shutdown.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/sigfd-deadlock.t/ya.make b/contrib/libs/liburing/test/sigfd-deadlock.t/ya.make index 923d05efa3..13f2a770f7 100644 --- a/contrib/libs/liburing/test/sigfd-deadlock.t/ya.make +++ b/contrib/libs/liburing/test/sigfd-deadlock.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/single-issuer.t/ya.make b/contrib/libs/liburing/test/single-issuer.t/ya.make index 22b9933c40..1e84c75510 100644 --- a/contrib/libs/liburing/test/single-issuer.t/ya.make +++ b/contrib/libs/liburing/test/single-issuer.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/skip-cqe.t/ya.make b/contrib/libs/liburing/test/skip-cqe.t/ya.make index b2d5c9ae5a..a4445c9e20 100644 --- a/contrib/libs/liburing/test/skip-cqe.t/ya.make +++ b/contrib/libs/liburing/test/skip-cqe.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/socket-getsetsock-cmd.t/ya.make b/contrib/libs/liburing/test/socket-getsetsock-cmd.t/ya.make index 17a58600d7..dc3b688a0b 100644 --- a/contrib/libs/liburing/test/socket-getsetsock-cmd.t/ya.make +++ b/contrib/libs/liburing/test/socket-getsetsock-cmd.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/socket-io-cmd.t/ya.make b/contrib/libs/liburing/test/socket-io-cmd.t/ya.make index 1bef521386..83a0249549 100644 --- a/contrib/libs/liburing/test/socket-io-cmd.t/ya.make +++ b/contrib/libs/liburing/test/socket-io-cmd.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/socket-rw-eagain.t/ya.make b/contrib/libs/liburing/test/socket-rw-eagain.t/ya.make index b8be4cd81a..420451f607 100644 --- a/contrib/libs/liburing/test/socket-rw-eagain.t/ya.make +++ b/contrib/libs/liburing/test/socket-rw-eagain.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/socket-rw-offset.t/ya.make b/contrib/libs/liburing/test/socket-rw-offset.t/ya.make index 58f6331b37..814cb935b0 100644 --- a/contrib/libs/liburing/test/socket-rw-offset.t/ya.make +++ b/contrib/libs/liburing/test/socket-rw-offset.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/socket-rw.t/ya.make b/contrib/libs/liburing/test/socket-rw.t/ya.make index df06bc4449..336701e98b 100644 --- a/contrib/libs/liburing/test/socket-rw.t/ya.make +++ b/contrib/libs/liburing/test/socket-rw.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/socket.c b/contrib/libs/liburing/test/socket.c index b4514e3154..d33fad4997 100644 --- a/contrib/libs/liburing/test/socket.c +++ b/contrib/libs/liburing/test/socket.c @@ -366,6 +366,43 @@ static int test(int use_sqthread, int regfiles, int socket_direct, int alloc) return (intptr_t)retval; } +static int test_bad_socket(void) +{ + struct io_uring ring; + struct io_uring_cqe *cqe; + struct io_uring_sqe *sqe; + int ret; + + ret = io_uring_queue_init(1, &ring, 0); + if (ret) { + fprintf(stderr, "queue init failed: %d\n", ret); + return 1; + } + + sqe = io_uring_get_sqe(&ring); + io_uring_prep_socket(sqe, -1, SOCK_DGRAM, 0, 0); + ret = io_uring_submit(&ring); + if (ret != 1) { + fprintf(stderr, "socket submit: %d\n", ret); + goto err; + } + ret = io_uring_wait_cqe(&ring, &cqe); + if (ret) { + fprintf(stderr, "wait_cqe: %d\n", ret); + goto err; + } + if (cqe->res != -EAFNOSUPPORT) { + fprintf(stderr, "socket res: %d\n", cqe->res); + goto err; + } + io_uring_cqe_seen(&ring, cqe); + io_uring_queue_exit(&ring); + return 0; +err: + io_uring_queue_exit(&ring); + return 1; +} + int main(int argc, char *argv[]) { int ret; @@ -405,5 +442,11 @@ int main(int argc, char *argv[]) return ret; } + ret = test_bad_socket(); + if (ret) { + fprintf(stderr, "test bad socket failed\n"); + return 1; + } + return 0; } diff --git a/contrib/libs/liburing/test/socket.t/ya.make b/contrib/libs/liburing/test/socket.t/ya.make index 598bf99516..54d72000a2 100644 --- a/contrib/libs/liburing/test/socket.t/ya.make +++ b/contrib/libs/liburing/test/socket.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/splice.c b/contrib/libs/liburing/test/splice.c index d4042a8fdb..b614cbf25a 100644 --- a/contrib/libs/liburing/test/splice.c +++ b/contrib/libs/liburing/test/splice.c @@ -192,7 +192,7 @@ static int do_splice(struct io_uring *ring, IORING_OP_SPLICE); } -static int do_tee(struct io_uring *ring, int fd_in, int fd_out, +static int do_tee(struct io_uring *ring, int fd_in, int fd_out, unsigned int len) { return do_splice_op(ring, fd_in, 0, fd_out, 0, len, IORING_OP_TEE); @@ -505,6 +505,8 @@ int main(int argc, char *argv[]) splice_flags = SPLICE_F_FD_IN_FIXED; sqe_flags = IOSQE_FIXED_FILE; ret = test_splice(&ring, &ctx); + free(ctx.buf_in); + free(ctx.buf_out); if (ret) { fprintf(stderr, "registered fds splice tests failed\n"); return ret; diff --git a/contrib/libs/liburing/test/splice.t/ya.make b/contrib/libs/liburing/test/splice.t/ya.make index 2dc1ee706a..dad18f999b 100644 --- a/contrib/libs/liburing/test/splice.t/ya.make +++ b/contrib/libs/liburing/test/splice.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/sq-full-cpp.t/ya.make b/contrib/libs/liburing/test/sq-full-cpp.t/ya.make index 5a4d26b61a..aa406abdee 100644 --- a/contrib/libs/liburing/test/sq-full-cpp.t/ya.make +++ b/contrib/libs/liburing/test/sq-full-cpp.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/sq-full.t/ya.make b/contrib/libs/liburing/test/sq-full.t/ya.make index baa4eb0cf5..ecf9fa084b 100644 --- a/contrib/libs/liburing/test/sq-full.t/ya.make +++ b/contrib/libs/liburing/test/sq-full.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/sq-poll-dup.c b/contrib/libs/liburing/test/sq-poll-dup.c index a821f21962..9a45f6a6bd 100644 --- a/contrib/libs/liburing/test/sq-poll-dup.c +++ b/contrib/libs/liburing/test/sq-poll-dup.c @@ -178,7 +178,7 @@ int main(int argc, char *argv[]) if (fname != argv[1]) unlink(fname); - if (__e == EINVAL) + if (__e == EINVAL || __e == EPERM || __e == EACCES) return T_EXIT_SKIP; perror("open"); return -1; diff --git a/contrib/libs/liburing/test/sq-poll-dup.t/ya.make b/contrib/libs/liburing/test/sq-poll-dup.t/ya.make index 9e86468e20..1fcca15117 100644 --- a/contrib/libs/liburing/test/sq-poll-dup.t/ya.make +++ b/contrib/libs/liburing/test/sq-poll-dup.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/sq-poll-kthread.t/ya.make b/contrib/libs/liburing/test/sq-poll-kthread.t/ya.make index 61be5885c7..858b6ea987 100644 --- a/contrib/libs/liburing/test/sq-poll-kthread.t/ya.make +++ b/contrib/libs/liburing/test/sq-poll-kthread.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/sq-poll-share.c b/contrib/libs/liburing/test/sq-poll-share.c index c8a72107f9..59a85835ad 100644 --- a/contrib/libs/liburing/test/sq-poll-share.c +++ b/contrib/libs/liburing/test/sq-poll-share.c @@ -91,6 +91,8 @@ int main(int argc, char *argv[]) fd = open(fname, O_RDONLY | O_DIRECT); if (fd < 0) { + if (errno == EPERM || errno == EACCES || errno == EINVAL) + return T_EXIT_SKIP; perror("open"); return -1; } diff --git a/contrib/libs/liburing/test/sq-poll-share.t/ya.make b/contrib/libs/liburing/test/sq-poll-share.t/ya.make index 7b739bc0f6..8b7321b3f4 100644 --- a/contrib/libs/liburing/test/sq-poll-share.t/ya.make +++ b/contrib/libs/liburing/test/sq-poll-share.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/sq-space_left.t/ya.make b/contrib/libs/liburing/test/sq-space_left.t/ya.make index f23eec434a..12f82d935b 100644 --- a/contrib/libs/liburing/test/sq-space_left.t/ya.make +++ b/contrib/libs/liburing/test/sq-space_left.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/sqpoll-disable-exit.c b/contrib/libs/liburing/test/sqpoll-disable-exit.c index 6e5bfc6f47..b0b0938cfb 100644 --- a/contrib/libs/liburing/test/sqpoll-disable-exit.c +++ b/contrib/libs/liburing/test/sqpoll-disable-exit.c @@ -23,8 +23,10 @@ #include <unistd.h> #include "liburing.h" +#include "helpers.h" #include "../src/syscall.h" +#ifndef CONFIG_USE_SANITIZER static void sleep_ms(uint64_t ms) { usleep(ms * 1000); @@ -195,3 +197,9 @@ int main(void) loop(); return 0; } +#else +int main(int argc, char *argv[]) +{ + return T_EXIT_SKIP; +} +#endif diff --git a/contrib/libs/liburing/test/sqpoll-disable-exit.t/ya.make b/contrib/libs/liburing/test/sqpoll-disable-exit.t/ya.make index 69163bf995..8e7341edbf 100644 --- a/contrib/libs/liburing/test/sqpoll-disable-exit.t/ya.make +++ b/contrib/libs/liburing/test/sqpoll-disable-exit.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/sqpoll-exec.t/ya.make b/contrib/libs/liburing/test/sqpoll-exec.t/ya.make index 7c98e7a947..1ac9e2986e 100644 --- a/contrib/libs/liburing/test/sqpoll-exec.t/ya.make +++ b/contrib/libs/liburing/test/sqpoll-exec.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/sqpoll-exit-hang.c b/contrib/libs/liburing/test/sqpoll-exit-hang.c index 7f5e539903..e009cbf1dc 100644 --- a/contrib/libs/liburing/test/sqpoll-exit-hang.c +++ b/contrib/libs/liburing/test/sqpoll-exit-hang.c @@ -11,31 +11,7 @@ #include <sys/time.h> #include <poll.h> #include "liburing.h" - -static unsigned long long mtime_since(const struct timeval *s, - const struct timeval *e) -{ - long long sec, usec; - - sec = e->tv_sec - s->tv_sec; - usec = (e->tv_usec - s->tv_usec); - if (sec > 0 && usec < 0) { - sec--; - usec += 1000000; - } - - sec *= 1000; - usec /= 1000; - return sec + usec; -} - -static unsigned long long mtime_since_now(struct timeval *tv) -{ - struct timeval end; - - gettimeofday(&end, NULL); - return mtime_since(tv, &end); -} +#include "helpers.h" int main(int argc, char *argv[]) { diff --git a/contrib/libs/liburing/test/sqpoll-exit-hang.t/ya.make b/contrib/libs/liburing/test/sqpoll-exit-hang.t/ya.make index c3fdac8493..cb4611bda5 100644 --- a/contrib/libs/liburing/test/sqpoll-exit-hang.t/ya.make +++ b/contrib/libs/liburing/test/sqpoll-exit-hang.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/sqpoll-sleep.c b/contrib/libs/liburing/test/sqpoll-sleep.c index f98d733ea4..439a6fa148 100644 --- a/contrib/libs/liburing/test/sqpoll-sleep.c +++ b/contrib/libs/liburing/test/sqpoll-sleep.c @@ -10,31 +10,7 @@ #include <unistd.h> #include <sys/time.h> #include "liburing.h" - -static unsigned long long mtime_since(const struct timeval *s, - const struct timeval *e) -{ - long long sec, usec; - - sec = e->tv_sec - s->tv_sec; - usec = (e->tv_usec - s->tv_usec); - if (sec > 0 && usec < 0) { - sec--; - usec += 1000000; - } - - sec *= 1000; - usec /= 1000; - return sec + usec; -} - -static unsigned long long mtime_since_now(struct timeval *tv) -{ - struct timeval end; - - gettimeofday(&end, NULL); - return mtime_since(tv, &end); -} +#include "helpers.h" int main(int argc, char *argv[]) { diff --git a/contrib/libs/liburing/test/sqpoll-sleep.t/ya.make b/contrib/libs/liburing/test/sqpoll-sleep.t/ya.make index ccf2774f1d..6ae9ae9827 100644 --- a/contrib/libs/liburing/test/sqpoll-sleep.t/ya.make +++ b/contrib/libs/liburing/test/sqpoll-sleep.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/sqwait.c b/contrib/libs/liburing/test/sqwait.c new file mode 100644 index 0000000000..135b50be3a --- /dev/null +++ b/contrib/libs/liburing/test/sqwait.c @@ -0,0 +1,137 @@ +#include "../config-host.h" +/* SPDX-License-Identifier: MIT */ +/* + * Description: test that the app can always get a new sqe after having + * called io_uring_sqring_wait(). + * + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "liburing.h" +#include "helpers.h" + +#define NR_IOS 10000 +#define INFLIGHT 256 +#define FILE_SIZE (256 * 1024 * 1024) + +static int inflight; + +static int reap(struct io_uring *ring) +{ + struct io_uring_cqe *cqe; + int ret; + + while (inflight >= INFLIGHT / 2) { + ret = io_uring_wait_cqe(ring, &cqe); + if (ret < 0) { + fprintf(stderr, "wait=%d\n", ret); + return 1; + } + if (cqe->res < 0) { + printf("cqe res %d\n", cqe->res); + return 1; + } + io_uring_cqe_seen(ring, cqe); + inflight--; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + struct io_uring_sqe *sqe; + struct io_uring ring; + int fd = -1, i, iov_off, ret, fret; + struct iovec iovs[INFLIGHT]; + const char *fname; + char buf[256]; + loff_t off; + + if (argc > 1) { + fname = argv[1]; + } else { + srand((unsigned)time(NULL)); + snprintf(buf, sizeof(buf), ".sqwait-%u-%u", (unsigned)rand(), + (unsigned)getpid()); + fname = buf; + t_create_file(fname, FILE_SIZE); + } + + fret = T_EXIT_SKIP; + ret = io_uring_queue_init(8, &ring, IORING_SETUP_SQPOLL); + if (ret < 0) { + if (errno == EINVAL || errno == EPERM) + goto err; + fprintf(stderr, "queue init %d\n", ret); + fret = T_EXIT_FAIL; + goto err; + } + + fd = open(fname, O_RDONLY | O_DIRECT); + if (fd < 0) { + if (errno == EACCES || errno == EPERM || errno == EINVAL) + return T_EXIT_SKIP; + perror("open"); + fret = T_EXIT_FAIL; + goto err; + } + + for (i = 0; i < INFLIGHT; i++) { + if (posix_memalign(&iovs[i].iov_base, 4096, 4096)) + goto err; + iovs[i].iov_len = 4096; + } + + iov_off = off = 0; + for (i = 0; i < NR_IOS; i++) { + struct iovec *iov = &iovs[iov_off]; + + sqe = io_uring_get_sqe(&ring); + if (!sqe) { + ret = io_uring_sqring_wait(&ring); + if (ret < 0) { + if (ret == -EINVAL) + return T_EXIT_SKIP; + fprintf(stderr, "sqwait=%d\n", ret); + fret = T_EXIT_FAIL; + goto err; + } + sqe = io_uring_get_sqe(&ring); + if (!sqe) { + fprintf(stderr, "No sqe post wait\n"); + fret = T_EXIT_FAIL; + goto err; + } + } + io_uring_prep_read(sqe, fd, iov->iov_base, iov->iov_len, 0); + io_uring_submit(&ring); + inflight++; + + iov_off++; + if (iov_off == INFLIGHT) + iov_off = 0; + off += 8192; + if (off > FILE_SIZE - 8192) + off = 0; + if (reap(&ring)) { + fret = T_EXIT_FAIL; + goto err; + } + } + + if (fd != -1) + close(fd); + if (fname != argv[1]) + unlink(fname); + io_uring_queue_exit(&ring); + return T_EXIT_PASS; +err: + if (fd != -1) + close(fd); + if (fname != argv[1]) + unlink(fname); + return fret; +} diff --git a/contrib/libs/liburing/test/sqwait.t/ya.make b/contrib/libs/liburing/test/sqwait.t/ya.make new file mode 100644 index 0000000000..303a16afd2 --- /dev/null +++ b/contrib/libs/liburing/test/sqwait.t/ya.make @@ -0,0 +1,35 @@ +# Generated by devtools/yamaker. + +PROGRAM() + +WITHOUT_LICENSE_TEXTS() + +VERSION(2.8) + +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 + sqwait.c +) + +END() diff --git a/contrib/libs/liburing/test/stdout.c b/contrib/libs/liburing/test/stdout.c index 02b0456955..5044ccab15 100644 --- a/contrib/libs/liburing/test/stdout.c +++ b/contrib/libs/liburing/test/stdout.c @@ -90,6 +90,7 @@ static int test_pipe_io_fixed(struct io_uring *ring) io_uring_cqe_seen(ring, cqe); } io_uring_unregister_buffers(ring); + free(vecs[0].iov_base); return 0; err: return 1; @@ -144,6 +145,7 @@ static int test_stdout_io_fixed(struct io_uring *ring) } io_uring_cqe_seen(ring, cqe); io_uring_unregister_buffers(ring); + free(vecs.iov_base); return 0; err: return 1; diff --git a/contrib/libs/liburing/test/stdout.t/ya.make b/contrib/libs/liburing/test/stdout.t/ya.make index 53a1c134cc..275a46da01 100644 --- a/contrib/libs/liburing/test/stdout.t/ya.make +++ b/contrib/libs/liburing/test/stdout.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/submit-and-wait.c b/contrib/libs/liburing/test/submit-and-wait.c index ab841ca6b1..166f63fb3d 100644 --- a/contrib/libs/liburing/test/submit-and-wait.c +++ b/contrib/libs/liburing/test/submit-and-wait.c @@ -14,33 +14,9 @@ #include <sys/time.h> #include "liburing.h" +#include "helpers.h" #include "test.h" -static unsigned long long mtime_since(const struct timeval *s, - const struct timeval *e) -{ - long long sec, usec; - - sec = e->tv_sec - s->tv_sec; - usec = (e->tv_usec - s->tv_usec); - if (sec > 0 && usec < 0) { - sec--; - usec += 1000000; - } - - sec *= 1000; - usec /= 1000; - return sec + usec; -} - -static unsigned long long mtime_since_now(struct timeval *tv) -{ - struct timeval end; - - gettimeofday(&end, NULL); - return mtime_since(tv, &end); -} - static int test(struct io_uring *ring) { struct io_uring_cqe *cqe; diff --git a/contrib/libs/liburing/test/submit-and-wait.t/ya.make b/contrib/libs/liburing/test/submit-and-wait.t/ya.make index 63234cd835..478d642e10 100644 --- a/contrib/libs/liburing/test/submit-and-wait.t/ya.make +++ b/contrib/libs/liburing/test/submit-and-wait.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/submit-link-fail.t/ya.make b/contrib/libs/liburing/test/submit-link-fail.t/ya.make index 342296fe78..b5c1118f59 100644 --- a/contrib/libs/liburing/test/submit-link-fail.t/ya.make +++ b/contrib/libs/liburing/test/submit-link-fail.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/submit-reuse.c b/contrib/libs/liburing/test/submit-reuse.c index 92f6b2f5d0..a57ab19997 100644 --- a/contrib/libs/liburing/test/submit-reuse.c +++ b/contrib/libs/liburing/test/submit-reuse.c @@ -103,31 +103,6 @@ static int wait_nr(int nr) return 0; } -static unsigned long long mtime_since(const struct timeval *s, - const struct timeval *e) -{ - long long sec, usec; - - sec = e->tv_sec - s->tv_sec; - usec = (e->tv_usec - s->tv_usec); - if (sec > 0 && usec < 0) { - sec--; - usec += 1000000; - } - - sec *= 1000; - usec /= 1000; - return sec + usec; -} - -static unsigned long long mtime_since_now(struct timeval *tv) -{ - struct timeval end; - - gettimeofday(&end, NULL); - return mtime_since(tv, &end); -} - static int test_reuse(int argc, char *argv[], int split, int async) { struct thread_data data; @@ -163,6 +138,8 @@ static int test_reuse(int argc, char *argv[], int split, int async) if (do_unlink) unlink(fname1); if (fd1 < 0) { + if (errno == EPERM || errno == EACCES) + return T_EXIT_SKIP; perror("open fname1"); goto err; } @@ -212,7 +189,6 @@ static int test_reuse(int argc, char *argv[], int split, int async) err: io_uring_queue_exit(&ring); return 1; - } int main(int argc, char *argv[]) @@ -226,6 +202,8 @@ int main(int argc, char *argv[]) async = (i & 2) != 0; ret = test_reuse(argc, argv, split, async); + if (ret == T_EXIT_SKIP) + continue; if (ret) { fprintf(stderr, "test_reuse %d %d failed\n", split, async); return ret; diff --git a/contrib/libs/liburing/test/submit-reuse.t/ya.make b/contrib/libs/liburing/test/submit-reuse.t/ya.make index 05b78c046d..43c5fe34fa 100644 --- a/contrib/libs/liburing/test/submit-reuse.t/ya.make +++ b/contrib/libs/liburing/test/submit-reuse.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/symlink.c b/contrib/libs/liburing/test/symlink.c index 1fc6b8e1db..3594f4c8b3 100644 --- a/contrib/libs/liburing/test/symlink.c +++ b/contrib/libs/liburing/test/symlink.c @@ -12,7 +12,6 @@ #include "liburing.h" - static int do_symlinkat(struct io_uring *ring, const char *oldname, const char *newname) { int ret; @@ -106,6 +105,18 @@ int main(int argc, char *argv[]) goto err1; } + ret = do_symlinkat(&ring, target, (const char *) (uintptr_t) 0x1234); + if (ret != -EFAULT) { + fprintf(stderr, "test_symlinkat bad target failed: %d\n", ret); + goto err1; + } + + ret = do_symlinkat(&ring, (const char *) (uintptr_t) 0x1234, target); + if (ret != -EFAULT) { + fprintf(stderr, "test_symlinkat bad source failed: %d\n", ret); + goto err1; + } + out: unlinkat(AT_FDCWD, linkname, 0); io_uring_queue_exit(&ring); diff --git a/contrib/libs/liburing/test/symlink.t/ya.make b/contrib/libs/liburing/test/symlink.t/ya.make index 781a2bacff..e689152500 100644 --- a/contrib/libs/liburing/test/symlink.t/ya.make +++ b/contrib/libs/liburing/test/symlink.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/sync-cancel.c b/contrib/libs/liburing/test/sync-cancel.c index 096d210ffb..b3a38f4d56 100644 --- a/contrib/libs/liburing/test/sync-cancel.c +++ b/contrib/libs/liburing/test/sync-cancel.c @@ -14,9 +14,9 @@ #include "liburing.h" #include "helpers.h" -static int no_sync_cancel; +static int no_sync_cancel, no_sync_cancel_op; -static int test_sync_cancel_timeout(struct io_uring *ring, int async) +static int test_sync_cancel_timeout(struct io_uring *ring, int async, int by_op) { struct io_uring_sync_cancel_reg reg = { }; struct io_uring_sqe *sqe; @@ -44,9 +44,15 @@ static int test_sync_cancel_timeout(struct io_uring *ring, int async) usleep(10000); - reg.addr = 0x89; + reg.flags = IORING_ASYNC_CANCEL_OP; + reg.opcode = IORING_OP_READ; reg.timeout.tv_nsec = 1; ret = io_uring_register_sync_cancel(ring, ®); + /* earlier kernels had sync cancel, but not per-op */ + if (ret == -EINVAL) { + no_sync_cancel_op = 1; + return 0; + } if (async) { /* we expect -ETIME here, but can race and get 0 */ if (ret != -ETIME && ret != 0) { @@ -81,7 +87,7 @@ static int test_sync_cancel_timeout(struct io_uring *ring, int async) } static int test_sync_cancel(struct io_uring *ring, int async, int nr_all, - int use_fd) + int use_fd, int by_op) { struct io_uring_sync_cancel_reg reg = { }; struct io_uring_sqe *sqe; @@ -169,7 +175,7 @@ int main(int argc, char *argv[]) else if (ret != T_SETUP_OK) return ret; - ret = test_sync_cancel(&ring, 0, 0, 0); + ret = test_sync_cancel(&ring, 0, 0, 0, 0); if (ret) { fprintf(stderr, "test_sync_cancel 0 0 0 failed\n"); return T_EXIT_FAIL; @@ -177,56 +183,84 @@ int main(int argc, char *argv[]) if (no_sync_cancel) return T_EXIT_SKIP; - ret = test_sync_cancel(&ring, 1, 0, 0); + ret = test_sync_cancel(&ring, 0, 0, 0, 1); if (ret) { - fprintf(stderr, "test_sync_cancel 1 0 0 failed\n"); + fprintf(stderr, "test_sync_cancel 0 0 1 failed\n"); return T_EXIT_FAIL; } - ret = test_sync_cancel(&ring, 0, 1, 0); + ret = test_sync_cancel(&ring, 1, 0, 0, 0); if (ret) { - fprintf(stderr, "test_sync_cancel 0 1 0 failed\n"); + fprintf(stderr, "test_sync_cancel 1 0 0 0 failed\n"); return T_EXIT_FAIL; } - ret = test_sync_cancel(&ring, 1, 1, 0); + ret = test_sync_cancel(&ring, 1, 0, 0, 1); if (ret) { - fprintf(stderr, "test_sync_cancel 1 1 0 failed\n"); + fprintf(stderr, "test_sync_cancel 1 0 0 1 failed\n"); return T_EXIT_FAIL; } - ret = test_sync_cancel(&ring, 0, 0, 1); + + ret = test_sync_cancel(&ring, 0, 1, 0, 0); if (ret) { - fprintf(stderr, "test_sync_cancel 0 0 1 failed\n"); + fprintf(stderr, "test_sync_cancel 0 1 0 0 failed\n"); + return T_EXIT_FAIL; + } + + ret = test_sync_cancel(&ring, 0, 1, 0, 1); + if (ret) { + fprintf(stderr, "test_sync_cancel 0 1 0 1 failed\n"); + return T_EXIT_FAIL; + } + + + ret = test_sync_cancel(&ring, 1, 1, 0, 0); + if (ret) { + fprintf(stderr, "test_sync_cancel 1 1 0 0 failed\n"); + return T_EXIT_FAIL; + } + + ret = test_sync_cancel(&ring, 0, 0, 1, 0); + if (ret) { + fprintf(stderr, "test_sync_cancel 0 0 1 0 failed\n"); + return T_EXIT_FAIL; + } + + ret = test_sync_cancel(&ring, 1, 0, 1, 0); + if (ret) { + fprintf(stderr, "test_sync_cancel 1 0 1 0 failed\n"); return T_EXIT_FAIL; } - ret = test_sync_cancel(&ring, 1, 0, 1); + ret = test_sync_cancel(&ring, 0, 1, 1, 0); if (ret) { - fprintf(stderr, "test_sync_cancel 1 0 1 failed\n"); + fprintf(stderr, "test_sync_cancel 0 1 1 0 failed\n"); return T_EXIT_FAIL; } - ret = test_sync_cancel(&ring, 0, 1, 1); + ret = test_sync_cancel(&ring, 1, 1, 1, 0); if (ret) { - fprintf(stderr, "test_sync_cancel 0 1 1 failed\n"); + fprintf(stderr, "test_sync_cancel 1 1 1 0 failed\n"); return T_EXIT_FAIL; } - ret = test_sync_cancel(&ring, 1, 1, 1); + ret = test_sync_cancel_timeout(&ring, 0, 0); if (ret) { - fprintf(stderr, "test_sync_cancel 1 1 1 failed\n"); + fprintf(stderr, "test_sync_cancel_timeout 0 0\n"); return T_EXIT_FAIL; } + if (no_sync_cancel_op) + return T_EXIT_PASS; - ret = test_sync_cancel_timeout(&ring, 0); + ret = test_sync_cancel_timeout(&ring, 0, 1); if (ret) { - fprintf(stderr, "test_sync_cancel_timeout 0\n"); + fprintf(stderr, "test_sync_cancel_timeout 0 1\n"); return T_EXIT_FAIL; } /* must be last, leaves request */ - ret = test_sync_cancel_timeout(&ring, 1); + ret = test_sync_cancel_timeout(&ring, 1, 0); if (ret) { fprintf(stderr, "test_sync_cancel_timeout 1\n"); return T_EXIT_FAIL; diff --git a/contrib/libs/liburing/test/sync-cancel.t/ya.make b/contrib/libs/liburing/test/sync-cancel.t/ya.make index d6a5a15318..253fe4f7a7 100644 --- a/contrib/libs/liburing/test/sync-cancel.t/ya.make +++ b/contrib/libs/liburing/test/sync-cancel.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/teardowns.t/ya.make b/contrib/libs/liburing/test/teardowns.t/ya.make index f227ee9f18..2899e8be17 100644 --- a/contrib/libs/liburing/test/teardowns.t/ya.make +++ b/contrib/libs/liburing/test/teardowns.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/thread-exit.c b/contrib/libs/liburing/test/thread-exit.c index 282b1e8461..7c83e4f549 100644 --- a/contrib/libs/liburing/test/thread-exit.c +++ b/contrib/libs/liburing/test/thread-exit.c @@ -103,6 +103,8 @@ int main(int argc, char *argv[]) if (do_unlink) unlink(fname); if (fd < 0) { + if (errno == EPERM || errno == EACCES) + goto skip; perror("open"); return 1; } @@ -141,4 +143,7 @@ int main(int argc, char *argv[]) err: free_g_buf(); return 1; +skip: + free_g_buf(); + return T_EXIT_SKIP; } diff --git a/contrib/libs/liburing/test/thread-exit.t/ya.make b/contrib/libs/liburing/test/thread-exit.t/ya.make index eefdfcf3f1..5ce470b9e1 100644 --- a/contrib/libs/liburing/test/thread-exit.t/ya.make +++ b/contrib/libs/liburing/test/thread-exit.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/timeout-new.c b/contrib/libs/liburing/test/timeout-new.c index e0f2935e63..0608675e59 100644 --- a/contrib/libs/liburing/test/timeout-new.c +++ b/contrib/libs/liburing/test/timeout-new.c @@ -9,6 +9,7 @@ #include <unistd.h> #include <pthread.h> #include "liburing.h" +#include "helpers.h" #define TIMEOUT_MSEC 200 #define TIMEOUT_SEC 10 @@ -23,32 +24,6 @@ static void msec_to_ts(struct __kernel_timespec *ts, unsigned int msec) ts->tv_nsec = (msec % 1000) * 1000000; } -static unsigned long long mtime_since(const struct timeval *s, - const struct timeval *e) -{ - long long sec, usec; - - sec = e->tv_sec - s->tv_sec; - usec = (e->tv_usec - s->tv_usec); - if (sec > 0 && usec < 0) { - sec--; - usec += 1000000; - } - - sec *= 1000; - usec /= 1000; - return sec + usec; -} - -static unsigned long long mtime_since_now(struct timeval *tv) -{ - struct timeval end; - - gettimeofday(&end, NULL); - return mtime_since(tv, &end); -} - - static int test_return_before_timeout(struct io_uring *ring) { struct io_uring_cqe *cqe; diff --git a/contrib/libs/liburing/test/timeout-new.t/ya.make b/contrib/libs/liburing/test/timeout-new.t/ya.make index 1303f2cf15..9ee0e1870d 100644 --- a/contrib/libs/liburing/test/timeout-new.t/ya.make +++ b/contrib/libs/liburing/test/timeout-new.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/timeout.c b/contrib/libs/liburing/test/timeout.c index 8e3c7bdf7c..0eb67315ac 100644 --- a/contrib/libs/liburing/test/timeout.c +++ b/contrib/libs/liburing/test/timeout.c @@ -30,31 +30,6 @@ static void msec_to_ts(struct __kernel_timespec *ts, unsigned int msec) ts->tv_nsec = (msec % 1000) * 1000000; } -static unsigned long long mtime_since(const struct timeval *s, - const struct timeval *e) -{ - long long sec, usec; - - sec = e->tv_sec - s->tv_sec; - usec = (e->tv_usec - s->tv_usec); - if (sec > 0 && usec < 0) { - sec--; - usec += 1000000; - } - - sec *= 1000; - usec /= 1000; - return sec + usec; -} - -static unsigned long long mtime_since_now(struct timeval *tv) -{ - struct timeval end; - - gettimeofday(&end, NULL); - return mtime_since(tv, &end); -} - /* * Test that we return to userspace if a timeout triggers, even if we * don't satisfy the number of events asked for. @@ -981,6 +956,7 @@ static int test_update_timeout(struct io_uring *ring, unsigned long ms, struct io_uring_cqe *cqe; struct __kernel_timespec ts, ts_upd; unsigned long long exp_ms, base_ms = 10000; + bool update_ealready = false; struct timeval tv; int ret, i, nr = 2; __u32 mode = abs ? IORING_TIMEOUT_ABS : 0; @@ -1043,6 +1019,16 @@ static int test_update_timeout(struct io_uring *ring, unsigned long ms, } break; case 2: + /* + * We should not be hitting this case, but for + * a kernel with PREEMPT_RT, even an instant attempt + * to remove a timer will return that the timer is + * already running... Deal with it. + */ + if (cqe->res == -EALREADY) { + update_ealready = true; + break; + } if (cqe->res != 0) { fprintf(stderr, "%s: got %d, wanted %d\n", __FUNCTION__, cqe->res, @@ -1063,7 +1049,7 @@ static int test_update_timeout(struct io_uring *ring, unsigned long ms, } exp_ms = mtime_since_now(&tv); - if (exp_ms >= base_ms / 2) { + if (!update_ealready && exp_ms >= base_ms / 2) { fprintf(stderr, "too long, timeout wasn't updated\n"); goto err; } diff --git a/contrib/libs/liburing/test/timeout.t/ya.make b/contrib/libs/liburing/test/timeout.t/ya.make index 3b26c010dd..a0d748a68e 100644 --- a/contrib/libs/liburing/test/timeout.t/ya.make +++ b/contrib/libs/liburing/test/timeout.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/truncate.t/ya.make b/contrib/libs/liburing/test/truncate.t/ya.make index 6a4e13ab41..4adbaa862e 100644 --- a/contrib/libs/liburing/test/truncate.t/ya.make +++ b/contrib/libs/liburing/test/truncate.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/tty-write-dpoll.t/ya.make b/contrib/libs/liburing/test/tty-write-dpoll.t/ya.make index f51141ac1e..4ddf4e4f1b 100644 --- a/contrib/libs/liburing/test/tty-write-dpoll.t/ya.make +++ b/contrib/libs/liburing/test/tty-write-dpoll.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/unlink.c b/contrib/libs/liburing/test/unlink.c index 95e613ae3f..b4161fff2a 100644 --- a/contrib/libs/liburing/test/unlink.c +++ b/contrib/libs/liburing/test/unlink.c @@ -14,6 +14,87 @@ #include "liburing.h" +static int test_rmdir(struct io_uring *ring) +{ + struct io_uring_cqe *cqe; + struct io_uring_sqe *sqe; + char buf[32]; + int ret; + + sprintf(buf, ".tmp.dir.%d", getpid()); + if (mkdir(buf, 0755) < 0) { + perror("mkdir"); + return 1; + } + + sqe = io_uring_get_sqe(ring); + if (!sqe) { + fprintf(stderr, "get sqe failed\n"); + goto err; + } + io_uring_prep_unlink(sqe, buf, AT_REMOVEDIR); + + 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); + + if (!ret) { + struct stat sb; + + if (!stat(buf, &sb)) { + fprintf(stderr, "dir unlinked but still there\n"); + goto err; + } + } + unlink(buf); + return ret; +err: + unlink(buf); + return 1; +} + +static int test_unlink_badaddr(struct io_uring *ring) +{ + const char *old = (const char *) (uintptr_t) 0x1234; + 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; + } + io_uring_prep_unlink(sqe, old, 0); + + 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 test_unlink(struct io_uring *ring, const char *old) { struct io_uring_cqe *cqe; @@ -26,7 +107,7 @@ static int test_unlink(struct io_uring *ring, const char *old) goto err; } io_uring_prep_unlink(sqe, old, 0); - + ret = io_uring_submit(ring); if (ret <= 0) { fprintf(stderr, "sqe submit failed: %d\n", ret); @@ -106,6 +187,18 @@ int main(int argc, char *argv[]) return 1; } + ret = test_unlink_badaddr(&ring); + if (ret != -EFAULT) { + fprintf(stderr, "badaddr unlink got %s\n", strerror(-ret)); + return 1; + } + + ret = test_rmdir(&ring); + if (ret) { + fprintf(stderr, "rmdir failed: %s\n", strerror(-ret)); + return 1; + } + return 0; err: unlink(buf); diff --git a/contrib/libs/liburing/test/unlink.t/ya.make b/contrib/libs/liburing/test/unlink.t/ya.make index 8c6bf7cdc3..78082b4401 100644 --- a/contrib/libs/liburing/test/unlink.t/ya.make +++ b/contrib/libs/liburing/test/unlink.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/uring_cmd_ublk.c b/contrib/libs/liburing/test/uring_cmd_ublk.c new file mode 100644 index 0000000000..30012c7516 --- /dev/null +++ b/contrib/libs/liburing/test/uring_cmd_ublk.c @@ -0,0 +1,1253 @@ +#include "../config-host.h" +/* SPDX-License-Identifier: MIT */ +/* + * Description: uring_cmd based ublk + * + * Covers cancellable uring_cmd feature. + */ +#include <unistd.h> +#include <stdlib.h> +#include <assert.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <pthread.h> +#include <limits.h> +#include <poll.h> +#include <sys/syscall.h> +#include <sys/mman.h> +#include <sys/ioctl.h> +#include <sys/inotify.h> +#include <sys/wait.h> + +#include "liburing.h" +#include "helpers.h" +#ifdef CONFIG_HAVE_UBLK_HEADER +#include <linux/ublk_cmd.h> + +/****************** part 1: libublk ********************/ + +#define CTRL_DEV "/dev/ublk-control" +#define UBLKC_DEV "/dev/ublkc" +#define UBLKB_DEV "/dev/ublkb" +#define UBLK_CTRL_RING_DEPTH 32 + +/* queue idle timeout */ +#define UBLKSRV_IO_IDLE_SECS 20 + +#define UBLK_IO_MAX_BYTES 65536 +#define UBLK_MAX_QUEUES 4 +#define UBLK_QUEUE_DEPTH 128 + +#define UBLK_DBG_DEV (1U << 0) +#define UBLK_DBG_QUEUE (1U << 1) +#define UBLK_DBG_IO_CMD (1U << 2) +#define UBLK_DBG_IO (1U << 3) +#define UBLK_DBG_CTRL_CMD (1U << 4) +#define UBLK_LOG (1U << 5) + +struct ublk_dev; +struct ublk_queue; + +struct ublk_ctrl_cmd_data { + __u32 cmd_op; +#define CTRL_CMD_HAS_DATA 1 +#define CTRL_CMD_HAS_BUF 2 + __u32 flags; + + __u64 data[2]; + __u64 addr; + __u32 len; +}; + +struct ublk_io { + char *buf_addr; + +#define UBLKSRV_NEED_FETCH_RQ (1UL << 0) +#define UBLKSRV_NEED_COMMIT_RQ_COMP (1UL << 1) +#define UBLKSRV_IO_FREE (1UL << 2) + unsigned int flags; + + unsigned int result; +}; + +struct ublk_tgt_ops { + const char *name; + int (*init_tgt)(struct ublk_dev *); + void (*deinit_tgt)(struct ublk_dev *); + + int (*queue_io)(struct ublk_queue *, int tag); + void (*tgt_io_done)(struct ublk_queue *, + int tag, const struct io_uring_cqe *); +}; + +struct ublk_tgt { + unsigned long dev_size; + const struct ublk_tgt_ops *ops; + struct ublk_params params; +}; + +struct ublk_queue { + int q_id; + int q_depth; + unsigned int cmd_inflight; + unsigned int io_inflight; + struct ublk_dev *dev; + const struct ublk_tgt_ops *tgt_ops; + char *io_cmd_buf; + struct io_uring ring; + struct ublk_io ios[UBLK_QUEUE_DEPTH]; +#define UBLKSRV_QUEUE_STOPPING (1U << 0) +#define UBLKSRV_QUEUE_IDLE (1U << 1) + unsigned state; + pid_t tid; + pthread_t thread; +}; + +struct ublk_dev { + struct ublk_tgt tgt; + struct ublksrv_ctrl_dev_info dev_info; + struct ublk_queue q[UBLK_MAX_QUEUES]; + + int fds[2]; /* fds[0] points to /dev/ublkcN */ + int nr_fds; + int ctrl_fd; + struct io_uring ring; +}; + +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER) +#endif + +#ifndef container_of +#define container_of(ptr, type, member) ({ \ + unsigned long __mptr = (unsigned long)(ptr); \ + ((type *)(__mptr - offsetof(type, member))); }) +#endif + +#define round_up(val, rnd) \ + (((val) + ((rnd) - 1)) & ~((rnd) - 1)) + +static unsigned int ublk_dbg_mask = 0; + +static const struct ublk_tgt_ops *ublk_find_tgt(const char *name); + +static inline int is_target_io(__u64 user_data) +{ + return (user_data & (1ULL << 63)) != 0; +} + +static inline __u64 build_user_data(unsigned tag, unsigned op, + unsigned tgt_data, unsigned is_target_io) +{ + assert(!(tag >> 16) && !(op >> 8) && !(tgt_data >> 16)); + + return tag | (op << 16) | (tgt_data << 24) | (__u64)is_target_io << 63; +} + +static inline unsigned int user_data_to_tag(__u64 user_data) +{ + return user_data & 0xffff; +} + +static inline unsigned int user_data_to_op(__u64 user_data) +{ + return (user_data >> 16) & 0xff; +} + +static void ublk_err(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); +} + +static void ublk_dbg(int level, const char *fmt, ...) +{ + if (level & ublk_dbg_mask) { + va_list ap; + va_start(ap, fmt); + vfprintf(stdout, fmt, ap); + } +} + +static inline void *ublk_get_sqe_cmd(const struct io_uring_sqe *sqe) +{ + return (void *)&sqe->cmd; +} + +static inline void ublk_mark_io_done(struct ublk_io *io, int res) +{ + io->flags |= (UBLKSRV_NEED_COMMIT_RQ_COMP | UBLKSRV_IO_FREE); + io->result = res; +} + +static inline const struct ublksrv_io_desc *ublk_get_iod( + const struct ublk_queue *q, int tag) +{ + return (struct ublksrv_io_desc *) + &(q->io_cmd_buf[tag * sizeof(struct ublksrv_io_desc)]); +} + +static inline void ublk_set_sqe_cmd_op(struct io_uring_sqe *sqe, + __u32 cmd_op) +{ + __u32 *addr = (__u32 *)&sqe->off; + + addr[0] = cmd_op; + addr[1] = 0; +} + +static inline int ublk_setup_ring(struct io_uring *r, int depth, + int cq_depth, unsigned flags) +{ + struct io_uring_params p; + + memset(&p, 0, sizeof(p)); + p.flags = flags | IORING_SETUP_CQSIZE; + p.cq_entries = cq_depth; + + return io_uring_queue_init_params(depth, r, &p); +} + +static void ublk_ctrl_init_cmd(struct ublk_dev *dev, + struct io_uring_sqe *sqe, + struct ublk_ctrl_cmd_data *data) +{ + struct ublksrv_ctrl_dev_info *info = &dev->dev_info; + struct ublksrv_ctrl_cmd *cmd = (struct ublksrv_ctrl_cmd *)ublk_get_sqe_cmd(sqe); + + sqe->fd = dev->ctrl_fd; + sqe->opcode = IORING_OP_URING_CMD; + sqe->ioprio = 0; + + if (data->flags & CTRL_CMD_HAS_BUF) { + cmd->addr = data->addr; + cmd->len = data->len; + } + + if (data->flags & CTRL_CMD_HAS_DATA) + cmd->data[0] = data->data[0]; + + cmd->dev_id = info->dev_id; + cmd->queue_id = -1; + + ublk_set_sqe_cmd_op(sqe, data->cmd_op); + + io_uring_sqe_set_data(sqe, cmd); +} + +static int __ublk_ctrl_cmd(struct ublk_dev *dev, + struct ublk_ctrl_cmd_data *data) +{ + struct io_uring_sqe *sqe; + struct io_uring_cqe *cqe; + int ret = -EINVAL; + + sqe = io_uring_get_sqe(&dev->ring); + if (!sqe) { + ublk_err("%s: can't get sqe ret %d\n", __func__, ret); + return ret; + } + + ublk_ctrl_init_cmd(dev, sqe, data); + + ret = io_uring_submit(&dev->ring); + if (ret < 0) { + ublk_err("uring submit ret %d\n", ret); + return ret; + } + + ret = io_uring_wait_cqe(&dev->ring, &cqe); + if (ret < 0) { + ublk_err("wait cqe: %s\n", strerror(-ret)); + return ret; + } + io_uring_cqe_seen(&dev->ring, cqe); + + return cqe->res; +} + +static int ublk_ctrl_start_dev(struct ublk_dev *dev, + int daemon_pid) +{ + struct ublk_ctrl_cmd_data data = { + .cmd_op = UBLK_U_CMD_START_DEV, + .flags = CTRL_CMD_HAS_DATA, + }; + + dev->dev_info.ublksrv_pid = data.data[0] = daemon_pid; + + return __ublk_ctrl_cmd(dev, &data); +} + +static int ublk_ctrl_add_dev(struct ublk_dev *dev) +{ + struct ublk_ctrl_cmd_data data = { + .cmd_op = UBLK_U_CMD_ADD_DEV, + .flags = CTRL_CMD_HAS_BUF, + .addr = (__u64) (uintptr_t) &dev->dev_info, + .len = sizeof(struct ublksrv_ctrl_dev_info), + }; + + return __ublk_ctrl_cmd(dev, &data); +} + +static int ublk_ctrl_del_dev(struct ublk_dev *dev) +{ + struct ublk_ctrl_cmd_data data = { + .cmd_op = UBLK_U_CMD_DEL_DEV, + .flags = 0, + }; + + return __ublk_ctrl_cmd(dev, &data); +} + +static int ublk_ctrl_get_info(struct ublk_dev *dev) +{ + struct ublk_ctrl_cmd_data data = { + .cmd_op = UBLK_U_CMD_GET_DEV_INFO, + .flags = CTRL_CMD_HAS_BUF, + .addr = (__u64) (uintptr_t) &dev->dev_info, + .len = sizeof(struct ublksrv_ctrl_dev_info), + }; + + return __ublk_ctrl_cmd(dev, &data); +} + +static int ublk_ctrl_set_params(struct ublk_dev *dev, + struct ublk_params *params) +{ + struct ublk_ctrl_cmd_data data = { + .cmd_op = UBLK_U_CMD_SET_PARAMS, + .flags = CTRL_CMD_HAS_BUF, + .addr = (__u64) (uintptr_t) params, + .len = sizeof(*params), + }; + params->len = sizeof(*params); + return __ublk_ctrl_cmd(dev, &data); +} + +static int ublk_ctrl_get_features(struct ublk_dev *dev, + __u64 *features) +{ + struct ublk_ctrl_cmd_data data = { + .cmd_op = UBLK_U_CMD_GET_FEATURES, + .flags = CTRL_CMD_HAS_BUF, + .addr = (__u64) (uintptr_t) features, + .len = sizeof(*features), + }; + + return __ublk_ctrl_cmd(dev, &data); +} + +static void ublk_ctrl_deinit(struct ublk_dev *dev) +{ + close(dev->ctrl_fd); + free(dev); +} + +static struct ublk_dev *ublk_ctrl_init(void) +{ + struct ublk_dev *dev = (struct ublk_dev *)calloc(1, sizeof(*dev)); + struct ublksrv_ctrl_dev_info *info = &dev->dev_info; + int ret; + + dev->ctrl_fd = open(CTRL_DEV, O_RDWR); + if (dev->ctrl_fd < 0) { + free(dev); + return NULL; + } + + info->max_io_buf_bytes = UBLK_IO_MAX_BYTES; + + ret = ublk_setup_ring(&dev->ring, UBLK_CTRL_RING_DEPTH, + UBLK_CTRL_RING_DEPTH, IORING_SETUP_SQE128); + if (ret < 0) { + ublk_err("queue_init: %s\n", strerror(-ret)); + free(dev); + return NULL; + } + dev->nr_fds = 1; + + return dev; +} + +static int ublk_queue_cmd_buf_sz(struct ublk_queue *q) +{ + int size = q->q_depth * sizeof(struct ublksrv_io_desc); + unsigned int page_sz = getpagesize(); + + return round_up(size, page_sz); +} + +static void ublk_queue_deinit(struct ublk_queue *q) +{ + int i; + int nr_ios = q->q_depth; + + io_uring_unregister_ring_fd(&q->ring); + + if (q->ring.ring_fd > 0) { + io_uring_unregister_files(&q->ring); + close(q->ring.ring_fd); + q->ring.ring_fd = -1; + } + + if (q->io_cmd_buf) + munmap(q->io_cmd_buf, ublk_queue_cmd_buf_sz(q)); + + for (i = 0; i < nr_ios; i++) + free(q->ios[i].buf_addr); +} + +static int ublk_queue_init(struct ublk_queue *q) +{ + struct ublk_dev *dev = q->dev; + int depth = dev->dev_info.queue_depth; + int i, ret = -1; + int cmd_buf_size, io_buf_size; + unsigned long off; + int ring_depth = depth, cq_depth = depth; + + q->tgt_ops = dev->tgt.ops; + q->state = 0; + q->q_depth = depth; + q->cmd_inflight = 0; + q->tid = gettid(); + + cmd_buf_size = ublk_queue_cmd_buf_sz(q); + off = UBLKSRV_CMD_BUF_OFFSET + + q->q_id * (UBLK_MAX_QUEUE_DEPTH * sizeof(struct ublksrv_io_desc)); + q->io_cmd_buf = (char *)mmap(0, cmd_buf_size, PROT_READ, + MAP_SHARED | MAP_POPULATE, dev->fds[0], off); + if (q->io_cmd_buf == MAP_FAILED) { + ublk_err("ublk dev %d queue %d map io_cmd_buf failed %m\n", + q->dev->dev_info.dev_id, q->q_id); + goto fail; + } + + io_buf_size = dev->dev_info.max_io_buf_bytes; + for (i = 0; i < q->q_depth; i++) { + q->ios[i].buf_addr = NULL; + + if (posix_memalign((void **)&q->ios[i].buf_addr, + getpagesize(), io_buf_size)) { + ublk_err("ublk dev %d queue %d io %d posix_memalign failed %m\n", + dev->dev_info.dev_id, q->q_id, i); + goto fail; + } + q->ios[i].flags = UBLKSRV_NEED_FETCH_RQ | UBLKSRV_IO_FREE; + } + + ret = ublk_setup_ring(&q->ring, ring_depth, cq_depth, + IORING_SETUP_COOP_TASKRUN); + if (ret < 0) { + ublk_err("ublk dev %d queue %d setup io_uring failed %d\n", + q->dev->dev_info.dev_id, q->q_id, ret); + goto fail; + } + + io_uring_register_ring_fd(&q->ring); + + ret = io_uring_register_files(&q->ring, dev->fds, dev->nr_fds); + if (ret) { + ublk_err("ublk dev %d queue %d register files failed %d\n", + q->dev->dev_info.dev_id, q->q_id, ret); + goto fail; + } + + return 0; + fail: + ublk_queue_deinit(q); + ublk_err("ublk dev %d queue %d failed\n", + dev->dev_info.dev_id, q->q_id); + return -ENOMEM; +} + +static int ublk_dev_prep(struct ublk_dev *dev) +{ + int dev_id = dev->dev_info.dev_id; + char buf[64]; + int ret = 0; + + snprintf(buf, 64, "%s%d", UBLKC_DEV, dev_id); + dev->fds[0] = open(buf, O_RDWR); + if (dev->fds[0] < 0) { + ret = -EBADF; + ublk_err("can't open %s, ret %d\n", buf, dev->fds[0]); + goto fail; + } + + if (dev->tgt.ops->init_tgt) + ret = dev->tgt.ops->init_tgt(dev); + + return ret; +fail: + close(dev->fds[0]); + return ret; +} + +static void ublk_dev_unprep(struct ublk_dev *dev) +{ + if (dev->tgt.ops->deinit_tgt) + dev->tgt.ops->deinit_tgt(dev); + close(dev->fds[0]); +} + +static int ublk_queue_io_cmd(struct ublk_queue *q, + struct ublk_io *io, unsigned tag) +{ + struct ublksrv_io_cmd *cmd; + struct io_uring_sqe *sqe; + unsigned int cmd_op = 0; + __u64 user_data; + + /* only freed io can be issued */ + if (!(io->flags & UBLKSRV_IO_FREE)) + return 0; + + /* we issue because we need either fetching or committing */ + if (!(io->flags & + (UBLKSRV_NEED_FETCH_RQ | UBLKSRV_NEED_COMMIT_RQ_COMP))) + return 0; + + if (io->flags & UBLKSRV_NEED_COMMIT_RQ_COMP) + cmd_op = UBLK_U_IO_COMMIT_AND_FETCH_REQ; + else if (io->flags & UBLKSRV_NEED_FETCH_RQ) + cmd_op = UBLK_U_IO_FETCH_REQ; + + sqe = io_uring_get_sqe(&q->ring); + if (!sqe) { + ublk_err("%s: run out of sqe %d, tag %d\n", + __func__, q->q_id, tag); + return -1; + } + + cmd = (struct ublksrv_io_cmd *)ublk_get_sqe_cmd(sqe); + + if (cmd_op == UBLK_U_IO_COMMIT_AND_FETCH_REQ) + cmd->result = io->result; + + /* These fields should be written once, never change */ + ublk_set_sqe_cmd_op(sqe, cmd_op); + sqe->fd = 0; /* dev->fds[0] */ + sqe->opcode = IORING_OP_URING_CMD; + sqe->flags = IOSQE_FIXED_FILE; + sqe->rw_flags = 0; + cmd->tag = tag; + cmd->addr = (__u64) (uintptr_t) io->buf_addr; + cmd->q_id = q->q_id; + + user_data = build_user_data(tag, _IOC_NR(cmd_op), 0, 0); + io_uring_sqe_set_data64(sqe, user_data); + + io->flags = 0; + + q->cmd_inflight += 1; + + ublk_dbg(UBLK_DBG_IO_CMD, "%s: (qid %d tag %u cmd_op %u) iof %x stopping %d\n", + __func__, q->q_id, tag, cmd_op, + io->flags, !!(q->state & UBLKSRV_QUEUE_STOPPING)); + return 1; +} + +static int ublk_complete_io(struct ublk_queue *q, + unsigned tag, int res) +{ + struct ublk_io *io = &q->ios[tag]; + + ublk_mark_io_done(io, res); + + return ublk_queue_io_cmd(q, io, tag); +} + +static void ublk_submit_fetch_commands(struct ublk_queue *q) +{ + int i = 0; + + for (i = 0; i < q->q_depth; i++) + ublk_queue_io_cmd(q, &q->ios[i], i); +} + +static int ublk_queue_is_idle(struct ublk_queue *q) +{ + return !io_uring_sq_ready(&q->ring) && !q->io_inflight; +} + +static int ublk_queue_is_done(struct ublk_queue *q) +{ + return (q->state & UBLKSRV_QUEUE_STOPPING) && ublk_queue_is_idle(q); +} + +static inline void ublksrv_handle_tgt_cqe(struct ublk_queue *q, + struct io_uring_cqe *cqe) +{ + unsigned tag = user_data_to_tag(cqe->user_data); + + if (cqe->res < 0 && cqe->res != -EAGAIN) + ublk_err("%s: failed tgt io: res %d qid %u tag %u, cmd_op %u\n", + __func__, cqe->res, q->q_id, + user_data_to_tag(cqe->user_data), + user_data_to_op(cqe->user_data)); + + if (q->tgt_ops->tgt_io_done) + q->tgt_ops->tgt_io_done(q, tag, cqe); +} + +static void ublk_handle_cqe(struct io_uring *r, + struct io_uring_cqe *cqe, void *data) +{ + struct ublk_queue *q = container_of(r, struct ublk_queue, ring); + unsigned tag = user_data_to_tag(cqe->user_data); + unsigned cmd_op = user_data_to_op(cqe->user_data); + int fetch = (cqe->res != UBLK_IO_RES_ABORT) && + !(q->state & UBLKSRV_QUEUE_STOPPING); + struct ublk_io *io; + + ublk_dbg(UBLK_DBG_IO_CMD, "%s: res %d (qid %d tag %u cmd_op %u target %d) stopping %d\n", + __func__, cqe->res, q->q_id, tag, cmd_op, + is_target_io(cqe->user_data), + (q->state & UBLKSRV_QUEUE_STOPPING)); + + /* Don't retrieve io in case of target io */ + if (is_target_io(cqe->user_data)) { + ublksrv_handle_tgt_cqe(q, cqe); + return; + } + + io = &q->ios[tag]; + q->cmd_inflight--; + + if (!fetch) { + q->state |= UBLKSRV_QUEUE_STOPPING; + io->flags &= ~UBLKSRV_NEED_FETCH_RQ; + } + + if (cqe->res == UBLK_IO_RES_OK) { + assert(tag < q->q_depth); + q->tgt_ops->queue_io(q, tag); + } else { + /* + * COMMIT_REQ will be completed immediately since no fetching + * piggyback is required. + * + * Marking IO_FREE only, then this io won't be issued since + * we only issue io with (UBLKSRV_IO_FREE | UBLKSRV_NEED_*) + * + * */ + io->flags = UBLKSRV_IO_FREE; + } +} + +static int ublk_reap_events_uring(struct io_uring *r) +{ + struct io_uring_cqe *cqe; + unsigned head; + int count = 0; + + io_uring_for_each_cqe(r, head, cqe) { + ublk_handle_cqe(r, cqe, NULL); + count += 1; + } + io_uring_cq_advance(r, count); + + return count; +} + +static int ublk_process_io(struct ublk_queue *q) +{ + int ret, reapped; + + ublk_dbg(UBLK_DBG_QUEUE, "dev%d-q%d: to_submit %d inflight cmd %u stopping %d\n", + q->dev->dev_info.dev_id, + q->q_id, io_uring_sq_ready(&q->ring), + q->cmd_inflight, + (q->state & UBLKSRV_QUEUE_STOPPING)); + + if (ublk_queue_is_done(q)) + return -ENODEV; + + ret = io_uring_submit_and_wait(&q->ring, 1); + reapped = ublk_reap_events_uring(&q->ring); + + ublk_dbg(UBLK_DBG_QUEUE, "submit result %d, reapped %d stop %d idle %d\n", + ret, reapped, (q->state & UBLKSRV_QUEUE_STOPPING), + (q->state & UBLKSRV_QUEUE_IDLE)); + + return reapped; +} + +static void *ublk_io_handler_fn(void *data) +{ + struct ublk_queue *q = data; + int dev_id = q->dev->dev_info.dev_id; + int ret; + + ret = ublk_queue_init(q); + if (ret) { + ublk_err("ublk dev %d queue %d init queue failed\n", + dev_id, q->q_id); + return NULL; + } + ublk_dbg(UBLK_DBG_QUEUE, "tid %d: ublk dev %d queue %d started\n", + q->tid, dev_id, q->q_id); + + /* submit all io commands to ublk driver */ + ublk_submit_fetch_commands(q); + do { + if (ublk_process_io(q) < 0) + break; + } while (1); + + ublk_dbg(UBLK_DBG_QUEUE, "ublk dev %d queue %d exited\n", dev_id, q->q_id); + ublk_queue_deinit(q); + return NULL; +} + +static void ublk_set_parameters(struct ublk_dev *dev) +{ + int ret; + + ret = ublk_ctrl_set_params(dev, &dev->tgt.params); + if (ret) + ublk_err("dev %d set basic parameter failed %d\n", + dev->dev_info.dev_id, ret); +} + +static int ublk_start_daemon(struct ublk_dev *dev) +{ + int ret, i; + void *thread_ret; + const struct ublksrv_ctrl_dev_info *dinfo = &dev->dev_info; + + if (daemon(1, 1) < 0) + return -errno; + + ublk_dbg(UBLK_DBG_DEV, "%s enter\n", __func__); + + ret = ublk_dev_prep(dev); + if (ret) + return ret; + + for (i = 0; i < dinfo->nr_hw_queues; i++) { + dev->q[i].dev = dev; + dev->q[i].q_id = i; + pthread_create(&dev->q[i].thread, NULL, + ublk_io_handler_fn, + &dev->q[i]); + } + + /* everything is fine now, start us */ + ublk_set_parameters(dev); + ret = ublk_ctrl_start_dev(dev, getpid()); + if (ret < 0) { + ublk_err("%s: ublk_ctrl_start_dev failed: %d\n", __func__, ret); + goto fail; + } + + /* wait until we are terminated */ + for (i = 0; i < dinfo->nr_hw_queues; i++) + pthread_join(dev->q[i].thread, &thread_ret); + fail: + ublk_dev_unprep(dev); + ublk_dbg(UBLK_DBG_DEV, "%s exit\n", __func__); + + return ret; +} + +static int wait_ublk_dev(char *dev_name, int evt_mask, unsigned timeout) +{ +#define EV_SIZE (sizeof(struct inotify_event)) +#define EV_BUF_LEN (128 * (EV_SIZE + 16)) + struct pollfd pfd; + int fd, wd; + int ret = -EINVAL; + + fd = inotify_init(); + if (fd < 0) { + ublk_dbg(UBLK_DBG_DEV, "%s: inotify init failed\n", __func__); + return fd; + } + + wd = inotify_add_watch(fd, "/dev", evt_mask); + if (wd == -1) { + ublk_dbg(UBLK_DBG_DEV, "%s: add watch for /dev failed\n", __func__); + goto fail; + } + + pfd.fd = fd; + pfd.events = POLL_IN; + while (1) { + int i = 0; + char buffer[EV_BUF_LEN]; + ret = poll(&pfd, 1, 1000 * timeout); + + if (ret == -1) { + ublk_err("%s: poll inotify failed: %d\n", __func__, ret); + goto rm_watch; + } else if (ret == 0) { + ublk_err("%s: poll inotify timeout\n", __func__); + ret = -ENOENT; + goto rm_watch; + } + + ret = read(fd, buffer, EV_BUF_LEN); + if (ret < 0) { + ublk_err("%s: read inotify fd failed\n", __func__); + goto rm_watch; + } + + while (i < ret) { + struct inotify_event *event = (struct inotify_event *)&buffer[i]; + + ublk_dbg(UBLK_DBG_DEV, "%s: inotify event %x %s\n", + __func__, event->mask, event->name); + if (event->mask & evt_mask) { + if (!strcmp(event->name, dev_name)) { + ret = 0; + goto rm_watch; + } + } + i += EV_SIZE + event->len; + } + } +rm_watch: + inotify_rm_watch(fd, wd); +fail: + close(fd); + return ret; +} + +static int ublk_stop_io_daemon(const struct ublk_dev *dev) +{ + int daemon_pid = dev->dev_info.ublksrv_pid; + int dev_id = dev->dev_info.dev_id; + char ublkc[64]; + int ret; + + /* + * Wait until ublk char device is closed, when our daemon is shutdown + */ + snprintf(ublkc, sizeof(ublkc), "%s%d", "ublkc", dev_id); + ret = wait_ublk_dev(ublkc, IN_CLOSE_WRITE, 10); + waitpid(dev->dev_info.ublksrv_pid, NULL, 0); + ublk_dbg(UBLK_DBG_DEV, "%s: pid %d dev_id %d ret %d\n", + __func__, daemon_pid, dev_id, ret); + + return ret; +} + +static int cmd_dev_add(char *tgt_type, int *exp_id, unsigned nr_queues, + unsigned depth) +{ + const struct ublk_tgt_ops *ops; + struct ublksrv_ctrl_dev_info *info; + struct ublk_dev *dev; + int dev_id = *exp_id; + char ublkb[64]; + int ret; + + ops = ublk_find_tgt(tgt_type); + if (!ops) { + ublk_err("%s: no such tgt type, type %s\n", + __func__, tgt_type); + return -ENODEV; + } + + if (nr_queues > UBLK_MAX_QUEUES || depth > UBLK_QUEUE_DEPTH) { + ublk_err("%s: invalid nr_queues or depth queues %u depth %u\n", + __func__, nr_queues, depth); + return -EINVAL; + } + + dev = ublk_ctrl_init(); + if (!dev) { + ublk_err("%s: can't alloc dev id %d, type %s\n", + __func__, dev_id, tgt_type); + return -ENOMEM; + } + + info = &dev->dev_info; + info->dev_id = dev_id; + info->nr_hw_queues = nr_queues; + info->queue_depth = depth; + dev->tgt.ops = ops; + + ret = ublk_ctrl_add_dev(dev); + if (ret < 0) { + ublk_err("%s: can't add dev id %d, type %s ret %d\n", + __func__, dev_id, tgt_type, ret); + goto fail; + } + + switch (fork()) { + case -1: + goto fail; + case 0: + ublk_start_daemon(dev); + return 0; + } + + /* + * Wait until ublk disk is added, when our daemon is started + * successfully + */ + snprintf(ublkb, sizeof(ublkb), "%s%u", "ublkb", dev->dev_info.dev_id); + ret = wait_ublk_dev(ublkb, IN_CREATE, 3); + if (ret < 0) { + ublk_err("%s: can't start daemon id %d, type %s\n", + __func__, dev_id, tgt_type); + ublk_ctrl_del_dev(dev); + } else { + *exp_id = dev->dev_info.dev_id; + } +fail: + ublk_ctrl_deinit(dev); + return ret; +} + +static int cmd_dev_del_by_kill(int number) +{ + struct ublk_dev *dev; + int ret; + + dev = ublk_ctrl_init(); + dev->dev_info.dev_id = number; + + ret = ublk_ctrl_get_info(dev); + if (ret < 0) + goto fail; + + /* simulate one ublk daemon panic */ + kill(dev->dev_info.ublksrv_pid, 9); + + ret = ublk_stop_io_daemon(dev); + if (ret < 0) + ublk_err("%s: can't stop daemon id %d\n", __func__, number); + ublk_ctrl_del_dev(dev); +fail: + if (ret >= 0) + ret = ublk_ctrl_get_info(dev); + ublk_ctrl_deinit(dev); + + return (ret != 0) ? 0 : -EIO; +} + +/****************** part 2: target implementation ********************/ + +static int ublk_null_tgt_init(struct ublk_dev *dev) +{ + const struct ublksrv_ctrl_dev_info *info = &dev->dev_info; + unsigned long dev_size = 250UL << 30; + + dev->tgt.dev_size = dev_size; + dev->tgt.params = (struct ublk_params) { + .types = UBLK_PARAM_TYPE_BASIC, + .basic = { + .logical_bs_shift = 9, + .physical_bs_shift = 12, + .io_opt_shift = 12, + .io_min_shift = 9, + .max_sectors = info->max_io_buf_bytes >> 9, + .dev_sectors = dev_size >> 9, + }, + }; + + return 0; +} + +static int ublk_null_queue_io(struct ublk_queue *q, int tag) +{ + const struct ublksrv_io_desc *iod = ublk_get_iod(q, tag); + + ublk_complete_io(q, tag, iod->nr_sectors << 9); + + return 0; +} + +static const struct ublk_tgt_ops tgt_ops_list[] = { + { + .name = "null", + .init_tgt = ublk_null_tgt_init, + .queue_io = ublk_null_queue_io, + }, +}; + +static const struct ublk_tgt_ops *ublk_find_tgt(const char *name) +{ + const struct ublk_tgt_ops *ops; + int i; + + if (name == NULL) + return NULL; + + for (i = 0; sizeof(tgt_ops_list) / sizeof(*ops); i++) + if (strcmp(tgt_ops_list[i].name, name) == 0) + return &tgt_ops_list[i]; + return NULL; +} + + +/****************** part 3: IO test over ublk disk ********************/ + +#include "helpers.h" +#include "liburing.h" +#define BS 4096 +#define BUFFERS 128 + +struct io_ctx { + int dev_id; + int write; + int seq; + + /* output */ + int res; + pthread_t handle; +}; + +static int __test_io(struct io_uring *ring, int fd, int write, + int seq, struct iovec *vecs, int exp_len, off_t start) +{ + struct io_uring_sqe *sqe; + struct io_uring_cqe *cqe; + int i, ret; + off_t offset; + + offset = start; + for (i = 0; i < BUFFERS; i++) { + sqe = io_uring_get_sqe(ring); + if (!sqe) { + fprintf(stderr, "sqe get failed\n"); + goto err; + } + if (!seq) + offset = start + BS * (rand() % BUFFERS); + if (write) { + io_uring_prep_write_fixed(sqe, fd, vecs[i].iov_base, + vecs[i].iov_len, + offset, i); + } else { + io_uring_prep_read_fixed(sqe, fd, vecs[i].iov_base, + vecs[i].iov_len, + offset, i); + } + sqe->user_data = i; + if (seq) + offset += BS; + } + + ret = io_uring_submit(ring); + if (ret != BUFFERS) { + fprintf(stderr, "submit got %d, wanted %d\n", ret, BUFFERS); + goto err; + } + + for (i = 0; i < BUFFERS; i++) { + ret = io_uring_wait_cqe(ring, &cqe); + if (ret) { + fprintf(stderr, "wait_cqe=%d\n", ret); + goto err; + } + if (exp_len == -1) { + int iov_len = vecs[cqe->user_data].iov_len; + + if (cqe->res != iov_len) { + fprintf(stderr, "cqe res %d, wanted %d\n", + cqe->res, iov_len); + goto err; + } + } else if (cqe->res != exp_len) { + fprintf(stderr, "cqe res %d, wanted %d\n", cqe->res, exp_len); + goto err; + } + io_uring_cqe_seen(ring, cqe); + } + + return 0; +err: + return 1; +} + +/* Run IO over ublk block device */ +static int test_io(struct io_ctx *ctx) +{ + struct io_uring ring; + int ret, ring_flags = 0; + char buf[256]; + int fd = -1; + off_t offset = 0; + unsigned long long bytes; + int open_flags = O_DIRECT; + struct iovec *vecs = t_create_buffers(BUFFERS, BS); + + ret = t_create_ring(BUFFERS, &ring, ring_flags); + if (ret == T_SETUP_SKIP) + return 0; + if (ret != T_SETUP_OK) { + fprintf(stderr, "ring create failed: %d\n", ret); + return 1; + } + + snprintf(buf, sizeof(buf), "%s%d", UBLKB_DEV, ctx->dev_id); + + if (ctx->write) + open_flags |= O_WRONLY; + else + open_flags |= O_RDONLY; + fd = open(buf, open_flags); + if (fd < 0) { + if (errno == EINVAL) + return 0; + return 1; + } + + if (ioctl(fd, BLKGETSIZE64, &bytes) != 0) + return 1; + + ret = t_register_buffers(&ring, vecs, BUFFERS); + if (ret == T_SETUP_SKIP) + return 0; + if (ret != T_SETUP_OK) { + fprintf(stderr, "buffer reg failed: %d\n", ret); + return 1; + } + + for (offset = 0; offset < bytes; offset += BS * BUFFERS) { + ret = __test_io(&ring, fd, ctx->write, ctx->seq, vecs, BS, + offset); + if (ret != T_SETUP_OK) { + fprintf(stderr, "/dev/ublkb%d read failed: offset %lu ret %d\n", + ctx->dev_id, (unsigned long) offset, ret); + break; + } + } + + close(fd); + io_uring_unregister_buffers(&ring); + io_uring_queue_exit(&ring); + + return ret; +} + +static void *test_io_fn(void *data) +{ + struct io_ctx *ctx = data; + + ctx->res = test_io(ctx); + + return data; +} + +static void ignore_stderr(void) +{ + int devnull = open("/dev/null", O_WRONLY); + + if (devnull >= 0) { + dup2(devnull, fileno(stderr)); + close(devnull); + } +} + +static int test_io_worker(int dev_id) +{ + const int nr_jobs = 4; + struct io_ctx ctx[nr_jobs]; + int i, ret = 0; + + for (i = 0; i < nr_jobs; i++) { + ctx[i].dev_id = dev_id; + ctx[i].write = (i & 0x1) ? 0 : 1; + ctx[i].seq = 1; + + pthread_create(&ctx[i].handle, NULL, test_io_fn, &ctx[i]); + } + + for (i = 0; i < nr_jobs; i++) { + pthread_join(ctx[i].handle, NULL); + + if (!ret && ctx[i].res) + ret = ctx[i].res; + } + + return ret; +} + +/* + * Run IO over created ublk device, meantime delete this ublk device + * + * Cover cancellable uring_cmd + * */ +static int test_del_ublk_with_io(void) +{ + const unsigned wait_ms = 200; + char *tgt_type = "null"; + int dev_id = -1; + int ret, pid; + + ret = cmd_dev_add(tgt_type, &dev_id, 2, BUFFERS); + if (ret != T_SETUP_OK) { + fprintf(stderr, "buffer reg failed: %d\n", ret); + return T_EXIT_FAIL; + } + + switch ((pid = fork())) { + case -1: + fprintf(stderr, "fork failed\n"); + return T_EXIT_FAIL; + case 0: + /* io error is expected since the parent is killing ublk */ + ignore_stderr(); + test_io_worker(dev_id); + return 0; + default: + /* + * Wait a little while until ublk IO pipeline is warm up, + * then try to shutdown ublk device by `kill -9 $ublk_daemon_pid`. + * + * cancellable uring_cmd code path can be covered in this way. + */ + usleep(wait_ms * 1000); + ret = cmd_dev_del_by_kill(dev_id); + waitpid(pid, NULL, 0); + return ret; + } +} + +int main(int argc, char *argv[]) +{ + const int nr_loop = 4; + struct ublk_dev *dev; + __u64 features; + int ret, i; + + if (argc > 1) + return T_EXIT_SKIP; + + dev = ublk_ctrl_init(); + /* ublk isn't supported or the module isn't loaded */ + if (!dev) + return T_EXIT_SKIP; + + /* kernel doesn't support get_features */ + ret = ublk_ctrl_get_features(dev, &features); + if (ret < 0) + return T_EXIT_SKIP; + + if (!(features & UBLK_F_CMD_IOCTL_ENCODE)) + return T_EXIT_SKIP; + + for (i = 0; i < nr_loop; i++) { + if (test_del_ublk_with_io()) + return T_EXIT_FAIL; + } + ublk_ctrl_deinit(dev); + return T_EXIT_PASS; +} +#else +int main(int argc, char *argv[]) +{ + return T_EXIT_SKIP; +} +#endif diff --git a/contrib/libs/liburing/test/uring_cmd_ublk.t/ya.make b/contrib/libs/liburing/test/uring_cmd_ublk.t/ya.make new file mode 100644 index 0000000000..edc9a36693 --- /dev/null +++ b/contrib/libs/liburing/test/uring_cmd_ublk.t/ya.make @@ -0,0 +1,35 @@ +# Generated by devtools/yamaker. + +PROGRAM() + +WITHOUT_LICENSE_TEXTS() + +VERSION(2.8) + +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 + uring_cmd_ublk.c +) + +END() diff --git a/contrib/libs/liburing/test/version.t/ya.make b/contrib/libs/liburing/test/version.t/ya.make index 8f387e4ca4..aca2c8b392 100644 --- a/contrib/libs/liburing/test/version.t/ya.make +++ b/contrib/libs/liburing/test/version.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/wait-timeout.c b/contrib/libs/liburing/test/wait-timeout.c new file mode 100644 index 0000000000..3d05a8763e --- /dev/null +++ b/contrib/libs/liburing/test/wait-timeout.c @@ -0,0 +1,288 @@ +#include "../config-host.h" +/* SPDX-License-Identifier: MIT */ +/* + * Description: run various timeout tests + * + */ +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <assert.h> + +#include "helpers.h" +#include "liburing.h" +#include "../src/syscall.h" + +#define IO_NSEC_PER_SEC 1000000000ULL + +static bool support_abs = false; +static bool support_clock = false; + +static unsigned long long timespec_to_ns(struct timespec *ts) +{ + return ts->tv_nsec + ts->tv_sec * IO_NSEC_PER_SEC; +} +static struct timespec ns_to_timespec(unsigned long long t) +{ + struct timespec ts; + + ts.tv_sec = t / IO_NSEC_PER_SEC; + ts.tv_nsec = t - ts.tv_sec * IO_NSEC_PER_SEC; + return ts; +} + +static long long ns_since(struct timespec *ts) +{ + struct timespec now; + int ret; + + ret = clock_gettime(CLOCK_MONOTONIC, &now); + if (ret) { + fprintf(stderr, "clock_gettime failed\n"); + exit(T_EXIT_FAIL); + } + + return timespec_to_ns(&now) - timespec_to_ns(ts); + +} + +static int t_io_uring_wait(struct io_uring *ring, int nr, unsigned enter_flags, + struct timespec *ts) +{ + struct __kernel_timespec kts = { + .tv_sec = ts->tv_sec, + .tv_nsec = ts->tv_nsec + }; + struct io_uring_getevents_arg arg = { + .sigmask = 0, + .sigmask_sz = _NSIG / 8, + .ts = (unsigned long) &kts + }; + int ret; + + enter_flags |= IORING_ENTER_GETEVENTS | IORING_ENTER_EXT_ARG; + ret = io_uring_enter2(ring->ring_fd, 0, nr, enter_flags, + (void *)&arg, sizeof(arg)); + return ret; +} + +static int probe_timers(void) +{ + struct io_uring_clock_register cr = { .clockid = CLOCK_MONOTONIC, }; + struct io_uring ring; + struct timespec ts; + int ret; + + ret = io_uring_queue_init(8, &ring, 0); + if (ret) { + fprintf(stderr, "probe ring setup failed: %d\n", ret); + return ret; + } + + ret = clock_gettime(CLOCK_MONOTONIC, &ts); + if (ret) { + fprintf(stderr, "clock_gettime failed\n"); + return ret; + } + + ret = t_io_uring_wait(&ring, 0, IORING_ENTER_ABS_TIMER, &ts); + if (!ret) { + support_abs = true; + } else if (ret != -EINVAL) { + fprintf(stderr, "wait failed %i\n", ret); + return ret; + } + + ret = io_uring_register_clock(&ring, &cr); + if (!ret) { + support_clock = true; + } else if (ret != -EINVAL) { + fprintf(stderr, "io_uring_register_clock %i\n", ret); + return ret; + } + + io_uring_queue_exit(&ring); + return 0; +} + +static int test_timeout(bool abs, bool set_clock) +{ + unsigned enter_flags = abs ? IORING_ENTER_ABS_TIMER : 0; + struct io_uring ring; + struct timespec start, end, ts; + long long dt; + int ret; + + ret = io_uring_queue_init(8, &ring, 0); + if (ret) { + fprintf(stderr, "ring setup failed: %d\n", ret); + return 1; + } + + if (set_clock) { + struct io_uring_clock_register cr = {}; + + cr.clockid = CLOCK_BOOTTIME; + ret = io_uring_register_clock(&ring, &cr); + if (ret) { + fprintf(stderr, "io_uring_register_clock failed\n"); + return 1; + } + } + + /* pass current time */ + ret = clock_gettime(CLOCK_MONOTONIC, &start); + assert(ret == 0); + + ts = abs ? start : ns_to_timespec(0); + ret = t_io_uring_wait(&ring, 1, enter_flags, &ts); + if (ret != -ETIME) { + fprintf(stderr, "wait current time failed, %i\n", ret); + return 1; + } + + if (ns_since(&start) >= IO_NSEC_PER_SEC) { + fprintf(stderr, "current time test failed\n"); + return 1; + } + + if (abs) { + /* expired time */ + ret = clock_gettime(CLOCK_MONOTONIC, &start); + assert(ret == 0); + ts = ns_to_timespec(timespec_to_ns(&start) - IO_NSEC_PER_SEC); + + ret = t_io_uring_wait(&ring, 1, enter_flags, &ts); + if (ret != -ETIME) { + fprintf(stderr, "expired timeout wait failed, %i\n", ret); + return 1; + } + + ret = clock_gettime(CLOCK_MONOTONIC, &end); + assert(ret == 0); + + if (ns_since(&start) >= IO_NSEC_PER_SEC) { + fprintf(stderr, "expired timer test failed\n"); + return 1; + } + } + + /* 1s wait */ + ret = clock_gettime(CLOCK_MONOTONIC, &start); + assert(ret == 0); + + dt = 2 * IO_NSEC_PER_SEC + (abs ? timespec_to_ns(&start) : 0); + ts = ns_to_timespec(dt); + ret = t_io_uring_wait(&ring, 1, enter_flags, &ts); + if (ret != -ETIME) { + fprintf(stderr, "wait timeout failed, %i\n", ret); + return 1; + } + + dt = ns_since(&start); + if (dt < IO_NSEC_PER_SEC || dt > 3 * IO_NSEC_PER_SEC) { + fprintf(stderr, "early wake up, %lld\n", dt); + return 1; + } + return 0; +} + +static int test_clock_setup(void) +{ + struct io_uring ring; + struct io_uring_clock_register cr = {}; + int ret; + + ret = io_uring_queue_init(8, &ring, 0); + if (ret) { + fprintf(stderr, "ring setup failed: %d\n", ret); + return T_EXIT_FAIL; + } + + ret = __sys_io_uring_register(ring.ring_fd, IORING_REGISTER_CLOCK, NULL, 0); + if (!ret) { + fprintf(stderr, "invalid null clock registration %i\n", ret); + return T_EXIT_FAIL; + } + + cr.clockid = -1; + ret = __sys_io_uring_register(ring.ring_fd, IORING_REGISTER_CLOCK, &cr, 0); + if (ret != -EINVAL) { + fprintf(stderr, "invalid clockid registration %i\n", ret); + return T_EXIT_FAIL; + } + + cr.clockid = CLOCK_MONOTONIC; + ret = __sys_io_uring_register(ring.ring_fd, IORING_REGISTER_CLOCK, &cr, 0); + if (ret) { + fprintf(stderr, "clock monotonic registration failed %i\n", ret); + return T_EXIT_FAIL; + } + + cr.clockid = CLOCK_BOOTTIME; + ret = __sys_io_uring_register(ring.ring_fd, IORING_REGISTER_CLOCK, &cr, 0); + if (ret) { + fprintf(stderr, "clock boottime registration failed %i\n", ret); + return T_EXIT_FAIL; + } + + cr.clockid = CLOCK_MONOTONIC; + ret = __sys_io_uring_register(ring.ring_fd, IORING_REGISTER_CLOCK, &cr, 0); + if (ret) { + fprintf(stderr, "2nd clock monotonic registration failed %i\n", ret); + return T_EXIT_FAIL; + } + + io_uring_queue_exit(&ring); + return 0; +} + +int main(int argc, char *argv[]) +{ + int ret, i; + + if (argc > 1) + return 0; + + ret = probe_timers(); + if (ret) { + fprintf(stderr, "probe failed\n"); + return T_EXIT_FAIL; + } + if (!support_abs && !support_clock) + return T_EXIT_SKIP; + + if (support_clock) { + ret = test_clock_setup(); + if (ret) { + fprintf(stderr, "test_clock_setup failed\n"); + return T_EXIT_FAIL; + } + } + + for (i = 0; i < 4; i++) { + bool abs = i & 1; + bool clock = i & 2; + + if (abs && !support_abs) + continue; + if (clock && !support_clock) + continue; + + ret = test_timeout(abs, clock); + if (ret) { + fprintf(stderr, "test_timeout failed %i %i\n", + abs, clock); + return ret; + } + } + + return 0; +} diff --git a/contrib/libs/liburing/test/wait-timeout.t/ya.make b/contrib/libs/liburing/test/wait-timeout.t/ya.make new file mode 100644 index 0000000000..ac1b89877f --- /dev/null +++ b/contrib/libs/liburing/test/wait-timeout.t/ya.make @@ -0,0 +1,35 @@ +# Generated by devtools/yamaker. + +PROGRAM() + +WITHOUT_LICENSE_TEXTS() + +VERSION(2.8) + +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 + wait-timeout.c +) + +END() diff --git a/contrib/libs/liburing/test/waitid.c b/contrib/libs/liburing/test/waitid.c index f7ebe55ac7..d66e483026 100644 --- a/contrib/libs/liburing/test/waitid.c +++ b/contrib/libs/liburing/test/waitid.c @@ -20,6 +20,39 @@ static void child(long usleep_time) exit(0); } +static int test_invalid_infop(struct io_uring *ring) +{ + struct io_uring_sqe *sqe; + struct io_uring_cqe *cqe; + siginfo_t *si = (siginfo_t *) (uintptr_t) 0x1234; + int ret, w; + pid_t pid; + + 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->user_data = 1; + 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 != -EFAULT) { + fprintf(stderr, "Bad return on invalid infop: %d\n", cqe->res); + return T_EXIT_FAIL; + } + io_uring_cqe_seen(ring, cqe); + wait(&w); + return T_EXIT_PASS; +} + /* * Test linked timeout with child not exiting in time */ @@ -28,9 +61,9 @@ static int test_noexit(struct io_uring *ring) struct io_uring_sqe *sqe; struct io_uring_cqe *cqe; struct __kernel_timespec ts; + int ret, i, w; siginfo_t si; pid_t pid; - int ret, i; pid = fork(); if (!pid) { @@ -68,6 +101,7 @@ static int test_noexit(struct io_uring *ring) io_uring_cqe_seen(ring, cqe); } + wait(&w); return T_EXIT_PASS; } @@ -80,7 +114,7 @@ static int test_double(struct io_uring *ring) struct io_uring_cqe *cqe; siginfo_t si; pid_t p1, p2; - int ret; + int ret, w; /* p1 will exit shortly */ p1 = fork(); @@ -117,6 +151,7 @@ static int test_double(struct io_uring *ring) } io_uring_cqe_seen(ring, cqe); + wait(&w); return T_EXIT_PASS; } @@ -168,7 +203,7 @@ static int test_cancel(struct io_uring *ring) { struct io_uring_sqe *sqe; struct io_uring_cqe *cqe; - int ret, i; + int ret, i, w; pid_t pid; pid = fork(); @@ -206,6 +241,7 @@ static int test_cancel(struct io_uring *ring) io_uring_cqe_seen(ring, cqe); } + wait(&w); return T_EXIT_PASS; } @@ -217,10 +253,12 @@ static int test_cancel_race(struct io_uring *ring, int async) { struct io_uring_sqe *sqe; struct io_uring_cqe *cqe; - int ret, i; + int ret, i, to_wait, total_forks; pid_t pid; + total_forks = 0; for (i = 0; i < 10; i++) { + total_forks++; pid = fork(); if (!pid) { child(getpid() & 1); @@ -244,16 +282,20 @@ static int test_cancel_race(struct io_uring *ring, int async) io_uring_submit(ring); + to_wait = total_forks; 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 == 1) { + if (!cqe->res) + to_wait--; + if (!(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 || @@ -264,6 +306,12 @@ static int test_cancel_race(struct io_uring *ring, int async) io_uring_cqe_seen(ring, cqe); } + for (i = 0; i < to_wait; i++) { + int w; + + wait(&w); + } + return T_EXIT_PASS; } @@ -361,6 +409,12 @@ int main(int argc, char *argv[]) return T_EXIT_FAIL; } + ret = test_invalid_infop(&ring); + if (ret == T_EXIT_FAIL) { + fprintf(stderr, "test_invalid_infop failed\n"); + return T_EXIT_FAIL; + } + for (i = 0; i < 1000; i++) { ret = test_cancel_race(&ring, i & 1); if (ret == T_EXIT_FAIL) { diff --git a/contrib/libs/liburing/test/waitid.t/ya.make b/contrib/libs/liburing/test/waitid.t/ya.make index d1b66baa8b..e3b160a48b 100644 --- a/contrib/libs/liburing/test/waitid.t/ya.make +++ b/contrib/libs/liburing/test/waitid.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/wakeup-hang.t/ya.make b/contrib/libs/liburing/test/wakeup-hang.t/ya.make index 32f72dadef..0dbdefae8c 100644 --- a/contrib/libs/liburing/test/wakeup-hang.t/ya.make +++ b/contrib/libs/liburing/test/wakeup-hang.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/wq-aff.c b/contrib/libs/liburing/test/wq-aff.c index 0548d6a698..0d3c10d3ef 100644 --- a/contrib/libs/liburing/test/wq-aff.c +++ b/contrib/libs/liburing/test/wq-aff.c @@ -128,6 +128,33 @@ static int test(int sqpoll) return ret; } +static int test_invalid_cpu(void) +{ + struct io_uring_params p = { }; + struct io_uring ring; + int ret, nr_cpus; + + nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); + if (nr_cpus < 0) { + perror("sysconf(_SC_NPROCESSORS_ONLN"); + return T_EXIT_SKIP; + } + + p.flags = IORING_SETUP_SQPOLL | IORING_SETUP_SQ_AFF; + p.sq_thread_cpu = 16 * nr_cpus; + + ret = io_uring_queue_init_params(8, &ring, &p); + if (ret == -EPERM) { + return T_EXIT_SKIP; + } else if (ret != -EINVAL) { + fprintf(stderr, "Queue init: %d\n", ret); + return T_EXIT_FAIL; + } + + io_uring_queue_exit(&ring); + return T_EXIT_PASS; +} + int main(int argc, char *argv[]) { int ret; @@ -135,6 +162,14 @@ int main(int argc, char *argv[]) if (argc > 1) return T_EXIT_SKIP; + ret = test_invalid_cpu(); + if (ret == T_EXIT_SKIP) { + return T_EXIT_SKIP; + } else if (ret != T_EXIT_PASS) { + fprintf(stderr, "test sqpoll cpu failed\n"); + return T_EXIT_FAIL; + } + ret = test(1); if (ret == T_EXIT_SKIP) { return T_EXIT_SKIP; diff --git a/contrib/libs/liburing/test/wq-aff.t/ya.make b/contrib/libs/liburing/test/wq-aff.t/ya.make index fc8c72502a..28c8e06301 100644 --- a/contrib/libs/liburing/test/wq-aff.t/ya.make +++ b/contrib/libs/liburing/test/wq-aff.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/test/xattr.t/ya.make b/contrib/libs/liburing/test/xattr.t/ya.make index 9a4d76006a..1ef224a2df 100644 --- a/contrib/libs/liburing/test/xattr.t/ya.make +++ b/contrib/libs/liburing/test/xattr.t/ya.make @@ -4,7 +4,7 @@ PROGRAM() WITHOUT_LICENSE_TEXTS() -VERSION(2.7) +VERSION(2.8) LICENSE(MIT) diff --git a/contrib/libs/liburing/ya.make b/contrib/libs/liburing/ya.make index 9ee5aee27d..776c355623 100644 --- a/contrib/libs/liburing/ya.make +++ b/contrib/libs/liburing/ya.make @@ -2,9 +2,9 @@ LIBRARY() -VERSION(2.7) +VERSION(2.8) -ORIGINAL_SOURCE(https://github.com/axboe/liburing/archive/liburing-2.7.tar.gz) +ORIGINAL_SOURCE(https://github.com/axboe/liburing/archive/liburing-2.8.tar.gz) LICENSE( "(GPL-2.0-only WITH Linux-syscall-note OR MIT)" AND @@ -60,6 +60,7 @@ RECURSE( test/buf-ring.t test/ce593a6c480a.t test/close-opath.t + test/cmd-discard.t test/connect-rep.t test/connect.t test/coredump.t @@ -90,6 +91,8 @@ RECURSE( test/fc2a85cb02ef.t test/fd-install.t test/fd-pass.t + test/fdinfo.t + test/fifo-nonblock-read.t test/file-register.t test/file-update.t test/file-verify.t @@ -114,18 +117,23 @@ RECURSE( test/iopoll-leak.t test/iopoll-overflow.t test/iopoll.t + test/kallsyms.t test/lfs-openat-write.t test/lfs-openat.t test/link-timeout.t test/link.t test/link_drain.t + test/linked-defer-close.t test/madvise.t + test/min-timeout-wait.t + test/min-timeout.t test/mkdir.t test/msg-ring-fd.t test/msg-ring-flags.t test/msg-ring-overflow.t test/msg-ring.t test/multicqes_drain.t + test/napi-test.t test/no-mmap-inval.t test/nolibc.t test/nop-all-sizes.t @@ -151,18 +159,22 @@ RECURSE( test/poll-ring.t test/poll-v-poll.t test/poll.t + test/pollfree.t test/probe.t test/read-before-exit.t test/read-mshot-empty.t + test/read-mshot-stdin.t test/read-mshot.t test/read-write.t test/recv-msgall-stream.t test/recv-msgall.t test/recv-multishot.t + test/recvsend_bundle-inc.t test/recvsend_bundle.t test/reg-fd-only.t test/reg-hint.t test/reg-reg-ring.t + test/regbuf-clone.t test/regbuf-merge.t test/register-restrictions.t test/rename.t @@ -199,6 +211,7 @@ RECURSE( test/sqpoll-exec.t test/sqpoll-exit-hang.t test/sqpoll-sleep.t + test/sqwait.t test/stdout.t test/submit-and-wait.t test/submit-link-fail.t @@ -212,7 +225,9 @@ RECURSE( test/truncate.t test/tty-write-dpoll.t test/unlink.t + test/uring_cmd_ublk.t test/version.t + test/wait-timeout.t test/waitid.t test/wakeup-hang.t test/wq-aff.t |