* [RFC PATCH liburing] man: Convert manpages to markdown
@ 2026-06-18 23:05 Gabriel Krisman Bertazi
2026-06-18 23:53 ` Ammar Faizi
0 siblings, 1 reply; 3+ messages in thread
From: Gabriel Krisman Bertazi @ 2026-06-18 23:05 UTC (permalink / raw)
To: axboe; +Cc: io-uring, Gabriel Krisman Bertazi
This has been discussed for a while due to the ongoing pain of writing
groff. Now that we just had a release, convert the manpages to markdown
and add infrastructure to generate back the groff automatically during
compilation.
The conversion is not lossless, mostly due to groff being painful.
You'll notice the conversion is not byte-per-byte accurate, but most of
the differences are whitespace, which is not relevant. Other more
tricky changes are in bold/italics, which I tried to preserve as much as
possible, but some cases will require manually fixing up the man pages
if we want keep byte-per-byte compatibility.
This obviously adds a build dependency on pandoc, which is already
packaged by any sane distro out there. The configure file is updated to
check for that.
There are a few caveats worth mentioned:
1) Groff comments need to be preserved because of copyrights
notices. This is done by a pre-processor python script.
2) A pandoc filter is applied to preserve bold in codeblocks. This has
to be written in Lua, a language I don't know, so I took help from an AI
agent for this part. The script is a few lines long, though, making it
not even copyrightable :)
3) We have a large number of symlinks. These are kept in an ALIAS file
and also re-generated during compilation.
This is an RFC since Jens is away anyway, and there might be some rough
edges I have not found.
Signed-off-by: Gabriel Krisman Bertazi <krisman@suse.de>
---
Makefile | 1 +
configure | 8 +
man/.gitignore | 8 +
man/ALIASES | 62 +
man/IO_URING_CHECK_VERSION.3 | 1 -
man/IO_URING_VERSION_MAJOR.3 | 1 -
man/IO_URING_VERSION_MINOR.3 | 1 -
man/Makefile | 26 +
man/__io_uring_buf_ring_cq_advance.3 | 1 -
man/filters/bold-block.lua | 14 +
| 18 +
man/io_uring.7 | 919 -------
man/io_uring.7.md | 538 ++++
man/io_uring_buf_ring_add.3 | 64 -
man/io_uring_buf_ring_add.3.md | 44 +
man/io_uring_buf_ring_advance.3 | 31 -
man/io_uring_buf_ring_advance.3.md | 34 +
man/io_uring_buf_ring_available.3 | 47 -
man/io_uring_buf_ring_available.3.md | 41 +
man/io_uring_buf_ring_cq_advance.3 | 55 -
man/io_uring_buf_ring_cq_advance.3.md | 42 +
man/io_uring_buf_ring_init.3 | 36 -
man/io_uring_buf_ring_init.3.md | 37 +
man/io_uring_buf_ring_mask.3 | 27 -
man/io_uring_buf_ring_mask.3.md | 33 +
man/io_uring_cancelation.7 | 324 ---
man/io_uring_cancelation.7.md | 221 ++
man/io_uring_check_version.3 | 72 -
man/io_uring_check_version.3.md | 42 +
man/io_uring_clone_buffers.3 | 165 --
man/io_uring_clone_buffers.3.md | 90 +
man/io_uring_clone_buffers_offset.3 | 1 -
man/io_uring_close_ring_fd.3 | 43 -
man/io_uring_close_ring_fd.3.md | 42 +
man/io_uring_cq_advance.3 | 49 -
man/io_uring_cq_advance.3.md | 40 +
man/io_uring_cq_eventfd_enabled.3 | 38 -
man/io_uring_cq_eventfd_enabled.3.md | 35 +
man/io_uring_cq_eventfd_toggle.3 | 48 -
man/io_uring_cq_eventfd_toggle.3.md | 41 +
man/io_uring_cq_has_overflow.3 | 31 -
man/io_uring_cq_has_overflow.3.md | 37 +
man/io_uring_cq_ready.3 | 26 -
man/io_uring_cq_ready.3.md | 33 +
man/io_uring_cqe_get_data.3 | 53 -
man/io_uring_cqe_get_data.3.md | 39 +
man/io_uring_cqe_get_data64.3 | 1 -
man/io_uring_cqe_nr.3 | 35 -
man/io_uring_cqe_nr.3.md | 35 +
man/io_uring_cqe_seen.3 | 41 -
man/io_uring_cqe_seen.3.md | 38 +
man/io_uring_enable_rings.3 | 40 -
man/io_uring_enable_rings.3.md | 41 +
man/io_uring_enter.2 | 2208 -----------------
man/io_uring_enter.2.md | 745 ++++++
man/io_uring_enter2.2 | 1 -
man/io_uring_for_each_cqe.3 | 63 -
man/io_uring_for_each_cqe.3.md | 54 +
man/io_uring_free_buf_ring.3 | 53 -
man/io_uring_free_buf_ring.3.md | 43 +
man/io_uring_free_probe.3 | 27 -
man/io_uring_free_probe.3.md | 33 +
man/io_uring_get_events.3 | 33 -
man/io_uring_get_events.3.md | 35 +
man/io_uring_get_probe.3 | 30 -
man/io_uring_get_probe.3.md | 37 +
man/io_uring_get_probe_ring.3 | 39 -
man/io_uring_get_probe_ring.3.md | 37 +
man/io_uring_get_sqe.3 | 57 -
man/io_uring_get_sqe.3.md | 40 +
man/io_uring_get_sqe128.3 | 67 -
man/io_uring_get_sqe128.3.md | 40 +
man/io_uring_linked_requests.7 | 271 --
man/io_uring_linked_requests.7.md | 212 ++
man/io_uring_major_version.3 | 1 -
man/io_uring_memory_size_params.3 | 45 -
man/io_uring_memory_size_params.3.md | 41 +
man/io_uring_minor_version.3 | 1 -
man/io_uring_mlock_size.3 | 42 -
man/io_uring_mlock_size.3.md | 37 +
man/io_uring_mlock_size_params.3 | 48 -
man/io_uring_mlock_size_params.3.md | 37 +
man/io_uring_multishot.7 | 246 --
man/io_uring_multishot.7.md | 164 ++
man/io_uring_opcode_supported.3 | 30 -
man/io_uring_opcode_supported.3.md | 34 +
man/io_uring_peek_batch_cqe.3 | 1 -
man/io_uring_peek_cqe.3 | 59 -
man/io_uring_peek_cqe.3.md | 42 +
man/io_uring_prep_accept.3 | 203 --
man/io_uring_prep_accept.3.md | 93 +
man/io_uring_prep_accept_direct.3 | 1 -
man/io_uring_prep_bind.3 | 54 -
man/io_uring_prep_bind.3.md | 43 +
man/io_uring_prep_cancel.3 | 136 -
man/io_uring_prep_cancel.3.md | 97 +
man/io_uring_prep_cancel64.3 | 1 -
man/io_uring_prep_cancel_fd.3 | 1 -
man/io_uring_prep_close.3 | 67 -
man/io_uring_prep_close.3.md | 45 +
man/io_uring_prep_close_direct.3 | 1 -
man/io_uring_prep_cmd_discard.3 | 64 -
man/io_uring_prep_cmd_discard.3.md | 44 +
man/io_uring_prep_cmd_getsockname.3 | 79 -
man/io_uring_prep_cmd_getsockname.3.md | 45 +
man/io_uring_prep_cmd_sock.3 | 219 --
man/io_uring_prep_cmd_sock.3.md | 109 +
man/io_uring_prep_connect.3 | 66 -
man/io_uring_prep_connect.3.md | 48 +
man/io_uring_prep_epoll_ctl.3 | 74 -
man/io_uring_prep_epoll_ctl.3.md | 57 +
man/io_uring_prep_epoll_wait.3 | 64 -
man/io_uring_prep_epoll_wait.3.md | 44 +
man/io_uring_prep_fadvise.3 | 76 -
man/io_uring_prep_fadvise.3.md | 52 +
man/io_uring_prep_fadvise64.3 | 1 -
man/io_uring_prep_fallocate.3 | 59 -
man/io_uring_prep_fallocate.3.md | 44 +
man/io_uring_prep_fgetxattr.3 | 1 -
man/io_uring_prep_files_update.3 | 92 -
man/io_uring_prep_files_update.3.md | 68 +
man/io_uring_prep_fixed_fd_install.3 | 70 -
man/io_uring_prep_fixed_fd_install.3.md | 45 +
man/io_uring_prep_fsetxattr.3 | 1 -
man/io_uring_prep_fsync.3 | 70 -
man/io_uring_prep_fsync.3.md | 43 +
man/io_uring_prep_ftruncate.3 | 54 -
man/io_uring_prep_ftruncate.3.md | 41 +
man/io_uring_prep_futex_wait.3 | 94 -
man/io_uring_prep_futex_wait.3.md | 58 +
man/io_uring_prep_futex_waitv.3 | 78 -
man/io_uring_prep_futex_waitv.3.md | 54 +
man/io_uring_prep_futex_wake.3 | 86 -
man/io_uring_prep_futex_wake.3.md | 52 +
man/io_uring_prep_getxattr.3 | 61 -
man/io_uring_prep_getxattr.3.md | 47 +
man/io_uring_prep_link.3 | 1 -
man/io_uring_prep_link_timeout.3 | 98 -
man/io_uring_prep_link_timeout.3.md | 86 +
man/io_uring_prep_linkat.3 | 91 -
man/io_uring_prep_linkat.3.md | 57 +
man/io_uring_prep_listen.3 | 52 -
man/io_uring_prep_listen.3.md | 42 +
man/io_uring_prep_madvise.3 | 72 -
man/io_uring_prep_madvise.3.md | 50 +
man/io_uring_prep_madvise64.3 | 1 -
man/io_uring_prep_mkdir.3 | 1 -
man/io_uring_prep_mkdirat.3 | 83 -
man/io_uring_prep_mkdirat.3.md | 54 +
man/io_uring_prep_msg_ring.3 | 92 -
man/io_uring_prep_msg_ring.3.md | 64 +
man/io_uring_prep_msg_ring_cqe_flags.3 | 1 -
man/io_uring_prep_msg_ring_fd.3 | 83 -
man/io_uring_prep_msg_ring_fd.3.md | 70 +
man/io_uring_prep_msg_ring_fd_alloc.3 | 1 -
man/io_uring_prep_multishot_accept.3 | 1 -
man/io_uring_prep_multishot_accept_direct.3 | 1 -
man/io_uring_prep_nop.3 | 28 -
man/io_uring_prep_nop.3.md | 37 +
man/io_uring_prep_nop128.3 | 30 -
man/io_uring_prep_nop128.3.md | 37 +
man/io_uring_prep_open.3 | 1 -
man/io_uring_prep_open_direct.3 | 1 -
man/io_uring_prep_openat.3 | 138 --
man/io_uring_prep_openat.3.md | 78 +
man/io_uring_prep_openat2.3 | 119 -
man/io_uring_prep_openat2.3.md | 66 +
man/io_uring_prep_openat2_direct.3 | 1 -
man/io_uring_prep_openat_direct.3 | 1 -
man/io_uring_prep_pipe.3 | 91 -
man/io_uring_prep_pipe.3.md | 50 +
man/io_uring_prep_pipe_direct.3 | 1 -
man/io_uring_prep_poll_add.3 | 72 -
man/io_uring_prep_poll_add.3.md | 46 +
man/io_uring_prep_poll_multishot.3 | 1 -
man/io_uring_prep_poll_remove.3 | 55 -
man/io_uring_prep_poll_remove.3.md | 53 +
man/io_uring_prep_poll_update.3 | 101 -
man/io_uring_prep_poll_update.3.md | 72 +
man/io_uring_prep_provide_buffers.3 | 140 --
man/io_uring_prep_provide_buffers.3.md | 76 +
man/io_uring_prep_read.3 | 76 -
man/io_uring_prep_read.3.md | 51 +
man/io_uring_prep_read_fixed.3 | 79 -
man/io_uring_prep_read_fixed.3.md | 50 +
man/io_uring_prep_read_multishot.3 | 107 -
man/io_uring_prep_read_multishot.3.md | 59 +
man/io_uring_prep_readv.3 | 92 -
man/io_uring_prep_readv.3.md | 54 +
man/io_uring_prep_readv2.3 | 118 -
man/io_uring_prep_readv2.3.md | 77 +
man/io_uring_prep_readv_fixed.3 | 74 -
man/io_uring_prep_readv_fixed.3.md | 53 +
man/io_uring_prep_recv.3 | 147 --
man/io_uring_prep_recv.3.md | 67 +
man/io_uring_prep_recv_multishot.3 | 1 -
man/io_uring_prep_recvmsg.3 | 130 -
man/io_uring_prep_recvmsg.3.md | 69 +
man/io_uring_prep_recvmsg_multishot.3 | 1 -
man/io_uring_prep_remove_buffers.3 | 52 -
man/io_uring_prep_remove_buffers.3.md | 51 +
man/io_uring_prep_rename.3 | 1 -
man/io_uring_prep_renameat.3 | 95 -
man/io_uring_prep_renameat.3.md | 56 +
man/io_uring_prep_send.3 | 197 --
man/io_uring_prep_send.3.md | 84 +
man/io_uring_prep_send_bundle.3 | 1 -
man/io_uring_prep_send_set_addr.3 | 38 -
man/io_uring_prep_send_set_addr.3.md | 35 +
man/io_uring_prep_send_zc.3 | 140 --
man/io_uring_prep_send_zc.3.md | 72 +
man/io_uring_prep_send_zc_fixed.3 | 1 -
man/io_uring_prep_sendmsg.3 | 136 -
man/io_uring_prep_sendmsg.3.md | 71 +
man/io_uring_prep_sendmsg_zc.3 | 1 -
man/io_uring_prep_sendmsg_zc_fixed.3 | 69 -
man/io_uring_prep_sendmsg_zc_fixed.3.md | 51 +
man/io_uring_prep_sendto.3 | 1 -
man/io_uring_prep_setxattr.3 | 64 -
man/io_uring_prep_setxattr.3.md | 49 +
man/io_uring_prep_shutdown.3 | 53 -
man/io_uring_prep_shutdown.3.md | 42 +
man/io_uring_prep_socket.3 | 118 -
man/io_uring_prep_socket.3.md | 65 +
man/io_uring_prep_socket_direct.3 | 1 -
man/io_uring_prep_socket_direct_alloc.3 | 1 -
man/io_uring_prep_splice.3 | 126 -
man/io_uring_prep_splice.3.md | 62 +
man/io_uring_prep_statx.3 | 74 -
man/io_uring_prep_statx.3.md | 52 +
man/io_uring_prep_symlink.3 | 1 -
man/io_uring_prep_symlinkat.3 | 85 -
man/io_uring_prep_symlinkat.3.md | 54 +
man/io_uring_prep_sync_file_range.3 | 59 -
man/io_uring_prep_sync_file_range.3.md | 44 +
man/io_uring_prep_tee.3 | 80 -
man/io_uring_prep_tee.3.md | 50 +
man/io_uring_prep_timeout.3 | 121 -
man/io_uring_prep_timeout.3.md | 90 +
man/io_uring_prep_timeout_remove.3 | 1 -
man/io_uring_prep_timeout_update.3 | 85 -
man/io_uring_prep_timeout_update.3.md | 72 +
man/io_uring_prep_unlink.3 | 1 -
man/io_uring_prep_unlinkat.3 | 82 -
man/io_uring_prep_unlinkat.3.md | 54 +
man/io_uring_prep_uring_cmd.3 | 37 -
man/io_uring_prep_uring_cmd.3.md | 41 +
man/io_uring_prep_uring_cmd128.3 | 38 -
man/io_uring_prep_uring_cmd128.3.md | 41 +
man/io_uring_prep_waitid.3 | 67 -
man/io_uring_prep_waitid.3.md | 47 +
man/io_uring_prep_write.3 | 70 -
man/io_uring_prep_write.3.md | 51 +
man/io_uring_prep_write_fixed.3 | 75 -
man/io_uring_prep_write_fixed.3.md | 50 +
man/io_uring_prep_writev.3 | 89 -
man/io_uring_prep_writev.3.md | 54 +
man/io_uring_prep_writev2.3 | 115 -
man/io_uring_prep_writev2.3.md | 77 +
man/io_uring_prep_writev_fixed.3 | 71 -
man/io_uring_prep_writev_fixed.3.md | 53 +
man/io_uring_provided_buffers.7 | 266 --
man/io_uring_provided_buffers.7.md | 189 ++
man/io_uring_queue_exit.3 | 30 -
man/io_uring_queue_exit.3.md | 36 +
man/io_uring_queue_init.3 | 144 --
man/io_uring_queue_init.3.md | 59 +
man/io_uring_queue_init_mem.3 | 1 -
man/io_uring_queue_init_params.3 | 1 -
man/io_uring_queue_mmap.3 | 49 -
man/io_uring_queue_mmap.3.md | 38 +
man/io_uring_recvmsg_cmsg_firsthdr.3 | 1 -
man/io_uring_recvmsg_cmsg_nexthdr.3 | 1 -
man/io_uring_recvmsg_name.3 | 1 -
man/io_uring_recvmsg_out.3 | 82 -
man/io_uring_recvmsg_out.3.md | 72 +
man/io_uring_recvmsg_payload.3 | 1 -
man/io_uring_recvmsg_payload_length.3 | 1 -
man/io_uring_recvmsg_validate.3 | 1 -
man/io_uring_register.2 | 1375 ----------
man/io_uring_register.2.md | 553 +++++
man/io_uring_register_bpf_filter.3 | 411 ---
man/io_uring_register_bpf_filter.3.md | 267 ++
man/io_uring_register_bpf_filter_task.3 | 1 -
man/io_uring_register_buf_ring.3 | 165 --
man/io_uring_register_buf_ring.3.md | 88 +
man/io_uring_register_buffers.3 | 105 -
man/io_uring_register_buffers.3.md | 59 +
man/io_uring_register_buffers_sparse.3 | 1 -
man/io_uring_register_buffers_tags.3 | 1 -
man/io_uring_register_buffers_update_tag.3 | 1 -
man/io_uring_register_clock.3 | 72 -
man/io_uring_register_clock.3.md | 57 +
man/io_uring_register_eventfd.3 | 50 -
man/io_uring_register_eventfd.3.md | 47 +
man/io_uring_register_eventfd_async.3 | 1 -
man/io_uring_register_file_alloc_range.3 | 52 -
man/io_uring_register_file_alloc_range.3.md | 40 +
man/io_uring_register_files.3 | 120 -
man/io_uring_register_files.3.md | 66 +
man/io_uring_register_files_sparse.3 | 1 -
man/io_uring_register_files_tags.3 | 1 -
man/io_uring_register_files_update.3 | 1 -
man/io_uring_register_files_update_tag.3 | 1 -
man/io_uring_register_ifq.3 | 49 -
man/io_uring_register_ifq.3.md | 38 +
man/io_uring_register_iowq_aff.3 | 67 -
man/io_uring_register_iowq_aff.3.md | 54 +
man/io_uring_register_iowq_max_workers.3 | 71 -
man/io_uring_register_iowq_max_workers.3.md | 56 +
man/io_uring_register_napi.3 | 40 -
man/io_uring_register_napi.3.md | 34 +
man/io_uring_register_personality.3 | 34 -
man/io_uring_register_personality.3.md | 35 +
man/io_uring_register_probe.3 | 47 -
man/io_uring_register_probe.3.md | 39 +
man/io_uring_register_query.3 | 114 -
man/io_uring_register_query.3.md | 74 +
man/io_uring_register_region.3 | 124 -
man/io_uring_register_region.3.md | 77 +
man/io_uring_register_restrictions.3 | 53 -
man/io_uring_register_restrictions.3.md | 41 +
man/io_uring_register_ring_fd.3 | 51 -
man/io_uring_register_ring_fd.3.md | 45 +
man/io_uring_register_sync_cancel.3 | 73 -
man/io_uring_register_sync_cancel.3.md | 50 +
man/io_uring_register_sync_msg.3 | 74 -
man/io_uring_register_sync_msg.3.md | 43 +
man/io_uring_register_wait_reg.3 | 45 -
man/io_uring_register_wait_reg.3.md | 39 +
man/io_uring_register_zcrx_ctrl.3 | 84 -
man/io_uring_register_zcrx_ctrl.3.md | 62 +
man/io_uring_registered_buffers.7 | 238 --
man/io_uring_registered_buffers.7.md | 147 ++
man/io_uring_registered_files.7 | 228 --
man/io_uring_registered_files.7.md | 149 ++
man/io_uring_resize_rings.3 | 116 -
man/io_uring_resize_rings.3.md | 82 +
man/io_uring_ring_dontfork.3 | 36 -
man/io_uring_ring_dontfork.3.md | 35 +
man/io_uring_set_iowait.3 | 57 -
man/io_uring_set_iowait.3.md | 43 +
man/io_uring_setup.2 | 820 ------
man/io_uring_setup.2.md | 334 +++
man/io_uring_setup_buf_ring.3 | 94 -
man/io_uring_setup_buf_ring.3.md | 56 +
man/io_uring_setup_flags.7 | 451 ----
man/io_uring_setup_flags.7.md | 236 ++
man/io_uring_sq_ready.3 | 31 -
man/io_uring_sq_ready.3.md | 35 +
man/io_uring_sq_space_left.3 | 25 -
man/io_uring_sq_space_left.3.md | 33 +
man/io_uring_sqe_set_buf_group.3 | 32 -
man/io_uring_sqe_set_buf_group.3.md | 36 +
man/io_uring_sqe_set_data.3 | 57 -
man/io_uring_sqe_set_data.3.md | 43 +
man/io_uring_sqe_set_data64.3 | 1 -
man/io_uring_sqe_set_flags.3 | 87 -
man/io_uring_sqe_set_flags.3.md | 64 +
man/io_uring_sqpoll.7 | 259 --
man/io_uring_sqpoll.7.md | 173 ++
man/io_uring_sqring_wait.3 | 34 -
man/io_uring_sqring_wait.3.md | 35 +
man/io_uring_submit.3 | 51 -
man/io_uring_submit.3.md | 39 +
man/io_uring_submit_and_get_events.3 | 31 -
man/io_uring_submit_and_get_events.3.md | 34 +
man/io_uring_submit_and_wait.3 | 44 -
man/io_uring_submit_and_wait.3.md | 38 +
man/io_uring_submit_and_wait_min_timeout.3 | 119 -
man/io_uring_submit_and_wait_min_timeout.3.md | 54 +
man/io_uring_submit_and_wait_reg.3 | 64 -
man/io_uring_submit_and_wait_reg.3.md | 42 +
man/io_uring_submit_and_wait_timeout.3 | 74 -
man/io_uring_submit_and_wait_timeout.3.md | 49 +
man/io_uring_unregister_buf_ring.3 | 30 -
man/io_uring_unregister_buf_ring.3.md | 35 +
man/io_uring_unregister_buffers.3 | 27 -
man/io_uring_unregister_buffers.3.md | 33 +
man/io_uring_unregister_eventfd.3 | 1 -
man/io_uring_unregister_files.3 | 27 -
man/io_uring_unregister_files.3.md | 33 +
man/io_uring_unregister_iowq_aff.3 | 1 -
man/io_uring_unregister_napi.3 | 27 -
man/io_uring_unregister_napi.3.md | 30 +
man/io_uring_unregister_personality.3 | 33 -
man/io_uring_unregister_personality.3.md | 35 +
man/io_uring_unregister_ring_fd.3 | 32 -
man/io_uring_unregister_ring_fd.3.md | 35 +
man/io_uring_wait_cqe.3 | 41 -
man/io_uring_wait_cqe.3.md | 36 +
man/io_uring_wait_cqe_nr.3 | 49 -
man/io_uring_wait_cqe_nr.3.md | 39 +
man/io_uring_wait_cqe_timeout.3 | 62 -
man/io_uring_wait_cqe_timeout.3.md | 41 +
man/io_uring_wait_cqes.3 | 82 -
man/io_uring_wait_cqes.3.md | 51 +
man/io_uring_wait_cqes_min_timeout.3 | 76 -
man/io_uring_wait_cqes_min_timeout.3.md | 50 +
399 files changed, 11719 insertions(+), 18975 deletions(-)
create mode 100644 man/.gitignore
create mode 100644 man/ALIASES
delete mode 120000 man/IO_URING_CHECK_VERSION.3
delete mode 120000 man/IO_URING_VERSION_MAJOR.3
delete mode 120000 man/IO_URING_VERSION_MINOR.3
create mode 100644 man/Makefile
delete mode 120000 man/__io_uring_buf_ring_cq_advance.3
create mode 100644 man/filters/bold-block.lua
create mode 100755 man/filters/preserve-comments.py
delete mode 100644 man/io_uring.7
create mode 100644 man/io_uring.7.md
delete mode 100644 man/io_uring_buf_ring_add.3
create mode 100644 man/io_uring_buf_ring_add.3.md
delete mode 100644 man/io_uring_buf_ring_advance.3
create mode 100644 man/io_uring_buf_ring_advance.3.md
delete mode 100644 man/io_uring_buf_ring_available.3
create mode 100644 man/io_uring_buf_ring_available.3.md
delete mode 100644 man/io_uring_buf_ring_cq_advance.3
create mode 100644 man/io_uring_buf_ring_cq_advance.3.md
delete mode 100644 man/io_uring_buf_ring_init.3
create mode 100644 man/io_uring_buf_ring_init.3.md
delete mode 100644 man/io_uring_buf_ring_mask.3
create mode 100644 man/io_uring_buf_ring_mask.3.md
delete mode 100644 man/io_uring_cancelation.7
create mode 100644 man/io_uring_cancelation.7.md
delete mode 100644 man/io_uring_check_version.3
create mode 100644 man/io_uring_check_version.3.md
delete mode 100644 man/io_uring_clone_buffers.3
create mode 100644 man/io_uring_clone_buffers.3.md
delete mode 120000 man/io_uring_clone_buffers_offset.3
delete mode 100644 man/io_uring_close_ring_fd.3
create mode 100644 man/io_uring_close_ring_fd.3.md
delete mode 100644 man/io_uring_cq_advance.3
create mode 100644 man/io_uring_cq_advance.3.md
delete mode 100644 man/io_uring_cq_eventfd_enabled.3
create mode 100644 man/io_uring_cq_eventfd_enabled.3.md
delete mode 100644 man/io_uring_cq_eventfd_toggle.3
create mode 100644 man/io_uring_cq_eventfd_toggle.3.md
delete mode 100644 man/io_uring_cq_has_overflow.3
create mode 100644 man/io_uring_cq_has_overflow.3.md
delete mode 100644 man/io_uring_cq_ready.3
create mode 100644 man/io_uring_cq_ready.3.md
delete mode 100644 man/io_uring_cqe_get_data.3
create mode 100644 man/io_uring_cqe_get_data.3.md
delete mode 120000 man/io_uring_cqe_get_data64.3
delete mode 100644 man/io_uring_cqe_nr.3
create mode 100644 man/io_uring_cqe_nr.3.md
delete mode 100644 man/io_uring_cqe_seen.3
create mode 100644 man/io_uring_cqe_seen.3.md
delete mode 100644 man/io_uring_enable_rings.3
create mode 100644 man/io_uring_enable_rings.3.md
delete mode 100644 man/io_uring_enter.2
create mode 100644 man/io_uring_enter.2.md
delete mode 120000 man/io_uring_enter2.2
delete mode 100644 man/io_uring_for_each_cqe.3
create mode 100644 man/io_uring_for_each_cqe.3.md
delete mode 100644 man/io_uring_free_buf_ring.3
create mode 100644 man/io_uring_free_buf_ring.3.md
delete mode 100644 man/io_uring_free_probe.3
create mode 100644 man/io_uring_free_probe.3.md
delete mode 100644 man/io_uring_get_events.3
create mode 100644 man/io_uring_get_events.3.md
delete mode 100644 man/io_uring_get_probe.3
create mode 100644 man/io_uring_get_probe.3.md
delete mode 100644 man/io_uring_get_probe_ring.3
create mode 100644 man/io_uring_get_probe_ring.3.md
delete mode 100644 man/io_uring_get_sqe.3
create mode 100644 man/io_uring_get_sqe.3.md
delete mode 100644 man/io_uring_get_sqe128.3
create mode 100644 man/io_uring_get_sqe128.3.md
delete mode 100644 man/io_uring_linked_requests.7
create mode 100644 man/io_uring_linked_requests.7.md
delete mode 120000 man/io_uring_major_version.3
delete mode 100644 man/io_uring_memory_size_params.3
create mode 100644 man/io_uring_memory_size_params.3.md
delete mode 120000 man/io_uring_minor_version.3
delete mode 100644 man/io_uring_mlock_size.3
create mode 100644 man/io_uring_mlock_size.3.md
delete mode 100644 man/io_uring_mlock_size_params.3
create mode 100644 man/io_uring_mlock_size_params.3.md
delete mode 100644 man/io_uring_multishot.7
create mode 100644 man/io_uring_multishot.7.md
delete mode 100644 man/io_uring_opcode_supported.3
create mode 100644 man/io_uring_opcode_supported.3.md
delete mode 120000 man/io_uring_peek_batch_cqe.3
delete mode 100644 man/io_uring_peek_cqe.3
create mode 100644 man/io_uring_peek_cqe.3.md
delete mode 100644 man/io_uring_prep_accept.3
create mode 100644 man/io_uring_prep_accept.3.md
delete mode 120000 man/io_uring_prep_accept_direct.3
delete mode 100644 man/io_uring_prep_bind.3
create mode 100644 man/io_uring_prep_bind.3.md
delete mode 100644 man/io_uring_prep_cancel.3
create mode 100644 man/io_uring_prep_cancel.3.md
delete mode 120000 man/io_uring_prep_cancel64.3
delete mode 120000 man/io_uring_prep_cancel_fd.3
delete mode 100644 man/io_uring_prep_close.3
create mode 100644 man/io_uring_prep_close.3.md
delete mode 120000 man/io_uring_prep_close_direct.3
delete mode 100644 man/io_uring_prep_cmd_discard.3
create mode 100644 man/io_uring_prep_cmd_discard.3.md
delete mode 100644 man/io_uring_prep_cmd_getsockname.3
create mode 100644 man/io_uring_prep_cmd_getsockname.3.md
delete mode 100644 man/io_uring_prep_cmd_sock.3
create mode 100644 man/io_uring_prep_cmd_sock.3.md
delete mode 100644 man/io_uring_prep_connect.3
create mode 100644 man/io_uring_prep_connect.3.md
delete mode 100644 man/io_uring_prep_epoll_ctl.3
create mode 100644 man/io_uring_prep_epoll_ctl.3.md
delete mode 100644 man/io_uring_prep_epoll_wait.3
create mode 100644 man/io_uring_prep_epoll_wait.3.md
delete mode 100644 man/io_uring_prep_fadvise.3
create mode 100644 man/io_uring_prep_fadvise.3.md
delete mode 120000 man/io_uring_prep_fadvise64.3
delete mode 100644 man/io_uring_prep_fallocate.3
create mode 100644 man/io_uring_prep_fallocate.3.md
delete mode 120000 man/io_uring_prep_fgetxattr.3
delete mode 100644 man/io_uring_prep_files_update.3
create mode 100644 man/io_uring_prep_files_update.3.md
delete mode 100644 man/io_uring_prep_fixed_fd_install.3
create mode 100644 man/io_uring_prep_fixed_fd_install.3.md
delete mode 120000 man/io_uring_prep_fsetxattr.3
delete mode 100644 man/io_uring_prep_fsync.3
create mode 100644 man/io_uring_prep_fsync.3.md
delete mode 100644 man/io_uring_prep_ftruncate.3
create mode 100644 man/io_uring_prep_ftruncate.3.md
delete mode 100644 man/io_uring_prep_futex_wait.3
create mode 100644 man/io_uring_prep_futex_wait.3.md
delete mode 100644 man/io_uring_prep_futex_waitv.3
create mode 100644 man/io_uring_prep_futex_waitv.3.md
delete mode 100644 man/io_uring_prep_futex_wake.3
create mode 100644 man/io_uring_prep_futex_wake.3.md
delete mode 100644 man/io_uring_prep_getxattr.3
create mode 100644 man/io_uring_prep_getxattr.3.md
delete mode 120000 man/io_uring_prep_link.3
delete mode 100644 man/io_uring_prep_link_timeout.3
create mode 100644 man/io_uring_prep_link_timeout.3.md
delete mode 100644 man/io_uring_prep_linkat.3
create mode 100644 man/io_uring_prep_linkat.3.md
delete mode 100644 man/io_uring_prep_listen.3
create mode 100644 man/io_uring_prep_listen.3.md
delete mode 100644 man/io_uring_prep_madvise.3
create mode 100644 man/io_uring_prep_madvise.3.md
delete mode 120000 man/io_uring_prep_madvise64.3
delete mode 120000 man/io_uring_prep_mkdir.3
delete mode 100644 man/io_uring_prep_mkdirat.3
create mode 100644 man/io_uring_prep_mkdirat.3.md
delete mode 100644 man/io_uring_prep_msg_ring.3
create mode 100644 man/io_uring_prep_msg_ring.3.md
delete mode 120000 man/io_uring_prep_msg_ring_cqe_flags.3
delete mode 100644 man/io_uring_prep_msg_ring_fd.3
create mode 100644 man/io_uring_prep_msg_ring_fd.3.md
delete mode 120000 man/io_uring_prep_msg_ring_fd_alloc.3
delete mode 120000 man/io_uring_prep_multishot_accept.3
delete mode 120000 man/io_uring_prep_multishot_accept_direct.3
delete mode 100644 man/io_uring_prep_nop.3
create mode 100644 man/io_uring_prep_nop.3.md
delete mode 100644 man/io_uring_prep_nop128.3
create mode 100644 man/io_uring_prep_nop128.3.md
delete mode 120000 man/io_uring_prep_open.3
delete mode 120000 man/io_uring_prep_open_direct.3
delete mode 100644 man/io_uring_prep_openat.3
create mode 100644 man/io_uring_prep_openat.3.md
delete mode 100644 man/io_uring_prep_openat2.3
create mode 100644 man/io_uring_prep_openat2.3.md
delete mode 120000 man/io_uring_prep_openat2_direct.3
delete mode 120000 man/io_uring_prep_openat_direct.3
delete mode 100644 man/io_uring_prep_pipe.3
create mode 100644 man/io_uring_prep_pipe.3.md
delete mode 120000 man/io_uring_prep_pipe_direct.3
delete mode 100644 man/io_uring_prep_poll_add.3
create mode 100644 man/io_uring_prep_poll_add.3.md
delete mode 120000 man/io_uring_prep_poll_multishot.3
delete mode 100644 man/io_uring_prep_poll_remove.3
create mode 100644 man/io_uring_prep_poll_remove.3.md
delete mode 100644 man/io_uring_prep_poll_update.3
create mode 100644 man/io_uring_prep_poll_update.3.md
delete mode 100644 man/io_uring_prep_provide_buffers.3
create mode 100644 man/io_uring_prep_provide_buffers.3.md
delete mode 100644 man/io_uring_prep_read.3
create mode 100644 man/io_uring_prep_read.3.md
delete mode 100644 man/io_uring_prep_read_fixed.3
create mode 100644 man/io_uring_prep_read_fixed.3.md
delete mode 100644 man/io_uring_prep_read_multishot.3
create mode 100644 man/io_uring_prep_read_multishot.3.md
delete mode 100644 man/io_uring_prep_readv.3
create mode 100644 man/io_uring_prep_readv.3.md
delete mode 100644 man/io_uring_prep_readv2.3
create mode 100644 man/io_uring_prep_readv2.3.md
delete mode 100644 man/io_uring_prep_readv_fixed.3
create mode 100644 man/io_uring_prep_readv_fixed.3.md
delete mode 100644 man/io_uring_prep_recv.3
create mode 100644 man/io_uring_prep_recv.3.md
delete mode 120000 man/io_uring_prep_recv_multishot.3
delete mode 100644 man/io_uring_prep_recvmsg.3
create mode 100644 man/io_uring_prep_recvmsg.3.md
delete mode 120000 man/io_uring_prep_recvmsg_multishot.3
delete mode 100644 man/io_uring_prep_remove_buffers.3
create mode 100644 man/io_uring_prep_remove_buffers.3.md
delete mode 120000 man/io_uring_prep_rename.3
delete mode 100644 man/io_uring_prep_renameat.3
create mode 100644 man/io_uring_prep_renameat.3.md
delete mode 100644 man/io_uring_prep_send.3
create mode 100644 man/io_uring_prep_send.3.md
delete mode 120000 man/io_uring_prep_send_bundle.3
delete mode 100644 man/io_uring_prep_send_set_addr.3
create mode 100644 man/io_uring_prep_send_set_addr.3.md
delete mode 100644 man/io_uring_prep_send_zc.3
create mode 100644 man/io_uring_prep_send_zc.3.md
delete mode 120000 man/io_uring_prep_send_zc_fixed.3
delete mode 100644 man/io_uring_prep_sendmsg.3
create mode 100644 man/io_uring_prep_sendmsg.3.md
delete mode 120000 man/io_uring_prep_sendmsg_zc.3
delete mode 100644 man/io_uring_prep_sendmsg_zc_fixed.3
create mode 100644 man/io_uring_prep_sendmsg_zc_fixed.3.md
delete mode 120000 man/io_uring_prep_sendto.3
delete mode 100644 man/io_uring_prep_setxattr.3
create mode 100644 man/io_uring_prep_setxattr.3.md
delete mode 100644 man/io_uring_prep_shutdown.3
create mode 100644 man/io_uring_prep_shutdown.3.md
delete mode 100644 man/io_uring_prep_socket.3
create mode 100644 man/io_uring_prep_socket.3.md
delete mode 120000 man/io_uring_prep_socket_direct.3
delete mode 120000 man/io_uring_prep_socket_direct_alloc.3
delete mode 100644 man/io_uring_prep_splice.3
create mode 100644 man/io_uring_prep_splice.3.md
delete mode 100644 man/io_uring_prep_statx.3
create mode 100644 man/io_uring_prep_statx.3.md
delete mode 120000 man/io_uring_prep_symlink.3
delete mode 100644 man/io_uring_prep_symlinkat.3
create mode 100644 man/io_uring_prep_symlinkat.3.md
delete mode 100644 man/io_uring_prep_sync_file_range.3
create mode 100644 man/io_uring_prep_sync_file_range.3.md
delete mode 100644 man/io_uring_prep_tee.3
create mode 100644 man/io_uring_prep_tee.3.md
delete mode 100644 man/io_uring_prep_timeout.3
create mode 100644 man/io_uring_prep_timeout.3.md
delete mode 120000 man/io_uring_prep_timeout_remove.3
delete mode 100644 man/io_uring_prep_timeout_update.3
create mode 100644 man/io_uring_prep_timeout_update.3.md
delete mode 120000 man/io_uring_prep_unlink.3
delete mode 100644 man/io_uring_prep_unlinkat.3
create mode 100644 man/io_uring_prep_unlinkat.3.md
delete mode 100644 man/io_uring_prep_uring_cmd.3
create mode 100644 man/io_uring_prep_uring_cmd.3.md
delete mode 100644 man/io_uring_prep_uring_cmd128.3
create mode 100644 man/io_uring_prep_uring_cmd128.3.md
delete mode 100644 man/io_uring_prep_waitid.3
create mode 100644 man/io_uring_prep_waitid.3.md
delete mode 100644 man/io_uring_prep_write.3
create mode 100644 man/io_uring_prep_write.3.md
delete mode 100644 man/io_uring_prep_write_fixed.3
create mode 100644 man/io_uring_prep_write_fixed.3.md
delete mode 100644 man/io_uring_prep_writev.3
create mode 100644 man/io_uring_prep_writev.3.md
delete mode 100644 man/io_uring_prep_writev2.3
create mode 100644 man/io_uring_prep_writev2.3.md
delete mode 100644 man/io_uring_prep_writev_fixed.3
create mode 100644 man/io_uring_prep_writev_fixed.3.md
delete mode 100644 man/io_uring_provided_buffers.7
create mode 100644 man/io_uring_provided_buffers.7.md
delete mode 100644 man/io_uring_queue_exit.3
create mode 100644 man/io_uring_queue_exit.3.md
delete mode 100644 man/io_uring_queue_init.3
create mode 100644 man/io_uring_queue_init.3.md
delete mode 120000 man/io_uring_queue_init_mem.3
delete mode 120000 man/io_uring_queue_init_params.3
delete mode 100644 man/io_uring_queue_mmap.3
create mode 100644 man/io_uring_queue_mmap.3.md
delete mode 120000 man/io_uring_recvmsg_cmsg_firsthdr.3
delete mode 120000 man/io_uring_recvmsg_cmsg_nexthdr.3
delete mode 120000 man/io_uring_recvmsg_name.3
delete mode 100644 man/io_uring_recvmsg_out.3
create mode 100644 man/io_uring_recvmsg_out.3.md
delete mode 120000 man/io_uring_recvmsg_payload.3
delete mode 120000 man/io_uring_recvmsg_payload_length.3
delete mode 120000 man/io_uring_recvmsg_validate.3
delete mode 100644 man/io_uring_register.2
create mode 100644 man/io_uring_register.2.md
delete mode 100644 man/io_uring_register_bpf_filter.3
create mode 100644 man/io_uring_register_bpf_filter.3.md
delete mode 120000 man/io_uring_register_bpf_filter_task.3
delete mode 100644 man/io_uring_register_buf_ring.3
create mode 100644 man/io_uring_register_buf_ring.3.md
delete mode 100644 man/io_uring_register_buffers.3
create mode 100644 man/io_uring_register_buffers.3.md
delete mode 120000 man/io_uring_register_buffers_sparse.3
delete mode 120000 man/io_uring_register_buffers_tags.3
delete mode 120000 man/io_uring_register_buffers_update_tag.3
delete mode 100644 man/io_uring_register_clock.3
create mode 100644 man/io_uring_register_clock.3.md
delete mode 100644 man/io_uring_register_eventfd.3
create mode 100644 man/io_uring_register_eventfd.3.md
delete mode 120000 man/io_uring_register_eventfd_async.3
delete mode 100644 man/io_uring_register_file_alloc_range.3
create mode 100644 man/io_uring_register_file_alloc_range.3.md
delete mode 100644 man/io_uring_register_files.3
create mode 100644 man/io_uring_register_files.3.md
delete mode 120000 man/io_uring_register_files_sparse.3
delete mode 120000 man/io_uring_register_files_tags.3
delete mode 120000 man/io_uring_register_files_update.3
delete mode 120000 man/io_uring_register_files_update_tag.3
delete mode 100644 man/io_uring_register_ifq.3
create mode 100644 man/io_uring_register_ifq.3.md
delete mode 100644 man/io_uring_register_iowq_aff.3
create mode 100644 man/io_uring_register_iowq_aff.3.md
delete mode 100644 man/io_uring_register_iowq_max_workers.3
create mode 100644 man/io_uring_register_iowq_max_workers.3.md
delete mode 100644 man/io_uring_register_napi.3
create mode 100644 man/io_uring_register_napi.3.md
delete mode 100644 man/io_uring_register_personality.3
create mode 100644 man/io_uring_register_personality.3.md
delete mode 100644 man/io_uring_register_probe.3
create mode 100644 man/io_uring_register_probe.3.md
delete mode 100644 man/io_uring_register_query.3
create mode 100644 man/io_uring_register_query.3.md
delete mode 100644 man/io_uring_register_region.3
create mode 100644 man/io_uring_register_region.3.md
delete mode 100644 man/io_uring_register_restrictions.3
create mode 100644 man/io_uring_register_restrictions.3.md
delete mode 100644 man/io_uring_register_ring_fd.3
create mode 100644 man/io_uring_register_ring_fd.3.md
delete mode 100644 man/io_uring_register_sync_cancel.3
create mode 100644 man/io_uring_register_sync_cancel.3.md
delete mode 100644 man/io_uring_register_sync_msg.3
create mode 100644 man/io_uring_register_sync_msg.3.md
delete mode 100644 man/io_uring_register_wait_reg.3
create mode 100644 man/io_uring_register_wait_reg.3.md
delete mode 100644 man/io_uring_register_zcrx_ctrl.3
create mode 100644 man/io_uring_register_zcrx_ctrl.3.md
delete mode 100644 man/io_uring_registered_buffers.7
create mode 100644 man/io_uring_registered_buffers.7.md
delete mode 100644 man/io_uring_registered_files.7
create mode 100644 man/io_uring_registered_files.7.md
delete mode 100644 man/io_uring_resize_rings.3
create mode 100644 man/io_uring_resize_rings.3.md
delete mode 100644 man/io_uring_ring_dontfork.3
create mode 100644 man/io_uring_ring_dontfork.3.md
delete mode 100644 man/io_uring_set_iowait.3
create mode 100644 man/io_uring_set_iowait.3.md
delete mode 100644 man/io_uring_setup.2
create mode 100644 man/io_uring_setup.2.md
delete mode 100644 man/io_uring_setup_buf_ring.3
create mode 100644 man/io_uring_setup_buf_ring.3.md
delete mode 100644 man/io_uring_setup_flags.7
create mode 100644 man/io_uring_setup_flags.7.md
delete mode 100644 man/io_uring_sq_ready.3
create mode 100644 man/io_uring_sq_ready.3.md
delete mode 100644 man/io_uring_sq_space_left.3
create mode 100644 man/io_uring_sq_space_left.3.md
delete mode 100644 man/io_uring_sqe_set_buf_group.3
create mode 100644 man/io_uring_sqe_set_buf_group.3.md
delete mode 100644 man/io_uring_sqe_set_data.3
create mode 100644 man/io_uring_sqe_set_data.3.md
delete mode 120000 man/io_uring_sqe_set_data64.3
delete mode 100644 man/io_uring_sqe_set_flags.3
create mode 100644 man/io_uring_sqe_set_flags.3.md
delete mode 100644 man/io_uring_sqpoll.7
create mode 100644 man/io_uring_sqpoll.7.md
delete mode 100644 man/io_uring_sqring_wait.3
create mode 100644 man/io_uring_sqring_wait.3.md
delete mode 100644 man/io_uring_submit.3
create mode 100644 man/io_uring_submit.3.md
delete mode 100644 man/io_uring_submit_and_get_events.3
create mode 100644 man/io_uring_submit_and_get_events.3.md
delete mode 100644 man/io_uring_submit_and_wait.3
create mode 100644 man/io_uring_submit_and_wait.3.md
delete mode 100644 man/io_uring_submit_and_wait_min_timeout.3
create mode 100644 man/io_uring_submit_and_wait_min_timeout.3.md
delete mode 100644 man/io_uring_submit_and_wait_reg.3
create mode 100644 man/io_uring_submit_and_wait_reg.3.md
delete mode 100644 man/io_uring_submit_and_wait_timeout.3
create mode 100644 man/io_uring_submit_and_wait_timeout.3.md
delete mode 100644 man/io_uring_unregister_buf_ring.3
create mode 100644 man/io_uring_unregister_buf_ring.3.md
delete mode 100644 man/io_uring_unregister_buffers.3
create mode 100644 man/io_uring_unregister_buffers.3.md
delete mode 120000 man/io_uring_unregister_eventfd.3
delete mode 100644 man/io_uring_unregister_files.3
create mode 100644 man/io_uring_unregister_files.3.md
delete mode 120000 man/io_uring_unregister_iowq_aff.3
delete mode 100644 man/io_uring_unregister_napi.3
create mode 100644 man/io_uring_unregister_napi.3.md
delete mode 100644 man/io_uring_unregister_personality.3
create mode 100644 man/io_uring_unregister_personality.3.md
delete mode 100644 man/io_uring_unregister_ring_fd.3
create mode 100644 man/io_uring_unregister_ring_fd.3.md
delete mode 100644 man/io_uring_wait_cqe.3
create mode 100644 man/io_uring_wait_cqe.3.md
delete mode 100644 man/io_uring_wait_cqe_nr.3
create mode 100644 man/io_uring_wait_cqe_nr.3.md
delete mode 100644 man/io_uring_wait_cqe_timeout.3
create mode 100644 man/io_uring_wait_cqe_timeout.3.md
delete mode 100644 man/io_uring_wait_cqes.3
create mode 100644 man/io_uring_wait_cqes.3.md
delete mode 100644 man/io_uring_wait_cqes_min_timeout.3
create mode 100644 man/io_uring_wait_cqes_min_timeout.3.md
diff --git a/Makefile b/Makefile
index a2c8e10f..f3300062 100644
--- a/Makefile
+++ b/Makefile
@@ -13,6 +13,7 @@ all:
@$(MAKE) -C src
@$(MAKE) -C test
@$(MAKE) -C examples
+ @$(MAKE) -C man
library:
@$(MAKE) -C src
diff --git a/configure b/configure
index 39c377c9..98761b49 100755
--- a/configure
+++ b/configure
@@ -530,6 +530,14 @@ if test "$has_clang" = "yes" && test "$has_bpftool" = "yes" && test "$has_bpf_cl
output_mak "bpf_toolchain" "y"
fi
+#############################################################################
+# check for pandoc
+
+if ! has pandoc ; then
+ fatal "pandoc is needed for manpages generation"
+fi
+print_config "pandoc" "yes"
+
#############################################################################
liburing_nolibc="no"
if test "$use_libc" != "yes"; then
diff --git a/man/.gitignore b/man/.gitignore
new file mode 100644
index 00000000..5fba7856
--- /dev/null
+++ b/man/.gitignore
@@ -0,0 +1,8 @@
+*.1
+*.2
+*.3
+*.4
+*.5
+*.6
+*.7
+*.8
diff --git a/man/ALIASES b/man/ALIASES
new file mode 100644
index 00000000..3a9abdfe
--- /dev/null
+++ b/man/ALIASES
@@ -0,0 +1,62 @@
+__io_uring_buf_ring_cq_advance.3 io_uring_buf_ring_cq_advance.3
+IO_URING_CHECK_VERSION.3 io_uring_check_version.3
+io_uring_clone_buffers_offset.3 io_uring_clone_buffers.3
+io_uring_cqe_get_data64.3 io_uring_cqe_get_data.3
+io_uring_enter2.2 io_uring_enter.2
+io_uring_major_version.3 io_uring_check_version.3
+io_uring_minor_version.3 io_uring_check_version.3
+io_uring_peek_batch_cqe.3 io_uring_peek_cqe.3
+io_uring_prep_accept_direct.3 io_uring_prep_accept.3
+io_uring_prep_cancel64.3 io_uring_prep_cancel.3
+io_uring_prep_cancel_fd.3 io_uring_prep_cancel.3
+io_uring_prep_close_direct.3 io_uring_prep_close.3
+io_uring_prep_fadvise64.3 io_uring_prep_fadvise.3
+io_uring_prep_fgetxattr.3 io_uring_prep_getxattr.3
+io_uring_prep_fsetxattr.3 io_uring_prep_setxattr.3
+io_uring_prep_link.3 io_uring_prep_linkat.3
+io_uring_prep_madvise64.3 io_uring_prep_madvise.3
+io_uring_prep_mkdir.3 io_uring_prep_mkdirat.3
+io_uring_prep_msg_ring_cqe_flags.3 io_uring_prep_msg_ring.3
+io_uring_prep_msg_ring_fd_alloc.3 io_uring_prep_msg_ring_fd.3
+io_uring_prep_multishot_accept.3 io_uring_prep_accept.3
+io_uring_prep_multishot_accept_direct.3 io_uring_prep_accept.3
+io_uring_prep_open.3 io_uring_prep_openat.3
+io_uring_prep_openat2_direct.3 io_uring_prep_openat2.3
+io_uring_prep_openat_direct.3 io_uring_prep_openat.3
+io_uring_prep_open_direct.3 io_uring_prep_openat.3
+io_uring_prep_pipe_direct.3 io_uring_prep_pipe.3
+io_uring_prep_poll_multishot.3 io_uring_prep_poll_add.3
+io_uring_prep_recvmsg_multishot.3 io_uring_prep_recvmsg.3
+io_uring_prep_recv_multishot.3 io_uring_prep_recv.3
+io_uring_prep_rename.3 io_uring_prep_renameat.3
+io_uring_prep_send_bundle.3 io_uring_prep_send.3
+io_uring_prep_sendmsg_zc.3 io_uring_prep_sendmsg.3
+io_uring_prep_sendto.3 io_uring_prep_send.3
+io_uring_prep_send_zc_fixed.3 io_uring_prep_send_zc.3
+io_uring_prep_socket_direct.3 io_uring_prep_socket.3
+io_uring_prep_socket_direct_alloc.3 io_uring_prep_socket.3
+io_uring_prep_symlink.3 io_uring_prep_symlinkat.3
+io_uring_prep_timeout_remove.3 io_uring_prep_timeout_update.3
+io_uring_prep_unlink.3 io_uring_prep_unlinkat.3
+io_uring_queue_init_mem.3 io_uring_queue_init.3
+io_uring_queue_init_params.3 io_uring_queue_init.3
+io_uring_recvmsg_cmsg_firsthdr.3 io_uring_recvmsg_out.3
+io_uring_recvmsg_cmsg_nexthdr.3 io_uring_recvmsg_out.3
+io_uring_recvmsg_name.3 io_uring_recvmsg_out.3
+io_uring_recvmsg_payload.3 io_uring_recvmsg_out.3
+io_uring_recvmsg_payload_length.3 io_uring_recvmsg_out.3
+io_uring_recvmsg_validate.3 io_uring_recvmsg_out.3
+io_uring_register_bpf_filter_task.3 io_uring_register_bpf_filter.3
+io_uring_register_buffers_sparse.3 io_uring_register_buffers.3
+io_uring_register_buffers_tags.3 io_uring_register_buffers.3
+io_uring_register_buffers_update_tag.3 io_uring_register_buffers.3
+io_uring_register_eventfd_async.3 io_uring_register_eventfd.3
+io_uring_register_files_sparse.3 io_uring_register_files.3
+io_uring_register_files_tags.3 io_uring_register_files.3
+io_uring_register_files_update.3 io_uring_register_files.3
+io_uring_register_files_update_tag.3 io_uring_register_files.3
+io_uring_sqe_set_data64.3 io_uring_sqe_set_data.3
+io_uring_unregister_eventfd.3 io_uring_register_eventfd.3
+io_uring_unregister_iowq_aff.3 io_uring_register_iowq_aff.3
+IO_URING_VERSION_MAJOR.3 io_uring_check_version.3
+IO_URING_VERSION_MINOR.3 io_uring_check_version.3
diff --git a/man/IO_URING_CHECK_VERSION.3 b/man/IO_URING_CHECK_VERSION.3
deleted file mode 120000
index 21bbf456..00000000
--- a/man/IO_URING_CHECK_VERSION.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_check_version.3
\ No newline at end of file
diff --git a/man/IO_URING_VERSION_MAJOR.3 b/man/IO_URING_VERSION_MAJOR.3
deleted file mode 120000
index 21bbf456..00000000
--- a/man/IO_URING_VERSION_MAJOR.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_check_version.3
\ No newline at end of file
diff --git a/man/IO_URING_VERSION_MINOR.3 b/man/IO_URING_VERSION_MINOR.3
deleted file mode 120000
index 21bbf456..00000000
--- a/man/IO_URING_VERSION_MINOR.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_check_version.3
\ No newline at end of file
diff --git a/man/Makefile b/man/Makefile
new file mode 100644
index 00000000..f28e01cd
--- /dev/null
+++ b/man/Makefile
@@ -0,0 +1,26 @@
+MDS := $(wildcard *.md)
+PAGES := $(patsubst %.md,%,$(MDS))
+VPATH = $(root)/man
+
+mandir ?= $(prefix)/share/man
+
+all: $(PAGES) gen_aliases
+
+%: %.md
+ sed -E '/\.\\/d' $<| pandoc --standalone --to man --lua-filter=filters/bold-block.lua -o $@
+ man -l $@ > gen/$@.out
+
+gen_aliases:
+ while IFS=$$'\t' read -r link tgt ; do ln -f -s $$tgt $$link; done < ALIASES
+
+clean:
+ -rm -f *.1 *.2 *.1 *.3 *.4 *.5 *.6 *.7 *.8 *.tmp
+
+%.md: man/%
+ filters/preserve-comments.py < $< > /$@
+ sed -E '/.BI/ s/"//g' $< | sed -E 's/^.BI(.*)/\1/' > $@.tmp
+ pandoc -p --wrap=preserve --standalone $@.tmp -f man -t markdown+hard_line_breaks >> $@ < $@.tmp
+
+gene: $(MDS)
+
+
diff --git a/man/__io_uring_buf_ring_cq_advance.3 b/man/__io_uring_buf_ring_cq_advance.3
deleted file mode 120000
index 4b3a1e5f..00000000
--- a/man/__io_uring_buf_ring_cq_advance.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_buf_ring_cq_advance.3
\ No newline at end of file
diff --git a/man/filters/bold-block.lua b/man/filters/bold-block.lua
new file mode 100644
index 00000000..850fde04
--- /dev/null
+++ b/man/filters/bold-block.lua
@@ -0,0 +1,14 @@
+-- SPDX-License-Identifier: LGPL-2.0-or-later
+-- Generated with Gemini 3.5
+
+function CodeBlock(el)
+ local code_text = el.text
+
+ return pandoc.BlockQuote({
+ pandoc.Para({ pandoc.Strong(pandoc.Str(code_text)) })
+ })
+end
+
+function Code(el)
+ return pandoc.Strong(el)
+end
\ No newline at end of file
--git a/man/filters/preserve-comments.py b/man/filters/preserve-comments.py
new file mode 100755
index 00000000..68ee5c6d
--- /dev/null
+++ b/man/filters/preserve-comments.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: LGPL-2.0-or-later
+
+import sys
+import re
+
+def preserve_groff_comments(source_text):
+ lines = source_text.splitlines()
+ processed_lines = []
+ for line in lines:
+ if line.strip().startswith('.\\\"'):
+ processed_lines.append("{}".format(line))
+ return "\n".join(processed_lines)+"\n"
+
+if __name__ == "__main__":
+ input_text = sys.stdin.read()
+ output_text = preserve_groff_comments(input_text)
+ sys.stdout.write(output_text)
diff --git a/man/io_uring.7 b/man/io_uring.7
deleted file mode 100644
index 723d7d0f..00000000
--- a/man/io_uring.7
+++ /dev/null
@@ -1,919 +0,0 @@
-.\" Copyright (C) 2020 Shuveb Hussain <shuveb@gmail.com>
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-
-.TH io_uring 7 "July 26, 2020" "Linux" "Linux Programmer's Manual"
-.SH NAME
-io_uring \- Asynchronous I/O facility
-.SH SYNOPSIS
-.nf
-.B "#include <linux/io_uring.h>"
-.fi
-.PP
-.SH DESCRIPTION
-.PP
-.B io_uring
-is a Linux-specific API for asynchronous I/O.
-It allows the user to submit one or more I/O requests,
-which are processed asynchronously without blocking the calling process.
-.B io_uring
-gets its name from ring buffers which are shared between user space and
-kernel space. This arrangement allows for efficient I/O,
-while avoiding the overhead of copying buffers between them,
-where possible.
-This interface makes
-.B io_uring
-different from other UNIX I/O APIs,
-wherein,
-rather than just communicate between kernel and user space with system calls,
-ring buffers are used as the main mode of communication.
-This arrangement has various performance benefits which are discussed in a
-separate section below.
-This man page uses the terms shared buffers, shared ring buffers and
-queues interchangeably.
-.PP
-The general programming model you need to follow for
-.B io_uring
-is outlined below
-.IP \(bu
-Set up shared buffers with
-.BR io_uring_setup (2)
-and
-.BR mmap (2),
-mapping into user space shared buffers for the submission queue (SQ) and the
-completion queue (CQ).
-You place I/O requests you want to make on the SQ,
-while the kernel places the results of those operations on the CQ.
-.IP \(bu
-For every I/O request you need to make (like to read a file, write a file,
-accept a socket connection, etc), you create a submission queue entry,
-or SQE,
-describe the I/O operation you need to get done and add it to the tail of
-the submission queue (SQ).
-Each I/O operation is,
-in essence,
-the equivalent of a system call you would have made otherwise,
-if you were not using
-.BR io_uring .
-For instance,
-a SQE with the
-.I opcode
-set to
-.B IORING_OP_READ
-will request a read operation to be issued that is similar to the
-.BR read (2)
-system call. Refer to the opcode documentation in
-.BR io_uring_enter (2)
-for all supported opcodes and their properties.
-You can add more than one SQE to the queue depending on the number of
-operations you want to request.
-.IP \(bu
-After you add one or more SQEs,
-you need to call
-.BR io_uring_enter (2)
-to tell the kernel to dequeue your I/O requests off the SQ and begin
-processing them.
-.IP \(bu
-For each SQE you submit,
-once it is done processing the request,
-the kernel places a completion queue event or CQE at the tail of the
-completion queue or CQ.
-The kernel places exactly one matching CQE in the CQ for every SQE you
-submit on the SQ.
-After you retrieve a CQE,
-minimally,
-you might be interested in checking the
-.I res
-field of the CQE structure,
-which corresponds to the return value of the system
-call's equivalent,
-had you used it directly without using
-.BR io_uring .
-Given that
-.B io_uring
-is an async interface,
-.I errno
-is never used for passing back error information. Instead,
-.I res
-will contain what the equivalent system call would have returned in case
-of success, and in case of error
-.I res
-will contain
-.IR -errno .
-For example, if the normal read system call would have returned -1 and set
-.I errno
-to
-.BR EINVAL ,
-then
-.I res
-would contain
-.BR -EINVAL .
-If the normal system call would have returned a read size of 1024, then
-.I res
-would contain 1024.
-.IP \(bu
-Optionally,
-.BR io_uring_enter (2)
-can also wait for a specified number of requests to be processed by the kernel
-before it returns.
-If you specified a certain number of completions to wait for,
-the kernel would have placed at least those many number of CQEs on the CQ,
-which you can then readily read,
-right after the return from
-.BR io_uring_enter (2).
-.IP \(bu
-It is important to remember that I/O requests submitted to the kernel can
-complete in any order.
-It is not necessary for the kernel to process one request after another,
-in the order you placed them.
-Given that the interface is a ring,
-the requests are attempted in order,
-however that doesn't imply any sort of ordering on their execution or
-completion.
-When more than one request is in flight,
-it is not possible to determine which one will execute or complete first.
-When you dequeue CQEs off the CQ,
-you should always check which submitted request it corresponds to.
-The most common method for doing so is utilizing the
-.I user_data
-field in the request, which is passed back on the completion side.
-.IP \(bu
-Concretely, for operations where strict ordering is required,
-such as for sends and receives on a stream-oriented TCP socket,
-it is generally unsafe to have more than one outstanding send,
-or more than one outstanding receive (the two directions are independent)
-on a given socket at a time, as the kernel may reorder their execution
-if poll arming or other background kernel activities are involved.
-However,
-.B io_uring
-provides various facilities to enable applications to efficiently
-pipeline their operations safely. If the requests are submitted in a
-single batch, the application may use
-.B IOSQE_IO_LINK
-to enforce an execution order in the kernel. Otherwise,
-.B io_uring
-provides advanced features like
-.I multi shot
-and send/receive
-.I bundles
-to allow applications to provide more data in fewer, more efficient trips
-to the kernel. Even if these features are used, applications must still
-ensure they do not overlap different sends or different receives on a
-given file.
-.PP
-Adding to and reading from the queues:
-.IP \(bu
-You add SQEs to the tail of the SQ.
-The kernel reads SQEs off the head of the queue.
-.IP \(bu
-The kernel adds CQEs to the tail of the CQ.
-You read CQEs off the head of the queue.
-.PP
-It should be noted that depending on the configuration io_uring's behavior
-can deviate from the behavior outlined above, like not posting a CQE for
-every SQE when setting
-.B IOSQE_CQE_SKIP_SUCCESS
-in the SQE or posting multiple CQEs for a single SQE for multi shot operations
-or requiring an
-.BR io_uring_enter (2)
-syscall to make the kernel begin processing newly added SQEs when using
-submission queue polling.
-
-.SS Submission queue polling
-One of the goals of
-.B io_uring
-is to provide a means for efficient I/O.
-To this end,
-.B io_uring
-supports a polling mode that lets you avoid the call to
-.BR io_uring_enter (2),
-which you use to inform the kernel that you have queued SQEs on to the SQ.
-With SQ Polling,
-.B io_uring
-starts a kernel thread that polls the submission queue for any I/O
-requests you submit by adding SQEs.
-With SQ Polling enabled,
-there is no need for you to call
-.BR io_uring_enter (2),
-letting you avoid the overhead of system calls.
-A designated kernel thread dequeues SQEs off the SQ as you add them and
-dispatches them for asynchronous processing.
-.SS Setting up io_uring
-.PP
-The main steps in setting up
-.B io_uring
-consist of mapping in the shared buffers with
-.BR mmap (2)
-calls.
-In the example program included in this man page,
-the function
-.BR app_setup_uring ()
-sets up
-.B io_uring
-with a QUEUE_DEPTH deep submission queue.
-Pay attention to the 2
-.BR mmap (2)
-calls that set up the shared submission and completion queues.
-If your kernel is older than version 5.4,
-three
-.BR mmap(2)
-calls are required.
-.PP
-.SS Submitting I/O requests
-The process of submitting a request consists of describing the I/O
-operation you need to get done using an
-.B io_uring_sqe
-structure instance.
-These details describe the equivalent system call and its parameters.
-Because the range of I/O operations Linux supports are very varied and the
-.B io_uring_sqe
-structure needs to be able to describe them,
-it has several fields,
-some packed into unions for space efficiency.
-Here is a simplified version of struct
-.B io_uring_sqe
-with some of the most often used fields:
-.PP
-.in +4n
-.EX
-struct io_uring_sqe {
- __u8 opcode; /* type of operation for this sqe */
- __s32 fd; /* file descriptor to do IO on */
- __u64 off; /* offset into file */
- __u64 addr; /* pointer to buffer or iovecs */
- __u32 len; /* buffer size or number of iovecs */
- __u64 user_data; /* data to be passed back at completion time */
- __u8 flags; /* IOSQE_ flags */
- ...
-};
-.EE
-.in
-
-Here is struct
-.B io_uring_sqe
-in full:
-
-.in +4n
-.EX
-struct io_uring_sqe {
- __u8 opcode; /* type of operation for this sqe */
- __u8 flags; /* IOSQE_ flags */
- __u16 ioprio; /* ioprio for the request */
- __s32 fd; /* file descriptor to do IO on */
- union {
- __u64 off; /* offset into file */
- __u64 addr2;
- struct {
- __u32 cmd_op;
- __u32 __pad1;
- };
- };
- union {
- __u64 addr; /* pointer to buffer or iovecs */
- __u64 splice_off_in;
- struct {
- __u32 level;
- __u32 optname;
- };
- };
- __u32 len; /* buffer size or number of iovecs */
- union {
- __kernel_rwf_t rw_flags;
- __u32 fsync_flags;
- __u16 poll_events; /* compatibility */
- __u32 poll32_events; /* word-reversed for BE */
- __u32 sync_range_flags;
- __u32 msg_flags;
- __u32 timeout_flags;
- __u32 accept_flags;
- __u32 cancel_flags;
- __u32 open_flags;
- __u32 statx_flags;
- __u32 fadvise_advice;
- __u32 splice_flags;
- __u32 rename_flags;
- __u32 unlink_flags;
- __u32 hardlink_flags;
- __u32 xattr_flags;
- __u32 msg_ring_flags;
- __u32 uring_cmd_flags;
- __u32 waitid_flags;
- __u32 futex_flags;
- __u32 install_fd_flags;
- __u32 nop_flags;
- };
- __u64 user_data; /* data to be passed back at completion time */
- /* pack this to avoid bogus arm OABI complaints */
- union {
- /* index into fixed buffers, if used */
- __u16 buf_index;
- /* for grouped buffer selection */
- __u16 buf_group;
- } __attribute__((packed));
- /* personality to use, if used */
- __u16 personality;
- union {
- __s32 splice_fd_in;
- __u32 file_index;
- __u32 optlen;
- struct {
- __u16 addr_len;
- __u16 __pad3[1];
- };
- };
- union {
- struct {
- __u64 addr3;
- __u64 __pad2[1];
- };
- __u64 optval;
- /*
- * If the ring is initialized with IORING_SETUP_SQE128, then
- * this field is used for 80 bytes of arbitrary command data
- */
- __u8 cmd[0];
- };
-};
-.EE
-.in
-.PP
-To submit an I/O request to
-.BR io_uring ,
-you need to acquire a submission queue entry (SQE) from the submission
-queue (SQ),
-fill it up with details of the operation you want to submit and call
-.BR io_uring_enter (2).
-There are helper functions of the form io_uring_prep_X to enable proper
-setup of the SQE. If you want to avoid calling
-.BR io_uring_enter (2),
-you have the option of setting up Submission Queue Polling.
-.PP
-SQEs are added to the tail of the submission queue.
-The kernel picks up SQEs off the head of the SQ.
-The general algorithm to get the next available SQE and update the tail is
-as follows.
-.PP
-.in +4n
-.EX
-struct io_uring_sqe *sqe;
-unsigned tail, index;
-tail = *sqring->tail;
-index = tail & (*sqring->ring_mask);
-sqe = &sqring->sqes[index];
-/* fill up details about this I/O request */
-describe_io(sqe);
-/* fill the sqe index into the SQ ring array */
-sqring->array[index] = index;
-tail++;
-atomic_store_explicit(sqring->tail, tail, memory_order_release);
-.EE
-.in
-.PP
-To get the index of an entry,
-the application must mask the current tail index with the size mask of the
-ring.
-This holds true for both SQs and CQs.
-Once the SQE is acquired,
-the necessary fields are filled in,
-describing the request.
-While the CQ ring directly indexes the shared array of CQEs,
-the submission side has an indirection array between them.
-The submission side ring buffer is an index into this array,
-which in turn contains the index into the SQEs.
-.PP
-The following code snippet demonstrates how a read operation,
-an equivalent of a
-.BR preadv2 (2)
-system call is described by filling up an SQE with the necessary
-parameters.
-.PP
-.in +4n
-.EX
-struct iovec iovecs[16];
- ...
-sqe->opcode = IORING_OP_READV;
-sqe->fd = fd;
-sqe->addr = (unsigned long) iovecs;
-sqe->len = 16;
-sqe->off = offset;
-sqe->flags = 0;
-.EE
-.in
-.TP
-.B Memory ordering
-Modern compilers and CPUs freely reorder reads and writes without
-affecting the program's outcome to optimize performance.
-Some aspects of this need to be kept in mind on SMP systems since
-.B io_uring
-involves buffers shared between kernel and user space.
-These buffers are both visible and modifiable from kernel and user space.
-As heads and tails belonging to these shared buffers are updated by kernel
-and user space,
-changes need to be coherently visible on either side,
-irrespective of whether a CPU switch took place after the kernel-user mode
-switch happened.
-We use memory barriers to enforce this coherency.
-Being significantly large subjects on their own,
-memory barriers are out of scope for further discussion on this man page.
-For more information on modern memory models the reader may refer to the
-Documentation/memory-barriers.txt in the kernel tree or to the documentation
-of the formal C11 or kernel memory model.
-.TP
-.B Letting the kernel know about I/O submissions
-Once you place one or more SQEs on to the SQ,
-you need to let the kernel know that you've done so.
-You can do this by calling the
-.BR io_uring_enter (2)
-system call.
-This system call is also capable of waiting for a specified count of
-events to complete.
-This way,
-you can be sure to find completion events in the completion queue without
-having to poll it for events later.
-.SS SQE pointer lifetimes & data stability
-Due to the fixed size of the submission queue entry (SQE) some data you
-provide in order to perform a desired operation will be passed in the
-form of a pointer rather than value. In this situation, you may free
-the memory backing the pointer once the succeeding
-.BR io_uring_enter (2)
-call has completed; providing it is only required by the operation when submitting.
-
-When
-.B IORING_SETUP_SQPOLL
-is not enabled, this is done when you call
-.BR io_uring_submit (3)
-In The event
-.B IORING_SETUP_SQPOLL
-is enabled, you must ensure any provided pointers remain valid until completion.
-
-However, very early kernels (5.4 and earlier) required state to be
- stable until the completion occurred regardless. Applications can test for this
- behavior by inspecting the
-.B IORING_FEAT_SUBMIT_STABLE
-flag passed back from
-.BR io_uring_queue_init_params (3).
-
-As an example, the
-.B IORING_OP_TIMEOUT
-operation takes a pointer to a __kernel_timespec struct. This struct is
-then read by the kernel when you submit the submission queue entries,
-once submitted, you may free the backing memory of the __kernel_timespec
-as it will not be read again by the kernel.
-
-It should be noted that this behaviour does not apply to data that is read
-or written while the operation is inflight. For example, the pointers to
-a buffer used as part of a
-.B IORING_OP_WRITE
-or
-.B IORING_OP_READ
-operation must remain valid until completion.
-.SS Reading completion events
-Similar to the submission queue (SQ),
-the completion queue (CQ) is a shared buffer between the kernel and user
-space.
-Whereas you placed submission queue entries on the tail of the SQ and the
-kernel read off the head,
-when it comes to the CQ,
-the kernel places completion queue events or CQEs on the tail of the CQ and
-you read off its head.
-.PP
-Submission is flexible (and thus a bit more complicated) since it needs to
-be able to encode different types of system calls that take various
-parameters.
-Completion,
-on the other hand is simpler since we're looking only for a return value
-back from the kernel.
-This is easily understood by looking at the completion queue event
-structure,
-struct
-.BR io_uring_cqe :
-.PP
-.in +4n
-.EX
-struct io_uring_cqe {
- __u64 user_data; /* sqe->data submission passed back */
- __s32 res; /* result code for this event */
- __u32 flags;
-};
-.EE
-.in
-.PP
-Here,
-.I user_data
-is custom data that is passed unchanged from submission to completion.
-That is,
-from SQEs to CQEs.
-This field can be used to set context,
-uniquely identifying submissions that got completed.
-Given that I/O requests can complete in any order,
-this field can be used to correlate a submission with a completion.
-.I res
-is the result from the system call that was performed as part of the
-submission;
-its return value.
-
-The
-.I flags
-field carries request-specific information. As of the 6.12 kernel,
-the following flags are defined:
-
-.TP
-.B IORING_CQE_F_BUFFER
-If set, the upper 16 bits of the flags field carries the buffer ID that was
-chosen for this request. The request must have been issued with
-.B IOSQE_BUFFER_SELECT
-set, and used with a request type that supports buffer selection. Additionally,
-buffers must have been provided upfront either via the
-.B IORING_OP_PROVIDE_BUFFERS
-or the
-.B IORING_REGISTER_PBUF_RING
-methods.
-.TP
-.B IORING_CQE_F_MORE
-If set, the application should expect more completions from the request. This
-is used for requests that can generate multiple completions, such as multi-shot
-requests, receive, or accept.
-.TP
-.B IORING_CQE_F_SOCK_NONEMPTY
-If set, upon receiving the data from the socket in the current request, the
-socket still had data left on completion of this request.
-.TP
-.B IORING_CQE_F_NOTIF
-Set for notification CQEs, as seen with the zero-copy networking send and
-receive support.
-.TP
-.B IORING_CQE_F_BUF_MORE
-If set, the buffer ID set in the completion will get more completions. This
-means that the provided buffer has been partially consumed and there's more
-buffer space left, and hence the application should expect more completions
-with this buffer ID. Each completion will continue where the previous one
-left off. This can only happen if the provided buffer ring has been setup
-with
-.B IOU_PBUF_RING_INC
-to allow for incremental / partial consumption of buffers.
-.TP
-.B IORING_CQE_F_SKIP
-If the ring has been configured with
-.B IORING_SETUP_CQE_MIXED ,
-then CQEs may be posted which has this flag set. This can happen if the ring
-is a single 16b CQE entry away from wrapping, but someone needs to post a 32b
-CQE. As CQEs must be contiguous in memory, a filler/pad CQE needs to get
-posted to allow posting of the 32b CQE. CQEs with this flag set should simply
-be skipped and ignored, they serve no other purpose than to fill a gap in the
-CQ ring.
-.TP
-.B IORING_CQE_F_32
-If the ring has been configured with
-.B IORING_SETUP_CQE_MIXED ,
-this flag is set when the CQE is of the 32b type. This tells the application
-that there's an extra 16b of space in this CQE, and that to get to the next
-CQE the CQ ring must be advanced by twice as much as for a normal 16b CQE.
-.PP
-The general sequence to read completion events off the completion queue is
-as follows:
-.PP
-.in +4n
-.EX
-unsigned head;
-head = *cqring->head;
-if (head != atomic_load_acquire(cqring->tail)) {
- struct io_uring_cqe *cqe;
- unsigned index;
- index = head & (cqring->mask);
- cqe = &cqring->cqes[index];
- /* process completed CQE */
- process_cqe(cqe);
- /* CQE consumption complete */
- head++;
-}
-atomic_store_explicit(cqring->head, head, memory_order_release);
-.EE
-.in
-.PP
-It helps to be reminded that the kernel adds CQEs to the tail of the CQ,
-while you need to dequeue them off the head.
-To get the index of an entry at the head,
-the application must mask the current head index with the size mask of the
-ring.
-Once the CQE has been consumed or processed,
-the head needs to be updated to reflect the consumption of the CQE.
-Attention should be paid to the read and write barriers to ensure
-successful read and update of the head.
-.SS io_uring performance
-Because of the shared ring buffers between kernel and user space,
-.B io_uring
-can be a zero-copy system.
-Copying buffers to and from becomes necessary when system calls that
-transfer data between kernel and user space are involved.
-But since the bulk of the communication in
-.B io_uring
-is via buffers shared between the kernel and user space,
-this huge performance overhead is completely avoided.
-.PP
-While system calls may not seem like a significant overhead,
-in high performance applications,
-making a lot of them will begin to matter.
-While workarounds the operating system has in place to deal with Spectre
-and Meltdown are ideally best done away with,
-unfortunately,
-some of these workarounds are around the system call interface,
-making system calls not as cheap as before on affected hardware.
-While newer hardware should not need these workarounds,
-hardware with these vulnerabilities can be expected to be in the wild for a
-long time.
-While using synchronous programming interfaces or even when using
-asynchronous programming interfaces under Linux,
-there is at least one system call involved in the submission of each
-request.
-In
-.BR io_uring ,
-on the other hand,
-you can batch several requests in one go,
-simply by queueing up multiple SQEs,
-each describing an I/O operation you want and make a single call to
-.BR io_uring_enter (2).
-This is possible due to
-.BR io_uring 's
-shared buffers based design.
-.PP
-While this batching in itself can avoid the overhead associated with
-potentially multiple and frequent system calls,
-you can reduce even this overhead further with Submission Queue Polling,
-by having the kernel poll and pick up your SQEs for processing as you add
-them to the submission queue. This avoids the
-.BR io_uring_enter (2)
-call you need to make to tell the kernel to pick SQEs up.
-For high-performance applications,
-this means even fewer system call overheads.
-.SH CONFORMING TO
-.B io_uring
-is Linux-specific.
-.SH EXAMPLES
-The following example uses
-.B io_uring
-to copy stdin to stdout.
-Using shell redirection,
-you should be able to copy files with this example.
-Because it uses a queue depth of only one,
-this example processes I/O requests one after the other.
-It is purposefully kept this way to aid understanding.
-In real-world scenarios however,
-you'll want to have a larger queue depth to parallelize I/O request
-processing so as to gain the kind of performance benefits
-.B io_uring
-provides with its asynchronous processing of requests.
-.PP
-.EX
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/syscall.h>
-#include <sys/mman.h>
-#include <sys/uio.h>
-#include <linux/fs.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdatomic.h>
-#include <errno.h>
-
-#include <linux/io_uring.h>
-
-#define QUEUE_DEPTH 1
-#define BLOCK_SZ 1024
-
-/* Macros for barriers needed by io_uring */
-#define io_uring_smp_store_release(p, v) \\
- atomic_store_explicit((_Atomic typeof(*(p)) *)(p), (v), \\
- memory_order_release)
-#define io_uring_smp_load_acquire(p) \\
- atomic_load_explicit((_Atomic typeof(*(p)) *)(p), \\
- memory_order_acquire)
-
-int ring_fd;
-unsigned *sring_tail, *sring_mask, *sring_array,
- *cring_head, *cring_tail, *cring_mask;
-struct io_uring_sqe *sqes;
-struct io_uring_cqe *cqes;
-char buff[BLOCK_SZ];
-off_t offset;
-
-/*
- * System call wrappers provided since glibc does not yet
- * provide wrappers for io_uring system calls.
-* */
-
-int io_uring_setup(unsigned entries, struct io_uring_params *p)
-{
- int ret;
- ret = syscall(__NR_io_uring_setup, entries, p);
- return (ret < 0) ? -errno : ret;
-}
-
-int io_uring_enter(int ring_fd, unsigned int to_submit,
- unsigned int min_complete, unsigned int flags)
-{
- int ret;
- ret = syscall(__NR_io_uring_enter, ring_fd, to_submit,
- min_complete, flags, NULL, 0);
- return (ret < 0) ? -errno : ret;
-}
-
-int app_setup_uring(void) {
- struct io_uring_params p;
- void *sq_ptr, *cq_ptr;
-
- /* See io_uring_setup(2) for io_uring_params.flags you can set */
- memset(&p, 0, sizeof(p));
- ring_fd = io_uring_setup(QUEUE_DEPTH, &p);
- if (ring_fd < 0) {
- perror("io_uring_setup");
- return 1;
- }
-
- /*
- * io_uring communication happens via 2 shared kernel-user space ring
- * buffers, which can be jointly mapped with a single mmap() call in
- * kernels >= 5.4.
- */
-
- int sring_sz = p.sq_off.array + p.sq_entries * sizeof(unsigned);
- int cring_sz = p.cq_off.cqes + p.cq_entries * sizeof(struct io_uring_cqe);
-
- /* Rather than check for kernel version, the recommended way is to
- * check the features field of the io_uring_params structure, which is a
- * bitmask. If IORING_FEAT_SINGLE_MMAP is set, we can do away with the
- * second mmap() call to map in the completion ring separately.
- */
- if (p.features & IORING_FEAT_SINGLE_MMAP) {
- if (cring_sz > sring_sz)
- sring_sz = cring_sz;
- cring_sz = sring_sz;
- }
-
- /* Map in the submission and completion queue ring buffers.
- * Kernels < 5.4 only map in the submission queue, though.
- */
- sq_ptr = mmap(0, sring_sz, PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_POPULATE,
- ring_fd, IORING_OFF_SQ_RING);
- if (sq_ptr == MAP_FAILED) {
- perror("mmap");
- return 1;
- }
-
- if (p.features & IORING_FEAT_SINGLE_MMAP) {
- cq_ptr = sq_ptr;
- } else {
- /* Map in the completion queue ring buffer in older kernels separately */
- cq_ptr = mmap(0, cring_sz, PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_POPULATE,
- ring_fd, IORING_OFF_CQ_RING);
- if (cq_ptr == MAP_FAILED) {
- perror("mmap");
- return 1;
- }
- }
- /* Save useful fields for later easy reference */
- sring_tail = sq_ptr + p.sq_off.tail;
- sring_mask = sq_ptr + p.sq_off.ring_mask;
- sring_array = sq_ptr + p.sq_off.array;
-
- /* Map in the submission queue entries array */
- sqes = mmap(0, p.sq_entries * sizeof(struct io_uring_sqe),
- PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
- ring_fd, IORING_OFF_SQES);
- if (sqes == MAP_FAILED) {
- perror("mmap");
- return 1;
- }
-
- /* Save useful fields for later easy reference */
- cring_head = cq_ptr + p.cq_off.head;
- cring_tail = cq_ptr + p.cq_off.tail;
- cring_mask = cq_ptr + p.cq_off.ring_mask;
- cqes = cq_ptr + p.cq_off.cqes;
-
- return 0;
-}
-
-/*
-* Read from completion queue.
-* In this function, we read completion events from the completion queue.
-* We dequeue the CQE, update and head and return the result of the operation.
-* */
-
-int read_from_cq() {
- struct io_uring_cqe *cqe;
- unsigned head;
-
- /* Read barrier */
- head = io_uring_smp_load_acquire(cring_head);
- /*
- * Remember, this is a ring buffer. If head == tail, it means that the
- * buffer is empty.
- * */
- if (head == *cring_tail)
- return -1;
-
- /* Get the entry */
- cqe = &cqes[head & (*cring_mask)];
- if (cqe->res < 0)
- fprintf(stderr, "Error: %s\\n", strerror(abs(cqe->res)));
-
- head++;
-
- /* Write barrier so that update to the head are made visible */
- io_uring_smp_store_release(cring_head, head);
-
- return cqe->res;
-}
-
-/*
-* Submit a read or a write request to the submission queue.
-* */
-
-int submit_to_sq(int fd, int op) {
- unsigned index, tail;
-
- /* Add our submission queue entry to the tail of the SQE ring buffer */
- tail = *sring_tail;
- index = tail & *sring_mask;
- struct io_uring_sqe *sqe = &sqes[index];
- /* Fill in the parameters required for the read or write operation */
- sqe->opcode = op;
- sqe->fd = fd;
- sqe->addr = (unsigned long) buff;
- if (op == IORING_OP_READ) {
- memset(buff, 0, sizeof(buff));
- sqe->len = BLOCK_SZ;
- }
- else {
- sqe->len = strlen(buff);
- }
- sqe->off = offset;
-
- sring_array[index] = index;
- tail++;
-
- /* Update the tail */
- io_uring_smp_store_release(sring_tail, tail);
-
- /*
- * Tell the kernel we have submitted events with the io_uring_enter()
- * system call. We also pass in the IORING_ENTER_GETEVENTS flag which
- * causes the io_uring_enter() call to wait until min_complete
- * (the 3rd param) events complete.
- * */
- int ret = io_uring_enter(ring_fd, 1,1,
- IORING_ENTER_GETEVENTS);
- if(ret < 0) {
- perror("io_uring_enter");
- return -1;
- }
-
- return ret;
-}
-
-int main(int argc, char *argv[]) {
- int res;
-
- /* Setup io_uring for use */
- if(app_setup_uring()) {
- fprintf(stderr, "Unable to setup uring!\\n");
- return 1;
- }
-
- /*
- * A while loop that reads from stdin and writes to stdout.
- * Breaks on EOF.
- */
- while (1) {
- /* Initiate read from stdin and wait for it to complete */
- submit_to_sq(STDIN_FILENO, IORING_OP_READ);
- /* Read completion queue entry */
- res = read_from_cq();
- if (res > 0) {
- /* Read successful. Write to stdout. */
- submit_to_sq(STDOUT_FILENO, IORING_OP_WRITE);
- read_from_cq();
- } else if (res == 0) {
- /* reached EOF */
- break;
- }
- else if (res < 0) {
- /* Error reading file */
- fprintf(stderr, "Error: %s\\n", strerror(abs(res)));
- break;
- }
- offset += res;
- }
-
- return 0;
-}
-.EE
-.SH SEE ALSO
-.BR io_uring_enter (2)
-.BR io_uring_register (2)
-.BR io_uring_setup (2)
diff --git a/man/io_uring.7.md b/man/io_uring.7.md
new file mode 100644
index 00000000..d1cfbc61
--- /dev/null
+++ b/man/io_uring.7.md
@@ -0,0 +1,538 @@
+.\" Copyright (C) 2020 Shuveb Hussain <shuveb@gmail.com>
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: July 26, 2020
+footer: Linux
+header: Linux Programmer\'s Manual
+section: 7
+title: io_uring
+---
+
+# NAME
+
+io_uring - Asynchronous I/O facility
+
+# SYNOPSIS
+
+ #include <linux/io_uring.h>
+
+# DESCRIPTION
+
+**io_uring** is a Linux-specific API for asynchronous I/O. It allows the user to submit one or more I/O requests, which are processed asynchronously without blocking the calling process. **io_uring** gets its name from ring buffers which are shared between user space and kernel space. This arrangement allows for efficient I/O, while avoiding the overhead of copying buffers between them, where possible. This interface makes **io_uring** different from other UNIX I/O APIs, wherein, rather than just communicate between kernel and user space with system calls, ring buffers are used as the main mode of communication. This arrangement has various performance benefits which are discussed in a separate section below. This man page uses the terms shared buffers, shared ring buffers and queues interchangeably.
+
+The general programming model you need to follow for **io_uring** is outlined below
+
+- Set up shared buffers with **io_uring_setup**(2) and **mmap**(2), mapping into user space shared buffers for the submission queue (SQ) and the completion queue (CQ). You place I/O requests you want to make on the SQ, while the kernel places the results of those operations on the CQ.
+
+- For every I/O request you need to make (like to read a file, write a file, accept a socket connection, etc), you create a submission queue entry, or SQE, describe the I/O operation you need to get done and add it to the tail of the submission queue (SQ). Each I/O operation is, in essence, the equivalent of a system call you would have made otherwise, if you were not using **io_uring**. For instance, a SQE with the *opcode* set to **IORING_OP_READ** will request a read operation to be issued that is similar to the **read**(2) system call. Refer to the opcode documentation in **io_uring_enter**(2) for all supported opcodes and their properties. You can add more than one SQE to the queue depending on the number of operations you want to request.
+
+- After you add one or more SQEs, you need to call **io_uring_enter**(2) to tell the kernel to dequeue your I/O requests off the SQ and begin processing them.
+
+- For each SQE you submit, once it is done processing the request, the kernel places a completion queue event or CQE at the tail of the completion queue or CQ. The kernel places exactly one matching CQE in the CQ for every SQE you submit on the SQ. After you retrieve a CQE, minimally, you might be interested in checking the *res* field of the CQE structure, which corresponds to the return value of the system call\'s equivalent, had you used it directly without using **io_uring**. Given that **io_uring** is an async interface, *errno* is never used for passing back error information. Instead, *res* will contain what the equivalent system call would have returned in case of success, and in case of error *res* will contain *-errno*. For example, if the normal read system call would have returned -1 and set *errno* to **EINVAL**, then *res* would contain **-EINVAL**. If the normal system call would have returned a read size of 1024, then *res* would contain 1024.
+
+- Optionally, **io_uring_enter**(2) can also wait for a specified number of requests to be processed by the kernel before it returns. If you specified a certain number of completions to wait for, the kernel would have placed at least those many number of CQEs on the CQ, which you can then readily read, right after the return from **io_uring_enter**(2).
+
+- It is important to remember that I/O requests submitted to the kernel can complete in any order. It is not necessary for the kernel to process one request after another, in the order you placed them. Given that the interface is a ring, the requests are attempted in order, however that doesn\'t imply any sort of ordering on their execution or completion. When more than one request is in flight, it is not possible to determine which one will execute or complete first. When you dequeue CQEs off the CQ, you should always check which submitted request it corresponds to. The most common method for doing so is utilizing the *user_data* field in the request, which is passed back on the completion side.
+
+- Concretely, for operations where strict ordering is required, such as for sends and receives on a stream-oriented TCP socket, it is generally unsafe to have more than one outstanding send, or more than one outstanding receive (the two directions are independent) on a given socket at a time, as the kernel may reorder their execution if poll arming or other background kernel activities are involved. However, **io_uring** provides various facilities to enable applications to efficiently pipeline their operations safely. If the requests are submitted in a single batch, the application may use **IOSQE_IO_LINK** to enforce an execution order in the kernel. Otherwise, **io_uring** provides advanced features like *multi shot* and send/receive *bundles* to allow applications to provide more data in fewer, more efficient trips to the kernel. Even if these features are used, applications must still ensure they do not overlap different sends or different receives on a given file.
+
+Adding to and reading from the queues:
+
+- You add SQEs to the tail of the SQ. The kernel reads SQEs off the head of the queue.
+
+- The kernel adds CQEs to the tail of the CQ. You read CQEs off the head of the queue.
+
+It should be noted that depending on the configuration io_uring\'s behavior can deviate from the behavior outlined above, like not posting a CQE for every SQE when setting **IOSQE_CQE_SKIP_SUCCESS** in the SQE or posting multiple CQEs for a single SQE for multi shot operations or requiring an **io_uring_enter**(2) syscall to make the kernel begin processing newly added SQEs when using submission queue polling.
+
+## Submission queue polling
+
+One of the goals of **io_uring** is to provide a means for efficient I/O. To this end, **io_uring** supports a polling mode that lets you avoid the call to **io_uring_enter**(2), which you use to inform the kernel that you have queued SQEs on to the SQ. With SQ Polling, **io_uring** starts a kernel thread that polls the submission queue for any I/O requests you submit by adding SQEs. With SQ Polling enabled, there is no need for you to call **io_uring_enter**(2), letting you avoid the overhead of system calls. A designated kernel thread dequeues SQEs off the SQ as you add them and dispatches them for asynchronous processing.
+
+## Setting up io_uring
+
+The main steps in setting up **io_uring** consist of mapping in the shared buffers with **mmap**(2) calls. In the example program included in this man page, the function **app_setup_uring**() sets up **io_uring** with a QUEUE_DEPTH deep submission queue. Pay attention to the 2 **mmap**(2) calls that set up the shared submission and completion queues. If your kernel is older than version 5.4, three **mmap(2)** calls are required.
+
+## Submitting I/O requests
+
+The process of submitting a request consists of describing the I/O operation you need to get done using an **io_uring_sqe** structure instance. These details describe the equivalent system call and its parameters. Because the range of I/O operations Linux supports are very varied and the **io_uring_sqe** structure needs to be able to describe them, it has several fields, some packed into unions for space efficiency. Here is a simplified version of struct **io_uring_sqe** with some of the most often used fields:
+
+ struct io_uring_sqe {
+ __u8 opcode; /* type of operation for this sqe */
+ __s32 fd; /* file descriptor to do IO on */
+ __u64 off; /* offset into file */
+ __u64 addr; /* pointer to buffer or iovecs */
+ __u32 len; /* buffer size or number of iovecs */
+ __u64 user_data; /* data to be passed back at completion time */
+ __u8 flags; /* IOSQE_ flags */
+ ...
+ };
+
+Here is struct **io_uring_sqe** in full:
+
+ struct io_uring_sqe {
+ __u8 opcode; /* type of operation for this sqe */
+ __u8 flags; /* IOSQE_ flags */
+ __u16 ioprio; /* ioprio for the request */
+ __s32 fd; /* file descriptor to do IO on */
+ union {
+ __u64 off; /* offset into file */
+ __u64 addr2;
+ struct {
+ __u32 cmd_op;
+ __u32 __pad1;
+ };
+ };
+ union {
+ __u64 addr; /* pointer to buffer or iovecs */
+ __u64 splice_off_in;
+ struct {
+ __u32 level;
+ __u32 optname;
+ };
+ };
+ __u32 len; /* buffer size or number of iovecs */
+ union {
+ __kernel_rwf_t rw_flags;
+ __u32 fsync_flags;
+ __u16 poll_events; /* compatibility */
+ __u32 poll32_events; /* word-reversed for BE */
+ __u32 sync_range_flags;
+ __u32 msg_flags;
+ __u32 timeout_flags;
+ __u32 accept_flags;
+ __u32 cancel_flags;
+ __u32 open_flags;
+ __u32 statx_flags;
+ __u32 fadvise_advice;
+ __u32 splice_flags;
+ __u32 rename_flags;
+ __u32 unlink_flags;
+ __u32 hardlink_flags;
+ __u32 xattr_flags;
+ __u32 msg_ring_flags;
+ __u32 uring_cmd_flags;
+ __u32 waitid_flags;
+ __u32 futex_flags;
+ __u32 install_fd_flags;
+ __u32 nop_flags;
+ };
+ __u64 user_data; /* data to be passed back at completion time */
+ /* pack this to avoid bogus arm OABI complaints */
+ union {
+ /* index into fixed buffers, if used */
+ __u16 buf_index;
+ /* for grouped buffer selection */
+ __u16 buf_group;
+ } __attribute__((packed));
+ /* personality to use, if used */
+ __u16 personality;
+ union {
+ __s32 splice_fd_in;
+ __u32 file_index;
+ __u32 optlen;
+ struct {
+ __u16 addr_len;
+ __u16 __pad3[1];
+ };
+ };
+ union {
+ struct {
+ __u64 addr3;
+ __u64 __pad2[1];
+ };
+ __u64 optval;
+ /*
+ * If the ring is initialized with IORING_SETUP_SQE128, then
+ * this field is used for 80 bytes of arbitrary command data
+ */
+ __u8 cmd[0];
+ };
+ };
+
+To submit an I/O request to **io_uring**, you need to acquire a submission queue entry (SQE) from the submission queue (SQ), fill it up with details of the operation you want to submit and call **io_uring_enter**(2). There are helper functions of the form io_uring_prep_X to enable proper setup of the SQE. If you want to avoid calling **io_uring_enter**(2), you have the option of setting up Submission Queue Polling.
+
+SQEs are added to the tail of the submission queue. The kernel picks up SQEs off the head of the SQ. The general algorithm to get the next available SQE and update the tail is as follows.
+
+```
+ struct io_uring_sqe *sqe;
+ unsigned tail, index;
+ tail = *sqring->tail;
+ index = tail & (*sqring->ring_mask);
+ sqe = &sqring->sqes[index];
+ /* fill up details about this I/O request */
+ describe_io(sqe);
+ /* fill the sqe index into the SQ ring array */
+ sqring->array[index] = index;
+ tail++;
+ atomic_store_explicit(sqring->tail, tail, memory_order_release);
+```
+
+To get the index of an entry, the application must mask the current tail index with the size mask of the ring. This holds true for both SQs and CQs. Once the SQE is acquired, the necessary fields are filled in, describing the request. While the CQ ring directly indexes the shared array of CQEs, the submission side has an indirection array between them. The submission side ring buffer is an index into this array, which in turn contains the index into the SQEs.
+
+The following code snippet demonstrates how a read operation, an equivalent of a **preadv2**(2) system call is described by filling up an SQE with the necessary parameters.
+
+```
+ struct iovec iovecs[16];
+ sqe->opcode = IORING_OP_READV;
+ sqe->fd = fd;
+ sqe->addr = (unsigned long) iovecs;
+ sqe->len = 16;
+ sqe->off = offset;
+ sqe->flags = 0;
+```
+
+**Memory ordering**
+
+: Modern compilers and CPUs freely reorder reads and writes without affecting the program\'s outcome to optimize performance. Some aspects of this need to be kept in mind on SMP systems since **io_uring** involves buffers shared between kernel and user space. These buffers are both visible and modifiable from kernel and user space. As heads and tails belonging to these shared buffers are updated by kernel and user space, changes need to be coherently visible on either side, irrespective of whether a CPU switch took place after the kernel-user mode switch happened. We use memory barriers to enforce this coherency. Being significantly large subjects on their own, memory barriers are out of scope for further discussion on this man page. For more information on modern memory models the reader may refer to the Documentation/memory-barriers.txt in the kernel tree or to the documentation of the formal C11 or kernel memory model.
+
+**Letting the kernel know about I/O submissions**
+
+: Once you place one or more SQEs on to the SQ, you need to let the kernel know that you\'ve done so. You can do this by calling the **io_uring_enter**(2) system call. This system call is also capable of waiting for a specified count of events to complete. This way, you can be sure to find completion events in the completion queue without having to poll it for events later.
+
+## SQE pointer lifetimes & data stability
+
+Due to the fixed size of the submission queue entry (SQE) some data you provide in order to perform a desired operation will be passed in the form of a pointer rather than value. In this situation, you may free the memory backing the pointer once the succeeding **io_uring_enter**(2) call has completed; providing it is only required by the operation when submitting.
+
+When **IORING_SETUP_SQPOLL** is not enabled, this is done when you call **io_uring_submit**(3) In The event **IORING_SETUP_SQPOLL** is enabled, you must ensure any provided pointers remain valid until completion.
+
+However, very early kernels (5.4 and earlier) required state to be stable until the completion occurred regardless. Applications can test for this behavior by inspecting the **IORING_FEAT_SUBMIT_STABLE** flag passed back from **io_uring_queue_init_params**(3).
+
+As an example, the **IORING_OP_TIMEOUT** operation takes a pointer to a \_\_kernel_timespec struct. This struct is then read by the kernel when you submit the submission queue entries, once submitted, you may free the backing memory of the \_\_kernel_timespec as it will not be read again by the kernel.
+
+It should be noted that this behaviour does not apply to data that is read or written while the operation is inflight. For example, the pointers to a buffer used as part of a **IORING_OP_WRITE** or **IORING_OP_READ** operation must remain valid until completion.
+
+## Reading completion events
+
+Similar to the submission queue (SQ), the completion queue (CQ) is a shared buffer between the kernel and user space. Whereas you placed submission queue entries on the tail of the SQ and the kernel read off the head, when it comes to the CQ, the kernel places completion queue events or CQEs on the tail of the CQ and you read off its head.
+
+Submission is flexible (and thus a bit more complicated) since it needs to be able to encode different types of system calls that take various parameters. Completion, on the other hand is simpler since we\'re looking only for a return value back from the kernel. This is easily understood by looking at the completion queue event structure, struct **io_uring_cqe**:
+
+ struct io_uring_cqe {
+ __u64 user_data; /* sqe->data submission passed back */
+ __s32 res; /* result code for this event */
+ __u32 flags;
+ };
+
+Here, *user_data* is custom data that is passed unchanged from submission to completion. That is, from SQEs to CQEs. This field can be used to set context, uniquely identifying submissions that got completed. Given that I/O requests can complete in any order, this field can be used to correlate a submission with a completion. *res* is the result from the system call that was performed as part of the submission; its return value.
+
+The *flags* field carries request-specific information. As of the 6.12 kernel, the following flags are defined:
+
+**IORING_CQE_F_BUFFER**
+
+: If set, the upper 16 bits of the flags field carries the buffer ID that was chosen for this request. The request must have been issued with **IOSQE_BUFFER_SELECT** set, and used with a request type that supports buffer selection. Additionally, buffers must have been provided upfront either via the **IORING_OP_PROVIDE_BUFFERS** or the **IORING_REGISTER_PBUF_RING** methods.
+
+**IORING_CQE_F_MORE**
+
+: If set, the application should expect more completions from the request. This is used for requests that can generate multiple completions, such as multi-shot requests, receive, or accept.
+
+**IORING_CQE_F_SOCK_NONEMPTY**
+
+: If set, upon receiving the data from the socket in the current request, the socket still had data left on completion of this request.
+
+**IORING_CQE_F_NOTIF**
+
+: Set for notification CQEs, as seen with the zero-copy networking send and receive support.
+
+**IORING_CQE_F_BUF_MORE**
+
+: If set, the buffer ID set in the completion will get more completions. This means that the provided buffer has been partially consumed and there\'s more buffer space left, and hence the application should expect more completions with this buffer ID. Each completion will continue where the previous one left off. This can only happen if the provided buffer ring has been setup with **IOU_PBUF_RING_INC** to allow for incremental / partial consumption of buffers.
+
+**IORING_CQE_F_SKIP**
+
+: If the ring has been configured with **IORING_SETUP_CQE_MIXED ,** then CQEs may be posted which has this flag set. This can happen if the ring is a single 16b CQE entry away from wrapping, but someone needs to post a 32b CQE. As CQEs must be contiguous in memory, a filler/pad CQE needs to get posted to allow posting of the 32b CQE. CQEs with this flag set should simply be skipped and ignored, they serve no other purpose than to fill a gap in the CQ ring.
+
+**IORING_CQE_F_32**
+
+: If the ring has been configured with **IORING_SETUP_CQE_MIXED ,** this flag is set when the CQE is of the 32b type. This tells the application that there\'s an extra 16b of space in this CQE, and that to get to the next CQE the CQ ring must be advanced by twice as much as for a normal 16b CQE.
+
+The general sequence to read completion events off the completion queue is as follows:
+
+```
+ unsigned head;
+ head = *cqring->head;
+ if (head != atomic_load_acquire(cqring->tail)) {
+ struct io_uring_cqe *cqe;
+ unsigned index;
+ index = head & (cqring->mask);
+ cqe = &cqring->cqes[index];
+ /* process completed CQE */
+ process_cqe(cqe);
+ /* CQE consumption complete */
+ head++;
+ }
+ atomic_store_explicit(cqring->head, head, memory_order_release);
+```
+
+It helps to be reminded that the kernel adds CQEs to the tail of the CQ, while you need to dequeue them off the head. To get the index of an entry at the head, the application must mask the current head index with the size mask of the ring. Once the CQE has been consumed or processed, the head needs to be updated to reflect the consumption of the CQE. Attention should be paid to the read and write barriers to ensure successful read and update of the head.
+
+## io_uring performance
+
+Because of the shared ring buffers between kernel and user space, **io_uring** can be a zero-copy system. Copying buffers to and from becomes necessary when system calls that transfer data between kernel and user space are involved. But since the bulk of the communication in **io_uring** is via buffers shared between the kernel and user space, this huge performance overhead is completely avoided.
+
+While system calls may not seem like a significant overhead, in high performance applications, making a lot of them will begin to matter. While workarounds the operating system has in place to deal with Spectre and Meltdown are ideally best done away with, unfortunately, some of these workarounds are around the system call interface, making system calls not as cheap as before on affected hardware. While newer hardware should not need these workarounds, hardware with these vulnerabilities can be expected to be in the wild for a long time. While using synchronous programming interfaces or even when using asynchronous programming interfaces under Linux, there is at least one system call involved in the submission of each request. In **io_uring**, on the other hand, you can batch several requests in one go, simply by queueing up multiple SQEs, each describing an I/O operation you want and make a single call to **io_uring_enter**(2). This is possible due to **io_uring**\'s shared buffers based design.
+
+While this batching in itself can avoid the overhead associated with potentially multiple and frequent system calls, you can reduce even this overhead further with Submission Queue Polling, by having the kernel poll and pick up your SQEs for processing as you add them to the submission queue. This avoids the **io_uring_enter**(2) call you need to make to tell the kernel to pick SQEs up. For high-performance applications, this means even fewer system call overheads.
+
+# CONFORMING TO
+
+**io_uring** is Linux-specific.
+
+# EXAMPLES
+
+The following example uses **io_uring** to copy stdin to stdout. Using shell redirection, you should be able to copy files with this example. Because it uses a queue depth of only one, this example processes I/O requests one after the other. It is purposefully kept this way to aid understanding. In real-world scenarios however, you\'ll want to have a larger queue depth to parallelize I/O request processing so as to gain the kind of performance benefits **io_uring** provides with its asynchronous processing of requests.
+
+```
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <sys/stat.h>
+ #include <sys/ioctl.h>
+ #include <sys/syscall.h>
+ #include <sys/mman.h>
+ #include <sys/uio.h>
+ #include <linux/fs.h>
+ #include <fcntl.h>
+ #include <unistd.h>
+ #include <string.h>
+ #include <stdatomic.h>
+ #include <errno.h>
+
+ #include <linux/io_uring.h>
+
+ #define QUEUE_DEPTH 1
+ #define BLOCK_SZ 1024
+
+ /* Macros for barriers needed by io_uring */
+ #define io_uring_smp_store_release(p, v) \
+ atomic_store_explicit((_Atomic typeof(*(p)) *)(p), (v), \
+ memory_order_release)
+ #define io_uring_smp_load_acquire(p) \
+ atomic_load_explicit((_Atomic typeof(*(p)) *)(p), \
+ memory_order_acquire)
+
+ int ring_fd;
+ unsigned *sring_tail, *sring_mask, *sring_array,
+ *cring_head, *cring_tail, *cring_mask;
+ struct io_uring_sqe *sqes;
+ struct io_uring_cqe *cqes;
+ char buff[BLOCK_SZ];
+ off_t offset;
+
+ /*
+ * System call wrappers provided since glibc does not yet
+ * provide wrappers for io_uring system calls.
+ * */
+
+ int io_uring_setup(unsigned entries, struct io_uring_params *p)
+ {
+ int ret;
+ ret = syscall(__NR_io_uring_setup, entries, p);
+ return (ret < 0) ? -errno : ret;
+ }
+
+ int io_uring_enter(int ring_fd, unsigned int to_submit,
+ unsigned int min_complete, unsigned int flags)
+ {
+ int ret;
+ ret = syscall(__NR_io_uring_enter, ring_fd, to_submit,
+ min_complete, flags, NULL, 0);
+ return (ret < 0) ? -errno : ret;
+ }
+
+ int app_setup_uring(void) {
+ struct io_uring_params p;
+ void *sq_ptr, *cq_ptr;
+
+ /* See io_uring_setup(2) for io_uring_params.flags you can set */
+ memset(&p, 0, sizeof(p));
+ ring_fd = io_uring_setup(QUEUE_DEPTH, &p);
+ if (ring_fd < 0) {
+ perror("io_uring_setup");
+ return 1;
+ }
+
+ /*
+ * io_uring communication happens via 2 shared kernel-user space ring
+ * buffers, which can be jointly mapped with a single mmap() call in
+ * kernels >= 5.4.
+ */
+
+ int sring_sz = p.sq_off.array + p.sq_entries * sizeof(unsigned);
+ int cring_sz = p.cq_off.cqes + p.cq_entries * sizeof(struct io_uring_cqe);
+
+ /* Rather than check for kernel version, the recommended way is to
+ * check the features field of the io_uring_params structure, which is a
+ * bitmask. If IORING_FEAT_SINGLE_MMAP is set, we can do away with the
+ * second mmap() call to map in the completion ring separately.
+ */
+ if (p.features & IORING_FEAT_SINGLE_MMAP) {
+ if (cring_sz > sring_sz)
+ sring_sz = cring_sz;
+ cring_sz = sring_sz;
+ }
+
+ /* Map in the submission and completion queue ring buffers.
+ * Kernels < 5.4 only map in the submission queue, though.
+ */
+ sq_ptr = mmap(0, sring_sz, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_POPULATE,
+ ring_fd, IORING_OFF_SQ_RING);
+ if (sq_ptr == MAP_FAILED) {
+ perror("mmap");
+ return 1;
+ }
+
+ if (p.features & IORING_FEAT_SINGLE_MMAP) {
+ cq_ptr = sq_ptr;
+ } else {
+ /* Map in the completion queue ring buffer in older kernels separately */
+ cq_ptr = mmap(0, cring_sz, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_POPULATE,
+ ring_fd, IORING_OFF_CQ_RING);
+ if (cq_ptr == MAP_FAILED) {
+ perror("mmap");
+ return 1;
+ }
+ }
+ /* Save useful fields for later easy reference */
+ sring_tail = sq_ptr + p.sq_off.tail;
+ sring_mask = sq_ptr + p.sq_off.ring_mask;
+ sring_array = sq_ptr + p.sq_off.array;
+
+ /* Map in the submission queue entries array */
+ sqes = mmap(0, p.sq_entries * sizeof(struct io_uring_sqe),
+ PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
+ ring_fd, IORING_OFF_SQES);
+ if (sqes == MAP_FAILED) {
+ perror("mmap");
+ return 1;
+ }
+
+ /* Save useful fields for later easy reference */
+ cring_head = cq_ptr + p.cq_off.head;
+ cring_tail = cq_ptr + p.cq_off.tail;
+ cring_mask = cq_ptr + p.cq_off.ring_mask;
+ cqes = cq_ptr + p.cq_off.cqes;
+
+ return 0;
+ }
+
+ /*
+ * Read from completion queue.
+ * In this function, we read completion events from the completion queue.
+ * We dequeue the CQE, update and head and return the result of the operation.
+ * */
+
+ int read_from_cq() {
+ struct io_uring_cqe *cqe;
+ unsigned head;
+
+ /* Read barrier */
+ head = io_uring_smp_load_acquire(cring_head);
+ /*
+ * Remember, this is a ring buffer. If head == tail, it means that the
+ * buffer is empty.
+ * */
+ if (head == *cring_tail)
+ return -1;
+
+ /* Get the entry */
+ cqe = &cqes[head & (*cring_mask)];
+ if (cqe->res < 0)
+ fprintf(stderr, "Error: %s\n", strerror(abs(cqe->res)));
+
+ head++;
+
+ /* Write barrier so that update to the head are made visible */
+ io_uring_smp_store_release(cring_head, head);
+
+ return cqe->res;
+ }
+
+ /*
+ * Submit a read or a write request to the submission queue.
+ * */
+
+ int submit_to_sq(int fd, int op) {
+ unsigned index, tail;
+
+ /* Add our submission queue entry to the tail of the SQE ring buffer */
+ tail = *sring_tail;
+ index = tail & *sring_mask;
+ struct io_uring_sqe *sqe = &sqes[index];
+ /* Fill in the parameters required for the read or write operation */
+ sqe->opcode = op;
+ sqe->fd = fd;
+ sqe->addr = (unsigned long) buff;
+ if (op == IORING_OP_READ) {
+ memset(buff, 0, sizeof(buff));
+ sqe->len = BLOCK_SZ;
+ }
+ else {
+ sqe->len = strlen(buff);
+ }
+ sqe->off = offset;
+
+ sring_array[index] = index;
+ tail++;
+
+ /* Update the tail */
+ io_uring_smp_store_release(sring_tail, tail);
+
+ /*
+ * Tell the kernel we have submitted events with the io_uring_enter()
+ * system call. We also pass in the IORING_ENTER_GETEVENTS flag which
+ * causes the io_uring_enter() call to wait until min_complete
+ * (the 3rd param) events complete.
+ * */
+ int ret = io_uring_enter(ring_fd, 1,1,
+ IORING_ENTER_GETEVENTS);
+ if(ret < 0) {
+ perror("io_uring_enter");
+ return -1;
+ }
+
+ return ret;
+ }
+
+ int main(int argc, char *argv[]) {
+ int res;
+
+ /* Setup io_uring for use */
+ if(app_setup_uring()) {
+ fprintf(stderr, "Unable to setup uring!\n");
+ return 1;
+ }
+
+ /*
+ * A while loop that reads from stdin and writes to stdout.
+ * Breaks on EOF.
+ */
+ while (1) {
+ /* Initiate read from stdin and wait for it to complete */
+ submit_to_sq(STDIN_FILENO, IORING_OP_READ);
+ /* Read completion queue entry */
+ res = read_from_cq();
+ if (res > 0) {
+ /* Read successful. Write to stdout. */
+ submit_to_sq(STDOUT_FILENO, IORING_OP_WRITE);
+ read_from_cq();
+ } else if (res == 0) {
+ /* reached EOF */
+ break;
+ }
+ else if (res < 0) {
+ /* Error reading file */
+ fprintf(stderr, "Error: %s\n", strerror(abs(res)));
+ break;
+ }
+ offset += res;
+ }
+
+ return 0;
+ }
+```
+
+# SEE ALSO
+
+**io_uring_enter**(2) **io_uring_register**(2) **io_uring_setup**(2)
diff --git a/man/io_uring_buf_ring_add.3 b/man/io_uring_buf_ring_add.3
deleted file mode 100644
index 8bbcf24f..00000000
--- a/man/io_uring_buf_ring_add.3
+++ /dev/null
@@ -1,64 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_buf_ring_add 3 "May 18, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_buf_ring_add \- add buffers to a shared buffer ring
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_buf_ring_add(struct io_uring_buf_ring *" br ",
-.BI " void *" addr ",
-.BI " unsigned int " len ",
-.BI " unsigned short " bid ",
-.BI " int " mask ",
-.BI " int " buf_offset ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_buf_ring_add (3)
-adds a new buffer to the shared buffer ring
-.IR br .
-The buffer address is indicated by
-.I addr
-and is of
-.I len
-bytes of length.
-.I bid
-is the buffer ID, which will be returned in the CQE.
-.I mask
-is the size mask of the ring, available from
-.BR io_uring_buf_ring_mask (3) .
-.I buf_offset
-is the offset to insert at from the current tail. If just one buffer is provided
-before the ring tail is committed with
-.BR io_uring_buf_ring_advance (3)
-or
-.BR io_uring_buf_ring_cq_advance (3),
-then
-.I buf_offset
-should be 0. If buffers are provided in a loop before being committed, the
-.I buf_offset
-must be incremented by one for each buffer added.
-
-.SH RETURN VALUE
-None
-.SH NOTES
-liburing (or the kernel, for that matter) doesn't care about what buffer ID maps
-to what buffer, and in fact when recycling buffers after use, the application is
-free to add a different buffer into the same buffer ID location. All that
-matters is that the application knows what a given buffer ID in time corresponds
-to in terms of virtual memory. There's no liburing or kernel assumption that
-these mappings are persistent over time, they can very well be different every
-time a given buffer ID is added to the provided buffer ring.
-
-Note that no uring functions can write more than INT_MAX bytes to a buffer in a
-single call. For details, see the man pages for individual functions.
-.SH SEE ALSO
-.BR io_uring_register_buf_ring (3),
-.BR io_uring_buf_ring_mask (3),
-.BR io_uring_buf_ring_advance (3),
-.BR io_uring_buf_ring_cq_advance (3)
diff --git a/man/io_uring_buf_ring_add.3.md b/man/io_uring_buf_ring_add.3.md
new file mode 100644
index 00000000..fc3a0fdf
--- /dev/null
+++ b/man/io_uring_buf_ring_add.3.md
@@ -0,0 +1,44 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: May 18, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_buf_ring_add
+---
+
+# NAME
+
+io_uring_buf_ring_add - add buffers to a shared buffer ring
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_buf_ring_add(struct io_uring_buf_ring * br ,
+ void * addr ,
+ unsigned int len ,
+ unsigned short bid ,
+ int mask ,
+ int buf_offset );
+
+# DESCRIPTION
+
+The **io_uring_buf_ring_add**(3) adds a new buffer to the shared buffer ring *br*. The buffer address is indicated by *addr* and is of *len* bytes of length. *bid* is the buffer ID, which will be returned in the CQE. *mask* is the size mask of the ring, available from **io_uring_buf_ring_mask**(3)**.** *buf_offset* is the offset to insert at from the current tail. If just one buffer is provided before the ring tail is committed with **io_uring_buf_ring_advance**(3) or **io_uring_buf_ring_cq_advance**(3), then *buf_offset* should be 0. If buffers are provided in a loop before being committed, the *buf_offset* must be incremented by one for each buffer added.
+
+# RETURN VALUE
+
+None
+
+# NOTES
+
+liburing (or the kernel, for that matter) doesn\'t care about what buffer ID maps to what buffer, and in fact when recycling buffers after use, the application is free to add a different buffer into the same buffer ID location. All that matters is that the application knows what a given buffer ID in time corresponds to in terms of virtual memory. There\'s no liburing or kernel assumption that these mappings are persistent over time, they can very well be different every time a given buffer ID is added to the provided buffer ring.
+
+Note that no uring functions can write more than INT_MAX bytes to a buffer in a single call. For details, see the man pages for individual functions.
+
+# SEE ALSO
+
+**io_uring_register_buf_ring**(3), **io_uring_buf_ring_mask**(3), **io_uring_buf_ring_advance**(3), **io_uring_buf_ring_cq_advance**(3)
diff --git a/man/io_uring_buf_ring_advance.3 b/man/io_uring_buf_ring_advance.3
deleted file mode 100644
index f2dc90b5..00000000
--- a/man/io_uring_buf_ring_advance.3
+++ /dev/null
@@ -1,31 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_buf_ring_advance 3 "May 18, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_buf_ring_advance \- advance index of provided buffer in buffer ring
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_buf_ring_advance(struct io_uring_buf_ring *" br ",
-.BI " int " count ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_buf_ring_advance (3)
-commits
-.I count
-previously added buffers to the shared buffer ring
-.IR br ,
-making them visible to the kernel and hence consumable. This passes ownership
-of the buffer to the ring.
-
-.SH RETURN VALUE
-None
-.SH SEE ALSO
-.BR io_uring_register_buf_ring (3),
-.BR io_uring_buf_ring_add (3),
-.BR io_uring_buf_ring_cq_advance (3)
diff --git a/man/io_uring_buf_ring_advance.3.md b/man/io_uring_buf_ring_advance.3.md
new file mode 100644
index 00000000..9c592065
--- /dev/null
+++ b/man/io_uring_buf_ring_advance.3.md
@@ -0,0 +1,34 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: May 18, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_buf_ring_advance
+---
+
+# NAME
+
+io_uring_buf_ring_advance - advance index of provided buffer in buffer ring
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_buf_ring_advance(struct io_uring_buf_ring * br ,
+ int count );
+
+# DESCRIPTION
+
+The **io_uring_buf_ring_advance**(3) commits *count* previously added buffers to the shared buffer ring *br*, making them visible to the kernel and hence consumable. This passes ownership of the buffer to the ring.
+
+# RETURN VALUE
+
+None
+
+# SEE ALSO
+
+**io_uring_register_buf_ring**(3), **io_uring_buf_ring_add**(3), **io_uring_buf_ring_cq_advance**(3)
diff --git a/man/io_uring_buf_ring_available.3 b/man/io_uring_buf_ring_available.3
deleted file mode 100644
index c1dc8b80..00000000
--- a/man/io_uring_buf_ring_available.3
+++ /dev/null
@@ -1,47 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_buf_ring_available 3 "Jan 11, 2024" "liburing-2.6" "liburing Manual"
-.SH NAME
-io_uring_buf_ring_available \- return number of unconsumed provided ring buffer entries
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_buf_ring_available(struct io_uring *" ring ",
-.BI " struct io_uring_buf_ring *" br ",
-.BI " unsigned short " bgid ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_buf_ring_available (3)
-helper returns the number of unconsumed (by the kernel) entries in the
-.IR br
-provided buffer group belonging to the io_uring
-.IR ring
-and identified by the buffer group ID
-.IR bgid.
-
-Since the head of the provided buffer ring is only visible to the kernel, it's
-impossible to otherwise know how many unconsumed entries exist in the given
-provided buffer ring. This function query the kernel to return that number.
-Available since kernel 6.8.
-
-.SH NOTES
-The returned number of entries reflect the amount of unconsumed entries at the
-time that it was queried. If inflight IO exists that may consume provided
-buffers from this buffer group, then the returned value is inherently racy.
-.SH RETURN VALUE
-Returns the number of unconsumed entries on success, which may be 0. In case
-of error, may return
-.BR -ENOENT
-if the specified buffer group doesn't exist, or
-.BR -EINVAL
-if the buffer group isn't of the correct type, or if the kernel doesn't
-support this feature.
-.SH SEE ALSO
-.BR io_uring_register_buf_ring (3),
-.BR io_uring_buf_ring_add (3),
-.BR io_uring_buf_ring_cq_advance (3)
diff --git a/man/io_uring_buf_ring_available.3.md b/man/io_uring_buf_ring_available.3.md
new file mode 100644
index 00000000..ff10ce71
--- /dev/null
+++ b/man/io_uring_buf_ring_available.3.md
@@ -0,0 +1,41 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: Jan 11, 2024
+footer: liburing-2.6
+header: liburing Manual
+section: 3
+title: io_uring_buf_ring_available
+---
+
+# NAME
+
+io_uring_buf_ring_available - return number of unconsumed provided ring buffer entries
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_buf_ring_available(struct io_uring * ring ,
+ struct io_uring_buf_ring * br ,
+ unsigned short bgid );
+
+# DESCRIPTION
+
+The **io_uring_buf_ring_available**(3) helper returns the number of unconsumed (by the kernel) entries in the *br* provided buffer group belonging to the io_uring *ring* and identified by the buffer group ID *bgid.*
+
+Since the head of the provided buffer ring is only visible to the kernel, it\'s impossible to otherwise know how many unconsumed entries exist in the given provided buffer ring. This function query the kernel to return that number. Available since kernel 6.8.
+
+# NOTES
+
+The returned number of entries reflect the amount of unconsumed entries at the time that it was queried. If inflight IO exists that may consume provided buffers from this buffer group, then the returned value is inherently racy.
+
+# RETURN VALUE
+
+Returns the number of unconsumed entries on success, which may be 0. In case of error, may return **-ENOENT** if the specified buffer group doesn\'t exist, or **-EINVAL** if the buffer group isn\'t of the correct type, or if the kernel doesn\'t support this feature.
+
+# SEE ALSO
+
+**io_uring_register_buf_ring**(3), **io_uring_buf_ring_add**(3), **io_uring_buf_ring_cq_advance**(3)
diff --git a/man/io_uring_buf_ring_cq_advance.3 b/man/io_uring_buf_ring_cq_advance.3
deleted file mode 100644
index d7ada5d0..00000000
--- a/man/io_uring_buf_ring_cq_advance.3
+++ /dev/null
@@ -1,55 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_buf_ring_cq_advance 3 "May 18, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_buf_ring_cq_advance \- advance index of provided buffer and CQ ring
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_buf_ring_cq_advance(struct io_uring *" ring ",
-.BI " struct io_uring_buf_ring *" br ",
-.BI " int " count ");"
-.PP
-.BI "void __io_uring_buf_ring_cq_advance(struct io_uring *" ring ",
-.BI " struct io_uring_buf_ring *" br ",
-.BI " int " cq_count ",
-.BI " int " buf_count ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_buf_ring_cq_advance (3)
-commits
-.I count
-previously added buffers to the shared buffer ring
-.IR br ,
-making them visible to the kernel and hence consumable. This passes ownership
-of the buffer to the ring. At the same time, it advances the CQ ring of
-.I ring
-by
-.I count
-amount. This effectively bundles both a
-.BR io_uring_buf_ring_advance (3)
-call and a
-.BR io_uring_cq_advance (3)
-into one operation. Since updating either ring index entails a store memory
-barrier, doing both at once is more efficient.
-
-The
-.BR __io_uring_buf_ring_cq_advance (3)
-function performs the same operation, except it splits the counts into two
-separate values. It advances the CQ ring by
-.I cq_count
-entries, and the buffer ring by
-.I buf_count
-entries rather than increment both by the same value.
-
-.SH RETURN VALUE
-None
-.SH SEE ALSO
-.BR io_uring_register_buf_ring (3),
-.BR io_uring_buf_ring_add (3),
-.BR io_uring_buf_ring_advance (3)
diff --git a/man/io_uring_buf_ring_cq_advance.3.md b/man/io_uring_buf_ring_cq_advance.3.md
new file mode 100644
index 00000000..6a7801e5
--- /dev/null
+++ b/man/io_uring_buf_ring_cq_advance.3.md
@@ -0,0 +1,42 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: May 18, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_buf_ring_cq_advance
+---
+
+# NAME
+
+io_uring_buf_ring_cq_advance - advance index of provided buffer and CQ ring
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_buf_ring_cq_advance(struct io_uring * ring ,
+ struct io_uring_buf_ring * br ,
+ int count );
+
+ void __io_uring_buf_ring_cq_advance(struct io_uring * ring ,
+ struct io_uring_buf_ring * br ,
+ int cq_count ,
+ int buf_count );
+
+# DESCRIPTION
+
+The **io_uring_buf_ring_cq_advance**(3) commits *count* previously added buffers to the shared buffer ring *br*, making them visible to the kernel and hence consumable. This passes ownership of the buffer to the ring. At the same time, it advances the CQ ring of *ring* by *count* amount. This effectively bundles both a **io_uring_buf_ring_advance**(3) call and a **io_uring_cq_advance**(3) into one operation. Since updating either ring index entails a store memory barrier, doing both at once is more efficient.
+
+The **\_\_io_uring_buf_ring_cq_advance**(3) function performs the same operation, except it splits the counts into two separate values. It advances the CQ ring by *cq_count* entries, and the buffer ring by *buf_count* entries rather than increment both by the same value.
+
+# RETURN VALUE
+
+None
+
+# SEE ALSO
+
+**io_uring_register_buf_ring**(3), **io_uring_buf_ring_add**(3), **io_uring_buf_ring_advance**(3)
diff --git a/man/io_uring_buf_ring_init.3 b/man/io_uring_buf_ring_init.3
deleted file mode 100644
index beabed8c..00000000
--- a/man/io_uring_buf_ring_init.3
+++ /dev/null
@@ -1,36 +0,0 @@
-.\" Copyright (C) 2022 Dylan Yudaken <dylany@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_buf_ring_init 3 "June 13, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_buf_ring_init \- Initialise a buffer ring
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_buf_ring_init(struct io_uring_buf_ring *" br ");"
-.fi
-.SH DESCRIPTION
-.PP
-.BR io_uring_buf_ring_init (3)
-initialises
-.IR br
-so that it is ready to be used. It may be called after
-.BR io_uring_register_buf_ring (3)
-but must be called before the buffer ring is used in any other way.
-
-.SH RETURN VALUE
-None
-
-.SH NOTES
-Unless manual setup is needed, it's recommended to use
-.BR io_uring_setup_buf_ring (3)
-as it provides a simpler way to setup a provided buffer ring.
-.
-.SH SEE ALSO
-.BR io_uring_register_buf_ring (3),
-.BR io_uring_setup_buf_ring (3),
-.BR io_uring_buf_ring_add (3)
-.BR io_uring_buf_ring_advance (3),
-.BR io_uring_buf_ring_cq_advance (3)
diff --git a/man/io_uring_buf_ring_init.3.md b/man/io_uring_buf_ring_init.3.md
new file mode 100644
index 00000000..abd27324
--- /dev/null
+++ b/man/io_uring_buf_ring_init.3.md
@@ -0,0 +1,37 @@
+.\" Copyright (C) 2022 Dylan Yudaken <dylany@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: June 13, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_buf_ring_init
+---
+
+# NAME
+
+io_uring_buf_ring_init - Initialise a buffer ring
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_buf_ring_init(struct io_uring_buf_ring * br );
+
+# DESCRIPTION
+
+**io_uring_buf_ring_init**(3) initialises *br* so that it is ready to be used. It may be called after **io_uring_register_buf_ring**(3) but must be called before the buffer ring is used in any other way.
+
+# RETURN VALUE
+
+None
+
+# NOTES
+
+Unless manual setup is needed, it\'s recommended to use **io_uring_setup_buf_ring**(3) as it provides a simpler way to setup a provided buffer ring.
+
+# SEE ALSO
+
+**io_uring_register_buf_ring**(3), **io_uring_setup_buf_ring**(3), **io_uring_buf_ring_add**(3) **io_uring_buf_ring_advance**(3), **io_uring_buf_ring_cq_advance**(3)
diff --git a/man/io_uring_buf_ring_mask.3 b/man/io_uring_buf_ring_mask.3
deleted file mode 100644
index 91606630..00000000
--- a/man/io_uring_buf_ring_mask.3
+++ /dev/null
@@ -1,27 +0,0 @@
-.\" Copyright (C) 2022 Dylan Yudaken <dylany@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_buf_ring_mask 3 "June 13, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_buf_ring_mask \- Calculate buffer ring mask size
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_buf_ring_mask(__u32 " ring_entries ");"
-.fi
-.SH DESCRIPTION
-.PP
-.BR io_uring_buf_ring_mask (3)
-calculates the appropriate size mask for a buffer ring.
-.IR ring_entries
-is the ring entries as specified in
-.BR io_uring_register_buf_ring (3) .
-
-.SH RETURN VALUE
-Size mask for the buffer ring.
-
-.SH SEE ALSO
-.BR io_uring_register_buf_ring (3),
-.BR io_uring_buf_ring_add (3)
diff --git a/man/io_uring_buf_ring_mask.3.md b/man/io_uring_buf_ring_mask.3.md
new file mode 100644
index 00000000..7b03ef89
--- /dev/null
+++ b/man/io_uring_buf_ring_mask.3.md
@@ -0,0 +1,33 @@
+.\" Copyright (C) 2022 Dylan Yudaken <dylany@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: June 13, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_buf_ring_mask
+---
+
+# NAME
+
+io_uring_buf_ring_mask - Calculate buffer ring mask size
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_buf_ring_mask(__u32 ring_entries );
+
+# DESCRIPTION
+
+**io_uring_buf_ring_mask**(3) calculates the appropriate size mask for a buffer ring. *ring_entries* is the ring entries as specified in **io_uring_register_buf_ring**(3)**.**
+
+# RETURN VALUE
+
+Size mask for the buffer ring.
+
+# SEE ALSO
+
+**io_uring_register_buf_ring**(3), **io_uring_buf_ring_add**(3)
diff --git a/man/io_uring_cancelation.7 b/man/io_uring_cancelation.7
deleted file mode 100644
index f74bed20..00000000
--- a/man/io_uring_cancelation.7
+++ /dev/null
@@ -1,324 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_cancelation 7 "January 18, 2025" "Linux" "Linux Programmer's Manual"
-.SH NAME
-io_uring_cancelation \- io_uring request cancelation overview
-.SH DESCRIPTION
-io_uring provides mechanisms to cancel in-flight requests before they
-complete naturally. This is useful for implementing timeouts, handling
-connection drops, closing connections that go away, or when a request is no
-longer needed.
-.SS Why cancel requests?
-Common scenarios requiring cancelation:
-.IP \(bu 2
-.B Timeouts:
-Cancel a read or accept that has been pending too long
-.IP \(bu
-.B Connection management:
-Cancel pending operations when a connection is closed
-.IP \(bu
-.B Resource cleanup:
-Cancel operations on a file descriptor being closed
-.IP \(bu
-.B Multishot termination:
-Stop a multishot operation that is no longer needed
-.SS Basic cancelation
-The primary cancelation mechanism is
-.B IORING_OP_ASYNC_CANCEL
-(set up with
-.BR io_uring_prep_cancel (3)
-or related functions). By default, it cancels a request matching a
-specific
-.IR user_data :
-.PP
-.in +4n
-.EX
-/* Submit a read with user_data = 1234 */
-sqe = io_uring_get_sqe(ring);
-io_uring_prep_read(sqe, fd, buf, len, 0);
-io_uring_sqe_set_data64(sqe, 1234);
-io_uring_submit(ring);
-
-/* Later, cancel it */
-sqe = io_uring_get_sqe(ring);
-io_uring_prep_cancel64(sqe, 1234, 0);
-io_uring_submit(ring);
-.EE
-.in
-.SS Cancelation results
-When a cancelation is submitted, two CQEs are generated:
-.PP
-.B The canceled request's CQE:
-.RS 4
-.IP \(bu 2
-.I res
-is set to
-.B -ECANCELED
-(or occasionally
-.B -EINTR
-if the operation was already in progress)
-.IP \(bu
-The
-.I user_data
-identifies which request was canceled
-.RE
-.PP
-.B The cancel request's CQE:
-.RS 4
-.IP \(bu 2
-.I res
-is 0 on success (request was found and canceled)
-.IP \(bu
-.I res
-is
-.B -ENOENT
-if no matching request was found
-.IP \(bu
-.I res
-is
-.B -EALREADY
-if the request was found but already completing
-.RE
-.PP
-The order of these CQEs is not guaranteed. The application may receive
-the cancel CQE before or after the canceled request's CQE.
-.SS Cancelation flags
-Various flags modify cancelation behavior:
-.PP
-.B IORING_ASYNC_CANCEL_ALL
-.RS 4
-Cancel all matching requests, not just the first one found. The cancel
-CQE's
-.I res
-indicates how many requests were canceled.
-.RE
-.PP
-.B IORING_ASYNC_CANCEL_FD
-.RS 4
-Match requests by file descriptor instead of
-.IR user_data .
-Cancels requests operating on the specified fd:
-.PP
-.in +4n
-.EX
-io_uring_prep_cancel_fd(sqe, fd, IORING_ASYNC_CANCEL_FD);
-.EE
-.in
-.RE
-.PP
-.B IORING_ASYNC_CANCEL_ANY
-.RS 4
-Cancel any single request, ignoring
-.I user_data
-matching. Useful for draining a ring of all pending requests when
-combined with
-.BR IORING_ASYNC_CANCEL_ALL .
-.RE
-.PP
-.B IORING_ASYNC_CANCEL_FD_FIXED
-.RS 4
-The file descriptor is a fixed file (registered file index) rather
-than a regular fd.
-.RE
-.PP
-Flags can be combined:
-.PP
-.in +4n
-.EX
-/* Cancel all requests on a specific fd */
-io_uring_prep_cancel_fd(sqe, fd,
- IORING_ASYNC_CANCEL_FD | IORING_ASYNC_CANCEL_ALL);
-
-/* Cancel all pending requests in the ring */
-io_uring_prep_cancel(sqe, NULL,
- IORING_ASYNC_CANCEL_ANY | IORING_ASYNC_CANCEL_ALL);
-.EE
-.in
-.SS Race conditions
-Cancelation is inherently racy. Between submitting the cancel request
-and the kernel processing it:
-.IP \(bu 2
-The target request may complete successfully
-.IP \(bu
-The target request may fail for another reason
-.IP \(bu
-The target request may already be in a non-cancelable state
-.PP
-Applications must handle these cases:
-.PP
-.in +4n
-.EX
-io_uring_wait_cqe(ring, &cqe);
-
-if (cqe->user_data == cancel_user_data) {
- /* This is the cancel operation's result */
- if (cqe->res == -ENOENT) {
- /* Request already completed or not found */
- } else if (cqe->res == -EALREADY) {
- /* Request was found but completing */
- } else if (cqe->res >= 0) {
- /* Successfully canceled res requests */
- }
-} else {
- /* This is the original request's result */
- if (cqe->res == -ECANCELED) {
- /* Request was canceled */
- } else {
- /* Request completed normally (or with error) */
- }
-}
-.EE
-.in
-.SS Link timeouts
-For timing out a single operation, link timeouts are often simpler
-than explicit cancelation. See
-.BR io_uring_linked_requests (7)
-for details:
-.PP
-.in +4n
-.EX
-sqe = io_uring_get_sqe(ring);
-io_uring_prep_read(sqe, fd, buf, len, 0);
-sqe->flags |= IOSQE_IO_LINK;
-
-sqe = io_uring_get_sqe(ring);
-io_uring_prep_link_timeout(sqe, &timeout, 0);
-.EE
-.in
-.PP
-The kernel handles the cancelation automatically if the timeout
-expires.
-.SS Canceling multishot requests
-Multishot requests (see
-.BR io_uring_multishot (7))
-continue generating completions until canceled or an error occurs.
-To stop a multishot request:
-.PP
-.in +4n
-.EX
-/* Cancel a multishot accept */
-io_uring_prep_cancel64(sqe, accept_user_data, 0);
-.EE
-.in
-.PP
-After cancelation:
-.IP \(bu 2
-The multishot generates a final CQE with
-.B -ECANCELED
-.IP \(bu
-The
-.B IORING_CQE_F_MORE
-flag is not set on this final CQE
-.IP \(bu
-The cancel CQE indicates success
-.SS Canceling by file descriptor
-When a file descriptor is closed (either via
-.BR close (2)
-or
-.BR IORING_OP_CLOSE ),
-pending requests operating on that fd are
-.B not
-automatically canceled. This differs from synchronous I/O behavior
-and is a common source of confusion.
-
-In synchronous I/O, closing a file descriptor is typically the last
-reference to the underlying file, so the close completes any pending
-operations. However, io_uring holds its own reference to the file for
-each pending request. Closing the application's fd does not release
-these references \(em the pending read, recv, or other operation
-continues to hold a reference and will not automatically complete or
-fail.
-
-If an application expects a pending read on an fd to post a completion
-when the fd is closed, that will not happen. The request must be
-explicitly canceled:
-.PP
-.in +4n
-.EX
-/* Cancel all operations on fd before closing */
-sqe = io_uring_get_sqe(ring);
-io_uring_prep_cancel_fd(sqe, fd,
- IORING_ASYNC_CANCEL_FD | IORING_ASYNC_CANCEL_ALL);
-io_uring_submit(ring);
-
-/* Wait for cancelations, then close */
-.EE
-.in
-.SS Shutdown cancelation
-When an io_uring instance is closed (via
-.BR io_uring_queue_exit (3)
-or closing the ring file descriptor), all pending requests are
-automatically canceled. Manual cancelation before shutdown is not
-required.
-
-However, if the application needs to ensure all requests are completed
-before proceeding (e.g., to process their results or free associated
-resources), explicit cancelation can be used:
-.PP
-.in +4n
-.EX
-/* Cancel everything */
-sqe = io_uring_get_sqe(ring);
-io_uring_prep_cancel(sqe, NULL,
- IORING_ASYNC_CANCEL_ANY | IORING_ASYNC_CANCEL_ALL);
-io_uring_submit(ring);
-
-/* Wait for all CQEs */
-while (pending_count > 0) {
- io_uring_wait_cqe(ring, &cqe);
- pending_count--;
- io_uring_cqe_seen(ring, cqe);
-}
-.EE
-.in
-.SS Synchronous cancelation
-For cases where the application needs to cancel requests and wait for
-the cancelation to complete in a single blocking call,
-.BR io_uring_register_sync_cancel (3)
-provides a synchronous interface:
-.PP
-.in +4n
-.EX
-struct io_uring_sync_cancel_reg reg = {
- .addr = user_data,
- .timeout.tv_sec = 5,
-};
-
-ret = io_uring_register_sync_cancel(ring, ®);
-.EE
-.in
-.PP
-This blocks until the matching request is canceled or the timeout
-expires. It is useful when the application cannot easily integrate
-asynchronous cancelation into its event loop.
-.SH NOTES
-.IP \(bu 2
-Not all operations are cancelable. Operations that have already
-been submitted to hardware (e.g., disk I/O in progress) typically
-cannot be canceled.
-.IP \(bu
-Cancelation is asynchronous. The cancel request itself may take
-time to complete.
-.IP \(bu
-When using
-.BR IORING_ASYNC_CANCEL_ALL ,
-the cancel CQE's
-.I res
-field contains the count of canceled requests.
-.IP \(bu
-Fixed files can be canceled using
-.B IORING_ASYNC_CANCEL_FD_FIXED
-with the file index instead of a regular fd.
-.IP \(bu
-Poll operations and multishot requests are generally good candidates
-for cancelation. Completed disk I/O is not.
-.SH SEE ALSO
-.BR io_uring (7),
-.BR io_uring_linked_requests (7),
-.BR io_uring_multishot (7),
-.BR io_uring_prep_cancel (3),
-.BR io_uring_prep_cancel64 (3),
-.BR io_uring_prep_cancel_fd (3),
-.BR io_uring_prep_link_timeout (3),
-.BR io_uring_register_sync_cancel (3)
diff --git a/man/io_uring_cancelation.7.md b/man/io_uring_cancelation.7.md
new file mode 100644
index 00000000..cb417142
--- /dev/null
+++ b/man/io_uring_cancelation.7.md
@@ -0,0 +1,221 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: Linux
+header: Linux Programmer\'s Manual
+section: 7
+title: io_uring_cancelation
+---
+
+# NAME
+
+io_uring_cancelation - io_uring request cancelation overview
+
+# DESCRIPTION
+
+io_uring provides mechanisms to cancel in-flight requests before they complete naturally. This is useful for implementing timeouts, handling connection drops, closing connections that go away, or when a request is no longer needed.
+
+## Why cancel requests?
+
+Common scenarios requiring cancelation:
+
+- **Timeouts:** Cancel a read or accept that has been pending too long
+
+- **Connection management:** Cancel pending operations when a connection is closed
+
+- **Resource cleanup:** Cancel operations on a file descriptor being closed
+
+- **Multishot termination:** Stop a multishot operation that is no longer needed
+
+## Basic cancelation
+
+The primary cancelation mechanism is **IORING_OP_ASYNC_CANCEL** (set up with **io_uring_prep_cancel**(3) or related functions). By default, it cancels a request matching a specific *user_data*:
+
+ /* Submit a read with user_data = 1234 */
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_read(sqe, fd, buf, len, 0);
+ io_uring_sqe_set_data64(sqe, 1234);
+ io_uring_submit(ring);
+
+ /* Later, cancel it */
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_cancel64(sqe, 1234, 0);
+ io_uring_submit(ring);
+
+## Cancelation results
+
+When a cancelation is submitted, two CQEs are generated:
+
+**The canceled request\'s CQE:**
+
+> - *res* is set to **-ECANCELED** (or occasionally **-EINTR** if the operation was already in progress)
+>
+> - The *user_data* identifies which request was canceled
+
+**The cancel request\'s CQE:**
+
+> - *res* is 0 on success (request was found and canceled)
+>
+> - *res* is **-ENOENT** if no matching request was found
+>
+> - *res* is **-EALREADY** if the request was found but already completing
+
+The order of these CQEs is not guaranteed. The application may receive the cancel CQE before or after the canceled request\'s CQE.
+
+## Cancelation flags
+
+Various flags modify cancelation behavior:
+
+**IORING_ASYNC_CANCEL_ALL**
+
+> Cancel all matching requests, not just the first one found. The cancel CQE\'s *res* indicates how many requests were canceled.
+
+**IORING_ASYNC_CANCEL_FD**
+
+> Match requests by file descriptor instead of *user_data*. Cancels requests operating on the specified fd:
+>
+> io_uring_prep_cancel_fd(sqe, fd, IORING_ASYNC_CANCEL_FD);
+
+**IORING_ASYNC_CANCEL_ANY**
+
+> Cancel any single request, ignoring *user_data* matching. Useful for draining a ring of all pending requests when combined with **IORING_ASYNC_CANCEL_ALL**.
+
+**IORING_ASYNC_CANCEL_FD_FIXED**
+
+> The file descriptor is a fixed file (registered file index) rather than a regular fd.
+
+Flags can be combined:
+
+ /* Cancel all requests on a specific fd */
+ io_uring_prep_cancel_fd(sqe, fd,
+ IORING_ASYNC_CANCEL_FD | IORING_ASYNC_CANCEL_ALL);
+
+ /* Cancel all pending requests in the ring */
+ io_uring_prep_cancel(sqe, NULL,
+ IORING_ASYNC_CANCEL_ANY | IORING_ASYNC_CANCEL_ALL);
+
+## Race conditions
+
+Cancelation is inherently racy. Between submitting the cancel request and the kernel processing it:
+
+- The target request may complete successfully
+
+- The target request may fail for another reason
+
+- The target request may already be in a non-cancelable state
+
+Applications must handle these cases:
+
+ io_uring_wait_cqe(ring, &cqe);
+
+ if (cqe->user_data == cancel_user_data) {
+ /* This is the cancel operation's result */
+ if (cqe->res == -ENOENT) {
+ /* Request already completed or not found */
+ } else if (cqe->res == -EALREADY) {
+ /* Request was found but completing */
+ } else if (cqe->res >= 0) {
+ /* Successfully canceled res requests */
+ }
+ } else {
+ /* This is the original request's result */
+ if (cqe->res == -ECANCELED) {
+ /* Request was canceled */
+ } else {
+ /* Request completed normally (or with error) */
+ }
+ }
+
+## Link timeouts
+
+For timing out a single operation, link timeouts are often simpler than explicit cancelation. See **io_uring_linked_requests**(7) for details:
+
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_read(sqe, fd, buf, len, 0);
+ sqe->flags |= IOSQE_IO_LINK;
+
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_link_timeout(sqe, &timeout, 0);
+
+The kernel handles the cancelation automatically if the timeout expires.
+
+## Canceling multishot requests
+
+Multishot requests (see **io_uring_multishot**(7)) continue generating completions until canceled or an error occurs. To stop a multishot request:
+
+ /* Cancel a multishot accept */
+ io_uring_prep_cancel64(sqe, accept_user_data, 0);
+
+After cancelation:
+
+- The multishot generates a final CQE with **-ECANCELED**
+
+- The **IORING_CQE_F_MORE** flag is not set on this final CQE
+
+- The cancel CQE indicates success
+
+## Canceling by file descriptor
+
+When a file descriptor is closed (either via **close**(2) or **IORING_OP_CLOSE**), pending requests operating on that fd are **not** automatically canceled. This differs from synchronous I/O behavior and is a common source of confusion.
+
+In synchronous I/O, closing a file descriptor is typically the last reference to the underlying file, so the close completes any pending operations. However, io_uring holds its own reference to the file for each pending request. Closing the application\'s fd does not release these references --- the pending read, recv, or other operation continues to hold a reference and will not automatically complete or fail.
+
+If an application expects a pending read on an fd to post a completion when the fd is closed, that will not happen. The request must be explicitly canceled:
+
+ /* Cancel all operations on fd before closing */
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_cancel_fd(sqe, fd,
+ IORING_ASYNC_CANCEL_FD | IORING_ASYNC_CANCEL_ALL);
+ io_uring_submit(ring);
+
+ /* Wait for cancelations, then close */
+
+## Shutdown cancelation
+
+When an io_uring instance is closed (via **io_uring_queue_exit**(3) or closing the ring file descriptor), all pending requests are automatically canceled. Manual cancelation before shutdown is not required.
+
+However, if the application needs to ensure all requests are completed before proceeding (e.g., to process their results or free associated resources), explicit cancelation can be used:
+
+ /* Cancel everything */
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_cancel(sqe, NULL,
+ IORING_ASYNC_CANCEL_ANY | IORING_ASYNC_CANCEL_ALL);
+ io_uring_submit(ring);
+
+ /* Wait for all CQEs */
+ while (pending_count > 0) {
+ io_uring_wait_cqe(ring, &cqe);
+ pending_count--;
+ io_uring_cqe_seen(ring, cqe);
+ }
+
+## Synchronous cancelation
+
+For cases where the application needs to cancel requests and wait for the cancelation to complete in a single blocking call, **io_uring_register_sync_cancel**(3) provides a synchronous interface:
+
+ struct io_uring_sync_cancel_reg reg = {
+ .addr = user_data,
+ .timeout.tv_sec = 5,
+ };
+
+ ret = io_uring_register_sync_cancel(ring, ®);
+
+This blocks until the matching request is canceled or the timeout expires. It is useful when the application cannot easily integrate asynchronous cancelation into its event loop.
+
+# NOTES
+
+- Not all operations are cancelable. Operations that have already been submitted to hardware (e.g., disk I/O in progress) typically cannot be canceled.
+
+- Cancelation is asynchronous. The cancel request itself may take time to complete.
+
+- When using **IORING_ASYNC_CANCEL_ALL**, the cancel CQE\'s *res* field contains the count of canceled requests.
+
+- Fixed files can be canceled using **IORING_ASYNC_CANCEL_FD_FIXED** with the file index instead of a regular fd.
+
+- Poll operations and multishot requests are generally good candidates for cancelation. Completed disk I/O is not.
+
+# SEE ALSO
+
+**io_uring**(7), **io_uring_linked_requests**(7), **io_uring_multishot**(7), **io_uring_prep_cancel**(3), **io_uring_prep_cancel64**(3), **io_uring_prep_cancel_fd**(3), **io_uring_prep_link_timeout**(3), **io_uring_register_sync_cancel**(3)
diff --git a/man/io_uring_check_version.3 b/man/io_uring_check_version.3
deleted file mode 100644
index b7d771ab..00000000
--- a/man/io_uring_check_version.3
+++ /dev/null
@@ -1,72 +0,0 @@
-.\" Copyright (C) 2022 Christian Hergert <chergert@redhat.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_check_version 3 "December 1, 2022" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_check_version \- functions and macros to check the liburing version
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "bool io_uring_check_version(int " major ", int " minor ");"
-.BI "IO_URING_CHECK_VERSION(" major ", " minor ");"
-.PP
-.BI "int io_uring_major_version(void);"
-.BI "IO_URING_VERSION_MAJOR;"
-.PP
-.BI "int io_uring_minor_version(void);"
-.BI "IO_URING_VERSION_MINOR;"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_check_version (3)
-function returns
-.I false
-if the liburing library loaded by the dynamic linker is greater-than
-or equal-to the
-.I major
-and
-.I minor
-numbers provided.
-
-.PP
-The
-.BR IO_URING_CHECK_VERSION (3)
-macro returns
-.I 0
-if the liburing library being compiled against is greater-than or equal-to the
-.I major
-and
-.I minor
-numbers provided.
-
-.PP
-The
-.BR io_uring_major_version (3)
-function returns the
-.I major
-version number of the liburing library loaded by the dynamic linker.
-
-.PP
-The
-.BR IO_URING_VERSION_MAJOR (3)
-macro returns the
-.I major
-version number of the liburing library being compiled against.
-
-.PP
-The
-.BR io_uring_minor_version (3)
-function returns the
-.I minor
-version number of the liburing library loaded by the dynamic linker.
-
-.PP
-The
-.BR IO_URING_VERSION_MINOR (3)
-macro returns the
-.I minor
-version number of the liburing library being compiled against.
-
diff --git a/man/io_uring_check_version.3.md b/man/io_uring_check_version.3.md
new file mode 100644
index 00000000..afbe43e1
--- /dev/null
+++ b/man/io_uring_check_version.3.md
@@ -0,0 +1,42 @@
+.\" Copyright (C) 2022 Christian Hergert <chergert@redhat.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: December 1, 2022
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_check_version
+---
+
+# NAME
+
+io_uring_check_version - functions and macros to check the liburing version
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ bool io_uring_check_version(int major , int minor );
+ IO_URING_CHECK_VERSION( major , minor );
+
+ int io_uring_major_version(void);
+ IO_URING_VERSION_MAJOR;
+
+ int io_uring_minor_version(void);
+ IO_URING_VERSION_MINOR;
+
+# DESCRIPTION
+
+The **io_uring_check_version**(3) function returns *false* if the liburing library loaded by the dynamic linker is greater-than or equal-to the *major* and *minor* numbers provided.
+
+The **IO_URING_CHECK_VERSION**(3) macro returns *0* if the liburing library being compiled against is greater-than or equal-to the *major* and *minor* numbers provided.
+
+The **io_uring_major_version**(3) function returns the *major* version number of the liburing library loaded by the dynamic linker.
+
+The **IO_URING_VERSION_MAJOR**(3) macro returns the *major* version number of the liburing library being compiled against.
+
+The **io_uring_minor_version**(3) function returns the *minor* version number of the liburing library loaded by the dynamic linker.
+
+The **IO_URING_VERSION_MINOR**(3) macro returns the *minor* version number of the liburing library being compiled against.
diff --git a/man/io_uring_clone_buffers.3 b/man/io_uring_clone_buffers.3
deleted file mode 100644
index 4fd9c241..00000000
--- a/man/io_uring_clone_buffers.3
+++ /dev/null
@@ -1,165 +0,0 @@
-.\" Copyright (C) 2024 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_clone_buffers 3 "September 12, 2024" "liburing-2.9" "liburing Manual"
-.SH NAME
-io_uring_clone_buffers \- Clones registered buffers between rings
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_clone_buffers(struct io_uring *" dst ","
-.BI " struct io_uring * " src ");"
-.PP
-.BI "int __io_uring_clone_buffers(struct io_uring *" dst ","
-.BI " struct io_uring * " src ","
-.BI " unsigned int " flags ");"
-.PP
-.BI "int io_uring_clone_buffers_offset(struct io_uring *" dst ","
-.BI " struct io_uring * " src ","
-.BI " unsigned int " dst_off ","
-.BI " unsigned int " src_off ","
-.BI " unsigned int " nr ","
-.BI " unsigned int " flags ");"
-.PP
-.BI "int __io_uring_clone_buffers_offset(struct io_uring *" dst ","
-.BI " struct io_uring * " src ","
-.BI " unsigned int " dst_off ","
-.BI " unsigned int " src_off ","
-.BI " unsigned int " nr ","
-.BI " unsigned int " flags ");"
-.PP
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_clone_buffers (3)
-function clones registered buffers from the ring indicated by
-.IR src
-to the ring indicated by
-.IR dst .
-Upon successful completion of this operation,
-.IR src
-and
-.IR dst
-will have the same set of registered buffers. This operation is identical to
-performing a
-.BR io_uring_register_buffers (3)
-operation on the
-.IR dst
-ring, if the
-.IR src
-ring previously had that same buffer registration operating done.
-
-The
-.IR dst
-ring must not have any buffers currently registered. If buffers are currently
-registered on the destination ring, they must be unregistered with
-.BR io_uring_unregister_buffers (3)
-first.
-
-For
-.BR __io_uring_clone_buffers (3) ,
-the only difference is that it takes a
-.IR flags
-argument. By default, if the destination ring has a registered file descriptor
-through
-.BR io_uring_register_ring_fd (3)
-AND the calling application is not the thread that registered that ring, then
-the kernel doesn't know how to look up the destination. This is problematic
-as
-.BR io_uring_clone_buffers (3)
-defaults to using the registered index if the destination is setup as such.
-Use
-.BR __io_uring_clone_buffers (3)
-which doesn't set
-.B IORING_REGISTER_SRC_REGISTERED
-by default. This requires the application to still have the original ring file
-descriptor open. See below for the flag definition.
-
-Available since kernel 6.12.
-
-The
-.BR io_uring_clone_buffers_offset (3)
-function also clones buffers from the
-.IR src
-ring to the
-.IR dst
-ring, however it supports cloning only a subset of the buffers, where
-.BR io_uring_clone_buffers (3)
-always clones all of them.
-.IR dst_off
-indicates at what offset cloning should start in the destination,
-.IR src_off
-indicates at what offset cloning should start in the source, and
-.IR nr
-indicates how many buffers to clone at the given offset. If both
-.IR dst_off ,
-.IR src_off ,
-and
-.IR nr
-are given as
-.B 0 ,
-then
-.BR io_uring_clone_buffers_offset (3)
-performs the same action as
-.BR io_uring_clone_buffers (3) .
-
-While
-.BR io_uring_clone_buffers_offset (3)
-sets
-.B IORING_REGISTER_SRC_REGISTERED
-by default, the
-.BR __io_uring_clone_buffers_offset (3)
-does not. See the explanation for
-.BR __io_uring_clone_buffers (3)
-for details.
-
-.IR flags
-may be set to the following value:
-.TP
-.B IORING_REGISTER_SRC_REGISTERED
-If the source ring is registered AND the calling thread is the one that
-originally registered its ring fd, then this flag may be set to lookup the
-registered index rather than use the normal file descriptor. If the normal
-file descriptor wasn't closed after registering it, there's no need to set
-this flag.
-.TP
-.B IORING_REGISTER_DST_REPLACE
-If set, cloning may happen for a destination ring that already has a buffer
-table assigned. In that case, existing nodes that overlap with the specified
-range will be released and replaced.
-.PP
-
-Available since kernel 6.13.
-
-.SH NOTES
-The source and target ring must shared address spaces, and hence internal
-kernel accounting.
-.SH RETURN VALUE
-On success
-.BR io_uring_clone_buffers (3)
-and
-.BR io_uring_clone_buffers_offset (3)
-return 0.
-On failure, they returns
-.BR -errno ,
-specifically
-.TP
-.B -EBUSY
-The destination ring already has buffers registered, and
-.B IORING_REGISTER_DST_REPLACE
-wasn't set.
-.TP
-.B -ENOMEM
-The kernel ran out of memory.
-.TP
-.B -ENXIO
-The source ring doesn't have any buffers registered.
-.SH SEE ALSO
-.BR io_uring_register (2),
-.BR io_uring_unregister_buffers (3),
-.BR io_uring_register_buffers (3),
-.BR io_uring_prep_read_fixed (3),
-.BR io_uring_prep_write_fixed (3)
diff --git a/man/io_uring_clone_buffers.3.md b/man/io_uring_clone_buffers.3.md
new file mode 100644
index 00000000..ce1f7635
--- /dev/null
+++ b/man/io_uring_clone_buffers.3.md
@@ -0,0 +1,90 @@
+.\" Copyright (C) 2024 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: September 12, 2024
+footer: liburing-2.9
+header: liburing Manual
+section: 3
+title: io_uring_clone_buffers
+---
+
+# NAME
+
+io_uring_clone_buffers - Clones registered buffers between rings
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_clone_buffers(struct io_uring * dst ,
+ struct io_uring * src );
+
+ int __io_uring_clone_buffers(struct io_uring * dst ,
+ struct io_uring * src ,
+ unsigned int flags );
+
+ int io_uring_clone_buffers_offset(struct io_uring * dst ,
+ struct io_uring * src ,
+ unsigned int dst_off ,
+ unsigned int src_off ,
+ unsigned int nr ,
+ unsigned int flags );
+
+ int __io_uring_clone_buffers_offset(struct io_uring * dst ,
+ struct io_uring * src ,
+ unsigned int dst_off ,
+ unsigned int src_off ,
+ unsigned int nr ,
+ unsigned int flags );
+
+# DESCRIPTION
+
+The **io_uring_clone_buffers**(3) function clones registered buffers from the ring indicated by *src* to the ring indicated by *dst*. Upon successful completion of this operation, *src* and *dst* will have the same set of registered buffers. This operation is identical to performing a **io_uring_register_buffers**(3) operation on the *dst* ring, if the *src* ring previously had that same buffer registration operating done.
+
+The *dst* ring must not have any buffers currently registered. If buffers are currently registered on the destination ring, they must be unregistered with **io_uring_unregister_buffers**(3) first.
+
+For **\_\_io_uring_clone_buffers**(3)**,** the only difference is that it takes a *flags* argument. By default, if the destination ring has a registered file descriptor through **io_uring_register_ring_fd**(3) AND the calling application is not the thread that registered that ring, then the kernel doesn\'t know how to look up the destination. This is problematic as **io_uring_clone_buffers**(3) defaults to using the registered index if the destination is setup as such. Use **\_\_io_uring_clone_buffers**(3) which doesn\'t set **IORING_REGISTER_SRC_REGISTERED** by default. This requires the application to still have the original ring file descriptor open. See below for the flag definition.
+
+Available since kernel 6.12.
+
+The **io_uring_clone_buffers_offset**(3) function also clones buffers from the *src* ring to the *dst* ring, however it supports cloning only a subset of the buffers, where **io_uring_clone_buffers**(3) always clones all of them. *dst_off* indicates at what offset cloning should start in the destination, *src_off* indicates at what offset cloning should start in the source, and *nr* indicates how many buffers to clone at the given offset. If both *dst_off*, *src_off*, and *nr* are given as **0 ,** then **io_uring_clone_buffers_offset**(3) performs the same action as **io_uring_clone_buffers**(3)**.**
+
+While **io_uring_clone_buffers_offset**(3) sets **IORING_REGISTER_SRC_REGISTERED** by default, the **\_\_io_uring_clone_buffers_offset**(3) does not. See the explanation for **\_\_io_uring_clone_buffers**(3) for details.
+
+*flags* may be set to the following value:
+
+**IORING_REGISTER_SRC_REGISTERED**
+
+: If the source ring is registered AND the calling thread is the one that originally registered its ring fd, then this flag may be set to lookup the registered index rather than use the normal file descriptor. If the normal file descriptor wasn\'t closed after registering it, there\'s no need to set this flag.
+
+**IORING_REGISTER_DST_REPLACE**
+
+: If set, cloning may happen for a destination ring that already has a buffer table assigned. In that case, existing nodes that overlap with the specified range will be released and replaced.
+
+Available since kernel 6.13.
+
+# NOTES
+
+The source and target ring must shared address spaces, and hence internal kernel accounting.
+
+# RETURN VALUE
+
+On success **io_uring_clone_buffers**(3) and **io_uring_clone_buffers_offset**(3) return 0. On failure, they returns **-errno**, specifically
+
+**-EBUSY**
+
+: The destination ring already has buffers registered, and **IORING_REGISTER_DST_REPLACE** wasn\'t set.
+
+**-ENOMEM**
+
+: The kernel ran out of memory.
+
+**-ENXIO**
+
+: The source ring doesn\'t have any buffers registered.
+
+# SEE ALSO
+
+**io_uring_register**(2), **io_uring_unregister_buffers**(3), **io_uring_register_buffers**(3), **io_uring_prep_read_fixed**(3), **io_uring_prep_write_fixed**(3)
diff --git a/man/io_uring_clone_buffers_offset.3 b/man/io_uring_clone_buffers_offset.3
deleted file mode 120000
index 6d7e5483..00000000
--- a/man/io_uring_clone_buffers_offset.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_clone_buffers.3
\ No newline at end of file
diff --git a/man/io_uring_close_ring_fd.3 b/man/io_uring_close_ring_fd.3
deleted file mode 100644
index b5963c9d..00000000
--- a/man/io_uring_close_ring_fd.3
+++ /dev/null
@@ -1,43 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\" Copyright (C) 2022 Josh Triplett <josh@joshtriplett.org>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_close_ring_fd 3 "September 25, 2022" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_close_ring_fd \- close a ring file descriptor and use it only via registered index
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_close_ring_fd(struct io_uring *" ring ");"
-.fi
-.SH DESCRIPTION
-.PP
-.BR io_uring_close_ring_fd (3)
-closes the ring file descriptor, which must have been previously registered.
-The file will remain open, but accessible only via the registered index, not
-via any file descriptor. Subsequent liburing calls will continue to work, using
-the registered ring fd.
-
-The kernel must support
-.BR IORING_FEAT_REG_REG_RING .
-
-Libraries that must avoid disrupting their users' uses of file descriptors, and
-must continue working even in the face of
-.BR close_range (2)
-and similar, can use
-.BR io_uring_close_ring_fd (3)
-to work with liburing without having any open file descriptor.
-
-.SH NOTES
-Each thread that wants to make use of io_uring must register the fd. A library
-that may get called from arbitrary theads may need to detect when it gets
-called on a previously unseen thread and create and register a ring for that
-thread.
-.SH RETURN VALUE
-Returns 1 on success, or
-.BR -errno
-on error.
-.SH SEE ALSO
-.BR io_uring_register_ring_fd (3)
diff --git a/man/io_uring_close_ring_fd.3.md b/man/io_uring_close_ring_fd.3.md
new file mode 100644
index 00000000..91b09e93
--- /dev/null
+++ b/man/io_uring_close_ring_fd.3.md
@@ -0,0 +1,42 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\" Copyright (C) 2022 Josh Triplett <josh@joshtriplett.org>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: September 25, 2022
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_close_ring_fd
+---
+
+# NAME
+
+io_uring_close_ring_fd - close a ring file descriptor and use it only via registered index
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_close_ring_fd(struct io_uring * ring );
+
+# DESCRIPTION
+
+**io_uring_close_ring_fd**(3) closes the ring file descriptor, which must have been previously registered. The file will remain open, but accessible only via the registered index, not via any file descriptor. Subsequent liburing calls will continue to work, using the registered ring fd.
+
+The kernel must support **IORING_FEAT_REG_REG_RING**.
+
+Libraries that must avoid disrupting their users\' uses of file descriptors, and must continue working even in the face of **close_range**(2) and similar, can use **io_uring_close_ring_fd**(3) to work with liburing without having any open file descriptor.
+
+# NOTES
+
+Each thread that wants to make use of io_uring must register the fd. A library that may get called from arbitrary theads may need to detect when it gets called on a previously unseen thread and create and register a ring for that thread.
+
+# RETURN VALUE
+
+Returns 1 on success, or **-errno** on error.
+
+# SEE ALSO
+
+**io_uring_register_ring_fd**(3)
diff --git a/man/io_uring_cq_advance.3 b/man/io_uring_cq_advance.3
deleted file mode 100644
index fae25722..00000000
--- a/man/io_uring_cq_advance.3
+++ /dev/null
@@ -1,49 +0,0 @@
-.\" Copyright (C) 2022 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_cq_advance 3 "January 25, 2022" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_cq_advance \- mark one or more io_uring completion events as consumed
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_cq_advance(struct io_uring *" ring ","
-.BI " unsigned " nr ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_cq_advance (3)
-function marks
-.I nr
-IO completions belonging to the
-.I ring
-param as consumed.
-
-After the caller has submitted a request with
-.BR io_uring_submit (3),
-the application can retrieve the completion with
-.BR io_uring_wait_cqe (3),
-.BR io_uring_peek_cqe (3),
-or any of the other CQE retrieval helpers, and mark it as consumed with
-.BR io_uring_cqe_seen (3).
-
-The function
-.BR io_uring_cqe_seen (3)
-calls the function
-.BR io_uring_cq_advance (3).
-
-Completions must be marked as seen, so their slot can get reused. Failure to do
-so will result in the same completion being returned on the next invocation.
-
-.SH RETURN VALUE
-None
-.SH SEE ALSO
-.BR io_uring_submit (3),
-.BR io_uring_wait_cqe (3),
-.BR io_uring_peek_cqe (3),
-.BR io_uring_wait_cqes (3),
-.BR io_uring_wait_cqe_timeout (3),
-.BR io_uring_cqe_seen (3)
diff --git a/man/io_uring_cq_advance.3.md b/man/io_uring_cq_advance.3.md
new file mode 100644
index 00000000..eaf780f8
--- /dev/null
+++ b/man/io_uring_cq_advance.3.md
@@ -0,0 +1,40 @@
+.\" Copyright (C) 2022 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 25, 2022
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_cq_advance
+---
+
+# NAME
+
+io_uring_cq_advance - mark one or more io_uring completion events as consumed
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_cq_advance(struct io_uring * ring ,
+ unsigned nr );
+
+# DESCRIPTION
+
+The **io_uring_cq_advance**(3) function marks *nr* IO completions belonging to the *ring* param as consumed.
+
+After the caller has submitted a request with **io_uring_submit**(3), the application can retrieve the completion with **io_uring_wait_cqe**(3), **io_uring_peek_cqe**(3), or any of the other CQE retrieval helpers, and mark it as consumed with **io_uring_cqe_seen**(3).
+
+The function **io_uring_cqe_seen**(3) calls the function **io_uring_cq_advance**(3).
+
+Completions must be marked as seen, so their slot can get reused. Failure to do so will result in the same completion being returned on the next invocation.
+
+# RETURN VALUE
+
+None
+
+# SEE ALSO
+
+**io_uring_submit**(3), **io_uring_wait_cqe**(3), **io_uring_peek_cqe**(3), **io_uring_wait_cqes**(3), **io_uring_wait_cqe_timeout**(3), **io_uring_cqe_seen**(3)
diff --git a/man/io_uring_cq_eventfd_enabled.3 b/man/io_uring_cq_eventfd_enabled.3
deleted file mode 100644
index 455a5f51..00000000
--- a/man/io_uring_cq_eventfd_enabled.3
+++ /dev/null
@@ -1,38 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_cq_eventfd_enabled 3 "January 18, 2025" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_cq_eventfd_enabled \- check if eventfd notifications are enabled
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "bool io_uring_cq_eventfd_enabled(const struct io_uring *" ring ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_cq_eventfd_enabled (3)
-function returns whether eventfd notifications are currently enabled for
-the io_uring instance specified by
-.IR ring .
-
-An eventfd can be registered with a ring using
-.BR io_uring_register_eventfd (3)
-or
-.BR io_uring_register_eventfd_async (3).
-Once registered, notifications can be temporarily disabled using
-.BR io_uring_cq_eventfd_toggle (3).
-
-.SH RETURN VALUE
-Returns
-.B true
-if eventfd notifications are enabled, or
-.B false
-if disabled.
-.SH SEE ALSO
-.BR io_uring_register_eventfd (3),
-.BR io_uring_register_eventfd_async (3),
-.BR io_uring_cq_eventfd_toggle (3)
diff --git a/man/io_uring_cq_eventfd_enabled.3.md b/man/io_uring_cq_eventfd_enabled.3.md
new file mode 100644
index 00000000..f5571bf1
--- /dev/null
+++ b/man/io_uring_cq_eventfd_enabled.3.md
@@ -0,0 +1,35 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_cq_eventfd_enabled
+---
+
+# NAME
+
+io_uring_cq_eventfd_enabled - check if eventfd notifications are enabled
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ bool io_uring_cq_eventfd_enabled(const struct io_uring * ring );
+
+# DESCRIPTION
+
+The **io_uring_cq_eventfd_enabled**(3) function returns whether eventfd notifications are currently enabled for the io_uring instance specified by *ring*.
+
+An eventfd can be registered with a ring using **io_uring_register_eventfd**(3) or **io_uring_register_eventfd_async**(3). Once registered, notifications can be temporarily disabled using **io_uring_cq_eventfd_toggle**(3).
+
+# RETURN VALUE
+
+Returns **true** if eventfd notifications are enabled, or **false** if disabled.
+
+# SEE ALSO
+
+**io_uring_register_eventfd**(3), **io_uring_register_eventfd_async**(3), **io_uring_cq_eventfd_toggle**(3)
diff --git a/man/io_uring_cq_eventfd_toggle.3 b/man/io_uring_cq_eventfd_toggle.3
deleted file mode 100644
index 21270607..00000000
--- a/man/io_uring_cq_eventfd_toggle.3
+++ /dev/null
@@ -1,48 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_cq_eventfd_toggle 3 "January 18, 2025" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_cq_eventfd_toggle \- toggle eventfd notifications on or off
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_cq_eventfd_toggle(struct io_uring *" ring ", bool " enabled ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_cq_eventfd_toggle (3)
-function toggles eventfd notifications for the io_uring instance specified by
-.IR ring .
-If
-.I enabled
-is
-.BR true ,
-eventfd notifications are enabled. If
-.I enabled
-is
-.BR false ,
-they are disabled.
-
-An eventfd must first be registered with the ring using
-.BR io_uring_register_eventfd (3)
-or
-.BR io_uring_register_eventfd_async (3)
-before this function can be used.
-
-This can be useful when the application wants to temporarily stop receiving
-eventfd notifications, for example during a batch processing phase.
-
-.SH RETURN VALUE
-Returns 0 on success. On error, a negative errno value is returned:
-.TP
-.B -EOPNOTSUPP
-The kernel does not support toggling eventfd notifications, or no eventfd
-is registered.
-.SH SEE ALSO
-.BR io_uring_register_eventfd (3),
-.BR io_uring_register_eventfd_async (3),
-.BR io_uring_cq_eventfd_enabled (3)
diff --git a/man/io_uring_cq_eventfd_toggle.3.md b/man/io_uring_cq_eventfd_toggle.3.md
new file mode 100644
index 00000000..7a433832
--- /dev/null
+++ b/man/io_uring_cq_eventfd_toggle.3.md
@@ -0,0 +1,41 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_cq_eventfd_toggle
+---
+
+# NAME
+
+io_uring_cq_eventfd_toggle - toggle eventfd notifications on or off
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_cq_eventfd_toggle(struct io_uring * ring , bool enabled );
+
+# DESCRIPTION
+
+The **io_uring_cq_eventfd_toggle**(3) function toggles eventfd notifications for the io_uring instance specified by *ring*. If *enabled* is **true**, eventfd notifications are enabled. If *enabled* is **false**, they are disabled.
+
+An eventfd must first be registered with the ring using **io_uring_register_eventfd**(3) or **io_uring_register_eventfd_async**(3) before this function can be used.
+
+This can be useful when the application wants to temporarily stop receiving eventfd notifications, for example during a batch processing phase.
+
+# RETURN VALUE
+
+Returns 0 on success. On error, a negative errno value is returned:
+
+**-EOPNOTSUPP**
+
+: The kernel does not support toggling eventfd notifications, or no eventfd is registered.
+
+# SEE ALSO
+
+**io_uring_register_eventfd**(3), **io_uring_register_eventfd_async**(3), **io_uring_cq_eventfd_enabled**(3)
diff --git a/man/io_uring_cq_has_overflow.3 b/man/io_uring_cq_has_overflow.3
deleted file mode 100644
index 8ca0ba86..00000000
--- a/man/io_uring_cq_has_overflow.3
+++ /dev/null
@@ -1,31 +0,0 @@
-.\" Copyright (C) 2022 Dylan Yudaken <dylany@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_cq_has_overflow 3 "September 5, 2022" "liburing-2.3" "liburing Manual"
-.SH NAME
-io_uring_cq_has_overflow \- returns if there are overflow entries waiting to move to the CQ ring
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "bool io_uring_cq_has_overflow(const struct io_uring *" ring ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_cq_has_overflow (3)
-function informs the application if CQ entries have overflowed and are waiting to be flushed to
-the CQ ring. For example using
-.BR io_uring_get_events (3)
-.SH NOTES
-Using this function is only valid if the ring has
-.B IORING_FEAT_NODROP
-set, as it's checking for a flag set by kernels supporting that feature. For
-really old kernels that don't support this feature, if CQE overflow is
-experienced the CQEs are lost. If that happens, the CQ ring overflow offset
-will get incremented.
-.SH RETURN VALUE
-True if there are CQ entries waiting to be flushed to the CQ ring.
-.SH SEE ALSO
-.BR io_uring_get_events (3)
diff --git a/man/io_uring_cq_has_overflow.3.md b/man/io_uring_cq_has_overflow.3.md
new file mode 100644
index 00000000..6d7f60ed
--- /dev/null
+++ b/man/io_uring_cq_has_overflow.3.md
@@ -0,0 +1,37 @@
+.\" Copyright (C) 2022 Dylan Yudaken <dylany@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: September 5, 2022
+footer: liburing-2.3
+header: liburing Manual
+section: 3
+title: io_uring_cq_has_overflow
+---
+
+# NAME
+
+io_uring_cq_has_overflow - returns if there are overflow entries waiting to move to the CQ ring
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ bool io_uring_cq_has_overflow(const struct io_uring * ring );
+
+# DESCRIPTION
+
+The **io_uring_cq_has_overflow**(3) function informs the application if CQ entries have overflowed and are waiting to be flushed to the CQ ring. For example using **io_uring_get_events**(3)
+
+# NOTES
+
+Using this function is only valid if the ring has **IORING_FEAT_NODROP** set, as it\'s checking for a flag set by kernels supporting that feature. For really old kernels that don\'t support this feature, if CQE overflow is experienced the CQEs are lost. If that happens, the CQ ring overflow offset will get incremented.
+
+# RETURN VALUE
+
+True if there are CQ entries waiting to be flushed to the CQ ring.
+
+# SEE ALSO
+
+**io_uring_get_events**(3)
diff --git a/man/io_uring_cq_ready.3 b/man/io_uring_cq_ready.3
deleted file mode 100644
index 641828a8..00000000
--- a/man/io_uring_cq_ready.3
+++ /dev/null
@@ -1,26 +0,0 @@
-.\" Copyright (C) 2022 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_cq_ready 3 "January 25, 2022" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_cq_ready \- returns number of unconsumed ready entries in the CQ ring
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "unsigned io_uring_cq_ready(const struct io_uring *" ring ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_cq_ready (3)
-function returns the number of unconsumed entries that are ready belonging to the
-.I ring
-param.
-
-.SH RETURN VALUE
-Returns the number of unconsumed ready entries in the CQ ring.
-.SH SEE ALSO
-.BR io_uring_submit (3),
-.BR io_uring_wait_cqe (3)
diff --git a/man/io_uring_cq_ready.3.md b/man/io_uring_cq_ready.3.md
new file mode 100644
index 00000000..527e2600
--- /dev/null
+++ b/man/io_uring_cq_ready.3.md
@@ -0,0 +1,33 @@
+.\" Copyright (C) 2022 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 25, 2022
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_cq_ready
+---
+
+# NAME
+
+io_uring_cq_ready - returns number of unconsumed ready entries in the CQ ring
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ unsigned io_uring_cq_ready(const struct io_uring * ring );
+
+# DESCRIPTION
+
+The **io_uring_cq_ready**(3) function returns the number of unconsumed entries that are ready belonging to the *ring* param.
+
+# RETURN VALUE
+
+Returns the number of unconsumed ready entries in the CQ ring.
+
+# SEE ALSO
+
+**io_uring_submit**(3), **io_uring_wait_cqe**(3)
diff --git a/man/io_uring_cqe_get_data.3 b/man/io_uring_cqe_get_data.3
deleted file mode 100644
index a4d2988a..00000000
--- a/man/io_uring_cqe_get_data.3
+++ /dev/null
@@ -1,53 +0,0 @@
-.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_cqe_get_data 3 "November 15, 2021" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_cqe_get_data \- get user data for completion event
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void *io_uring_cqe_get_data(struct io_uring_cqe *" cqe ");"
-.BI "
-.BI "__u64 io_uring_cqe_get_data64(struct io_uring_cqe *" cqe ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_cqe_get_data (3)
-function returns the user_data with the completion queue entry
-.IR cqe
-as a data pointer.
-
-The
-.BR io_uring_cqe_get_data64 (3)
-function returns the user_data with the completion queue entry
-.IR cqe
-as a 64-bit data value.
-
-After the caller has received a completion queue entry (CQE) with
-.BR io_uring_wait_cqe (3),
-the application can call
-.BR io_uring_cqe_get_data (3)
-or
-.BR io_uring_cqe_get_data64 (3)
-function to retrieve the
-.I user_data
-value. This requires that
-.I user_data
-has been set earlier with the function
-.BR io_uring_sqe_set_data (3)
-or
-.BR io_uring_sqe_set_data64 (3).
-
-.SH RETURN VALUE
-If the
-.I user_data
-value has been set before submitting the request, it will be returned.
-Otherwise, the return value is undefined.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_sqe_set_data (3),
-.BR io_uring_sqe_submit (3)
diff --git a/man/io_uring_cqe_get_data.3.md b/man/io_uring_cqe_get_data.3.md
new file mode 100644
index 00000000..b21739ba
--- /dev/null
+++ b/man/io_uring_cqe_get_data.3.md
@@ -0,0 +1,39 @@
+.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: November 15, 2021
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_cqe_get_data
+---
+
+# NAME
+
+io_uring_cqe_get_data - get user data for completion event
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void *io_uring_cqe_get_data(struct io_uring_cqe * cqe );
+
+ __u64 io_uring_cqe_get_data64(struct io_uring_cqe * cqe );
+
+# DESCRIPTION
+
+The **io_uring_cqe_get_data**(3) function returns the user_data with the completion queue entry *cqe* as a data pointer.
+
+The **io_uring_cqe_get_data64**(3) function returns the user_data with the completion queue entry *cqe* as a 64-bit data value.
+
+After the caller has received a completion queue entry (CQE) with **io_uring_wait_cqe**(3), the application can call **io_uring_cqe_get_data**(3) or **io_uring_cqe_get_data64**(3) function to retrieve the *user_data* value. This requires that *user_data* has been set earlier with the function **io_uring_sqe_set_data**(3) or **io_uring_sqe_set_data64**(3).
+
+# RETURN VALUE
+
+If the *user_data* value has been set before submitting the request, it will be returned. Otherwise, the return value is undefined.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_sqe_set_data**(3), **io_uring_sqe_submit**(3)
diff --git a/man/io_uring_cqe_get_data64.3 b/man/io_uring_cqe_get_data64.3
deleted file mode 120000
index 51991c2a..00000000
--- a/man/io_uring_cqe_get_data64.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_cqe_get_data.3
\ No newline at end of file
diff --git a/man/io_uring_cqe_nr.3 b/man/io_uring_cqe_nr.3
deleted file mode 100644
index 75568083..00000000
--- a/man/io_uring_cqe_nr.3
+++ /dev/null
@@ -1,35 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_cqe_nr 3 "January 18, 2025" "liburing-2.12" "liburing Manual"
-.SH NAME
-io_uring_cqe_nr \- return the number of CQ ring slots consumed by a CQE
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "unsigned io_uring_cqe_nr(const struct io_uring_cqe *" cqe ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_cqe_nr (3)
-function returns the number of CQ ring slots consumed by
-.IR cqe .
-For normal 16-byte CQEs, this returns 1. For 32-byte CQEs (when
-.B IORING_CQE_F_32
-is set in the CQE flags), this returns 2.
-
-This function is useful when advancing the CQ ring with
-.BR io_uring_cq_advance (3)
-on rings that use
-.B IORING_SETUP_CQE_MIXED
-where both 16-byte and 32-byte CQEs may be present.
-
-.SH RETURN VALUE
-Returns 1 for normal CQEs, or 2 for 32-byte CQEs.
-.SH SEE ALSO
-.BR io_uring_cq_advance (3),
-.BR io_uring_cqe_seen (3),
-.BR io_uring_setup (2)
diff --git a/man/io_uring_cqe_nr.3.md b/man/io_uring_cqe_nr.3.md
new file mode 100644
index 00000000..13856981
--- /dev/null
+++ b/man/io_uring_cqe_nr.3.md
@@ -0,0 +1,35 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: liburing-2.12
+header: liburing Manual
+section: 3
+title: io_uring_cqe_nr
+---
+
+# NAME
+
+io_uring_cqe_nr - return the number of CQ ring slots consumed by a CQE
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ unsigned io_uring_cqe_nr(const struct io_uring_cqe * cqe );
+
+# DESCRIPTION
+
+The **io_uring_cqe_nr**(3) function returns the number of CQ ring slots consumed by *cqe*. For normal 16-byte CQEs, this returns 1. For 32-byte CQEs (when **IORING_CQE_F_32** is set in the CQE flags), this returns 2.
+
+This function is useful when advancing the CQ ring with **io_uring_cq_advance**(3) on rings that use **IORING_SETUP_CQE_MIXED** where both 16-byte and 32-byte CQEs may be present.
+
+# RETURN VALUE
+
+Returns 1 for normal CQEs, or 2 for 32-byte CQEs.
+
+# SEE ALSO
+
+**io_uring_cq_advance**(3), **io_uring_cqe_seen**(3), **io_uring_setup**(2)
diff --git a/man/io_uring_cqe_seen.3 b/man/io_uring_cqe_seen.3
deleted file mode 100644
index 5c9cd4e5..00000000
--- a/man/io_uring_cqe_seen.3
+++ /dev/null
@@ -1,41 +0,0 @@
-.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_cqe_seen 3 "November 15, 2021" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_cqe_seen \- mark io_uring completion event as consumed
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_cqe_seen(struct io_uring *" ring ","
-.BI " struct io_uring_cqe *" cqe ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_cqe_seen (3)
-function marks the IO completion
-.I cqe
-belonging to the
-.I ring
-param as consumed.
-
-After the caller has submitted a request with
-.BR io_uring_submit (3),
-the application can retrieve the completion with
-.BR io_uring_wait_cqe (3),
-.BR io_uring_peek_cqe (3),
-or any of the other CQE retrieval helpers, and mark it as consumed with
-.BR io_uring_cqe_seen (3).
-
-Completions must be marked as completed so their slot can get reused.
-.SH RETURN VALUE
-None
-.SH SEE ALSO
-.BR io_uring_submit (3),
-.BR io_uring_peek_cqe (3),
-.BR io_uring_wait_cqe (3),
-.BR io_uring_wait_cqes (3),
-.BR io_uring_wait_cqe_timeout (3)
diff --git a/man/io_uring_cqe_seen.3.md b/man/io_uring_cqe_seen.3.md
new file mode 100644
index 00000000..8dbb6853
--- /dev/null
+++ b/man/io_uring_cqe_seen.3.md
@@ -0,0 +1,38 @@
+.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: November 15, 2021
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_cqe_seen
+---
+
+# NAME
+
+io_uring_cqe_seen - mark io_uring completion event as consumed
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_cqe_seen(struct io_uring * ring ,
+ struct io_uring_cqe * cqe );
+
+# DESCRIPTION
+
+The **io_uring_cqe_seen**(3) function marks the IO completion *cqe* belonging to the *ring* param as consumed.
+
+After the caller has submitted a request with **io_uring_submit**(3), the application can retrieve the completion with **io_uring_wait_cqe**(3), **io_uring_peek_cqe**(3), or any of the other CQE retrieval helpers, and mark it as consumed with **io_uring_cqe_seen**(3).
+
+Completions must be marked as completed so their slot can get reused.
+
+# RETURN VALUE
+
+None
+
+# SEE ALSO
+
+**io_uring_submit**(3), **io_uring_peek_cqe**(3), **io_uring_wait_cqe**(3), **io_uring_wait_cqes**(3), **io_uring_wait_cqe_timeout**(3)
diff --git a/man/io_uring_enable_rings.3 b/man/io_uring_enable_rings.3
deleted file mode 100644
index a01713be..00000000
--- a/man/io_uring_enable_rings.3
+++ /dev/null
@@ -1,40 +0,0 @@
-.\" Copyright (C) 2023 nick black <dankamongmen@gmail.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_enable_rings 3 "July 26, 2024" "liburing-2.7" "liburing Manual"
-.SH NAME
-io_uring_enable_rings \- enable a disabled ring
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_enable_rings(struct io_uring *" ring ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_enable_rings (3)
-function enables a ring after having created it with the
-.B IORING_SETUP_R_DISABLED
-flag to
-.BR io_uring_queue_init (3)
-
-It is not possible to submit work to such a ring until this
-function has been successfully called.
-
-.SH RETURN VALUE
-.BR io_uring_enable_rings (3)
-returns 0 on success. It otherwise returns a negative error code.
-It does not write to
-.BR errno .
-
-.SH ERRORS
-.TP
-.B EBADFD
-The ring was not disabled.
-
-.SH SEE ALSO
-.BR io_uring_queue_init (3),
-.BR io_uring_register (2),
-.BR io_uring_setup (2)
diff --git a/man/io_uring_enable_rings.3.md b/man/io_uring_enable_rings.3.md
new file mode 100644
index 00000000..a1cc0dc5
--- /dev/null
+++ b/man/io_uring_enable_rings.3.md
@@ -0,0 +1,41 @@
+.\" Copyright (C) 2023 nick black <dankamongmen@gmail.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: July 26, 2024
+footer: liburing-2.7
+header: liburing Manual
+section: 3
+title: io_uring_enable_rings
+---
+
+# NAME
+
+io_uring_enable_rings - enable a disabled ring
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_enable_rings(struct io_uring * ring );
+
+# DESCRIPTION
+
+The **io_uring_enable_rings**(3) function enables a ring after having created it with the **IORING_SETUP_R_DISABLED** flag to **io_uring_queue_init**(3)
+
+It is not possible to submit work to such a ring until this function has been successfully called.
+
+# RETURN VALUE
+
+**io_uring_enable_rings**(3) returns 0 on success. It otherwise returns a negative error code. It does not write to **errno**.
+
+# ERRORS
+
+**EBADFD**
+
+: The ring was not disabled.
+
+# SEE ALSO
+
+**io_uring_queue_init**(3), **io_uring_register**(2), **io_uring_setup**(2)
diff --git a/man/io_uring_enter.2 b/man/io_uring_enter.2
deleted file mode 100644
index 7b99335e..00000000
--- a/man/io_uring_enter.2
+++ /dev/null
@@ -1,2208 +0,0 @@
-.\" Copyright (C) 2019 Jens Axboe <axboe@kernel.dk>
-.\" Copyright (C) 2019 Red Hat, Inc.
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_enter 2 "January 22, 2019" "Linux" "Linux Programmer's Manual"
-.SH NAME
-io_uring_enter \- initiate and/or complete asynchronous I/O
-.SH SYNOPSIS
-.nf
-.BR "#include <liburing.h>"
-.PP
-.BI "int io_uring_enter(unsigned int " fd ", unsigned int " to_submit ,
-.BI " unsigned int " min_complete ", unsigned int " flags ,
-.BI " sigset_t *" sig );
-.PP
-.BI "int io_uring_enter2(unsigned int " fd ", unsigned int " to_submit ,
-.BI " unsigned int " min_complete ", unsigned int " flags ,
-.BI " void *" arg ", size_t " sz );
-.fi
-.PP
-.SH DESCRIPTION
-.PP
-.BR io_uring_enter (2)
-is used to initiate and complete I/O using the shared submission and
-completion queues setup by a call to
-.BR io_uring_setup (2).
-A single call can both submit new I/O and wait for completions of I/O
-initiated by this call or previous calls to
-.BR io_uring_enter (2).
-
-.I fd
-is the file descriptor returned by
-.BR io_uring_setup (2).
-.I to_submit
-specifies the number of I/Os to submit from the submission queue.
-.I flags
-is a bitmask of the following values:
-.TP
-.B IORING_ENTER_GETEVENTS
-If this flag is set, then the system call will wait for the specified
-number of events in
-.I min_complete
-before returning. This flag can be set along with
-.I to_submit
-to both submit and complete events in a single system call.
-If this flag is set either the flag
-.B IORING_SETUP_DEFER_TASKRUN
-must not be set or the thread issuing the syscall must be the thread that
-created the io_uring associated with
-.I fd,
-or be the thread that enabled the ring originally created with
-.B IORING_SETUP_R_DISABLED
-via
-.BR io_uring_register (2)
-or
-.BR io_uring_enable_rings (3).
-.TP
-.B IORING_ENTER_SQ_WAKEUP
-If the ring has been created with
-.B IORING_SETUP_SQPOLL,
-then this flag asks the kernel to wakeup the SQ kernel thread to submit IO.
-.TP
-.B IORING_ENTER_SQ_WAIT
-If the ring has been created with
-.B IORING_SETUP_SQPOLL,
-then the application has no real insight into when the SQ kernel thread has
-consumed entries from the SQ ring. This can lead to a situation where the
-application can no longer get a free SQE entry to submit, without knowing
-when one will become available as the SQ kernel thread consumes them. If
-the system call is used with this flag set, then it will wait until at least
-one entry is free in the SQ ring.
-.TP
-.B IORING_ENTER_EXT_ARG
-By default,
-.I arg
-is a
-.I sigset_t
-pointer. If
-.B IORING_ENTER_EXT_ARG
-is set (supported since kernel 5.11), then
-.I arg
-is instead a pointer to a
-.I struct io_uring_getevents_arg
-and
-.I argsz
-must be set to the size of this structure. The definition is as follows:
-
-.nf
-.BI "struct io_uring_getevents_arg {
-.BI " __u64 sigmask;
-.BI " __u32 sigmask_sz;
-.BI " __u32 pad;
-.BI " __u64 ts;
-.BI "};
-.fi
-
-which allows passing in both a signal mask as well as pointer to a
-.I struct __kernel_timespec
-timeout value. If
-.I ts
-is set to a valid pointer, then this time value indicates the timeout for
-waiting on events. If an application is waiting on events and wishes to
-stop waiting after a specified amount of time, then this can be accomplished
-directly in version 5.11 and newer by using this feature.
-.TP
-.B IORING_ENTER_REGISTERED_RING
-If the ring file descriptor has been registered through use of
-.BR IORING_REGISTER_RING_FDS ,
-then setting this flag will tell the kernel that the
-.I ring_fd
-passed in is the registered ring offset rather than a normal file descriptor.
-
-.TP
-.B IORING_ENTER_ABS_TIMER
-
-When this flag is set, the timeout argument passed in
-.I struct io_uring_getevents_arg
-will be interpreted as an absolute
-time of the registered clock (see
-.BR IORING_REGISTER_CLOCK)
-until which the waiting should end.
-
-Available since 6.12
-
-.TP
-.B IORING_ENTER_EXT_ARG_REG
-
-When this flag is set,
-.IR arg
-is not a pointer to a
-.IR struct io_uring_getevents_arg ,
-but merely an offset into an area of wait regions previously registered with
-.BR io_uring_register (2)
-using the
-.B IORING_REGISTER_MEM_REGION
-operation.
-
-Available since 6.13
-
-.TP
-.B IORING_ENTER_NO_IOWAIT
-When this flag is set, the system call will not mark the waiting task as being
-in iowait if it is sleeping waiting on events and there are pending requests.
-This is useful if iowait isn't expected when waiting for events. It can also
-prevent extra power usage by allowing the CPU to enter lower sleep states.
-This flag is only available if the kernel supports the
-.B IORING_FEAT_NO_IOWAIT
-feature.
-
-Available since 6.15.
-
-.PP
-.PP
-If the io_uring instance was configured for polling, by specifying
-.B IORING_SETUP_IOPOLL
-in the call to
-.BR io_uring_setup (2),
-then min_complete has a slightly different meaning. Passing a value
-of 0 instructs the kernel to return any events which are already complete,
-without blocking. If
-.I min_complete
-is a non-zero value, the kernel will still return immediately if any
-completion events are available. If no event completions are
-available, then the call will poll either until one or more
-completions become available, or until the process has exceeded its
-scheduler time slice.
-
-Note that, for interrupt driven I/O (where
-.B IORING_SETUP_IOPOLL
-was not specified in the call to
-.BR io_uring_setup (2)),
-an application may check the completion queue for event completions
-without entering the kernel at all.
-.PP
-When the system call returns that a certain amount of SQEs have been
-consumed and submitted, it's safe to reuse SQE entries in the ring. This is
-true even if the actual IO submission had to be punted to async context,
-which means that the SQE may in fact not have been submitted yet. If the
-kernel requires later use of a particular SQE entry, it will have made a
-private copy of it.
-
-.I sig
-is a pointer to a signal mask (see
-.BR sigprocmask (2));
-if
-.I sig
-is not NULL,
-.BR io_uring_enter (2)
-first replaces the current signal mask by the one pointed to by
-.IR sig ,
-then waits for events to become available in the completion queue, and
-then restores the original signal mask. The following
-.BR io_uring_enter (2)
-call:
-.PP
-.in +4n
-.EX
-ret = io_uring_enter(fd, 0, 1, IORING_ENTER_GETEVENTS, &sig);
-.EE
-.in
-.PP
-is equivalent to
-.I atomically
-executing the following calls:
-.PP
-.in +4n
-.EX
-pthread_sigmask(SIG_SETMASK, &sig, &orig);
-ret = io_uring_enter(fd, 0, 1, IORING_ENTER_GETEVENTS, NULL);
-pthread_sigmask(SIG_SETMASK, &orig, NULL);
-.EE
-.in
-.PP
-See the description of
-.BR pselect (2)
-for an explanation of why the
-.I sig
-parameter is necessary.
-
-Submission queue entries are represented using the following data
-structure:
-.PP
-.in +4n
-.EX
-/*
- * IO submission data structure (Submission Queue Entry)
- */
-struct io_uring_sqe {
- __u8 opcode; /* type of operation for this sqe */
- __u8 flags; /* IOSQE_ flags */
- __u16 ioprio; /* ioprio for the request */
- __s32 fd; /* file descriptor to do IO on */
- union {
- __u64 off; /* offset into file */
- __u64 addr2;
- struct {
- __u32 cmd_op;
- __u32 __pad1;
- };
- };
- union {
- __u64 addr; /* pointer to buffer or iovecs */
- __u64 splice_off_in;
- struct {
- __u32 level;
- __u32 optname;
- };
- };
- __u32 len; /* buffer size or number of iovecs */
- union {
- __kernel_rwf_t rw_flags;
- __u32 fsync_flags;
- __u16 poll_events; /* compatibility */
- __u32 poll32_events; /* word-reversed for BE */
- __u32 sync_range_flags;
- __u32 msg_flags;
- __u32 timeout_flags;
- __u32 accept_flags;
- __u32 cancel_flags;
- __u32 open_flags;
- __u32 statx_flags;
- __u32 fadvise_advice;
- __u32 splice_flags;
- __u32 rename_flags;
- __u32 unlink_flags;
- __u32 hardlink_flags;
- __u32 xattr_flags;
- __u32 msg_ring_flags;
- __u32 uring_cmd_flags;
- __u32 waitid_flags;
- __u32 futex_flags;
- __u32 install_fd_flags;
- __u32 nop_flags;
- };
- __u64 user_data; /* data to be passed back at completion time */
- /* pack this to avoid bogus arm OABI complaints */
- union {
- /* index into fixed buffers, if used */
- __u16 buf_index;
- /* for grouped buffer selection */
- __u16 buf_group;
- } __attribute__((packed));
- /* personality to use, if used */
- __u16 personality;
- union {
- __s32 splice_fd_in;
- __u32 file_index;
- __u32 optlen;
- struct {
- __u16 addr_len;
- __u16 __pad3[1];
- };
- };
- union {
- struct {
- __u64 addr3;
- __u64 __pad2[1];
- };
- __u64 optval;
- /*
- * If the ring is initialized with IORING_SETUP_SQE128, then
- * this field is used for 80 bytes of arbitrary command data
- */
- __u8 cmd[0];
- };
-};
-.EE
-.in
-.PP
-The
-.I opcode
-describes the operation to be performed. It can be one of:
-.TP
-.B IORING_OP_NOP
-Do not perform any I/O. This is useful for testing the performance of
-the io_uring implementation itself.
-.TP
-.B IORING_OP_READV
-.TP
-.B IORING_OP_WRITEV
-Vectored read and write operations, similar to
-.BR preadv2 (2)
-and
-.BR pwritev2 (2).
-If the file is not seekable,
-.I off
-must be set to zero or -1.
-
-.TP
-.B IORING_OP_READ_FIXED
-.TP
-.B IORING_OP_WRITE_FIXED
-Read from or write to pre-mapped buffers. See
-.BR io_uring_register (2)
-for details on how to setup a context for fixed reads and writes.
-
-.TP
-.B IORING_OP_FSYNC
-File sync. See also
-.BR fsync (2).
-Optionally
-.I off
-and
-.I len
-can be used to specify a range within the file to be synced rather than
-syncing the entire file, which is the default behavior.
-Note that, while I/O is initiated in the order in which it appears in
-the submission queue, completions are unordered. For example, an
-application which places a write I/O followed by an fsync in the
-submission queue cannot expect the fsync to apply to the write. The
-two operations execute in parallel, so the fsync may complete before
-the write is issued to the storage. The same is also true for
-previously issued writes that have not completed prior to the fsync.
-To enforce ordering one may utilize linked SQEs,
-.B IOSQE_IO_DRAIN
-or wait for the arrival of CQEs of requests which have to be ordered
-before a given request before submitting its SQE.
-
-.TP
-.B IORING_OP_POLL_ADD
-Poll the
-.I fd
-specified in the submission queue entry for the events
-specified in the
-.I poll_events
-field. Unlike poll or epoll without
-.BR EPOLLONESHOT ,
-by default this interface always works in one shot mode. That is, once the poll
-operation is completed, it will have to be resubmitted.
-
-If
-.B IORING_POLL_ADD_MULTI
-is set in the SQE
-.I len
-field, then the poll will work in multi shot mode instead. That means it'll
-repatedly trigger when the requested event becomes true, and hence multiple
-CQEs can be generated from this single SQE. The CQE
-.I flags
-field will have
-.B IORING_CQE_F_MORE
-set on completion if the application should expect further CQE entries from
-the original request. If this flag isn't set on completion, then the poll
-request has been terminated and no further events will be generated. This mode
-is available since 5.13.
-
-This command works like
-an async
-.BR poll(2)
-and the completion event result is the returned mask of events.
-
-Without
-.B IORING_POLL_ADD_MULTI
-and the initial poll operation with
-.B IORING_POLL_ADD_MULTI
-the operation is level triggered, i.e. if there is data ready or events
-pending etc. at the time of submission a corresponding CQE will be posted.
-Potential further completions beyond the first caused by a
-.B IORING_POLL_ADD_MULTI
-are edge triggered.
-
-.TP
-.B IORING_OP_POLL_REMOVE
-Remove or update an existing poll request. If found, the
-.I res
-field of the
-.I "struct io_uring_cqe"
-will contain 0. If not found,
-.I res
-will contain
-.B -ENOENT,
-or
-.B -EALREADY
-if the poll request was in the process of completing already.
-
-If
-.B IORING_POLL_UPDATE_EVENTS
-is set in the SQE
-.I len
-field, then the request will update an existing poll request with the mask of
-events passed in with this request. The lookup is based on the
-.I user_data
-field of the original SQE submitted, and this values is passed in the
-.I addr
-field of the SQE.
-If
-.B IORING_POLL_UPDATE_USER_DATA
-is set in the SQE
-.I len
-field, then the request will update the
-.I user_data
-of an existing poll request based on the value passed in the
-.I off
-field. Updating an existing poll is available since 5.13.
-
-.TP
-.B IORING_OP_EPOLL_CTL
-Add, remove or modify entries in the interest list of
-.BR epoll (7).
-See
-.BR epoll_ctl (2)
-for details of the system call.
-.I fd
-holds the file descriptor that represents the epoll instance,
-.I off
-holds the file descriptor to add, remove or modify,
-.I len
-holds the operation (
-.BR EPOLL_CTL_ADD ,
-.BR EPOLL_CTL_DEL ,
-.BR EPOLL_CTL_MOD )
-to perform and,
-.I addr
-holds a pointer to the
-.I epoll_event
-structure. Available since 5.6.
-
-.TP
-.B IORING_OP_SYNC_FILE_RANGE
-Issue the equivalent of a \fBsync_file_range\fR (2) on the file descriptor. The
-.I fd
-field is the file descriptor to sync, the
-.I off
-field holds the offset in bytes, the
-.I len
-field holds the length in bytes, and the
-.I sync_range_flags
-field holds the flags for the command. See also
-.BR sync_file_range (2)
-for the general description of the related system call. Available since 5.2.
-
-.TP
-.B IORING_OP_SENDMSG
-Issue the equivalent of a
-.BR sendmsg(2)
-system call.
-.I fd
-must be set to the socket file descriptor,
-.I addr
-must contain a pointer to the msghdr structure, and
-.I msg_flags
-holds the flags associated with the system call. See also
-.BR sendmsg (2)
-for the general description of the related system call. Available since 5.3.
-
-This command also supports the following modifiers in
-.I ioprio:
-
-.PP
-.in +12
-.B IORING_RECVSEND_POLL_FIRST
-If set, io_uring will assume the socket is currently full and attempting to
-send data will be unsuccessful. For this case, io_uring will arm internal
-poll and trigger a send of the data when there is enough space available.
-This initial send attempt can be wasteful for the case where the socket
-is expected to be full, setting this flag will bypass the initial send
-attempt and go straight to arming poll. If poll does indicate that data can
-be sent, the operation will proceed.
-.EE
-.in
-.PP
-
-.TP
-.B IORING_OP_RECVMSG
-Works just like IORING_OP_SENDMSG, except for
-.BR recvmsg(2)
-instead. See the description of IORING_OP_SENDMSG. Available since 5.3.
-
-This command also supports the following modifiers in
-.I ioprio:
-
-.PP
-.in +12
-.B IORING_RECVSEND_POLL_FIRST
-If set, io_uring will assume the socket is currently empty and attempting to
-receive data will be unsuccessful. For this case, io_uring will arm internal
-poll and trigger a receive of the data when the socket has data to be read.
-This initial receive attempt can be wasteful for the case where the socket
-is expected to be empty, setting this flag will bypass the initial receive
-attempt and go straight to arming poll. If poll does indicate that data is
-ready to be received, the operation will proceed.
-.EE
-.in
-.PP
-
-.TP
-.B IORING_OP_SEND
-Issue the equivalent of a
-.BR send(2)
-system call.
-.I fd
-must be set to the socket file descriptor,
-.I addr
-must contain a pointer to the buffer,
-.I len
-denotes the length of the buffer to send, and
-.I msg_flags
-holds the flags associated with the system call. See also
-.BR send(2)
-for the general description of the related system call. Available since 5.6.
-
-This command also supports the following modifiers in
-.I ioprio:
-
-.PP
-.in +12
-.B IORING_RECVSEND_POLL_FIRST
-If set, io_uring will assume the socket is currently full and attempting to
-send data will be unsuccessful. For this case, io_uring will arm internal
-poll and trigger a send of the data when there is enough space available.
-This initial send attempt can be wasteful for the case where the socket
-is expected to be full, setting this flag will bypass the initial send
-attempt and go straight to arming poll. If poll does indicate that data can
-be sent, the operation will proceed.
-.EE
-.in
-.PP
-
-.TP
-.B IORING_OP_RECV
-Works just like IORING_OP_SEND, except for
-.BR recv(2)
-instead. See the description of IORING_OP_SEND. Available since 5.6.
-
-This command also supports the following modifiers in
-.I ioprio:
-
-.PP
-.in +12
-.B IORING_RECVSEND_POLL_FIRST
-If set, io_uring will assume the socket is currently empty and attempting to
-receive data will be unsuccessful. For this case, io_uring will arm internal
-poll and trigger a receive of the data when the socket has data to be read.
-This initial receive attempt can be wasteful for the case where the socket
-is expected to be empty, setting this flag will bypass the initial receive
-attempt and go straight to arming poll. If poll does indicate that data is
-ready to be received, the operation will proceed.
-.EE
-.in
-.PP
-
-.TP
-.B IORING_OP_TIMEOUT
-This command will register a timeout operation. The
-.I addr
-field must contain a pointer to a struct __kernel_timespec structure,
-.I len
-must contain 1 to signify one __kernel_timespec structure,
-.I timeout_flags
-may contain
-.B IORING_TIMEOUT_ABS
-for an absolute timeout value, or 0 for a relative timeout.
-.I off
-may contain a completion event count. A timeout
-will trigger a wakeup event on the completion ring for anyone waiting for
-events. A timeout condition is met when either the specified timeout expires,
-or the specified number of events have completed. Either condition will
-trigger the event. If set to 0, completed events are not counted, which
-effectively acts like a timer. io_uring timeouts use the
-.B CLOCK_MONOTONIC
-as the default clock source. The request will complete with
-.B -ETIME
-if the timeout got completed through expiration of the timer, or
-.I 0
-if the timeout got completed through requests completing on their own. If
-the timeout was canceled before it expired, the request will complete with
-.B -ECANCELED.
-Available since 5.4.
-
-Since 5.15, this command also supports the following modifiers in
-.I timeout_flags:
-
-.PP
-.in +12
-.B IORING_TIMEOUT_BOOTTIME
-If set, then the clocksource used is
-.B CLOCK_BOOTTIME
-instead of
-.BR CLOCK_MONOTONIC .
-This clocksource differs in that it includes time elapsed if the system was
-suspend while having a timeout request in-flight.
-
-.B IORING_TIMEOUT_REALTIME
-If set, then the clocksource used is
-.B CLOCK_REALTIME
-instead of
-.BR CLOCK_MONOTONIC .
-.EE
-.in
-.PP
-
-.PP
-.in +7
-Since 5.16,
-.B IORING_TIMEOUT_ETIME_SUCCESS
-can be set in
-.IR timeout_flags ,
-which will result in the expiration of the timer and subsequent completion
-with
-.B -ETIME
-not being interpreted as an error. This is mostly relevant for linked SQEs, as
-subsequent requests in the chain would not get canceled by the timeout, if
-this flag is set. See
-.B IOSQE_IO_LINK
-for more details on linked SQEs.
-.in
-.PP
-
-.PP
-.in +7
-Since 6.4,
-.B IORING_TIMEOUT_MULTISHOT
-can be set in
-.IR timeout_flags ,
-which will result in the timer producing multiple consecutive completions
-like other multi shot operations e.g.
-.B IORING_OP_READ_MULTISHOT
-or
-.BR IORING_POLL_ADD_MULTI .
-.I off
-must be set to the amount of desired completions.
-.B IORING_TIMEOUT_MULTISHOT
-must not be used with
-.BR IORING_TIMEOUT_ABS .
-.in
-.PP
-
-.PP
-.in +7
-Since kernel 7.1,
-.B IORING_TIMEOUT_IMMEDIATE_ARG
-can be set in
-.IR timeout_flags ,
-which causes the
-.I addr
-field to be interpreted as a timeout value in nanoseconds rather than a
-pointer to a
-.B struct __kernel_timespec.
-This avoids the need to keep a timespec structure valid in user memory until
-the request is submitted.
-.in
-.PP
-
-.TP
-.B IORING_OP_TIMEOUT_REMOVE
-If
-.I timeout_flags
-are zero, then it attempts to remove an existing timeout operation.
-.I addr
-must contain the
-.I user_data
-field of the previously issued timeout operation. If the specified timeout
-request is found and canceled successfully, this request will terminate
-with a result value of
-.I 0
-If the timeout request was found but expiration was already in progress,
-this request will terminate with a result value of
-.B -EBUSY
-If the timeout request wasn't found, the request will terminate with a result
-value of
-.B -ENOENT
-Available since 5.5.
-
-If
-.I timeout_flags
-contain
-.BR IORING_TIMEOUT_UPDATE ,
-instead of removing an existing operation, it updates it.
-.I addr
-and return values are same as before.
-.I addr2
-field must contain a pointer to a struct __kernel_timespec structure.
-.I timeout_flags
-may also contain IORING_TIMEOUT_ABS, in which case the value given is an
-absolute one, not a relative one.
-Available since 5.11.
-
-.TP
-.B IORING_OP_ACCEPT
-Issue the equivalent of an
-.BR accept4 (2)
-system call.
-.I fd
-must be set to the socket file descriptor,
-.I addr
-must contain the pointer to the sockaddr structure, and
-.I addr2
-must contain a pointer to the socklen_t addrlen field. Flags can be passed using
-the
-.I accept_flags
-field. See also
-.BR accept4 (2)
-for the general description of the related system call. Available since 5.5.
-
-If the
-.I file_index
-field is set to a positive number, the file won't be installed into the
-normal file table as usual but will be placed into the fixed file table at index
-.I file_index
-- 1.
-In this case, instead of returning a file descriptor, the result will contain
-either 0 on success or an error. If the index points to a valid empty slot, the
-installation is guaranteed to not fail. If there is already a file in the slot,
-it will be replaced, similar to
-.B IORING_OP_FILES_UPDATE.
-Please note that only io_uring has access to such files and no other syscall
-can use them. See
-.B IOSQE_FIXED_FILE
-and
-.BR IORING_REGISTER_FILES .
-
-Available since 5.5.
-
-.TP
-.B IORING_OP_ASYNC_CANCEL
-Attempt to cancel an already issued request.
-.I addr
-must contain the
-.I user_data
-field of the request that should be canceled. The cancelation request will
-complete with one of the following results codes. If found, the
-.I res
-field of the cqe will contain 0. If not found,
-.I res
-will contain
-.BR -ENOENT .
-If found and attempted canceled, the
-.I res
-field will contain
-.BR -EALREADY .
-In this case, the request may or may not
-terminate. In general, requests that are interruptible (like socket IO) will
-get canceled, while disk IO requests cannot be canceled if already started.
-Available since 5.5.
-
-.TP
-.B IORING_OP_LINK_TIMEOUT
-This request must be linked with another request through
-.B IOSQE_IO_LINK
-which is described below. Unlike
-.BR IORING_OP_TIMEOUT ,
-.B IORING_OP_LINK_TIMEOUT
-acts on the linked request, not the completion queue. The format of the command
-is otherwise like
-.BR IORING_OP_TIMEOUT ,
-except there's no completion event count as it's tied to a specific request.
-If used, the timeout specified in the command will cancel the linked command,
-unless the linked command completes before the timeout. The timeout will
-complete with
-.B -ETIME
-if the timer expired and the linked request was attempted canceled, or
-.B -ECANCELED
-if the timer got canceled because of completion of the linked request. Like
-.B IORING_OP_TIMEOUT
-the clock source used is
-.B CLOCK_MONOTONIC
-Available since 5.5.
-
-
-.TP
-.B IORING_OP_CONNECT
-Issue the equivalent of a
-.BR connect (2)
-system call.
-.I fd
-must be set to the socket file descriptor,
-.I addr
-must contain the const pointer to the sockaddr structure, and
-.I off
-must contain the socklen_t addrlen field. See also
-.BR connect (2)
-for the general description of the related system call. Available since 5.5.
-
-.TP
-.B IORING_OP_FALLOCATE
-Issue the equivalent of a
-.BR fallocate (2)
-system call.
-.I fd
-must be set to the file descriptor,
-.I len
-must contain the mode associated with the operation,
-.I off
-must contain the offset on which to operate, and
-.I addr
-must contain the length. See also
-.BR fallocate (2)
-for the general description of the related system call. Available since 5.6.
-
-.TP
-.B IORING_OP_FADVISE
-Issue the equivalent of a
-.BR posix_fadvise (2)
-system call.
-.I fd
-must be set to the file descriptor,
-.I off
-must contain the offset on which to operate,
-.I len
-must contain the length, and
-.I fadvise_advice
-must contain the advice associated with the operation. See also
-.BR posix_fadvise (2)
-for the general description of the related system call. Available since 5.6.
-
-.TP
-.B IORING_OP_MADVISE
-Issue the equivalent of a
-.BR madvise (2)
-system call.
-.I addr
-must contain the address to operate on,
-.I len
-must contain the length on which to operate,
-and
-.I fadvise_advice
-must contain the advice associated with the operation. See also
-.BR madvise (2)
-for the general description of the related system call. Available since 5.6.
-
-.TP
-.B IORING_OP_OPENAT
-Issue the equivalent of a
-.BR openat (2)
-system call.
-.I fd
-is the
-.I dirfd
-argument,
-.I addr
-must contain a pointer to the
-.I *pathname
-argument,
-.I open_flags
-should contain any flags passed in, and
-.I len
-is access mode of the file. See also
-.BR openat (2)
-for the general description of the related system call. Available since 5.6.
-
-If the
-.I file_index
-field is set to a positive number, the file won't be installed into the
-normal file table as usual but will be placed into the fixed file table at index
-.I file_index - 1.
-In this case, instead of returning a file descriptor, the result will contain
-either 0 on success or an error. If the index points to a valid empty slot, the
-installation is guaranteed to not fail. If there is already a file in the slot,
-it will be replaced, similar to
-.B IORING_OP_FILES_UPDATE.
-Please note that only io_uring has access to such files and no other syscall
-can use them. See
-.B IOSQE_FIXED_FILE
-and
-.BR IORING_REGISTER_FILES .
-
-Available since 5.15.
-
-.TP
-.B IORING_OP_OPENAT2
-Issue the equivalent of a
-.BR openat2 (2)
-system call.
-.I fd
-is the
-.I dirfd
-argument,
-.I addr
-must contain a pointer to the
-.I *pathname
-argument,
-.I len
-should contain the size of the open_how structure, and
-.I off
-should be set to the address of the open_how structure. See also
-.BR openat2 (2)
-for the general description of the related system call. Available since 5.6.
-
-If the
-.I file_index
-field is set to a positive number, the file won't be installed into the
-normal file table as usual but will be placed into the fixed file table at index
-.I file_index - 1.
-In this case, instead of returning a file descriptor, the result will contain
-either 0 on success or an error. If the index points to a valid empty slot, the
-installation is guaranteed to not fail. If there is already a file in the slot,
-it will be replaced, similar to
-.BR IORING_OP_FILES_UPDATE .
-Please note that only io_uring has access to such files and no other syscall
-can use them. See
-.B IOSQE_FIXED_FILE
-and
-.BR IORING_REGISTER_FILES .
-
-Available since 5.15.
-
-.TP
-.B IORING_OP_CLOSE
-Issue the equivalent of a
-.BR close (2)
-system call.
-.I fd
-is the file descriptor to be closed. See also
-.BR close (2)
-for the general description of the related system call. Available since 5.6.
-If the
-.I file_index
-field is set to a positive number, this command can be used to close files
-that were direct opened through
-.BR IORING_OP_OPENAT ,
-.BR IORING_OP_OPENAT2 ,
-or
-.B IORING_OP_ACCEPT
-using the io_uring specific direct descriptors. Note that only one of the
-descriptor fields may be set. The direct close feature is available since
-the 5.15 kernel, where direct descriptors were introduced.
-
-.TP
-.B IORING_OP_STATX
-Issue the equivalent of a
-.BR statx (2)
-system call.
-.I fd
-is the
-.I dirfd
-argument,
-.I addr
-must contain a pointer to the
-.I *pathname
-string,
-.I statx_flags
-is the
-.I flags
-argument,
-.I len
-should be the
-.I mask
-argument, and
-.I off
-must contain a pointer to the
-.I statxbuf
-to be filled in. See also
-.BR statx (2)
-for the general description of the related system call. Available since 5.6.
-
-.TP
-.B IORING_OP_READ
-.TP
-.B IORING_OP_WRITE
-Issue the equivalent of a
-.BR pread (2)
-or
-.BR pwrite (2)
-system call.
-.I fd
-is the file descriptor to be operated on,
-.I addr
-contains the buffer in question,
-.I len
-contains the length of the IO operation, and
-.I offs
-contains the read or write offset. If
-.I fd
-does not refer to a seekable file,
-.I off
-must be set to zero or -1. If
-.I offs
-is set to
-.B -1
-, the offset will use (and advance) the file position, like the
-.BR read (2)
-and
-.BR write (2)
-system calls. These are non-vectored versions of the
-.B IORING_OP_READV
-and
-.B IORING_OP_WRITEV
-opcodes. See also
-.BR read (2)
-and
-.BR write (2)
-for the general description of the related system call. Available since 5.6.
-
-.TP
-.B IORING_OP_SPLICE
-Issue the equivalent of a
-.BR splice (2)
-system call.
-.I splice_fd_in
-is the file descriptor to read from,
-.I splice_off_in
-is an offset to read from,
-.I fd
-is the file descriptor to write to,
-.I off
-is an offset from which to start writing to. A sentinel value of
-.B -1
-is used to pass the equivalent of a NULL for the offsets to
-.BR splice (2).
-.I len
-contains the number of bytes to copy.
-.I splice_flags
-contains a bit mask for the flag field associated with the system call.
-Please note that one of the file descriptors must refer to a pipe.
-See also
-.BR splice (2)
-for the general description of the related system call. Available since 5.7.
-
-.TP
-.B IORING_OP_TEE
-Issue the equivalent of a
-.BR tee (2)
-system call.
-.I splice_fd_in
-is the file descriptor to read from,
-.I fd
-is the file descriptor to write to,
-.I len
-contains the number of bytes to copy, and
-.I splice_flags
-contains a bit mask for the flag field associated with the system call.
-Please note that both of the file descriptors must refer to a pipe.
-See also
-.BR tee (2)
-for the general description of the related system call. Available since 5.8.
-
-.TP
-.B IORING_OP_FILES_UPDATE
-This command is an alternative to using
-.B IORING_REGISTER_FILES_UPDATE
-which then works in an async fashion, like the rest of the io_uring commands.
-The arguments passed in are the same.
-.I addr
-must contain a pointer to the array of file descriptors,
-.I len
-must contain the length of the array, and
-.I off
-must contain the offset at which to operate. Note that the array of file
-descriptors pointed to in
-.I addr
-must remain valid until this operation has completed. Available since 5.6.
-
-.TP
-.B IORING_OP_PROVIDE_BUFFERS
-This command allows an application to register a group of buffers to be used
-by commands that read/receive data. Using buffers in this manner can eliminate
-the need to separate the poll + read, which provides a convenient point in
-time to allocate a buffer for a given request. It's often infeasible to have
-as many buffers available as pending reads or receive. With this feature, the
-application can have its pool of buffers ready in the kernel, and when the
-file or socket is ready to read/receive data, a buffer can be selected for the
-operation.
-.I fd
-must contain the number of buffers to provide,
-.I addr
-must contain the starting address to add buffers from,
-.I len
-must contain the length of each buffer to add from the range,
-.I buf_group
-must contain the group ID of this range of buffers, and
-.I off
-must contain the starting buffer ID of this range of buffers. With that set,
-the kernel adds buffers starting with the memory address in
-.I addr,
-each with a length of
-.I len.
-Hence the application should provide
-.I len * fd
-worth of memory in
-.I addr.
-Buffers are grouped by the group ID, and each buffer within this group will be
-identical in size according to the above arguments. This allows the application
-to provide different groups of buffers, and this is often used to have
-differently sized buffers available depending on what the expectations are of
-the individual request. When submitting a request that should use a provided
-buffer, the
-.B IOSQE_BUFFER_SELECT
-flag must be set, and
-.I buf_group
-must be set to the desired buffer group ID where the buffer should be selected
-from. Available since 5.7.
-
-.TP
-.B IORING_OP_REMOVE_BUFFERS
-Remove buffers previously registered with
-.BR IORING_OP_PROVIDE_BUFFERS .
-.I fd
-must contain the number of buffers to remove, and
-.I buf_group
-must contain the buffer group ID from which to remove the buffers. Available
-since 5.7.
-
-.TP
-.B IORING_OP_SHUTDOWN
-Issue the equivalent of a
-.BR shutdown (2)
-system call.
-.I fd
-is the file descriptor to the socket being shutdown, and
-.I len
-must be set to the
-.I how
-argument. No no other fields should be set. Available since 5.11.
-
-.TP
-.B IORING_OP_RENAMEAT
-Issue the equivalent of a
-.BR renameat2 (2)
-system call.
-.I fd
-should be set to the
-.IR olddirfd ,
-.I addr
-should be set to the
-.IR oldpath ,
-.I len
-should be set to the
-.IR newdirfd ,
-.I addr
-should be set to the
-.IR oldpath ,
-.I addr2
-should be set to the
-.IR newpath ,
-and finally
-.I rename_flags
-should be set to the
-.I flags
-passed in to
-.BR renameat2 (2).
-Available since 5.11.
-
-.TP
-.B IORING_OP_UNLINKAT
-Issue the equivalent of a
-.BR unlinkat (2)
-system call.
-.I fd
-should be set to the
-.IR dirfd ,
-.I addr
-should be set to the
-.IR pathname ,
-and
-.I unlink_flags
-should be set to the
-.I flags
-being passed in to
-.BR unlinkat (2).
-Available since 5.11.
-
-.TP
-.B IORING_OP_MKDIRAT
-Issue the equivalent of a
-.BR mkdirat (2)
-system call.
-.I fd
-should be set to the
-.IR dirfd ,
-.I addr
-should be set to the
-.IR pathname ,
-and
-.I len
-should be set to the
-.I mode
-being passed in to
-.BR mkdirat (2).
-Available since 5.15.
-
-.TP
-.B IORING_OP_SYMLINKAT
-Issue the equivalent of a
-.BR symlinkat (2)
-system call.
-.I fd
-should be set to the
-.IR newdirfd ,
-.I addr
-should be set to the
-.I target
-and
-.I addr2
-should be set to the
-.I linkpath
-being passed in to
-.BR symlinkat (2).
-Available since 5.15.
-
-.TP
-.B IORING_OP_LINKAT
-Issue the equivalent of a
-.BR linkat (2)
-system call.
-.I fd
-should be set to the
-.IR olddirfd ,
-.I addr
-should be set to the
-.IR oldpath ,
-.I len
-should be set to the
-.IR newdirfd ,
-.I addr2
-should be set to the
-.IR newpath ,
-and
-.I hardlink_flags
-should be set to the
-.I flags
-being passed in to
-.BR linkat (2).
-Available since 5.15.
-
-.TP
-.B IORING_OP_MSG_RING
-Send a message to an io_uring.
-.I fd
-must be set to a file descriptor of a ring that the application has access to,
-.I len
-can be set to any 32-bit value that the application wishes to pass on, and
-.I off
-should be set any 64-bit value that the application wishes to send. On the
-target ring, a CQE will be posted with the
-.I res
-field matching the
-.I len
-set, and a
-.I user_data
-field matching the
-.I off
-value being passed in. This request type can be used to either just wake or
-interrupt anyone waiting for completions on the target ring, or it can be used
-to pass messages via the two fields. Available since 5.18.
-
-.TP
-.B IORING_OP_SOCKET
-Issue the equivalent of a
-.BR socket (2)
-system call.
-.I fd
-must contain the communication domain,
-.I off
-must contain the communication type,
-.I len
-must contain the protocol, and
-.I rw_flags
-is currently unused and must be set to zero. See also
-.BR socket (2)
-for the general description of the related system call. Available since 5.19.
-
-If the
-.I file_index
-field is set to a positive number, the file won't be installed into the
-normal file table as usual but will be placed into the fixed file table at index
-.I file_index
-- 1.
-In this case, instead of returning a file descriptor, the result will contain
-either 0 on success or an error. If the index points to a valid empty slot, the
-installation is guaranteed to not fail. If there is already a file in the slot,
-it will be replaced, similar to
-.BR IORING_OP_FILES_UPDATE .
-Please note that only io_uring has access to such files and no other syscall
-can use them. See
-.B IOSQE_FIXED_FILE
-and
-.BR IORING_REGISTER_FILES .
-
-Available since 5.19.
-
-.TP
-.B IORING_OP_URING_CMD
-Issues an asynchronous, per-file private operation, similar to
-.BR ioctl (2).
-Further information may be found in the dedicated man page of
-.BR IORING_OP_URING_CMD .
-
-Available since 5.19.
-
-.TP
-.B IORING_OP_SEND_ZC
-Issue the zerocopy equivalent of a
-.BR send(2)
-system call. Similar to
-.BR IORING_OP_SEND ,
-but tries to avoid making intermediate
-copies of data. Zerocopy execution is not guaranteed and may fall back to
-copying. The request may also fail with
-.BR -EOPNOTSUPP ,
-when a protocol doesn't support zerocopy, in which case users are recommended
-to use copying sends instead.
-
-The
-.I flags
-field of the first
-.I "struct io_uring_cqe"
-may likely contain
-.BR IORING_CQE_F_MORE ,
-which means that there will be a second completion event / notification for
-the request, with the
-.I user_data
-field set to the same value. The user must not modify the data buffer until the
-notification is posted. The first cqe follows the usual rules and so its
-.I res
-field will contain the number of bytes sent or a negative error code. The
-notification's
-.I res
-field will be set to zero and the
-.I flags
-field will contain
-.BR IORING_CQE_F_NOTIF .
-The two step model is needed because the kernel may hold on to buffers for a
-long time, e.g. waiting for a TCP ACK, and having a separate cqe for request
-completions allows userspace to push more data without extra delays. Note,
-notifications are only responsible for controlling the lifetime of the buffers,
-and as such don't mean anything about whether the data has atually been sent
-out or received by the other end. Even errored requests may generate a
-notification, and the user must check for
-.B IORING_CQE_F_MORE
-rather than relying on the result.
-
-.I fd
-must be set to the socket file descriptor,
-.I addr
-must contain a pointer to the buffer,
-.I len
-denotes the length of the buffer to send, and
-.I msg_flags
-holds the flags associated with the system call. When
-.I addr2
-is non-zero it points to the address of the target with
-.I addr_len
-specifying its size, turning the request into a
-.BR sendto (2)
-system call equivalent.
-
-Available since 6.0.
-
-This command also supports the following modifiers in
-.I ioprio:
-
-.PP
-.in +12
-.B IORING_RECVSEND_POLL_FIRST
-If set, io_uring will assume the socket is currently full and attempting to
-send data will be unsuccessful. For this case, io_uring will arm internal
-poll and trigger a send of the data when there is enough space available.
-This initial send attempt can be wasteful for the case where the socket
-is expected to be full, setting this flag will bypass the initial send
-attempt and go straight to arming poll. If poll does indicate that data can
-be sent, the operation will proceed.
-
-.B IORING_RECVSEND_FIXED_BUF
-If set, instructs io_uring to use a pre-mapped buffer. The
-.I buf_index
-field should contain an index into an array of fixed buffers. See
-.BR io_uring_register (2)
-for details on how to setup a context for fixed buffer I/O.
-.EE
-.in
-.PP
-
-.TP
-.B IORING_OP_SENDMSG_ZC
-Issue the zerocopy equivalent of a
-.BR sendmsg (2)
-system call.
-Works just like
-.BR IORING_OP_SENDMSG ,
-but like
-.B IORING_OP_SEND_ZC
-supports
-.BR IORING_RECVSEND_FIXED_BUF .
-For additional notes regarding zero copy see
-.BR IORING_OP_SEND_ZC .
-
-Available since 6.1
-
-.TP
-.B IORING_OP_WAITID
-Issue the equivalent of a
-.BR waitid (2)
-system call.
-.I len
-must contain the idtype being queried/waited for and
-.I fd
-must contain the 'pid' (or id) being waited for.
-.I file_index
-is the 'options' being set (the child state changes to wait for).
-.I addr2
-is a pointer to siginfo_t, if any, being filled in. See also
-.BR waitid (2)
-for the general description of the related system call. Available since 6.5.
-
-.TP
-.B IORING_OP_SETXATTR
-.TP
-.B IORING_OP_GETXATTR
-.TP
-.B IORING_OP_FSETXATTR
-.TP
-.B IORING_OP_FGETXATTR
-Issue the equivalent of a
-.BR setxattr (2)
-or
-.BR getxattr (2)
-or
-.BR fsetxattr (2)
-or
-.BR fgetxattr (2)
-system call.
-.I addr
-must contain a pointer to a buffer containing the name of the extended
-attribute.
-.I addr2
-must contain a pointer to a buffer of maximum length
-.IR len ,
-in which the value of the extended attribute is to be placed or is read from.
-Additional flags maybe provided in
-.IR xattr_flags .
-For
-.BR setxattr (2)
-or
-.BR getxattr (2)
-.I addr3
-must contain a pointer to the path of the file.
-For
-.BR fsetxattr (2)
-or
-.BR fgetxattr (2)
-.I fd
-must contain the file descriptor of the file.
-
-Available since 5.19.
-
-.TP
-.B IORING_OP_BIND
-Issues the equivalent of the
-.BR bind (2)
-system call.
-.I fd
-must contain the file descriptor of the socket,
-.I addr
-must contain a pointer to the sockaddr struct containing the address to assign
-and
-.I addr2
-must contain the length of the address.
-
-Available since 6.11.
-
-.TP
-.B IORING_OP_LISTEN
-Issues the equivalent of the
-.BR listen (2)
-system call.
-.I fd
-must contain the file descriptor of the socket and
-.I len
-must contain the backlog parameter, i.e. the maximum amount of pending
-queued connections.
-
-Available since 6.11.
-
-.TP
-.B IORING_OP_FTRUNCATE
-Issues the equivalent of the
-.BR ftruncate (2)
-system call.
-.I fd
-must contain the file descriptor of the file to truncate and
-.I off
-must contain the length to which the file will be truncated.
-
-Available since 6.9.
-
-.TP
-.B IORING_OP_READ_MULTISHOT
-Like
-.BR IORING_OP_READ ,
-but similar to requests prepared with
-.IR io_uring_prep_multishot_accept (3)
-additional reads and thus CQEs will be performed based on this single SQE once
-there is more data available.
-Is restricted to pollable files and will fall back to single shot if the file
-does not support
-.BR NOWAIT .
-Like other multishot type requests, the application should look at the CQE
-flags and see if
-.B IORING_CQE_F_MORE
-is set on completion as an indication of whether or not the read request will
-generate further CQEs. Available since 6.7.
-
-.TP
-.B IORING_OP_FUTEX_WAIT
-Issues the equivalent of the
-.BR futex_wait (2)
-system call.
-.I addr
-must hold a pointer to the futex,
-.I addr2
-must hold the value to which the futex has to be changed so this caller to
-.BR futex_wait (2)
-can be woken by a call to
-.BR futex_wake (2),
-.I addr3
-must hold the bitmask of this
-.BR futex_wait (2)
-caller.
-For a caller of
-.BR futex_wake (2)
-to wake a waiter additionally the bitmask of the waiter and waker must have
-at least one set bit in common.
-.I fd
-must contain additional flags passed in.
-
-Available since 6.7.
-
-.TP
-.B IORING_OP_FUTEX_WAKE
-Issues the equivalent of the
-.BR futex_wake (2)
-system call.
-.I addr
-must hold a pointer to the futex,
-.I addr2
-must hold the maximum number of waiters waiting on this futex to wake,
-.I addr3
-must hold the bitmask of this
-.BR futex_wake (2)
-call.
-To wake a waiter additionally the bitmask of the waiter and waker must have
-at least one set bit in common.
-.I fd
-must contain additional flags passed in.
-
-Available since 6.7.
-
-.TP
-.B IORING_OP_FUTEX_WAITV
-Issues the equivalent of the
-.BR futex_waitv (2)
-system call.
-.I addr
-must hold a pointer to the futexv struct,
-.I len
-must hold the length of the futexv struct, which may not be 0 and must be
-smaller than
-.B FUTEX_WAITV_MAX
-(as of 6.11 == 128).
-
-Available since 6.7.
-
-.TP
-.B IORING_OP_FIXED_FD_INSTALL
-This operation is used to insert a registered file into the regular process
-file table.
-Consequently
-.I fd
-must contain the file index and
-.B IOSQE_FIXED_FILE
-must be set.
-The resulting regular fd is returned via cqe->res.
-Additional flags may be passed in via
-.IR install_fd_flags .
-Currently supported flags are:
-.BR IORING_FIXED_FD_NO_CLOEXEC ,
-which overrides a potentially set
-.B O_CLOEXEC
-flag set on the initial file.
-
-Available since 6.8.
-
-.TP
-.B IORING_OP_PIPE
-This operation is used to create a pipe, a set of file descriptors that can be
-used for communication. The pipe may either be created as a set of normal
-file descriptors, or it can be created as fixed/direct descriptors.
-.I addr
-must contain a pointer to an array of two integers, where upon successful
-completion of the request, index 0 will contain the read side and index 1 the
-write side of the pipe.
-.I pipe_flags
-may contain flags associated with pipe creation. Currently
-.B O_CLOEXEC | O_NONBLOCK | O_DIRECT | O_NOTIFICATION_PIPE
-are supported.
-.I file_index
-may contain the the desired starting point for a fixed descriptor pipe
-creation. If this is set to
-.B 0,
-then regular file descriptors are used. If set to
-.B IORING_FILE_INDEX_ALLOC,
-then the kernel will allocate descriptors from the previously registered
-direct descriptor table. If set to any non-zero value, then it sets the
-exact direct descriptor value for index 0 of the pipe, and index 1 will be
-the following integer value.
-
-If used with direct descriptors rather than normal file descriptors, a
-direct descriptor table must have been previously registered with the kernel.
-
-Available since 6.16.
-
-.TP
-.B IORING_OP_RECV_ZC
-Receive data from a socket using zero-copy techniques. Unlike
-.BR IORING_OP_RECV ,
-this operation does not use a user-provided buffer. Instead, data is delivered
-through a pre-registered zero-copy RX interface queue.
-.I fd
-must be set to the socket file descriptor.
-.I zcrx_ifq_idx
-specifies the index of the registered zero-copy RX interface queue.
-.I len
-specifies the maximum amount of data to receive.
-.I ioprio
-can contain flags such as
-.B IORING_RECVSEND_POLL_FIRST
-and
-.BR IORING_RECV_MULTISHOT .
-This operation requires multishot mode.
-
-Before using this command, a zero-copy RX interface queue must be registered via
-.BR io_uring_register (2)
-using
-.BR IORING_REGISTER_ZCRX_IFQ .
-Data completions are posted as auxiliary CQEs.
-
-Available since 6.15.
-
-.TP
-.B IORING_OP_EPOLL_WAIT
-Wait for events on an epoll instance. This is an async version of
-.BR epoll_wait (2).
-.I fd
-must be set to the epoll file descriptor,
-.I addr
-must point to an array of
-.I struct epoll_event
-to receive the events, and
-.I len
-must contain the maximum number of events to return.
-
-The primary use case is for legacy event loops that still use epoll for some
-file descriptors. By using io_uring to wait on epoll events, the application
-can unify its event handling through io_uring while maintaining backwards
-compatibility with epoll-based components.
-
-Available since 6.15.
-
-.TP
-.B IORING_OP_READV_FIXED
-.TP
-.B IORING_OP_WRITEV_FIXED
-Vectored read and write operations using pre-registered buffers, combining the
-functionality of
-.BR IORING_OP_READV / IORING_OP_WRITEV
-with
-.BR IORING_OP_READ_FIXED / IORING_OP_WRITE_FIXED .
-The
-.I buf_index
-field specifies the index into the registered buffer table. Unlike the
-non-fixed vectored operations, the iovec entries point into the registered
-buffer region. This allows vectored I/O while still benefiting from the
-reduced overhead of pre-registered buffers.
-
-Available since 6.15.
-
-.TP
-.B IORING_OP_NOP128
-No operation, similar to
-.BR IORING_OP_NOP ,
-but explicitly uses a 128-byte SQE. This can be useful for testing or
-alignment purposes when using mixed 64/128-byte SQE rings
-.RB ( IORING_SETUP_SQE_MIXED ).
-
-Available since 6.19.
-
-.TP
-.B IORING_OP_URING_CMD128
-Passthrough command to the underlying file, identical to
-.BR IORING_OP_URING_CMD ,
-but explicitly uses a 128-byte SQE. The extra 64 bytes provide additional
-space for command-specific data. This is useful with
-.B IORING_SETUP_SQE_MIXED
-rings where some commands need the larger SQE size while others do not.
-
-See
-.BR IORING_OP_URING_CMD
-for general usage details.
-
-Available since 6.19.
-
-.PP
-The
-.I flags
-field is a bit mask. The supported flags are:
-.TP
-.B IOSQE_FIXED_FILE
-When this flag is specified,
-.I fd
-is an index into the files array registered with the io_uring instance (see the
-.B IORING_REGISTER_FILES
-section of the
-.BR io_uring_register (2)
-man page). Note that this isn't always available for all commands. If used on
-a command that doesn't support fixed files, the SQE will error with
-.BR -EBADF .
-Available since 5.1.
-.TP
-.B IOSQE_IO_DRAIN
-When this flag is specified, the SQE will not be started before previously
-submitted SQEs have completed, and new SQEs will not be started before this
-one completes. Available since 5.2.
-.TP
-.B IOSQE_IO_LINK
-When this flag is specified, the SQE forms a link with the next SQE in the
-submission ring. That next SQE will not be started before the previous request
-completes. This, in effect, forms a chain of SQEs, which can be arbitrarily
-long. The tail of the chain is denoted by the first SQE that does not have this
-flag set. Chains are not supported across submission boundaries. Even if the
-last SQE in a submission has this flag set, it will still terminate the current
-chain. This flag has no effect on previous SQE submissions, nor does it impact
-SQEs that are outside of the chain tail. This means that multiple chains can be
-executing in parallel, or chains and individual SQEs. Only members inside the
-chain are serialized. A chain of SQEs will be broken if any request in that
-chain ends in error. io_uring considers any unexpected result an error. This
-means that, eg, a short read will also terminate the remainder of the chain.
-If a chain of SQE links is broken, the remaining unstarted part of the chain
-will be terminated and completed with
-.B -ECANCELED
-as the error code. Available since 5.3.
-.TP
-.B IOSQE_IO_HARDLINK
-Like IOSQE_IO_LINK, but it doesn't sever regardless of the completion result.
-Note that the link will still sever if we fail submitting the parent request,
-hard links are only resilient in the presence of completion results for
-requests that did submit correctly.
-.B IOSQE_IO_HARDLINK
-implies
-.BR IOSQE_IO_LINK .
-Available since 5.5.
-.TP
-.B IOSQE_ASYNC
-Normal operation for io_uring is to try and issue an sqe as non-blocking first,
-and if that fails, execute it in an async manner. To support more efficient
-overlapped operation of requests that the application knows/assumes will
-always (or most of the time) block, the application can ask for an sqe to be
-issued async from the start. Available since 5.6.
-.TP
-.B IOSQE_BUFFER_SELECT
-Used in conjunction with the
-.B IORING_OP_PROVIDE_BUFFERS
-command, which registers a pool of buffers to be used by commands that read
-or receive data. When buffers are registered for this use case, and this
-flag is set in the command, io_uring will grab a buffer from this pool when
-the request is ready to receive or read data. If successful, the resulting CQE
-will have
-.B IORING_CQE_F_BUFFER
-set in the flags part of the struct, and the upper
-.B IORING_CQE_BUFFER_SHIFT
-bits will contain the ID of the selected buffers. This allows the application
-to know exactly which buffer was selected for the operation. If no buffers
-are available and this flag is set, then the request will fail with
-.B -ENOBUFS
-as the error code. Once a buffer has been used, it is no longer available in
-the kernel pool. The application must re-register the given buffer again when
-it is ready to recycle it (eg has completed using it). Available since 5.7.
-.TP
-.B IOSQE_CQE_SKIP_SUCCESS
-Don't generate a CQE if the request completes successfully. If the request
-fails, an appropriate CQE will be posted as usual and if there is no
-.B IOSQE_IO_HARDLINK,
-CQEs for all linked requests will be omitted. The notion of failure/success is
-opcode specific and is the same as with breaking chains of
-.BR IOSQE_IO_LINK .
-One special case is when the request has a linked timeout, then the CQE
-generation for the linked timeout is decided solely by whether it has
-.B IOSQE_CQE_SKIP_SUCCESS
-set, regardless whether it timed out or was canceled. In other words, if a
-linked timeout has the flag set, it's guaranteed to not post a CQE.
-
-The semantics are chosen to accommodate several use cases. First, when all but
-the last request of a normal link without linked timeouts are marked with the
-flag, only one CQE per link is posted. Additionally, it enables suppression of
-CQEs in cases where the side effects of a successfully executed operation is
-enough for userspace to know the state of the system. One such example would
-be writing to a synchronisation file.
-
-This flag is incompatible with
-.BR IOSQE_IO_DRAIN .
-Using both of them in a single ring is undefined behavior, even when they are
-not used together in a single request. Currently, after the first request with
-.BR IOSQE_CQE_SKIP_SUCCESS ,
-all subsequent requests marked with drain will be failed at submission time.
-Note that the error reporting is best effort only, and restrictions may change
-in the future.
-
-Available since 5.17.
-
-.PP
-.I ioprio
-specifies the I/O priority. See
-.BR ioprio_get (2)
-for a description of Linux I/O priorities.
-
-.I fd
-specifies the file descriptor against which the operation will be
-performed, with the exception noted above.
-
-If the operation is one of
-.B IORING_OP_READ_FIXED
-or
-.BR IORING_OP_WRITE_FIXED ,
-.I addr
-and
-.I len
-must fall within the buffer located at
-.I buf_index
-in the fixed buffer array. If the operation is either
-.B IORING_OP_READV
-or
-.BR IORING_OP_WRITEV ,
-then
-.I addr
-points to an iovec array of
-.I len
-entries.
-
-.IR rw_flags ,
-specified for read and write operations, contains a bitwise OR of
-per-I/O flags, as described in the
-.BR preadv2 (2)
-man page.
-
-The
-.I fsync_flags
-bit mask may contain either 0, for a normal file integrity sync, or
-.B IORING_FSYNC_DATASYNC
-to provide data sync only semantics. See the descriptions of
-.B O_SYNC
-and
-.B O_DSYNC
-in the
-.BR open (2)
-manual page for more information.
-
-The bits that may be set in
-.I poll_events
-are defined in \fI<poll.h>\fP, and documented in
-.BR poll (2).
-
-.I user_data
-is an application-supplied value that will be copied into
-the completion queue entry (see below).
-.I buf_index
-is an index into an array of fixed buffers, and is only valid if fixed
-buffers were registered.
-.I personality
-is the credentials id to use for this operation. See
-.BR io_uring_register (2)
-for how to register personalities with io_uring. If set to 0, the current
-personality of the submitting task is used.
-.PP
-Once the submission queue entry is initialized, I/O is submitted by
-placing the index of the submission queue entry into the tail of the
-submission queue. After one or more indexes are added to the queue,
-and the queue tail is advanced, the
-.BR io_uring_enter (2)
-system call can be invoked to initiate the I/O.
-
-Completions use the following data structure:
-.PP
-.in +4n
-.EX
-/*
- * IO completion data structure (Completion Queue Entry)
- */
-struct io_uring_cqe {
- __u64 user_data; /* sqe->data submission passed back */
- __s32 res; /* result code for this event */
- __u32 flags;
-};
-.EE
-.in
-.PP
-.I user_data
-is copied from the field of the same name in the submission queue
-entry. The primary use case is to store data that the application
-will need to access upon completion of this particular I/O. The
-.I flags
-is used for certain commands, like
-.B IORING_OP_POLL_ADD
-or in conjunction with
-.B IOSQE_BUFFER_SELECT
-or
-.BR IORING_OP_MSG_RING ,
-see those entries for details.
-.I res
-is the operation-specific result, but io_uring-specific errors
-(e.g. flags or opcode invalid) are returned through this field.
-They are described in section
-.B CQE
-.BR ERRORS .
-.PP
-For read and write opcodes, the
-return values match
-.I errno
-values documented in the
-.BR preadv2 (2)
-and
-.BR pwritev2 (2)
-man pages, with
-.I
-res
-holding the equivalent of
-.I -errno
-for error cases, or the transferred number of bytes in case the operation
-is successful. Hence both error and success return can be found in that
-field in the CQE. For other request types, the return values are documented
-in the matching man page for that type, or in the opcodes section above for
-io_uring-specific opcodes.
-.PP
-.SH RETURN VALUE
-.BR io_uring_enter (2)
-returns the number of I/Os successfully consumed. This can be zero
-if
-.I to_submit
-was zero or if the submission queue was empty. Note that if the ring was
-created with
-.B IORING_SETUP_SQPOLL
-specified, then the return value will generally be the same as
-.I to_submit
-as submission happens outside the context of the system call.
-
-The errors related to a submission queue entry will be returned through a
-completion queue entry (see section
-.B CQE
-.BR ERRORS ),
-rather than through the system call itself.
-
-Errors that occur not on behalf of a submission queue entry are returned via the
-system call directly. On such an error, a negative error code is returned. The
-caller should not rely on
-.I errno
-variable.
-.PP
-.SH ERRORS
-These are the errors returned by
-.BR io_uring_enter (2)
-system call.
-.TP
-.B EAGAIN
-The kernel was unable to allocate memory for the request, or otherwise ran out
-of resources to handle it. The application should wait for some completions and
-try again.
-.TP
-.B EBADF
-.I fd
-is not a valid file descriptor.
-.TP
-.B EBADFD
-.I fd
-is a valid file descriptor, but the io_uring ring is not in the right state
-(enabled). See
-.BR io_uring_register (2)
-for details on how to enable the ring.
-.TP
-.B EBADR
-At least one CQE was dropped even with the
-.B IORING_FEAT_NODROP
-feature, and there are no otherwise available CQEs. This clears the error state
-and so with no other changes the next call to
-.BR io_uring_enter (2)
-will not have this error. This error should be extremely rare and indicates the
-machine is running critically low on memory. It may be reasonable for the
-application to terminate running unless it is able to safely handle any CQE
-being lost.
-.TP
-.B EBUSY
-If the
-.B IORING_FEAT_NODROP
-feature flag is set, then
-.B EBUSY
-will be returned if there were overflow entries,
-.B IORING_ENTER_GETEVENTS
-flag is set and not all of the overflow entries were able to be flushed to
-the CQ ring.
-
-Without
-.B IORING_FEAT_NODROP
-the application is attempting to overcommit the number of requests it can have
-pending. The application should wait for some completions and try again. May
-occur if the application tries to queue more requests than we have room for in
-the CQ ring, or if the application attempts to wait for more events without
-having reaped the ones already present in the CQ ring.
-.TP
-.B EEXIST
-The thread submitting the work is invalid. This may occur if
-.B IORING_ENTER_GETEVENTS
-and
-.B IORING_SETUP_DEFER_TASKRUN
-is set, but the submitting thread is not the thread that initially created or
-enabled the io_uring associated with
-.I fd.
-.TP
-.B EINVAL
-Some bits in the
-.I flags
-argument are invalid.
-.TP
-.B EFAULT
-An invalid user space address was specified for the
-.I sig
-argument.
-.TP
-.B ENXIO
-The io_uring instance is in the process of being torn down.
-.TP
-.B EOPNOTSUPP
-.I fd
-does not refer to an io_uring instance.
-.TP
-.B EINTR
-The operation was interrupted by a delivery of a signal before it could
-complete; see
-.BR signal (7).
-Can happen while waiting for events with
-.B IORING_ENTER_GETEVENTS.
-.TP
-.B EOWNERDEAD
-The ring has been setup with
-.B IORING_SETUP_SQPOLL
-and the sq poll kernel thread has been killed.
-
-.SH CQE ERRORS
-These io_uring-specific errors are returned as a negative value in the
-.I res
-field of the completion queue entry.
-.TP
-.B EACCES
-The
-.I flags
-field or
-.I opcode
-in a submission queue entry is not allowed due to registered restrictions.
-See
-.BR io_uring_register (2)
-for details on how restrictions work.
-.TP
-.B EBADF
-The
-.I fd
-field in the submission queue entry is invalid, or the
-.B IOSQE_FIXED_FILE
-flag was set in the submission queue entry, but no files were registered
-with the io_uring instance.
-.TP
-.B EFAULT
-buffer is outside of the process' accessible address space
-.TP
-.B EFAULT
-.B IORING_OP_READ_FIXED
-or
-.B IORING_OP_WRITE_FIXED
-was specified in the
-.I opcode
-field of the submission queue entry, but either buffers were not
-registered for this io_uring instance, or the address range described
-by
-.I addr
-and
-.I len
-does not fit within the buffer registered at
-.IR buf_index .
-.TP
-.B EINVAL
-The
-.I flags
-field or
-.I opcode
-in a submission queue entry is invalid.
-.TP
-.B EINVAL
-The
-.I buf_index
-member of the submission queue entry is invalid.
-.TP
-.B EINVAL
-The
-.I personality
-field in a submission queue entry is invalid.
-.TP
-.B EINVAL
-.B IORING_OP_READV
-or
-.B IORING_OP_WRITEV
-was specified in the submission queue entry, but the io_uring instance
-has fixed buffers registered.
-.TP
-.B EINVAL
-.B IORING_OP_READ_FIXED
-or
-.B IORING_OP_WRITE_FIXED
-was specified in the submission queue entry, and the
-.I buf_index
-is invalid.
-.TP
-.B EINVAL
-.BR IORING_OP_READV ,
-.BR IORING_OP_WRITEV ,
-.BR IORING_OP_READ_FIXED ,
-.B IORING_OP_WRITE_FIXED
-or
-.B IORING_OP_FSYNC
-was specified in the submission queue entry, but the io_uring instance
-was configured for IOPOLLing, or any of
-.IR addr ,
-.IR ioprio ,
-.IR off ,
-.IR len ,
-or
-.I buf_index
-was set in the submission queue entry.
-.TP
-.B EINVAL
-.B IORING_OP_POLL_ADD
-or
-.B IORING_OP_POLL_REMOVE
-was specified in the
-.I opcode
-field of the submission queue entry, but the io_uring instance was
-configured for busy-wait polling
-.RB ( IORING_SETUP_IOPOLL ),
-or any of
-.IR ioprio ,
-.IR off ,
-.IR len ,
-or
-.I buf_index
-was non-zero in the submission queue entry.
-.TP
-.B EINVAL
-.B IORING_OP_POLL_ADD
-was specified in the
-.I opcode
-field of the submission queue entry, and the
-.I addr
-field was non-zero.
-.TP
-.B EOPNOTSUPP
-.I opcode
-is valid, but not supported by this kernel.
-.TP
-.B EOPNOTSUPP
-.B IOSQE_BUFFER_SELECT
-was set in the
-.I flags
-field of the submission queue entry, but the
-.I opcode
-doesn't support buffer selection.
-.TP
-.B EINVAL
-.B IORING_OP_TIMEOUT
-was specified, but
-.I timeout_flags
-specified more than one clock source or
-.B IORING_TIMEOUT_MULTISHOT
-was set alongside
-.BR IORING_TIMEOUT_ABS .
diff --git a/man/io_uring_enter.2.md b/man/io_uring_enter.2.md
new file mode 100644
index 00000000..f33ac3d1
--- /dev/null
+++ b/man/io_uring_enter.2.md
@@ -0,0 +1,745 @@
+.\" Copyright (C) 2019 Jens Axboe <axboe@kernel.dk>
+.\" Copyright (C) 2019 Red Hat, Inc.
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 22, 2019
+footer: Linux
+header: Linux Programmer\'s Manual
+section: 2
+title: io_uring_enter
+---
+
+# NAME
+
+io_uring_enter - initiate and/or complete asynchronous I/O
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_enter(unsigned int fd , unsigned int to_submit ,
+ unsigned int min_complete , unsigned int flags ,
+ sigset_t * sig );
+
+ int io_uring_enter2(unsigned int fd , unsigned int to_submit ,
+ unsigned int min_complete , unsigned int flags ,
+ void * arg , size_t sz );
+
+# DESCRIPTION
+
+**io_uring_enter**(2) is used to initiate and complete I/O using the shared submission and completion queues setup by a call to **io_uring_setup**(2). A single call can both submit new I/O and wait for completions of I/O initiated by this call or previous calls to **io_uring_enter**(2).
+
+*fd* is the file descriptor returned by **io_uring_setup**(2). *to_submit* specifies the number of I/Os to submit from the submission queue. *flags* is a bitmask of the following values:
+
+**IORING_ENTER_GETEVENTS**
+
+: If this flag is set, then the system call will wait for the specified number of events in *min_complete* before returning. This flag can be set along with *to_submit* to both submit and complete events in a single system call. If this flag is set either the flag **IORING_SETUP_DEFER_TASKRUN** must not be set or the thread issuing the syscall must be the thread that created the io_uring associated with *fd,* or be the thread that enabled the ring originally created with **IORING_SETUP_R_DISABLED** via **io_uring_register**(2) or **io_uring_enable_rings**(3).
+
+**IORING_ENTER_SQ_WAKEUP**
+
+: If the ring has been created with **IORING_SETUP_SQPOLL,** then this flag asks the kernel to wakeup the SQ kernel thread to submit IO.
+
+**IORING_ENTER_SQ_WAIT**
+
+: If the ring has been created with **IORING_SETUP_SQPOLL,** then the application has no real insight into when the SQ kernel thread has consumed entries from the SQ ring. This can lead to a situation where the application can no longer get a free SQE entry to submit, without knowing when one will become available as the SQ kernel thread consumes them. If the system call is used with this flag set, then it will wait until at least one entry is free in the SQ ring.
+
+**IORING_ENTER_EXT_ARG**
+
+: By default, *arg* is a *sigset_t* pointer. If **IORING_ENTER_EXT_ARG** is set (supported since kernel 5.11), then *arg* is instead a pointer to a *struct io_uring_getevents_arg* and *argsz* must be set to the size of this structure. The definition is as follows:
+
+ struct io_uring_getevents_arg {
+ __u64 sigmask;
+ __u32 sigmask_sz;
+ __u32 pad;
+ __u64 ts;
+ };
+
+ which allows passing in both a signal mask as well as pointer to a *struct \_\_kernel_timespec* timeout value. If *ts* is set to a valid pointer, then this time value indicates the timeout for waiting on events. If an application is waiting on events and wishes to stop waiting after a specified amount of time, then this can be accomplished directly in version 5.11 and newer by using this feature.
+
+**IORING_ENTER_REGISTERED_RING**
+
+: If the ring file descriptor has been registered through use of **IORING_REGISTER_RING_FDS**, then setting this flag will tell the kernel that the *ring_fd* passed in is the registered ring offset rather than a normal file descriptor.
+
+**IORING_ENTER_ABS_TIMER**
+
+: When this flag is set, the timeout argument passed in *struct io_uring_getevents_arg* will be interpreted as an absolute time of the registered clock (see **IORING_REGISTER_CLOCK)** until which the waiting should end.
+
+ Available since 6.12
+
+**IORING_ENTER_EXT_ARG_REG**
+
+: When this flag is set, *arg* is not a pointer to a *struct*io_uring_getevents_arg*,* but merely an offset into an area of wait regions previously registered with **io_uring_register**(2) using the **IORING_REGISTER_MEM_REGION** operation.
+
+ Available since 6.13
+
+**IORING_ENTER_NO_IOWAIT**
+
+: When this flag is set, the system call will not mark the waiting task as being in iowait if it is sleeping waiting on events and there are pending requests. This is useful if iowait isn\'t expected when waiting for events. It can also prevent extra power usage by allowing the CPU to enter lower sleep states. This flag is only available if the kernel supports the **IORING_FEAT_NO_IOWAIT** feature.
+
+ Available since 6.15.
+
+If the io_uring instance was configured for polling, by specifying **IORING_SETUP_IOPOLL** in the call to **io_uring_setup**(2), then min_complete has a slightly different meaning. Passing a value of 0 instructs the kernel to return any events which are already complete, without blocking. If *min_complete* is a non-zero value, the kernel will still return immediately if any completion events are available. If no event completions are available, then the call will poll either until one or more completions become available, or until the process has exceeded its scheduler time slice.
+
+Note that, for interrupt driven I/O (where **IORING_SETUP_IOPOLL** was not specified in the call to **io_uring_setup**(2)), an application may check the completion queue for event completions without entering the kernel at all.
+
+When the system call returns that a certain amount of SQEs have been consumed and submitted, it\'s safe to reuse SQE entries in the ring. This is true even if the actual IO submission had to be punted to async context, which means that the SQE may in fact not have been submitted yet. If the kernel requires later use of a particular SQE entry, it will have made a private copy of it.
+
+*sig* is a pointer to a signal mask (see **sigprocmask**(2)); if *sig* is not NULL, **io_uring_enter**(2) first replaces the current signal mask by the one pointed to by *sig*, then waits for events to become available in the completion queue, and then restores the original signal mask. The following **io_uring_enter**(2) call:
+
+ ret = io_uring_enter(fd, 0, 1, IORING_ENTER_GETEVENTS, &sig);
+
+is equivalent to *atomically* executing the following calls:
+
+ pthread_sigmask(SIG_SETMASK, &sig, &orig);
+ ret = io_uring_enter(fd, 0, 1, IORING_ENTER_GETEVENTS, NULL);
+ pthread_sigmask(SIG_SETMASK, &orig, NULL);
+
+See the description of **pselect**(2) for an explanation of why the *sig* parameter is necessary.
+
+Submission queue entries are represented using the following data structure:
+
+ /*
+ * IO submission data structure (Submission Queue Entry)
+ */
+ struct io_uring_sqe {
+ __u8 opcode; /* type of operation for this sqe */
+ __u8 flags; /* IOSQE_ flags */
+ __u16 ioprio; /* ioprio for the request */
+ __s32 fd; /* file descriptor to do IO on */
+ union {
+ __u64 off; /* offset into file */
+ __u64 addr2;
+ struct {
+ __u32 cmd_op;
+ __u32 __pad1;
+ };
+ };
+ union {
+ __u64 addr; /* pointer to buffer or iovecs */
+ __u64 splice_off_in;
+ struct {
+ __u32 level;
+ __u32 optname;
+ };
+ };
+ __u32 len; /* buffer size or number of iovecs */
+ union {
+ __kernel_rwf_t rw_flags;
+ __u32 fsync_flags;
+ __u16 poll_events; /* compatibility */
+ __u32 poll32_events; /* word-reversed for BE */
+ __u32 sync_range_flags;
+ __u32 msg_flags;
+ __u32 timeout_flags;
+ __u32 accept_flags;
+ __u32 cancel_flags;
+ __u32 open_flags;
+ __u32 statx_flags;
+ __u32 fadvise_advice;
+ __u32 splice_flags;
+ __u32 rename_flags;
+ __u32 unlink_flags;
+ __u32 hardlink_flags;
+ __u32 xattr_flags;
+ __u32 msg_ring_flags;
+ __u32 uring_cmd_flags;
+ __u32 waitid_flags;
+ __u32 futex_flags;
+ __u32 install_fd_flags;
+ __u32 nop_flags;
+ };
+ __u64 user_data; /* data to be passed back at completion time */
+ /* pack this to avoid bogus arm OABI complaints */
+ union {
+ /* index into fixed buffers, if used */
+ __u16 buf_index;
+ /* for grouped buffer selection */
+ __u16 buf_group;
+ } __attribute__((packed));
+ /* personality to use, if used */
+ __u16 personality;
+ union {
+ __s32 splice_fd_in;
+ __u32 file_index;
+ __u32 optlen;
+ struct {
+ __u16 addr_len;
+ __u16 __pad3[1];
+ };
+ };
+ union {
+ struct {
+ __u64 addr3;
+ __u64 __pad2[1];
+ };
+ __u64 optval;
+ /*
+ * If the ring is initialized with IORING_SETUP_SQE128, then
+ * this field is used for 80 bytes of arbitrary command data
+ */
+ __u8 cmd[0];
+ };
+ };
+
+The *opcode* describes the operation to be performed. It can be one of:
+
+**IORING_OP_NOP**
+
+: Do not perform any I/O. This is useful for testing the performance of the io_uring implementation itself.
+
+**IORING_OP_READV**
+
+:
+
+ **IORING_OP_WRITEV**
+
+ : Vectored read and write operations, similar to **preadv2**(2) and **pwritev2**(2). If the file is not seekable, *off* must be set to zero or -1.
+
+ **IORING_OP_READ_FIXED**
+
+ :
+
+ **IORING_OP_WRITE_FIXED**
+
+ : Read from or write to pre-mapped buffers. See **io_uring_register**(2) for details on how to setup a context for fixed reads and writes.
+
+ **IORING_OP_FSYNC**
+
+ : File sync. See also **fsync**(2). Optionally *off* and *len* can be used to specify a range within the file to be synced rather than syncing the entire file, which is the default behavior. Note that, while I/O is initiated in the order in which it appears in the submission queue, completions are unordered. For example, an application which places a write I/O followed by an fsync in the submission queue cannot expect the fsync to apply to the write. The two operations execute in parallel, so the fsync may complete before the write is issued to the storage. The same is also true for previously issued writes that have not completed prior to the fsync. To enforce ordering one may utilize linked SQEs, **IOSQE_IO_DRAIN** or wait for the arrival of CQEs of requests which have to be ordered before a given request before submitting its SQE.
+
+ **IORING_OP_POLL_ADD**
+
+ : Poll the *fd* specified in the submission queue entry for the events specified in the *poll_events* field. Unlike poll or epoll without **EPOLLONESHOT**, by default this interface always works in one shot mode. That is, once the poll operation is completed, it will have to be resubmitted.
+
+ If **IORING_POLL_ADD_MULTI** is set in the SQE *len* field, then the poll will work in multi shot mode instead. That means it\'ll repatedly trigger when the requested event becomes true, and hence multiple CQEs can be generated from this single SQE. The CQE *flags* field will have **IORING_CQE_F_MORE** set on completion if the application should expect further CQE entries from the original request. If this flag isn\'t set on completion, then the poll request has been terminated and no further events will be generated. This mode is available since 5.13.
+
+ This command works like an async **poll(2)** and the completion event result is the returned mask of events.
+
+ Without **IORING_POLL_ADD_MULTI** and the initial poll operation with **IORING_POLL_ADD_MULTI** the operation is level triggered, i.e. if there is data ready or events pending etc. at the time of submission a corresponding CQE will be posted. Potential further completions beyond the first caused by a **IORING_POLL_ADD_MULTI** are edge triggered.
+
+ **IORING_OP_POLL_REMOVE**
+
+ : Remove or update an existing poll request. If found, the *res* field of the *struct io_uring_cqe* will contain 0. If not found, *res* will contain **-ENOENT,** or **-EALREADY** if the poll request was in the process of completing already.
+
+ If **IORING_POLL_UPDATE_EVENTS** is set in the SQE *len* field, then the request will update an existing poll request with the mask of events passed in with this request. The lookup is based on the *user_data* field of the original SQE submitted, and this values is passed in the *addr* field of the SQE. If **IORING_POLL_UPDATE_USER_DATA** is set in the SQE *len* field, then the request will update the *user_data* of an existing poll request based on the value passed in the *off* field. Updating an existing poll is available since 5.13.
+
+ **IORING_OP_EPOLL_CTL**
+
+ : Add, remove or modify entries in the interest list of **epoll**(7). See **epoll_ctl**(2) for details of the system call. *fd* holds the file descriptor that represents the epoll instance, *off* holds the file descriptor to add, remove or modify, *len* holds the operation ( **EPOLL_CTL_ADD**, **EPOLL_CTL_DEL**, **EPOLL_CTL_MOD**) to perform and, *addr* holds a pointer to the *epoll_event* structure. Available since 5.6.
+
+ **IORING_OP_SYNC_FILE_RANGE**
+
+ : Issue the equivalent of a **sync_file_range** (2) on the file descriptor. The *fd* field is the file descriptor to sync, the *off* field holds the offset in bytes, the *len* field holds the length in bytes, and the *sync_range_flags* field holds the flags for the command. See also **sync_file_range**(2) for the general description of the related system call. Available since 5.2.
+
+ **IORING_OP_SENDMSG**
+
+ : Issue the equivalent of a **sendmsg(2)** system call. *fd* must be set to the socket file descriptor, *addr* must contain a pointer to the msghdr structure, and *msg_flags* holds the flags associated with the system call. See also **sendmsg**(2) for the general description of the related system call. Available since 5.3.
+
+ This command also supports the following modifiers in *ioprio:*
+
+**IORING_RECVSEND_POLL_FIRST** If set, io_uring will assume the socket is currently full and attempting to send data will be unsuccessful. For this case, io_uring will arm internal poll and trigger a send of the data when there is enough space available. This initial send attempt can be wasteful for the case where the socket is expected to be full, setting this flag will bypass the initial send attempt and go straight to arming poll. If poll does indicate that data can be sent, the operation will proceed.
+
+**IORING_OP_RECVMSG**
+
+: Works just like IORING_OP_SENDMSG, except for **recvmsg(2)** instead. See the description of IORING_OP_SENDMSG. Available since 5.3.
+
+ This command also supports the following modifiers in *ioprio:*
+
+**IORING_RECVSEND_POLL_FIRST** If set, io_uring will assume the socket is currently empty and attempting to receive data will be unsuccessful. For this case, io_uring will arm internal poll and trigger a receive of the data when the socket has data to be read. This initial receive attempt can be wasteful for the case where the socket is expected to be empty, setting this flag will bypass the initial receive attempt and go straight to arming poll. If poll does indicate that data is ready to be received, the operation will proceed.
+
+**IORING_OP_SEND**
+
+: Issue the equivalent of a **send(2)** system call. *fd* must be set to the socket file descriptor, *addr* must contain a pointer to the buffer, *len* denotes the length of the buffer to send, and *msg_flags* holds the flags associated with the system call. See also **send(2)** for the general description of the related system call. Available since 5.6.
+
+ This command also supports the following modifiers in *ioprio:*
+
+**IORING_RECVSEND_POLL_FIRST** If set, io_uring will assume the socket is currently full and attempting to send data will be unsuccessful. For this case, io_uring will arm internal poll and trigger a send of the data when there is enough space available. This initial send attempt can be wasteful for the case where the socket is expected to be full, setting this flag will bypass the initial send attempt and go straight to arming poll. If poll does indicate that data can be sent, the operation will proceed.
+
+**IORING_OP_RECV**
+
+: Works just like IORING_OP_SEND, except for **recv(2)** instead. See the description of IORING_OP_SEND. Available since 5.6.
+
+ This command also supports the following modifiers in *ioprio:*
+
+**IORING_RECVSEND_POLL_FIRST** If set, io_uring will assume the socket is currently empty and attempting to receive data will be unsuccessful. For this case, io_uring will arm internal poll and trigger a receive of the data when the socket has data to be read. This initial receive attempt can be wasteful for the case where the socket is expected to be empty, setting this flag will bypass the initial receive attempt and go straight to arming poll. If poll does indicate that data is ready to be received, the operation will proceed.
+
+**IORING_OP_TIMEOUT**
+
+: This command will register a timeout operation. The *addr* field must contain a pointer to a struct \_\_kernel_timespec structure, *len* must contain 1 to signify one \_\_kernel_timespec structure, *timeout_flags* may contain **IORING_TIMEOUT_ABS** for an absolute timeout value, or 0 for a relative timeout. *off* may contain a completion event count. A timeout will trigger a wakeup event on the completion ring for anyone waiting for events. A timeout condition is met when either the specified timeout expires, or the specified number of events have completed. Either condition will trigger the event. If set to 0, completed events are not counted, which effectively acts like a timer. io_uring timeouts use the **CLOCK_MONOTONIC** as the default clock source. The request will complete with **-ETIME** if the timeout got completed through expiration of the timer, or *0* if the timeout got completed through requests completing on their own. If the timeout was canceled before it expired, the request will complete with **-ECANCELED.** Available since 5.4.
+
+ Since 5.15, this command also supports the following modifiers in *timeout_flags:*
+
+**IORING_TIMEOUT_BOOTTIME** If set, then the clocksource used is **CLOCK_BOOTTIME** instead of **CLOCK_MONOTONIC**. This clocksource differs in that it includes time elapsed if the system was suspend while having a timeout request in-flight.
+
+**IORING_TIMEOUT_REALTIME** If set, then the clocksource used is **CLOCK_REALTIME** instead of **CLOCK_MONOTONIC**.
+
+Since 5.16, **IORING_TIMEOUT_ETIME_SUCCESS** can be set in *timeout_flags*, which will result in the expiration of the timer and subsequent completion with **-ETIME** not being interpreted as an error. This is mostly relevant for linked SQEs, as subsequent requests in the chain would not get canceled by the timeout, if this flag is set. See **IOSQE_IO_LINK** for more details on linked SQEs.
+
+Since 6.4, **IORING_TIMEOUT_MULTISHOT** can be set in *timeout_flags*, which will result in the timer producing multiple consecutive completions like other multi shot operations e.g. **IORING_OP_READ_MULTISHOT** or **IORING_POLL_ADD_MULTI**. *off* must be set to the amount of desired completions. **IORING_TIMEOUT_MULTISHOT** must not be used with **IORING_TIMEOUT_ABS**.
+
+Since kernel 7.1, **IORING_TIMEOUT_IMMEDIATE_ARG** can be set in *timeout_flags*, which causes the *addr* field to be interpreted as a timeout value in nanoseconds rather than a pointer to a **struct \_\_kernel_timespec.** This avoids the need to keep a timespec structure valid in user memory until the request is submitted.
+
+**IORING_OP_TIMEOUT_REMOVE**
+
+: If *timeout_flags* are zero, then it attempts to remove an existing timeout operation. *addr* must contain the *user_data* field of the previously issued timeout operation. If the specified timeout request is found and canceled successfully, this request will terminate with a result value of *0* If the timeout request was found but expiration was already in progress, this request will terminate with a result value of **-EBUSY** If the timeout request wasn\'t found, the request will terminate with a result value of **-ENOENT** Available since 5.5.
+
+ If *timeout_flags* contain **IORING_TIMEOUT_UPDATE**, instead of removing an existing operation, it updates it. *addr* and return values are same as before. *addr2* field must contain a pointer to a struct \_\_kernel_timespec structure. *timeout_flags* may also contain IORING_TIMEOUT_ABS, in which case the value given is an absolute one, not a relative one. Available since 5.11.
+
+**IORING_OP_ACCEPT**
+
+: Issue the equivalent of an **accept4**(2) system call. *fd* must be set to the socket file descriptor, *addr* must contain the pointer to the sockaddr structure, and *addr2* must contain a pointer to the socklen_t addrlen field. Flags can be passed using the *accept_flags* field. See also **accept4**(2) for the general description of the related system call. Available since 5.5.
+
+ If the *file_index* field is set to a positive number, the file won\'t be installed into the normal file table as usual but will be placed into the fixed file table at index *file_index* - 1. In this case, instead of returning a file descriptor, the result will contain either 0 on success or an error. If the index points to a valid empty slot, the installation is guaranteed to not fail. If there is already a file in the slot, it will be replaced, similar to **IORING_OP_FILES_UPDATE.** Please note that only io_uring has access to such files and no other syscall can use them. See **IOSQE_FIXED_FILE** and **IORING_REGISTER_FILES**.
+
+ Available since 5.5.
+
+**IORING_OP_ASYNC_CANCEL**
+
+: Attempt to cancel an already issued request. *addr* must contain the *user_data* field of the request that should be canceled. The cancelation request will complete with one of the following results codes. If found, the *res* field of the cqe will contain 0. If not found, *res* will contain **-ENOENT**. If found and attempted canceled, the *res* field will contain **-EALREADY**. In this case, the request may or may not terminate. In general, requests that are interruptible (like socket IO) will get canceled, while disk IO requests cannot be canceled if already started. Available since 5.5.
+
+**IORING_OP_LINK_TIMEOUT**
+
+: This request must be linked with another request through **IOSQE_IO_LINK** which is described below. Unlike **IORING_OP_TIMEOUT**, **IORING_OP_LINK_TIMEOUT** acts on the linked request, not the completion queue. The format of the command is otherwise like **IORING_OP_TIMEOUT**, except there\'s no completion event count as it\'s tied to a specific request. If used, the timeout specified in the command will cancel the linked command, unless the linked command completes before the timeout. The timeout will complete with **-ETIME** if the timer expired and the linked request was attempted canceled, or **-ECANCELED** if the timer got canceled because of completion of the linked request. Like **IORING_OP_TIMEOUT** the clock source used is **CLOCK_MONOTONIC** Available since 5.5.
+
+**IORING_OP_CONNECT**
+
+: Issue the equivalent of a **connect**(2) system call. *fd* must be set to the socket file descriptor, *addr* must contain the const pointer to the sockaddr structure, and *off* must contain the socklen_t addrlen field. See also **connect**(2) for the general description of the related system call. Available since 5.5.
+
+**IORING_OP_FALLOCATE**
+
+: Issue the equivalent of a **fallocate**(2) system call. *fd* must be set to the file descriptor, *len* must contain the mode associated with the operation, *off* must contain the offset on which to operate, and *addr* must contain the length. See also **fallocate**(2) for the general description of the related system call. Available since 5.6.
+
+**IORING_OP_FADVISE**
+
+: Issue the equivalent of a **posix_fadvise**(2) system call. *fd* must be set to the file descriptor, *off* must contain the offset on which to operate, *len* must contain the length, and *fadvise_advice* must contain the advice associated with the operation. See also **posix_fadvise**(2) for the general description of the related system call. Available since 5.6.
+
+**IORING_OP_MADVISE**
+
+: Issue the equivalent of a **madvise**(2) system call. *addr* must contain the address to operate on, *len* must contain the length on which to operate, and *fadvise_advice* must contain the advice associated with the operation. See also **madvise**(2) for the general description of the related system call. Available since 5.6.
+
+**IORING_OP_OPENAT**
+
+: Issue the equivalent of a **openat**(2) system call. *fd* is the *dirfd* argument, *addr* must contain a pointer to the *\*pathname* argument, *open_flags* should contain any flags passed in, and *len* is access mode of the file. See also **openat**(2) for the general description of the related system call. Available since 5.6.
+
+ If the *file_index* field is set to a positive number, the file won\'t be installed into the normal file table as usual but will be placed into the fixed file table at index *file_index - 1.* In this case, instead of returning a file descriptor, the result will contain either 0 on success or an error. If the index points to a valid empty slot, the installation is guaranteed to not fail. If there is already a file in the slot, it will be replaced, similar to **IORING_OP_FILES_UPDATE.** Please note that only io_uring has access to such files and no other syscall can use them. See **IOSQE_FIXED_FILE** and **IORING_REGISTER_FILES**.
+
+ Available since 5.15.
+
+**IORING_OP_OPENAT2**
+
+: Issue the equivalent of a **openat2**(2) system call. *fd* is the *dirfd* argument, *addr* must contain a pointer to the *\*pathname* argument, *len* should contain the size of the open_how structure, and *off* should be set to the address of the open_how structure. See also **openat2**(2) for the general description of the related system call. Available since 5.6.
+
+ If the *file_index* field is set to a positive number, the file won\'t be installed into the normal file table as usual but will be placed into the fixed file table at index *file_index - 1.* In this case, instead of returning a file descriptor, the result will contain either 0 on success or an error. If the index points to a valid empty slot, the installation is guaranteed to not fail. If there is already a file in the slot, it will be replaced, similar to **IORING_OP_FILES_UPDATE**. Please note that only io_uring has access to such files and no other syscall can use them. See **IOSQE_FIXED_FILE** and **IORING_REGISTER_FILES**.
+
+ Available since 5.15.
+
+**IORING_OP_CLOSE**
+
+: Issue the equivalent of a **close**(2) system call. *fd* is the file descriptor to be closed. See also **close**(2) for the general description of the related system call. Available since 5.6. If the *file_index* field is set to a positive number, this command can be used to close files that were direct opened through **IORING_OP_OPENAT**, **IORING_OP_OPENAT2**, or **IORING_OP_ACCEPT** using the io_uring specific direct descriptors. Note that only one of the descriptor fields may be set. The direct close feature is available since the 5.15 kernel, where direct descriptors were introduced.
+
+**IORING_OP_STATX**
+
+: Issue the equivalent of a **statx**(2) system call. *fd* is the *dirfd* argument, *addr* must contain a pointer to the *\*pathname* string, *statx_flags* is the *flags* argument, *len* should be the *mask* argument, and *off* must contain a pointer to the *statxbuf* to be filled in. See also **statx**(2) for the general description of the related system call. Available since 5.6.
+
+**IORING_OP_READ**
+
+:
+
+ **IORING_OP_WRITE**
+
+ : Issue the equivalent of a **pread**(2) or **pwrite**(2) system call. *fd* is the file descriptor to be operated on, *addr* contains the buffer in question, *len* contains the length of the IO operation, and *offs* contains the read or write offset. If *fd* does not refer to a seekable file, *off* must be set to zero or -1. If *offs* is set to **-1** , the offset will use (and advance) the file position, like the **read**(2) and **write**(2) system calls. These are non-vectored versions of the **IORING_OP_READV** and **IORING_OP_WRITEV** opcodes. See also **read**(2) and **write**(2) for the general description of the related system call. Available since 5.6.
+
+ **IORING_OP_SPLICE**
+
+ : Issue the equivalent of a **splice**(2) system call. *splice_fd_in* is the file descriptor to read from, *splice_off_in* is an offset to read from, *fd* is the file descriptor to write to, *off* is an offset from which to start writing to. A sentinel value of **-1** is used to pass the equivalent of a NULL for the offsets to **splice**(2). *len* contains the number of bytes to copy. *splice_flags* contains a bit mask for the flag field associated with the system call. Please note that one of the file descriptors must refer to a pipe. See also **splice**(2) for the general description of the related system call. Available since 5.7.
+
+ **IORING_OP_TEE**
+
+ : Issue the equivalent of a **tee**(2) system call. *splice_fd_in* is the file descriptor to read from, *fd* is the file descriptor to write to, *len* contains the number of bytes to copy, and *splice_flags* contains a bit mask for the flag field associated with the system call. Please note that both of the file descriptors must refer to a pipe. See also **tee**(2) for the general description of the related system call. Available since 5.8.
+
+ **IORING_OP_FILES_UPDATE**
+
+ : This command is an alternative to using **IORING_REGISTER_FILES_UPDATE** which then works in an async fashion, like the rest of the io_uring commands. The arguments passed in are the same. *addr* must contain a pointer to the array of file descriptors, *len* must contain the length of the array, and *off* must contain the offset at which to operate. Note that the array of file descriptors pointed to in *addr* must remain valid until this operation has completed. Available since 5.6.
+
+ **IORING_OP_PROVIDE_BUFFERS**
+
+ : This command allows an application to register a group of buffers to be used by commands that read/receive data. Using buffers in this manner can eliminate the need to separate the poll + read, which provides a convenient point in time to allocate a buffer for a given request. It\'s often infeasible to have as many buffers available as pending reads or receive. With this feature, the application can have its pool of buffers ready in the kernel, and when the file or socket is ready to read/receive data, a buffer can be selected for the operation. *fd* must contain the number of buffers to provide, *addr* must contain the starting address to add buffers from, *len* must contain the length of each buffer to add from the range, *buf_group* must contain the group ID of this range of buffers, and *off* must contain the starting buffer ID of this range of buffers. With that set, the kernel adds buffers starting with the memory address in *addr,* each with a length of *len.* Hence the application should provide *len \* fd* worth of memory in *addr.* Buffers are grouped by the group ID, and each buffer within this group will be identical in size according to the above arguments. This allows the application to provide different groups of buffers, and this is often used to have differently sized buffers available depending on what the expectations are of the individual request. When submitting a request that should use a provided buffer, the **IOSQE_BUFFER_SELECT** flag must be set, and *buf_group* must be set to the desired buffer group ID where the buffer should be selected from. Available since 5.7.
+
+ **IORING_OP_REMOVE_BUFFERS**
+
+ : Remove buffers previously registered with **IORING_OP_PROVIDE_BUFFERS**. *fd* must contain the number of buffers to remove, and *buf_group* must contain the buffer group ID from which to remove the buffers. Available since 5.7.
+
+ **IORING_OP_SHUTDOWN**
+
+ : Issue the equivalent of a **shutdown**(2) system call. *fd* is the file descriptor to the socket being shutdown, and *len* must be set to the *how* argument. No no other fields should be set. Available since 5.11.
+
+ **IORING_OP_RENAMEAT**
+
+ : Issue the equivalent of a **renameat2**(2) system call. *fd* should be set to the *olddirfd*, *addr* should be set to the *oldpath*, *len* should be set to the *newdirfd*, *addr* should be set to the *oldpath*, *addr2* should be set to the *newpath*, and finally *rename_flags* should be set to the *flags* passed in to **renameat2**(2). Available since 5.11.
+
+ **IORING_OP_UNLINKAT**
+
+ : Issue the equivalent of a **unlinkat**(2) system call. *fd* should be set to the *dirfd*, *addr* should be set to the *pathname*, and *unlink_flags* should be set to the *flags* being passed in to **unlinkat**(2). Available since 5.11.
+
+ **IORING_OP_MKDIRAT**
+
+ : Issue the equivalent of a **mkdirat**(2) system call. *fd* should be set to the *dirfd*, *addr* should be set to the *pathname*, and *len* should be set to the *mode* being passed in to **mkdirat**(2). Available since 5.15.
+
+ **IORING_OP_SYMLINKAT**
+
+ : Issue the equivalent of a **symlinkat**(2) system call. *fd* should be set to the *newdirfd*, *addr* should be set to the *target* and *addr2* should be set to the *linkpath* being passed in to **symlinkat**(2). Available since 5.15.
+
+ **IORING_OP_LINKAT**
+
+ : Issue the equivalent of a **linkat**(2) system call. *fd* should be set to the *olddirfd*, *addr* should be set to the *oldpath*, *len* should be set to the *newdirfd*, *addr2* should be set to the *newpath*, and *hardlink_flags* should be set to the *flags* being passed in to **linkat**(2). Available since 5.15.
+
+ **IORING_OP_MSG_RING**
+
+ : Send a message to an io_uring. *fd* must be set to a file descriptor of a ring that the application has access to, *len* can be set to any 32-bit value that the application wishes to pass on, and *off* should be set any 64-bit value that the application wishes to send. On the target ring, a CQE will be posted with the *res* field matching the *len* set, and a *user_data* field matching the *off* value being passed in. This request type can be used to either just wake or interrupt anyone waiting for completions on the target ring, or it can be used to pass messages via the two fields. Available since 5.18.
+
+ **IORING_OP_SOCKET**
+
+ : Issue the equivalent of a **socket**(2) system call. *fd* must contain the communication domain, *off* must contain the communication type, *len* must contain the protocol, and *rw_flags* is currently unused and must be set to zero. See also **socket**(2) for the general description of the related system call. Available since 5.19.
+
+ If the *file_index* field is set to a positive number, the file won\'t be installed into the normal file table as usual but will be placed into the fixed file table at index *file_index* - 1. In this case, instead of returning a file descriptor, the result will contain either 0 on success or an error. If the index points to a valid empty slot, the installation is guaranteed to not fail. If there is already a file in the slot, it will be replaced, similar to **IORING_OP_FILES_UPDATE**. Please note that only io_uring has access to such files and no other syscall can use them. See **IOSQE_FIXED_FILE** and **IORING_REGISTER_FILES**.
+
+ Available since 5.19.
+
+ **IORING_OP_URING_CMD**
+
+ : Issues an asynchronous, per-file private operation, similar to **ioctl**(2). Further information may be found in the dedicated man page of **IORING_OP_URING_CMD**.
+
+ Available since 5.19.
+
+ **IORING_OP_SEND_ZC**
+
+ : Issue the zerocopy equivalent of a **send(2)** system call. Similar to **IORING_OP_SEND**, but tries to avoid making intermediate copies of data. Zerocopy execution is not guaranteed and may fall back to copying. The request may also fail with **-EOPNOTSUPP**, when a protocol doesn\'t support zerocopy, in which case users are recommended to use copying sends instead.
+
+ The *flags* field of the first *struct io_uring_cqe* may likely contain **IORING_CQE_F_MORE**, which means that there will be a second completion event / notification for the request, with the *user_data* field set to the same value. The user must not modify the data buffer until the notification is posted. The first cqe follows the usual rules and so its *res* field will contain the number of bytes sent or a negative error code. The notification\'s *res* field will be set to zero and the *flags* field will contain **IORING_CQE_F_NOTIF**. The two step model is needed because the kernel may hold on to buffers for a long time, e.g. waiting for a TCP ACK, and having a separate cqe for request completions allows userspace to push more data without extra delays. Note, notifications are only responsible for controlling the lifetime of the buffers, and as such don\'t mean anything about whether the data has atually been sent out or received by the other end. Even errored requests may generate a notification, and the user must check for **IORING_CQE_F_MORE** rather than relying on the result.
+
+ *fd* must be set to the socket file descriptor, *addr* must contain a pointer to the buffer, *len* denotes the length of the buffer to send, and *msg_flags* holds the flags associated with the system call. When *addr2* is non-zero it points to the address of the target with *addr_len* specifying its size, turning the request into a **sendto**(2) system call equivalent.
+
+ Available since 6.0.
+
+ This command also supports the following modifiers in *ioprio:*
+
+**IORING_RECVSEND_POLL_FIRST** If set, io_uring will assume the socket is currently full and attempting to send data will be unsuccessful. For this case, io_uring will arm internal poll and trigger a send of the data when there is enough space available. This initial send attempt can be wasteful for the case where the socket is expected to be full, setting this flag will bypass the initial send attempt and go straight to arming poll. If poll does indicate that data can be sent, the operation will proceed.
+
+**IORING_RECVSEND_FIXED_BUF** If set, instructs io_uring to use a pre-mapped buffer. The *buf_index* field should contain an index into an array of fixed buffers. See **io_uring_register**(2) for details on how to setup a context for fixed buffer I/O.
+
+**IORING_OP_SENDMSG_ZC**
+
+: Issue the zerocopy equivalent of a **sendmsg**(2) system call. Works just like **IORING_OP_SENDMSG**, but like **IORING_OP_SEND_ZC** supports **IORING_RECVSEND_FIXED_BUF**. For additional notes regarding zero copy see **IORING_OP_SEND_ZC**.
+
+ Available since 6.1
+
+**IORING_OP_WAITID**
+
+: Issue the equivalent of a **waitid**(2) system call. *len* must contain the idtype being queried/waited for and *fd* must contain the \'pid\' (or id) being waited for. *file_index* is the \'options\' being set (the child state changes to wait for). *addr2* is a pointer to siginfo_t, if any, being filled in. See also **waitid**(2) for the general description of the related system call. Available since 6.5.
+
+**IORING_OP_SETXATTR**
+
+:
+
+ **IORING_OP_GETXATTR**
+
+ :
+
+ **IORING_OP_FSETXATTR**
+
+ :
+
+ **IORING_OP_FGETXATTR**
+
+ : Issue the equivalent of a **setxattr**(2) or **getxattr**(2) or **fsetxattr**(2) or **fgetxattr**(2) system call. *addr* must contain a pointer to a buffer containing the name of the extended attribute. *addr2* must contain a pointer to a buffer of maximum length *len*, in which the value of the extended attribute is to be placed or is read from. Additional flags maybe provided in *xattr_flags*. For **setxattr**(2) or **getxattr**(2) *addr3* must contain a pointer to the path of the file. For **fsetxattr**(2) or **fgetxattr**(2) *fd* must contain the file descriptor of the file.
+
+ Available since 5.19.
+
+ **IORING_OP_BIND**
+
+ : Issues the equivalent of the **bind**(2) system call. *fd* must contain the file descriptor of the socket, *addr* must contain a pointer to the sockaddr struct containing the address to assign and *addr2* must contain the length of the address.
+
+ Available since 6.11.
+
+ **IORING_OP_LISTEN**
+
+ : Issues the equivalent of the **listen**(2) system call. *fd* must contain the file descriptor of the socket and *len* must contain the backlog parameter, i.e. the maximum amount of pending queued connections.
+
+ Available since 6.11.
+
+ **IORING_OP_FTRUNCATE**
+
+ : Issues the equivalent of the **ftruncate**(2) system call. *fd* must contain the file descriptor of the file to truncate and *off* must contain the length to which the file will be truncated.
+
+ Available since 6.9.
+
+ **IORING_OP_READ_MULTISHOT**
+
+ : Like **IORING_OP_READ**, but similar to requests prepared with *io_uring_prep_multishot_accept*(3) additional reads and thus CQEs will be performed based on this single SQE once there is more data available. Is restricted to pollable files and will fall back to single shot if the file does not support **NOWAIT**. Like other multishot type requests, the application should look at the CQE flags and see if **IORING_CQE_F_MORE** is set on completion as an indication of whether or not the read request will generate further CQEs. Available since 6.7.
+
+ **IORING_OP_FUTEX_WAIT**
+
+ : Issues the equivalent of the **futex_wait**(2) system call. *addr* must hold a pointer to the futex, *addr2* must hold the value to which the futex has to be changed so this caller to **futex_wait**(2) can be woken by a call to **futex_wake**(2), *addr3* must hold the bitmask of this **futex_wait**(2) caller. For a caller of **futex_wake**(2) to wake a waiter additionally the bitmask of the waiter and waker must have at least one set bit in common. *fd* must contain additional flags passed in.
+
+ Available since 6.7.
+
+ **IORING_OP_FUTEX_WAKE**
+
+ : Issues the equivalent of the **futex_wake**(2) system call. *addr* must hold a pointer to the futex, *addr2* must hold the maximum number of waiters waiting on this futex to wake, *addr3* must hold the bitmask of this **futex_wake**(2) call. To wake a waiter additionally the bitmask of the waiter and waker must have at least one set bit in common. *fd* must contain additional flags passed in.
+
+ Available since 6.7.
+
+ **IORING_OP_FUTEX_WAITV**
+
+ : Issues the equivalent of the **futex_waitv**(2) system call. *addr* must hold a pointer to the futexv struct, *len* must hold the length of the futexv struct, which may not be 0 and must be smaller than **FUTEX_WAITV_MAX** (as of 6.11 == 128).
+
+ Available since 6.7.
+
+ **IORING_OP_FIXED_FD_INSTALL**
+
+ : This operation is used to insert a registered file into the regular process file table. Consequently *fd* must contain the file index and **IOSQE_FIXED_FILE** must be set. The resulting regular fd is returned via cqe-\>res. Additional flags may be passed in via *install_fd_flags*. Currently supported flags are: **IORING_FIXED_FD_NO_CLOEXEC**, which overrides a potentially set **O_CLOEXEC** flag set on the initial file.
+
+ Available since 6.8.
+
+ **IORING_OP_PIPE**
+
+ : This operation is used to create a pipe, a set of file descriptors that can be used for communication. The pipe may either be created as a set of normal file descriptors, or it can be created as fixed/direct descriptors. *addr* must contain a pointer to an array of two integers, where upon successful completion of the request, index 0 will contain the read side and index 1 the write side of the pipe. *pipe_flags* may contain flags associated with pipe creation. Currently **O_CLOEXEC \| O_NONBLOCK \| O_DIRECT \| O_NOTIFICATION_PIPE** are supported. *file_index* may contain the the desired starting point for a fixed descriptor pipe creation. If this is set to **0,** then regular file descriptors are used. If set to **IORING_FILE_INDEX_ALLOC,** then the kernel will allocate descriptors from the previously registered direct descriptor table. If set to any non-zero value, then it sets the exact direct descriptor value for index 0 of the pipe, and index 1 will be the following integer value.
+
+ If used with direct descriptors rather than normal file descriptors, a direct descriptor table must have been previously registered with the kernel.
+
+ Available since 6.16.
+
+ **IORING_OP_RECV_ZC**
+
+ : Receive data from a socket using zero-copy techniques. Unlike **IORING_OP_RECV**, this operation does not use a user-provided buffer. Instead, data is delivered through a pre-registered zero-copy RX interface queue. *fd* must be set to the socket file descriptor. *zcrx_ifq_idx* specifies the index of the registered zero-copy RX interface queue. *len* specifies the maximum amount of data to receive. *ioprio* can contain flags such as **IORING_RECVSEND_POLL_FIRST** and **IORING_RECV_MULTISHOT**. This operation requires multishot mode.
+
+ Before using this command, a zero-copy RX interface queue must be registered via **io_uring_register**(2) using **IORING_REGISTER_ZCRX_IFQ**. Data completions are posted as auxiliary CQEs.
+
+ Available since 6.15.
+
+ **IORING_OP_EPOLL_WAIT**
+
+ : Wait for events on an epoll instance. This is an async version of **epoll_wait**(2). *fd* must be set to the epoll file descriptor, *addr* must point to an array of *struct epoll_event* to receive the events, and *len* must contain the maximum number of events to return.
+
+ The primary use case is for legacy event loops that still use epoll for some file descriptors. By using io_uring to wait on epoll events, the application can unify its event handling through io_uring while maintaining backwards compatibility with epoll-based components.
+
+ Available since 6.15.
+
+ **IORING_OP_READV_FIXED**
+
+ :
+
+ **IORING_OP_WRITEV_FIXED**
+
+ : Vectored read and write operations using pre-registered buffers, combining the functionality of **IORING_OP_READV**/**IORING_OP_WRITEV** with **IORING_OP_READ_FIXED**/**IORING_OP_WRITE_FIXED**. The *buf_index* field specifies the index into the registered buffer table. Unlike the non-fixed vectored operations, the iovec entries point into the registered buffer region. This allows vectored I/O while still benefiting from the reduced overhead of pre-registered buffers.
+
+ Available since 6.15.
+
+ **IORING_OP_NOP128**
+
+ : No operation, similar to **IORING_OP_NOP**, but explicitly uses a 128-byte SQE. This can be useful for testing or alignment purposes when using mixed 64/128-byte SQE rings (**IORING_SETUP_SQE_MIXED**).
+
+ Available since 6.19.
+
+ **IORING_OP_URING_CMD128**
+
+ : Passthrough command to the underlying file, identical to **IORING_OP_URING_CMD**, but explicitly uses a 128-byte SQE. The extra 64 bytes provide additional space for command-specific data. This is useful with **IORING_SETUP_SQE_MIXED** rings where some commands need the larger SQE size while others do not.
+
+ See **IORING_OP_URING_CMD** for general usage details.
+
+ Available since 6.19.
+
+The *flags* field is a bit mask. The supported flags are:
+
+**IOSQE_FIXED_FILE**
+
+: When this flag is specified, *fd* is an index into the files array registered with the io_uring instance (see the **IORING_REGISTER_FILES** section of the **io_uring_register**(2) man page). Note that this isn\'t always available for all commands. If used on a command that doesn\'t support fixed files, the SQE will error with **-EBADF**. Available since 5.1.
+
+**IOSQE_IO_DRAIN**
+
+: When this flag is specified, the SQE will not be started before previously submitted SQEs have completed, and new SQEs will not be started before this one completes. Available since 5.2.
+
+**IOSQE_IO_LINK**
+
+: When this flag is specified, the SQE forms a link with the next SQE in the submission ring. That next SQE will not be started before the previous request completes. This, in effect, forms a chain of SQEs, which can be arbitrarily long. The tail of the chain is denoted by the first SQE that does not have this flag set. Chains are not supported across submission boundaries. Even if the last SQE in a submission has this flag set, it will still terminate the current chain. This flag has no effect on previous SQE submissions, nor does it impact SQEs that are outside of the chain tail. This means that multiple chains can be executing in parallel, or chains and individual SQEs. Only members inside the chain are serialized. A chain of SQEs will be broken if any request in that chain ends in error. io_uring considers any unexpected result an error. This means that, eg, a short read will also terminate the remainder of the chain. If a chain of SQE links is broken, the remaining unstarted part of the chain will be terminated and completed with **-ECANCELED** as the error code. Available since 5.3.
+
+**IOSQE_IO_HARDLINK**
+
+: Like IOSQE_IO_LINK, but it doesn\'t sever regardless of the completion result. Note that the link will still sever if we fail submitting the parent request, hard links are only resilient in the presence of completion results for requests that did submit correctly. **IOSQE_IO_HARDLINK** implies **IOSQE_IO_LINK**. Available since 5.5.
+
+**IOSQE_ASYNC**
+
+: Normal operation for io_uring is to try and issue an sqe as non-blocking first, and if that fails, execute it in an async manner. To support more efficient overlapped operation of requests that the application knows/assumes will always (or most of the time) block, the application can ask for an sqe to be issued async from the start. Available since 5.6.
+
+**IOSQE_BUFFER_SELECT**
+
+: Used in conjunction with the **IORING_OP_PROVIDE_BUFFERS** command, which registers a pool of buffers to be used by commands that read or receive data. When buffers are registered for this use case, and this flag is set in the command, io_uring will grab a buffer from this pool when the request is ready to receive or read data. If successful, the resulting CQE will have **IORING_CQE_F_BUFFER** set in the flags part of the struct, and the upper **IORING_CQE_BUFFER_SHIFT** bits will contain the ID of the selected buffers. This allows the application to know exactly which buffer was selected for the operation. If no buffers are available and this flag is set, then the request will fail with **-ENOBUFS** as the error code. Once a buffer has been used, it is no longer available in the kernel pool. The application must re-register the given buffer again when it is ready to recycle it (eg has completed using it). Available since 5.7.
+
+**IOSQE_CQE_SKIP_SUCCESS**
+
+: Don\'t generate a CQE if the request completes successfully. If the request fails, an appropriate CQE will be posted as usual and if there is no **IOSQE_IO_HARDLINK,** CQEs for all linked requests will be omitted. The notion of failure/success is opcode specific and is the same as with breaking chains of **IOSQE_IO_LINK**. One special case is when the request has a linked timeout, then the CQE generation for the linked timeout is decided solely by whether it has **IOSQE_CQE_SKIP_SUCCESS** set, regardless whether it timed out or was canceled. In other words, if a linked timeout has the flag set, it\'s guaranteed to not post a CQE.
+
+ The semantics are chosen to accommodate several use cases. First, when all but the last request of a normal link without linked timeouts are marked with the flag, only one CQE per link is posted. Additionally, it enables suppression of CQEs in cases where the side effects of a successfully executed operation is enough for userspace to know the state of the system. One such example would be writing to a synchronisation file.
+
+ This flag is incompatible with **IOSQE_IO_DRAIN**. Using both of them in a single ring is undefined behavior, even when they are not used together in a single request. Currently, after the first request with **IOSQE_CQE_SKIP_SUCCESS**, all subsequent requests marked with drain will be failed at submission time. Note that the error reporting is best effort only, and restrictions may change in the future.
+
+ Available since 5.17.
+
+*ioprio* specifies the I/O priority. See **ioprio_get**(2) for a description of Linux I/O priorities.
+
+*fd* specifies the file descriptor against which the operation will be performed, with the exception noted above.
+
+If the operation is one of **IORING_OP_READ_FIXED** or **IORING_OP_WRITE_FIXED**, *addr* and *len* must fall within the buffer located at *buf_index* in the fixed buffer array. If the operation is either **IORING_OP_READV** or **IORING_OP_WRITEV**, then *addr* points to an iovec array of *len* entries.
+
+*rw_flags*, specified for read and write operations, contains a bitwise OR of per-I/O flags, as described in the **preadv2**(2) man page.
+
+The *fsync_flags* bit mask may contain either 0, for a normal file integrity sync, or **IORING_FSYNC_DATASYNC** to provide data sync only semantics. See the descriptions of **O_SYNC** and **O_DSYNC** in the **open**(2) manual page for more information.
+
+The bits that may be set in *poll_events* are defined in *\<poll.h\>*, and documented in **poll**(2).
+
+*user_data* is an application-supplied value that will be copied into the completion queue entry (see below). *buf_index* is an index into an array of fixed buffers, and is only valid if fixed buffers were registered. *personality* is the credentials id to use for this operation. See **io_uring_register**(2) for how to register personalities with io_uring. If set to 0, the current personality of the submitting task is used.
+
+Once the submission queue entry is initialized, I/O is submitted by placing the index of the submission queue entry into the tail of the submission queue. After one or more indexes are added to the queue, and the queue tail is advanced, the **io_uring_enter**(2) system call can be invoked to initiate the I/O.
+
+Completions use the following data structure:
+
+ /*
+ * IO completion data structure (Completion Queue Entry)
+ */
+ struct io_uring_cqe {
+ __u64 user_data; /* sqe->data submission passed back */
+ __s32 res; /* result code for this event */
+ __u32 flags;
+ };
+
+*user_data* is copied from the field of the same name in the submission queue entry. The primary use case is to store data that the application will need to access upon completion of this particular I/O. The *flags* is used for certain commands, like **IORING_OP_POLL_ADD** or in conjunction with **IOSQE_BUFFER_SELECT** or **IORING_OP_MSG_RING**, see those entries for details. *res* is the operation-specific result, but io_uring-specific errors (e.g. flags or opcode invalid) are returned through this field. They are described in section **CQE** **ERRORS**.
+
+For read and write opcodes, the return values match *errno* values documented in the **preadv2**(2) and **pwritev2**(2) man pages, with *res* holding the equivalent of *-errno* for error cases, or the transferred number of bytes in case the operation is successful. Hence both error and success return can be found in that field in the CQE. For other request types, the return values are documented in the matching man page for that type, or in the opcodes section above for io_uring-specific opcodes.
+
+# RETURN VALUE
+
+**io_uring_enter**(2) returns the number of I/Os successfully consumed. This can be zero if *to_submit* was zero or if the submission queue was empty. Note that if the ring was created with **IORING_SETUP_SQPOLL** specified, then the return value will generally be the same as *to_submit* as submission happens outside the context of the system call.
+
+The errors related to a submission queue entry will be returned through a completion queue entry (see section **CQE** **ERRORS**), rather than through the system call itself.
+
+Errors that occur not on behalf of a submission queue entry are returned via the system call directly. On such an error, a negative error code is returned. The caller should not rely on *errno* variable.
+
+# ERRORS
+
+These are the errors returned by **io_uring_enter**(2) system call.
+
+**EAGAIN**
+
+: The kernel was unable to allocate memory for the request, or otherwise ran out of resources to handle it. The application should wait for some completions and try again.
+
+**EBADF**
+
+: *fd* is not a valid file descriptor.
+
+**EBADFD**
+
+: *fd* is a valid file descriptor, but the io_uring ring is not in the right state (enabled). See **io_uring_register**(2) for details on how to enable the ring.
+
+**EBADR**
+
+: At least one CQE was dropped even with the **IORING_FEAT_NODROP** feature, and there are no otherwise available CQEs. This clears the error state and so with no other changes the next call to **io_uring_enter**(2) will not have this error. This error should be extremely rare and indicates the machine is running critically low on memory. It may be reasonable for the application to terminate running unless it is able to safely handle any CQE being lost.
+
+**EBUSY**
+
+: If the **IORING_FEAT_NODROP** feature flag is set, then **EBUSY** will be returned if there were overflow entries, **IORING_ENTER_GETEVENTS** flag is set and not all of the overflow entries were able to be flushed to the CQ ring.
+
+ Without **IORING_FEAT_NODROP** the application is attempting to overcommit the number of requests it can have pending. The application should wait for some completions and try again. May occur if the application tries to queue more requests than we have room for in the CQ ring, or if the application attempts to wait for more events without having reaped the ones already present in the CQ ring.
+
+**EEXIST**
+
+: The thread submitting the work is invalid. This may occur if **IORING_ENTER_GETEVENTS** and **IORING_SETUP_DEFER_TASKRUN** is set, but the submitting thread is not the thread that initially created or enabled the io_uring associated with *fd.*
+
+**EINVAL**
+
+: Some bits in the *flags* argument are invalid.
+
+**EFAULT**
+
+: An invalid user space address was specified for the *sig* argument.
+
+**ENXIO**
+
+: The io_uring instance is in the process of being torn down.
+
+**EOPNOTSUPP**
+
+: *fd* does not refer to an io_uring instance.
+
+**EINTR**
+
+: The operation was interrupted by a delivery of a signal before it could complete; see **signal**(7). Can happen while waiting for events with **IORING_ENTER_GETEVENTS.**
+
+**EOWNERDEAD**
+
+: The ring has been setup with **IORING_SETUP_SQPOLL** and the sq poll kernel thread has been killed.
+
+# CQE ERRORS
+
+These io_uring-specific errors are returned as a negative value in the *res* field of the completion queue entry.
+
+**EACCES**
+
+: The *flags* field or *opcode* in a submission queue entry is not allowed due to registered restrictions. See **io_uring_register**(2) for details on how restrictions work.
+
+**EBADF**
+
+: The *fd* field in the submission queue entry is invalid, or the **IOSQE_FIXED_FILE** flag was set in the submission queue entry, but no files were registered with the io_uring instance.
+
+**EFAULT**
+
+: buffer is outside of the process\' accessible address space
+
+**EFAULT**
+
+: **IORING_OP_READ_FIXED** or **IORING_OP_WRITE_FIXED** was specified in the *opcode* field of the submission queue entry, but either buffers were not registered for this io_uring instance, or the address range described by *addr* and *len* does not fit within the buffer registered at *buf_index*.
+
+**EINVAL**
+
+: The *flags* field or *opcode* in a submission queue entry is invalid.
+
+**EINVAL**
+
+: The *buf_index* member of the submission queue entry is invalid.
+
+**EINVAL**
+
+: The *personality* field in a submission queue entry is invalid.
+
+**EINVAL**
+
+: **IORING_OP_READV** or **IORING_OP_WRITEV** was specified in the submission queue entry, but the io_uring instance has fixed buffers registered.
+
+**EINVAL**
+
+: **IORING_OP_READ_FIXED** or **IORING_OP_WRITE_FIXED** was specified in the submission queue entry, and the *buf_index* is invalid.
+
+**EINVAL**
+
+: **IORING_OP_READV**, **IORING_OP_WRITEV**, **IORING_OP_READ_FIXED**, **IORING_OP_WRITE_FIXED** or **IORING_OP_FSYNC** was specified in the submission queue entry, but the io_uring instance was configured for IOPOLLing, or any of *addr*, *ioprio*, *off*, *len*, or *buf_index* was set in the submission queue entry.
+
+**EINVAL**
+
+: **IORING_OP_POLL_ADD** or **IORING_OP_POLL_REMOVE** was specified in the *opcode* field of the submission queue entry, but the io_uring instance was configured for busy-wait polling (**IORING_SETUP_IOPOLL**), or any of *ioprio*, *off*, *len*, or *buf_index* was non-zero in the submission queue entry.
+
+**EINVAL**
+
+: **IORING_OP_POLL_ADD** was specified in the *opcode* field of the submission queue entry, and the *addr* field was non-zero.
+
+**EOPNOTSUPP**
+
+: *opcode* is valid, but not supported by this kernel.
+
+**EOPNOTSUPP**
+
+: **IOSQE_BUFFER_SELECT** was set in the *flags* field of the submission queue entry, but the *opcode* doesn\'t support buffer selection.
+
+**EINVAL**
+
+: **IORING_OP_TIMEOUT** was specified, but *timeout_flags* specified more than one clock source or **IORING_TIMEOUT_MULTISHOT** was set alongside **IORING_TIMEOUT_ABS**.
diff --git a/man/io_uring_enter2.2 b/man/io_uring_enter2.2
deleted file mode 120000
index 5566c093..00000000
--- a/man/io_uring_enter2.2
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_enter.2
\ No newline at end of file
diff --git a/man/io_uring_for_each_cqe.3 b/man/io_uring_for_each_cqe.3
deleted file mode 100644
index 78d8f6fc..00000000
--- a/man/io_uring_for_each_cqe.3
+++ /dev/null
@@ -1,63 +0,0 @@
-.\" Copyright (C) 2023 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_for_each_cqe 3 "June 04, 2023" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_for_each_cqe \- iterate pending completion events
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "io_uring_for_each_cqe(struct io_uring *" ring ","
-.BI " unsigned " head ","
-.BI " struct io_uring_cqe *" cqe ") { }
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_for_each_cqe (3)
-is a macro helper that iterates completion events belonging to the
-.I ring
-using
-.I head
-as a temporary iterator, and points
-.I cqe
-to each pending event when iterating.
-
-This helper provides an efficient way to iterate all pending events in
-the ring, and then advancing the CQ ring by calling
-.BR io_uring_cq_advance (3)
-with the number of CQEs consumed when done. As updating the kernel visible
-CQ ring state involves an ordered write, doing it once for a number of
-events is more efficient than handling each completion separately and
-calling
-.BR io_uring_cqe_seen (3)
-for each of them.
-
-.SH EXAMPLE
-.EX
-void handle_cqes(struct io_uring *ring)
-{
- struct io_uring_cqe *cqe;
- unsigned head;
- unsigned i = 0;
-
- io_uring_for_each_cqe(ring, head, cqe) {
- /* handle completion */
- printf("cqe: %d\\n", cqe->res);
- i++;
- }
-
- io_uring_cq_advance(ring, i);
-}
-.EE
-
-.SH RETURN VALUE
-None
-.SH SEE ALSO
-.BR io_uring_wait_cqe_timeout (3),
-.BR io_uring_wait_cqe (3),
-.BR io_uring_wait_cqes (3),
-.BR io_uring_cqe_seen (3),
-.BR io_uring_buf_ring_cq_advance (3)
diff --git a/man/io_uring_for_each_cqe.3.md b/man/io_uring_for_each_cqe.3.md
new file mode 100644
index 00000000..e3933c5f
--- /dev/null
+++ b/man/io_uring_for_each_cqe.3.md
@@ -0,0 +1,54 @@
+.\" Copyright (C) 2023 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: June 04, 2023
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_for_each_cqe
+---
+
+# NAME
+
+io_uring_for_each_cqe - iterate pending completion events
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ io_uring_for_each_cqe(struct io_uring * ring ,
+ unsigned head ,
+ struct io_uring_cqe * cqe ) { }
+
+# DESCRIPTION
+
+The **io_uring_for_each_cqe**(3) is a macro helper that iterates completion events belonging to the *ring* using *head* as a temporary iterator, and points *cqe* to each pending event when iterating.
+
+This helper provides an efficient way to iterate all pending events in the ring, and then advancing the CQ ring by calling **io_uring_cq_advance**(3) with the number of CQEs consumed when done. As updating the kernel visible CQ ring state involves an ordered write, doing it once for a number of events is more efficient than handling each completion separately and calling **io_uring_cqe_seen**(3) for each of them.
+
+# EXAMPLE
+
+ void handle_cqes(struct io_uring *ring)
+ {
+ struct io_uring_cqe *cqe;
+ unsigned head;
+ unsigned i = 0;
+
+ io_uring_for_each_cqe(ring, head, cqe) {
+ /* handle completion */
+ printf("cqe: %d\n", cqe->res);
+ i++;
+ }
+
+ io_uring_cq_advance(ring, i);
+ }
+
+# RETURN VALUE
+
+None
+
+# SEE ALSO
+
+**io_uring_wait_cqe_timeout**(3), **io_uring_wait_cqe**(3), **io_uring_wait_cqes**(3), **io_uring_cqe_seen**(3), **io_uring_buf_ring_cq_advance**(3)
diff --git a/man/io_uring_free_buf_ring.3 b/man/io_uring_free_buf_ring.3
deleted file mode 100644
index 649cabb3..00000000
--- a/man/io_uring_free_buf_ring.3
+++ /dev/null
@@ -1,53 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_free_buf_ring 3 "Mar 07, 2023" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_free_buf_ring \- register and free a buffer ring for provided buffers
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_free_buf_ring(struct io_uring *" ring ",
-.BI " struct io_uring_buf_ring *" br ",
-.BI " unsigned int " nentries ",
-.BI " int " bgid ");"
-.BI "
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_free_buf_ring (3)
-function unregisters a previously registered shared buffer ring. The ring must
-have heen previously returned from
-.BR io_uring_setup_buf_ring (3) .
-
-The
-.I ring
-argument must pointer to the ring for which the provided buffer ring is being
-registered,
-.I br
-must point to a buffer ring previously returned by
-.BR io_uring_setup_buf_ring (3) ,
-.I nentries
-is the number of entries requested in the buffer ring, and
-.I bgid
-is the buffer group ID that
-.I br
-was setup with.
-
-Under the covers, this function uses
-.BR io_uring_unregister_buf_ring (3)
-to unregister the ring, and handles the freeing of the ring rather than
-letting the application open code it.
-
-Available since 5.19.
-
-.SH RETURN VALUE
-On success
-.BR io_uring_free_buf_ring (3)
-returns zero. On failure it returns
-.BR -errno .
-.SH SEE ALSO
-.BR io_uring_setup_buf_ring (3)
diff --git a/man/io_uring_free_buf_ring.3.md b/man/io_uring_free_buf_ring.3.md
new file mode 100644
index 00000000..cca8e7b4
--- /dev/null
+++ b/man/io_uring_free_buf_ring.3.md
@@ -0,0 +1,43 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: Mar 07, 2023
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_free_buf_ring
+---
+
+# NAME
+
+io_uring_free_buf_ring - register and free a buffer ring for provided buffers
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_free_buf_ring(struct io_uring * ring ,
+ struct io_uring_buf_ring * br ,
+ unsigned int nentries ,
+ int bgid );
+
+
+# DESCRIPTION
+
+The **io_uring_free_buf_ring**(3) function unregisters a previously registered shared buffer ring. The ring must have heen previously returned from **io_uring_setup_buf_ring**(3)**.**
+
+The *ring* argument must pointer to the ring for which the provided buffer ring is being registered, *br* must point to a buffer ring previously returned by **io_uring_setup_buf_ring**(3)**,** *nentries* is the number of entries requested in the buffer ring, and *bgid* is the buffer group ID that *br* was setup with.
+
+Under the covers, this function uses **io_uring_unregister_buf_ring**(3) to unregister the ring, and handles the freeing of the ring rather than letting the application open code it.
+
+Available since 5.19.
+
+# RETURN VALUE
+
+On success **io_uring_free_buf_ring**(3) returns zero. On failure it returns **-errno**.
+
+# SEE ALSO
+
+**io_uring_setup_buf_ring**(3)
diff --git a/man/io_uring_free_probe.3 b/man/io_uring_free_probe.3
deleted file mode 100644
index 960fda39..00000000
--- a/man/io_uring_free_probe.3
+++ /dev/null
@@ -1,27 +0,0 @@
-.\" Copyright (C) 2022 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_free_probe 3 "January 25, 2022" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_free_probe \- free probe instance
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_free_probe(struct io_uring_probe *" probe ");"
-.fi
-.SH DESCRIPTION
-.PP
-The function
-.BR io_uring_free_probe (3)
-frees the
-.I probe
-instance allocated with the
-.BR io_uring_get_probe (3)
-function.
-
-.SH RETURN VALUE
-None
-.SH SEE ALSO
-.BR io_uring_get_probe (3)
diff --git a/man/io_uring_free_probe.3.md b/man/io_uring_free_probe.3.md
new file mode 100644
index 00000000..1647cef7
--- /dev/null
+++ b/man/io_uring_free_probe.3.md
@@ -0,0 +1,33 @@
+.\" Copyright (C) 2022 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 25, 2022
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_free_probe
+---
+
+# NAME
+
+io_uring_free_probe - free probe instance
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_free_probe(struct io_uring_probe * probe );
+
+# DESCRIPTION
+
+The function **io_uring_free_probe**(3) frees the *probe* instance allocated with the **io_uring_get_probe**(3) function.
+
+# RETURN VALUE
+
+None
+
+# SEE ALSO
+
+**io_uring_get_probe**(3)
diff --git a/man/io_uring_get_events.3 b/man/io_uring_get_events.3
deleted file mode 100644
index f2415423..00000000
--- a/man/io_uring_get_events.3
+++ /dev/null
@@ -1,33 +0,0 @@
-.\" Copyright (C) 2022 Dylan Yudaken
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_get_events 3 "September 5, 2022" "liburing-2.3" "liburing Manual"
-.SH NAME
-io_uring_get_events \- Flush outstanding requests to CQE ring
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_get_events(struct io_uring *" ring ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_get_events (3)
-function runs outstanding work and flushes completion events to the CQE ring.
-
-There can be events needing to be flushed if the ring was full and had overflowed.
-Alternatively if the ring was setup with the
-.BR IORING_SETUP_DEFER_TASKRUN
-flag then this will process outstanding tasks, possibly resulting in more CQEs.
-
-.SH RETURN VALUE
-On success
-.BR io_uring_get_events (3)
-returns 0. On failure it returns
-.BR -errno .
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit_and_get_events (3),
-.BR io_uring_cq_has_overflow (3)
diff --git a/man/io_uring_get_events.3.md b/man/io_uring_get_events.3.md
new file mode 100644
index 00000000..fc1abbdb
--- /dev/null
+++ b/man/io_uring_get_events.3.md
@@ -0,0 +1,35 @@
+.\" Copyright (C) 2022 Dylan Yudaken
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: September 5, 2022
+footer: liburing-2.3
+header: liburing Manual
+section: 3
+title: io_uring_get_events
+---
+
+# NAME
+
+io_uring_get_events - Flush outstanding requests to CQE ring
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_get_events(struct io_uring * ring );
+
+# DESCRIPTION
+
+The **io_uring_get_events**(3) function runs outstanding work and flushes completion events to the CQE ring.
+
+There can be events needing to be flushed if the ring was full and had overflowed. Alternatively if the ring was setup with the **IORING_SETUP_DEFER_TASKRUN** flag then this will process outstanding tasks, possibly resulting in more CQEs.
+
+# RETURN VALUE
+
+On success **io_uring_get_events**(3) returns 0. On failure it returns **-errno**.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit_and_get_events**(3), **io_uring_cq_has_overflow**(3)
diff --git a/man/io_uring_get_probe.3 b/man/io_uring_get_probe.3
deleted file mode 100644
index 353cc731..00000000
--- a/man/io_uring_get_probe.3
+++ /dev/null
@@ -1,30 +0,0 @@
-.\" Copyright (C) 2022 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_get_probe 3 "January 25, 2022" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_get_probe \- get probe instance
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "io_uring_probe *io_uring_get_probe(void);"
-.fi
-.SH DESCRIPTION
-.PP
-The function
-.BR io_uring_get_probe (3)
-returns an allocated io_uring_probe structure to the caller. The caller is
-responsible for freeing the structure with the function
-.BR io_uring_free_probe (3).
-
-.SH NOTES
-Earlier versions of the Linux kernel do not support probe. If the kernel
-doesn't support probe, this function will return NULL.
-
-.SH RETURN VALUE
-On success it returns an allocated io_uring_probe structure, otherwise
-it returns NULL.
-.SH SEE ALSO
-.BR io_uring_free_probe (3)
diff --git a/man/io_uring_get_probe.3.md b/man/io_uring_get_probe.3.md
new file mode 100644
index 00000000..c2eb8cad
--- /dev/null
+++ b/man/io_uring_get_probe.3.md
@@ -0,0 +1,37 @@
+.\" Copyright (C) 2022 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 25, 2022
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_get_probe
+---
+
+# NAME
+
+io_uring_get_probe - get probe instance
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ io_uring_probe *io_uring_get_probe(void);
+
+# DESCRIPTION
+
+The function **io_uring_get_probe**(3) returns an allocated io_uring_probe structure to the caller. The caller is responsible for freeing the structure with the function **io_uring_free_probe**(3).
+
+# NOTES
+
+Earlier versions of the Linux kernel do not support probe. If the kernel doesn\'t support probe, this function will return NULL.
+
+# RETURN VALUE
+
+On success it returns an allocated io_uring_probe structure, otherwise it returns NULL.
+
+# SEE ALSO
+
+**io_uring_free_probe**(3)
diff --git a/man/io_uring_get_probe_ring.3 b/man/io_uring_get_probe_ring.3
deleted file mode 100644
index 63490743..00000000
--- a/man/io_uring_get_probe_ring.3
+++ /dev/null
@@ -1,39 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_get_probe_ring 3 "January 18, 2025" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_get_probe_ring \- get probe information from an existing ring
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "struct io_uring_probe *io_uring_get_probe_ring(struct io_uring *" ring ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_get_probe_ring (3)
-function returns probe information for the io_uring instance specified by
-.IR ring .
-This allows the application to determine which opcodes are supported by
-the kernel.
-
-The returned probe structure and must be freed by the application using
-.BR io_uring_free_probe (3)
-when no longer needed.
-
-This function is similar to
-.BR io_uring_get_probe (3),
-except it uses an existing ring instead of creating a temporary one.
-
-.SH RETURN VALUE
-Returns a pointer to an allocated
-.I struct io_uring_probe
-on success, or NULL on failure.
-.SH SEE ALSO
-.BR io_uring_get_probe (3),
-.BR io_uring_free_probe (3),
-.BR io_uring_opcode_supported (3),
-.BR io_uring_register_probe (3)
diff --git a/man/io_uring_get_probe_ring.3.md b/man/io_uring_get_probe_ring.3.md
new file mode 100644
index 00000000..6166c124
--- /dev/null
+++ b/man/io_uring_get_probe_ring.3.md
@@ -0,0 +1,37 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_get_probe_ring
+---
+
+# NAME
+
+io_uring_get_probe_ring - get probe information from an existing ring
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ struct io_uring_probe *io_uring_get_probe_ring(struct io_uring * ring );
+
+# DESCRIPTION
+
+The **io_uring_get_probe_ring**(3) function returns probe information for the io_uring instance specified by *ring*. This allows the application to determine which opcodes are supported by the kernel.
+
+The returned probe structure and must be freed by the application using **io_uring_free_probe**(3) when no longer needed.
+
+This function is similar to **io_uring_get_probe**(3), except it uses an existing ring instead of creating a temporary one.
+
+# RETURN VALUE
+
+Returns a pointer to an allocated *struct io_uring_probe* on success, or NULL on failure.
+
+# SEE ALSO
+
+**io_uring_get_probe**(3), **io_uring_free_probe**(3), **io_uring_opcode_supported**(3), **io_uring_register_probe**(3)
diff --git a/man/io_uring_get_sqe.3 b/man/io_uring_get_sqe.3
deleted file mode 100644
index b257ebb3..00000000
--- a/man/io_uring_get_sqe.3
+++ /dev/null
@@ -1,57 +0,0 @@
-.\" Copyright (C) 2020 Jens Axboe <axboe@kernel.dk>
-.\" Copyright (C) 2020 Red Hat, Inc.
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_get_sqe 3 "July 10, 2020" "liburing-0.7" "liburing Manual"
-.SH NAME
-io_uring_get_sqe \- get the next available submission queue entry from the
-submission queue
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "struct io_uring_sqe *io_uring_get_sqe(struct io_uring *" ring ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_get_sqe (3)
-function gets the next available submission queue entry from the submission
-queue belonging to the
-.I ring
-param.
-
-On success
-.BR io_uring_get_sqe (3)
-returns a pointer to the submission queue entry. On failure NULL is returned.
-
-If a submission queue entry is returned, it should be filled out via one of the
-prep functions such as
-.BR io_uring_prep_read (3)
-and submitted via
-.BR io_uring_submit (3).
-
-Note that neither
-.BR io_uring_get_sqe
-nor the prep functions set (or clear) the
-.B user_data
-field of the SQE. If the caller expects
-.BR io_uring_cqe_get_data (3)
-or
-.BR io_uring_cqe_get_data64 (3)
-to return valid data when reaping IO completions, either
-.BR io_uring_sqe_set_data (3)
-or
-.BR io_uring_sqe_set_data64 (3)
-.B MUST
-have been called before submitting the request.
-
-.SH RETURN VALUE
-.BR io_uring_get_sqe (3)
-returns a pointer to the next submission queue event on success and NULL on
-failure. If NULL is returned, the SQ ring is currently full and entries must
-be submitted for processing before new ones can get allocated.
-.SH SEE ALSO
-.BR io_uring_submit (3),
-.BR io_uring_sqe_set_data (3)
diff --git a/man/io_uring_get_sqe.3.md b/man/io_uring_get_sqe.3.md
new file mode 100644
index 00000000..98ed9355
--- /dev/null
+++ b/man/io_uring_get_sqe.3.md
@@ -0,0 +1,40 @@
+.\" Copyright (C) 2020 Jens Axboe <axboe@kernel.dk>
+.\" Copyright (C) 2020 Red Hat, Inc.
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: July 10, 2020
+footer: liburing-0.7
+header: liburing Manual
+section: 3
+title: io_uring_get_sqe
+---
+
+# NAME
+
+io_uring_get_sqe - get the next available submission queue entry from the submission queue
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ struct io_uring_sqe *io_uring_get_sqe(struct io_uring * ring );
+
+# DESCRIPTION
+
+The **io_uring_get_sqe**(3) function gets the next available submission queue entry from the submission queue belonging to the *ring* param.
+
+On success **io_uring_get_sqe**(3) returns a pointer to the submission queue entry. On failure NULL is returned.
+
+If a submission queue entry is returned, it should be filled out via one of the prep functions such as **io_uring_prep_read**(3) and submitted via **io_uring_submit**(3).
+
+Note that neither **io_uring_get_sqe** nor the prep functions set (or clear) the **user_data** field of the SQE. If the caller expects **io_uring_cqe_get_data**(3) or **io_uring_cqe_get_data64**(3) to return valid data when reaping IO completions, either **io_uring_sqe_set_data**(3) or **io_uring_sqe_set_data64**(3) **MUST** have been called before submitting the request.
+
+# RETURN VALUE
+
+**io_uring_get_sqe**(3) returns a pointer to the next submission queue event on success and NULL on failure. If NULL is returned, the SQ ring is currently full and entries must be submitted for processing before new ones can get allocated.
+
+# SEE ALSO
+
+**io_uring_submit**(3), **io_uring_sqe_set_data**(3)
diff --git a/man/io_uring_get_sqe128.3 b/man/io_uring_get_sqe128.3
deleted file mode 100644
index 1acc82f9..00000000
--- a/man/io_uring_get_sqe128.3
+++ /dev/null
@@ -1,67 +0,0 @@
-.\" Copyright (C) 2020 Jens Axboe <axboe@kernel.dk>
-.\" Copyright (C) 2020 Red Hat, Inc.
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_get_sqe128 3 "October 22, 2025" "liburing-2.13" "liburing Manual"
-.SH NAME
-io_uring_get_sqe128 \- get the next available 128-byte submission queue entry
-from the submission queue
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "struct io_uring_sqe *io_uring_get_sqe128(struct io_uring *" ring ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_get_sqe128 (3)
-function gets the next available 128-byte submission queue entry from the
-submission queue belonging to the
-.I ring
-param.
-
-On success
-.BR io_uring_get_sqe128 (3)
-returns a pointer to the submission queue entry. On failure
-.B NULL
-is returned.
-
-If a submission queue entry is returned, it should be filled out via one of the
-prep functions such as
-.BR io_uring_prep_uring_cmd128 (3)
-and submitted via
-.BR io_uring_submit (3).
-
-Note that neither
-.BR io_uring_get_sqe128 (3)
-nor the prep functions set (or clear) the
-.B user_data
-field of the SQE. If the caller expects
-.BR io_uring_cqe_get_data (3)
-or
-.BR io_uring_cqe_get_data64 (3)
-to return valid data when reaping IO completions, either
-.BR io_uring_sqe_set_data (3)
-or
-.BR io_uring_sqe_set_data64 (3)
-.B MUST
-have been called before submitting the request.
-
-.SH RETURN VALUE
-.BR io_uring_get_sqe128 (3)
-returns a pointer to the next submission queue event on success and NULL on
-failure. If
-.B NULL
-is returned, the SQ ring either wasn't created with support for 128-byte SQE
-entries (
-.B IORING_SETUP_SQE128
-or
-.B IORING_SETUP_SQE_MIXED
-) or is currently full and entries must be submitted for processing before new
-ones can get allocated.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_sqe_set_data (3)
diff --git a/man/io_uring_get_sqe128.3.md b/man/io_uring_get_sqe128.3.md
new file mode 100644
index 00000000..54af8e4b
--- /dev/null
+++ b/man/io_uring_get_sqe128.3.md
@@ -0,0 +1,40 @@
+.\" Copyright (C) 2020 Jens Axboe <axboe@kernel.dk>
+.\" Copyright (C) 2020 Red Hat, Inc.
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: October 22, 2025
+footer: liburing-2.13
+header: liburing Manual
+section: 3
+title: io_uring_get_sqe128
+---
+
+# NAME
+
+io_uring_get_sqe128 - get the next available 128-byte submission queue entry from the submission queue
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ struct io_uring_sqe *io_uring_get_sqe128(struct io_uring * ring );
+
+# DESCRIPTION
+
+The **io_uring_get_sqe128**(3) function gets the next available 128-byte submission queue entry from the submission queue belonging to the *ring* param.
+
+On success **io_uring_get_sqe128**(3) returns a pointer to the submission queue entry. On failure **NULL** is returned.
+
+If a submission queue entry is returned, it should be filled out via one of the prep functions such as **io_uring_prep_uring_cmd128**(3) and submitted via **io_uring_submit**(3).
+
+Note that neither **io_uring_get_sqe128**(3) nor the prep functions set (or clear) the **user_data** field of the SQE. If the caller expects **io_uring_cqe_get_data**(3) or **io_uring_cqe_get_data64**(3) to return valid data when reaping IO completions, either **io_uring_sqe_set_data**(3) or **io_uring_sqe_set_data64**(3) **MUST** have been called before submitting the request.
+
+# RETURN VALUE
+
+**io_uring_get_sqe128**(3) returns a pointer to the next submission queue event on success and NULL on failure. If **NULL** is returned, the SQ ring either wasn\'t created with support for 128-byte SQE entries ( **IORING_SETUP_SQE128** or **IORING_SETUP_SQE_MIXED** ) or is currently full and entries must be submitted for processing before new ones can get allocated.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_sqe_set_data**(3)
diff --git a/man/io_uring_linked_requests.7 b/man/io_uring_linked_requests.7
deleted file mode 100644
index 8f58ad13..00000000
--- a/man/io_uring_linked_requests.7
+++ /dev/null
@@ -1,271 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_linked_requests 7 "January 18, 2025" "Linux" "Linux Programmer's Manual"
-.SH NAME
-io_uring_linked_requests \- io_uring linked requests overview
-.SH DESCRIPTION
-Linked requests allow applications to chain multiple io_uring operations
-together, creating dependencies between them. When requests are linked,
-they execute sequentially rather than concurrently, with each request
-starting only after the previous one in the chain completes.
-.SS Why use linked requests?
-Normal io_uring submissions are independent and may execute in any order
-or concurrently. However, some operations have natural dependencies:
-.IP \(bu 2
-Read from one file, then write to another
-.IP \(bu
-Connect to a server, then send a request
-.IP \(bu
-Accept a connection, then receive data
-.IP \(bu
-Perform an operation with a timeout
-.PP
-Without linking, applications would need to wait for completions and
-submit follow-up requests manually. Linked requests allow the entire
-chain to be submitted at once, reducing round trips between user space
-and the kernel.
-
-Linked requests are most beneficial when:
-.IP \(bu 2
-Operations must execute in a specific order
-.IP \(bu
-Later operations depend on earlier ones succeeding
-.IP \(bu
-You want to attach a timeout to an operation
-.IP \(bu
-Reducing submission latency is important
-.SS Creating linked requests
-Requests are linked by setting the
-.B IOSQE_IO_LINK
-flag on a request. This links it to the next request in the submission.
-The chain continues until a request without the link flag is encountered.
-.PP
-.in +4n
-.EX
-struct io_uring_sqe *sqe;
-
-/* First request in chain */
-sqe = io_uring_get_sqe(ring);
-io_uring_prep_read(sqe, fd_in, buf, len, 0);
-sqe->flags |= IOSQE_IO_LINK;
-
-/* Second request, linked to first */
-sqe = io_uring_get_sqe(ring);
-io_uring_prep_write(sqe, fd_out, buf, len, 0);
-sqe->flags |= IOSQE_IO_LINK;
-
-/* Third request, end of chain (no link flag) */
-sqe = io_uring_get_sqe(ring);
-io_uring_prep_fsync(sqe, fd_out, 0);
-
-io_uring_submit(ring);
-.EE
-.in
-.PP
-In this example, the read completes first, then the write, then the
-fsync. Each operation waits for the previous one to complete before
-starting.
-.SS Soft links vs hard links
-There are two types of links, which differ in how they handle errors:
-.PP
-.B Soft links (IOSQE_IO_LINK)
-.RS 4
-If a request in the chain fails (returns a negative error code), all
-subsequent requests in the chain are canceled with
-.BR -ECANCELED .
-This is useful when later operations depend on earlier ones succeeding.
-.RE
-.PP
-.B Hard links (IOSQE_IO_HARDLINK)
-.RS 4
-The chain continues executing even if a request fails. Each request
-runs regardless of the outcome of previous requests. This is useful
-when you want to attempt all operations even if some fail.
-.RE
-.PP
-.in +4n
-.EX
-/* Soft link: write is canceled if read fails */
-sqe = io_uring_get_sqe(ring);
-io_uring_prep_read(sqe, fd, buf, len, 0);
-sqe->flags |= IOSQE_IO_LINK;
-
-sqe = io_uring_get_sqe(ring);
-io_uring_prep_write(sqe, fd2, buf, len, 0);
-
-/* Hard link: write runs even if read fails */
-sqe = io_uring_get_sqe(ring);
-io_uring_prep_read(sqe, fd, buf, len, 0);
-sqe->flags |= IOSQE_IO_HARDLINK;
-
-sqe = io_uring_get_sqe(ring);
-io_uring_prep_write(sqe, fd2, buf, len, 0);
-.EE
-.in
-.SS Link timeouts
-A common use of linked requests is to add a timeout to an operation.
-The
-.B IORING_OP_LINK_TIMEOUT
-operation (set up with
-.BR io_uring_prep_link_timeout (3))
-is designed specifically for this:
-.PP
-.in +4n
-.EX
-struct __kernel_timespec ts = { .tv_sec = 5, .tv_nsec = 0 };
-
-/* The operation to be timed */
-sqe = io_uring_get_sqe(ring);
-io_uring_prep_read(sqe, fd, buf, len, 0);
-sqe->flags |= IOSQE_IO_LINK;
-
-/* The timeout, linked to the read */
-sqe = io_uring_get_sqe(ring);
-io_uring_prep_link_timeout(sqe, &ts, 0);
-
-io_uring_submit(ring);
-.EE
-.in
-.PP
-If the read completes before the timeout:
-.IP \(bu 2
-The read CQE has the actual result
-.IP \(bu
-The timeout CQE has
-.B -ECANCELED
-.PP
-If the timeout expires first:
-.IP \(bu 2
-The read CQE has
-.B -ECANCELED
-(or
-.B -EINTR
-if it was in progress)
-.IP \(bu
-The timeout CQE has
-.B -ETIME
-.PP
-Link timeouts only apply to the immediately preceding request in the
-chain. To timeout an entire chain, the timeout must be linked after
-the last operation.
-.SS Completion ordering
-Each request in a linked chain generates its own CQE. Completions for
-linked requests are ordered \(em the CQE for an earlier request in the
-chain will be posted before the CQE for a later request.
-
-Applications can rely on this ordering when processing completions.
-However, if other unlinked requests are in flight, their completions
-may be interleaved with the chain's completions.
-.SS Error handling
-For soft-linked chains, error handling is straightforward:
-.IP \(bu 2
-Check each CQE's result
-.IP \(bu
-If a request failed, all subsequent requests will have
-.B -ECANCELED
-.IP \(bu
-The first non-canceled error indicates where the chain broke
-.PP
-.in +4n
-.EX
-/* Processing a linked chain's completions */
-for (int i = 0; i < chain_length; i++) {
- io_uring_wait_cqe(ring, &cqe);
-
- if (cqe->res == -ECANCELED) {
- /* Previous request in chain failed */
- } else if (cqe->res < 0) {
- /* This request failed, caused chain break */
- handle_error(cqe->res);
- } else {
- /* Success */
- handle_success(cqe->res);
- }
-
- io_uring_cqe_seen(ring, cqe);
-}
-.EE
-.in
-.SS Common patterns
-.PP
-.B Copy with sync:
-.RS 4
-Read data, write it elsewhere, then sync:
-.PP
-.in +4n
-.EX
-io_uring_prep_read(sqe1, src_fd, buf, len, 0);
-sqe1->flags |= IOSQE_IO_LINK;
-
-io_uring_prep_write(sqe2, dst_fd, buf, len, 0);
-sqe2->flags |= IOSQE_IO_LINK;
-
-io_uring_prep_fsync(sqe3, dst_fd, 0);
-.EE
-.in
-.RE
-.PP
-.B Connect with timeout:
-.RS 4
-Attempt connection with a time limit:
-.PP
-.in +4n
-.EX
-io_uring_prep_connect(sqe1, sockfd, addr, addrlen);
-sqe1->flags |= IOSQE_IO_LINK;
-
-io_uring_prep_link_timeout(sqe2, &timeout, 0);
-.EE
-.in
-.RE
-.PP
-.B Send after connect:
-.RS 4
-Connect then immediately send data:
-.PP
-.in +4n
-.EX
-io_uring_prep_connect(sqe1, sockfd, addr, addrlen);
-sqe1->flags |= IOSQE_IO_LINK;
-
-io_uring_prep_send(sqe2, sockfd, data, len, 0);
-.EE
-.in
-.RE
-.SH NOTES
-.IP \(bu 2
-Linked requests must be submitted together in the same
-.BR io_uring_submit (3)
-call. The chain is defined by the order of SQEs in the submission.
-.IP \(bu
-The link flag on the last request in a chain is ignored (it has
-nothing to link to).
-.IP \(bu
-Chains can be arbitrarily long, limited only by SQ ring size.
-.IP \(bu
-Mixing
-.B IOSQE_IO_LINK
-and
-.B IOSQE_IO_HARDLINK
-in the same chain is allowed. Each link's type determines what happens
-if that specific request fails.
-.IP \(bu
-Linked requests share the same
-.I personality
-if set, allowing credential inheritance through the chain.
-.IP \(bu
-If a request in a chain is canceled (e.g., via
-.BR io_uring_prep_cancel (3)),
-the chain breaks as if that request had failed.
-.IP \(bu
-Linked requests have performance implications: they force sequential
-execution, preventing the kernel from optimizing or parallelizing
-operations. Use links only when ordering is required. For independent
-operations, submitting them without links allows the kernel to execute
-them concurrently or reorder them for better performance.
-.SH SEE ALSO
-.BR io_uring (7),
-.BR io_uring_prep_link_timeout (3),
-.BR io_uring_prep_cancel (3),
-.BR io_uring_sqe_set_flags (3)
diff --git a/man/io_uring_linked_requests.7.md b/man/io_uring_linked_requests.7.md
new file mode 100644
index 00000000..73b8537a
--- /dev/null
+++ b/man/io_uring_linked_requests.7.md
@@ -0,0 +1,212 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: Linux
+header: Linux Programmer\'s Manual
+section: 7
+title: io_uring_linked_requests
+---
+
+# NAME
+
+io_uring_linked_requests - io_uring linked requests overview
+
+# DESCRIPTION
+
+Linked requests allow applications to chain multiple io_uring operations together, creating dependencies between them. When requests are linked, they execute sequentially rather than concurrently, with each request starting only after the previous one in the chain completes.
+
+## Why use linked requests?
+
+Normal io_uring submissions are independent and may execute in any order or concurrently. However, some operations have natural dependencies:
+
+- Read from one file, then write to another
+
+- Connect to a server, then send a request
+
+- Accept a connection, then receive data
+
+- Perform an operation with a timeout
+
+Without linking, applications would need to wait for completions and submit follow-up requests manually. Linked requests allow the entire chain to be submitted at once, reducing round trips between user space and the kernel.
+
+Linked requests are most beneficial when:
+
+- Operations must execute in a specific order
+
+- Later operations depend on earlier ones succeeding
+
+- You want to attach a timeout to an operation
+
+- Reducing submission latency is important
+
+## Creating linked requests
+
+Requests are linked by setting the **IOSQE_IO_LINK** flag on a request. This links it to the next request in the submission. The chain continues until a request without the link flag is encountered.
+
+ struct io_uring_sqe *sqe;
+
+ /* First request in chain */
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_read(sqe, fd_in, buf, len, 0);
+ sqe->flags |= IOSQE_IO_LINK;
+
+ /* Second request, linked to first */
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_write(sqe, fd_out, buf, len, 0);
+ sqe->flags |= IOSQE_IO_LINK;
+
+ /* Third request, end of chain (no link flag) */
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_fsync(sqe, fd_out, 0);
+
+ io_uring_submit(ring);
+
+In this example, the read completes first, then the write, then the fsync. Each operation waits for the previous one to complete before starting.
+
+## Soft links vs hard links
+
+There are two types of links, which differ in how they handle errors:
+
+**Soft links (IOSQE_IO_LINK)**
+
+> If a request in the chain fails (returns a negative error code), all subsequent requests in the chain are canceled with **-ECANCELED**. This is useful when later operations depend on earlier ones succeeding.
+
+**Hard links (IOSQE_IO_HARDLINK)**
+
+> The chain continues executing even if a request fails. Each request runs regardless of the outcome of previous requests. This is useful when you want to attempt all operations even if some fail.
+
+ /* Soft link: write is canceled if read fails */
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_read(sqe, fd, buf, len, 0);
+ sqe->flags |= IOSQE_IO_LINK;
+
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_write(sqe, fd2, buf, len, 0);
+
+ /* Hard link: write runs even if read fails */
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_read(sqe, fd, buf, len, 0);
+ sqe->flags |= IOSQE_IO_HARDLINK;
+
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_write(sqe, fd2, buf, len, 0);
+
+## Link timeouts
+
+A common use of linked requests is to add a timeout to an operation. The **IORING_OP_LINK_TIMEOUT** operation (set up with **io_uring_prep_link_timeout**(3)) is designed specifically for this:
+
+ struct __kernel_timespec ts = { .tv_sec = 5, .tv_nsec = 0 };
+
+ /* The operation to be timed */
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_read(sqe, fd, buf, len, 0);
+ sqe->flags |= IOSQE_IO_LINK;
+
+ /* The timeout, linked to the read */
+ sqe = io_uring_get_sqe(ring);
+ io_uring_prep_link_timeout(sqe, &ts, 0);
+
+ io_uring_submit(ring);
+
+If the read completes before the timeout:
+
+- The read CQE has the actual result
+
+- The timeout CQE has **-ECANCELED**
+
+If the timeout expires first:
+
+- The read CQE has **-ECANCELED** (or **-EINTR** if it was in progress)
+
+- The timeout CQE has **-ETIME**
+
+Link timeouts only apply to the immediately preceding request in the chain. To timeout an entire chain, the timeout must be linked after the last operation.
+
+## Completion ordering
+
+Each request in a linked chain generates its own CQE. Completions for linked requests are ordered --- the CQE for an earlier request in the chain will be posted before the CQE for a later request.
+
+Applications can rely on this ordering when processing completions. However, if other unlinked requests are in flight, their completions may be interleaved with the chain\'s completions.
+
+## Error handling
+
+For soft-linked chains, error handling is straightforward:
+
+- Check each CQE\'s result
+
+- If a request failed, all subsequent requests will have **-ECANCELED**
+
+- The first non-canceled error indicates where the chain broke
+
+<!-- -->
+
+ /* Processing a linked chain's completions */
+ for (int i = 0; i < chain_length; i++) {
+ io_uring_wait_cqe(ring, &cqe);
+
+ if (cqe->res == -ECANCELED) {
+ /* Previous request in chain failed */
+ } else if (cqe->res < 0) {
+ /* This request failed, caused chain break */
+ handle_error(cqe->res);
+ } else {
+ /* Success */
+ handle_success(cqe->res);
+ }
+
+ io_uring_cqe_seen(ring, cqe);
+ }
+
+## Common patterns
+
+**Copy with sync:**
+
+> Read data, write it elsewhere, then sync:
+>
+> io_uring_prep_read(sqe1, src_fd, buf, len, 0);
+> sqe1->flags |= IOSQE_IO_LINK;
+>
+> io_uring_prep_write(sqe2, dst_fd, buf, len, 0);
+> sqe2->flags |= IOSQE_IO_LINK;
+>
+> io_uring_prep_fsync(sqe3, dst_fd, 0);
+
+**Connect with timeout:**
+
+> Attempt connection with a time limit:
+>
+> io_uring_prep_connect(sqe1, sockfd, addr, addrlen);
+> sqe1->flags |= IOSQE_IO_LINK;
+>
+> io_uring_prep_link_timeout(sqe2, &timeout, 0);
+
+**Send after connect:**
+
+> Connect then immediately send data:
+>
+> io_uring_prep_connect(sqe1, sockfd, addr, addrlen);
+> sqe1->flags |= IOSQE_IO_LINK;
+>
+> io_uring_prep_send(sqe2, sockfd, data, len, 0);
+
+# NOTES
+
+- Linked requests must be submitted together in the same **io_uring_submit**(3) call. The chain is defined by the order of SQEs in the submission.
+
+- The link flag on the last request in a chain is ignored (it has nothing to link to).
+
+- Chains can be arbitrarily long, limited only by SQ ring size.
+
+- Mixing **IOSQE_IO_LINK** and **IOSQE_IO_HARDLINK** in the same chain is allowed. Each link\'s type determines what happens if that specific request fails.
+
+- Linked requests share the same *personality* if set, allowing credential inheritance through the chain.
+
+- If a request in a chain is canceled (e.g., via **io_uring_prep_cancel**(3)), the chain breaks as if that request had failed.
+
+- Linked requests have performance implications: they force sequential execution, preventing the kernel from optimizing or parallelizing operations. Use links only when ordering is required. For independent operations, submitting them without links allows the kernel to execute them concurrently or reorder them for better performance.
+
+# SEE ALSO
+
+**io_uring**(7), **io_uring_prep_link_timeout**(3), **io_uring_prep_cancel**(3), **io_uring_sqe_set_flags**(3)
diff --git a/man/io_uring_major_version.3 b/man/io_uring_major_version.3
deleted file mode 120000
index 21bbf456..00000000
--- a/man/io_uring_major_version.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_check_version.3
\ No newline at end of file
diff --git a/man/io_uring_memory_size_params.3 b/man/io_uring_memory_size_params.3
deleted file mode 100644
index 49ea6c10..00000000
--- a/man/io_uring_memory_size_params.3
+++ /dev/null
@@ -1,45 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_memory_size_params 3 "January 18, 2025" "liburing-2.11" "liburing Manual"
-.SH NAME
-io_uring_memory_size_params \- get memory size needed for a ring with params
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "ssize_t io_uring_memory_size_params(unsigned " entries ", struct io_uring_params *" p ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_memory_size_params (3)
-function returns the total memory size needed for an io_uring ring with
-.I entries
-entries and the parameters specified in
-.IR p .
-
-This is useful for applications that want to pre-allocate memory for a ring
-or want to know the memory footprint before creating a ring.
-
-This function provides more control than
-.BR io_uring_memory_size (3)
-by allowing the caller to specify full ring parameters including CQ size
-via
-.I p->cq_entries
-when
-.B IORING_SETUP_CQSIZE
-is set in
-.IR p->flags .
-
-.SH RETURN VALUE
-Returns the required memory size in bytes on success, or a negative errno
-value on error.
-.TP
-.B -EINVAL
-Invalid entries value (0 or too large without IORING_SETUP_CLAMP).
-.SH SEE ALSO
-.BR io_uring_memory_size (3),
-.BR io_uring_mlock_size_params (3),
-.BR io_uring_queue_init_params (3)
diff --git a/man/io_uring_memory_size_params.3.md b/man/io_uring_memory_size_params.3.md
new file mode 100644
index 00000000..e13b609a
--- /dev/null
+++ b/man/io_uring_memory_size_params.3.md
@@ -0,0 +1,41 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: liburing-2.11
+header: liburing Manual
+section: 3
+title: io_uring_memory_size_params
+---
+
+# NAME
+
+io_uring_memory_size_params - get memory size needed for a ring with params
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ ssize_t io_uring_memory_size_params(unsigned entries , struct io_uring_params * p );
+
+# DESCRIPTION
+
+The **io_uring_memory_size_params**(3) function returns the total memory size needed for an io_uring ring with *entries* entries and the parameters specified in *p*.
+
+This is useful for applications that want to pre-allocate memory for a ring or want to know the memory footprint before creating a ring.
+
+This function provides more control than **io_uring_memory_size**(3) by allowing the caller to specify full ring parameters including CQ size via *p-\>cq_entries* when **IORING_SETUP_CQSIZE** is set in *p-\>flags*.
+
+# RETURN VALUE
+
+Returns the required memory size in bytes on success, or a negative errno value on error.
+
+**-EINVAL**
+
+: Invalid entries value (0 or too large without IORING_SETUP_CLAMP).
+
+# SEE ALSO
+
+**io_uring_memory_size**(3), **io_uring_mlock_size_params**(3), **io_uring_queue_init_params**(3)
diff --git a/man/io_uring_minor_version.3 b/man/io_uring_minor_version.3
deleted file mode 120000
index 21bbf456..00000000
--- a/man/io_uring_minor_version.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_check_version.3
\ No newline at end of file
diff --git a/man/io_uring_mlock_size.3 b/man/io_uring_mlock_size.3
deleted file mode 100644
index d75bb5e7..00000000
--- a/man/io_uring_mlock_size.3
+++ /dev/null
@@ -1,42 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_mlock_size 3 "January 18, 2025" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_mlock_size \- get required memlock size for a ring
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "ssize_t io_uring_mlock_size(unsigned " entries ", unsigned " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_mlock_size (3)
-function returns the required
-.B RLIMIT_MEMLOCK
-memory size for an io_uring ring with
-.I entries
-entries and the specified setup
-.IR flags .
-
-On newer kernels (5.12+), io_uring no longer requires any memlock memory
-and this function will return 0. On older kernels (5.11 and prior), this
-returns the required memory so that the caller can ensure that enough
-.B RLIMIT_MEMLOCK
-space is available before setting up a ring.
-
-For more control over the ring parameters, use
-.BR io_uring_mlock_size_params (3)
-instead.
-
-.SH RETURN VALUE
-Returns the required memlock size in bytes on success, 0 if no memlock
-is needed, or a negative errno value on error.
-.SH SEE ALSO
-.BR io_uring_mlock_size_params (3),
-.BR io_uring_memory_size (3),
-.BR io_uring_queue_init (3),
-.BR getrlimit (2)
diff --git a/man/io_uring_mlock_size.3.md b/man/io_uring_mlock_size.3.md
new file mode 100644
index 00000000..221ec879
--- /dev/null
+++ b/man/io_uring_mlock_size.3.md
@@ -0,0 +1,37 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_mlock_size
+---
+
+# NAME
+
+io_uring_mlock_size - get required memlock size for a ring
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ ssize_t io_uring_mlock_size(unsigned entries , unsigned flags );
+
+# DESCRIPTION
+
+The **io_uring_mlock_size**(3) function returns the required **RLIMIT_MEMLOCK** memory size for an io_uring ring with *entries* entries and the specified setup *flags*.
+
+On newer kernels (5.12+), io_uring no longer requires any memlock memory and this function will return 0. On older kernels (5.11 and prior), this returns the required memory so that the caller can ensure that enough **RLIMIT_MEMLOCK** space is available before setting up a ring.
+
+For more control over the ring parameters, use **io_uring_mlock_size_params**(3) instead.
+
+# RETURN VALUE
+
+Returns the required memlock size in bytes on success, 0 if no memlock is needed, or a negative errno value on error.
+
+# SEE ALSO
+
+**io_uring_mlock_size_params**(3), **io_uring_memory_size**(3), **io_uring_queue_init**(3), **getrlimit**(2)
diff --git a/man/io_uring_mlock_size_params.3 b/man/io_uring_mlock_size_params.3
deleted file mode 100644
index afb615d3..00000000
--- a/man/io_uring_mlock_size_params.3
+++ /dev/null
@@ -1,48 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_mlock_size_params 3 "January 18, 2025" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_mlock_size_params \- get required memlock size for a ring with params
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "ssize_t io_uring_mlock_size_params(unsigned " entries ", struct io_uring_params *" p ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_mlock_size_params (3)
-function returns the required
-.B RLIMIT_MEMLOCK
-memory size for an io_uring ring with
-.I entries
-entries and the parameters specified in
-.IR p .
-
-On newer kernels (5.12+), io_uring no longer requires any memlock memory
-and this function will return 0. On older kernels (5.11 and prior), this
-returns the required memory so that the caller can ensure that enough
-.B RLIMIT_MEMLOCK
-space is available before setting up a ring.
-
-This function provides more control than
-.BR io_uring_mlock_size (3)
-by allowing the caller to specify full ring parameters including CQ size
-via
-.I p->cq_entries
-when
-.B IORING_SETUP_CQSIZE
-is set in
-.IR p->flags .
-
-.SH RETURN VALUE
-Returns the required memlock size in bytes on success, 0 if no memlock
-is needed, or a negative errno value on error.
-.SH SEE ALSO
-.BR io_uring_mlock_size (3),
-.BR io_uring_memory_size_params (3),
-.BR io_uring_queue_init_params (3),
-.BR getrlimit (2)
diff --git a/man/io_uring_mlock_size_params.3.md b/man/io_uring_mlock_size_params.3.md
new file mode 100644
index 00000000..866fac27
--- /dev/null
+++ b/man/io_uring_mlock_size_params.3.md
@@ -0,0 +1,37 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_mlock_size_params
+---
+
+# NAME
+
+io_uring_mlock_size_params - get required memlock size for a ring with params
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ ssize_t io_uring_mlock_size_params(unsigned entries , struct io_uring_params * p );
+
+# DESCRIPTION
+
+The **io_uring_mlock_size_params**(3) function returns the required **RLIMIT_MEMLOCK** memory size for an io_uring ring with *entries* entries and the parameters specified in *p*.
+
+On newer kernels (5.12+), io_uring no longer requires any memlock memory and this function will return 0. On older kernels (5.11 and prior), this returns the required memory so that the caller can ensure that enough **RLIMIT_MEMLOCK** space is available before setting up a ring.
+
+This function provides more control than **io_uring_mlock_size**(3) by allowing the caller to specify full ring parameters including CQ size via *p-\>cq_entries* when **IORING_SETUP_CQSIZE** is set in *p-\>flags*.
+
+# RETURN VALUE
+
+Returns the required memlock size in bytes on success, 0 if no memlock is needed, or a negative errno value on error.
+
+# SEE ALSO
+
+**io_uring_mlock_size**(3), **io_uring_memory_size_params**(3), **io_uring_queue_init_params**(3), **getrlimit**(2)
diff --git a/man/io_uring_multishot.7 b/man/io_uring_multishot.7
deleted file mode 100644
index 44ad2cec..00000000
--- a/man/io_uring_multishot.7
+++ /dev/null
@@ -1,246 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_multishot 7 "January 18, 2025" "Linux" "Linux Programmer's Manual"
-.SH NAME
-io_uring_multishot \- io_uring multishot requests overview
-.SH DESCRIPTION
-Multishot requests are a class of io_uring operations where a single
-submission queue entry (SQE) can generate multiple completion queue
-entries (CQEs). This is in contrast to normal "oneshot" operations where
-each SQE produces exactly one CQE.
-.SS Why use multishot requests?
-Traditional I/O operations require submitting a new request for each
-operation. For high-frequency operations like accepting connections or
-receiving data, this creates overhead:
-.IP \(bu 2
-CPU cycles spent preparing and submitting SQEs
-.IP \(bu
-Memory bandwidth for SQE/CQE processing
-.IP \(bu
-Potential for gaps between completions and new submissions
-.PP
-Multishot requests eliminate this overhead by keeping the operation
-active after each completion. The kernel automatically re-arms the
-operation, generating a new CQE when the next event occurs.
-Additionally, the internal poll mechanism remains persistent for the
-request, avoiding the need to manipulate poll state for each operation.
-
-Multishot operations are most beneficial for:
-.IP \(bu 2
-Network servers accepting many connections
-.IP \(bu
-Applications receiving data on long-lived connections
-.IP \(bu
-Event monitoring with poll
-.IP \(bu
-Any scenario with repeated identical operations
-.SS How multishot works
-When a multishot operation completes, the CQE has the
-.B IORING_CQE_F_MORE
-flag set in
-.IR cqe->flags .
-This indicates that the operation remains active and more completions
-will follow. The operation continues until:
-.IP \(bu 2
-An error occurs (the final CQE will not have
-.B IORING_CQE_F_MORE
-set)
-.IP \(bu
-The operation is explicitly canceled
-.IP \(bu
-A termination condition specific to the operation is met (e.g., buffer
-exhaustion for receives)
-.PP
-The final CQE for a multishot operation will not have
-.B IORING_CQE_F_MORE
-set, indicating the operation has terminated.
-.SS Multishot accept
-.BR io_uring_prep_multishot_accept (3)
-and
-.BR io_uring_prep_multishot_accept_direct (3)
-set up a multishot accept operation. Each incoming connection generates
-a CQE with the new file descriptor in
-.IR cqe->res .
-.PP
-.in +4n
-.EX
-struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
-io_uring_prep_multishot_accept(sqe, listen_fd, NULL, NULL, 0);
-.EE
-.in
-.PP
-The operation continues accepting connections until an error occurs or
-it is canceled. Using the direct variant with
-.B IORING_FILE_INDEX_ALLOC
-allows accepted sockets to be placed directly into the fixed file table.
-.SS Multishot receive
-.BR io_uring_prep_recv_multishot (3)
-sets up a multishot receive operation. Each time data arrives on the
-socket, a CQE is generated. This is typically used with provided buffers
-(see
-.BR io_uring_provided_buffers (7)):
-.PP
-.in +4n
-.EX
-struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
-io_uring_prep_recv_multishot(sqe, sockfd, NULL, 0, 0);
-sqe->buf_group = bgid;
-sqe->flags |= IOSQE_BUFFER_SELECT;
-.EE
-.in
-.PP
-Each completion includes:
-.IP \(bu 2
-.B IORING_CQE_F_MORE
-if more completions will follow
-.IP \(bu
-.B IORING_CQE_F_BUFFER
-indicating a buffer was selected
-.IP \(bu
-The buffer ID in the upper bits of
-.I cqe->flags
-.IP \(bu
-The number of bytes received in
-.I cqe->res
-.PP
-The multishot receive terminates when an error occurs, the connection
-closes, or the buffer ring is exhausted.
-.SS Multishot recvmsg
-.BR io_uring_prep_recvmsg_multishot (3)
-is similar to multishot receive but uses the
-.I msghdr
-structure for scatter/gather I/O and ancillary data. A provided buffer
-is used for each message, with the kernel writing a
-.I struct io_uring_recvmsg_out
-header at the start of the buffer containing the actual message
-parameters.
-.SS Multishot read
-.BR io_uring_prep_read_multishot (3)
-sets up a multishot read operation, typically used with pipes or other
-stream-oriented file descriptors. Like multishot receive, this is used
-with provided buffers:
-.PP
-.in +4n
-.EX
-struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
-io_uring_prep_read_multishot(sqe, fd, 0, 0, bgid);
-.EE
-.in
-.PP
-The operation generates a CQE each time data becomes available to read.
-.SS Multishot poll
-.BR io_uring_prep_poll_multishot (3)
-sets up a multishot poll operation, or it can be done manually by
-setting the
-.B IORING_POLL_ADD_MULTI
-flag:
-.PP
-.in +4n
-.EX
-struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
-io_uring_prep_poll_multishot(sqe, fd, POLLIN);
-/* or equivalently: */
-io_uring_prep_poll_add(sqe, fd, POLLIN);
-sqe->len |= IORING_POLL_ADD_MULTI;
-.EE
-.in
-.PP
-Each time the polled condition becomes true, a CQE is generated with
-the triggered events in
-.IR cqe->res .
-Unlike oneshot poll which is automatically removed after triggering,
-multishot poll remains active.
-
-For level-triggered events, the application should be careful to handle
-the event (e.g., read all available data) before the next poll
-completion, or spurious wakeups may occur.
-.SS Multishot waitid
-.BR io_uring_prep_waitid (3)
-can operate in multishot mode by setting
-.B IORING_ACCEPT_MULTISHOT
-in the flags. This allows waiting for multiple child process state
-changes with a single SQE.
-.SS Handling multishot completions
-Applications must check for
-.B IORING_CQE_F_MORE
-to determine if the operation is still active:
-.PP
-.in +4n
-.EX
-struct io_uring_cqe *cqe;
-
-while (io_uring_peek_cqe(ring, &cqe) == 0) {
- if (cqe->res < 0) {
- /* Error occurred, operation terminated */
- handle_error(cqe->res);
- } else {
- process_completion(cqe);
- }
-
- if (!(cqe->flags & IORING_CQE_F_MORE)) {
- /* Operation terminated, may need to resubmit */
- rearm_if_needed();
- }
-
- io_uring_cqe_seen(ring, cqe);
-}
-.EE
-.in
-.SS Canceling multishot operations
-Multishot operations can be canceled using
-.BR io_uring_prep_cancel (3)
-or related functions. The cancellation request generates its own CQE,
-and the multishot operation generates a final CQE (typically with
-.BR -ECANCELED )
-without
-.B IORING_CQE_F_MORE
-set.
-.PP
-.in +4n
-.EX
-struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
-io_uring_prep_cancel64(sqe, user_data, 0);
-.EE
-.in
-.SS Integration with provided buffers
-Multishot receive and read operations are designed to work with provided
-buffer rings (see
-.BR io_uring_provided_buffers (7)).
-Each completion consumes a buffer from the ring, and the application
-must return buffers to the ring to keep the operation running.
-
-If the buffer ring becomes empty, the multishot operation terminates
-with
-.BR -ENOBUFS .
-Applications should ensure adequate buffers are available and promptly
-return used buffers to the ring.
-.SH NOTES
-.IP \(bu 2
-Always check
-.B IORING_CQE_F_MORE
-to know if a multishot operation is still active.
-.IP \(bu
-Multishot operations may generate many CQEs quickly. Ensure the CQ ring
-is large enough to avoid overflow.
-.IP \(bu
-When using provided buffers with multishot receives, monitor buffer
-availability to prevent premature termination.
-.IP \(bu
-Multishot operations are edge-triggered conceptually \(em they generate
-completions when events occur, not continuously while conditions are
-true.
-.IP \(bu
-Error completions from multishot operations do not have
-.B IORING_CQE_F_MORE
-set, indicating termination.
-.SH SEE ALSO
-.BR io_uring (7),
-.BR io_uring_provided_buffers (7),
-.BR io_uring_prep_multishot_accept (3),
-.BR io_uring_prep_recv_multishot (3),
-.BR io_uring_prep_recvmsg_multishot (3),
-.BR io_uring_prep_read_multishot (3),
-.BR io_uring_prep_poll_add (3),
-.BR io_uring_prep_poll_multishot (3),
-.BR io_uring_prep_cancel (3)
diff --git a/man/io_uring_multishot.7.md b/man/io_uring_multishot.7.md
new file mode 100644
index 00000000..4a991bc3
--- /dev/null
+++ b/man/io_uring_multishot.7.md
@@ -0,0 +1,164 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: Linux
+header: Linux Programmer\'s Manual
+section: 7
+title: io_uring_multishot
+---
+
+# NAME
+
+io_uring_multishot - io_uring multishot requests overview
+
+# DESCRIPTION
+
+Multishot requests are a class of io_uring operations where a single submission queue entry (SQE) can generate multiple completion queue entries (CQEs). This is in contrast to normal \"oneshot\" operations where each SQE produces exactly one CQE.
+
+## Why use multishot requests?
+
+Traditional I/O operations require submitting a new request for each operation. For high-frequency operations like accepting connections or receiving data, this creates overhead:
+
+- CPU cycles spent preparing and submitting SQEs
+
+- Memory bandwidth for SQE/CQE processing
+
+- Potential for gaps between completions and new submissions
+
+Multishot requests eliminate this overhead by keeping the operation active after each completion. The kernel automatically re-arms the operation, generating a new CQE when the next event occurs. Additionally, the internal poll mechanism remains persistent for the request, avoiding the need to manipulate poll state for each operation.
+
+Multishot operations are most beneficial for:
+
+- Network servers accepting many connections
+
+- Applications receiving data on long-lived connections
+
+- Event monitoring with poll
+
+- Any scenario with repeated identical operations
+
+## How multishot works
+
+When a multishot operation completes, the CQE has the **IORING_CQE_F_MORE** flag set in *cqe-\>flags*. This indicates that the operation remains active and more completions will follow. The operation continues until:
+
+- An error occurs (the final CQE will not have **IORING_CQE_F_MORE** set)
+
+- The operation is explicitly canceled
+
+- A termination condition specific to the operation is met (e.g., buffer exhaustion for receives)
+
+The final CQE for a multishot operation will not have **IORING_CQE_F_MORE** set, indicating the operation has terminated.
+
+## Multishot accept
+
+**io_uring_prep_multishot_accept**(3) and **io_uring_prep_multishot_accept_direct**(3) set up a multishot accept operation. Each incoming connection generates a CQE with the new file descriptor in *cqe-\>res*.
+
+ struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
+ io_uring_prep_multishot_accept(sqe, listen_fd, NULL, NULL, 0);
+
+The operation continues accepting connections until an error occurs or it is canceled. Using the direct variant with **IORING_FILE_INDEX_ALLOC** allows accepted sockets to be placed directly into the fixed file table.
+
+## Multishot receive
+
+**io_uring_prep_recv_multishot**(3) sets up a multishot receive operation. Each time data arrives on the socket, a CQE is generated. This is typically used with provided buffers (see **io_uring_provided_buffers**(7)):
+
+ struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
+ io_uring_prep_recv_multishot(sqe, sockfd, NULL, 0, 0);
+ sqe->buf_group = bgid;
+ sqe->flags |= IOSQE_BUFFER_SELECT;
+
+Each completion includes:
+
+- **IORING_CQE_F_MORE** if more completions will follow
+
+- **IORING_CQE_F_BUFFER** indicating a buffer was selected
+
+- The buffer ID in the upper bits of *cqe-\>flags*
+
+- The number of bytes received in *cqe-\>res*
+
+The multishot receive terminates when an error occurs, the connection closes, or the buffer ring is exhausted.
+
+## Multishot recvmsg
+
+**io_uring_prep_recvmsg_multishot**(3) is similar to multishot receive but uses the *msghdr* structure for scatter/gather I/O and ancillary data. A provided buffer is used for each message, with the kernel writing a *struct io_uring_recvmsg_out* header at the start of the buffer containing the actual message parameters.
+
+## Multishot read
+
+**io_uring_prep_read_multishot**(3) sets up a multishot read operation, typically used with pipes or other stream-oriented file descriptors. Like multishot receive, this is used with provided buffers:
+
+ struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
+ io_uring_prep_read_multishot(sqe, fd, 0, 0, bgid);
+
+The operation generates a CQE each time data becomes available to read.
+
+## Multishot poll
+
+**io_uring_prep_poll_multishot**(3) sets up a multishot poll operation, or it can be done manually by setting the **IORING_POLL_ADD_MULTI** flag:
+
+ struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
+ io_uring_prep_poll_multishot(sqe, fd, POLLIN);
+ /* or equivalently: */
+ io_uring_prep_poll_add(sqe, fd, POLLIN);
+ sqe->len |= IORING_POLL_ADD_MULTI;
+
+Each time the polled condition becomes true, a CQE is generated with the triggered events in *cqe-\>res*. Unlike oneshot poll which is automatically removed after triggering, multishot poll remains active.
+
+For level-triggered events, the application should be careful to handle the event (e.g., read all available data) before the next poll completion, or spurious wakeups may occur.
+
+## Multishot waitid
+
+**io_uring_prep_waitid**(3) can operate in multishot mode by setting **IORING_ACCEPT_MULTISHOT** in the flags. This allows waiting for multiple child process state changes with a single SQE.
+
+## Handling multishot completions
+
+Applications must check for **IORING_CQE_F_MORE** to determine if the operation is still active:
+
+ struct io_uring_cqe *cqe;
+
+ while (io_uring_peek_cqe(ring, &cqe) == 0) {
+ if (cqe->res < 0) {
+ /* Error occurred, operation terminated */
+ handle_error(cqe->res);
+ } else {
+ process_completion(cqe);
+ }
+
+ if (!(cqe->flags & IORING_CQE_F_MORE)) {
+ /* Operation terminated, may need to resubmit */
+ rearm_if_needed();
+ }
+
+ io_uring_cqe_seen(ring, cqe);
+ }
+
+## Canceling multishot operations
+
+Multishot operations can be canceled using **io_uring_prep_cancel**(3) or related functions. The cancellation request generates its own CQE, and the multishot operation generates a final CQE (typically with **-ECANCELED**) without **IORING_CQE_F_MORE** set.
+
+ struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
+ io_uring_prep_cancel64(sqe, user_data, 0);
+
+## Integration with provided buffers
+
+Multishot receive and read operations are designed to work with provided buffer rings (see **io_uring_provided_buffers**(7)). Each completion consumes a buffer from the ring, and the application must return buffers to the ring to keep the operation running.
+
+If the buffer ring becomes empty, the multishot operation terminates with **-ENOBUFS**. Applications should ensure adequate buffers are available and promptly return used buffers to the ring.
+
+# NOTES
+
+- Always check **IORING_CQE_F_MORE** to know if a multishot operation is still active.
+
+- Multishot operations may generate many CQEs quickly. Ensure the CQ ring is large enough to avoid overflow.
+
+- When using provided buffers with multishot receives, monitor buffer availability to prevent premature termination.
+
+- Multishot operations are edge-triggered conceptually --- they generate completions when events occur, not continuously while conditions are true.
+
+- Error completions from multishot operations do not have **IORING_CQE_F_MORE** set, indicating termination.
+
+# SEE ALSO
+
+**io_uring**(7), **io_uring_provided_buffers**(7), **io_uring_prep_multishot_accept**(3), **io_uring_prep_recv_multishot**(3), **io_uring_prep_recvmsg_multishot**(3), **io_uring_prep_read_multishot**(3), **io_uring_prep_poll_add**(3), **io_uring_prep_poll_multishot**(3), **io_uring_prep_cancel**(3)
diff --git a/man/io_uring_opcode_supported.3 b/man/io_uring_opcode_supported.3
deleted file mode 100644
index b981ed7d..00000000
--- a/man/io_uring_opcode_supported.3
+++ /dev/null
@@ -1,30 +0,0 @@
-.\" Copyright (C) 2022 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_opcode_supported 3 "January 25, 2022" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_opcode_supported \- is op code supported?
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_opcode_supported(struct io_uring_probe *" probe ","
-.BI " int " opcode ");"
-.fi
-.SH DESCRIPTION
-.PP
-The function
-.BR io_uring_opcode_supported (3)
-allows the caller to determine if the passed in
-.I opcode
-belonging to the
-.I probe
-param is supported. An instance of the io_uring_probe instance can be
-obtained by calling the function
-.BR io_uring_get_probe (3).
-
-.SH RETURN VALUE
-On success it returns 1, otherwise it returns 0.
-.SH SEE ALSO
-.BR io_uring_get_probe (3)
diff --git a/man/io_uring_opcode_supported.3.md b/man/io_uring_opcode_supported.3.md
new file mode 100644
index 00000000..872c27b8
--- /dev/null
+++ b/man/io_uring_opcode_supported.3.md
@@ -0,0 +1,34 @@
+.\" Copyright (C) 2022 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 25, 2022
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_opcode_supported
+---
+
+# NAME
+
+io_uring_opcode_supported - is op code supported?
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_opcode_supported(struct io_uring_probe * probe ,
+ int opcode );
+
+# DESCRIPTION
+
+The function **io_uring_opcode_supported**(3) allows the caller to determine if the passed in *opcode* belonging to the *probe* param is supported. An instance of the io_uring_probe instance can be obtained by calling the function **io_uring_get_probe**(3).
+
+# RETURN VALUE
+
+On success it returns 1, otherwise it returns 0.
+
+# SEE ALSO
+
+**io_uring_get_probe**(3)
diff --git a/man/io_uring_peek_batch_cqe.3 b/man/io_uring_peek_batch_cqe.3
deleted file mode 120000
index fbf4e4cc..00000000
--- a/man/io_uring_peek_batch_cqe.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_peek_cqe.3
\ No newline at end of file
diff --git a/man/io_uring_peek_cqe.3 b/man/io_uring_peek_cqe.3
deleted file mode 100644
index 4416e15a..00000000
--- a/man/io_uring_peek_cqe.3
+++ /dev/null
@@ -1,59 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_peek_cqe 3 "March 12, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_peek_cqe \- check if an io_uring completion event is available
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_peek_cqe(struct io_uring *" ring ","
-.BI " struct io_uring_cqe **" cqe_ptr ");"
-.PP
-.BI "unsigned io_uring_peek_batch_cqe(struct io_uring *" ring ","
-.BI " struct io_uring_cqe **" cqe_ptrs ","
-.BI " unsigned " count ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_peek_cqe (3)
-function returns an IO completion from the queue belonging to the
-.I ring
-param, if one is readily available. On successful return,
-.I cqe_ptr
-param is filled with a valid CQE entry.
-
-This function does not enter the kernel to wait for an event, an event
-is only returned if it's already available in the CQ ring.
-
-The
-.BR io_uring_peek_batch_cqe (3)
-function returns up to
-.I count
-request completions in
-.I cqe_ptrs
-belonging to the
-.I ring
-param, if they are readily available. It will not enter the kernel, unless the
-CQ ring is in an overflow condition. Upon successful return,
-.I cqe_ptrs
-are filled with the number of events indicated by the return value.
-
-.SH RETURN VALUE
-On success
-.BR io_uring_peek_cqe (3)
-returns
-.B 0
-and the cqe_ptr parameter is filled in. On success
-.BR io_uring_peek_batch_cqe (3)
-returns the number of completions filled in. On failure,
-.BR io_uring_peek_cqe (3)
-may return
-.BR -EAGAIN .
-.SH SEE ALSO
-.BR io_uring_submit (3),
-.BR io_uring_wait_cqes (3),
-.BR io_uring_wait_cqe (3)
diff --git a/man/io_uring_peek_cqe.3.md b/man/io_uring_peek_cqe.3.md
new file mode 100644
index 00000000..fce10487
--- /dev/null
+++ b/man/io_uring_peek_cqe.3.md
@@ -0,0 +1,42 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 12, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_peek_cqe
+---
+
+# NAME
+
+io_uring_peek_cqe - check if an io_uring completion event is available
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_peek_cqe(struct io_uring * ring ,
+ struct io_uring_cqe ** cqe_ptr );
+
+ unsigned io_uring_peek_batch_cqe(struct io_uring * ring ,
+ struct io_uring_cqe ** cqe_ptrs ,
+ unsigned count );
+
+# DESCRIPTION
+
+The **io_uring_peek_cqe**(3) function returns an IO completion from the queue belonging to the *ring* param, if one is readily available. On successful return, *cqe_ptr* param is filled with a valid CQE entry.
+
+This function does not enter the kernel to wait for an event, an event is only returned if it\'s already available in the CQ ring.
+
+The **io_uring_peek_batch_cqe**(3) function returns up to *count* request completions in *cqe_ptrs* belonging to the *ring* param, if they are readily available. It will not enter the kernel, unless the CQ ring is in an overflow condition. Upon successful return, *cqe_ptrs* are filled with the number of events indicated by the return value.
+
+# RETURN VALUE
+
+On success **io_uring_peek_cqe**(3) returns **0** and the cqe_ptr parameter is filled in. On success **io_uring_peek_batch_cqe**(3) returns the number of completions filled in. On failure, **io_uring_peek_cqe**(3) may return **-EAGAIN**.
+
+# SEE ALSO
+
+**io_uring_submit**(3), **io_uring_wait_cqes**(3), **io_uring_wait_cqe**(3)
diff --git a/man/io_uring_prep_accept.3 b/man/io_uring_prep_accept.3
deleted file mode 100644
index 950ab7d4..00000000
--- a/man/io_uring_prep_accept.3
+++ /dev/null
@@ -1,203 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_accept 3 "March 13, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_accept \- prepare an accept request
-.SH SYNOPSIS
-.nf
-.B #include <sys/socket.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_accept(struct io_uring_sqe *" sqe ","
-.BI " int " sockfd ","
-.BI " struct sockaddr *" addr ","
-.BI " socklen_t *" addrlen ","
-.BI " int " flags ");"
-.PP
-.BI "void io_uring_prep_accept_direct(struct io_uring_sqe *" sqe ","
-.BI " int " sockfd ","
-.BI " struct sockaddr *" addr ","
-.BI " socklen_t *" addrlen ","
-.BI " int " flags ","
-.BI " unsigned int " file_index ");"
-.PP
-.BI "void io_uring_prep_multishot_accept(struct io_uring_sqe *" sqe ","
-.BI " int " sockfd ","
-.BI " struct sockaddr *" addr ","
-.BI " socklen_t *" addrlen ","
-.BI " int " flags ");"
-.PP
-.BI "void io_uring_prep_multishot_accept_direct(struct io_uring_sqe *" sqe ","
-.BI " int " sockfd ","
-.BI " struct sockaddr *" addr ","
-.BI " socklen_t *" addrlen ","
-.BI " int " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_accept (3)
-function and its three variants prepare an accept request similar to
-.BR accept4 (2).
-The submission queue entry
-.I sqe
-is setup to use the file descriptor
-.I sockfd
-to start accepting a connection request described by the socket address at
-.I addr
-and of structure length
-.I addrlen
-and using modifier flags in
-.IR flags .
-
-The three variants allow combining the direct file table and multishot features.
-
-Direct descriptors are io_uring private file descriptors. They
-avoid some of the overhead associated with thread shared file tables and
-can be used in any io_uring request that takes a file descriptor.
-The two direct variants here create such direct descriptors.
-Subsequent to their creation, they can be used by setting
-.B IOSQE_FIXED_FILE
-in the SQE
-.I flags
-member, and setting the SQE
-.I fd
-field to the direct descriptor value rather than the regular file
-descriptor. Direct descriptors are managed like registered files.
-
-To use an accept direct variant, the application must first have registered
-a file table of a desired size using
-.BR io_uring_register_files (3)
-or
-.BR io_uring_register_files_sparse (3).
-Once registered,
-.BR io_uring_prep_accept_direct (3)
-allows an entry in that table to be specifically selected through the
-.I file_index
-argument.
-If the specified entry already contains a file, the file will first be removed
-from the table and closed, consistent with the behavior of updating an
-existing file with
-.BR io_uring_register_files_update (3).
-.I file_index
-can also be set to
-.B IORING_FILE_INDEX_ALLOC
-for this variant and
-an unused table index will be dynamically chosen and returned.
-Likewise,
-.B io_uring_prep_multishot_accept_direct
-will have an unused table index dynamically chosen and returned for each connection accepted.
-If both forms of direct selection will be employed, specific and dynamic, see
-.BR io_uring_register_file_alloc_range (3)
-for setting up the table so dynamically chosen entries are made against
-a different range than that targeted by specific requests.
-
-Note that old kernels don't check the SQE
-.I file_index
-field meaning
-applications cannot rely on a
-.B -EINVAL
-CQE
-.I res
-being returned when the kernel is too old because older kernels
-may not recognize they are being asked to use a direct table slot.
-
-When a direct descriptor accept request asks for a table slot to be
-dynamically chosen but there are no free entries,
-.B -ENFILE
-is returned as the CQE
-.IR res .
-
-The multishot variants allow an application to issue
-a single accept request, which will repeatedly trigger a CQE when a connection
-request comes in. Like other multishot type requests, the application should
-look at the CQE
-.I flags
-and see if
-.B IORING_CQE_F_MORE
-is set on completion as an indication of whether or not the accept request
-will generate further CQEs. Note that for the multishot variants, setting
-.B addr
-and
-.B addrlen
-may not make a lot of sense, as the same value would be used for every
-accepted connection. This means that the data written to
-.B addr
-may be overwritten by a new connection before the application has had time
-to process a past connection. If the application knows that a new connection
-cannot come in before a previous one has been processed, it may be used as
-expected. The multishot variants are available since 5.19.
-
-See the man page
-.BR accept4 (2)
-for details of the accept function itself.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation.
-
-.BR io_uring_prep_accept (3)
-generates the installed file descriptor as its result.
-
-.BR io_uring_prep_accept_direct (3)
-and
-.I file_index
-set to a specific direct descriptor
-generates
-.B 0
-on success.
-The caller must remember which direct descriptor was picked for this request.
-
-.BR io_uring_prep_accept_direct (3)
-and
-.I file_index
-set to
-.B IORING_FILE_INDEX_ALLOC
-generates the dynamically chosen direct descriptor.
-
-.BR io_uring_prep_multishot_accept (3)
-generates the installed file descriptor in each result.
-
-.BR io_uring_prep_multishot_accept_direct (3),
-generates the dynamically chosen direct descriptor in each result.
-
-Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it generates the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-As with any request that passes in data in a struct, that data must remain
-valid until the request has been successfully submitted. It need not remain
-valid until completion. Once a request has been submitted, the in-kernel
-state is stable. Very early kernels (5.4 and earlier) required state to be
-stable until the completion occurred. Applications can test for this
-behavior by inspecting the
-.B IORING_FEAT_SUBMIT_STABLE
-flag passed back from
-.BR io_uring_queue_init_params (3).
-.P
-Note that the direct versions of accept do not accept
-.B SOCK_CLOEXEC ,
-and setting that flag will result in an
-.B -EINVAL
-error in the CQE.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_register_files (3),
-.BR io_uring_register_files_sparse (3),
-.BR io_uring_register_file_alloc_range (3),
-.BR io_uring_register (2),
-.BR accept4 (2)
diff --git a/man/io_uring_prep_accept.3.md b/man/io_uring_prep_accept.3.md
new file mode 100644
index 00000000..e4a9b4ad
--- /dev/null
+++ b/man/io_uring_prep_accept.3.md
@@ -0,0 +1,93 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 13, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_accept
+---
+
+# NAME
+
+io_uring_prep_accept - prepare an accept request
+
+# SYNOPSIS
+
+ #include <sys/socket.h>
+ #include <liburing.h>
+
+ void io_uring_prep_accept(struct io_uring_sqe * sqe ,
+ int sockfd ,
+ struct sockaddr * addr ,
+ socklen_t * addrlen ,
+ int flags );
+
+ void io_uring_prep_accept_direct(struct io_uring_sqe * sqe ,
+ int sockfd ,
+ struct sockaddr * addr ,
+ socklen_t * addrlen ,
+ int flags ,
+ unsigned int file_index );
+
+ void io_uring_prep_multishot_accept(struct io_uring_sqe * sqe ,
+ int sockfd ,
+ struct sockaddr * addr ,
+ socklen_t * addrlen ,
+ int flags );
+
+ void io_uring_prep_multishot_accept_direct(struct io_uring_sqe * sqe ,
+ int sockfd ,
+ struct sockaddr * addr ,
+ socklen_t * addrlen ,
+ int flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_accept**(3) function and its three variants prepare an accept request similar to **accept4**(2). The submission queue entry *sqe* is setup to use the file descriptor *sockfd* to start accepting a connection request described by the socket address at *addr* and of structure length *addrlen* and using modifier flags in *flags*.
+
+The three variants allow combining the direct file table and multishot features.
+
+Direct descriptors are io_uring private file descriptors. They avoid some of the overhead associated with thread shared file tables and can be used in any io_uring request that takes a file descriptor. The two direct variants here create such direct descriptors. Subsequent to their creation, they can be used by setting **IOSQE_FIXED_FILE** in the SQE *flags* member, and setting the SQE *fd* field to the direct descriptor value rather than the regular file descriptor. Direct descriptors are managed like registered files.
+
+To use an accept direct variant, the application must first have registered a file table of a desired size using **io_uring_register_files**(3) or **io_uring_register_files_sparse**(3). Once registered, **io_uring_prep_accept_direct**(3) allows an entry in that table to be specifically selected through the *file_index* argument. If the specified entry already contains a file, the file will first be removed from the table and closed, consistent with the behavior of updating an existing file with **io_uring_register_files_update**(3). *file_index* can also be set to **IORING_FILE_INDEX_ALLOC** for this variant and an unused table index will be dynamically chosen and returned. Likewise, **io_uring_prep_multishot_accept_direct** will have an unused table index dynamically chosen and returned for each connection accepted. If both forms of direct selection will be employed, specific and dynamic, see **io_uring_register_file_alloc_range**(3) for setting up the table so dynamically chosen entries are made against a different range than that targeted by specific requests.
+
+Note that old kernels don\'t check the SQE *file_index* field meaning applications cannot rely on a **-EINVAL** CQE *res* being returned when the kernel is too old because older kernels may not recognize they are being asked to use a direct table slot.
+
+When a direct descriptor accept request asks for a table slot to be dynamically chosen but there are no free entries, **-ENFILE** is returned as the CQE *res*.
+
+The multishot variants allow an application to issue a single accept request, which will repeatedly trigger a CQE when a connection request comes in. Like other multishot type requests, the application should look at the CQE *flags* and see if **IORING_CQE_F_MORE** is set on completion as an indication of whether or not the accept request will generate further CQEs. Note that for the multishot variants, setting **addr** and **addrlen** may not make a lot of sense, as the same value would be used for every accepted connection. This means that the data written to **addr** may be overwritten by a new connection before the application has had time to process a past connection. If the application knows that a new connection cannot come in before a previous one has been processed, it may be used as expected. The multishot variants are available since 5.19.
+
+See the man page **accept4**(2) for details of the accept function itself.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation.
+
+**io_uring_prep_accept**(3) generates the installed file descriptor as its result.
+
+**io_uring_prep_accept_direct**(3) and *file_index* set to a specific direct descriptor generates **0** on success. The caller must remember which direct descriptor was picked for this request.
+
+**io_uring_prep_accept_direct**(3) and *file_index* set to **IORING_FILE_INDEX_ALLOC** generates the dynamically chosen direct descriptor.
+
+**io_uring_prep_multishot_accept**(3) generates the installed file descriptor in each result.
+
+**io_uring_prep_multishot_accept_direct**(3), generates the dynamically chosen direct descriptor in each result.
+
+Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it generates the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+As with any request that passes in data in a struct, that data must remain valid until the request has been successfully submitted. It need not remain valid until completion. Once a request has been submitted, the in-kernel state is stable. Very early kernels (5.4 and earlier) required state to be stable until the completion occurred. Applications can test for this behavior by inspecting the **IORING_FEAT_SUBMIT_STABLE** flag passed back from **io_uring_queue_init_params**(3).
+
+Note that the direct versions of accept do not accept **SOCK_CLOEXEC ,** and setting that flag will result in an **-EINVAL** error in the CQE.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_register_files**(3), **io_uring_register_files_sparse**(3), **io_uring_register_file_alloc_range**(3), **io_uring_register**(2), **accept4**(2)
diff --git a/man/io_uring_prep_accept_direct.3 b/man/io_uring_prep_accept_direct.3
deleted file mode 120000
index 0404bf59..00000000
--- a/man/io_uring_prep_accept_direct.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_accept.3
\ No newline at end of file
diff --git a/man/io_uring_prep_bind.3 b/man/io_uring_prep_bind.3
deleted file mode 100644
index b62905c4..00000000
--- a/man/io_uring_prep_bind.3
+++ /dev/null
@@ -1,54 +0,0 @@
-.\" Copyright (C) 2024 SUSE LLC
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_bind 3 "Jun 3, 2024" "liburing-2.7" "liburing Manual"
-.SH NAME
-io_uring_prep_bind \- prepare a bind request
-.SH SYNOPSIS
-.nf
-.B #include <sys/socket.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_bind(struct io_uring_sqe *" sqe ","
-.BI " int " sockfd ","
-.BI " const struct sockaddr *" addr ","
-.BI " socklen_t " addrlen ");"
-.fi
-.SH DESCRIPTION
-The
-.BR io_uring_prep_bind (3)
-function prepares a bind request. The submission queue entry
-.I sqe
-is setup to assign the network address at
-.IR addr ,
-of length
-.IR addrlen ,
-to the socket descriptor
-.IR sockfd.
-
-This function prepares an async
-.BR bind (2)
-request. See that man page for details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR bind (2)
diff --git a/man/io_uring_prep_bind.3.md b/man/io_uring_prep_bind.3.md
new file mode 100644
index 00000000..d4b55a50
--- /dev/null
+++ b/man/io_uring_prep_bind.3.md
@@ -0,0 +1,43 @@
+.\" Copyright (C) 2024 SUSE LLC
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: Jun 3, 2024
+footer: liburing-2.7
+header: liburing Manual
+section: 3
+title: io_uring_prep_bind
+---
+
+# NAME
+
+io_uring_prep_bind - prepare a bind request
+
+# SYNOPSIS
+
+ #include <sys/socket.h>
+ #include <liburing.h>
+
+ void io_uring_prep_bind(struct io_uring_sqe * sqe ,
+ int sockfd ,
+ const struct sockaddr * addr ,
+ socklen_t addrlen );
+
+# DESCRIPTION
+
+The **io_uring_prep_bind**(3) function prepares a bind request. The submission queue entry *sqe* is setup to assign the network address at *addr*, of length *addrlen*, to the socket descriptor *sockfd.*
+
+This function prepares an async **bind**(2) request. See that man page for details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **bind**(2)
diff --git a/man/io_uring_prep_cancel.3 b/man/io_uring_prep_cancel.3
deleted file mode 100644
index fa134d7a..00000000
--- a/man/io_uring_prep_cancel.3
+++ /dev/null
@@ -1,136 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_cancel 3 "March 12, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_cancel \- prepare a cancelation request
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_cancel64(struct io_uring_sqe *" sqe ","
-.BI " __u64 " user_data ","
-.BI " int " flags ");"
-.PP
-.BI "void io_uring_prep_cancel(struct io_uring_sqe *" sqe ","
-.BI " const void *" user_data ","
-.BI " int " flags ");"
-.PP
-.BI "void io_uring_prep_cancel_fd(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " unsigned int " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_cancel (3)
-function prepares a cancelation request. The submission queue entry
-.I sqe
-is prepared to cancel an existing request identified by
-.IR user_data .
-For the
-.I flags
-argument, see below.
-
-.BR io_uring_prep_cancel64 (3)
-is identical to
-.BR io_uring_prep_cancel (3) ,
-except it takes a 64-bit integer rather than a pointer type.
-
-The cancelation request will attempt to find the previously issued request
-identified by
-.I user_data
-and cancel it. The identifier is what the previously issued request has in
-their
-.I user_data
-field in the SQE.
-
-The
-.BR io_uring_prep_cancel_fd (3)
-function prepares a cancelation request. The submission queue entry
-.I sqe
-is prepared to cancel an existing request that used the file descriptor
-.IR fd .
-For the
-.I flags
-argument, see below.
-
-The cancelation request will attempt to find the previously issued request
-that used
-.I fd
-as the file descriptor and cancel it.
-
-By default, the first request matching the criteria given will be canceled.
-This can be modified with any of the following flags passed in:
-.TP
-.B IORING_ASYNC_CANCEL_ALL
-Cancel all requests that match the given criteria, rather than just canceling
-the first one found. Available since 5.19.
-.TP
-.B IORING_ASYNC_CANCEL_FD
-Match based on the file descriptor used in the original request rather than
-the user_data. This is what
-.BR io_uring_prep_cancel_fd (3)
-sets up. Available since 5.19.
-.TP
-.B IORING_ASYNC_CANCEL_FD_FIXED
-Set in conjunction with
-.B IORING_ASYNC_CANCEL_FD ,
-indicating that the file descriptor given is a direct descriptor rather than
-a normal file descriptor. Available since 6.0.
-.TP
-.B IORING_ASYNC_CANCEL_ANY
-Match any request in the ring, regardless of user_data or file descriptor.
-Can be used to cancel any pending request in the ring. Available since 5.19.
-.TP
-.B IORING_ASYNC_CANCEL_USERDATA
-Match request based on the user data field set in the original request. This
-is the default lookup key, if no other key matching has been specified.
-Available since 6.6.
-.TP
-.B IORING_ASYNC_CANCEL_OP
-Use the original request opcode as the matching key. The opcopde requested
-must be set in the sqe
-.I len
-field after using one of the generic cancel preparation helpers. Available
-since 6.6.
-.P
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-These are the errors that are reported in the CQE
-.I res
-field. If no flags are used to cancel multiple requests,
-.B 0
-is returned on success. If flags are used to match multiple requests, then
-a positive value is returned indicating how many requests were found and
-canceled.
-.TP
-.B -ENOENT
-The request identified by
-.I user_data
-could not be located. This could be because it completed before the cancelation
-request was issued, or if an invalid identifier is used.
-.TP
-.B -EINVAL
-One of the fields set in the SQE was invalid.
-.TP
-.B -EALREADY
-The execution state of the request has progressed far enough that cancelation
-is no longer possible. This should normally mean that it will complete shortly,
-either successfully, or interrupted due to the cancelation.
-.SH NOTES
-Although the cancelation request uses async request syntax, the kernel side of
-the cancelation is always run synchronously. It is guaranteed that a CQE is
-always generated by the time the cancel request has been submitted. If the
-cancelation is successful, the completion for the request targeted for
-cancelation will have been posted by the time submission returns. For
-.B -EALREADY
-it may take a bit of time to do so. For this case, the caller must wait for the
-canceled request to post its completion event.
-.SH SEE ALSO
-.BR io_uring_prep_poll_remove (3),
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3)
diff --git a/man/io_uring_prep_cancel.3.md b/man/io_uring_prep_cancel.3.md
new file mode 100644
index 00000000..0e4d9f56
--- /dev/null
+++ b/man/io_uring_prep_cancel.3.md
@@ -0,0 +1,97 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 12, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_cancel
+---
+
+# NAME
+
+io_uring_prep_cancel - prepare a cancelation request
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_cancel64(struct io_uring_sqe * sqe ,
+ __u64 user_data ,
+ int flags );
+
+ void io_uring_prep_cancel(struct io_uring_sqe * sqe ,
+ const void * user_data ,
+ int flags );
+
+ void io_uring_prep_cancel_fd(struct io_uring_sqe * sqe ,
+ int fd ,
+ unsigned int flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_cancel**(3) function prepares a cancelation request. The submission queue entry *sqe* is prepared to cancel an existing request identified by *user_data*. For the *flags* argument, see below.
+
+**io_uring_prep_cancel64**(3) is identical to **io_uring_prep_cancel**(3)**,** except it takes a 64-bit integer rather than a pointer type.
+
+The cancelation request will attempt to find the previously issued request identified by *user_data* and cancel it. The identifier is what the previously issued request has in their *user_data* field in the SQE.
+
+The **io_uring_prep_cancel_fd**(3) function prepares a cancelation request. The submission queue entry *sqe* is prepared to cancel an existing request that used the file descriptor *fd*. For the *flags* argument, see below.
+
+The cancelation request will attempt to find the previously issued request that used *fd* as the file descriptor and cancel it.
+
+By default, the first request matching the criteria given will be canceled. This can be modified with any of the following flags passed in:
+
+**IORING_ASYNC_CANCEL_ALL**
+
+: Cancel all requests that match the given criteria, rather than just canceling the first one found. Available since 5.19.
+
+**IORING_ASYNC_CANCEL_FD**
+
+: Match based on the file descriptor used in the original request rather than the user_data. This is what **io_uring_prep_cancel_fd**(3) sets up. Available since 5.19.
+
+**IORING_ASYNC_CANCEL_FD_FIXED**
+
+: Set in conjunction with **IORING_ASYNC_CANCEL_FD ,** indicating that the file descriptor given is a direct descriptor rather than a normal file descriptor. Available since 6.0.
+
+**IORING_ASYNC_CANCEL_ANY**
+
+: Match any request in the ring, regardless of user_data or file descriptor. Can be used to cancel any pending request in the ring. Available since 5.19.
+
+**IORING_ASYNC_CANCEL_USERDATA**
+
+: Match request based on the user data field set in the original request. This is the default lookup key, if no other key matching has been specified. Available since 6.6.
+
+**IORING_ASYNC_CANCEL_OP**
+
+: Use the original request opcode as the matching key. The opcopde requested must be set in the sqe *len* field after using one of the generic cancel preparation helpers. Available since 6.6.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+These are the errors that are reported in the CQE *res* field. If no flags are used to cancel multiple requests, **0** is returned on success. If flags are used to match multiple requests, then a positive value is returned indicating how many requests were found and canceled.
+
+**-ENOENT**
+
+: The request identified by *user_data* could not be located. This could be because it completed before the cancelation request was issued, or if an invalid identifier is used.
+
+**-EINVAL**
+
+: One of the fields set in the SQE was invalid.
+
+**-EALREADY**
+
+: The execution state of the request has progressed far enough that cancelation is no longer possible. This should normally mean that it will complete shortly, either successfully, or interrupted due to the cancelation.
+
+# NOTES
+
+Although the cancelation request uses async request syntax, the kernel side of the cancelation is always run synchronously. It is guaranteed that a CQE is always generated by the time the cancel request has been submitted. If the cancelation is successful, the completion for the request targeted for cancelation will have been posted by the time submission returns. For **-EALREADY** it may take a bit of time to do so. For this case, the caller must wait for the canceled request to post its completion event.
+
+# SEE ALSO
+
+**io_uring_prep_poll_remove**(3), **io_uring_get_sqe**(3), **io_uring_submit**(3)
diff --git a/man/io_uring_prep_cancel64.3 b/man/io_uring_prep_cancel64.3
deleted file mode 120000
index 347db090..00000000
--- a/man/io_uring_prep_cancel64.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_cancel.3
\ No newline at end of file
diff --git a/man/io_uring_prep_cancel_fd.3 b/man/io_uring_prep_cancel_fd.3
deleted file mode 120000
index 347db090..00000000
--- a/man/io_uring_prep_cancel_fd.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_cancel.3
\ No newline at end of file
diff --git a/man/io_uring_prep_close.3 b/man/io_uring_prep_close.3
deleted file mode 100644
index d7eac2e8..00000000
--- a/man/io_uring_prep_close.3
+++ /dev/null
@@ -1,67 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_close 3 "March 13, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_close \- prepare a file descriptor close request
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_close(struct io_uring_sqe *" sqe ","
-.BI " int " fd ");"
-.PP
-.BI "void io_uring_prep_close_direct(struct io_uring_sqe *" sqe ","
-.BI " unsigned " file_index ");"
-.PP
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_close (3)
-function prepares a close request. The submission queue entry
-.I sqe
-is setup to close the file descriptor indicated by
-.IR fd .
-
-For a direct descriptor close request, the offset is specified by the
-.I file_index
-argument instead of the
-.IR fd .
-This is identical to unregistering the direct descriptor, and is provided as
-a convenience. Note that even though it's closing a direct descriptor, the
-application must not set
-.B IOSQE_FIXED_FILE
-on the SQE. Otherwise the request will complete with
-.B -EBADF
-as the result.
-
-These functions prepare an async
-.BR close (2)
-request. See that man page for details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. For closing of a direct descriptor, the only
-failure cases are the kernel running completely out of memory, or if the
-application has specified an invalid direct descriptor. Note that where
-synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR close (2)
diff --git a/man/io_uring_prep_close.3.md b/man/io_uring_prep_close.3.md
new file mode 100644
index 00000000..8510f8b0
--- /dev/null
+++ b/man/io_uring_prep_close.3.md
@@ -0,0 +1,45 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 13, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_close
+---
+
+# NAME
+
+io_uring_prep_close - prepare a file descriptor close request
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_close(struct io_uring_sqe * sqe ,
+ int fd );
+
+ void io_uring_prep_close_direct(struct io_uring_sqe * sqe ,
+ unsigned file_index );
+
+# DESCRIPTION
+
+The **io_uring_prep_close**(3) function prepares a close request. The submission queue entry *sqe* is setup to close the file descriptor indicated by *fd*.
+
+For a direct descriptor close request, the offset is specified by the *file_index* argument instead of the *fd*. This is identical to unregistering the direct descriptor, and is provided as a convenience. Note that even though it\'s closing a direct descriptor, the application must not set **IOSQE_FIXED_FILE** on the SQE. Otherwise the request will complete with **-EBADF** as the result.
+
+These functions prepare an async **close**(2) request. See that man page for details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. For closing of a direct descriptor, the only failure cases are the kernel running completely out of memory, or if the application has specified an invalid direct descriptor. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **close**(2)
diff --git a/man/io_uring_prep_close_direct.3 b/man/io_uring_prep_close_direct.3
deleted file mode 120000
index d9ce6a60..00000000
--- a/man/io_uring_prep_close_direct.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_close.3
\ No newline at end of file
diff --git a/man/io_uring_prep_cmd_discard.3 b/man/io_uring_prep_cmd_discard.3
deleted file mode 100644
index 97786726..00000000
--- a/man/io_uring_prep_cmd_discard.3
+++ /dev/null
@@ -1,64 +0,0 @@
-.\" Copyright (C) 2024 Pavel Begunkov <asml.silence@gmail.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_cmd_discard 3 "Oct 13, 2024" "liburing-2.8" "liburing Manual"
-.SH NAME
-io_uring_prep_cmd_discard \- prepare a discard command
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_cmd_discard(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " uint64_t " offset ","
-.BI " uint64_t " nbytes ");"
-.fi
-.SH DESCRIPTION
-The
-.BR io_uring_prep_cmd_discard (3)
-function prepares a discard command request. The submission queue entry
-.I sqe
-is setup to use the file descriptor
-.IR fd
-to start discarding
-.I nbytes
-at the specified
-.IR offset .
-
-The command is an asynchronous equivalent of
-.B BLOCK_URING_CMD_DISCARD
-ioctl with a few differences. It allows multiple parallel discards, and it does
-not exclude concurrent writes and reads. As a result, it may lead to races for
-the data on the disk, if the application has IO inflight for the same ranges
-that the discard operates on. It's the user's responsibility to account for that.
-Furthermore, only best efforts are done to invalidate page caches. The user has
-to make sure that no other inflight requests are modifying or reading the
-range(s). If that is the case, it might result in stale page cache and data
-inconsistencies.
-
-Available since 6.12.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. On success, this field will be
-set to
-.B 0 .
-On error, a negative error value is returned. Note that where synchronous
-system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
diff --git a/man/io_uring_prep_cmd_discard.3.md b/man/io_uring_prep_cmd_discard.3.md
new file mode 100644
index 00000000..c570c51a
--- /dev/null
+++ b/man/io_uring_prep_cmd_discard.3.md
@@ -0,0 +1,44 @@
+.\" Copyright (C) 2024 Pavel Begunkov <asml.silence@gmail.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: Oct 13, 2024
+footer: liburing-2.8
+header: liburing Manual
+section: 3
+title: io_uring_prep_cmd_discard
+---
+
+# NAME
+
+io_uring_prep_cmd_discard - prepare a discard command
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_cmd_discard(struct io_uring_sqe * sqe ,
+ int fd ,
+ uint64_t offset ,
+ uint64_t nbytes );
+
+# DESCRIPTION
+
+The **io_uring_prep_cmd_discard**(3) function prepares a discard command request. The submission queue entry *sqe* is setup to use the file descriptor *fd* to start discarding *nbytes* at the specified *offset*.
+
+The command is an asynchronous equivalent of **BLOCK_URING_CMD_DISCARD** ioctl with a few differences. It allows multiple parallel discards, and it does not exclude concurrent writes and reads. As a result, it may lead to races for the data on the disk, if the application has IO inflight for the same ranges that the discard operates on. It\'s the user\'s responsibility to account for that. Furthermore, only best efforts are done to invalidate page caches. The user has to make sure that no other inflight requests are modifying or reading the range(s). If that is the case, it might result in stale page cache and data inconsistencies.
+
+Available since 6.12.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. On success, this field will be set to **0 .** On error, a negative error value is returned. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3),
diff --git a/man/io_uring_prep_cmd_getsockname.3 b/man/io_uring_prep_cmd_getsockname.3
deleted file mode 100644
index 221b49dc..00000000
--- a/man/io_uring_prep_cmd_getsockname.3
+++ /dev/null
@@ -1,79 +0,0 @@
-.\" Copyright (C) 2025 SUSE LLC.
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_cmd_getsockname 3 "December 3, 2025" "liburing-2.13" "liburing Manual"
-.SH NAME
-io_uring_prep_cmd_getsockname \- prepare a getsockname or getpeername request
-.SH SYNOPSIS
-.nf
-.B #include <sys/socket.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_cmd_getsockname(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " struct sockaddr *" sockaddr ","
-.BI " socklen_t *" sockaddr_len ","
-.BI " int " peer ");"
-.fi
-.SH DESCRIPTION
-The
-.BR io_uring_prep_cmd_getsockname (3)
-function prepares a getsockname/getpeername request.
-The submission queue entry
-.I sqe
-is setup to fetch the locally bound address or peer address of the socket
-file descriptor pointed by
-.IR sockfd .
-The parameter
-.IR sockaddr
-points to a region of size
-.IR sockaddr_len
-where the output is written.
-.IR sockaddr_len
-is modified by the kernel on return to indicate how many bytes were written.
-The output address is the locally bound address if
-.IR peer
-is set to
-.B 0
-or the peer address if
-.IR peer
-is set to
-.BR 1 .
-
-This function prepares an async
-.BR getsockname (2)
-or
-.BR getpeername (2)
-request. See those man pages for details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.BR
-Differently from the equivalent system calls, if the user attempts to
-use this operation on a non-socket file descriptor, the CQE error result
-is
-.IR ENOTSUP
-instead of
-.IR ENOSOCK.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR getsockname (2),
-.BR getpeername (2)
diff --git a/man/io_uring_prep_cmd_getsockname.3.md b/man/io_uring_prep_cmd_getsockname.3.md
new file mode 100644
index 00000000..4059e2c5
--- /dev/null
+++ b/man/io_uring_prep_cmd_getsockname.3.md
@@ -0,0 +1,45 @@
+.\" Copyright (C) 2025 SUSE LLC.
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: December 3, 2025
+footer: liburing-2.13
+header: liburing Manual
+section: 3
+title: io_uring_prep_cmd_getsockname
+---
+
+# NAME
+
+io_uring_prep_cmd_getsockname - prepare a getsockname or getpeername request
+
+# SYNOPSIS
+
+ #include <sys/socket.h>
+ #include <liburing.h>
+
+ void io_uring_prep_cmd_getsockname(struct io_uring_sqe * sqe ,
+ int fd ,
+ struct sockaddr * sockaddr ,
+ socklen_t * sockaddr_len ,
+ int peer );
+
+# DESCRIPTION
+
+The **io_uring_prep_cmd_getsockname**(3) function prepares a getsockname/getpeername request. The submission queue entry *sqe* is setup to fetch the locally bound address or peer address of the socket file descriptor pointed by *sockfd*. The parameter *sockaddr* points to a region of size *sockaddr_len* where the output is written. *sockaddr_len* is modified by the kernel on return to indicate how many bytes were written. The output address is the locally bound address if *peer* is set to **0** or the peer address if *peer* is set to **1**.
+
+This function prepares an async **getsockname**(2) or **getpeername**(2) request. See those man pages for details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field. Differently from the equivalent system calls, if the user attempts to use this operation on a non-socket file descriptor, the CQE error result is *ENOTSUP* instead of *ENOSOCK.*
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **getsockname**(2), **getpeername**(2)
diff --git a/man/io_uring_prep_cmd_sock.3 b/man/io_uring_prep_cmd_sock.3
deleted file mode 100644
index 2cc77bce..00000000
--- a/man/io_uring_prep_cmd_sock.3
+++ /dev/null
@@ -1,219 +0,0 @@
-.\" Copyright (C) 2023 Breno Leitao <leitao@debian.org>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_cmd_sock 3 "July 27, 2023" "liburing-2.5" "liburing Manual"
-.SH NAME
-io_uring_prep_cmd_sock \- prepare a command request for a socket
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_cmd_sock(struct io_uring_sqe *" sqe ","
-.BI " int " cmd_op ","
-.BI " int " fd ","
-.BI " int " level ","
-.BI " int " optname ","
-.BI " void " *optval ","
-.BI " int " optlen ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_cmd_sock (3)
-function prepares an cmd request for a socket. The submission queue entry
-.I sqe
-is setup to use the socket file descriptor pointed to by
-.I fd
-to start an command operation defined by
-.I cmd_op.
-
-This is a generic function, and each command has their own individual
-.I level, optname, optval
-values. The optlen defines the size pointed by
-.I optval.
-
-.SH Available commands
-
-.TP
-.B SOCKET_URING_OP_SIOCINQ
-Returns the amount of queued unread data in the receive buffer.
-The socket must not be in LISTEN state, otherwise an error
-.B -EINVAL
-is returned in the CQE
-.I res
-field.
-The following arguments are not used for this command
-.I level, optname, optval
-and
-.I optlen.
-
-Negative return value means an error.
-
-For more information about this command, please check
-.BR unix(7).
-
-Available since 6.7.
-
-.TP
-.B SOCKET_URING_OP_SIOCOUTQ
-Returns the amount of unsent data in the socket send queue.
-The socket must not be in LISTEN state, otherwise an error
-.B -EINVAL
-is returned in the CQE
-.I res.
-field.
-The following arguments are not used for this command
-.I level, optname, optval
-and
-.I optlen.
-
-Negative return value means an error.
-
-For more information about this command, please check
-.BR unix(7).
-
-.TP
-.B SOCKET_URING_OP_GETSOCKOPT
-Command to get options for the socket referred to by the socket file descriptor
-.I fd.
-The arguments are similar to the
-.BR getsockopt(2)
-system call.
-
-The
-.BR SOCKET_URING_OP_GETSOCKOPT
-command is limited to
-.BR SOL_SOCKET
-.I level.
-
-Differently from the
-.BR getsockopt(2)
-system call, the updated
-.I optlen
-value is returned in the CQE
-.I res
-field, on success. On failure, the CQE
-.I res
-contains a negative error number.
-
-.TP
-.B SOCKET_URING_OP_SETSOCKOPT
-Command to set options for the socket referred to by the socket file descriptor
-.I fd.
-The arguments are similar to the
-.BR setsockopt(2)
-system call.
-
-Available since 6.7.
-
-.TP
-.B SOCKET_URING_OP_TX_TIMESTAMP
-Retrieve transmit timestamps from the socket's error queue. This provides an
-alternative to the traditional
-.BR recvmsg(2)
-error queue interface for obtaining TX timestamps.
-
-The command operates in a polled multishot mode: io_uring will poll the socket
-and keep posting timestamps as CQEs until the request is cancelled or fails.
-The ring must be created with
-.B IORING_SETUP_CQE32
-or
-.B IORING_SETUP_CQE_MIXED
-to provide space for the timestamp data.
-
-The socket must first be configured for timestamping via
-.BR setsockopt(2)
-with
-.B SO_TIMESTAMPING
-at the
-.B SOL_SOCKET
-level, specifying the desired timestamp types (e.g.
-.BR SOF_TIMESTAMPING_TX_SOFTWARE ,
-.BR SOF_TIMESTAMPING_TX_SCHED ,
-.BR SOF_TIMESTAMPING_TX_ACK )
-along with
-.B SOF_TIMESTAMPING_SOFTWARE
-and
-.BR SOF_TIMESTAMPING_OPT_TSONLY .
-
-The following arguments are not used for this command:
-.I level, optname, optval
-and
-.I optlen.
-
-Each timestamp is delivered as a CQE with
-.B IORING_CQE_F_MORE
-set in
-.I cqe->flags
-to indicate more timestamps may follow. The
-.I cqe->res
-field contains the timestamp key
-.RI ( tskey ),
-which corresponds to the byte offset (for TCP) or packet count (for UDP).
-The timestamp type
-.RI ( SCM_TSTAMP_SCHED ,
-.I SCM_TSTAMP_SND
-or
-.IR SCM_TSTAMP_ACK )
-is stored in the upper bits of
-.I cqe->flags
-at offset
-.BR IORING_TIMESTAMP_TYPE_SHIFT .
-If the timestamp is a hardware timestamp, the
-.B IORING_CQE_F_TSTAMP_HW
-flag is set.
-
-The actual timestamp value is stored in the extended CQE area as a
-.B struct io_timespec
-(with 64-bit
-.I tv_sec
-and
-.I tv_nsec
-fields), accessible at
-.IR "(cqe + 1)" .
-
-The final CQE will not have
-.B IORING_CQE_F_MORE
-set, and its
-.I cqe->res
-will contain 0 on success or a negative error code on failure.
-
-Available since 6.17.
-
-.TP
-.B SOCKET_URING_OP_GETSOCKNAME
-Returns the current address to which the socket is bound. The result is
-stored in the buffer pointed to by
-.I optval,
-which should be a pointer to a
-.I struct sockaddr
-(or appropriate variant). The
-.I optlen
-argument specifies the size of the buffer. On success, the CQE
-.I res
-field contains the actual size of the socket address. If the buffer is too
-small, the result is truncated.
-
-This is the io_uring equivalent of
-.BR getsockname (2).
-
-Available since 6.19.
-
-.SH NOTES
-The memory block pointed by
-.I optval
-needs to be valid/live until the CQE returns.
-
-.SH RETURN VALUE
-Dependent on the command.
-
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_register (2),
-.BR unix (7)
diff --git a/man/io_uring_prep_cmd_sock.3.md b/man/io_uring_prep_cmd_sock.3.md
new file mode 100644
index 00000000..2e62c630
--- /dev/null
+++ b/man/io_uring_prep_cmd_sock.3.md
@@ -0,0 +1,109 @@
+.\" Copyright (C) 2023 Breno Leitao <leitao@debian.org>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: July 27, 2023
+footer: liburing-2.5
+header: liburing Manual
+section: 3
+title: io_uring_prep_cmd_sock
+---
+
+# NAME
+
+io_uring_prep_cmd_sock - prepare a command request for a socket
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_cmd_sock(struct io_uring_sqe * sqe ,
+ int cmd_op ,
+ int fd ,
+ int level ,
+ int optname ,
+ void *optval ,
+ int optlen );
+
+# DESCRIPTION
+
+The **io_uring_prep_cmd_sock**(3) function prepares an cmd request for a socket. The submission queue entry *sqe* is setup to use the socket file descriptor pointed to by *fd* to start an command operation defined by *cmd_op.*
+
+This is a generic function, and each command has their own individual *level, optname, optval* values. The optlen defines the size pointed by *optval.*
+
+# Available commands
+
+**SOCKET_URING_OP_SIOCINQ**
+
+: Returns the amount of queued unread data in the receive buffer. The socket must not be in LISTEN state, otherwise an error **-EINVAL** is returned in the CQE *res* field. The following arguments are not used for this command *level, optname, optval* and *optlen.*
+
+ Negative return value means an error.
+
+ For more information about this command, please check **unix(7).**
+
+ Available since 6.7.
+
+**SOCKET_URING_OP_SIOCOUTQ**
+
+: Returns the amount of unsent data in the socket send queue. The socket must not be in LISTEN state, otherwise an error **-EINVAL** is returned in the CQE *res.* field. The following arguments are not used for this command *level, optname, optval* and *optlen.*
+
+ Negative return value means an error.
+
+ For more information about this command, please check **unix(7).**
+
+**SOCKET_URING_OP_GETSOCKOPT**
+
+: Command to get options for the socket referred to by the socket file descriptor *fd.* The arguments are similar to the **getsockopt(2)** system call.
+
+ The **SOCKET_URING_OP_GETSOCKOPT** command is limited to **SOL_SOCKET** *level.*
+
+ Differently from the **getsockopt(2)** system call, the updated *optlen* value is returned in the CQE *res* field, on success. On failure, the CQE *res* contains a negative error number.
+
+**SOCKET_URING_OP_SETSOCKOPT**
+
+: Command to set options for the socket referred to by the socket file descriptor *fd.* The arguments are similar to the **setsockopt(2)** system call.
+
+ Available since 6.7.
+
+**SOCKET_URING_OP_TX_TIMESTAMP**
+
+: Retrieve transmit timestamps from the socket\'s error queue. This provides an alternative to the traditional **recvmsg(2)** error queue interface for obtaining TX timestamps.
+
+ The command operates in a polled multishot mode: io_uring will poll the socket and keep posting timestamps as CQEs until the request is cancelled or fails. The ring must be created with **IORING_SETUP_CQE32** or **IORING_SETUP_CQE_MIXED** to provide space for the timestamp data.
+
+ The socket must first be configured for timestamping via **setsockopt(2)** with **SO_TIMESTAMPING** at the **SOL_SOCKET** level, specifying the desired timestamp types (e.g. **SOF_TIMESTAMPING_TX_SOFTWARE**, **SOF_TIMESTAMPING_TX_SCHED**, **SOF_TIMESTAMPING_TX_ACK**) along with **SOF_TIMESTAMPING_SOFTWARE** and **SOF_TIMESTAMPING_OPT_TSONLY**.
+
+ The following arguments are not used for this command: *level, optname, optval* and *optlen.*
+
+ Each timestamp is delivered as a CQE with **IORING_CQE_F_MORE** set in *cqe-\>flags* to indicate more timestamps may follow. The *cqe-\>res* field contains the timestamp key (*tskey*), which corresponds to the byte offset (for TCP) or packet count (for UDP). The timestamp type (*SCM_TSTAMP_SCHED*, *SCM_TSTAMP_SND* or *SCM_TSTAMP_ACK*) is stored in the upper bits of *cqe-\>flags* at offset **IORING_TIMESTAMP_TYPE_SHIFT**. If the timestamp is a hardware timestamp, the **IORING_CQE_F_TSTAMP_HW** flag is set.
+
+ The actual timestamp value is stored in the extended CQE area as a **struct io_timespec** (with 64-bit *tv_sec* and *tv_nsec* fields), accessible at *(cqe + 1)*.
+
+ The final CQE will not have **IORING_CQE_F_MORE** set, and its *cqe-\>res* will contain 0 on success or a negative error code on failure.
+
+ Available since 6.17.
+
+**SOCKET_URING_OP_GETSOCKNAME**
+
+: Returns the current address to which the socket is bound. The result is stored in the buffer pointed to by *optval,* which should be a pointer to a *struct sockaddr* (or appropriate variant). The *optlen* argument specifies the size of the buffer. On success, the CQE *res* field contains the actual size of the socket address. If the buffer is too small, the result is truncated.
+
+ This is the io_uring equivalent of **getsockname**(2).
+
+ Available since 6.19.
+
+# NOTES
+
+The memory block pointed by *optval* needs to be valid/live until the CQE returns.
+
+# RETURN VALUE
+
+Dependent on the command.
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_register**(2), **unix**(7)
diff --git a/man/io_uring_prep_connect.3 b/man/io_uring_prep_connect.3
deleted file mode 100644
index 6a7c64a6..00000000
--- a/man/io_uring_prep_connect.3
+++ /dev/null
@@ -1,66 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_connect 3 "March 13, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_connect \- prepare a connect request
-.SH SYNOPSIS
-.nf
-.B #include <sys/types.h>
-.B #include <sys/socket.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_connect(struct io_uring_sqe *" sqe ","
-.BI " int " sockfd ","
-.BI " const struct sockaddr *" addr ","
-.BI " socklen_t " addrlen ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_connect (3)
-function prepares a connect request. The submission queue entry
-.I sqe
-is setup to use the file descriptor
-.I sockfd
-to start connecting to the destination described by the socket address at
-.I addr
-and of structure length
-.IR addrlen .
-
-This function prepares an async
-.BR connect (2)
-request. See that man page for details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-As with any request that passes in data in a struct, that data must remain
-valid until the request has been successfully submitted. It need not remain
-valid until completion. Once a request has been submitted, the in-kernel
-state is stable. Very early kernels (5.4 and earlier) required state to be
-stable until the completion occurred. Applications can test for this
-behavior by inspecting the
-.B IORING_FEAT_SUBMIT_STABLE
-flag passed back from
-.BR io_uring_queue_init_params (3).
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR connect (2)
diff --git a/man/io_uring_prep_connect.3.md b/man/io_uring_prep_connect.3.md
new file mode 100644
index 00000000..5ce356ac
--- /dev/null
+++ b/man/io_uring_prep_connect.3.md
@@ -0,0 +1,48 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 13, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_connect
+---
+
+# NAME
+
+io_uring_prep_connect - prepare a connect request
+
+# SYNOPSIS
+
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <liburing.h>
+
+ void io_uring_prep_connect(struct io_uring_sqe * sqe ,
+ int sockfd ,
+ const struct sockaddr * addr ,
+ socklen_t addrlen );
+
+# DESCRIPTION
+
+The **io_uring_prep_connect**(3) function prepares a connect request. The submission queue entry *sqe* is setup to use the file descriptor *sockfd* to start connecting to the destination described by the socket address at *addr* and of structure length *addrlen*.
+
+This function prepares an async **connect**(2) request. See that man page for details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+As with any request that passes in data in a struct, that data must remain valid until the request has been successfully submitted. It need not remain valid until completion. Once a request has been submitted, the in-kernel state is stable. Very early kernels (5.4 and earlier) required state to be stable until the completion occurred. Applications can test for this behavior by inspecting the **IORING_FEAT_SUBMIT_STABLE** flag passed back from **io_uring_queue_init_params**(3).
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **connect**(2)
diff --git a/man/io_uring_prep_epoll_ctl.3 b/man/io_uring_prep_epoll_ctl.3
deleted file mode 100644
index f709a9ac..00000000
--- a/man/io_uring_prep_epoll_ctl.3
+++ /dev/null
@@ -1,74 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_epoll_ctl 3 "January 18, 2025" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_prep_epoll_ctl \- prepare an epoll_ctl request
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_epoll_ctl(struct io_uring_sqe *" sqe ","
-.BI " int " epfd ","
-.BI " int " fd ","
-.BI " int " op ","
-.BI " const struct epoll_event *" ev ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_epoll_ctl (3)
-function prepares an epoll control request. The submission queue entry
-.I sqe
-is setup to use the epoll instance referred to by
-.IR epfd ,
-performing the operation
-.I op
-on the file descriptor
-.IR fd .
-The
-.I ev
-argument points to an
-.I epoll_event
-structure as defined in
-.BR epoll_ctl (2).
-
-The
-.I op
-argument can be one of:
-.TP
-.B EPOLL_CTL_ADD
-Add
-.I fd
-to the epoll instance.
-.TP
-.B EPOLL_CTL_MOD
-Modify the settings for
-.IR fd .
-.TP
-.B EPOLL_CTL_DEL
-Remove
-.I fd
-from the epoll instance.
-.I ev
-is ignored for this operation.
-
-This function prepares an async
-.BR epoll_ctl (2)
-request. See that man page for details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation, 0 on success. On error,
-a negative errno value is returned. See
-.BR epoll_ctl (2)
-for possible error values.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_prep_epoll_wait (3),
-.BR epoll_ctl (2)
diff --git a/man/io_uring_prep_epoll_ctl.3.md b/man/io_uring_prep_epoll_ctl.3.md
new file mode 100644
index 00000000..51271960
--- /dev/null
+++ b/man/io_uring_prep_epoll_ctl.3.md
@@ -0,0 +1,57 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_prep_epoll_ctl
+---
+
+# NAME
+
+io_uring_prep_epoll_ctl - prepare an epoll_ctl request
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_epoll_ctl(struct io_uring_sqe * sqe ,
+ int epfd ,
+ int fd ,
+ int op ,
+ const struct epoll_event * ev );
+
+# DESCRIPTION
+
+The **io_uring_prep_epoll_ctl**(3) function prepares an epoll control request. The submission queue entry *sqe* is setup to use the epoll instance referred to by *epfd*, performing the operation *op* on the file descriptor *fd*. The *ev* argument points to an *epoll_event* structure as defined in **epoll_ctl**(2).
+
+The *op* argument can be one of:
+
+**EPOLL_CTL_ADD**
+
+: Add *fd* to the epoll instance.
+
+**EPOLL_CTL_MOD**
+
+: Modify the settings for *fd*.
+
+**EPOLL_CTL_DEL**
+
+: Remove *fd* from the epoll instance. *ev* is ignored for this operation.
+
+ This function prepares an async **epoll_ctl**(2) request. See that man page for details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation, 0 on success. On error, a negative errno value is returned. See **epoll_ctl**(2) for possible error values.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_prep_epoll_wait**(3), **epoll_ctl**(2)
diff --git a/man/io_uring_prep_epoll_wait.3 b/man/io_uring_prep_epoll_wait.3
deleted file mode 100644
index 292f3974..00000000
--- a/man/io_uring_prep_epoll_wait.3
+++ /dev/null
@@ -1,64 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_epoll_wait 3 "March 6, 2025" "liburing-2.10" "liburing Manual"
-.SH NAME
-io_uring_prep_epoll_wait \- prepare an epoll wait request
-.SH SYNOPSIS
-.nf
-.B #include <sys/epoll.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_epoll_wait(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " struct epoll_event *" events ","
-.BI " int " maxevents ","
-.BI " unsigned flags ");"
-.PP
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_epoll_wait (3)
-function prepares an epoll_wait request. The submission queue entry
-.I sqe
-is setup to wait on a maximum of
-.IR maxevents
-events on the epoll file descriptor indicated by
-.IR fd ,
-and filling the received events into the memory pointed to by
-.IR events .
-
-This function prepares an async
-.BR epoll_wait (2)
-request. See that man page for details. The use case is mostly for legacy
-event loops, where certain file descriptors may still be using epoll for
-readiness notifications. Normally this would necessitate using epoll_wait
-with the io_uring fd added to that set as well, which is suboptimal as
-epoll doesn't provide the same kind of fine grained batch control and
-wakeup reductions that io_uring does. By using io_uring to read epoll events,
-the event loop can be entirely switched to io_uring, and reap the benefits
-of batch waiting and context switch reductions.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR epoll_wait (2)
diff --git a/man/io_uring_prep_epoll_wait.3.md b/man/io_uring_prep_epoll_wait.3.md
new file mode 100644
index 00000000..8c1adbc5
--- /dev/null
+++ b/man/io_uring_prep_epoll_wait.3.md
@@ -0,0 +1,44 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 6, 2025
+footer: liburing-2.10
+header: liburing Manual
+section: 3
+title: io_uring_prep_epoll_wait
+---
+
+# NAME
+
+io_uring_prep_epoll_wait - prepare an epoll wait request
+
+# SYNOPSIS
+
+ #include <sys/epoll.h>
+ #include <liburing.h>
+
+ void io_uring_prep_epoll_wait(struct io_uring_sqe * sqe ,
+ int fd ,
+ struct epoll_event * events ,
+ int maxevents ,
+ unsigned flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_epoll_wait**(3) function prepares an epoll_wait request. The submission queue entry *sqe* is setup to wait on a maximum of *maxevents* events on the epoll file descriptor indicated by *fd*, and filling the received events into the memory pointed to by *events*.
+
+This function prepares an async **epoll_wait**(2) request. See that man page for details. The use case is mostly for legacy event loops, where certain file descriptors may still be using epoll for readiness notifications. Normally this would necessitate using epoll_wait with the io_uring fd added to that set as well, which is suboptimal as epoll doesn\'t provide the same kind of fine grained batch control and wakeup reductions that io_uring does. By using io_uring to read epoll events, the event loop can be entirely switched to io_uring, and reap the benefits of batch waiting and context switch reductions.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **epoll_wait**(2)
diff --git a/man/io_uring_prep_fadvise.3 b/man/io_uring_prep_fadvise.3
deleted file mode 100644
index 226eee59..00000000
--- a/man/io_uring_prep_fadvise.3
+++ /dev/null
@@ -1,76 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_fadvise 3 "March 13, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_fadvise \- prepare a fadvise request
-.SH SYNOPSIS
-.nf
-.B #include <fcntl.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_fadvise(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " __u64 " offset ","
-.BI " __u32 " len ","
-.BI " int " advice ");"
-.BI "
-.BI "void io_uring_prep_fadvise64(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " __u64 " offset ","
-.BI " off_t " len ","
-.BI " int " advice ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_fadvise (3)
-function prepares an fadvise request. The submission queue entry
-.I sqe
-is setup to use the file descriptor pointed to by
-.I fd
-to start an fadvise operation at
-.I offset
-and of
-.I len
-length in bytes, giving it the advise located in
-.IR advice .
-
-The
-.BR io_uring_prep_fadvise64 (3)
-function works like
-.BR io_uring_prep_fadvise (3)
-except that it takes a 64-bit length rather than just a 32-bit one. Older
-kernels may not support the 64-bit length variant. If this variant is attempted
-used on a kernel that doesn't support 64-bit lengths, then the request will get
-errored with
-.B -EINVAL
-in the results field of the CQE.
-
-This function prepares an async
-.BR posix_fadvise (2)
-request. See that man page for details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_register (2),
-.BR posix_fadvise (2)
diff --git a/man/io_uring_prep_fadvise.3.md b/man/io_uring_prep_fadvise.3.md
new file mode 100644
index 00000000..83f571b7
--- /dev/null
+++ b/man/io_uring_prep_fadvise.3.md
@@ -0,0 +1,52 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 13, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_fadvise
+---
+
+# NAME
+
+io_uring_prep_fadvise - prepare a fadvise request
+
+# SYNOPSIS
+
+ #include <fcntl.h>
+ #include <liburing.h>
+
+ void io_uring_prep_fadvise(struct io_uring_sqe * sqe ,
+ int fd ,
+ __u64 offset ,
+ __u32 len ,
+ int advice );
+
+ void io_uring_prep_fadvise64(struct io_uring_sqe * sqe ,
+ int fd ,
+ __u64 offset ,
+ off_t len ,
+ int advice );
+
+# DESCRIPTION
+
+The **io_uring_prep_fadvise**(3) function prepares an fadvise request. The submission queue entry *sqe* is setup to use the file descriptor pointed to by *fd* to start an fadvise operation at *offset* and of *len* length in bytes, giving it the advise located in *advice*.
+
+The **io_uring_prep_fadvise64**(3) function works like **io_uring_prep_fadvise**(3) except that it takes a 64-bit length rather than just a 32-bit one. Older kernels may not support the 64-bit length variant. If this variant is attempted used on a kernel that doesn\'t support 64-bit lengths, then the request will get errored with **-EINVAL** in the results field of the CQE.
+
+This function prepares an async **posix_fadvise**(2) request. See that man page for details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_register**(2), **posix_fadvise**(2)
diff --git a/man/io_uring_prep_fadvise64.3 b/man/io_uring_prep_fadvise64.3
deleted file mode 120000
index cfd68287..00000000
--- a/man/io_uring_prep_fadvise64.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_fadvise.3
\ No newline at end of file
diff --git a/man/io_uring_prep_fallocate.3 b/man/io_uring_prep_fallocate.3
deleted file mode 100644
index 426e1d52..00000000
--- a/man/io_uring_prep_fallocate.3
+++ /dev/null
@@ -1,59 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_fallocate 3 "March 13, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_fallocate \- prepare a fallocate request
-.SH SYNOPSIS
-.nf
-.B #include <fcntl.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_fallocate(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " int " mode ","
-.BI " __u64 " offset ","
-.BI " __u64 " len ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_fallocate (3)
-function prepares a fallocate request. The submission queue entry
-.I sqe
-is setup to use the file descriptor pointed to by
-.I fd
-to start a fallocate operation described by
-.I mode
-at offset
-.I offset
-and
-.I len
-length in bytes.
-
-This function prepares an async
-.BR fallocate (2)
-request. See that man page for details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR fallocate (2)
diff --git a/man/io_uring_prep_fallocate.3.md b/man/io_uring_prep_fallocate.3.md
new file mode 100644
index 00000000..9900e82c
--- /dev/null
+++ b/man/io_uring_prep_fallocate.3.md
@@ -0,0 +1,44 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 13, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_fallocate
+---
+
+# NAME
+
+io_uring_prep_fallocate - prepare a fallocate request
+
+# SYNOPSIS
+
+ #include <fcntl.h>
+ #include <liburing.h>
+
+ void io_uring_prep_fallocate(struct io_uring_sqe * sqe ,
+ int fd ,
+ int mode ,
+ __u64 offset ,
+ __u64 len );
+
+# DESCRIPTION
+
+The **io_uring_prep_fallocate**(3) function prepares a fallocate request. The submission queue entry *sqe* is setup to use the file descriptor pointed to by *fd* to start a fallocate operation described by *mode* at offset *offset* and *len* length in bytes.
+
+This function prepares an async **fallocate**(2) request. See that man page for details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **fallocate**(2)
diff --git a/man/io_uring_prep_fgetxattr.3 b/man/io_uring_prep_fgetxattr.3
deleted file mode 120000
index fd0634a9..00000000
--- a/man/io_uring_prep_fgetxattr.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_getxattr.3
\ No newline at end of file
diff --git a/man/io_uring_prep_files_update.3 b/man/io_uring_prep_files_update.3
deleted file mode 100644
index bedb85e0..00000000
--- a/man/io_uring_prep_files_update.3
+++ /dev/null
@@ -1,92 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_files_update 3 "March 13, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_files_update \- prepare a registered file update request
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_files_update(struct io_uring_sqe *" sqe ","
-.BI " int *" fds ","
-.BI " unsigned " nr_fds ","
-.BI " int " offset ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_files_update (3)
-function prepares a request for updating a number of previously registered file
-descriptors. The submission queue entry
-.I sqe
-is setup to use the file descriptor array pointed to by
-.I fds
-and of
-.I nr_fds
-in length to update that amount of previously registered files starting at
-offset
-.IR offset .
-
-Once a previously registered file is updated with a new one, the existing
-entry is updated and then removed from the table. This operation is equivalent to
-first unregistering that entry and then inserting a new one, just bundled into
-one combined operation.
-
-If
-.I offset
-is specified as IORING_FILE_INDEX_ALLOC, io_uring will allocate free direct
-descriptors instead of having the application to pass, and store allocated
-direct descriptors into
-.I fds
-array,
-.I cqe->res
-will return the number of direct descriptors allocated.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-These are the errors that are reported in the CQE
-.I res
-field. On success,
-.I res
-will contain the number of successfully updated file descriptors. On error,
-the following errors can occur.
-.TP
-.B -ENOMEM
-The kernel was unable to allocate memory for the request.
-.TP
-.B -EINVAL
-One of the fields set in the SQE was invalid.
-.TP
-.B -EFAULT
-The kernel was unable to copy in the memory pointed to by
-.IR fds .
-.TP
-.B -EBADF
-On of the descriptors located in
-.I fds
-didn't refer to a valid file descriptor, or one of the file descriptors in
-the array referred to an io_uring instance.
-.TP
-.B -EOVERFLOW
-The product of
-.I offset
-and
-.I nr_fds
-exceed the valid amount or overflowed.
-.SH NOTES
-As with any request that passes in data in a struct, that data must remain
-valid until the request has been successfully submitted. It need not remain
-valid until completion. Once a request has been submitted, the in-kernel
-state is stable. Very early kernels (5.4 and earlier) required state to be
-stable until the completion occurred. Applications can test for this
-behavior by inspecting the
-.B IORING_FEAT_SUBMIT_STABLE
-flag passed back from
-.BR io_uring_queue_init_params (3).
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_register (2)
diff --git a/man/io_uring_prep_files_update.3.md b/man/io_uring_prep_files_update.3.md
new file mode 100644
index 00000000..b6135ce1
--- /dev/null
+++ b/man/io_uring_prep_files_update.3.md
@@ -0,0 +1,68 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 13, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_files_update
+---
+
+# NAME
+
+io_uring_prep_files_update - prepare a registered file update request
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_files_update(struct io_uring_sqe * sqe ,
+ int * fds ,
+ unsigned nr_fds ,
+ int offset );
+
+# DESCRIPTION
+
+The **io_uring_prep_files_update**(3) function prepares a request for updating a number of previously registered file descriptors. The submission queue entry *sqe* is setup to use the file descriptor array pointed to by *fds* and of *nr_fds* in length to update that amount of previously registered files starting at offset *offset*.
+
+Once a previously registered file is updated with a new one, the existing entry is updated and then removed from the table. This operation is equivalent to first unregistering that entry and then inserting a new one, just bundled into one combined operation.
+
+If *offset* is specified as IORING_FILE_INDEX_ALLOC, io_uring will allocate free direct descriptors instead of having the application to pass, and store allocated direct descriptors into *fds* array, *cqe-\>res* will return the number of direct descriptors allocated.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+These are the errors that are reported in the CQE *res* field. On success, *res* will contain the number of successfully updated file descriptors. On error, the following errors can occur.
+
+**-ENOMEM**
+
+: The kernel was unable to allocate memory for the request.
+
+**-EINVAL**
+
+: One of the fields set in the SQE was invalid.
+
+**-EFAULT**
+
+: The kernel was unable to copy in the memory pointed to by *fds*.
+
+**-EBADF**
+
+: On of the descriptors located in *fds* didn\'t refer to a valid file descriptor, or one of the file descriptors in the array referred to an io_uring instance.
+
+**-EOVERFLOW**
+
+: The product of *offset* and *nr_fds* exceed the valid amount or overflowed.
+
+# NOTES
+
+As with any request that passes in data in a struct, that data must remain valid until the request has been successfully submitted. It need not remain valid until completion. Once a request has been submitted, the in-kernel state is stable. Very early kernels (5.4 and earlier) required state to be stable until the completion occurred. Applications can test for this behavior by inspecting the **IORING_FEAT_SUBMIT_STABLE** flag passed back from **io_uring_queue_init_params**(3).
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_register**(2)
diff --git a/man/io_uring_prep_fixed_fd_install.3 b/man/io_uring_prep_fixed_fd_install.3
deleted file mode 100644
index 3300c450..00000000
--- a/man/io_uring_prep_fixed_fd_install.3
+++ /dev/null
@@ -1,70 +0,0 @@
-.\" Copyright (C) 2023 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_fixed_fd_install 3 "December 8, 2023" "liburing-2.6" "liburing Manual"
-.SH NAME
-io_uring_prep_fixed_fd_install \- prepare fixed file fd installation request
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_fixed_fd_install(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " unsigned int " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_fixed_fd_install (3)
-helper prepares a fixed file descriptor installation. The submission queue entry
-.I sqe
-is setup to install the direct/fixed file descriptor
-.I fd
-with the specified
-.I flags
-file installation flags.
-
-One use case of direct/fixed file descriptors is to turn a regular file
-descriptor into a direct one, reducing the overhead of any request that
-needs to access this file. This helper provides a way to go the other way,
-turning a direct descriptor into a regular file descriptor that can then
-subsequently be used by regular system calls that take a normal file descriptor.
-This can be handy if no regular file descriptor exists for this direct
-descriptor. Either because it was instantiated directly as a fixed descriptor,
-or because the regular file was closed with
-.BR close (2)
-after being turned into a direct descriptor.
-
-Upon successful return of this request, both a normal and fixed file descriptor
-exists for the same file. Either one of them may be used to access the file.
-Either one of them may be closed without affecting the other one.
-
-.I flags
-may be either zero, or set to
-.B IORING_FIXED_FD_NO_CLOEXEC
-to indicate that the new regular file descriptor should not be closed during
-exec. By default,
-.B O_CLOEXEC
-will be set on the new descriptor otherwise. Setting this field to anything but
-those two values will result in the request being failed with
-.B -EINVAL
-in the CQE
-.I res
-field.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation, which in this case will be the
-value of the new regular file descriptor. In case of failure, a negative value
-is returned.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_register_files (3),
-.BR io_uring_unregister_files (3),
-.BR io_uring_prep_close_direct (3),
-.BR io_uring_prep_openat_direct (3)
diff --git a/man/io_uring_prep_fixed_fd_install.3.md b/man/io_uring_prep_fixed_fd_install.3.md
new file mode 100644
index 00000000..4814ddfc
--- /dev/null
+++ b/man/io_uring_prep_fixed_fd_install.3.md
@@ -0,0 +1,45 @@
+.\" Copyright (C) 2023 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: December 8, 2023
+footer: liburing-2.6
+header: liburing Manual
+section: 3
+title: io_uring_prep_fixed_fd_install
+---
+
+# NAME
+
+io_uring_prep_fixed_fd_install - prepare fixed file fd installation request
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_fixed_fd_install(struct io_uring_sqe * sqe ,
+ int fd ,
+ unsigned int flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_fixed_fd_install**(3) helper prepares a fixed file descriptor installation. The submission queue entry *sqe* is setup to install the direct/fixed file descriptor *fd* with the specified *flags* file installation flags.
+
+One use case of direct/fixed file descriptors is to turn a regular file descriptor into a direct one, reducing the overhead of any request that needs to access this file. This helper provides a way to go the other way, turning a direct descriptor into a regular file descriptor that can then subsequently be used by regular system calls that take a normal file descriptor. This can be handy if no regular file descriptor exists for this direct descriptor. Either because it was instantiated directly as a fixed descriptor, or because the regular file was closed with **close**(2) after being turned into a direct descriptor.
+
+Upon successful return of this request, both a normal and fixed file descriptor exists for the same file. Either one of them may be used to access the file. Either one of them may be closed without affecting the other one.
+
+*flags* may be either zero, or set to **IORING_FIXED_FD_NO_CLOEXEC** to indicate that the new regular file descriptor should not be closed during exec. By default, **O_CLOEXEC** will be set on the new descriptor otherwise. Setting this field to anything but those two values will result in the request being failed with **-EINVAL** in the CQE *res* field.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation, which in this case will be the value of the new regular file descriptor. In case of failure, a negative value is returned.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_register_files**(3), **io_uring_unregister_files**(3), **io_uring_prep_close_direct**(3), **io_uring_prep_openat_direct**(3)
diff --git a/man/io_uring_prep_fsetxattr.3 b/man/io_uring_prep_fsetxattr.3
deleted file mode 120000
index 724254cd..00000000
--- a/man/io_uring_prep_fsetxattr.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_setxattr.3
\ No newline at end of file
diff --git a/man/io_uring_prep_fsync.3 b/man/io_uring_prep_fsync.3
deleted file mode 100644
index a3259a0c..00000000
--- a/man/io_uring_prep_fsync.3
+++ /dev/null
@@ -1,70 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_fsync 3 "March 12, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_fsync \- prepare an fsync request
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_fsync(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " unsigned " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_fsync (3)
-function prepares an fsync request. The submission queue entry
-.I sqe
-is setup to use the file descriptor
-.I fd
-that should get synced, with the modifier flags indicated by the
-.I flags
-argument.
-
-This function prepares an fsync request. It can act either like an
-.BR fsync (2)
-operation, which is the default behavior. If
-.B IORING_FSYNC_DATASYNC
-is set in the
-.I flags
-argument, then it behaves like
-.BR fdatasync (2).
-If no range is specified, the
-.I fd
-will be synced from 0 to end-of-file.
-
-It's possible to specify a range to sync, if one is desired. If the
-.I off
-field of the SQE is set to non-zero, then that indicates the offset to
-start syncing at. If
-.I len
-is set in the SQE, then that indicates the size in bytes to sync from the
-offset. Note that these fields are not accepted by this helper, so they have
-to be set manually in the SQE after calling this prep helper.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR fsync (2),
-.BR fdatasync (2)
diff --git a/man/io_uring_prep_fsync.3.md b/man/io_uring_prep_fsync.3.md
new file mode 100644
index 00000000..5a6f850f
--- /dev/null
+++ b/man/io_uring_prep_fsync.3.md
@@ -0,0 +1,43 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 12, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_fsync
+---
+
+# NAME
+
+io_uring_prep_fsync - prepare an fsync request
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_fsync(struct io_uring_sqe * sqe ,
+ int fd ,
+ unsigned flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_fsync**(3) function prepares an fsync request. The submission queue entry *sqe* is setup to use the file descriptor *fd* that should get synced, with the modifier flags indicated by the *flags* argument.
+
+This function prepares an fsync request. It can act either like an **fsync**(2) operation, which is the default behavior. If **IORING_FSYNC_DATASYNC** is set in the *flags* argument, then it behaves like **fdatasync**(2). If no range is specified, the *fd* will be synced from 0 to end-of-file.
+
+It\'s possible to specify a range to sync, if one is desired. If the *off* field of the SQE is set to non-zero, then that indicates the offset to start syncing at. If *len* is set in the SQE, then that indicates the size in bytes to sync from the offset. Note that these fields are not accepted by this helper, so they have to be set manually in the SQE after calling this prep helper.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **fsync**(2), **fdatasync**(2)
diff --git a/man/io_uring_prep_ftruncate.3 b/man/io_uring_prep_ftruncate.3
deleted file mode 100644
index e3f1f7e0..00000000
--- a/man/io_uring_prep_ftruncate.3
+++ /dev/null
@@ -1,54 +0,0 @@
-.\" Copyright (C) 2024 Tony Solomonik <tony.solomonik@gmail.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_ftruncate 3 "January 23, 2024" "liburing-2.6" "liburing Manual"
-.SH NAME
-io_uring_prep_ftruncate \- prepare an ftruncate request
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_ftruncate(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " loff_t " len ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_ftruncate (3)
-function prepares an ftruncate request. The submission queue entry
-.I sqe
-is setup to use the file descriptor
-.I fd
-that should get truncated to the length indicated by the
-.I len
-argument.
-
-Applications must define
-.B _GNU_SOURCE
-to obtain the definition of this helper, as
-.I loff_t
-will not be defined without it.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR ftruncate (2),
diff --git a/man/io_uring_prep_ftruncate.3.md b/man/io_uring_prep_ftruncate.3.md
new file mode 100644
index 00000000..39a87371
--- /dev/null
+++ b/man/io_uring_prep_ftruncate.3.md
@@ -0,0 +1,41 @@
+.\" Copyright (C) 2024 Tony Solomonik <tony.solomonik@gmail.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 23, 2024
+footer: liburing-2.6
+header: liburing Manual
+section: 3
+title: io_uring_prep_ftruncate
+---
+
+# NAME
+
+io_uring_prep_ftruncate - prepare an ftruncate request
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_ftruncate(struct io_uring_sqe * sqe ,
+ int fd ,
+ loff_t len );
+
+# DESCRIPTION
+
+The **io_uring_prep_ftruncate**(3) function prepares an ftruncate request. The submission queue entry *sqe* is setup to use the file descriptor *fd* that should get truncated to the length indicated by the *len* argument.
+
+Applications must define **\_GNU_SOURCE** to obtain the definition of this helper, as *loff_t* will not be defined without it.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **ftruncate**(2),
diff --git a/man/io_uring_prep_futex_wait.3 b/man/io_uring_prep_futex_wait.3
deleted file mode 100644
index cf9bc455..00000000
--- a/man/io_uring_prep_futex_wait.3
+++ /dev/null
@@ -1,94 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_futex_wait 3 "Sep 29, 2023" "liburing-2.5" "liburing Manual"
-.SH NAME
-io_uring_prep_futex_wait \- prepare a futex wait request
-.SH SYNOPSIS
-.nf
-.B #include <linux/futex.h>
-.B #include <unistd.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_futex_wait(struct io_uring_sqe *" sqe ","
-.BI " const uint32_t *" futex ","
-.BI " uint64_t " val ","
-.BI " uint64_t " mask ","
-.BI " uint32_t " futex_flags ","
-.BI " unsigned int " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_futex_wait (3)
-function prepares a futex wait request. The submission queue entry
-.I sqe
-is setup for waiting on a futex at address
-.I futex
-and which still has the value
-.I val
-and with
-.BR futex2 (2)
-flags of
-.I futex_flags
-and io_uring futex flags of
-.I flags .
-
-.I mask
-can be set to a specific bitset mask, which will be matched by the waking
-side to decide who to wake up. To always get woken, an application may use
-.B FUTEX_BITSET_MATCH_ANY .
-
-.I futex_flags
-follows the
-.BR futex2 (2)
-flags, not the
-.BR futex (2)
-v1 interface flags.
-
-.I flags
-are currently unused and hence
-.B 0
-must be passed.
-
-This function prepares an async
-.BR futex (2)
-wait request. See that man page for details. Note that the io_uring futex
-wait request is similar to the
-.B FUTEX_WAIT_BITSET
-operation, as
-.B FUTEX_WAIT
-is a strict subset of that.
-
-Available since kernel 6.7.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-Unlike the sync futex syscalls that wait on a futex, io_uring does not support
-passing in a timeout for the request. Instead, applications are encouraged
-to use a linked timeout to abort the futex request at a given time, if desired.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_prep_futex_waitv (3),
-.BR io_uring_prep_futex_wake (3),
-.BR io_uring_prep_link_timeout (3),
-.BR futex (2)
-.BR futex2 (2)
diff --git a/man/io_uring_prep_futex_wait.3.md b/man/io_uring_prep_futex_wait.3.md
new file mode 100644
index 00000000..c0105601
--- /dev/null
+++ b/man/io_uring_prep_futex_wait.3.md
@@ -0,0 +1,58 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: Sep 29, 2023
+footer: liburing-2.5
+header: liburing Manual
+section: 3
+title: io_uring_prep_futex_wait
+---
+
+# NAME
+
+io_uring_prep_futex_wait - prepare a futex wait request
+
+# SYNOPSIS
+
+ #include <linux/futex.h>
+ #include <unistd.h>
+ #include <liburing.h>
+
+ void io_uring_prep_futex_wait(struct io_uring_sqe * sqe ,
+ const uint32_t * futex ,
+ uint64_t val ,
+ uint64_t mask ,
+ uint32_t futex_flags ,
+ unsigned int flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_futex_wait**(3) function prepares a futex wait request. The submission queue entry *sqe* is setup for waiting on a futex at address *futex* and which still has the value *val* and with **futex2**(2) flags of *futex_flags* and io_uring futex flags of *flags .*
+
+*mask* can be set to a specific bitset mask, which will be matched by the waking side to decide who to wake up. To always get woken, an application may use **FUTEX_BITSET_MATCH_ANY .**
+
+*futex_flags* follows the **futex2**(2) flags, not the **futex**(2) v1 interface flags.
+
+*flags* are currently unused and hence **0** must be passed.
+
+This function prepares an async **futex**(2) wait request. See that man page for details. Note that the io_uring futex wait request is similar to the **FUTEX_WAIT_BITSET** operation, as **FUTEX_WAIT** is a strict subset of that.
+
+Available since kernel 6.7.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+Unlike the sync futex syscalls that wait on a futex, io_uring does not support passing in a timeout for the request. Instead, applications are encouraged to use a linked timeout to abort the futex request at a given time, if desired.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_prep_futex_waitv**(3), **io_uring_prep_futex_wake**(3), **io_uring_prep_link_timeout**(3), **futex**(2) **futex2**(2)
diff --git a/man/io_uring_prep_futex_waitv.3 b/man/io_uring_prep_futex_waitv.3
deleted file mode 100644
index d81fb9de..00000000
--- a/man/io_uring_prep_futex_waitv.3
+++ /dev/null
@@ -1,78 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_futex_waitv 3 "Sep 29, 2023" "liburing-2.5" "liburing Manual"
-.SH NAME
-io_uring_prep_futex_waitv \- prepare a futex waitv request
-.SH SYNOPSIS
-.nf
-.B #include <linux/futex.h>
-.B #include <unistd.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_futex_waitv(struct io_uring_sqe *" sqe ","
-.BI " const struct futex_waitv *" futexv ","
-.BI " uint32_t " nr_futex ","
-.BI " unsigned int " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_futex_waitv (3)
-function prepares a futex wait request for multiple futexes at the same time.
-The submission queue entry
-.I sqe
-is setup for waiting on all futexes given by
-.I futexv
-and
-.I nr_futex
-is the number of futexes in that array.
-.I flags
-must be set to the io_uring specific futex flags.
-
-Unlike
-.BR io_uring_prep_futex_wait (3),
-the desired bitset mask and values are passed in
-.IR futexv .
-
-.I flags
-are currently unused and hence
-.B 0
-must be passed.
-
-This function prepares an async
-.BR futex (2)
-waitv request. See that man page for details.
-
-Available since kernel 6.7.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-Unlike the sync futex syscalls that wait on a futex, io_uring does not support
-passing in a timeout for the request. Instead, applications are encouraged
-to use a linked timeout to abort the futex request at a given time, if desired.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_prep_futex_wait (3),
-.BR io_uring_prep_futex_wake (3),
-.BR io_uring_prep_link_timeout (3),
-.BR futex (2)
-.BR futex2 (2)
diff --git a/man/io_uring_prep_futex_waitv.3.md b/man/io_uring_prep_futex_waitv.3.md
new file mode 100644
index 00000000..ea885c0d
--- /dev/null
+++ b/man/io_uring_prep_futex_waitv.3.md
@@ -0,0 +1,54 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: Sep 29, 2023
+footer: liburing-2.5
+header: liburing Manual
+section: 3
+title: io_uring_prep_futex_waitv
+---
+
+# NAME
+
+io_uring_prep_futex_waitv - prepare a futex waitv request
+
+# SYNOPSIS
+
+ #include <linux/futex.h>
+ #include <unistd.h>
+ #include <liburing.h>
+
+ void io_uring_prep_futex_waitv(struct io_uring_sqe * sqe ,
+ const struct futex_waitv * futexv ,
+ uint32_t nr_futex ,
+ unsigned int flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_futex_waitv**(3) function prepares a futex wait request for multiple futexes at the same time. The submission queue entry *sqe* is setup for waiting on all futexes given by *futexv* and *nr_futex* is the number of futexes in that array. *flags* must be set to the io_uring specific futex flags.
+
+Unlike **io_uring_prep_futex_wait**(3), the desired bitset mask and values are passed in *futexv*.
+
+*flags* are currently unused and hence **0** must be passed.
+
+This function prepares an async **futex**(2) waitv request. See that man page for details.
+
+Available since kernel 6.7.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+Unlike the sync futex syscalls that wait on a futex, io_uring does not support passing in a timeout for the request. Instead, applications are encouraged to use a linked timeout to abort the futex request at a given time, if desired.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_prep_futex_wait**(3), **io_uring_prep_futex_wake**(3), **io_uring_prep_link_timeout**(3), **futex**(2) **futex2**(2)
diff --git a/man/io_uring_prep_futex_wake.3 b/man/io_uring_prep_futex_wake.3
deleted file mode 100644
index 3bf646a5..00000000
--- a/man/io_uring_prep_futex_wake.3
+++ /dev/null
@@ -1,86 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_futex_wake 3 "Sep 29, 2023" "liburing-2.5" "liburing Manual"
-.SH NAME
-io_uring_prep_futex_wake \- prepare a futex wake request
-.SH SYNOPSIS
-.nf
-.B #include <linux/futex.h>
-.B #include <unistd.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_futex_wake(struct io_uring_sqe *" sqe ","
-.BI " const uint32_t *" futex ","
-.BI " uint64_t " val ","
-.BI " uint64_t " mask ","
-.BI " uint32_t " futex_flags ","
-.BI " unsigned int " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_futex_wake (3)
-function prepares a futex wake request. The submission queue entry
-.I sqe
-is setup for waking any waiters on the futex indicated by
-.I futex
-and at most
-.I val
-futexes.
-.I futex_flags
-indicates the
-.BR futex2 (2)
-modifier flags, and io_uring futex flags of
-.I flags .
-
-If a given bitset for who to wake is desired, then that must be set in
-.I mask .
-Use
-.B FUTEX_BITSET_MATCH_ANY
-to match any waiter on the given futex.
-
-.I flags
-are currently unused and hence
-.B 0
-must be passed.
-
-This function prepares an async
-.BR futex (2)
-wake request. See that man page for details. Note that the io_uring futex
-wake request is similar to the
-.B FUTEX_WAKE_BITSET
-operation, as
-.B FUTEX_WAKE
-is a strict subset of that.
-
-Available since kernel 6.7.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. On success, the value will be
-the index into
-.I futexv
-which received a wakeup. See the related man page for details on possible
-values for errors. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_prep_futex_wait (3),
-.BR io_uring_prep_futex_waitv (3),
-.BR futex (2)
-.BR futex2 (2)
diff --git a/man/io_uring_prep_futex_wake.3.md b/man/io_uring_prep_futex_wake.3.md
new file mode 100644
index 00000000..52ffa320
--- /dev/null
+++ b/man/io_uring_prep_futex_wake.3.md
@@ -0,0 +1,52 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: Sep 29, 2023
+footer: liburing-2.5
+header: liburing Manual
+section: 3
+title: io_uring_prep_futex_wake
+---
+
+# NAME
+
+io_uring_prep_futex_wake - prepare a futex wake request
+
+# SYNOPSIS
+
+ #include <linux/futex.h>
+ #include <unistd.h>
+ #include <liburing.h>
+
+ void io_uring_prep_futex_wake(struct io_uring_sqe * sqe ,
+ const uint32_t * futex ,
+ uint64_t val ,
+ uint64_t mask ,
+ uint32_t futex_flags ,
+ unsigned int flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_futex_wake**(3) function prepares a futex wake request. The submission queue entry *sqe* is setup for waking any waiters on the futex indicated by *futex* and at most *val* futexes. *futex_flags* indicates the **futex2**(2) modifier flags, and io_uring futex flags of *flags .*
+
+If a given bitset for who to wake is desired, then that must be set in *mask .* Use **FUTEX_BITSET_MATCH_ANY** to match any waiter on the given futex.
+
+*flags* are currently unused and hence **0** must be passed.
+
+This function prepares an async **futex**(2) wake request. See that man page for details. Note that the io_uring futex wake request is similar to the **FUTEX_WAKE_BITSET** operation, as **FUTEX_WAKE** is a strict subset of that.
+
+Available since kernel 6.7.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. On success, the value will be the index into *futexv* which received a wakeup. See the related man page for details on possible values for errors. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_prep_futex_wait**(3), **io_uring_prep_futex_waitv**(3), **futex**(2) **futex2**(2)
diff --git a/man/io_uring_prep_getxattr.3 b/man/io_uring_prep_getxattr.3
deleted file mode 100644
index 61274056..00000000
--- a/man/io_uring_prep_getxattr.3
+++ /dev/null
@@ -1,61 +0,0 @@
-.\" Copyright (C) 2023 Rutvik Patel <heyrutvik@gmail.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_getxattr 3 "January 23, 2023" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_prep_getxattr, io_uring_prep_fgetxattr \- prepare a request to get an
-extended attribute value
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_getxattr(struct io_uring_sqe *" sqe ","
-.BI " const char *" name ","
-.BI " char *" value ","
-.BI " const char *" path ","
-.BI " unsigned int " len ");"
-.PP
-.BI "void io_uring_prep_fgetxattr(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " const char *" name ","
-.BI " char *" value ","
-.BI " unsigned int " len ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_getxattr (3)
-function prepares a request to get an extended attribute value. The submission
-queue entry
-.I sqe
-is setup to get the
-.I value
-of the extended attribute identified by
-.I name
-and associated with the given
-.I path
-in the filesystem.
-The
-.I len
-argument specifies the size (in bytes) of
-.IR value .
-
-.BR io_uring_prep_fgetxattr (3)
-is identical to
-.BR io_uring_prep_getxattr (3),
-only the open file referred to by
-.I fd
-is interrogated in place of
-.IR path .
-
-This function prepares an async
-.BR getxattr (2)
-request. See that man page for details.
-
-.SH RETURN VALUE
-None
-
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR getxattr (2)
diff --git a/man/io_uring_prep_getxattr.3.md b/man/io_uring_prep_getxattr.3.md
new file mode 100644
index 00000000..ffc32c9f
--- /dev/null
+++ b/man/io_uring_prep_getxattr.3.md
@@ -0,0 +1,47 @@
+.\" Copyright (C) 2023 Rutvik Patel <heyrutvik@gmail.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 23, 2023
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_prep_getxattr
+---
+
+# NAME
+
+io_uring_prep_getxattr, io_uring_prep_fgetxattr - prepare a request to get an extended attribute value
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_getxattr(struct io_uring_sqe * sqe ,
+ const char * name ,
+ char * value ,
+ const char * path ,
+ unsigned int len );
+
+ void io_uring_prep_fgetxattr(struct io_uring_sqe * sqe ,
+ int fd ,
+ const char * name ,
+ char * value ,
+ unsigned int len );
+
+# DESCRIPTION
+
+The **io_uring_prep_getxattr**(3) function prepares a request to get an extended attribute value. The submission queue entry *sqe* is setup to get the *value* of the extended attribute identified by *name* and associated with the given *path* in the filesystem. The *len* argument specifies the size (in bytes) of *value*.
+
+**io_uring_prep_fgetxattr**(3) is identical to **io_uring_prep_getxattr**(3), only the open file referred to by *fd* is interrogated in place of *path*.
+
+This function prepares an async **getxattr**(2) request. See that man page for details.
+
+# RETURN VALUE
+
+None
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **getxattr**(2)
diff --git a/man/io_uring_prep_link.3 b/man/io_uring_prep_link.3
deleted file mode 120000
index 6d3059de..00000000
--- a/man/io_uring_prep_link.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_linkat.3
\ No newline at end of file
diff --git a/man/io_uring_prep_link_timeout.3 b/man/io_uring_prep_link_timeout.3
deleted file mode 100644
index 3afbd728..00000000
--- a/man/io_uring_prep_link_timeout.3
+++ /dev/null
@@ -1,98 +0,0 @@
-.\" Copyright (C) 2023 Rutvik Patel <heyrutvik@gmail.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_link_timeout 3 "January 23, 2023" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_prep_link_timeout \- a timeout request for linked sqes
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_link_timeout(struct io_uring_sqe *" sqe ","
-.BI " const struct __kernel_timespec *" ts ","
-.BI " unsigned " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_link_timeout (3)
-function prepares a timeout request for linked sqes. The submission queue entry
-.I sqe
-is setup for with timeout specified by
-.IR ts .
-The flags argument holds modifier
-.I flags
-for the timeout behaviour of the request.
-
-The
-.I ts
-argument must be filled in with the appropriate information for the timeout. It
-looks as follows:
-.PP
-.in +4n
-.EX
-struct __kernel_timespec {
- __kernel_time64_t tv_sec;
- long long tv_nsec;
-};
-.EE
-.in
-.PP
-
-The
-.I flags
-argument may contain:
-.TP
-.B IORING_TIMEOUT_ABS
-The value specified in
-.I ts
-is an absolute value rather than a relative one.
-.TP
-.B IORING_TIMEOUT_BOOTTIME
-The boottime clock source should be used.
-.TP
-.B IORING_TIMEOUT_REALTIME
-The realtime clock source should be used.
-.TP
-.B IORING_TIMEOUT_ETIME_SUCCESS
-Consider an expired timeout a success in terms of the posted completion.
-.PP
-
-It is invalid to create a chain (linked sqes) consisting only of a link timeout
-request. If all the requests in the chain are completed before timeout, then the
-link timeout request gets canceled. Upon timeout, all the uncompleted requests
-in the chain get canceled.
-
-.SH RETURN VALUE
-None
-
-.SH ERRORS
-.PP
-These are the errors that are reported in the CQE
-.I res
-field. On success,
-.B 0
-is returned.
-.TP
-.B -ETIME
-The specified timeout occurred and triggered the completion event.
-.TP
-.B -EINVAL
-One of the fields set in the SQE was invalid. For example, two clock sources
-where given, or the specified timeout seconds or nanoseconds where < 0.
-.TP
-.B -EFAULT
-io_uring was unable to access the data specified by ts.
-.TP
-.B -ECANCELED
-The timeout was canceled because all submitted requests were completed successfully
-or one of the requests resulted in failure.
-.TP
-.B -ENOENT
-The request to which the linked timeout was linked already completed and could
-not be found when the timer expired.
-
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_prep_timeout (3)
diff --git a/man/io_uring_prep_link_timeout.3.md b/man/io_uring_prep_link_timeout.3.md
new file mode 100644
index 00000000..96fb33df
--- /dev/null
+++ b/man/io_uring_prep_link_timeout.3.md
@@ -0,0 +1,86 @@
+.\" Copyright (C) 2023 Rutvik Patel <heyrutvik@gmail.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 23, 2023
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_prep_link_timeout
+---
+
+# NAME
+
+io_uring_prep_link_timeout - a timeout request for linked sqes
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_link_timeout(struct io_uring_sqe * sqe ,
+ const struct __kernel_timespec * ts ,
+ unsigned flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_link_timeout**(3) function prepares a timeout request for linked sqes. The submission queue entry *sqe* is setup for with timeout specified by *ts*. The flags argument holds modifier *flags* for the timeout behaviour of the request.
+
+The *ts* argument must be filled in with the appropriate information for the timeout. It looks as follows:
+
+ struct __kernel_timespec {
+ __kernel_time64_t tv_sec;
+ long long tv_nsec;
+ };
+
+The *flags* argument may contain:
+
+**IORING_TIMEOUT_ABS**
+
+: The value specified in *ts* is an absolute value rather than a relative one.
+
+**IORING_TIMEOUT_BOOTTIME**
+
+: The boottime clock source should be used.
+
+**IORING_TIMEOUT_REALTIME**
+
+: The realtime clock source should be used.
+
+**IORING_TIMEOUT_ETIME_SUCCESS**
+
+: Consider an expired timeout a success in terms of the posted completion.
+
+It is invalid to create a chain (linked sqes) consisting only of a link timeout request. If all the requests in the chain are completed before timeout, then the link timeout request gets canceled. Upon timeout, all the uncompleted requests in the chain get canceled.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+These are the errors that are reported in the CQE *res* field. On success, **0** is returned.
+
+**-ETIME**
+
+: The specified timeout occurred and triggered the completion event.
+
+**-EINVAL**
+
+: One of the fields set in the SQE was invalid. For example, two clock sources where given, or the specified timeout seconds or nanoseconds where \< 0.
+
+**-EFAULT**
+
+: io_uring was unable to access the data specified by ts.
+
+**-ECANCELED**
+
+: The timeout was canceled because all submitted requests were completed successfully or one of the requests resulted in failure.
+
+**-ENOENT**
+
+: The request to which the linked timeout was linked already completed and could not be found when the timer expired.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_prep_timeout**(3)
diff --git a/man/io_uring_prep_linkat.3 b/man/io_uring_prep_linkat.3
deleted file mode 100644
index 0949e3b4..00000000
--- a/man/io_uring_prep_linkat.3
+++ /dev/null
@@ -1,91 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_linkat 3 "March 13, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_linkat \- prepare a linkat request
-.SH SYNOPSIS
-.nf
-.B #include <fcntl.h>
-.B #include <unistd.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_linkat(struct io_uring_sqe *" sqe ","
-.BI " int " olddirfd ","
-.BI " const char *" oldpath ","
-.BI " int " newdirfd ","
-.BI " const char *" newpath ","
-.BI " int " flags ");"
-.PP
-.BI "void io_uring_prep_link(struct io_uring_sqe *" sqe ","
-.BI " const char *" oldpath ","
-.BI " const char *" newpath ","
-.BI " int " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_linkat (3)
-function prepares a linkat request. The submission queue entry
-.I sqe
-is setup to use the old directory file descriptor pointed to by
-.I olddirfd
-and old path pointed to by
-.I oldpath
-with the new directory file descriptor pointed to by
-.I newdirfd
-and the new path pointed to by
-.I newpath
-and using the specified flags in
-.IR flags .
-
-The
-.BR io_uring_prep_link (3)
-function prepares a link request. The submission queue entry
-.I sqe
-is setup to use the old path pointed to by
-.I oldpath
-and the new path pointed to by
-.IR newpath ,
-both relative to the current working directory and using the specified flags in
-.IR flags .
-
-These functions prepare an async
-.BR linkat (2)
-or
-.BR link (2)
-request. See those man pages for details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-As with any request that passes in data in a struct, that data must remain
-valid until the request has been successfully submitted. It need not remain
-valid until completion. Once a request has been submitted, the in-kernel
-state is stable. Very early kernels (5.4 and earlier) required state to be
-stable until the completion occurred. Applications can test for this
-behavior by inspecting the
-.B IORING_FEAT_SUBMIT_STABLE
-flag passed back from
-.BR io_uring_queue_init_params (3).
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR linkat (2),
-.BR link (2)
diff --git a/man/io_uring_prep_linkat.3.md b/man/io_uring_prep_linkat.3.md
new file mode 100644
index 00000000..cdf387f3
--- /dev/null
+++ b/man/io_uring_prep_linkat.3.md
@@ -0,0 +1,57 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 13, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_linkat
+---
+
+# NAME
+
+io_uring_prep_linkat - prepare a linkat request
+
+# SYNOPSIS
+
+ #include <fcntl.h>
+ #include <unistd.h>
+ #include <liburing.h>
+
+ void io_uring_prep_linkat(struct io_uring_sqe * sqe ,
+ int olddirfd ,
+ const char * oldpath ,
+ int newdirfd ,
+ const char * newpath ,
+ int flags );
+
+ void io_uring_prep_link(struct io_uring_sqe * sqe ,
+ const char * oldpath ,
+ const char * newpath ,
+ int flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_linkat**(3) function prepares a linkat request. The submission queue entry *sqe* is setup to use the old directory file descriptor pointed to by *olddirfd* and old path pointed to by *oldpath* with the new directory file descriptor pointed to by *newdirfd* and the new path pointed to by *newpath* and using the specified flags in *flags*.
+
+The **io_uring_prep_link**(3) function prepares a link request. The submission queue entry *sqe* is setup to use the old path pointed to by *oldpath* and the new path pointed to by *newpath*, both relative to the current working directory and using the specified flags in *flags*.
+
+These functions prepare an async **linkat**(2) or **link**(2) request. See those man pages for details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+As with any request that passes in data in a struct, that data must remain valid until the request has been successfully submitted. It need not remain valid until completion. Once a request has been submitted, the in-kernel state is stable. Very early kernels (5.4 and earlier) required state to be stable until the completion occurred. Applications can test for this behavior by inspecting the **IORING_FEAT_SUBMIT_STABLE** flag passed back from **io_uring_queue_init_params**(3).
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **linkat**(2), **link**(2)
diff --git a/man/io_uring_prep_listen.3 b/man/io_uring_prep_listen.3
deleted file mode 100644
index b765298a..00000000
--- a/man/io_uring_prep_listen.3
+++ /dev/null
@@ -1,52 +0,0 @@
-.\" Copyright (C) 2024 SUSE LLC.
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_listen 3 "Jun 3, 2024" "liburing-2.7" "liburing Manual"
-.SH NAME
-io_uring_prep_listen \- prepare a listen request
-.SH SYNOPSIS
-.nf
-.B #include <sys/socket.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_listen(struct io_uring_sqe *" sqe ","
-.BI " int " sockfd ","
-.BI " int" backlog ");"
-.fi
-.SH DESCRIPTION
-The
-.BR io_uring_prep_listen (3)
-function prepares a listen request. The submission queue entry
-.I sqe
-is setup to place the socket file descriptor pointed by
-.IR sockfd
-into a state to accept incoming connections. The parameter
-.IR backlog ,
-defines the maximum length of the queue of pending connections.
-
-This function prepares an async
-.BR listen (2)
-request. See that man page for details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR listen (2)
diff --git a/man/io_uring_prep_listen.3.md b/man/io_uring_prep_listen.3.md
new file mode 100644
index 00000000..48763c5e
--- /dev/null
+++ b/man/io_uring_prep_listen.3.md
@@ -0,0 +1,42 @@
+.\" Copyright (C) 2024 SUSE LLC.
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: Jun 3, 2024
+footer: liburing-2.7
+header: liburing Manual
+section: 3
+title: io_uring_prep_listen
+---
+
+# NAME
+
+io_uring_prep_listen - prepare a listen request
+
+# SYNOPSIS
+
+ #include <sys/socket.h>
+ #include <liburing.h>
+
+ void io_uring_prep_listen(struct io_uring_sqe * sqe ,
+ int sockfd ,
+ int backlog );
+
+# DESCRIPTION
+
+The **io_uring_prep_listen**(3) function prepares a listen request. The submission queue entry *sqe* is setup to place the socket file descriptor pointed by *sockfd* into a state to accept incoming connections. The parameter *backlog*, defines the maximum length of the queue of pending connections.
+
+This function prepares an async **listen**(2) request. See that man page for details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **listen**(2)
diff --git a/man/io_uring_prep_madvise.3 b/man/io_uring_prep_madvise.3
deleted file mode 100644
index f29fa920..00000000
--- a/man/io_uring_prep_madvise.3
+++ /dev/null
@@ -1,72 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_madvise 3 "March 13, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_madvise \- prepare a madvise request
-.SH SYNOPSIS
-.nf
-.B #include <sys/mman.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_madvise(struct io_uring_sqe *" sqe ","
-.BI " void *" addr ","
-.BI " __u32 " len ","
-.BI " int " advice ");"
-.BI "
-.BI "void io_uring_prep_madvise64(struct io_uring_sqe *" sqe ","
-.BI " void *" addr ","
-.BI " off_t " len ","
-.BI " int " advice ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_madvise (3)
-function prepares an madvise request. The submission queue entry
-.I sqe
-is setup to start an madvise operation at the virtual address of
-.I addr
-and of
-.I len
-length in bytes, giving it the advise located in
-.IR advice .
-
-The
-.BR io_uring_prep_madvise64 (3)
-function works like
-.BR io_uring_prep_madvise (3)
-except that it takes a 64-bit length rather than just a 32-bit one. Older
-kernels may not support the 64-bit length variant. If this variant is attempted
-used on a kernel that doesn't support 64-bit lengths, then the request will get
-errored with
-.B -EINVAL
-in the results field of the CQE.
-
-This function prepares an async
-.BR madvise (2)
-request. See that man page for details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_register (2),
-.BR madvise (2)
diff --git a/man/io_uring_prep_madvise.3.md b/man/io_uring_prep_madvise.3.md
new file mode 100644
index 00000000..4e707ca7
--- /dev/null
+++ b/man/io_uring_prep_madvise.3.md
@@ -0,0 +1,50 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 13, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_madvise
+---
+
+# NAME
+
+io_uring_prep_madvise - prepare a madvise request
+
+# SYNOPSIS
+
+ #include <sys/mman.h>
+ #include <liburing.h>
+
+ void io_uring_prep_madvise(struct io_uring_sqe * sqe ,
+ void * addr ,
+ __u32 len ,
+ int advice );
+
+ void io_uring_prep_madvise64(struct io_uring_sqe * sqe ,
+ void * addr ,
+ off_t len ,
+ int advice );
+
+# DESCRIPTION
+
+The **io_uring_prep_madvise**(3) function prepares an madvise request. The submission queue entry *sqe* is setup to start an madvise operation at the virtual address of *addr* and of *len* length in bytes, giving it the advise located in *advice*.
+
+The **io_uring_prep_madvise64**(3) function works like **io_uring_prep_madvise**(3) except that it takes a 64-bit length rather than just a 32-bit one. Older kernels may not support the 64-bit length variant. If this variant is attempted used on a kernel that doesn\'t support 64-bit lengths, then the request will get errored with **-EINVAL** in the results field of the CQE.
+
+This function prepares an async **madvise**(2) request. See that man page for details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_register**(2), **madvise**(2)
diff --git a/man/io_uring_prep_madvise64.3 b/man/io_uring_prep_madvise64.3
deleted file mode 120000
index 1a368eea..00000000
--- a/man/io_uring_prep_madvise64.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_madvise.3
\ No newline at end of file
diff --git a/man/io_uring_prep_mkdir.3 b/man/io_uring_prep_mkdir.3
deleted file mode 120000
index b3412d1d..00000000
--- a/man/io_uring_prep_mkdir.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_mkdirat.3
\ No newline at end of file
diff --git a/man/io_uring_prep_mkdirat.3 b/man/io_uring_prep_mkdirat.3
deleted file mode 100644
index a98b4e35..00000000
--- a/man/io_uring_prep_mkdirat.3
+++ /dev/null
@@ -1,83 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_mkdirat 3 "March 13, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_mkdirat \- prepare an mkdirat request
-.SH SYNOPSIS
-.nf
-.B #include <fcntl.h>
-.B #include <sys/stat.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_mkdirat(struct io_uring_sqe *" sqe ","
-.BI " int " dirfd ","
-.BI " const char *" path ","
-.BI " mode_t " mode ");"
-.PP
-.BI "void io_uring_prep_mkdir(struct io_uring_sqe *" sqe ","
-.BI " const char *" path ","
-.BI " mode_t " mode ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_mkdirat (3)
-function prepares a mkdirat request. The submission queue entry
-.I sqe
-is setup to use the directory file descriptor pointed to by
-.I dirfd
-to start a mkdirat operation on the path identified by
-.I path
-with the mode given in
-.IR mode .
-
-The
-.BR io_uring_prep_mkdir (3)
-function prepares a mkdir request. The submission queue entry
-.I sqe
-is setup to use the current working directory to start a mkdir
-operation on the path identified by
-.I path
-with the mode given in
-.IR mode .
-
-These functions prepare an async
-.BR mkdir (2)
-or
-.BR mkdirat (2)
-request. See those man pages for details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-As with any request that passes in data in a struct, that data must remain
-valid until the request has been successfully submitted. It need not remain
-valid until completion. Once a request has been submitted, the in-kernel
-state is stable. Very early kernels (5.4 and earlier) required state to be
-stable until the completion occurred. Applications can test for this
-behavior by inspecting the
-.B IORING_FEAT_SUBMIT_STABLE
-flag passed back from
-.BR io_uring_queue_init_params (3).
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR mkdirat (2),
-.BR mkdir (2)
diff --git a/man/io_uring_prep_mkdirat.3.md b/man/io_uring_prep_mkdirat.3.md
new file mode 100644
index 00000000..eceb710e
--- /dev/null
+++ b/man/io_uring_prep_mkdirat.3.md
@@ -0,0 +1,54 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 13, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_mkdirat
+---
+
+# NAME
+
+io_uring_prep_mkdirat - prepare an mkdirat request
+
+# SYNOPSIS
+
+ #include <fcntl.h>
+ #include <sys/stat.h>
+ #include <liburing.h>
+
+ void io_uring_prep_mkdirat(struct io_uring_sqe * sqe ,
+ int dirfd ,
+ const char * path ,
+ mode_t mode );
+
+ void io_uring_prep_mkdir(struct io_uring_sqe * sqe ,
+ const char * path ,
+ mode_t mode );
+
+# DESCRIPTION
+
+The **io_uring_prep_mkdirat**(3) function prepares a mkdirat request. The submission queue entry *sqe* is setup to use the directory file descriptor pointed to by *dirfd* to start a mkdirat operation on the path identified by *path* with the mode given in *mode*.
+
+The **io_uring_prep_mkdir**(3) function prepares a mkdir request. The submission queue entry *sqe* is setup to use the current working directory to start a mkdir operation on the path identified by *path* with the mode given in *mode*.
+
+These functions prepare an async **mkdir**(2) or **mkdirat**(2) request. See those man pages for details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+As with any request that passes in data in a struct, that data must remain valid until the request has been successfully submitted. It need not remain valid until completion. Once a request has been submitted, the in-kernel state is stable. Very early kernels (5.4 and earlier) required state to be stable until the completion occurred. Applications can test for this behavior by inspecting the **IORING_FEAT_SUBMIT_STABLE** flag passed back from **io_uring_queue_init_params**(3).
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **mkdirat**(2), **mkdir**(2)
diff --git a/man/io_uring_prep_msg_ring.3 b/man/io_uring_prep_msg_ring.3
deleted file mode 100644
index 70caebe7..00000000
--- a/man/io_uring_prep_msg_ring.3
+++ /dev/null
@@ -1,92 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_msg_ring 3 "March 10, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_msg_ring \- send a message to another ring
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_msg_ring(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " unsigned int " len ","
-.BI " __u64 " data ","
-.BI " unsigned int " flags ");"
-.PP
-.BI "void io_uring_prep_msg_ring_cqe_flags(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " unsigned int " len ","
-.BI " __u64 " data ","
-.BI " unsigned int " flags ","
-.BI " unsigned int " cqe_flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-.BR io_uring_prep_msg_ring (3)
-prepares to send a CQE to an io_uring file descriptor. The submission queue
-entry
-.I sqe
-is setup to use the file descriptor
-.IR fd ,
-which must identify a io_uring context, to post a CQE on that ring where the
-target CQE
-.B res
-field will contain the content of
-.I len
-and the
-.B user_data
-of
-.I data
-with the request modifier flags set by
-.IR flags .
-Currently there are no valid flag modifiers, this field must contain
-.BR 0 .
-
-The targeted ring may be any ring that the user has access to, even the ring
-itself. This request can be used for simple message passing to another ring,
-allowing 32+64 bits of data to be transferred through the
-.I len
-and
-.I data
-fields. The use case may be anything from simply waking up someone waiting
-on the targeted ring, or it can be used to pass messages between the two
-rings.
-
-.BR io_uring_prep_msg_ring_cqe_flags (3)
-is similar to
-.BR io_uring_prep_msg_ring (3) .
-But has an addition
-.I cqe_flags
-parameter, which is used to set
-.I flags
-field on CQE side. That way, you can set the CQE flags field
-.I cqe->flags
-when sending a message. Be aware that io_uring could potentially set additional
-bits into this field.
-
-.SH RETURN VALUE
-None
-
-.SH ERRORS
-These are the errors that are reported in the CQE
-.I res
-field.
-.TP
-.B -ENOMEM
-The kernel was unable to allocate memory for the request.
-.TP
-.B -EINVAL
-One of the fields set in the SQE was invalid.
-.TP
-.B -EBADFD
-The descriptor passed in
-.I fd
-does not refer to an io_uring file descriptor, or the ring is in a disabled
-state.
-.TP
-.B -EOVERFLOW
-The kernel was unable to fill a CQE on the target ring. This can happen if
-the target CQ ring is in an overflow state and the kernel wasn't able to
-allocate memory for a new CQE entry.
diff --git a/man/io_uring_prep_msg_ring.3.md b/man/io_uring_prep_msg_ring.3.md
new file mode 100644
index 00000000..006ee88e
--- /dev/null
+++ b/man/io_uring_prep_msg_ring.3.md
@@ -0,0 +1,64 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 10, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_msg_ring
+---
+
+# NAME
+
+io_uring_prep_msg_ring - send a message to another ring
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_msg_ring(struct io_uring_sqe * sqe ,
+ int fd ,
+ unsigned int len ,
+ __u64 data ,
+ unsigned int flags );
+
+ void io_uring_prep_msg_ring_cqe_flags(struct io_uring_sqe * sqe ,
+ int fd ,
+ unsigned int len ,
+ __u64 data ,
+ unsigned int flags ,
+ unsigned int cqe_flags );
+
+# DESCRIPTION
+
+**io_uring_prep_msg_ring**(3) prepares to send a CQE to an io_uring file descriptor. The submission queue entry *sqe* is setup to use the file descriptor *fd*, which must identify a io_uring context, to post a CQE on that ring where the target CQE **res** field will contain the content of *len* and the **user_data** of *data* with the request modifier flags set by *flags*. Currently there are no valid flag modifiers, this field must contain **0**.
+
+The targeted ring may be any ring that the user has access to, even the ring itself. This request can be used for simple message passing to another ring, allowing 32+64 bits of data to be transferred through the *len* and *data* fields. The use case may be anything from simply waking up someone waiting on the targeted ring, or it can be used to pass messages between the two rings.
+
+**io_uring_prep_msg_ring_cqe_flags**(3) is similar to **io_uring_prep_msg_ring**(3)**.** But has an addition *cqe_flags* parameter, which is used to set *flags* field on CQE side. That way, you can set the CQE flags field *cqe-\>flags* when sending a message. Be aware that io_uring could potentially set additional bits into this field.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+These are the errors that are reported in the CQE *res* field.
+
+**-ENOMEM**
+
+: The kernel was unable to allocate memory for the request.
+
+**-EINVAL**
+
+: One of the fields set in the SQE was invalid.
+
+**-EBADFD**
+
+: The descriptor passed in *fd* does not refer to an io_uring file descriptor, or the ring is in a disabled state.
+
+**-EOVERFLOW**
+
+: The kernel was unable to fill a CQE on the target ring. This can happen if the target CQ ring is in an overflow state and the kernel wasn\'t able to allocate memory for a new CQE entry.
diff --git a/man/io_uring_prep_msg_ring_cqe_flags.3 b/man/io_uring_prep_msg_ring_cqe_flags.3
deleted file mode 120000
index c96663b8..00000000
--- a/man/io_uring_prep_msg_ring_cqe_flags.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_msg_ring.3
\ No newline at end of file
diff --git a/man/io_uring_prep_msg_ring_fd.3 b/man/io_uring_prep_msg_ring_fd.3
deleted file mode 100644
index 39cd34aa..00000000
--- a/man/io_uring_prep_msg_ring_fd.3
+++ /dev/null
@@ -1,83 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_msg_ring_fd 3 "Mar 16, 2023" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_prep_msg_ring_fd \- send a direct descriptor to another ring
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_msg_ring_fd(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " int " source_fd ","
-.BI " int " target_fd ","
-.BI " __u64 " data ","
-.BI " unsigned int " flags ");"
-.PP
-.BI "void io_uring_prep_msg_ring_fd_alloc(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " int " source_fd ","
-.BI " __u64 " data ","
-.BI " unsigned int " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-.BR io_uring_prep_msg_ring_fd (3)
-prepares an SQE to send a direct file descriptor to another ring. The submission
-queue entry
-.I sqe
-is setup to use the file descriptor
-.IR fd ,
-which must identify a target io_uring context, to send the locally registered
-file descriptor with value
-.I source_fd
-to the destination ring into index
-.I target_fd
-and passing
-.I data
-as the user data in the target CQE with the request modifier flags set by
-.IR flags .
-Currently there are no valid flag modifiers, this field must contain
-.BR 0 .
-
-.BR io_uring_prep_msg_ring_fd_alloc (3)
-is similar to
-.BR io_uring_prep_msg_ring_fd (3) ,
-but doesn't specify a target index for the direct descriptor. Instead, this
-index is allocated in the target ring and returned in the CQE
-.IR res
-field.
-
-.SH RETURN VALUE
-None
-
-.SH ERRORS
-These are the errors that are reported in the CQE
-.I res
-field.
-.TP
-.B -ENOMEM
-The kernel was unable to allocate memory for the request.
-.TP
-.B -EINVAL
-One of the fields set in the SQE was invalid.
-.TP
-.B -EINVAL
-Target ring is identical to the source ring.
-.TP
-.B -EBADFD
-The descriptor passed in
-.I fd
-does not refer to an io_uring file descriptor, or the ring is in a disabled
-state.
-.TP
-.B -EOVERFLOW
-The kernel was unable to fill a CQE on the target ring. This can happen if
-the target CQ ring is in an overflow state and the kernel wasn't able to
-allocate memory for a new CQE entry.
-.TP
-.B -ENFILE
-The direct descriptor table in the target ring was full, no new descriptors
-could be successfully allocated.
diff --git a/man/io_uring_prep_msg_ring_fd.3.md b/man/io_uring_prep_msg_ring_fd.3.md
new file mode 100644
index 00000000..9fdbff2d
--- /dev/null
+++ b/man/io_uring_prep_msg_ring_fd.3.md
@@ -0,0 +1,70 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: Mar 16, 2023
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_prep_msg_ring_fd
+---
+
+# NAME
+
+io_uring_prep_msg_ring_fd - send a direct descriptor to another ring
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_msg_ring_fd(struct io_uring_sqe * sqe ,
+ int fd ,
+ int source_fd ,
+ int target_fd ,
+ __u64 data ,
+ unsigned int flags );
+
+ void io_uring_prep_msg_ring_fd_alloc(struct io_uring_sqe * sqe ,
+ int fd ,
+ int source_fd ,
+ __u64 data ,
+ unsigned int flags );
+
+# DESCRIPTION
+
+**io_uring_prep_msg_ring_fd**(3) prepares an SQE to send a direct file descriptor to another ring. The submission queue entry *sqe* is setup to use the file descriptor *fd*, which must identify a target io_uring context, to send the locally registered file descriptor with value *source_fd* to the destination ring into index *target_fd* and passing *data* as the user data in the target CQE with the request modifier flags set by *flags*. Currently there are no valid flag modifiers, this field must contain **0**.
+
+**io_uring_prep_msg_ring_fd_alloc**(3) is similar to **io_uring_prep_msg_ring_fd**(3)**,** but doesn\'t specify a target index for the direct descriptor. Instead, this index is allocated in the target ring and returned in the CQE *res* field.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+These are the errors that are reported in the CQE *res* field.
+
+**-ENOMEM**
+
+: The kernel was unable to allocate memory for the request.
+
+**-EINVAL**
+
+: One of the fields set in the SQE was invalid.
+
+**-EINVAL**
+
+: Target ring is identical to the source ring.
+
+**-EBADFD**
+
+: The descriptor passed in *fd* does not refer to an io_uring file descriptor, or the ring is in a disabled state.
+
+**-EOVERFLOW**
+
+: The kernel was unable to fill a CQE on the target ring. This can happen if the target CQ ring is in an overflow state and the kernel wasn\'t able to allocate memory for a new CQE entry.
+
+**-ENFILE**
+
+: The direct descriptor table in the target ring was full, no new descriptors could be successfully allocated.
diff --git a/man/io_uring_prep_msg_ring_fd_alloc.3 b/man/io_uring_prep_msg_ring_fd_alloc.3
deleted file mode 120000
index a3a7731f..00000000
--- a/man/io_uring_prep_msg_ring_fd_alloc.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_msg_ring_fd.3
\ No newline at end of file
diff --git a/man/io_uring_prep_multishot_accept.3 b/man/io_uring_prep_multishot_accept.3
deleted file mode 120000
index 0404bf59..00000000
--- a/man/io_uring_prep_multishot_accept.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_accept.3
\ No newline at end of file
diff --git a/man/io_uring_prep_multishot_accept_direct.3 b/man/io_uring_prep_multishot_accept_direct.3
deleted file mode 120000
index 0404bf59..00000000
--- a/man/io_uring_prep_multishot_accept_direct.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_accept.3
\ No newline at end of file
diff --git a/man/io_uring_prep_nop.3 b/man/io_uring_prep_nop.3
deleted file mode 100644
index 81853d77..00000000
--- a/man/io_uring_prep_nop.3
+++ /dev/null
@@ -1,28 +0,0 @@
-.\" Copyright (C) 2022 Samuel Williams
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_nop 3 "October 20, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_nop \- prepare a nop request
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_nop(struct io_uring_sqe *" sqe ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_nop (3)
-function prepares nop (no operation) request. The submission queue entry
-.I sqe
-does not require any additional setup.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-None
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
diff --git a/man/io_uring_prep_nop.3.md b/man/io_uring_prep_nop.3.md
new file mode 100644
index 00000000..6ece9f24
--- /dev/null
+++ b/man/io_uring_prep_nop.3.md
@@ -0,0 +1,37 @@
+.\" Copyright (C) 2022 Samuel Williams
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: October 20, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_nop
+---
+
+# NAME
+
+io_uring_prep_nop - prepare a nop request
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_nop(struct io_uring_sqe * sqe );
+
+# DESCRIPTION
+
+The **io_uring_prep_nop**(3) function prepares nop (no operation) request. The submission queue entry *sqe* does not require any additional setup.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+None
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3),
diff --git a/man/io_uring_prep_nop128.3 b/man/io_uring_prep_nop128.3
deleted file mode 100644
index 1ff82e9a..00000000
--- a/man/io_uring_prep_nop128.3
+++ /dev/null
@@ -1,30 +0,0 @@
-.\" Copyright (C) 2022 Samuel Williams
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_nop128 3 "October 22, 2025" "liburing-2.13" "liburing Manual"
-.SH NAME
-io_uring_prep_nop128 \- prepare a nop request
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_nop128(struct io_uring_sqe *" sqe ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_nop128 (3)
-function prepares nop (no operation) request for a 128-byte entry. The
-submission queue entry
-.I sqe
-does not require any additional setup.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-None
-.SH SEE ALSO
-.BR io_uring_prep_nop (3),
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
diff --git a/man/io_uring_prep_nop128.3.md b/man/io_uring_prep_nop128.3.md
new file mode 100644
index 00000000..b47cf31e
--- /dev/null
+++ b/man/io_uring_prep_nop128.3.md
@@ -0,0 +1,37 @@
+.\" Copyright (C) 2022 Samuel Williams
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: October 22, 2025
+footer: liburing-2.13
+header: liburing Manual
+section: 3
+title: io_uring_prep_nop128
+---
+
+# NAME
+
+io_uring_prep_nop128 - prepare a nop request
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_nop128(struct io_uring_sqe * sqe );
+
+# DESCRIPTION
+
+The **io_uring_prep_nop128**(3) function prepares nop (no operation) request for a 128-byte entry. The submission queue entry *sqe* does not require any additional setup.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+None
+
+# SEE ALSO
+
+**io_uring_prep_nop**(3), **io_uring_get_sqe**(3), **io_uring_submit**(3),
diff --git a/man/io_uring_prep_open.3 b/man/io_uring_prep_open.3
deleted file mode 120000
index 67f501e5..00000000
--- a/man/io_uring_prep_open.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_openat.3
\ No newline at end of file
diff --git a/man/io_uring_prep_open_direct.3 b/man/io_uring_prep_open_direct.3
deleted file mode 120000
index 67f501e5..00000000
--- a/man/io_uring_prep_open_direct.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_openat.3
\ No newline at end of file
diff --git a/man/io_uring_prep_openat.3 b/man/io_uring_prep_openat.3
deleted file mode 100644
index 071a9f83..00000000
--- a/man/io_uring_prep_openat.3
+++ /dev/null
@@ -1,138 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_openat 3 "March 13, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_openat \- prepare an openat request
-.SH SYNOPSIS
-.nf
-.B #include <sys/types.h>
-.B #include <sys/stat.h>
-.B #include <fcntl.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_open(struct io_uring_sqe *" sqe ","
-.BI " const char *" path ","
-.BI " int " flags ","
-.BI " mode_t " mode ");"
-.PP
-.BI "void io_uring_prep_open_direct(struct io_uring_sqe *" sqe ","
-.BI " const char *" path ","
-.BI " int " flags ","
-.BI " mode_t " mode ","
-.BI " unsigned " file_index ");"
-.PP
-.BI "void io_uring_prep_openat(struct io_uring_sqe *" sqe ","
-.BI " int " dfd ","
-.BI " const char *" path ","
-.BI " int " flags ","
-.BI " mode_t " mode ");"
-.PP
-.BI "void io_uring_prep_openat_direct(struct io_uring_sqe *" sqe ","
-.BI " int " dfd ","
-.BI " const char *" path ","
-.BI " int " flags ","
-.BI " mode_t " mode ","
-.BI " unsigned " file_index ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_openat (3)
-function prepares an openat request. The submission queue entry
-.I sqe
-is setup to use the directory file descriptor
-.I dfd
-to start opening a file described by
-.I path
-and using the open flags in
-.I flags
-and using the file mode bits specified in
-.IR mode .
-Similarly
-.BR io_uring_prep_open (3)
-prepares an open request.
-
-If the direct variant is used, the application must first have registered
-a file table using
-.BR io_uring_register_files (3)
-of the appropriate size. Once registered, a direct accept request may use any
-entry in that table and is specified in
-.I file_index
-, as long as it is within the size of the registered table.
-If a specified entry already contains a file, the file will first be removed
-from the table and closed. It's consistent with the behavior of updating an
-existing file with
-.BR io_uring_register_files_update (3).
-
-If
-.B IORING_FILE_INDEX_ALLOC
-is used as the
-.I file_index
-for a direct open, then io_uring will allocate a free direct descriptor in
-the existing table. The allocated descriptor is returned in the CQE
-.I res
-field just like it would be for a non-direct open request. If no more entries
-are available in the direct descriptor table,
-.B -ENFILE
-is returned instead.
-
-Direct descriptors are io_uring private file descriptors. They
-avoid some of the overhead associated with thread shared file tables, and
-can be used in any subsequent io_uring request that takes a file descriptor. To do so,
-.B IOSQE_FIXED_FILE
-must be set in the SQE
-.I flags
-member, and the SQE
-.I fd
-field should use the direct descriptor value rather than the regular file
-descriptor. Direct descriptors are managed like registered files.
-
-The directory file descriptor
-.I dfd
-is always a regular file descriptor.
-
-Note that old kernels don't check the SQE
-.I file_index
-field, which is not a problem for liburing helpers, but users of the raw
-io_uring interface need to zero SQEs to avoid unexpected behavior.
-
-These functions prepare an async
-.BR openat (2)
-or
-.BR open (2)
-request. See that man page for details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-As with any request that passes in data in a struct, that data must remain
-valid until the request has been successfully submitted. It need not remain
-valid until completion. Once a request has been submitted, the in-kernel
-state is stable. Very early kernels (5.4 and earlier) required state to be
-stable until the completion occurred. Applications can test for this
-behavior by inspecting the
-.B IORING_FEAT_SUBMIT_STABLE
-flag passed back from
-.BR io_uring_queue_init_params (3).
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_register (2),
-.BR openat (2)
diff --git a/man/io_uring_prep_openat.3.md b/man/io_uring_prep_openat.3.md
new file mode 100644
index 00000000..9e9b91b8
--- /dev/null
+++ b/man/io_uring_prep_openat.3.md
@@ -0,0 +1,78 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 13, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_openat
+---
+
+# NAME
+
+io_uring_prep_openat - prepare an openat request
+
+# SYNOPSIS
+
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <fcntl.h>
+ #include <liburing.h>
+
+ void io_uring_prep_open(struct io_uring_sqe * sqe ,
+ const char * path ,
+ int flags ,
+ mode_t mode );
+
+ void io_uring_prep_open_direct(struct io_uring_sqe * sqe ,
+ const char * path ,
+ int flags ,
+ mode_t mode ,
+ unsigned file_index );
+
+ void io_uring_prep_openat(struct io_uring_sqe * sqe ,
+ int dfd ,
+ const char * path ,
+ int flags ,
+ mode_t mode );
+
+ void io_uring_prep_openat_direct(struct io_uring_sqe * sqe ,
+ int dfd ,
+ const char * path ,
+ int flags ,
+ mode_t mode ,
+ unsigned file_index );
+
+# DESCRIPTION
+
+The **io_uring_prep_openat**(3) function prepares an openat request. The submission queue entry *sqe* is setup to use the directory file descriptor *dfd* to start opening a file described by *path* and using the open flags in *flags* and using the file mode bits specified in *mode*. Similarly **io_uring_prep_open**(3) prepares an open request.
+
+If the direct variant is used, the application must first have registered a file table using **io_uring_register_files**(3) of the appropriate size. Once registered, a direct accept request may use any entry in that table and is specified in *file_index* , as long as it is within the size of the registered table. If a specified entry already contains a file, the file will first be removed from the table and closed. It\'s consistent with the behavior of updating an existing file with **io_uring_register_files_update**(3).
+
+If **IORING_FILE_INDEX_ALLOC** is used as the *file_index* for a direct open, then io_uring will allocate a free direct descriptor in the existing table. The allocated descriptor is returned in the CQE *res* field just like it would be for a non-direct open request. If no more entries are available in the direct descriptor table, **-ENFILE** is returned instead.
+
+Direct descriptors are io_uring private file descriptors. They avoid some of the overhead associated with thread shared file tables, and can be used in any subsequent io_uring request that takes a file descriptor. To do so, **IOSQE_FIXED_FILE** must be set in the SQE *flags* member, and the SQE *fd* field should use the direct descriptor value rather than the regular file descriptor. Direct descriptors are managed like registered files.
+
+The directory file descriptor *dfd* is always a regular file descriptor.
+
+Note that old kernels don\'t check the SQE *file_index* field, which is not a problem for liburing helpers, but users of the raw io_uring interface need to zero SQEs to avoid unexpected behavior.
+
+These functions prepare an async **openat**(2) or **open**(2) request. See that man page for details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+As with any request that passes in data in a struct, that data must remain valid until the request has been successfully submitted. It need not remain valid until completion. Once a request has been submitted, the in-kernel state is stable. Very early kernels (5.4 and earlier) required state to be stable until the completion occurred. Applications can test for this behavior by inspecting the **IORING_FEAT_SUBMIT_STABLE** flag passed back from **io_uring_queue_init_params**(3).
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_register**(2), **openat**(2)
diff --git a/man/io_uring_prep_openat2.3 b/man/io_uring_prep_openat2.3
deleted file mode 100644
index fe361699..00000000
--- a/man/io_uring_prep_openat2.3
+++ /dev/null
@@ -1,119 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_openat2 3 "March 13, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_openat2 \- prepare an openat2 request
-.SH SYNOPSIS
-.nf
-.B #include <sys/types.h>
-.B #include <sys/stat.h>
-.B #include <fcntl.h>
-.B #include <linux/openat2.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_openat2(struct io_uring_sqe *" sqe ","
-.BI " int " dfd ","
-.BI " const char *" path ","
-.BI " const struct open_how *" how ");"
-.PP
-.BI "void io_uring_prep_openat2_direct(struct io_uring_sqe *" sqe ","
-.BI " int " dfd ","
-.BI " const char *" path ","
-.BI " const struct open_how *" how ","
-.BI " unsigned " file_index ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_openat2 (3)
-function prepares an openat2 request. The submission queue entry
-.I sqe
-is setup to use the directory file descriptor
-.I dfd
-to start opening a file described by
-.I path
-and using the instructions on how to open the file given in
-.IR how .
-
-If the direct variant is used, the application must first have registered
-a file table using
-.BR io_uring_register_files (3)
-of the appropriate size. Once registered, a direct request may use any
-entry in that table and is specified in
-.I file_index
-, as long as it is within the size of the registered table.
-If the specified entry already contains a file, the file will first be removed
-from the table and closed. It's consistent with the behavior of updating an
-existing file with
-.BR io_uring_register_files_update (3).
-
-If
-.B IORING_FILE_INDEX_ALLOC
-is used as the
-.I file_index
-for a direct open, then io_uring will allocate a free direct descriptor in
-the existing table. The allocated descriptor is returned in the CQE
-.I res
-field just like it would be for a non-direct open request. If no more entries
-are available in the direct descriptor table,
-.B -ENFILE
-is returned instead.
-
-Direct descriptors are io_uring private file descriptors. They
-avoid some of the overhead associated with thread shared file tables, and
-can be used in any subsequent io_uring request that takes a file descriptor. To do so,
-.B IOSQE_FIXED_FILE
-must be set in the SQE
-.I flags
-member, and the SQE
-.I fd
-field should use the direct descriptor value rather than the regular file
-descriptor. Direct descriptors are managed like registered files.
-
-The directory file descriptor
-.I dfd
-is always a regular file descriptor.
-
-Note that old kernels don't check the SQE
-.I file_index
-field, which is not a problem for liburing helpers, but users of the raw
-io_uring interface need to zero SQEs to avoid unexpected behavior.
-
-These functions prepare an async
-.BR openat2 (2)
-request. See that man page for details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-As with any request that passes in data in a struct, that data must remain
-valid until the request has been successfully submitted. It need not remain
-valid until completion. Once a request has been submitted, the in-kernel
-state is stable. Very early kernels (5.4 and earlier) required state to be
-stable until the completion occurred. Applications can test for this
-behavior by inspecting the
-.B IORING_FEAT_SUBMIT_STABLE
-flag passed back from
-.BR io_uring_queue_init_params (3).
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_register (2),
-.BR openat2 (2)
diff --git a/man/io_uring_prep_openat2.3.md b/man/io_uring_prep_openat2.3.md
new file mode 100644
index 00000000..17c99a03
--- /dev/null
+++ b/man/io_uring_prep_openat2.3.md
@@ -0,0 +1,66 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 13, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_openat2
+---
+
+# NAME
+
+io_uring_prep_openat2 - prepare an openat2 request
+
+# SYNOPSIS
+
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <fcntl.h>
+ #include <linux/openat2.h>
+ #include <liburing.h>
+
+ void io_uring_prep_openat2(struct io_uring_sqe * sqe ,
+ int dfd ,
+ const char * path ,
+ const struct open_how * how );
+
+ void io_uring_prep_openat2_direct(struct io_uring_sqe * sqe ,
+ int dfd ,
+ const char * path ,
+ const struct open_how * how ,
+ unsigned file_index );
+
+# DESCRIPTION
+
+The **io_uring_prep_openat2**(3) function prepares an openat2 request. The submission queue entry *sqe* is setup to use the directory file descriptor *dfd* to start opening a file described by *path* and using the instructions on how to open the file given in *how*.
+
+If the direct variant is used, the application must first have registered a file table using **io_uring_register_files**(3) of the appropriate size. Once registered, a direct request may use any entry in that table and is specified in *file_index* , as long as it is within the size of the registered table. If the specified entry already contains a file, the file will first be removed from the table and closed. It\'s consistent with the behavior of updating an existing file with **io_uring_register_files_update**(3).
+
+If **IORING_FILE_INDEX_ALLOC** is used as the *file_index* for a direct open, then io_uring will allocate a free direct descriptor in the existing table. The allocated descriptor is returned in the CQE *res* field just like it would be for a non-direct open request. If no more entries are available in the direct descriptor table, **-ENFILE** is returned instead.
+
+Direct descriptors are io_uring private file descriptors. They avoid some of the overhead associated with thread shared file tables, and can be used in any subsequent io_uring request that takes a file descriptor. To do so, **IOSQE_FIXED_FILE** must be set in the SQE *flags* member, and the SQE *fd* field should use the direct descriptor value rather than the regular file descriptor. Direct descriptors are managed like registered files.
+
+The directory file descriptor *dfd* is always a regular file descriptor.
+
+Note that old kernels don\'t check the SQE *file_index* field, which is not a problem for liburing helpers, but users of the raw io_uring interface need to zero SQEs to avoid unexpected behavior.
+
+These functions prepare an async **openat2**(2) request. See that man page for details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+As with any request that passes in data in a struct, that data must remain valid until the request has been successfully submitted. It need not remain valid until completion. Once a request has been submitted, the in-kernel state is stable. Very early kernels (5.4 and earlier) required state to be stable until the completion occurred. Applications can test for this behavior by inspecting the **IORING_FEAT_SUBMIT_STABLE** flag passed back from **io_uring_queue_init_params**(3).
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_register**(2), **openat2**(2)
diff --git a/man/io_uring_prep_openat2_direct.3 b/man/io_uring_prep_openat2_direct.3
deleted file mode 120000
index 2c0e6c9c..00000000
--- a/man/io_uring_prep_openat2_direct.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_openat2.3
\ No newline at end of file
diff --git a/man/io_uring_prep_openat_direct.3 b/man/io_uring_prep_openat_direct.3
deleted file mode 120000
index 67f501e5..00000000
--- a/man/io_uring_prep_openat_direct.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_openat.3
\ No newline at end of file
diff --git a/man/io_uring_prep_pipe.3 b/man/io_uring_prep_pipe.3
deleted file mode 100644
index 948f345c..00000000
--- a/man/io_uring_prep_pipe.3
+++ /dev/null
@@ -1,91 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_pipe 3 "April 8, 2025" "liburing-2.10" "liburing Manual"
-.SH NAME
-io_uring_prep_pipe \- prepare a pipe creation request
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_pipe(struct io_uring_sqe *" sqe ","
-.BI " int *" fds ","
-.BI " int " pipe_flags ");"
-.BI "
-.BI "void io_uring_prep_pipe_direct(struct io_uring_sqe *" sqe ","
-.BI " int *" fds ","
-.BI " int " pipe_flags ","
-.BI " unsigned int " file_index ");"
-.PP
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_pipe (3)
-function prepares a pipe creation request. The submission queue entry
-.I sqe
-is setup to create a pipe with the created descriptors being copied to the
-array indicated by
-.I fds
-and using
-.I pipe_flags
-as the pipe creation flags. See
-.BR pipe2(2)
-for details on the flags accepted.
-
-The
-.BR io_uring_prep_pipe_direct (3)
-function works in the same way, however it uses fixed/registered file
-descriptors rather than normal file descriptors. This helper takes an
-additional
-.I file_index
-argument, which can set to either an explicit direct descriptor offset to create
-the two pipe file descriptors at, or it can be set to
-.B IORING_FILE_INDEX_ALLOC
-to let io_uring pick any available descriptors for the read and write side
-of the pipe. If a specific index is given, the read side of the pipe will
-be created at that offset, if free, and the write side will be created at
-the next (+1) index. Both of these must be currently unused, or the
-operation will fail. Also see
-.BR io_uring_prep_accept_direct (3)
-or
-.BR io_uring_prep_socket_direct (3)
-for details on the
-.I file_index
-parameter.
-
-For both the direct and normal file descriptor pipe request, the resulting
-input/read side of the pipe will be stored in
-.I fds[0]
-and the output/write side of the pipe will be stored in
-.I fds[1]
-upon successful completion of this request.
-
-This function prepares an async
-.BR pipe2 (2)
-request. See that man page for details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR pipe2 (2),
-.BR io_uring_prep_accept_direct (3),
-.BR io_uring_prep_socket_direct (3)
diff --git a/man/io_uring_prep_pipe.3.md b/man/io_uring_prep_pipe.3.md
new file mode 100644
index 00000000..587d3169
--- /dev/null
+++ b/man/io_uring_prep_pipe.3.md
@@ -0,0 +1,50 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: April 8, 2025
+footer: liburing-2.10
+header: liburing Manual
+section: 3
+title: io_uring_prep_pipe
+---
+
+# NAME
+
+io_uring_prep_pipe - prepare a pipe creation request
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_pipe(struct io_uring_sqe * sqe ,
+ int * fds ,
+ int pipe_flags );
+
+ void io_uring_prep_pipe_direct(struct io_uring_sqe * sqe ,
+ int * fds ,
+ int pipe_flags ,
+ unsigned int file_index );
+
+# DESCRIPTION
+
+The **io_uring_prep_pipe**(3) function prepares a pipe creation request. The submission queue entry *sqe* is setup to create a pipe with the created descriptors being copied to the array indicated by *fds* and using *pipe_flags* as the pipe creation flags. See **pipe2(2)** for details on the flags accepted.
+
+The **io_uring_prep_pipe_direct**(3) function works in the same way, however it uses fixed/registered file descriptors rather than normal file descriptors. This helper takes an additional *file_index* argument, which can set to either an explicit direct descriptor offset to create the two pipe file descriptors at, or it can be set to **IORING_FILE_INDEX_ALLOC** to let io_uring pick any available descriptors for the read and write side of the pipe. If a specific index is given, the read side of the pipe will be created at that offset, if free, and the write side will be created at the next (+1) index. Both of these must be currently unused, or the operation will fail. Also see **io_uring_prep_accept_direct**(3) or **io_uring_prep_socket_direct**(3) for details on the *file_index* parameter.
+
+For both the direct and normal file descriptor pipe request, the resulting input/read side of the pipe will be stored in *fds\[0\]* and the output/write side of the pipe will be stored in *fds\[1\]* upon successful completion of this request.
+
+This function prepares an async **pipe2**(2) request. See that man page for details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **pipe2**(2), **io_uring_prep_accept_direct**(3), **io_uring_prep_socket_direct**(3)
diff --git a/man/io_uring_prep_pipe_direct.3 b/man/io_uring_prep_pipe_direct.3
deleted file mode 120000
index 025c635b..00000000
--- a/man/io_uring_prep_pipe_direct.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_pipe.3
\ No newline at end of file
diff --git a/man/io_uring_prep_poll_add.3 b/man/io_uring_prep_poll_add.3
deleted file mode 100644
index 82539b9a..00000000
--- a/man/io_uring_prep_poll_add.3
+++ /dev/null
@@ -1,72 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_poll_add 3 "March 12, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_poll_add \- prepare a poll request
-.SH SYNOPSIS
-.nf
-.B #include <poll.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_poll_add(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " unsigned " poll_mask ");"
-.PP
-.BI "void io_uring_prep_poll_multishot(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " unsigned " poll_mask ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_poll_add (3)
-function prepares a poll request. The submission queue entry
-.I sqe
-is setup to use the file descriptor
-.I fd
-that should get polled, with the events desired specified in the
-.I poll_mask
-argument.
-
-The default behavior is a single-shot poll request. When the specified event
-has triggered, a completion CQE is posted and no more events will be generated
-by the poll request.
-.BR io_uring_prep_poll_multishot (3)
-behaves identically in terms of events, but it persists across notifications
-and will repeatedly post notifications for the same registration. A CQE
-posted from a multishot poll request will have
-.B IORING_CQE_F_MORE
-set in the CQE
-.I flags
-member, indicating that the application should expect more completions from
-this request. If the multishot poll request gets terminated or experiences
-an error, this flag will not be set in the CQE. If this happens, the application
-should not expect further CQEs from the original request and must reissue a
-new one if it still wishes to get notifications on this file descriptor.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation, which is a bitmask of the
-events notified. See the
-.BR poll (2)
-man page for details. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR poll (2),
-.BR epoll_ctl (3)
diff --git a/man/io_uring_prep_poll_add.3.md b/man/io_uring_prep_poll_add.3.md
new file mode 100644
index 00000000..3f2cad08
--- /dev/null
+++ b/man/io_uring_prep_poll_add.3.md
@@ -0,0 +1,46 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 12, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_poll_add
+---
+
+# NAME
+
+io_uring_prep_poll_add - prepare a poll request
+
+# SYNOPSIS
+
+ #include <poll.h>
+ #include <liburing.h>
+
+ void io_uring_prep_poll_add(struct io_uring_sqe * sqe ,
+ int fd ,
+ unsigned poll_mask );
+
+ void io_uring_prep_poll_multishot(struct io_uring_sqe * sqe ,
+ int fd ,
+ unsigned poll_mask );
+
+# DESCRIPTION
+
+The **io_uring_prep_poll_add**(3) function prepares a poll request. The submission queue entry *sqe* is setup to use the file descriptor *fd* that should get polled, with the events desired specified in the *poll_mask* argument.
+
+The default behavior is a single-shot poll request. When the specified event has triggered, a completion CQE is posted and no more events will be generated by the poll request. **io_uring_prep_poll_multishot**(3) behaves identically in terms of events, but it persists across notifications and will repeatedly post notifications for the same registration. A CQE posted from a multishot poll request will have **IORING_CQE_F_MORE** set in the CQE *flags* member, indicating that the application should expect more completions from this request. If the multishot poll request gets terminated or experiences an error, this flag will not be set in the CQE. If this happens, the application should not expect further CQEs from the original request and must reissue a new one if it still wishes to get notifications on this file descriptor.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation, which is a bitmask of the events notified. See the **poll**(2) man page for details. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **poll**(2), **epoll_ctl**(3)
diff --git a/man/io_uring_prep_poll_multishot.3 b/man/io_uring_prep_poll_multishot.3
deleted file mode 120000
index ac8fb8fd..00000000
--- a/man/io_uring_prep_poll_multishot.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_poll_add.3
\ No newline at end of file
diff --git a/man/io_uring_prep_poll_remove.3 b/man/io_uring_prep_poll_remove.3
deleted file mode 100644
index b6f4b263..00000000
--- a/man/io_uring_prep_poll_remove.3
+++ /dev/null
@@ -1,55 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_poll_remove 3 "March 12, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_poll_remove \- prepare a poll deletion request
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_poll_remove(struct io_uring_sqe *" sqe ","
-.BI " __u64 " user_data ");"
-.BI "
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_poll_remove (3)
-function prepares a poll removal request. The submission queue entry
-.I sqe
-is setup to remove a poll request identified by
-.I user_data
-
-Works like
-.BR io_uring_prep_cancel (3)
-except only looks for poll requests. Apart from that, behavior is identical.
-See that man page for specific details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-These are the errors that are reported in the CQE
-.I res
-field. On success,
-.B 0
-is returned.
-.TP
-.B -ENOENT
-The request identified by
-.I user_data
-could not be located. This could be because it completed before the cancelation
-request was issued, or if an invalid identifier is used.
-.TP
-.B -EINVAL
-One of the fields set in the SQE was invalid.
-.TP
-.B -EALREADY
-The execution state of the request has progressed far enough that cancelation
-is no longer possible. This should normally mean that it will complete shortly,
-either successfully, or interrupted due to the cancelation.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_prep_cancel (3)
diff --git a/man/io_uring_prep_poll_remove.3.md b/man/io_uring_prep_poll_remove.3.md
new file mode 100644
index 00000000..6a58e943
--- /dev/null
+++ b/man/io_uring_prep_poll_remove.3.md
@@ -0,0 +1,53 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 12, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_poll_remove
+---
+
+# NAME
+
+io_uring_prep_poll_remove - prepare a poll deletion request
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_poll_remove(struct io_uring_sqe * sqe ,
+ __u64 user_data );
+
+
+# DESCRIPTION
+
+The **io_uring_prep_poll_remove**(3) function prepares a poll removal request. The submission queue entry *sqe* is setup to remove a poll request identified by *user_data*
+
+Works like **io_uring_prep_cancel**(3) except only looks for poll requests. Apart from that, behavior is identical. See that man page for specific details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+These are the errors that are reported in the CQE *res* field. On success, **0** is returned.
+
+**-ENOENT**
+
+: The request identified by *user_data* could not be located. This could be because it completed before the cancelation request was issued, or if an invalid identifier is used.
+
+**-EINVAL**
+
+: One of the fields set in the SQE was invalid.
+
+**-EALREADY**
+
+: The execution state of the request has progressed far enough that cancelation is no longer possible. This should normally mean that it will complete shortly, either successfully, or interrupted due to the cancelation.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_prep_cancel**(3)
diff --git a/man/io_uring_prep_poll_update.3 b/man/io_uring_prep_poll_update.3
deleted file mode 100644
index 41cf7766..00000000
--- a/man/io_uring_prep_poll_update.3
+++ /dev/null
@@ -1,101 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_poll_update 3 "March 12, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_poll_update \- update an existing poll request
-.SH SYNOPSIS
-.nf
-.B #include <poll.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_poll_update(struct io_uring_sqe *" sqe ","
-.BI " __u64 " old_user_data ","
-.BI " __u64 " new_user_data ","
-.BI " unsigned " poll_mask ","
-.BI " unsigned " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_poll_update (3)
-function prepares a poll update request. The submission queue entry
-.I sqe
-is setup to update a poll request identified by
-.IR old_user_data ,
-replacing it with the
-.I new_user_data
-information. The
-.I poll_mask
-arguments contains the new mask to use for the poll request, and
-.I flags
-argument contains modifier flags telling io_uring what fields to update.
-
-The
-.I flags
-modifier flags is a bitmask and may contain and OR'ed mask of:
-.TP
-.B IORING_POLL_UPDATE_EVENTS
-If set, the poll update request will replace the existing events being waited
-for with the ones specified in the
-.I poll_mask
-argument to the function. Note that only the lower 16 bits of events can
-be updated. This includes things like
-.B EPOLLIN
-and
-.B EPOLLOUT .
-Higher order masks/settings are included as internal state, and cannot be
-modified. That includes settings like
-.B EPOLLONESHOT ,
-.B EPOLLEXCLUSIVE ,
-and
-.B EPOLLET .
-If an application wishes to modify these, it must cancel/remove the existing
-poll request and arm a new one.
-.TP
-.B IORING_POLL_UPDATE_USER_DATA
-If set, the poll update request will update the existing user_data of the
-request with the value passed in as the
-.I new_user_data
-argument.
-.TP
-.B IORING_POLL_ADD_MULTI
-If set, this will change the poll request from a singleshot to a multishot
-request. This must be used along with
-.B IORING_POLL_UPDATE_EVENTS
-as the event field must be updated to enable multishot.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-These are the errors that are reported in the CQE
-.I res
-field. On success,
-.B 0
-is returned.
-.TP
-.B -ENOENT
-The request identified by
-.I user_data
-could not be located. This could be because it completed before the cancelation
-request was issued, or if an invalid identifier is used.
-.TP
-.B -EINVAL
-One of the fields set in the SQE was invalid.
-.TP
-.B -EALREADY
-The execution state of the request has progressed far enough that cancelation
-is no longer possible. This should normally mean that it will complete shortly,
-either successfully, or interrupted due to the cancelation.
-.TP
-.B -ECANCELED
-.B IORING_POLL_UPDATE_EVENTS
-was set and an error occurred re-arming the poll request with the new mask.
-The original poll request is terminated if this happens, and that termination
-CQE will contain the reason for the error re-arming.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_prep_poll_add (3),
-.BR io_uring_prep_poll_multishot (3)
diff --git a/man/io_uring_prep_poll_update.3.md b/man/io_uring_prep_poll_update.3.md
new file mode 100644
index 00000000..55aa18f2
--- /dev/null
+++ b/man/io_uring_prep_poll_update.3.md
@@ -0,0 +1,72 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 12, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_poll_update
+---
+
+# NAME
+
+io_uring_prep_poll_update - update an existing poll request
+
+# SYNOPSIS
+
+ #include <poll.h>
+ #include <liburing.h>
+
+ void io_uring_prep_poll_update(struct io_uring_sqe * sqe ,
+ __u64 old_user_data ,
+ __u64 new_user_data ,
+ unsigned poll_mask ,
+ unsigned flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_poll_update**(3) function prepares a poll update request. The submission queue entry *sqe* is setup to update a poll request identified by *old_user_data*, replacing it with the *new_user_data* information. The *poll_mask* arguments contains the new mask to use for the poll request, and *flags* argument contains modifier flags telling io_uring what fields to update.
+
+The *flags* modifier flags is a bitmask and may contain and OR\'ed mask of:
+
+**IORING_POLL_UPDATE_EVENTS**
+
+: If set, the poll update request will replace the existing events being waited for with the ones specified in the *poll_mask* argument to the function. Note that only the lower 16 bits of events can be updated. This includes things like **EPOLLIN** and **EPOLLOUT .** Higher order masks/settings are included as internal state, and cannot be modified. That includes settings like **EPOLLONESHOT ,** **EPOLLEXCLUSIVE ,** and **EPOLLET .** If an application wishes to modify these, it must cancel/remove the existing poll request and arm a new one.
+
+**IORING_POLL_UPDATE_USER_DATA**
+
+: If set, the poll update request will update the existing user_data of the request with the value passed in as the *new_user_data* argument.
+
+**IORING_POLL_ADD_MULTI**
+
+: If set, this will change the poll request from a singleshot to a multishot request. This must be used along with **IORING_POLL_UPDATE_EVENTS** as the event field must be updated to enable multishot.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+These are the errors that are reported in the CQE *res* field. On success, **0** is returned.
+
+**-ENOENT**
+
+: The request identified by *user_data* could not be located. This could be because it completed before the cancelation request was issued, or if an invalid identifier is used.
+
+**-EINVAL**
+
+: One of the fields set in the SQE was invalid.
+
+**-EALREADY**
+
+: The execution state of the request has progressed far enough that cancelation is no longer possible. This should normally mean that it will complete shortly, either successfully, or interrupted due to the cancelation.
+
+**-ECANCELED**
+
+: **IORING_POLL_UPDATE_EVENTS** was set and an error occurred re-arming the poll request with the new mask. The original poll request is terminated if this happens, and that termination CQE will contain the reason for the error re-arming.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_prep_poll_add**(3), **io_uring_prep_poll_multishot**(3)
diff --git a/man/io_uring_prep_provide_buffers.3 b/man/io_uring_prep_provide_buffers.3
deleted file mode 100644
index ae51c1dc..00000000
--- a/man/io_uring_prep_provide_buffers.3
+++ /dev/null
@@ -1,140 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_provide_buffers 3 "March 13, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_provide_buffers \- prepare a provide buffers request
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_provide_buffers(struct io_uring_sqe *" sqe ","
-.BI " void *" addr ","
-.BI " int " len ","
-.BI " int " nr ","
-.BI " int " bgid ","
-.BI " int " bid ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_provide_buffers (3)
-function prepares a request for providing the kernel with buffers. The
-submission queue entry
-.I sqe
-is setup to consume
-.I nr
-number of
-.I len
-sized buffers starting at
-.I addr
-and identified by the buffer group ID of
-.I bgid
-and numbered sequentially starting at
-.IR bid .
-
-This function sets up a request to provide buffers to the io_uring context
-that can be used by read or receive operations. This is done by filling in
-the SQE
-.I buf_group
-field and setting
-.B IOSQE_BUFFER_SELECT
-in the SQE
-.I flags
-member. If buffer selection is used for a request, no buffer should be provided
-in the address field. Instead, the group ID is set to match one that was
-previously provided to the kernel. The kernel will then select a buffer from
-this group for the IO operation. On successful completion of the IO request,
-the CQE
-.I flags
-field will have
-.B IORING_CQE_F_BUFFER
-set and the selected buffer ID will be indicated by the upper 16-bits of the
-.I flags
-field.
-
-Different buffer group IDs can be used by the application to have different
-sizes or types of buffers available. Once a buffer has been consumed for an
-operation, it is no longer known to io_uring. It must be re-provided if so
-desired or freed by the application if no longer needed.
-
-The buffer IDs are internally tracked from
-.I bid
-and sequentially ascending from that value. If
-.B 16
-buffers are provided and start with an initial
-.I bid
-of 0, then the buffer IDs will range from
-.BR 0..15 .
-The application must be aware of this to make sense of the buffer ID passed
-back in the CQE.
-
-Buffer IDs always range from
-.B 0
-to
-.B 65535 ,
-as there are only 16-bits available in the CQE to pass them back. This range
-is independent of how the buffer group initially got created. Attempting to
-add buffer IDs larger than that, or buffer IDs that will wrap when cast to
-a 16-bit value, will cause the request to fail with
-.B -E2BIG
-or
-.B -EINVAL .
-
-Not all requests support buffer selection, as it only really makes sense for
-requests that receive data from the kernel rather than write or provide data.
-Currently, this mode of operation is supported for any file read or socket
-receive request. Attempting to use
-.B IOSQE_BUFFER_SELECT
-with a command that doesn't support it will result in a CQE
-.I res
-error of
-.BR -EINVAL .
-Buffer selection will work with operations that take a
-.B struct iovec
-as its data destination, but only if 1 iovec is provided.
-.
-.SH RETURN VALUE
-None
-.SH ERRORS
-These are the errors that are reported in the CQE
-.I res
-field. On success,
-.I res
-will contain
-.B 0
-or the number of successfully provided buffers.
-.TP
-.B -ENOMEM
-The kernel was unable to allocate memory for the request.
-.TP
-.B -EINVAL
-One of the fields set in the SQE was invalid.
-.TP
-.B -E2BIG
-The number of buffers provided was too big, or the
-.I bid
-was too big. A max value of
-.B USHRT_MAX
-buffers can be specified.
-.TP
-.B -EFAULT
-Some of the user memory given was invalid for the application.
-.TP
-.B -EOVERFLOW
-The product of
-.I len
-and
-.I nr
-exceed the valid amount or overflowed, or the sum of
-.I addr
-and the length of buffers overflowed.
-.TP
-.B -EBUSY
-Attempt to update a slot that is already used.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_register (2),
-.BR io_uring_prep_remove_buffers (3)
diff --git a/man/io_uring_prep_provide_buffers.3.md b/man/io_uring_prep_provide_buffers.3.md
new file mode 100644
index 00000000..f294b2ed
--- /dev/null
+++ b/man/io_uring_prep_provide_buffers.3.md
@@ -0,0 +1,76 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 13, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_provide_buffers
+---
+
+# NAME
+
+io_uring_prep_provide_buffers - prepare a provide buffers request
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_provide_buffers(struct io_uring_sqe * sqe ,
+ void * addr ,
+ int len ,
+ int nr ,
+ int bgid ,
+ int bid );
+
+# DESCRIPTION
+
+The **io_uring_prep_provide_buffers**(3) function prepares a request for providing the kernel with buffers. The submission queue entry *sqe* is setup to consume *nr* number of *len* sized buffers starting at *addr* and identified by the buffer group ID of *bgid* and numbered sequentially starting at *bid*.
+
+This function sets up a request to provide buffers to the io_uring context that can be used by read or receive operations. This is done by filling in the SQE *buf_group* field and setting **IOSQE_BUFFER_SELECT** in the SQE *flags* member. If buffer selection is used for a request, no buffer should be provided in the address field. Instead, the group ID is set to match one that was previously provided to the kernel. The kernel will then select a buffer from this group for the IO operation. On successful completion of the IO request, the CQE *flags* field will have **IORING_CQE_F_BUFFER** set and the selected buffer ID will be indicated by the upper 16-bits of the *flags* field.
+
+Different buffer group IDs can be used by the application to have different sizes or types of buffers available. Once a buffer has been consumed for an operation, it is no longer known to io_uring. It must be re-provided if so desired or freed by the application if no longer needed.
+
+The buffer IDs are internally tracked from *bid* and sequentially ascending from that value. If **16** buffers are provided and start with an initial *bid* of 0, then the buffer IDs will range from **0..15**. The application must be aware of this to make sense of the buffer ID passed back in the CQE.
+
+Buffer IDs always range from **0** to **65535 ,** as there are only 16-bits available in the CQE to pass them back. This range is independent of how the buffer group initially got created. Attempting to add buffer IDs larger than that, or buffer IDs that will wrap when cast to a 16-bit value, will cause the request to fail with **-E2BIG** or **-EINVAL .**
+
+Not all requests support buffer selection, as it only really makes sense for requests that receive data from the kernel rather than write or provide data. Currently, this mode of operation is supported for any file read or socket receive request. Attempting to use **IOSQE_BUFFER_SELECT** with a command that doesn\'t support it will result in a CQE *res* error of **-EINVAL**. Buffer selection will work with operations that take a **struct iovec** as its data destination, but only if 1 iovec is provided.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+These are the errors that are reported in the CQE *res* field. On success, *res* will contain **0** or the number of successfully provided buffers.
+
+**-ENOMEM**
+
+: The kernel was unable to allocate memory for the request.
+
+**-EINVAL**
+
+: One of the fields set in the SQE was invalid.
+
+**-E2BIG**
+
+: The number of buffers provided was too big, or the *bid* was too big. A max value of **USHRT_MAX** buffers can be specified.
+
+**-EFAULT**
+
+: Some of the user memory given was invalid for the application.
+
+**-EOVERFLOW**
+
+: The product of *len* and *nr* exceed the valid amount or overflowed, or the sum of *addr* and the length of buffers overflowed.
+
+**-EBUSY**
+
+: Attempt to update a slot that is already used.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_register**(2), **io_uring_prep_remove_buffers**(3)
diff --git a/man/io_uring_prep_read.3 b/man/io_uring_prep_read.3
deleted file mode 100644
index 197e960a..00000000
--- a/man/io_uring_prep_read.3
+++ /dev/null
@@ -1,76 +0,0 @@
-.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_read 3 "November 15, 2021" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_prep_read \- prepare I/O read request
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_read(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " void *" buf ","
-.BI " unsigned " nbytes ","
-.BI " __u64 " offset ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_read (3)
-prepares an IO read request. The submission queue entry
-.I sqe
-is setup to use the file descriptor
-.I fd
-to start reading
-.I nbytes
-into the buffer
-.I buf
-at the specified
-.IR offset .
-
-On files that support seeking, if the offset is set to
-.BR -1 ,
-the read operation commences at the file offset, and the file offset is
-incremented by the number of bytes read. See
-.BR read (2)
-for more details. Note that for an async API, reading and updating the
-current file offset may result in unpredictable behavior, unless access
-to the file is serialized. It is not encouraged to use this feature, if it's
-possible to provide the desired IO offset from the application or library.
-
-On files that are not capable of seeking, the offset must be 0 or -1.
-
-After the read has been prepared it can be submitted with one of the submit
-functions.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-This function accepts an unsigned number of bytes, but io_uring_cqe's result
-code is an __s32 value, so in theory a short read with a large enough nbytes
-value could generate an ambiguous return. But the number of bytes actually
-transferred has the same limit as
-.BR read (2)
-so this cannot happen in practice.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_prep_readv (3),
-.BR io_uring_prep_readv2 (3),
-.BR io_uring_submit (3)
diff --git a/man/io_uring_prep_read.3.md b/man/io_uring_prep_read.3.md
new file mode 100644
index 00000000..ea56ff45
--- /dev/null
+++ b/man/io_uring_prep_read.3.md
@@ -0,0 +1,51 @@
+.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: November 15, 2021
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_prep_read
+---
+
+# NAME
+
+io_uring_prep_read - prepare I/O read request
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_read(struct io_uring_sqe * sqe ,
+ int fd ,
+ void * buf ,
+ unsigned nbytes ,
+ __u64 offset );
+
+# DESCRIPTION
+
+The **io_uring_prep_read**(3) prepares an IO read request. The submission queue entry *sqe* is setup to use the file descriptor *fd* to start reading *nbytes* into the buffer *buf* at the specified *offset*.
+
+On files that support seeking, if the offset is set to **-1**, the read operation commences at the file offset, and the file offset is incremented by the number of bytes read. See **read**(2) for more details. Note that for an async API, reading and updating the current file offset may result in unpredictable behavior, unless access to the file is serialized. It is not encouraged to use this feature, if it\'s possible to provide the desired IO offset from the application or library.
+
+On files that are not capable of seeking, the offset must be 0 or -1.
+
+After the read has been prepared it can be submitted with one of the submit functions.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+This function accepts an unsigned number of bytes, but io_uring_cqe\'s result code is an \_\_s32 value, so in theory a short read with a large enough nbytes value could generate an ambiguous return. But the number of bytes actually transferred has the same limit as **read**(2) so this cannot happen in practice.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_prep_readv**(3), **io_uring_prep_readv2**(3), **io_uring_submit**(3)
diff --git a/man/io_uring_prep_read_fixed.3 b/man/io_uring_prep_read_fixed.3
deleted file mode 100644
index c351d092..00000000
--- a/man/io_uring_prep_read_fixed.3
+++ /dev/null
@@ -1,79 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_read_fixed 3 "February 13, 2022" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_prep_read_fixed \- prepare I/O read request with registered buffer
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_read_fixed(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " void *" buf ","
-.BI " unsigned " nbytes ","
-.BI " __u64 " offset ","
-.BI " int " buf_index ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_read_fixed (3)
-prepares an IO read request with a previously registered IO buffer. The
-submission queue entry
-.I sqe
-is setup to use the file descriptor
-.I fd
-to start reading
-.I nbytes
-into the buffer
-.I buf
-at the specified
-.IR offset ,
-and with the buffer matching the registered index of
-.IR buf_index .
-
-This works just like
-.BR io_uring_prep_read (3)
-except it requires the use of buffers that have been registered with
-.BR io_uring_register_buffers (3).
-The
-.I buf
-and
-.I nbytes
-arguments must fall within a region specified by
-.I buf_index
-in the previously registered buffer. The buffer need not be aligned with
-the start of the registered buffer.
-
-After the read has been prepared it can be submitted with one of the submit
-functions.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-This function accepts an unsigned number of bytes, but io_uring_cqe's result
-code is an __s32 value, so in theory a short read with a large enough nbytes
-value could generate an ambiguous return. But the number of bytes actually
-transferred has the same limit as
-.BR read (2)
-so this cannot happen in practice.
-.SH SEE ALSO
-.BR io_uring_prep_read (3),
-.BR io_uring_register_buffers (3)
diff --git a/man/io_uring_prep_read_fixed.3.md b/man/io_uring_prep_read_fixed.3.md
new file mode 100644
index 00000000..580159eb
--- /dev/null
+++ b/man/io_uring_prep_read_fixed.3.md
@@ -0,0 +1,50 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: February 13, 2022
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_prep_read_fixed
+---
+
+# NAME
+
+io_uring_prep_read_fixed - prepare I/O read request with registered buffer
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_read_fixed(struct io_uring_sqe * sqe ,
+ int fd ,
+ void * buf ,
+ unsigned nbytes ,
+ __u64 offset ,
+ int buf_index );
+
+# DESCRIPTION
+
+The **io_uring_prep_read_fixed**(3) prepares an IO read request with a previously registered IO buffer. The submission queue entry *sqe* is setup to use the file descriptor *fd* to start reading *nbytes* into the buffer *buf* at the specified *offset*, and with the buffer matching the registered index of *buf_index*.
+
+This works just like **io_uring_prep_read**(3) except it requires the use of buffers that have been registered with **io_uring_register_buffers**(3). The *buf* and *nbytes* arguments must fall within a region specified by *buf_index* in the previously registered buffer. The buffer need not be aligned with the start of the registered buffer.
+
+After the read has been prepared it can be submitted with one of the submit functions.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+This function accepts an unsigned number of bytes, but io_uring_cqe\'s result code is an \_\_s32 value, so in theory a short read with a large enough nbytes value could generate an ambiguous return. But the number of bytes actually transferred has the same limit as **read**(2) so this cannot happen in practice.
+
+# SEE ALSO
+
+**io_uring_prep_read**(3), **io_uring_register_buffers**(3)
diff --git a/man/io_uring_prep_read_multishot.3 b/man/io_uring_prep_read_multishot.3
deleted file mode 100644
index ebad9346..00000000
--- a/man/io_uring_prep_read_multishot.3
+++ /dev/null
@@ -1,107 +0,0 @@
-.\" Copyright (C) 2023 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_read_multishot 3 "September 12, 2023" "liburing-2.5" "liburing Manual"
-.SH NAME
-io_uring_prep_read_multishot \- prepare I/O read multishot request
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_read_multishot(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " unsigned " nbytes ","
-.BI " __u64 " offset ","
-.BI " int " buf_group ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_read_multishot (3)
-helper prepares an IO read multishot request. The submission queue entry
-.I sqe
-is setup to use the file descriptor
-.I fd
-to start reading
-into a buffer from the provided buffer group with ID
-.I buf_group
-at the specified
-.IR offset .
-
-.I nbytes
-must be set to zero, as the size read will be given by the size of the
-buffers in the indicated buffer group IO.
-
-On files that are not capable of seeking, the offset must be 0 or -1.
-
-If
-.I nbytes
-exceeds the size of the buffers in the specified buffer group, or if
-.I nbytes
-is
-.B 0 ,
-then the size of the buffer in that group will be used for the transfer.
-
-A multishot read request will repeatedly trigger a completion event
-whenever data is available to read from the file. Because of that,
-this type of request can only be used with a file type that is pollable.
-Examples of that include pipes, tun devices, etc. If used with a regular
-file, or a wrong file type in general, the request will fail with
-.B -EBADFD
-in the CQE
-.I res
-field.
-
-Since multishot requests repeatedly trigger completion events as data
-arrives, it must be used with provided buffers. With provided buffers, the
-application provides buffers to io_uring upfront, and then the kernel picks
-a buffer from the specified group in
-.I buf_group
-when the request is ready to transfer data.
-
-A multishot request will persist as long as no errors are encountered
-doing handling of the request. For each CQE posted on behalf of this request,
-the CQE
-.I flags
-will have
-.B IORING_CQE_F_MORE
-set if the application should expect more completions from this request.
-If this flag isn't set, then that signifies termination of the multishot
-read request.
-
-After the read has been prepared it can be submitted with one of the submit
-functions.
-
-Available since 6.7.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-
-This function accepts an unsigned number of bytes, but io_uring_cqe's result
-code is an __s32 value, so in theory a short read with a large enough nbytes
-value could generate an ambiguous return. But the number of bytes actually
-transferred has the same limit as
-.BR read (2)
-so this cannot happen in practice.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_prep_read (3),
-.BR io_uring_buf_ring_init (3)
-.BR io_uring_buf_ring_add (3),
-.BR io_uring_submit (3)
diff --git a/man/io_uring_prep_read_multishot.3.md b/man/io_uring_prep_read_multishot.3.md
new file mode 100644
index 00000000..c05ec1ad
--- /dev/null
+++ b/man/io_uring_prep_read_multishot.3.md
@@ -0,0 +1,59 @@
+.\" Copyright (C) 2023 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: September 12, 2023
+footer: liburing-2.5
+header: liburing Manual
+section: 3
+title: io_uring_prep_read_multishot
+---
+
+# NAME
+
+io_uring_prep_read_multishot - prepare I/O read multishot request
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_read_multishot(struct io_uring_sqe * sqe ,
+ int fd ,
+ unsigned nbytes ,
+ __u64 offset ,
+ int buf_group );
+
+# DESCRIPTION
+
+The **io_uring_prep_read_multishot**(3) helper prepares an IO read multishot request. The submission queue entry *sqe* is setup to use the file descriptor *fd* to start reading into a buffer from the provided buffer group with ID *buf_group* at the specified *offset*.
+
+*nbytes* must be set to zero, as the size read will be given by the size of the buffers in the indicated buffer group IO.
+
+On files that are not capable of seeking, the offset must be 0 or -1.
+
+If *nbytes* exceeds the size of the buffers in the specified buffer group, or if *nbytes* is **0 ,** then the size of the buffer in that group will be used for the transfer.
+
+A multishot read request will repeatedly trigger a completion event whenever data is available to read from the file. Because of that, this type of request can only be used with a file type that is pollable. Examples of that include pipes, tun devices, etc. If used with a regular file, or a wrong file type in general, the request will fail with **-EBADFD** in the CQE *res* field.
+
+Since multishot requests repeatedly trigger completion events as data arrives, it must be used with provided buffers. With provided buffers, the application provides buffers to io_uring upfront, and then the kernel picks a buffer from the specified group in *buf_group* when the request is ready to transfer data.
+
+A multishot request will persist as long as no errors are encountered doing handling of the request. For each CQE posted on behalf of this request, the CQE *flags* will have **IORING_CQE_F_MORE** set if the application should expect more completions from this request. If this flag isn\'t set, then that signifies termination of the multishot read request.
+
+After the read has been prepared it can be submitted with one of the submit functions.
+
+Available since 6.7.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+This function accepts an unsigned number of bytes, but io_uring_cqe\'s result code is an \_\_s32 value, so in theory a short read with a large enough nbytes value could generate an ambiguous return. But the number of bytes actually transferred has the same limit as **read**(2) so this cannot happen in practice.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_prep_read**(3), **io_uring_buf_ring_init**(3) **io_uring_buf_ring_add**(3), **io_uring_submit**(3)
diff --git a/man/io_uring_prep_readv.3 b/man/io_uring_prep_readv.3
deleted file mode 100644
index a3693820..00000000
--- a/man/io_uring_prep_readv.3
+++ /dev/null
@@ -1,92 +0,0 @@
-.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_readv 3 "November 15, 2021" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_prep_readv \- prepare vector I/O read request
-.SH SYNOPSIS
-.nf
-.B #include <sys/uio.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_readv(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " const struct iovec *" iovecs ","
-.BI " unsigned " nr_vecs ","
-.BI " __u64 " offset ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_readv (3)
-prepares a vectored IO read request. The submission queue entry
-.I sqe
-is setup to use the file descriptor
-.I fd
-to start reading
-.I nr_vecs
-into the
-.I iovecs
-array at the specified
-.IR offset .
-
-On files that support seeking, if the offset is set to
-.BR -1 ,
-the read operation commences at the file offset, and the file offset is
-incremented by the number of bytes read. See
-.BR read (2)
-for more details. Note that for an async API, reading and updating the
-current file offset may result in unpredictable behavior, unless access
-to the file is serialized. It is not encouraged to use this feature, if it's
-possible to provide the desired IO offset from the application or library.
-
-On files that are not capable of seeking, the offset must be 0 or -1.
-
-After the read has been prepared it can be submitted with one of the submit
-functions.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-Unless an application explicitly needs to pass in more than one iovec, it
-is more efficient to use
-.BR io_uring_prep_read (3)
-rather than this function, as no state has to be maintained for a
-non-vectored IO request.
-As with any request that passes in data in a struct, that data must remain
-valid until the request has been successfully submitted. It need not remain
-valid until completion. Once a request has been submitted, the in-kernel
-state is stable. Very early kernels (5.4 and earlier) required state to be
-stable until the completion occurred. Applications can test for this
-behavior by inspecting the
-.B IORING_FEAT_SUBMIT_STABLE
-flag passed back from
-.BR io_uring_queue_init_params (3).
-
-This function accepts an array of iovec's with a size_t number of bytes each,
-but io_uring_cqe's result code is an __s32 value, so in theory a short read
-with a large enough iov_len value could generate an ambiguous return.
-But the number of bytes actually transferred has the same limit as
-.BR read (2)
-so this cannot happen in practice.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_prep_read (3),
-.BR io_uring_prep_readv2 (3),
-.BR io_uring_submit (3)
diff --git a/man/io_uring_prep_readv.3.md b/man/io_uring_prep_readv.3.md
new file mode 100644
index 00000000..f625976a
--- /dev/null
+++ b/man/io_uring_prep_readv.3.md
@@ -0,0 +1,54 @@
+.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: November 15, 2021
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_prep_readv
+---
+
+# NAME
+
+io_uring_prep_readv - prepare vector I/O read request
+
+# SYNOPSIS
+
+ #include <sys/uio.h>
+ #include <liburing.h>
+
+ void io_uring_prep_readv(struct io_uring_sqe * sqe ,
+ int fd ,
+ const struct iovec * iovecs ,
+ unsigned nr_vecs ,
+ __u64 offset );
+
+# DESCRIPTION
+
+The **io_uring_prep_readv**(3) prepares a vectored IO read request. The submission queue entry *sqe* is setup to use the file descriptor *fd* to start reading *nr_vecs* into the *iovecs* array at the specified *offset*.
+
+On files that support seeking, if the offset is set to **-1**, the read operation commences at the file offset, and the file offset is incremented by the number of bytes read. See **read**(2) for more details. Note that for an async API, reading and updating the current file offset may result in unpredictable behavior, unless access to the file is serialized. It is not encouraged to use this feature, if it\'s possible to provide the desired IO offset from the application or library.
+
+On files that are not capable of seeking, the offset must be 0 or -1.
+
+After the read has been prepared it can be submitted with one of the submit functions.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+Unless an application explicitly needs to pass in more than one iovec, it is more efficient to use **io_uring_prep_read**(3) rather than this function, as no state has to be maintained for a non-vectored IO request. As with any request that passes in data in a struct, that data must remain valid until the request has been successfully submitted. It need not remain valid until completion. Once a request has been submitted, the in-kernel state is stable. Very early kernels (5.4 and earlier) required state to be stable until the completion occurred. Applications can test for this behavior by inspecting the **IORING_FEAT_SUBMIT_STABLE** flag passed back from **io_uring_queue_init_params**(3).
+
+This function accepts an array of iovec\'s with a size_t number of bytes each, but io_uring_cqe\'s result code is an \_\_s32 value, so in theory a short read with a large enough iov_len value could generate an ambiguous return. But the number of bytes actually transferred has the same limit as **read**(2) so this cannot happen in practice.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_prep_read**(3), **io_uring_prep_readv2**(3), **io_uring_submit**(3)
diff --git a/man/io_uring_prep_readv2.3 b/man/io_uring_prep_readv2.3
deleted file mode 100644
index bbdfe7c4..00000000
--- a/man/io_uring_prep_readv2.3
+++ /dev/null
@@ -1,118 +0,0 @@
-.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_readv2 3 "November 15, 2021" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_readv2 \- prepare vector I/O read request with flags
-.SH SYNOPSIS
-.nf
-.B #include <sys/uio.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_readv2(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " const struct iovec *" iovecs ","
-.BI " unsigned " nr_vecs ","
-.BI " __u64 " offset ","
-.BI " int " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_readv2 (3)
-prepares a vectored IO read request. The submission queue entry
-.I sqe
-is setup to use the file descriptor
-.I fd
-to start reading
-.I nr_vecs
-into the
-.I iovecs
-array at the specified
-.IR offset .
-The behavior of the function can be controlled with the
-.I flags
-parameter.
-
-Supported values for
-.I flags
-are:
-.TP
-.B RWF_HIPRI
-High priority request, poll if possible
-.TP
-.B RWF_DSYNC
-per-IO O_DSYNC
-.TP
-.B RWF_SYNC
-per-IO O_SYNC
-.TP
-.B RWF_NOWAIT
-per-IO, return
-.B -EAGAIN
-if operation would block
-.TP
-.B RWF_APPEND
-per-IO O_APPEND
-
-.P
-On files that support seeking, if the offset is set to
-.BR -1 ,
-the read operation commences at the file offset, and the file offset is
-incremented by the number of bytes read. See
-.BR read (2)
-for more details. Note that for an async API, reading and updating the
-current file offset may result in unpredictable behavior, unless access
-to the file is serialized. It is not encouraged to use this feature, if it's
-possible to provide the desired IO offset from the application or library.
-
-On files that are not capable of seeking, the offset must be 0 or -1.
-
-After the read has been prepared, it can be submitted with one of the submit
-functions.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-Unless an application explicitly needs to pass in more than one iovec, it
-is more efficient to use
-.BR io_uring_prep_read (3)
-rather than this function, as no state has to be maintained for a
-non-vectored IO request.
-As with any request that passes in data in a struct, that data must remain
-valid until the request has been successfully submitted. It need not remain
-valid until completion. Once a request has been submitted, the in-kernel
-state is stable. Very early kernels (5.4 and earlier) required state to be
-stable until the completion occurred. Applications can test for this
-behavior by inspecting the
-.B IORING_FEAT_SUBMIT_STABLE
-flag passed back from
-.BR io_uring_queue_init_params (3).
-
-This function accepts an array of iovec's with a size_t number of bytes each,
-but io_uring_cqe's result code is an __s32 value, so in theory a short read
-with a large enough iov_len value could generate an ambiguous return.
-But the number of bytes actually transferred has the same limit as
-.BR read (2)
-so this cannot happen in practice.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_prep_read (3),
-.BR io_uring_prep_readv (3),
-.BR io_uring_submit (3)
diff --git a/man/io_uring_prep_readv2.3.md b/man/io_uring_prep_readv2.3.md
new file mode 100644
index 00000000..50b71a6f
--- /dev/null
+++ b/man/io_uring_prep_readv2.3.md
@@ -0,0 +1,77 @@
+.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: November 15, 2021
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_readv2
+---
+
+# NAME
+
+io_uring_prep_readv2 - prepare vector I/O read request with flags
+
+# SYNOPSIS
+
+ #include <sys/uio.h>
+ #include <liburing.h>
+
+ void io_uring_prep_readv2(struct io_uring_sqe * sqe ,
+ int fd ,
+ const struct iovec * iovecs ,
+ unsigned nr_vecs ,
+ __u64 offset ,
+ int flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_readv2**(3) prepares a vectored IO read request. The submission queue entry *sqe* is setup to use the file descriptor *fd* to start reading *nr_vecs* into the *iovecs* array at the specified *offset*. The behavior of the function can be controlled with the *flags* parameter.
+
+Supported values for *flags* are:
+
+**RWF_HIPRI**
+
+: High priority request, poll if possible
+
+**RWF_DSYNC**
+
+: per-IO O_DSYNC
+
+**RWF_SYNC**
+
+: per-IO O_SYNC
+
+**RWF_NOWAIT**
+
+: per-IO, return **-EAGAIN** if operation would block
+
+**RWF_APPEND**
+
+: per-IO O_APPEND
+
+On files that support seeking, if the offset is set to **-1**, the read operation commences at the file offset, and the file offset is incremented by the number of bytes read. See **read**(2) for more details. Note that for an async API, reading and updating the current file offset may result in unpredictable behavior, unless access to the file is serialized. It is not encouraged to use this feature, if it\'s possible to provide the desired IO offset from the application or library.
+
+On files that are not capable of seeking, the offset must be 0 or -1.
+
+After the read has been prepared, it can be submitted with one of the submit functions.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+Unless an application explicitly needs to pass in more than one iovec, it is more efficient to use **io_uring_prep_read**(3) rather than this function, as no state has to be maintained for a non-vectored IO request. As with any request that passes in data in a struct, that data must remain valid until the request has been successfully submitted. It need not remain valid until completion. Once a request has been submitted, the in-kernel state is stable. Very early kernels (5.4 and earlier) required state to be stable until the completion occurred. Applications can test for this behavior by inspecting the **IORING_FEAT_SUBMIT_STABLE** flag passed back from **io_uring_queue_init_params**(3).
+
+This function accepts an array of iovec\'s with a size_t number of bytes each, but io_uring_cqe\'s result code is an \_\_s32 value, so in theory a short read with a large enough iov_len value could generate an ambiguous return. But the number of bytes actually transferred has the same limit as **read**(2) so this cannot happen in practice.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_prep_read**(3), **io_uring_prep_readv**(3), **io_uring_submit**(3)
diff --git a/man/io_uring_prep_readv_fixed.3 b/man/io_uring_prep_readv_fixed.3
deleted file mode 100644
index 6812869e..00000000
--- a/man/io_uring_prep_readv_fixed.3
+++ /dev/null
@@ -1,74 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_readv_fixed 3 "January 18, 2025" "liburing-2.10" "liburing Manual"
-.SH NAME
-io_uring_prep_readv_fixed \- prepare a vectored read using fixed buffers
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_readv_fixed(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " const struct iovec *" iovecs ","
-.BI " unsigned " nr_vecs ","
-.BI " __u64 " offset ","
-.BI " int " flags ","
-.BI " int " buf_index ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_readv_fixed (3)
-function prepares a vectored read request using fixed (registered) buffers.
-The submission queue entry
-.I sqe
-is setup to use the file descriptor
-.I fd
-to start reading
-.I nr_vecs
-iovecs from the file position
-.IR offset .
-
-The
-.I iovecs
-argument points to an array of iovec structures describing the read
-buffers. All buffers must be part of the registered buffer set at index
-.IR buf_index ,
-previously registered with
-.BR io_uring_register_buffers (3).
-
-The
-.I flags
-argument can contain any per-request flags, such as
-.B RWF_NOWAIT
-or other flags supported by
-.BR preadv2 (2).
-
-Using fixed buffers avoids the overhead of mapping buffers for each I/O
-operation, improving performance for applications that reuse the same
-buffers.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation, the number of bytes read
-on success. On error, a negative errno value is returned.
-.SH NOTES
-This function accepts an array of iovec's with a size_t number of bytes each,
-but io_uring_cqe's result code is an __s32 value, so in theory a short read
-with a large enough iov_len value could generate an ambiguous return.
-But the number of bytes actually transferred has the same limit as
-.BR read (2)
-so this cannot happen in practice.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_prep_readv (3),
-.BR io_uring_prep_readv2 (3),
-.BR io_uring_prep_read_fixed (3),
-.BR io_uring_prep_writev_fixed (3),
-.BR io_uring_register_buffers (3)
diff --git a/man/io_uring_prep_readv_fixed.3.md b/man/io_uring_prep_readv_fixed.3.md
new file mode 100644
index 00000000..41398df7
--- /dev/null
+++ b/man/io_uring_prep_readv_fixed.3.md
@@ -0,0 +1,53 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: liburing-2.10
+header: liburing Manual
+section: 3
+title: io_uring_prep_readv_fixed
+---
+
+# NAME
+
+io_uring_prep_readv_fixed - prepare a vectored read using fixed buffers
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_readv_fixed(struct io_uring_sqe * sqe ,
+ int fd ,
+ const struct iovec * iovecs ,
+ unsigned nr_vecs ,
+ __u64 offset ,
+ int flags ,
+ int buf_index );
+
+# DESCRIPTION
+
+The **io_uring_prep_readv_fixed**(3) function prepares a vectored read request using fixed (registered) buffers. The submission queue entry *sqe* is setup to use the file descriptor *fd* to start reading *nr_vecs* iovecs from the file position *offset*.
+
+The *iovecs* argument points to an array of iovec structures describing the read buffers. All buffers must be part of the registered buffer set at index *buf_index*, previously registered with **io_uring_register_buffers**(3).
+
+The *flags* argument can contain any per-request flags, such as **RWF_NOWAIT** or other flags supported by **preadv2**(2).
+
+Using fixed buffers avoids the overhead of mapping buffers for each I/O operation, improving performance for applications that reuse the same buffers.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation, the number of bytes read on success. On error, a negative errno value is returned.
+
+# NOTES
+
+This function accepts an array of iovec\'s with a size_t number of bytes each, but io_uring_cqe\'s result code is an \_\_s32 value, so in theory a short read with a large enough iov_len value could generate an ambiguous return. But the number of bytes actually transferred has the same limit as **read**(2) so this cannot happen in practice.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_prep_readv**(3), **io_uring_prep_readv2**(3), **io_uring_prep_read_fixed**(3), **io_uring_prep_writev_fixed**(3), **io_uring_register_buffers**(3)
diff --git a/man/io_uring_prep_recv.3 b/man/io_uring_prep_recv.3
deleted file mode 100644
index 509b3552..00000000
--- a/man/io_uring_prep_recv.3
+++ /dev/null
@@ -1,147 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_recv 3 "March 12, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_recv \- prepare a recv request
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_recv(struct io_uring_sqe *" sqe ","
-.BI " int " sockfd ","
-.BI " void *" buf ","
-.BI " size_t " len ","
-.BI " int " flags ");"
-.PP
-.BI "void io_uring_prep_recv_multishot(struct io_uring_sqe *" sqe ","
-.BI " int " sockfd ","
-.BI " void *" buf ","
-.BI " size_t " len ","
-.BI " int " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_recv (3)
-function prepares a recv request. The submission
-queue entry
-.I sqe
-is setup to use the file descriptor
-.I sockfd
-to start receiving the data into the destination buffer
-.I buf
-of size
-.I len
-and with modifier flags
-.IR flags .
-
-This function prepares an async
-.BR recv (2)
-request. See that man page for details on the arguments specified to this
-prep helper.
-
-The multishot version allows the application to issue a single receive request,
-which repeatedly posts a CQE when data is available. Length can either be set
-to 0, in which case there are no limits on how much data a single invocation
-of the receive will transfer, or it can be set to a positive value. If the
-latter is the case, then each trigger invocation of the receive multishot will
-transfer at most length bytes. This can be useful if the ring is handling many
-receive multishot operations on different sockets, to ensure fairness between
-them, particularly when used with bundles. The
-.B IOSQE_BUFFER_SELECT
-flag to be set and no
-.B MSG_WAITALL
-flag to be set.
-Therefore each CQE will take a buffer out of a provided buffer pool for receiving.
-The application should check the flags of each CQE, regardless of its result.
-If a posted CQE does not have the
-.B IORING_CQE_F_MORE
-flag set, then the multishot receive is done and the application must issue a
-new request if it still wishes to receive data from the socket.
-Multishot variants are available since kernel 6.0.
-
-
-After calling this function, additional io_uring internal modifier flags
-may be set in the SQE
-.I ioprio
-field. The following flags are supported:
-.TP
-.B IORING_RECVSEND_POLL_FIRST
-If set, io_uring will assume the socket is currently empty and attempting to
-receive data will be unsuccessful. For this case, io_uring will arm internal
-poll and trigger a receive of the data when the socket has data to be read.
-This initial receive attempt can be wasteful for the case where the socket
-is expected to be empty, setting this flag will bypass the initial receive
-attempt and go straight to arming poll. If poll does indicate that data is
-ready to be received, the operation will proceed.
-
-Can be used with the CQE
-.B IORING_CQE_F_SOCK_NONEMPTY
-flag, which io_uring will set on CQEs after a
-.BR recv (2)
-or
-.BR recvmsg (2)
-operation. If set, the socket still had data to be read after the operation
-completed. Both these flags are available since 5.19.
-
-.TP
-.B IORING_RECVSEND_BUNDLE
-If set and provided buffers are used with
-.B IOSQE_BUFFER_SELECT ,
-the receive operation will attempt to fill multiple buffers with rather than
-just pick a single buffer to fill. To receive multiple buffers in a single
-receive, the buffer group ID set in the SQE must be of the ring provided type.
-If set, the CQE
-.I res
-field indicates the total number of bytes received, and the buffer ID returned
-in the CQE
-.I flags
-field indicates the first buffer in the receive operation. The application must
-process the indicated initial buffer ID and until all
-.I res
-bytes have been seen to know which is the last buffer in the receive operation.
-The buffers consumed will be contiguous from the initial buffer, in the order
-in which they appear in the buffer ring. The CQE struct does not contain
-the position of the buffer in the buffer ring, therefore in order to identify
-buffers contained by the bundle, it is advised to maintain the cached head
-index per buffer ring. This uint16_t index represents the position of the next
-buffer to be consumed within the ring. Upon completion of a receive operation,
-the cached head index should be incremented accordingly.
-Receiving in bundles can improve performance when more than one chunk of
-data is available to receive,
-by eliminating redundant round trips through the networking stack. Receive
-bundles may be used by both single shot and multishot receive operations. Note
-that, internally, bundles rely on the networking stack passing back how much
-data is left in the socket after the initial receive. This means that the
-initial receive may contain less buffers than what is available, with the
-followup receive(s) containing more buffers. Available since 6.10.
-.P
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-Despite accepting a size_t number of bytes, these functions can transfer at most
-INT_MAX bytes per call (the maximum for the underlying syscall interface).
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_buf_ring_init (3),
-.BR io_uring_buf_ring_add (3),
-.BR recv (2)
diff --git a/man/io_uring_prep_recv.3.md b/man/io_uring_prep_recv.3.md
new file mode 100644
index 00000000..5a3b4b7d
--- /dev/null
+++ b/man/io_uring_prep_recv.3.md
@@ -0,0 +1,67 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 12, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_recv
+---
+
+# NAME
+
+io_uring_prep_recv - prepare a recv request
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_recv(struct io_uring_sqe * sqe ,
+ int sockfd ,
+ void * buf ,
+ size_t len ,
+ int flags );
+
+ void io_uring_prep_recv_multishot(struct io_uring_sqe * sqe ,
+ int sockfd ,
+ void * buf ,
+ size_t len ,
+ int flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_recv**(3) function prepares a recv request. The submission queue entry *sqe* is setup to use the file descriptor *sockfd* to start receiving the data into the destination buffer *buf* of size *len* and with modifier flags *flags*.
+
+This function prepares an async **recv**(2) request. See that man page for details on the arguments specified to this prep helper.
+
+The multishot version allows the application to issue a single receive request, which repeatedly posts a CQE when data is available. Length can either be set to 0, in which case there are no limits on how much data a single invocation of the receive will transfer, or it can be set to a positive value. If the latter is the case, then each trigger invocation of the receive multishot will transfer at most length bytes. This can be useful if the ring is handling many receive multishot operations on different sockets, to ensure fairness between them, particularly when used with bundles. The **IOSQE_BUFFER_SELECT** flag to be set and no **MSG_WAITALL** flag to be set. Therefore each CQE will take a buffer out of a provided buffer pool for receiving. The application should check the flags of each CQE, regardless of its result. If a posted CQE does not have the **IORING_CQE_F_MORE** flag set, then the multishot receive is done and the application must issue a new request if it still wishes to receive data from the socket. Multishot variants are available since kernel 6.0.
+
+After calling this function, additional io_uring internal modifier flags may be set in the SQE *ioprio* field. The following flags are supported:
+
+**IORING_RECVSEND_POLL_FIRST**
+
+: If set, io_uring will assume the socket is currently empty and attempting to receive data will be unsuccessful. For this case, io_uring will arm internal poll and trigger a receive of the data when the socket has data to be read. This initial receive attempt can be wasteful for the case where the socket is expected to be empty, setting this flag will bypass the initial receive attempt and go straight to arming poll. If poll does indicate that data is ready to be received, the operation will proceed.
+
+ Can be used with the CQE **IORING_CQE_F_SOCK_NONEMPTY** flag, which io_uring will set on CQEs after a **recv**(2) or **recvmsg**(2) operation. If set, the socket still had data to be read after the operation completed. Both these flags are available since 5.19.
+
+**IORING_RECVSEND_BUNDLE**
+
+: If set and provided buffers are used with **IOSQE_BUFFER_SELECT ,** the receive operation will attempt to fill multiple buffers with rather than just pick a single buffer to fill. To receive multiple buffers in a single receive, the buffer group ID set in the SQE must be of the ring provided type. If set, the CQE *res* field indicates the total number of bytes received, and the buffer ID returned in the CQE *flags* field indicates the first buffer in the receive operation. The application must process the indicated initial buffer ID and until all *res* bytes have been seen to know which is the last buffer in the receive operation. The buffers consumed will be contiguous from the initial buffer, in the order in which they appear in the buffer ring. The CQE struct does not contain the position of the buffer in the buffer ring, therefore in order to identify buffers contained by the bundle, it is advised to maintain the cached head index per buffer ring. This uint16_t index represents the position of the next buffer to be consumed within the ring. Upon completion of a receive operation, the cached head index should be incremented accordingly. Receiving in bundles can improve performance when more than one chunk of data is available to receive, by eliminating redundant round trips through the networking stack. Receive bundles may be used by both single shot and multishot receive operations. Note that, internally, bundles rely on the networking stack passing back how much data is left in the socket after the initial receive. This means that the initial receive may contain less buffers than what is available, with the followup receive(s) containing more buffers. Available since 6.10.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+Despite accepting a size_t number of bytes, these functions can transfer at most INT_MAX bytes per call (the maximum for the underlying syscall interface).
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_buf_ring_init**(3), **io_uring_buf_ring_add**(3), **recv**(2)
diff --git a/man/io_uring_prep_recv_multishot.3 b/man/io_uring_prep_recv_multishot.3
deleted file mode 120000
index 71fe277d..00000000
--- a/man/io_uring_prep_recv_multishot.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_recv.3
\ No newline at end of file
diff --git a/man/io_uring_prep_recvmsg.3 b/man/io_uring_prep_recvmsg.3
deleted file mode 100644
index 74a0c9ef..00000000
--- a/man/io_uring_prep_recvmsg.3
+++ /dev/null
@@ -1,130 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_recvmsg 3 "March 12, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_recvmsg \- prepare a recvmsg request
-.SH SYNOPSIS
-.nf
-.B #include <sys/types.h>
-.B #include <sys/socket.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_recvmsg(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " struct msghdr *" msg ","
-.BI " unsigned " flags ");"
-.PP
-.BI "void io_uring_prep_recvmsg_multishot(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " struct msghdr *" msg ","
-.BI " unsigned " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_recvmsg (3)
-function prepares a recvmsg request. The submission queue entry
-.I sqe
-is setup to use the file descriptor
-.I fd
-to start receiving the data indicated by
-.I msg
-with the
-.BR recvmsg (2)
-defined flags in the
-.I flags
-argument.
-
-This function prepares an async
-.BR recvmsg (2)
-request. See that man page for details on the arguments specified to this
-prep helper.
-
-The multishot version allows the application to issue a single receive request,
-which repeatedly posts a CQE when data is available. It requires the
-.B IOSQE_BUFFER_SELECT
-flag to be set and no
-.B MSG_WAITALL
-flag to be set.
-Therefore each CQE will take a buffer out of a provided buffer pool for receiving.
-The application should check the flags of each CQE, regardless of its result.
-If a posted CQE does not have the
-.B IORING_CQE_F_MORE
-flag set, then the multishot receive is done and the application must issue a
-new request if it still wishes to receive data from the socket.
-
-Unlike
-.BR recvmsg (2),
-multishot recvmsg will prepend a
-.I struct io_uring_recvmsg_out
-which describes the layout of the rest of the buffer in combination with the initial
-.I struct msghdr
-submitted with the request. See
-.BR io_uring_recvmsg_out (3)
-for more information on accessing the data.
-
-Multishot variants are available since kernel 6.0.
-
-After calling this function, additional io_uring internal modifier flags
-may be set in the SQE
-.I ioprio
-field. The following flags are supported:
-.TP
-.B IORING_RECVSEND_POLL_FIRST
-If set, io_uring will assume the socket is currently empty and attempting to
-receive data will be unsuccessful. For this case, io_uring will arm internal
-poll and trigger a receive of the data when the socket has data to be read.
-This initial receive attempt can be wasteful for the case where the socket
-is expected to be empty, setting this flag will bypass the initial receive
-attempt and go straight to arming poll. If poll does indicate that data is
-ready to be received, the operation will proceed.
-
-Can be used with the CQE
-.B IORING_CQE_F_SOCK_NONEMPTY
-flag, which io_uring will set on CQEs after a
-.BR recv (2)
-or
-.BR recvmsg (2)
-operation. If set, the socket still had data to be read after the operation
-completed. Both these flags are available since 5.19.
-.P
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-As with any request that passes in data in a struct, that data must remain
-valid until the request has been successfully submitted. It need not remain
-valid until completion. Once a request has been submitted, the in-kernel
-state is stable. Very early kernels (5.4 and earlier) required state to be
-stable until the completion occurred. Applications can test for this
-behavior by inspecting the
-.B IORING_FEAT_SUBMIT_STABLE
-flag passed back from
-.BR io_uring_queue_init_params (3).
-
-Despite accepting an array of iovec's with a size_t number of bytes each,
-these functions can transfer at most INT_MAX bytes per call (the maximum
-for the underlying syscall interface).
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_buf_ring_init (3),
-.BR io_uring_buf_ring_add (3),
-.BR recvmsg (2)
diff --git a/man/io_uring_prep_recvmsg.3.md b/man/io_uring_prep_recvmsg.3.md
new file mode 100644
index 00000000..2f03c0ad
--- /dev/null
+++ b/man/io_uring_prep_recvmsg.3.md
@@ -0,0 +1,69 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 12, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_recvmsg
+---
+
+# NAME
+
+io_uring_prep_recvmsg - prepare a recvmsg request
+
+# SYNOPSIS
+
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <liburing.h>
+
+ void io_uring_prep_recvmsg(struct io_uring_sqe * sqe ,
+ int fd ,
+ struct msghdr * msg ,
+ unsigned flags );
+
+ void io_uring_prep_recvmsg_multishot(struct io_uring_sqe * sqe ,
+ int fd ,
+ struct msghdr * msg ,
+ unsigned flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_recvmsg**(3) function prepares a recvmsg request. The submission queue entry *sqe* is setup to use the file descriptor *fd* to start receiving the data indicated by *msg* with the **recvmsg**(2) defined flags in the *flags* argument.
+
+This function prepares an async **recvmsg**(2) request. See that man page for details on the arguments specified to this prep helper.
+
+The multishot version allows the application to issue a single receive request, which repeatedly posts a CQE when data is available. It requires the **IOSQE_BUFFER_SELECT** flag to be set and no **MSG_WAITALL** flag to be set. Therefore each CQE will take a buffer out of a provided buffer pool for receiving. The application should check the flags of each CQE, regardless of its result. If a posted CQE does not have the **IORING_CQE_F_MORE** flag set, then the multishot receive is done and the application must issue a new request if it still wishes to receive data from the socket.
+
+Unlike **recvmsg**(2), multishot recvmsg will prepend a *struct io_uring_recvmsg_out* which describes the layout of the rest of the buffer in combination with the initial *struct msghdr* submitted with the request. See **io_uring_recvmsg_out**(3) for more information on accessing the data.
+
+Multishot variants are available since kernel 6.0.
+
+After calling this function, additional io_uring internal modifier flags may be set in the SQE *ioprio* field. The following flags are supported:
+
+**IORING_RECVSEND_POLL_FIRST**
+
+: If set, io_uring will assume the socket is currently empty and attempting to receive data will be unsuccessful. For this case, io_uring will arm internal poll and trigger a receive of the data when the socket has data to be read. This initial receive attempt can be wasteful for the case where the socket is expected to be empty, setting this flag will bypass the initial receive attempt and go straight to arming poll. If poll does indicate that data is ready to be received, the operation will proceed.
+
+ Can be used with the CQE **IORING_CQE_F_SOCK_NONEMPTY** flag, which io_uring will set on CQEs after a **recv**(2) or **recvmsg**(2) operation. If set, the socket still had data to be read after the operation completed. Both these flags are available since 5.19.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+As with any request that passes in data in a struct, that data must remain valid until the request has been successfully submitted. It need not remain valid until completion. Once a request has been submitted, the in-kernel state is stable. Very early kernels (5.4 and earlier) required state to be stable until the completion occurred. Applications can test for this behavior by inspecting the **IORING_FEAT_SUBMIT_STABLE** flag passed back from **io_uring_queue_init_params**(3).
+
+Despite accepting an array of iovec\'s with a size_t number of bytes each, these functions can transfer at most INT_MAX bytes per call (the maximum for the underlying syscall interface).
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_buf_ring_init**(3), **io_uring_buf_ring_add**(3), **recvmsg**(2)
diff --git a/man/io_uring_prep_recvmsg_multishot.3 b/man/io_uring_prep_recvmsg_multishot.3
deleted file mode 120000
index cd9566f2..00000000
--- a/man/io_uring_prep_recvmsg_multishot.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_recvmsg.3
\ No newline at end of file
diff --git a/man/io_uring_prep_remove_buffers.3 b/man/io_uring_prep_remove_buffers.3
deleted file mode 100644
index cf4f2264..00000000
--- a/man/io_uring_prep_remove_buffers.3
+++ /dev/null
@@ -1,52 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_remove_buffers 3 "March 13, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_remove_buffers \- prepare a remove buffers request
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_remove_buffers(struct io_uring_sqe *" sqe ","
-.BI " int " nr ","
-.BI " int " bgid ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_remove_buffers (3)
-function prepares a request for removing previously supplied buffers. The
-submission queue entry
-.I sqe
-is setup to remove
-.I nr
-number of buffers from the buffer group ID indicated by
-.IR bgid .
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-These are the errors that are reported in the CQE
-.I res
-field. On success,
-.I res
-will contain the number of successfully removed buffers. On error,
-the following errors can occur.
-.TP
-.B -ENOMEM
-The kernel was unable to allocate memory for the request.
-.TP
-.B -EINVAL
-One of the fields set in the SQE was invalid.
-.TP
-.B -ENOENT
-No buffers exist at the specified
-.I bgid
-buffer group ID.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_register (2),
-.BR io_uring_prep_provide_buffers (3)
diff --git a/man/io_uring_prep_remove_buffers.3.md b/man/io_uring_prep_remove_buffers.3.md
new file mode 100644
index 00000000..76869689
--- /dev/null
+++ b/man/io_uring_prep_remove_buffers.3.md
@@ -0,0 +1,51 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 13, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_remove_buffers
+---
+
+# NAME
+
+io_uring_prep_remove_buffers - prepare a remove buffers request
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_remove_buffers(struct io_uring_sqe * sqe ,
+ int nr ,
+ int bgid );
+
+# DESCRIPTION
+
+The **io_uring_prep_remove_buffers**(3) function prepares a request for removing previously supplied buffers. The submission queue entry *sqe* is setup to remove *nr* number of buffers from the buffer group ID indicated by *bgid*.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+These are the errors that are reported in the CQE *res* field. On success, *res* will contain the number of successfully removed buffers. On error, the following errors can occur.
+
+**-ENOMEM**
+
+: The kernel was unable to allocate memory for the request.
+
+**-EINVAL**
+
+: One of the fields set in the SQE was invalid.
+
+**-ENOENT**
+
+: No buffers exist at the specified *bgid* buffer group ID.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_register**(2), **io_uring_prep_provide_buffers**(3)
diff --git a/man/io_uring_prep_rename.3 b/man/io_uring_prep_rename.3
deleted file mode 120000
index 785b55eb..00000000
--- a/man/io_uring_prep_rename.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_renameat.3
\ No newline at end of file
diff --git a/man/io_uring_prep_renameat.3 b/man/io_uring_prep_renameat.3
deleted file mode 100644
index 1ecdc2ab..00000000
--- a/man/io_uring_prep_renameat.3
+++ /dev/null
@@ -1,95 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_renameat 3 "March 13, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_renameat \- prepare a renameat request
-.SH SYNOPSIS
-.nf
-.B #include <fcntl.h>
-.B #include <stdio.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_renameat(struct io_uring_sqe *" sqe ","
-.BI " int " olddirfd ","
-.BI " const char *" oldpath ","
-.BI " int " newdirfd ","
-.BI " const char *" newpath ","
-.BI " unsigned int " flags ");"
-.PP
-.BI "void io_uring_prep_rename(struct io_uring_sqe *" sqe ","
-.BI " const char *" oldpath ","
-.BI " const char *" newpath ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_renameat (3)
-function prepares a renameat request. The submission queue entry
-.I sqe
-is setup to use the old directory file descriptor pointed to by
-.I olddirfd
-and old path pointed to by
-.I oldpath
-with the new directory file descriptor pointed to by
-.I newdirfd
-and the new path pointed to by
-.I newpath
-and using the specified flags in
-.IR flags .
-
-The
-.BR io_uring_prep_rename (3)
-function prepares a rename request. The submission queue entry
-.I sqe
-is setup to use the old path pointed to by
-.I oldpath
-with the new path pointed to by
-.IR newpath ,
-both relative to the current working directory and using the specified flags in
-.IR flags .
-
-These functions prepare an async
-.BR renameat2 (2)
-or
-.BR rename (2)
-request. If
-.I flags
-is zero, then this call is similar to the
-.BR renameat (2)
-system call. See those man pages for details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-As with any request that passes in data in a struct, that data must remain
-valid until the request has been successfully submitted. It need not remain
-valid until completion. Once a request has been submitted, the in-kernel
-state is stable. Very early kernels (5.4 and earlier) required state to be
-stable until the completion occurred. Applications can test for this
-behavior by inspecting the
-.B IORING_FEAT_SUBMIT_STABLE
-flag passed back from
-.BR io_uring_queue_init_params (3).
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR renameat (2),
-.BR renameat2 (2),
-.BR rename (2)
diff --git a/man/io_uring_prep_renameat.3.md b/man/io_uring_prep_renameat.3.md
new file mode 100644
index 00000000..03cd06a5
--- /dev/null
+++ b/man/io_uring_prep_renameat.3.md
@@ -0,0 +1,56 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 13, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_renameat
+---
+
+# NAME
+
+io_uring_prep_renameat - prepare a renameat request
+
+# SYNOPSIS
+
+ #include <fcntl.h>
+ #include <stdio.h>
+ #include <liburing.h>
+
+ void io_uring_prep_renameat(struct io_uring_sqe * sqe ,
+ int olddirfd ,
+ const char * oldpath ,
+ int newdirfd ,
+ const char * newpath ,
+ unsigned int flags );
+
+ void io_uring_prep_rename(struct io_uring_sqe * sqe ,
+ const char * oldpath ,
+ const char * newpath );
+
+# DESCRIPTION
+
+The **io_uring_prep_renameat**(3) function prepares a renameat request. The submission queue entry *sqe* is setup to use the old directory file descriptor pointed to by *olddirfd* and old path pointed to by *oldpath* with the new directory file descriptor pointed to by *newdirfd* and the new path pointed to by *newpath* and using the specified flags in *flags*.
+
+The **io_uring_prep_rename**(3) function prepares a rename request. The submission queue entry *sqe* is setup to use the old path pointed to by *oldpath* with the new path pointed to by *newpath*, both relative to the current working directory and using the specified flags in *flags*.
+
+These functions prepare an async **renameat2**(2) or **rename**(2) request. If *flags* is zero, then this call is similar to the **renameat**(2) system call. See those man pages for details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+As with any request that passes in data in a struct, that data must remain valid until the request has been successfully submitted. It need not remain valid until completion. Once a request has been submitted, the in-kernel state is stable. Very early kernels (5.4 and earlier) required state to be stable until the completion occurred. Applications can test for this behavior by inspecting the **IORING_FEAT_SUBMIT_STABLE** flag passed back from **io_uring_queue_init_params**(3).
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **renameat**(2), **renameat2**(2), **rename**(2)
diff --git a/man/io_uring_prep_send.3 b/man/io_uring_prep_send.3
deleted file mode 100644
index f4470528..00000000
--- a/man/io_uring_prep_send.3
+++ /dev/null
@@ -1,197 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_send 3 "March 12, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_send \- prepare a send request
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_send(struct io_uring_sqe *" sqe ","
-.BI " int " sockfd ","
-.BI " const void *" buf ","
-.BI " size_t " len ","
-.BI " int " flags ");"
-.PP
-.BI "void io_uring_prep_sendto(struct io_uring_sqe *" sqe ","
-.BI " int " sockfd ","
-.BI " const void *" buf ","
-.BI " size_t " len ","
-.BI " int " flags ","
-.BI " const struct sockaddr *" addr ","
-.BI " socklen_t " addrlen ");"
-.PP
-.BI "void io_uring_prep_send_bundle(struct io_uring_sqe *" sqe ","
-.BI " int " sockfd ","
-.BI " size_t " len ","
-.BI " int " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_send (3)
-function prepares a send request. The submission queue entry
-.I sqe
-is setup to use the file descriptor
-.I sockfd
-to start sending the data from
-.I buf
-of size
-.I len
-bytes and with modifier flags
-.IR flags .
-
-After calling this function, additional io_uring internal modifier flags
-may be set in the SQE
-.I ioprio
-field. The following flags are supported:
-.TP
-.B IORING_RECVSEND_POLL_FIRST
-If set, io_uring will assume the socket is currently full and attempting to
-send data will be unsuccessful. For this case, io_uring will arm internal
-poll and trigger a send of the data when the socket has space available.
-If poll does indicate that space is available in the socket, the operation
-will proceed immediately.
-
-.TP
-.B IORING_RECVSEND_BUNDLE
-If set, the send operation will attempt to fill multiple buffers with rather than
-just pick a single buffer to fill. To send multiple buffers in a single
-send, the buffer group ID set in the SQE must be of the ring provided type.
-If set, the CQE
-.I res
-field indicates the total number of bytes sent, and the buffer ID returned
-in the CQE
-.I flags
-field indicates the first buffer in the send operation. The application must
-process the indicated initial buffer ID and until all
-.I res
-bytes have been seen to know which is the last buffer in the send operation.
-The buffers consumed will be contiguous from the initial buffer, in the order
-in which they appear in the buffer ring. The CQE struct does not contain
-the position of the buffer in the buffer ring, therefore in order to identify
-buffers contained by the bundle, it is advised to maintain the cached head
-index per buffer ring. This uint16_t index represents the position of the next
-buffer to be consumed within the ring. Upon completion of a bundle send operation,
-the cached head index should be incremented accordingly.
-Sending in bundles can improve performance when more than one chunk of
-data is available by eliminating redundant round trips through the networking
-stack.
-.TP
-.B IORING_SEND_VECTORIZED
-If set,
-.I addr must point to an array of
-.I struct iovec
-and
-.I len
-must be the number of vectors in that array. This enables use of vectorized IO
-for a normal send operation, rather than needing a sendmsg variant to
-accomplish that.
-.P
-
-Note that using
-.B IOSQE_IO_LINK
-with this request type requires the setting of
-.B MSG_WAITALL
-in the
-.IR flags
-argument, as a short send isn't a considered an error condition without
-that being set.
-
-This function prepares an async
-.BR send (2)
-request. See that man page for details.
-
-The
-.BR io_uring_prep_sendto (3)
-function prepares a sendto request. The submission queue entry
-.I sqe
-is setup to use the file descriptor
-.I sockfd
-to start sending the data from
-.I buf
-of size
-.I len
-bytes and with modifier flags
-.IR flags .
-The destination address is specified by
-.I addr
-and
-.I addrlen
-and must be a valid address for the socket type.
-
-This function prepares an async
-.BR sendto (2)
-request. See that man page for details.
-
-Both of the above send variants may be used with provided buffers, where rather
-than pass a buffer in directly with the request,
-.B IOSQE_BUFFER_SELECT
-is set in the SQE
-.I flags
-field, and additionally a buffer group ID is set in the SQE
-.I buf_group
-field. By using provided buffers with send requests, the application can
-prevent any kind of reordering of the outgoing data which can otherwise
-occur if the application has more than one send request inflight for a single
-socket. This provides better pipelining of data, where previously the app
-needed to manually serialize sends.
-
-The bundle version allows the application to issue a single send request,
-with a buffer group ID given in the SQE
-.I buf_group
-field, which keeps sending from that buffer group until it runs out of buffers.
-As with any other request using provided buffers,
-.B IOSQE_BUFFER_SELECT
-must also be set in the SQE
-.I flags
-before submission. Currently
-.I len
-must be given as
-.B 0
-otherwise the request will be errored with
-.B -EINVAL
-as the result code. Future versions may allow setting
-.I
-to limit the transfer size. A single CQE is posted for the send, with the result
-being how many bytes were sent, on success. When used with provided buffers,
-send or send bundle will contain the starting buffer group ID in the CQE
-.I flags
-field. The number of bytes sent starts from there, and will be in contiguous
-buffer IDs after that. Send bundle, and send with provided buffers in general,
-are available since kernel 6.10, and can be further identified by checking for
-the
-.B IORING_FEAT_SEND_BUF_SELECT
-flag returned in when using
-.BR io_uring_queue_init_params (3)
-to setup the ring.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-Despite accepting a size_t number of bytes, these functions can transfer at most
-INT_MAX bytes per call (the maximum for the underlying syscall interface).
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_buf_ring_init (3),
-.BR io_uring_buf_ring_add (3),
-.BR send (2)
-.BR sendto (2)
diff --git a/man/io_uring_prep_send.3.md b/man/io_uring_prep_send.3.md
new file mode 100644
index 00000000..4da96ef2
--- /dev/null
+++ b/man/io_uring_prep_send.3.md
@@ -0,0 +1,84 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 12, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_send
+---
+
+# NAME
+
+io_uring_prep_send - prepare a send request
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_send(struct io_uring_sqe * sqe ,
+ int sockfd ,
+ const void * buf ,
+ size_t len ,
+ int flags );
+
+ void io_uring_prep_sendto(struct io_uring_sqe * sqe ,
+ int sockfd ,
+ const void * buf ,
+ size_t len ,
+ int flags ,
+ const struct sockaddr * addr ,
+ socklen_t addrlen );
+
+ void io_uring_prep_send_bundle(struct io_uring_sqe * sqe ,
+ int sockfd ,
+ size_t len ,
+ int flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_send**(3) function prepares a send request. The submission queue entry *sqe* is setup to use the file descriptor *sockfd* to start sending the data from *buf* of size *len* bytes and with modifier flags *flags*.
+
+After calling this function, additional io_uring internal modifier flags may be set in the SQE *ioprio* field. The following flags are supported:
+
+**IORING_RECVSEND_POLL_FIRST**
+
+: If set, io_uring will assume the socket is currently full and attempting to send data will be unsuccessful. For this case, io_uring will arm internal poll and trigger a send of the data when the socket has space available. If poll does indicate that space is available in the socket, the operation will proceed immediately.
+
+**IORING_RECVSEND_BUNDLE**
+
+: If set, the send operation will attempt to fill multiple buffers with rather than just pick a single buffer to fill. To send multiple buffers in a single send, the buffer group ID set in the SQE must be of the ring provided type. If set, the CQE *res* field indicates the total number of bytes sent, and the buffer ID returned in the CQE *flags* field indicates the first buffer in the send operation. The application must process the indicated initial buffer ID and until all *res* bytes have been seen to know which is the last buffer in the send operation. The buffers consumed will be contiguous from the initial buffer, in the order in which they appear in the buffer ring. The CQE struct does not contain the position of the buffer in the buffer ring, therefore in order to identify buffers contained by the bundle, it is advised to maintain the cached head index per buffer ring. This uint16_t index represents the position of the next buffer to be consumed within the ring. Upon completion of a bundle send operation, the cached head index should be incremented accordingly. Sending in bundles can improve performance when more than one chunk of data is available by eliminating redundant round trips through the networking stack.
+
+**IORING_SEND_VECTORIZED**
+
+: If set, *addr must point to an array of* *struct iovec* and *len* must be the number of vectors in that array. This enables use of vectorized IO for a normal send operation, rather than needing a sendmsg variant to accomplish that.
+
+Note that using **IOSQE_IO_LINK** with this request type requires the setting of **MSG_WAITALL** in the *flags* argument, as a short send isn\'t a considered an error condition without that being set.
+
+This function prepares an async **send**(2) request. See that man page for details.
+
+The **io_uring_prep_sendto**(3) function prepares a sendto request. The submission queue entry *sqe* is setup to use the file descriptor *sockfd* to start sending the data from *buf* of size *len* bytes and with modifier flags *flags*. The destination address is specified by *addr* and *addrlen* and must be a valid address for the socket type.
+
+This function prepares an async **sendto**(2) request. See that man page for details.
+
+Both of the above send variants may be used with provided buffers, where rather than pass a buffer in directly with the request, **IOSQE_BUFFER_SELECT** is set in the SQE *flags* field, and additionally a buffer group ID is set in the SQE *buf_group* field. By using provided buffers with send requests, the application can prevent any kind of reordering of the outgoing data which can otherwise occur if the application has more than one send request inflight for a single socket. This provides better pipelining of data, where previously the app needed to manually serialize sends.
+
+The bundle version allows the application to issue a single send request, with a buffer group ID given in the SQE *buf_group* field, which keeps sending from that buffer group until it runs out of buffers. As with any other request using provided buffers, **IOSQE_BUFFER_SELECT** must also be set in the SQE *flags* before submission. Currently *len* must be given as **0** otherwise the request will be errored with **-EINVAL** as the result code. Future versions may allow setting *to limit the transfer size. A single CQE is posted for the send, with the result* being how many bytes were sent, on success. When used with provided buffers, send or send bundle will contain the starting buffer group ID in the CQE *flags* field. The number of bytes sent starts from there, and will be in contiguous buffer IDs after that. Send bundle, and send with provided buffers in general, are available since kernel 6.10, and can be further identified by checking for the **IORING_FEAT_SEND_BUF_SELECT** flag returned in when using **io_uring_queue_init_params**(3) to setup the ring.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+Despite accepting a size_t number of bytes, these functions can transfer at most INT_MAX bytes per call (the maximum for the underlying syscall interface).
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_buf_ring_init**(3), **io_uring_buf_ring_add**(3), **send**(2) **sendto**(2)
diff --git a/man/io_uring_prep_send_bundle.3 b/man/io_uring_prep_send_bundle.3
deleted file mode 120000
index ba85e684..00000000
--- a/man/io_uring_prep_send_bundle.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_send.3
\ No newline at end of file
diff --git a/man/io_uring_prep_send_set_addr.3 b/man/io_uring_prep_send_set_addr.3
deleted file mode 100644
index 5adcdbc8..00000000
--- a/man/io_uring_prep_send_set_addr.3
+++ /dev/null
@@ -1,38 +0,0 @@
-.\" Copyright (C) 2023 Rutvik Patel <heyrutvik@gmail.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_send_set_addr 3 "January 23, 2023" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_prep_send_set_addr \- set address details for send requests
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_send_set_addr(struct io_uring_sqe *" sqe ","
-.BI " const struct sockaddr *" dest_addr ","
-.BI " __u16 " addr_len ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_send_set_addr (3)
-function sets a socket destination address specified by
-.I dest_addr
-and its length using
-.I addr_len
-parameters. It can be used once
-.I sqe
-is prepared using any of the
-.BR send (2)
-io_uring helpers. See man pages of
-.BR io_uring_prep_send (3)
-or
-.BR io_uring_prep_send_zc (3).
-.SH RETURN VALUE
-None
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_prep_send (3),
-.BR io_uring_prep_send_zc (3),
-.BR send (2)
diff --git a/man/io_uring_prep_send_set_addr.3.md b/man/io_uring_prep_send_set_addr.3.md
new file mode 100644
index 00000000..35e1d14d
--- /dev/null
+++ b/man/io_uring_prep_send_set_addr.3.md
@@ -0,0 +1,35 @@
+.\" Copyright (C) 2023 Rutvik Patel <heyrutvik@gmail.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 23, 2023
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_prep_send_set_addr
+---
+
+# NAME
+
+io_uring_prep_send_set_addr - set address details for send requests
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_send_set_addr(struct io_uring_sqe * sqe ,
+ const struct sockaddr * dest_addr ,
+ __u16 addr_len );
+
+# DESCRIPTION
+
+The **io_uring_prep_send_set_addr**(3) function sets a socket destination address specified by *dest_addr* and its length using *addr_len* parameters. It can be used once *sqe* is prepared using any of the **send**(2) io_uring helpers. See man pages of **io_uring_prep_send**(3) or **io_uring_prep_send_zc**(3).
+
+# RETURN VALUE
+
+None
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_prep_send**(3), **io_uring_prep_send_zc**(3), **send**(2)
diff --git a/man/io_uring_prep_send_zc.3 b/man/io_uring_prep_send_zc.3
deleted file mode 100644
index 8d96f07f..00000000
--- a/man/io_uring_prep_send_zc.3
+++ /dev/null
@@ -1,140 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_send_zc 3 "September 6, 2022" "liburing-2.3" "liburing Manual"
-.SH NAME
-io_uring_prep_send_zc \- prepare a zerocopy send request
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_send_zc(struct io_uring_sqe *" sqe ","
-.BI " int " sockfd ","
-.BI " const void *" buf ","
-.BI " size_t " len ","
-.BI " int " flags ","
-.BI " unsigned " zc_flags ");"
-.PP
-.BI "void io_uring_prep_send_zc_fixed(struct io_uring_sqe *" sqe ","
-.BI " int " sockfd ","
-.BI " const void *" buf ","
-.BI " size_t " len ","
-.BI " int " flags ","
-.BI " unsigned " zc_flags ");"
-.BI " unsigned " buf_index ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_send_zc (3)
-function prepares a zerocopy send request. The submission queue entry
-.I sqe
-is setup to use the file descriptor
-.I sockfd
-to start sending the data from
-.I buf
-of size
-.I len
-bytes with send modifier flags
-.I flags
-and zerocopy modifier flags
-.IR zc_flags .
-
-The
-.BR io_uring_prep_send_zc_fixed (3)
-works just like
-.BR io_uring_prep_send_zc (3)
-except it requires the use of buffers that have been registered with
-.BR io_uring_register_buffers (3).
-The
-.I buf
-and
-.I len
-arguments must fall within a region specified by
-.I buf_index
-in the previously registered buffer. The buffer need not be aligned with the
-start of the registered buffer.
-
-See
-.BR io_uring_prep_send (3)
-for a description of flags that can be set in the SQE
-.I ioprio
-field. In addition to those, the zero-copy send also supports setting
-.B IORING_SEND_ZC_REPORT_USAGE .
-If set, the notification CQE
-.I res
-field will report the number of bytes that were copied rather than sent with
-zero copy. A value of
-.B 0
-indicates success. If the value is
-.B IORING_NOTIF_USAGE_ZC_COPIED ,
-then data was copied.
-
-As opposed to non-zerocopy send requests, a zerocopy send will usually
-generate two CQEs. The first CQE holds the result of the send operation itself,
-and if that CQE has
-.B IORING_CQE_F_MORE
-set in the CQE
-.I flags
-field, then a second notification CQE will be posted for the operation. This
-second notification tells the application that the memory associated with the
-send is safe to get reused. The second CQE will have
-.B IORING_CQE_F_NOTIF
-set in the CQE
-.I flags
-field. Also see the
-.BR io_uring_enter (2)
-man page for a fuller description of the notification CQE.
-
-Note that using
-.B IOSQE_IO_LINK
-with this request type requires the setting of
-.B MSG_WAITALL
-in the
-.I flags
-argument, as a short send isn't considered an error condition without
-that being set.
-
-These functions prepare an async zerocopy
-.BR send (2)
-request. See that man page for details. For details on the zerocopy nature
-of it, see
-.BR io_uring_enter (2) .
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field. Some common error cases are:
-.TP
-.B -ENOMEM
-The
-.BR ulimit (1)
--l setting is too low to support the size of the attempted zero copy send.
-Increasing the limit may help
-.TP
-.B -ENOMEM
-The kernel ran out of memory.
-.P
-.SH NOTES
-Despite accepting a size_t number of bytes, these functions can transfer at most
-INT_MAX bytes per call (the maximum for the underlying syscall interface).
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_prep_send (3),
-.BR io_uring_enter (2),
-.BR send (2)
diff --git a/man/io_uring_prep_send_zc.3.md b/man/io_uring_prep_send_zc.3.md
new file mode 100644
index 00000000..3a95c93b
--- /dev/null
+++ b/man/io_uring_prep_send_zc.3.md
@@ -0,0 +1,72 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: September 6, 2022
+footer: liburing-2.3
+header: liburing Manual
+section: 3
+title: io_uring_prep_send_zc
+---
+
+# NAME
+
+io_uring_prep_send_zc - prepare a zerocopy send request
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_send_zc(struct io_uring_sqe * sqe ,
+ int sockfd ,
+ const void * buf ,
+ size_t len ,
+ int flags ,
+ unsigned zc_flags );
+
+ void io_uring_prep_send_zc_fixed(struct io_uring_sqe * sqe ,
+ int sockfd ,
+ const void * buf ,
+ size_t len ,
+ int flags ,
+ unsigned zc_flags );
+ unsigned buf_index );
+
+# DESCRIPTION
+
+The **io_uring_prep_send_zc**(3) function prepares a zerocopy send request. The submission queue entry *sqe* is setup to use the file descriptor *sockfd* to start sending the data from *buf* of size *len* bytes with send modifier flags *flags* and zerocopy modifier flags *zc_flags*.
+
+The **io_uring_prep_send_zc_fixed**(3) works just like **io_uring_prep_send_zc**(3) except it requires the use of buffers that have been registered with **io_uring_register_buffers**(3). The *buf* and *len* arguments must fall within a region specified by *buf_index* in the previously registered buffer. The buffer need not be aligned with the start of the registered buffer.
+
+See **io_uring_prep_send**(3) for a description of flags that can be set in the SQE *ioprio* field. In addition to those, the zero-copy send also supports setting **IORING_SEND_ZC_REPORT_USAGE .** If set, the notification CQE *res* field will report the number of bytes that were copied rather than sent with zero copy. A value of **0** indicates success. If the value is **IORING_NOTIF_USAGE_ZC_COPIED ,** then data was copied.
+
+As opposed to non-zerocopy send requests, a zerocopy send will usually generate two CQEs. The first CQE holds the result of the send operation itself, and if that CQE has **IORING_CQE_F_MORE** set in the CQE *flags* field, then a second notification CQE will be posted for the operation. This second notification tells the application that the memory associated with the send is safe to get reused. The second CQE will have **IORING_CQE_F_NOTIF** set in the CQE *flags* field. Also see the **io_uring_enter**(2) man page for a fuller description of the notification CQE.
+
+Note that using **IOSQE_IO_LINK** with this request type requires the setting of **MSG_WAITALL** in the *flags* argument, as a short send isn\'t considered an error condition without that being set.
+
+These functions prepare an async zerocopy **send**(2) request. See that man page for details. For details on the zerocopy nature of it, see **io_uring_enter**(2)**.**
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field. Some common error cases are:
+
+**-ENOMEM**
+
+: The **ulimit**(1) -l setting is too low to support the size of the attempted zero copy send. Increasing the limit may help
+
+**-ENOMEM**
+
+: The kernel ran out of memory.
+
+# NOTES
+
+Despite accepting a size_t number of bytes, these functions can transfer at most INT_MAX bytes per call (the maximum for the underlying syscall interface).
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_prep_send**(3), **io_uring_enter**(2), **send**(2)
diff --git a/man/io_uring_prep_send_zc_fixed.3 b/man/io_uring_prep_send_zc_fixed.3
deleted file mode 120000
index c66c84d6..00000000
--- a/man/io_uring_prep_send_zc_fixed.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_send_zc.3
\ No newline at end of file
diff --git a/man/io_uring_prep_sendmsg.3 b/man/io_uring_prep_sendmsg.3
deleted file mode 100644
index 7bb7a534..00000000
--- a/man/io_uring_prep_sendmsg.3
+++ /dev/null
@@ -1,136 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_sendmsg 3 "March 12, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_sendmsg \- prepare a sendmsg request
-.SH SYNOPSIS
-.nf
-.B #include <sys/types.h>
-.B #include <sys/socket.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_sendmsg(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " const struct msghdr *" msg ","
-.BI " unsigned " flags ");"
-.PP
-.BI "void io_uring_prep_sendmsg_zc(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " const struct msghdr *" msg ","
-.BI " unsigned " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_sendmsg (3)
-function prepares a sendmsg request. The submission queue entry
-.I sqe
-is setup to use the file descriptor
-.I fd
-to start sending the data indicated by
-.I msg
-with the
-.BR sendmsg (2)
-defined flags in the
-.I flags
-argument.
-
-The
-.BR io_uring_prep_sendmsg_zc (3)
-accepts the same parameters as
-.BR io_uring_prep_sendmsg (3)
-but prepares a zerocopy sendmsg request.
-
-See
-.BR io_uring_prep_send (3)
-for a description of flags that can be set in the SQE
-.I ioprio
-field. In addition to those, the zero-copy send also supports setting
-.B IORING_SEND_ZC_REPORT_USAGE .
-If set, the notification CQE
-.I res
-field will report the number of bytes that were copied rather than sent with
-zero copy. A value of
-.B 0
-indicates success. If the value is
-.B IORING_NOTIF_USAGE_ZC_COPIED ,
-then data was copied.
-
-As opposed to non-zerocopy send requests, a zerocopy send will usually
-generate two CQEs. The first CQE holds the result of the send operation itself,
-and if that CQE has
-.B IORING_CQE_F_MORE
-set in the CQE
-.I flags
-field, then a second notification CQE will be posted for the operation. This
-second notification tells the application that the memory associated with the
-send is safe to get reused. The second CQE will have
-.B IORING_CQE_F_NOTIF
-set in the CQE
-.I flags
-field. Also see the
-.BR io_uring_enter (2)
-man page for a fuller description of the notification CQE.
-
-Note that using
-.B IOSQE_IO_LINK
-with this request type requires the setting of
-.B MSG_WAITALL
-in the
-.I flags
-argument, as a short send isn't considered an error condition without
-that being set.
-
-This function prepares an async
-.BR sendmsg (2)
-request. See that man page for details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field. Some common error cases are:
-.TP
-.B -ENOMEM
-The
-.BR ulimit (1)
--l setting is too low to support the size of the attempted zero copy send.
-Increasing the limit may help
-.TP
-.B -ENOMEM
-The kernel ran out of memory.
-.P
-.SH NOTES
-As with any request that passes in data in a struct, that data must remain
-valid until the request has been successfully submitted. It need not remain
-valid until completion. Once a request has been submitted, the in-kernel
-state is stable. Very early kernels (5.4 and earlier) required state to be
-stable until the completion occurred. Applications can test for this
-behavior by inspecting the
-.B IORING_FEAT_SUBMIT_STABLE
-flag passed back from
-.BR io_uring_queue_init_params (3).
-
-Despite accepting an array of iovec's with a size_t number of bytes each,
-these functions can transfer at most INT_MAX bytes per call (the maximum
-for the underlying syscall interface).
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_buf_ring_init (3),
-.BR io_uring_buf_ring_add (3),
-.BR sendmsg (2)
diff --git a/man/io_uring_prep_sendmsg.3.md b/man/io_uring_prep_sendmsg.3.md
new file mode 100644
index 00000000..cfbb11e6
--- /dev/null
+++ b/man/io_uring_prep_sendmsg.3.md
@@ -0,0 +1,71 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 12, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_sendmsg
+---
+
+# NAME
+
+io_uring_prep_sendmsg - prepare a sendmsg request
+
+# SYNOPSIS
+
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <liburing.h>
+
+ void io_uring_prep_sendmsg(struct io_uring_sqe * sqe ,
+ int fd ,
+ const struct msghdr * msg ,
+ unsigned flags );
+
+ void io_uring_prep_sendmsg_zc(struct io_uring_sqe * sqe ,
+ int fd ,
+ const struct msghdr * msg ,
+ unsigned flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_sendmsg**(3) function prepares a sendmsg request. The submission queue entry *sqe* is setup to use the file descriptor *fd* to start sending the data indicated by *msg* with the **sendmsg**(2) defined flags in the *flags* argument.
+
+The **io_uring_prep_sendmsg_zc**(3) accepts the same parameters as **io_uring_prep_sendmsg**(3) but prepares a zerocopy sendmsg request.
+
+See **io_uring_prep_send**(3) for a description of flags that can be set in the SQE *ioprio* field. In addition to those, the zero-copy send also supports setting **IORING_SEND_ZC_REPORT_USAGE .** If set, the notification CQE *res* field will report the number of bytes that were copied rather than sent with zero copy. A value of **0** indicates success. If the value is **IORING_NOTIF_USAGE_ZC_COPIED ,** then data was copied.
+
+As opposed to non-zerocopy send requests, a zerocopy send will usually generate two CQEs. The first CQE holds the result of the send operation itself, and if that CQE has **IORING_CQE_F_MORE** set in the CQE *flags* field, then a second notification CQE will be posted for the operation. This second notification tells the application that the memory associated with the send is safe to get reused. The second CQE will have **IORING_CQE_F_NOTIF** set in the CQE *flags* field. Also see the **io_uring_enter**(2) man page for a fuller description of the notification CQE.
+
+Note that using **IOSQE_IO_LINK** with this request type requires the setting of **MSG_WAITALL** in the *flags* argument, as a short send isn\'t considered an error condition without that being set.
+
+This function prepares an async **sendmsg**(2) request. See that man page for details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field. Some common error cases are:
+
+**-ENOMEM**
+
+: The **ulimit**(1) -l setting is too low to support the size of the attempted zero copy send. Increasing the limit may help
+
+**-ENOMEM**
+
+: The kernel ran out of memory.
+
+# NOTES
+
+As with any request that passes in data in a struct, that data must remain valid until the request has been successfully submitted. It need not remain valid until completion. Once a request has been submitted, the in-kernel state is stable. Very early kernels (5.4 and earlier) required state to be stable until the completion occurred. Applications can test for this behavior by inspecting the **IORING_FEAT_SUBMIT_STABLE** flag passed back from **io_uring_queue_init_params**(3).
+
+Despite accepting an array of iovec\'s with a size_t number of bytes each, these functions can transfer at most INT_MAX bytes per call (the maximum for the underlying syscall interface).
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_buf_ring_init**(3), **io_uring_buf_ring_add**(3), **sendmsg**(2)
diff --git a/man/io_uring_prep_sendmsg_zc.3 b/man/io_uring_prep_sendmsg_zc.3
deleted file mode 120000
index 47599fb0..00000000
--- a/man/io_uring_prep_sendmsg_zc.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_sendmsg.3
\ No newline at end of file
diff --git a/man/io_uring_prep_sendmsg_zc_fixed.3 b/man/io_uring_prep_sendmsg_zc_fixed.3
deleted file mode 100644
index f8baa12b..00000000
--- a/man/io_uring_prep_sendmsg_zc_fixed.3
+++ /dev/null
@@ -1,69 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_sendmsg_zc_fixed 3 "January 18, 2025" "liburing-2.10" "liburing Manual"
-.SH NAME
-io_uring_prep_sendmsg_zc_fixed \- prepare a zero-copy sendmsg using fixed buffers
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_sendmsg_zc_fixed(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " const struct msghdr *" msg ","
-.BI " unsigned " flags ","
-.BI " unsigned " buf_index ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_sendmsg_zc_fixed (3)
-function prepares a zero-copy sendmsg request using fixed (registered)
-buffers. The submission queue entry
-.I sqe
-is setup to send data on the socket indicated by the file descriptor
-.I fd
-using the message structure
-.IR msg .
-
-The
-.I flags
-argument contains flags for the sendmsg operation, as described in
-.BR sendmsg (2).
-
-The
-.I buf_index
-specifies the index of the registered buffer set to use. The buffers in
-.I msg
-must be part of the registered buffer set previously registered with
-.BR io_uring_register_buffers (3).
-
-Zero-copy sends avoid copying data from user to kernel space, improving
-performance for large transfers. Using fixed buffers additionally avoids
-the overhead of mapping buffers for each I/O operation.
-
-Note that zero-copy sends require the application to wait for a notification
-before reusing the buffer. See
-.BR io_uring_prep_send_zc (3)
-for more details on zero-copy semantics.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation, the number of bytes sent
-on success. On error, a negative errno value is returned.
-
-Despite accepting an array of iovec's with a size_t number of bytes each,
-this function can transfer at most INT_MAX bytes per call (the maximum
-for the underlying syscall interface).
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_prep_sendmsg_zc (3),
-.BR io_uring_prep_sendmsg (3),
-.BR io_uring_prep_send_zc_fixed (3),
-.BR io_uring_register_buffers (3),
-.BR sendmsg (2)
diff --git a/man/io_uring_prep_sendmsg_zc_fixed.3.md b/man/io_uring_prep_sendmsg_zc_fixed.3.md
new file mode 100644
index 00000000..fd0028b0
--- /dev/null
+++ b/man/io_uring_prep_sendmsg_zc_fixed.3.md
@@ -0,0 +1,51 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: liburing-2.10
+header: liburing Manual
+section: 3
+title: io_uring_prep_sendmsg_zc_fixed
+---
+
+# NAME
+
+io_uring_prep_sendmsg_zc_fixed - prepare a zero-copy sendmsg using fixed buffers
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_sendmsg_zc_fixed(struct io_uring_sqe * sqe ,
+ int fd ,
+ const struct msghdr * msg ,
+ unsigned flags ,
+ unsigned buf_index );
+
+# DESCRIPTION
+
+The **io_uring_prep_sendmsg_zc_fixed**(3) function prepares a zero-copy sendmsg request using fixed (registered) buffers. The submission queue entry *sqe* is setup to send data on the socket indicated by the file descriptor *fd* using the message structure *msg*.
+
+The *flags* argument contains flags for the sendmsg operation, as described in **sendmsg**(2).
+
+The *buf_index* specifies the index of the registered buffer set to use. The buffers in *msg* must be part of the registered buffer set previously registered with **io_uring_register_buffers**(3).
+
+Zero-copy sends avoid copying data from user to kernel space, improving performance for large transfers. Using fixed buffers additionally avoids the overhead of mapping buffers for each I/O operation.
+
+Note that zero-copy sends require the application to wait for a notification before reusing the buffer. See **io_uring_prep_send_zc**(3) for more details on zero-copy semantics.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation, the number of bytes sent on success. On error, a negative errno value is returned.
+
+Despite accepting an array of iovec\'s with a size_t number of bytes each, this function can transfer at most INT_MAX bytes per call (the maximum for the underlying syscall interface).
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_prep_sendmsg_zc**(3), **io_uring_prep_sendmsg**(3), **io_uring_prep_send_zc_fixed**(3), **io_uring_register_buffers**(3), **sendmsg**(2)
diff --git a/man/io_uring_prep_sendto.3 b/man/io_uring_prep_sendto.3
deleted file mode 120000
index ba85e684..00000000
--- a/man/io_uring_prep_sendto.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_send.3
\ No newline at end of file
diff --git a/man/io_uring_prep_setxattr.3 b/man/io_uring_prep_setxattr.3
deleted file mode 100644
index 5ccff752..00000000
--- a/man/io_uring_prep_setxattr.3
+++ /dev/null
@@ -1,64 +0,0 @@
-.\" Copyright (C) 2023 Rutvik Patel <heyrutvik@gmail.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_setxattr 3 "January 23, 2023" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_prep_setxattr, io_uring_prep_fsetxattr \- prepare a request to set an
-extended attribute value
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_setxattr(struct io_uring_sqe *" sqe ","
-.BI " const char *" name ","
-.BI " const char *" value ","
-.BI " const char *" path ","
-.BI " int " flags ","
-.BI " unsigned int " len ");"
-.PP
-.BI "void io_uring_prep_fsetxattr(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " const char *" name ","
-.BI " const char *" value ","
-.BI " int " flags ","
-.BI " unsigned int " len ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_setxattr (3)
-function prepares a request to set an extended attribute value. The submission
-queue entry
-.I sqe
-is setup to set the
-.I value
-of the extended attribute identified by
-.I name
-and associated with the given
-.I path
-in the filesystem with modifier flags
-.IR flags .
-The
-.I len
-argument specifies the size (in bytes) of
-.IR value .
-
-.BR io_uring_prep_fsetxattr (3)
-is identical to
-.BR io_uring_prep_setxattr (3),
-only the extended attribute is set on the open file referred to by
-.I fd
-in place of
-.IR path .
-
-This function prepares an async
-.BR setxattr (2)
-request. See that man page for details.
-
-.SH RETURN VALUE
-None
-
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR setxattr (2)
diff --git a/man/io_uring_prep_setxattr.3.md b/man/io_uring_prep_setxattr.3.md
new file mode 100644
index 00000000..1bdd4e77
--- /dev/null
+++ b/man/io_uring_prep_setxattr.3.md
@@ -0,0 +1,49 @@
+.\" Copyright (C) 2023 Rutvik Patel <heyrutvik@gmail.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 23, 2023
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_prep_setxattr
+---
+
+# NAME
+
+io_uring_prep_setxattr, io_uring_prep_fsetxattr - prepare a request to set an extended attribute value
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_setxattr(struct io_uring_sqe * sqe ,
+ const char * name ,
+ const char * value ,
+ const char * path ,
+ int flags ,
+ unsigned int len );
+
+ void io_uring_prep_fsetxattr(struct io_uring_sqe * sqe ,
+ int fd ,
+ const char * name ,
+ const char * value ,
+ int flags ,
+ unsigned int len );
+
+# DESCRIPTION
+
+The **io_uring_prep_setxattr**(3) function prepares a request to set an extended attribute value. The submission queue entry *sqe* is setup to set the *value* of the extended attribute identified by *name* and associated with the given *path* in the filesystem with modifier flags *flags*. The *len* argument specifies the size (in bytes) of *value*.
+
+**io_uring_prep_fsetxattr**(3) is identical to **io_uring_prep_setxattr**(3), only the extended attribute is set on the open file referred to by *fd* in place of *path*.
+
+This function prepares an async **setxattr**(2) request. See that man page for details.
+
+# RETURN VALUE
+
+None
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **setxattr**(2)
diff --git a/man/io_uring_prep_shutdown.3 b/man/io_uring_prep_shutdown.3
deleted file mode 100644
index 9125e95f..00000000
--- a/man/io_uring_prep_shutdown.3
+++ /dev/null
@@ -1,53 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_shutdown 3 "March 12, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_shutdown \- prepare a shutdown request
-.SH SYNOPSIS
-.nf
-.B #include <sys/socket.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_shutdown(struct io_uring_sqe *" sqe ","
-.BI " int " sockfd ","
-.BI " int " how ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_shutdown (3)
-function prepares a shutdown request. The submission queue entry
-.I sqe
-is setup to use the file descriptor
-.I sockfd
-that should be shutdown with the
-.I how
-argument.
-
-This function prepares an async
-.BR shutdown (2)
-request. See that man page for details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR shutdown (2)
diff --git a/man/io_uring_prep_shutdown.3.md b/man/io_uring_prep_shutdown.3.md
new file mode 100644
index 00000000..092cdfbe
--- /dev/null
+++ b/man/io_uring_prep_shutdown.3.md
@@ -0,0 +1,42 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 12, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_shutdown
+---
+
+# NAME
+
+io_uring_prep_shutdown - prepare a shutdown request
+
+# SYNOPSIS
+
+ #include <sys/socket.h>
+ #include <liburing.h>
+
+ void io_uring_prep_shutdown(struct io_uring_sqe * sqe ,
+ int sockfd ,
+ int how );
+
+# DESCRIPTION
+
+The **io_uring_prep_shutdown**(3) function prepares a shutdown request. The submission queue entry *sqe* is setup to use the file descriptor *sockfd* that should be shutdown with the *how* argument.
+
+This function prepares an async **shutdown**(2) request. See that man page for details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **shutdown**(2)
diff --git a/man/io_uring_prep_socket.3 b/man/io_uring_prep_socket.3
deleted file mode 100644
index 77dba66b..00000000
--- a/man/io_uring_prep_socket.3
+++ /dev/null
@@ -1,118 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_socket 3 "May 27, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_socket \- prepare a socket creation request
-.SH SYNOPSIS
-.nf
-.B #include <sys/socket.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_socket(struct io_uring_sqe *" sqe ","
-.BI " int " domain ","
-.BI " int " type ","
-.BI " int " protocol ","
-.BI " unsigned int " flags ");"
-.PP
-.BI "void io_uring_prep_socket_direct(struct io_uring_sqe *" sqe ","
-.BI " int " domain ","
-.BI " int " type ","
-.BI " int " protocol ","
-.BI " unsigned int " file_index ","
-.BI " unsigned int " flags ");"
-.PP
-.BI "void io_uring_prep_socket_direct_alloc(struct io_uring_sqe *" sqe ","
-.BI " int " domain ","
-.BI " int " type ","
-.BI " int " protocol ","
-.BI " unsigned int " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_socket (3)
-function prepares a socket creation request. The submission queue entry
-.I sqe
-is setup to use the communication domain defined by
-.I domain
-and use the communication type defined by
-.I type
-and the protocol set by
-.IR protocol .
-The
-.I flags
-argument are currently unused.
-
-The
-.BR io_uring_prep_socket_direct (3)
-helper works just like
-.BR io_uring_prep_socket (3),
-except it maps the socket to a direct descriptor rather than return a normal
-file descriptor. The
-.I file_index
-argument should be set to the slot that should be used for this socket.
-
-The
-.BR io_uring_prep_socket_direct_alloc (3)
-helper works just like
-.BR io_uring_prep_socket_direct (3),
-except it allocates a new direct descriptor rather than pass a free slot in. It
-is equivalent to using
-.BR io_uring_prep_socket_direct (3)
-with
-.B IORING_FILE_INDEX_ALLOC
-as the
-.I
-file_index .
-Upon completion, the
-.I res
-field of the CQE will return the direct slot that was allocated for the
-socket.
-
-If the direct variants are used, the application must first have registered
-a file table using
-.BR io_uring_register_files (3)
-of the appropriate size. Once registered, a direct socket request may use any
-entry in that table, as long as it is within the size of the registered table.
-If a specified entry already contains a file, the file will first be removed
-from the table and closed. It's consistent with the behavior of updating an
-existing file with
-.BR io_uring_register_files_update (3).
-
-For a direct descriptor socket request, the
-.I file_index
-argument can be set to
-.BR IORING_FILE_INDEX_ALLOC ,
-In this case a free entry in io_uring file table will
-be used automatically and the file index will be returned as CQE
-.IR res .
-.B -ENFILE
-is otherwise returned if there is no free entries in the io_uring file table.
-
-These functions prepare an async
-.BR socket (2)
-request. See that man page for details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR socket (2)
diff --git a/man/io_uring_prep_socket.3.md b/man/io_uring_prep_socket.3.md
new file mode 100644
index 00000000..fafd0991
--- /dev/null
+++ b/man/io_uring_prep_socket.3.md
@@ -0,0 +1,65 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: May 27, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_socket
+---
+
+# NAME
+
+io_uring_prep_socket - prepare a socket creation request
+
+# SYNOPSIS
+
+ #include <sys/socket.h>
+ #include <liburing.h>
+
+ void io_uring_prep_socket(struct io_uring_sqe * sqe ,
+ int domain ,
+ int type ,
+ int protocol ,
+ unsigned int flags );
+
+ void io_uring_prep_socket_direct(struct io_uring_sqe * sqe ,
+ int domain ,
+ int type ,
+ int protocol ,
+ unsigned int file_index ,
+ unsigned int flags );
+
+ void io_uring_prep_socket_direct_alloc(struct io_uring_sqe * sqe ,
+ int domain ,
+ int type ,
+ int protocol ,
+ unsigned int flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_socket**(3) function prepares a socket creation request. The submission queue entry *sqe* is setup to use the communication domain defined by *domain* and use the communication type defined by *type* and the protocol set by *protocol*. The *flags* argument are currently unused.
+
+The **io_uring_prep_socket_direct**(3) helper works just like **io_uring_prep_socket**(3), except it maps the socket to a direct descriptor rather than return a normal file descriptor. The *file_index* argument should be set to the slot that should be used for this socket.
+
+The **io_uring_prep_socket_direct_alloc**(3) helper works just like **io_uring_prep_socket_direct**(3), except it allocates a new direct descriptor rather than pass a free slot in. It is equivalent to using **io_uring_prep_socket_direct**(3) with **IORING_FILE_INDEX_ALLOC** as the *file_index .* Upon completion, the *res* field of the CQE will return the direct slot that was allocated for the socket.
+
+If the direct variants are used, the application must first have registered a file table using **io_uring_register_files**(3) of the appropriate size. Once registered, a direct socket request may use any entry in that table, as long as it is within the size of the registered table. If a specified entry already contains a file, the file will first be removed from the table and closed. It\'s consistent with the behavior of updating an existing file with **io_uring_register_files_update**(3).
+
+For a direct descriptor socket request, the *file_index* argument can be set to **IORING_FILE_INDEX_ALLOC**, In this case a free entry in io_uring file table will be used automatically and the file index will be returned as CQE *res*. **-ENFILE** is otherwise returned if there is no free entries in the io_uring file table.
+
+These functions prepare an async **socket**(2) request. See that man page for details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **socket**(2)
diff --git a/man/io_uring_prep_socket_direct.3 b/man/io_uring_prep_socket_direct.3
deleted file mode 120000
index 15d7b7f0..00000000
--- a/man/io_uring_prep_socket_direct.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_socket.3
\ No newline at end of file
diff --git a/man/io_uring_prep_socket_direct_alloc.3 b/man/io_uring_prep_socket_direct_alloc.3
deleted file mode 120000
index 15d7b7f0..00000000
--- a/man/io_uring_prep_socket_direct_alloc.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_socket.3
\ No newline at end of file
diff --git a/man/io_uring_prep_splice.3 b/man/io_uring_prep_splice.3
deleted file mode 100644
index b600249f..00000000
--- a/man/io_uring_prep_splice.3
+++ /dev/null
@@ -1,126 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_splice 3 "March 13, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_splice \- prepare an splice request
-.SH SYNOPSIS
-.nf
-.B #include <fcntl.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_splice(struct io_uring_sqe *" sqe ","
-.BI " int " fd_in ","
-.BI " int64_t " off_in ","
-.BI " int " fd_out ","
-.BI " int64_t " off_out ","
-.BI " unsigned int " nbytes ","
-.BI " unsigned int " splice_flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_splice (3)
-function prepares a splice request. The submission queue entry
-.I sqe
-is setup to use as input the file descriptor
-.I fd_in
-at offset
-.IR off_in ,
-splicing data to the file descriptor at
-.I fd_out
-and at offset
-.IR off_out .
-.I nbytes
-bytes of data should be spliced between the two descriptors.
-.I splice_flags
-are modifier flags for the operation. See
-.BR splice (2)
-for the generic splice flags.
-
-If
-.I fd_out
-is a direct descriptor,
-.B IOSQE_FIXED_FILE
-can be set in the SQE to indicate that. For the input file, the io_uring
-specific
-.B SPLICE_F_FD_IN_FIXED
-can be set in
-.I splice_flags
-and
-.I fd_in
-given as a registered file descriptor offset.
-
-If
-.I fd_in
-refers to a pipe,
-.I off_in
-is ignored and must be set to -1.
-
-If
-.I fd_in
-does not refer to a pipe and
-.I off_in
-is -1, then
-.I nbytes
-are read from
-.I fd_in
-starting from the file offset, which is incremented by the number of bytes read.
-
-If
-.I fd_in
-does not refer to a pipe and
-.I off_in
-is not -1, then the starting offset of
-.I fd_in
-will be
-.IR off_in .
-
-The same rules apply to
-.I fd_out
-and
-.IR off_out .
-
-This function prepares an async
-.BR splice (2)
-request. See that man page for details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_register (2),
-.BR splice (2)
-
-.SH NOTES
-Note that even if
-.I fd_in
-or
-.I fd_out
-refers to a pipe, the splice operation can still fail with
-.B EINVAL
-if one of the fd doesn't explicitly support splice operation, e.g. reading from
-terminal is unsupported from kernel 5.7 to 5.11.
-
-Despite accepting an unsigned number of bytes, this function can transfer at most
-INT_MAX bytes per call (the maximum for the underlying syscall interface).
-In practice, limits as low as 65536 have been observed (just like with
-.BR splice (2)
-itself).
diff --git a/man/io_uring_prep_splice.3.md b/man/io_uring_prep_splice.3.md
new file mode 100644
index 00000000..92e96cbc
--- /dev/null
+++ b/man/io_uring_prep_splice.3.md
@@ -0,0 +1,62 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 13, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_splice
+---
+
+# NAME
+
+io_uring_prep_splice - prepare an splice request
+
+# SYNOPSIS
+
+ #include <fcntl.h>
+ #include <liburing.h>
+
+ void io_uring_prep_splice(struct io_uring_sqe * sqe ,
+ int fd_in ,
+ int64_t off_in ,
+ int fd_out ,
+ int64_t off_out ,
+ unsigned int nbytes ,
+ unsigned int splice_flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_splice**(3) function prepares a splice request. The submission queue entry *sqe* is setup to use as input the file descriptor *fd_in* at offset *off_in*, splicing data to the file descriptor at *fd_out* and at offset *off_out*. *nbytes* bytes of data should be spliced between the two descriptors. *splice_flags* are modifier flags for the operation. See **splice**(2) for the generic splice flags.
+
+If *fd_out* is a direct descriptor, **IOSQE_FIXED_FILE** can be set in the SQE to indicate that. For the input file, the io_uring specific **SPLICE_F_FD_IN_FIXED** can be set in *splice_flags* and *fd_in* given as a registered file descriptor offset.
+
+If *fd_in* refers to a pipe, *off_in* is ignored and must be set to -1.
+
+If *fd_in* does not refer to a pipe and *off_in* is -1, then *nbytes* are read from *fd_in* starting from the file offset, which is incremented by the number of bytes read.
+
+If *fd_in* does not refer to a pipe and *off_in* is not -1, then the starting offset of *fd_in* will be *off_in*.
+
+The same rules apply to *fd_out* and *off_out*.
+
+This function prepares an async **splice**(2) request. See that man page for details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_register**(2), **splice**(2)
+
+# NOTES
+
+Note that even if *fd_in* or *fd_out* refers to a pipe, the splice operation can still fail with **EINVAL** if one of the fd doesn\'t explicitly support splice operation, e.g. reading from terminal is unsupported from kernel 5.7 to 5.11.
+
+Despite accepting an unsigned number of bytes, this function can transfer at most INT_MAX bytes per call (the maximum for the underlying syscall interface). In practice, limits as low as 65536 have been observed (just like with **splice**(2) itself).
diff --git a/man/io_uring_prep_statx.3 b/man/io_uring_prep_statx.3
deleted file mode 100644
index d9d983a0..00000000
--- a/man/io_uring_prep_statx.3
+++ /dev/null
@@ -1,74 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_statx 3 "March 13, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_statx \- prepare a statx request
-.SH SYNOPSIS
-.nf
-.B #include <sys/types.h>
-.B #include <sys/stat.h>
-.B #include <unistd.h>
-.B #include <fcntl.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_statx(struct io_uring_sqe *" sqe ","
-.BI " int " dirfd ","
-.BI " const char *" path ","
-.BI " int " flags ","
-.BI " unsigned " mask ","
-.BI " struct statx *" statxbuf ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_statx (3)
-function prepares a statx request. The submission queue entry
-.I sqe
-is setup to use the directory file descriptor pointed to by
-.I dirfd
-to start a statx operation on the path identified by
-.I path
-and using the flags given in
-.I flags
-for the fields specified by
-.I mask
-and into the buffer located at
-.IR statxbuf .
-
-This function prepares an async
-.BR statx (2)
-request. See that man page for details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-As with any request that passes in data in a struct, that data must remain
-valid until the request has been successfully submitted. It need not remain
-valid until completion. Once a request has been submitted, the in-kernel
-state is stable. Very early kernels (5.4 and earlier) required state to be
-stable until the completion occurred. Applications can test for this
-behavior by inspecting the
-.B IORING_FEAT_SUBMIT_STABLE
-flag passed back from
-.BR io_uring_queue_init_params (3).
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR statx (2)
diff --git a/man/io_uring_prep_statx.3.md b/man/io_uring_prep_statx.3.md
new file mode 100644
index 00000000..6153cd17
--- /dev/null
+++ b/man/io_uring_prep_statx.3.md
@@ -0,0 +1,52 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 13, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_statx
+---
+
+# NAME
+
+io_uring_prep_statx - prepare a statx request
+
+# SYNOPSIS
+
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <liburing.h>
+
+ void io_uring_prep_statx(struct io_uring_sqe * sqe ,
+ int dirfd ,
+ const char * path ,
+ int flags ,
+ unsigned mask ,
+ struct statx * statxbuf );
+
+# DESCRIPTION
+
+The **io_uring_prep_statx**(3) function prepares a statx request. The submission queue entry *sqe* is setup to use the directory file descriptor pointed to by *dirfd* to start a statx operation on the path identified by *path* and using the flags given in *flags* for the fields specified by *mask* and into the buffer located at *statxbuf*.
+
+This function prepares an async **statx**(2) request. See that man page for details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+As with any request that passes in data in a struct, that data must remain valid until the request has been successfully submitted. It need not remain valid until completion. Once a request has been submitted, the in-kernel state is stable. Very early kernels (5.4 and earlier) required state to be stable until the completion occurred. Applications can test for this behavior by inspecting the **IORING_FEAT_SUBMIT_STABLE** flag passed back from **io_uring_queue_init_params**(3).
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **statx**(2)
diff --git a/man/io_uring_prep_symlink.3 b/man/io_uring_prep_symlink.3
deleted file mode 120000
index ae6f41a2..00000000
--- a/man/io_uring_prep_symlink.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_symlinkat.3
\ No newline at end of file
diff --git a/man/io_uring_prep_symlinkat.3 b/man/io_uring_prep_symlinkat.3
deleted file mode 100644
index b809f938..00000000
--- a/man/io_uring_prep_symlinkat.3
+++ /dev/null
@@ -1,85 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_symlinkat 3 "March 13, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_symlinkat \- prepare a symlinkat request
-.SH SYNOPSIS
-.nf
-.B #include <fcntl.h>
-.B #include <unistd.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_symlinkat(struct io_uring_sqe *" sqe ","
-.BI " const char *" target ","
-.BI " int " newdirfd ","
-.BI " const char *" linkpath ");"
-.PP
-.BI "void io_uring_prep_symlink(struct io_uring_sqe *" sqe ","
-.BI " const char *" target ","
-.BI " const char *" linkpath ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_symlinkat (3)
-function prepares a symlinkat request. The submission queue entry
-.I sqe
-is setup to symlink the target path pointed to by
-.I target
-to the new destination indicated by
-.I newdirfd
-and
-.IR linkpath .
-
-The
-.BR io_uring_prep_symlink (3)
-function prepares a symlink request. The submission queue entry
-.I sqe
-is setup to symlink the target path pointed to by
-.I target
-to the new destination indicated by
-.I linkpath
-relative to the current working directory. This function prepares an async
-.BR symlink (2)
-request. See that man page for details.
-
-These functions prepare an async
-.BR symlinkat (2)
-or
-.BR symlink (2)
-request. See those man pages for details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-As with any request that passes in data in a struct, that data must remain
-valid until the request has been successfully submitted. It need not remain
-valid until completion. Once a request has been submitted, the in-kernel
-state is stable. Very early kernels (5.4 and earlier) required state to be
-stable until the completion occurred. Applications can test for this
-behavior by inspecting the
-.B IORING_FEAT_SUBMIT_STABLE
-flag passed back from
-.BR io_uring_queue_init_params (3).
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR symlinkat (2),
-.BR symlink (2)
diff --git a/man/io_uring_prep_symlinkat.3.md b/man/io_uring_prep_symlinkat.3.md
new file mode 100644
index 00000000..4a7437d2
--- /dev/null
+++ b/man/io_uring_prep_symlinkat.3.md
@@ -0,0 +1,54 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 13, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_symlinkat
+---
+
+# NAME
+
+io_uring_prep_symlinkat - prepare a symlinkat request
+
+# SYNOPSIS
+
+ #include <fcntl.h>
+ #include <unistd.h>
+ #include <liburing.h>
+
+ void io_uring_prep_symlinkat(struct io_uring_sqe * sqe ,
+ const char * target ,
+ int newdirfd ,
+ const char * linkpath );
+
+ void io_uring_prep_symlink(struct io_uring_sqe * sqe ,
+ const char * target ,
+ const char * linkpath );
+
+# DESCRIPTION
+
+The **io_uring_prep_symlinkat**(3) function prepares a symlinkat request. The submission queue entry *sqe* is setup to symlink the target path pointed to by *target* to the new destination indicated by *newdirfd* and *linkpath*.
+
+The **io_uring_prep_symlink**(3) function prepares a symlink request. The submission queue entry *sqe* is setup to symlink the target path pointed to by *target* to the new destination indicated by *linkpath* relative to the current working directory. This function prepares an async **symlink**(2) request. See that man page for details.
+
+These functions prepare an async **symlinkat**(2) or **symlink**(2) request. See those man pages for details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+As with any request that passes in data in a struct, that data must remain valid until the request has been successfully submitted. It need not remain valid until completion. Once a request has been submitted, the in-kernel state is stable. Very early kernels (5.4 and earlier) required state to be stable until the completion occurred. Applications can test for this behavior by inspecting the **IORING_FEAT_SUBMIT_STABLE** flag passed back from **io_uring_queue_init_params**(3).
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **symlinkat**(2), **symlink**(2)
diff --git a/man/io_uring_prep_sync_file_range.3 b/man/io_uring_prep_sync_file_range.3
deleted file mode 100644
index 830e4115..00000000
--- a/man/io_uring_prep_sync_file_range.3
+++ /dev/null
@@ -1,59 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_sync_file_range 3 "March 12, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_sync_file_range \- prepare a sync_file_range request
-.SH SYNOPSIS
-.nf
-.B #include <fcntl.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_sync_file_range(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " unsigned " len ","
-.BI " __u64 " offset ","
-.BI " int " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_sync_file_range (3)
-function prepares a sync_file_range request. The submission queue entry
-.I sqe
-is setup to use the file descriptor
-.I fd
-that should get
-.I len
-bytes synced started at offset
-.I offset
-and with modifier flags in the
-.I flags
-argument.
-
-This function prepares an async
-.BR sync_file_range (2)
-request. See that man page for details on the arguments.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR sync_file_range (2)
diff --git a/man/io_uring_prep_sync_file_range.3.md b/man/io_uring_prep_sync_file_range.3.md
new file mode 100644
index 00000000..24a33959
--- /dev/null
+++ b/man/io_uring_prep_sync_file_range.3.md
@@ -0,0 +1,44 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 12, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_sync_file_range
+---
+
+# NAME
+
+io_uring_prep_sync_file_range - prepare a sync_file_range request
+
+# SYNOPSIS
+
+ #include <fcntl.h>
+ #include <liburing.h>
+
+ void io_uring_prep_sync_file_range(struct io_uring_sqe * sqe ,
+ int fd ,
+ unsigned len ,
+ __u64 offset ,
+ int flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_sync_file_range**(3) function prepares a sync_file_range request. The submission queue entry *sqe* is setup to use the file descriptor *fd* that should get *len* bytes synced started at offset *offset* and with modifier flags in the *flags* argument.
+
+This function prepares an async **sync_file_range**(2) request. See that man page for details on the arguments.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **sync_file_range**(2)
diff --git a/man/io_uring_prep_tee.3 b/man/io_uring_prep_tee.3
deleted file mode 100644
index 10b57737..00000000
--- a/man/io_uring_prep_tee.3
+++ /dev/null
@@ -1,80 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_tee 3 "March 13, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_tee \- prepare a tee request
-.SH SYNOPSIS
-.nf
-.B #include <fcntl.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_tee(struct io_uring_sqe *" sqe ","
-.BI " int " fd_in ","
-.BI " int " fd_out ","
-.BI " unsigned int " nbytes ","
-.BI " unsigned int " splice_flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_tee (3)
-function prepares a tee request. The submission queue entry
-.I sqe
-is setup to use as input the file descriptor
-.I fd_in
-and as output the file descriptor
-.I fd_out
-duplicating up to
-.I nbytes
-bytes worth of data.
-.I splice_flags
-are modifier flags for the operation. See
-.BR tee (2)
-for the generic splice flags.
-
-If
-.I fd_out
-is a direct descriptor,
-.B IOSQE_FIXED_FILE
-can be set in the SQE to indicate that. For the input file, the io_uring
-specific
-.B SPLICE_F_FD_IN_FIXED
-can be set and
-.I fd_in
-given as a registered file descriptor offset.
-
-This function prepares an async
-.BR tee (2)
-request. See that man page for details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-Despite accepting an unsigned number of bytes, this function can transfer at most
-INT_MAX bytes per call (the maximum for the underlying syscall interface).
-In practice, limits as low as 65536 have been observed (just like with
-.BR tee (2)
-itself).
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_register (2),
-.BR splice (2),
-.BR tee (2)
diff --git a/man/io_uring_prep_tee.3.md b/man/io_uring_prep_tee.3.md
new file mode 100644
index 00000000..31f8bad6
--- /dev/null
+++ b/man/io_uring_prep_tee.3.md
@@ -0,0 +1,50 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 13, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_tee
+---
+
+# NAME
+
+io_uring_prep_tee - prepare a tee request
+
+# SYNOPSIS
+
+ #include <fcntl.h>
+ #include <liburing.h>
+
+ void io_uring_prep_tee(struct io_uring_sqe * sqe ,
+ int fd_in ,
+ int fd_out ,
+ unsigned int nbytes ,
+ unsigned int splice_flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_tee**(3) function prepares a tee request. The submission queue entry *sqe* is setup to use as input the file descriptor *fd_in* and as output the file descriptor *fd_out* duplicating up to *nbytes* bytes worth of data. *splice_flags* are modifier flags for the operation. See **tee**(2) for the generic splice flags.
+
+If *fd_out* is a direct descriptor, **IOSQE_FIXED_FILE** can be set in the SQE to indicate that. For the input file, the io_uring specific **SPLICE_F_FD_IN_FIXED** can be set and *fd_in* given as a registered file descriptor offset.
+
+This function prepares an async **tee**(2) request. See that man page for details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+Despite accepting an unsigned number of bytes, this function can transfer at most INT_MAX bytes per call (the maximum for the underlying syscall interface). In practice, limits as low as 65536 have been observed (just like with **tee**(2) itself).
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_register**(2), **splice**(2), **tee**(2)
diff --git a/man/io_uring_prep_timeout.3 b/man/io_uring_prep_timeout.3
deleted file mode 100644
index 0c4a44e7..00000000
--- a/man/io_uring_prep_timeout.3
+++ /dev/null
@@ -1,121 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_timeout 3 "March 12, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_timeout \- prepare a timeout request
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_timeout(struct io_uring_sqe *" sqe ","
-.BI " const struct __kernel_timespec *" ts ","
-.BI " unsigned " count ","
-.BI " unsigned " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_timeout (3)
-function prepares a timeout request. The submission queue entry
-.I sqe
-is setup to arm a timeout specified by
-.I ts
-and with a timeout count of
-.I count
-completion entries. The
-.I flags
-argument holds modifier flags for the request.
-
-This request type can be used as a timeout waking anyone sleeping
-for events on the CQ ring. The
-.I flags
-argument may contain:
-.TP
-.B IORING_TIMEOUT_ABS
-The value specified in
-.I ts
-is an absolute value rather than a relative one.
-.TP
-.B IORING_TIMEOUT_BOOTTIME
-The boottime clock source should be used.
-.TP
-.B IORING_TIMEOUT_REALTIME
-The realtime clock source should be used.
-.TP
-.B IORING_TIMEOUT_ETIME_SUCCESS
-Consider an expired timeout a success in terms of the posted completion. This
-means it will not sever dependent links, as a failed request normally would. The
-posted CQE result code will still contain
-.B -ETIME
-in the
-.I res
-value.
-.TP
-.B IORING_TIMEOUT_MULTISHOT
-The request will return multiple timeout completions. The completion flag
-IORING_CQE_F_MORE is set if more timeouts are expected. The value specified in
-.I count
-is the number of repeats. A value of 0 means the timeout is indefinite and can
-only be stopped by a removal request. Available since the 6.4 kernel.
-.TP
-.B IORING_TIMEOUT_IMMEDIATE_ARG
-The timeout value is stored directly in the SQE as a nanosecond value rather
-than as a pointer to a
-.B struct __kernel_timespec.
-When this flag is set, the
-.I ts
-argument to
-.BR io_uring_prep_timeout (3)
-is reinterpreted as a nanosecond value (cast to a
-.BR __u64 )
-rather than a pointer. This avoids the need to keep a timespec structure valid
-in user memory until the request is submitted.
-Available since the 7.1 kernel.
-.PP
-If no alternate clock source is given in the above flags, then
-.B CLOCK_MONOTONIC
-is used.
-
-The timeout completion event will trigger if either the specified timeout
-has occurred, or the specified number of events to wait for have been posted
-to the CQ ring.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-These are the errors that are reported in the CQE
-.I res
-field. On success,
-.B 0
-is returned.
-.TP
-.B -ETIME
-The specified timeout occurred and triggered the completion event.
-.TP
-.B -EINVAL
-One of the fields set in the SQE was invalid. For example, two clocksources
-were given, the specified timeout seconds or nanoseconds were < 0.
-.TP
-.B -EFAULT
-io_uring was unable to access the data specified by
-.IR ts .
-.TP
-.B -ECANCELED
-The timeout was canceled by a removal request.
-.SH NOTES
-As with any request that passes in data in a struct, that data must remain
-valid until the request has been successfully submitted. It need not remain
-valid until completion. Once a request has been submitted, the in-kernel
-state is stable. Very early kernels (5.4 and earlier) required state to be
-stable until the completion occurred. Applications can test for this
-behavior by inspecting the
-.B IORING_FEAT_SUBMIT_STABLE
-flag passed back from
-.BR io_uring_queue_init_params (3).
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_prep_timeout_remove (3),
-.BR io_uring_prep_timeout_update (3)
diff --git a/man/io_uring_prep_timeout.3.md b/man/io_uring_prep_timeout.3.md
new file mode 100644
index 00000000..64337bda
--- /dev/null
+++ b/man/io_uring_prep_timeout.3.md
@@ -0,0 +1,90 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 12, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_timeout
+---
+
+# NAME
+
+io_uring_prep_timeout - prepare a timeout request
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_timeout(struct io_uring_sqe * sqe ,
+ const struct __kernel_timespec * ts ,
+ unsigned count ,
+ unsigned flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_timeout**(3) function prepares a timeout request. The submission queue entry *sqe* is setup to arm a timeout specified by *ts* and with a timeout count of *count* completion entries. The *flags* argument holds modifier flags for the request.
+
+This request type can be used as a timeout waking anyone sleeping for events on the CQ ring. The *flags* argument may contain:
+
+**IORING_TIMEOUT_ABS**
+
+: The value specified in *ts* is an absolute value rather than a relative one.
+
+**IORING_TIMEOUT_BOOTTIME**
+
+: The boottime clock source should be used.
+
+**IORING_TIMEOUT_REALTIME**
+
+: The realtime clock source should be used.
+
+**IORING_TIMEOUT_ETIME_SUCCESS**
+
+: Consider an expired timeout a success in terms of the posted completion. This means it will not sever dependent links, as a failed request normally would. The posted CQE result code will still contain **-ETIME** in the *res* value.
+
+**IORING_TIMEOUT_MULTISHOT**
+
+: The request will return multiple timeout completions. The completion flag IORING_CQE_F_MORE is set if more timeouts are expected. The value specified in *count* is the number of repeats. A value of 0 means the timeout is indefinite and can only be stopped by a removal request. Available since the 6.4 kernel.
+
+**IORING_TIMEOUT_IMMEDIATE_ARG**
+
+: The timeout value is stored directly in the SQE as a nanosecond value rather than as a pointer to a **struct \_\_kernel_timespec.** When this flag is set, the *ts* argument to **io_uring_prep_timeout**(3) is reinterpreted as a nanosecond value (cast to a **\_\_u64**) rather than a pointer. This avoids the need to keep a timespec structure valid in user memory until the request is submitted. Available since the 7.1 kernel.
+
+If no alternate clock source is given in the above flags, then **CLOCK_MONOTONIC** is used.
+
+The timeout completion event will trigger if either the specified timeout has occurred, or the specified number of events to wait for have been posted to the CQ ring.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+These are the errors that are reported in the CQE *res* field. On success, **0** is returned.
+
+**-ETIME**
+
+: The specified timeout occurred and triggered the completion event.
+
+**-EINVAL**
+
+: One of the fields set in the SQE was invalid. For example, two clocksources were given, the specified timeout seconds or nanoseconds were \< 0.
+
+**-EFAULT**
+
+: io_uring was unable to access the data specified by *ts*.
+
+**-ECANCELED**
+
+: The timeout was canceled by a removal request.
+
+# NOTES
+
+As with any request that passes in data in a struct, that data must remain valid until the request has been successfully submitted. It need not remain valid until completion. Once a request has been submitted, the in-kernel state is stable. Very early kernels (5.4 and earlier) required state to be stable until the completion occurred. Applications can test for this behavior by inspecting the **IORING_FEAT_SUBMIT_STABLE** flag passed back from **io_uring_queue_init_params**(3).
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_prep_timeout_remove**(3), **io_uring_prep_timeout_update**(3)
diff --git a/man/io_uring_prep_timeout_remove.3 b/man/io_uring_prep_timeout_remove.3
deleted file mode 120000
index 5aebd368..00000000
--- a/man/io_uring_prep_timeout_remove.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_timeout_update.3
\ No newline at end of file
diff --git a/man/io_uring_prep_timeout_update.3 b/man/io_uring_prep_timeout_update.3
deleted file mode 100644
index ef4f8c75..00000000
--- a/man/io_uring_prep_timeout_update.3
+++ /dev/null
@@ -1,85 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_timeout_update 3 "March 12, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_timeout_update \- prepare a request to update an existing timeout
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_timeout_update(struct io_uring_sqe *" sqe ","
-.BI " const struct __kernel_timespec *" ts ","
-.BI " __u64 " user_data ","
-.BI " unsigned " flags ");"
-.PP
-.BI "void io_uring_prep_timeout_remove(struct io_uring_sqe *" sqe ","
-.BI " __u64 " user_data ","
-.BI " unsigned " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-These functions modify or cancel an existing timeout request. The submission
-queue entry
-.I sqe
-is setup to arm a timeout update or removal specified by
-.I user_data
-and with modifier flags given by
-.IR flags .
-Additionally, the update request includes a
-.I ts
-structure, which contains new timeout information.
-
-For an update request, the
-.I flags
-member may contain a bitmask of the following values:
-.TP
-.B IORING_TIMEOUT_ABS
-The value specified in
-.I ts
-is an absolute value rather than a relative one.
-.PP
-The timeout remove command does not currently accept any flags.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-These are the errors that are reported in the CQE
-.I res
-field. On success,
-.B 0
-is returned.
-.TP
-.B -ENOENT
-The timeout identified by
-.I user_data
-could not be found. It may be invalid, or triggered before the update or
-removal request was processed.
-.TP
-.B -EALREADY
-The timeout identified by
-.I user_data
-is already firing and cannot be canceled.
-.TP
-.B -EINVAL
-One of the fields set in the SQE was invalid. For example, two clocksources
-were given, or the specified timeout seconds or nanoseconds were < 0.
-.TP
-.B -EFAULT
-io_uring was unable to access the data specified by
-.IR ts .
-.SH NOTES
-As with any request that passes in data in a struct, that data must remain
-valid until the request has been successfully submitted. It need not remain
-valid until completion. Once a request has been submitted, the in-kernel
-state is stable. Very early kernels (5.4 and earlier) required state to be
-stable until the completion occurred. Applications can test for this
-behavior by inspecting the
-.B IORING_FEAT_SUBMIT_STABLE
-flag passed back from
-.BR io_uring_queue_init_params (3).
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_prep_timeout (3)
diff --git a/man/io_uring_prep_timeout_update.3.md b/man/io_uring_prep_timeout_update.3.md
new file mode 100644
index 00000000..8d974951
--- /dev/null
+++ b/man/io_uring_prep_timeout_update.3.md
@@ -0,0 +1,72 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 12, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_timeout_update
+---
+
+# NAME
+
+io_uring_prep_timeout_update - prepare a request to update an existing timeout
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_timeout_update(struct io_uring_sqe * sqe ,
+ const struct __kernel_timespec * ts ,
+ __u64 user_data ,
+ unsigned flags );
+
+ void io_uring_prep_timeout_remove(struct io_uring_sqe * sqe ,
+ __u64 user_data ,
+ unsigned flags );
+
+# DESCRIPTION
+
+These functions modify or cancel an existing timeout request. The submission queue entry *sqe* is setup to arm a timeout update or removal specified by *user_data* and with modifier flags given by *flags*. Additionally, the update request includes a *ts* structure, which contains new timeout information.
+
+For an update request, the *flags* member may contain a bitmask of the following values:
+
+**IORING_TIMEOUT_ABS**
+
+: The value specified in *ts* is an absolute value rather than a relative one.
+
+The timeout remove command does not currently accept any flags.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+These are the errors that are reported in the CQE *res* field. On success, **0** is returned.
+
+**-ENOENT**
+
+: The timeout identified by *user_data* could not be found. It may be invalid, or triggered before the update or removal request was processed.
+
+**-EALREADY**
+
+: The timeout identified by *user_data* is already firing and cannot be canceled.
+
+**-EINVAL**
+
+: One of the fields set in the SQE was invalid. For example, two clocksources were given, or the specified timeout seconds or nanoseconds were \< 0.
+
+**-EFAULT**
+
+: io_uring was unable to access the data specified by *ts*.
+
+# NOTES
+
+As with any request that passes in data in a struct, that data must remain valid until the request has been successfully submitted. It need not remain valid until completion. Once a request has been submitted, the in-kernel state is stable. Very early kernels (5.4 and earlier) required state to be stable until the completion occurred. Applications can test for this behavior by inspecting the **IORING_FEAT_SUBMIT_STABLE** flag passed back from **io_uring_queue_init_params**(3).
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_prep_timeout**(3)
diff --git a/man/io_uring_prep_unlink.3 b/man/io_uring_prep_unlink.3
deleted file mode 120000
index 80f86d2d..00000000
--- a/man/io_uring_prep_unlink.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_prep_unlinkat.3
\ No newline at end of file
diff --git a/man/io_uring_prep_unlinkat.3 b/man/io_uring_prep_unlinkat.3
deleted file mode 100644
index ba2633cf..00000000
--- a/man/io_uring_prep_unlinkat.3
+++ /dev/null
@@ -1,82 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_unlinkat 3 "March 13, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_unlinkat \- prepare an unlinkat request
-.SH SYNOPSIS
-.nf
-.B #include <fcntl.h>
-.B #include <unistd.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_unlinkat(struct io_uring_sqe *" sqe ","
-.BI " int " dirfd ","
-.BI " const char *" path ","
-.BI " int " flags ");"
-.PP
-.BI "void io_uring_prep_unlink(struct io_uring_sqe *" sqe ","
-.BI " const char *" path ","
-.BI " int " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_unlinkat (3)
-function prepares an unlinkat request. The submission queue entry
-.I sqe
-is setup to use the directory file descriptor pointed to by
-.I dirfd
-to start an unlinkat operation on the path identified by
-.I path
-and using the flags given in
-.IR flags .
-
-The
-.BR io_uring_prep_unlink (3)
-function prepares an unlink request. The submission queue entry
-.I sqe
-is setup to start an unlinkat operation on the path identified by
-.I path
-relative to the current working directory and using the flags given in
-.IR flags .
-
-These functions prepare an async
-.BR unlinkat (2)
-or
-.BR unlink (2)
-request. See those man pages for details.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-As with any request that passes in data in a struct, that data must remain
-valid until the request has been successfully submitted. It need not remain
-valid until completion. Once a request has been submitted, the in-kernel
-state is stable. Very early kernels (5.4 and earlier) required state to be
-stable until the completion occurred. Applications can test for this
-behavior by inspecting the
-.B IORING_FEAT_SUBMIT_STABLE
-flag passed back from
-.BR io_uring_queue_init_params (3).
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR unlinkat (2),
-.BR unlink (2)
diff --git a/man/io_uring_prep_unlinkat.3.md b/man/io_uring_prep_unlinkat.3.md
new file mode 100644
index 00000000..e9b61305
--- /dev/null
+++ b/man/io_uring_prep_unlinkat.3.md
@@ -0,0 +1,54 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 13, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_unlinkat
+---
+
+# NAME
+
+io_uring_prep_unlinkat - prepare an unlinkat request
+
+# SYNOPSIS
+
+ #include <fcntl.h>
+ #include <unistd.h>
+ #include <liburing.h>
+
+ void io_uring_prep_unlinkat(struct io_uring_sqe * sqe ,
+ int dirfd ,
+ const char * path ,
+ int flags );
+
+ void io_uring_prep_unlink(struct io_uring_sqe * sqe ,
+ const char * path ,
+ int flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_unlinkat**(3) function prepares an unlinkat request. The submission queue entry *sqe* is setup to use the directory file descriptor pointed to by *dirfd* to start an unlinkat operation on the path identified by *path* and using the flags given in *flags*.
+
+The **io_uring_prep_unlink**(3) function prepares an unlink request. The submission queue entry *sqe* is setup to start an unlinkat operation on the path identified by *path* relative to the current working directory and using the flags given in *flags*.
+
+These functions prepare an async **unlinkat**(2) or **unlink**(2) request. See those man pages for details.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+As with any request that passes in data in a struct, that data must remain valid until the request has been successfully submitted. It need not remain valid until completion. Once a request has been submitted, the in-kernel state is stable. Very early kernels (5.4 and earlier) required state to be stable until the completion occurred. Applications can test for this behavior by inspecting the **IORING_FEAT_SUBMIT_STABLE** flag passed back from **io_uring_queue_init_params**(3).
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **unlinkat**(2), **unlink**(2)
diff --git a/man/io_uring_prep_uring_cmd.3 b/man/io_uring_prep_uring_cmd.3
deleted file mode 100644
index b40369ef..00000000
--- a/man/io_uring_prep_uring_cmd.3
+++ /dev/null
@@ -1,37 +0,0 @@
-.\" Copyright (C) 2022 Samuel Williams
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_uring_cmd 3 "October 22, 2025" "liburing-2.13" "liburing Manual"
-.SH NAME
-io_uring_prep_uring_cmd \- prepare a uring_cmd request
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_uring_cmd(struct io_uring_sqe *" sqe ","
-.BI " int " cmd_op ","
-.BI " int " fd ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_uring_cmd (3)
-function prepares uring_cmd (fd specific) request. The submission queue entry
-.I sqe
-is setup to use the filedescriptor
-.I fd
-to send file descriptor specific
-.IR cmd_op .
-
-The reserved fields are initialized to 0. Otherwise the caller has to set up
-any submission queue entry's operation specific fields.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-None
-.SH SEE ALSO
-.BR io_uring_prep_uring_cmd128 (3),
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
diff --git a/man/io_uring_prep_uring_cmd.3.md b/man/io_uring_prep_uring_cmd.3.md
new file mode 100644
index 00000000..ce21d514
--- /dev/null
+++ b/man/io_uring_prep_uring_cmd.3.md
@@ -0,0 +1,41 @@
+.\" Copyright (C) 2022 Samuel Williams
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: October 22, 2025
+footer: liburing-2.13
+header: liburing Manual
+section: 3
+title: io_uring_prep_uring_cmd
+---
+
+# NAME
+
+io_uring_prep_uring_cmd - prepare a uring_cmd request
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_uring_cmd(struct io_uring_sqe * sqe ,
+ int cmd_op ,
+ int fd );
+
+# DESCRIPTION
+
+The **io_uring_prep_uring_cmd**(3) function prepares uring_cmd (fd specific) request. The submission queue entry *sqe* is setup to use the filedescriptor *fd* to send file descriptor specific *cmd_op*.
+
+The reserved fields are initialized to 0. Otherwise the caller has to set up any submission queue entry\'s operation specific fields.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+None
+
+# SEE ALSO
+
+**io_uring_prep_uring_cmd128**(3), **io_uring_get_sqe**(3), **io_uring_submit**(3),
diff --git a/man/io_uring_prep_uring_cmd128.3 b/man/io_uring_prep_uring_cmd128.3
deleted file mode 100644
index 63f263f0..00000000
--- a/man/io_uring_prep_uring_cmd128.3
+++ /dev/null
@@ -1,38 +0,0 @@
-.\" Copyright (C) 2022 Samuel Williams
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_uring_cmd128 3 "October 22, 2025" "liburing-2.13" "liburing Manual"
-.SH NAME
-io_uring_prep_uring_cmd128 \- prepare a uring_cmd request
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_uring_cmd128(struct io_uring_sqe *" sqe ","
-.BI " int " cmd_op ","
-.BI " int " fd ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_uring_cmd128 (3)
-function prepares uring_cmd (fd specific) request for a 128 byte submission
-queue entry. The submission queue entry
-.I sqe
-is setup to use the filedescriptor
-.I fd
-to send file descriptor specific
-.IR cmd_op .
-
-The reserved fields are initialized to 0. Otherwise the caller has to set up
-any submission queue entry's operation specific fields.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-None
-.SH SEE ALSO
-.BR io_uring_prep_uring_cmd (3),
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
diff --git a/man/io_uring_prep_uring_cmd128.3.md b/man/io_uring_prep_uring_cmd128.3.md
new file mode 100644
index 00000000..75cbb5a6
--- /dev/null
+++ b/man/io_uring_prep_uring_cmd128.3.md
@@ -0,0 +1,41 @@
+.\" Copyright (C) 2022 Samuel Williams
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: October 22, 2025
+footer: liburing-2.13
+header: liburing Manual
+section: 3
+title: io_uring_prep_uring_cmd128
+---
+
+# NAME
+
+io_uring_prep_uring_cmd128 - prepare a uring_cmd request
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_uring_cmd128(struct io_uring_sqe * sqe ,
+ int cmd_op ,
+ int fd );
+
+# DESCRIPTION
+
+The **io_uring_prep_uring_cmd128**(3) function prepares uring_cmd (fd specific) request for a 128 byte submission queue entry. The submission queue entry *sqe* is setup to use the filedescriptor *fd* to send file descriptor specific *cmd_op*.
+
+The reserved fields are initialized to 0. Otherwise the caller has to set up any submission queue entry\'s operation specific fields.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+None
+
+# SEE ALSO
+
+**io_uring_prep_uring_cmd**(3), **io_uring_get_sqe**(3), **io_uring_submit**(3),
diff --git a/man/io_uring_prep_waitid.3 b/man/io_uring_prep_waitid.3
deleted file mode 100644
index 06bda74e..00000000
--- a/man/io_uring_prep_waitid.3
+++ /dev/null
@@ -1,67 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_waitid 3 "July 14, 2023" "liburing-2.5" "liburing Manual"
-.SH NAME
-io_uring_prep_waitid \- prepare a waitid request
-.SH SYNOPSIS
-.nf
-.B #include <sys/wait.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_waitid(struct io_uring_sqe *" sqe ","
-.BI " idtype_t " idtype ","
-.BI " id_t " id ","
-.BI " siginfo_t *" infop ","
-.BI " int " options ","
-.BI " unsigned int " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_waitid (3)
-function prepares a waitid request. The submission queue entry
-.I sqe
-is setup to use the
-.I idtype
-and
-.I id
-arguments select the child(ren), and
-.I options
-to specify the child state changes to wait for. Upon successful
-return, it fills
-.I infop
-with information of the child process, if any.
-.I flags
-is io_uring specific modifier flags. They are currently unused, and hence
-.B 0
-should be passed.
-
-This function prepares an async
-.BR waitid (2)
-request. See that man page for details.
-
-Available since kernel 6.7.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR waitid (2)
diff --git a/man/io_uring_prep_waitid.3.md b/man/io_uring_prep_waitid.3.md
new file mode 100644
index 00000000..35a1b856
--- /dev/null
+++ b/man/io_uring_prep_waitid.3.md
@@ -0,0 +1,47 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: July 14, 2023
+footer: liburing-2.5
+header: liburing Manual
+section: 3
+title: io_uring_prep_waitid
+---
+
+# NAME
+
+io_uring_prep_waitid - prepare a waitid request
+
+# SYNOPSIS
+
+ #include <sys/wait.h>
+ #include <liburing.h>
+
+ void io_uring_prep_waitid(struct io_uring_sqe * sqe ,
+ idtype_t idtype ,
+ id_t id ,
+ siginfo_t * infop ,
+ int options ,
+ unsigned int flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_waitid**(3) function prepares a waitid request. The submission queue entry *sqe* is setup to use the *idtype* and *id* arguments select the child(ren), and *options* to specify the child state changes to wait for. Upon successful return, it fills *infop* with information of the child process, if any. *flags* is io_uring specific modifier flags. They are currently unused, and hence **0** should be passed.
+
+This function prepares an async **waitid**(2) request. See that man page for details.
+
+Available since kernel 6.7.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **waitid**(2)
diff --git a/man/io_uring_prep_write.3 b/man/io_uring_prep_write.3
deleted file mode 100644
index fde22136..00000000
--- a/man/io_uring_prep_write.3
+++ /dev/null
@@ -1,70 +0,0 @@
-.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_write 3 "November 15, 2021" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_prep_write \- prepare I/O write request
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_write(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " const void *" buf ","
-.BI " unsigned " nbytes ","
-.BI " __u64 " offset ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_write (3)
-prepares an IO write request. The submission queue entry
-.I sqe
-is setup to use the file descriptor
-.I fd
-to start writing
-.I nbytes
-from the buffer
-.I buf
-at the specified
-.IR offset .
-
-On files that support seeking, if the offset is set to
-.BR -1 ,
-the write operation commences at the file offset, and the file offset is
-incremented by the number of bytes written. See
-.BR write (2)
-for more details. Note that for an async API, reading and updating the
-current file offset may result in unpredictable behavior, unless access
-to the file is serialized. It is not encouraged to use this feature if it's
-possible to provide the desired IO offset from the application or library.
-
-On files that are not capable of seeking, the offset must be 0 or -1.
-
-After the write has been prepared, it can be submitted with one of the submit
-functions.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-Despite accepting an unsigned number of bytes, this function can transfer at most
-INT_MAX bytes per call (the maximum for the underlying syscall interface).
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3)
diff --git a/man/io_uring_prep_write.3.md b/man/io_uring_prep_write.3.md
new file mode 100644
index 00000000..3d93147d
--- /dev/null
+++ b/man/io_uring_prep_write.3.md
@@ -0,0 +1,51 @@
+.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: November 15, 2021
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_prep_write
+---
+
+# NAME
+
+io_uring_prep_write - prepare I/O write request
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_write(struct io_uring_sqe * sqe ,
+ int fd ,
+ const void * buf ,
+ unsigned nbytes ,
+ __u64 offset );
+
+# DESCRIPTION
+
+The **io_uring_prep_write**(3) prepares an IO write request. The submission queue entry *sqe* is setup to use the file descriptor *fd* to start writing *nbytes* from the buffer *buf* at the specified *offset*.
+
+On files that support seeking, if the offset is set to **-1**, the write operation commences at the file offset, and the file offset is incremented by the number of bytes written. See **write**(2) for more details. Note that for an async API, reading and updating the current file offset may result in unpredictable behavior, unless access to the file is serialized. It is not encouraged to use this feature if it\'s possible to provide the desired IO offset from the application or library.
+
+On files that are not capable of seeking, the offset must be 0 or -1.
+
+After the write has been prepared, it can be submitted with one of the submit functions.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+Despite accepting an unsigned number of bytes, this function can transfer at most INT_MAX bytes per call (the maximum for the underlying syscall interface).
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3)
diff --git a/man/io_uring_prep_write_fixed.3 b/man/io_uring_prep_write_fixed.3
deleted file mode 100644
index 28f53282..00000000
--- a/man/io_uring_prep_write_fixed.3
+++ /dev/null
@@ -1,75 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_write_fixed 3 "February 13, 2022" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_prep_write_fixed \- prepare I/O write request with registered buffer
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_write_fixed(struct io_uring_sqe *" sqe ","
-.BI " int " fd ",
-.BI " const void *" buf ","
-.BI " unsigned " nbytes ","
-.BI " __u64 " offset ","
-.BI " int " buf_index ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_write_fixed (3)
-prepares an IO write request with a previously registered IO buffer. The
-submission queue entry
-.I sqe
-is setup to use the file descriptor
-.I fd
-to start writing
-.I nbytes
-from the buffer
-.I buf
-at the specified
-.I offset
-and with the buffer matching the registered index of
-.IR buf_index .
-
-This works just like
-.BR io_uring_prep_write (3)
-except it requires the use of buffers that have been registered with
-.BR io_uring_register_buffers (3).
-The
-.I buf
-and
-.I nbytes
-arguments must fall within a region specified by
-.I buf_index
-in the previously registered buffer. The buffer need not be aligned with
-the start of the registered buffer.
-
-After the write has been prepared it can be submitted with one of the submit
-functions.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-Despite accepting an unsigned number of bytes, this function can transfer at most
-INT_MAX bytes per call (the maximum for the underlying syscall interface).
-.SH SEE ALSO
-.BR io_uring_prep_write (3),
-.BR io_uring_register_buffers (3)
diff --git a/man/io_uring_prep_write_fixed.3.md b/man/io_uring_prep_write_fixed.3.md
new file mode 100644
index 00000000..b6c9dc5d
--- /dev/null
+++ b/man/io_uring_prep_write_fixed.3.md
@@ -0,0 +1,50 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: February 13, 2022
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_prep_write_fixed
+---
+
+# NAME
+
+io_uring_prep_write_fixed - prepare I/O write request with registered buffer
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_write_fixed(struct io_uring_sqe * sqe ,
+ int fd ,
+ const void * buf ,
+ unsigned nbytes ,
+ __u64 offset ,
+ int buf_index );
+
+# DESCRIPTION
+
+The **io_uring_prep_write_fixed**(3) prepares an IO write request with a previously registered IO buffer. The submission queue entry *sqe* is setup to use the file descriptor *fd* to start writing *nbytes* from the buffer *buf* at the specified *offset* and with the buffer matching the registered index of *buf_index*.
+
+This works just like **io_uring_prep_write**(3) except it requires the use of buffers that have been registered with **io_uring_register_buffers**(3). The *buf* and *nbytes* arguments must fall within a region specified by *buf_index* in the previously registered buffer. The buffer need not be aligned with the start of the registered buffer.
+
+After the write has been prepared it can be submitted with one of the submit functions.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+Despite accepting an unsigned number of bytes, this function can transfer at most INT_MAX bytes per call (the maximum for the underlying syscall interface).
+
+# SEE ALSO
+
+**io_uring_prep_write**(3), **io_uring_register_buffers**(3)
diff --git a/man/io_uring_prep_writev.3 b/man/io_uring_prep_writev.3
deleted file mode 100644
index 042ac398..00000000
--- a/man/io_uring_prep_writev.3
+++ /dev/null
@@ -1,89 +0,0 @@
-.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_writev 3 "November 15, 2021" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_prep_writev \- prepare vector I/O write request
-.SH SYNOPSIS
-.nf
-.B #include <sys/uio.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_writev(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " const struct iovec *" iovecs ","
-.BI " unsigned " nr_vecs ","
-.BI " __u64 " offset ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_writev (3)
-prepares a vectored IO write request. The submission queue entry
-.I sqe
-is setup to use the file descriptor
-.I fd
-to start writing
-.I nr_vecs
-from the
-.I iovecs
-array at the specified
-.IR offset .
-
-On files that support seeking, if the offset is set to
-.BR -1 ,
-the write operation commences at the file offset, and the file offset is
-incremented by the number of bytes written. See
-.BR write (2)
-for more details. Note that for an async API, reading and updating the
-current file offset may result in unpredictable behavior, unless access
-to the file is serialized. It is not encouraged to use this feature if it's
-possible to provide the desired IO offset from the application or library.
-
-On files that are not capable of seeking, the offset must be 0 or -1.
-
-After the write has been prepared it can be submitted with one of the submit
-functions.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-Unless an application explicitly needs to pass in more than one iovec, it
-is more efficient to use
-.BR io_uring_prep_write (3)
-rather than this function, as no state has to be maintained for a
-non-vectored IO request.
-As with any request that passes in data in a struct, that data must remain
-valid until the request has been successfully submitted. It need not remain
-valid until completion. Once a request has been submitted, the in-kernel
-state is stable. Very early kernels (5.4 and earlier) required state to be
-stable until the completion occurred. Applications can test for this
-behavior by inspecting the
-.B IORING_FEAT_SUBMIT_STABLE
-flag passed back from
-.BR io_uring_queue_init_params (3).
-
-Despite accepting an array of iovec's with a size_t number of bytes each,
-this function can transfer at most INT_MAX bytes per call (the maximum
-for the underlying syscall interface).
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_prep_write (3),
-.BR io_uring_prep_writev2 (3),
-.BR io_uring_submit (3)
diff --git a/man/io_uring_prep_writev.3.md b/man/io_uring_prep_writev.3.md
new file mode 100644
index 00000000..4387366c
--- /dev/null
+++ b/man/io_uring_prep_writev.3.md
@@ -0,0 +1,54 @@
+.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: November 15, 2021
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_prep_writev
+---
+
+# NAME
+
+io_uring_prep_writev - prepare vector I/O write request
+
+# SYNOPSIS
+
+ #include <sys/uio.h>
+ #include <liburing.h>
+
+ void io_uring_prep_writev(struct io_uring_sqe * sqe ,
+ int fd ,
+ const struct iovec * iovecs ,
+ unsigned nr_vecs ,
+ __u64 offset );
+
+# DESCRIPTION
+
+The **io_uring_prep_writev**(3) prepares a vectored IO write request. The submission queue entry *sqe* is setup to use the file descriptor *fd* to start writing *nr_vecs* from the *iovecs* array at the specified *offset*.
+
+On files that support seeking, if the offset is set to **-1**, the write operation commences at the file offset, and the file offset is incremented by the number of bytes written. See **write**(2) for more details. Note that for an async API, reading and updating the current file offset may result in unpredictable behavior, unless access to the file is serialized. It is not encouraged to use this feature if it\'s possible to provide the desired IO offset from the application or library.
+
+On files that are not capable of seeking, the offset must be 0 or -1.
+
+After the write has been prepared it can be submitted with one of the submit functions.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+Unless an application explicitly needs to pass in more than one iovec, it is more efficient to use **io_uring_prep_write**(3) rather than this function, as no state has to be maintained for a non-vectored IO request. As with any request that passes in data in a struct, that data must remain valid until the request has been successfully submitted. It need not remain valid until completion. Once a request has been submitted, the in-kernel state is stable. Very early kernels (5.4 and earlier) required state to be stable until the completion occurred. Applications can test for this behavior by inspecting the **IORING_FEAT_SUBMIT_STABLE** flag passed back from **io_uring_queue_init_params**(3).
+
+Despite accepting an array of iovec\'s with a size_t number of bytes each, this function can transfer at most INT_MAX bytes per call (the maximum for the underlying syscall interface).
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_prep_write**(3), **io_uring_prep_writev2**(3), **io_uring_submit**(3)
diff --git a/man/io_uring_prep_writev2.3 b/man/io_uring_prep_writev2.3
deleted file mode 100644
index 93659be9..00000000
--- a/man/io_uring_prep_writev2.3
+++ /dev/null
@@ -1,115 +0,0 @@
-.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_writev2 3 "November 15, 2021" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_prep_writev2 \- prepare vector I/O write request with flags
-.SH SYNOPSIS
-.nf
-.B #include <sys/uio.h>
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_writev2(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " const struct iovec *" iovecs ","
-.BI " unsigned " nr_vecs ","
-.BI " __u64 " offset ","
-.BI " int " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_writev2 (3)
-prepares a vectored IO write request. The submission queue entry
-.I sqe
-is setup to use the file descriptor
-.I fd
-to start writing
-.I nr_vecs
-from the
-.I iovecs
-array at the specified
-.IR offset .
-The behavior of the function can be controlled with the
-.I flags
-parameter.
-
-Supported values for
-.I flags
-are:
-.TP
-.B RWF_HIPRI
-High priority request, poll if possible
-.TP
-.B RWF_DSYNC
-per-IO O_DSYNC
-.TP
-.B RWF_SYNC
-per-IO O_SYNC
-.TP
-.B RWF_NOWAIT
-per-IO, return
-.B -EAGAIN
-if operation would block
-.TP
-.B RWF_APPEND
-per-IO O_APPEND
-
-.P
-On files that support seeking, if the offset is set to
-.BR -1 ,
-the write operation commences at the file offset, and the file offset is
-incremented by the number of bytes written. See
-.BR write (2)
-for more details. Note that for an async API, reading and updating the
-current file offset may result in unpredictable behavior, unless access
-to the file is serialized. It is not encouraged to use this feature if it's
-possible to provide the desired IO offset from the application or library.
-
-On files that are not capable of seeking, the offset must be 0 or -1.
-
-After the write has been prepared, it can be submitted with one of the submit
-functions.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation. See the related man page for
-details on possible values. Note that where synchronous system calls will return
-.B -1
-on failure and set
-.I errno
-to the actual error value, io_uring never uses
-.IR errno .
-Instead it returns the negated
-.I errno
-directly in the CQE
-.I res
-field.
-.SH NOTES
-Unless an application explicitly needs to pass in more than one iovec, it
-is more efficient to use
-.BR io_uring_prep_write (3)
-rather than this function, as no state has to be maintained for a
-non-vectored IO request.
-As with any request that passes in data in a struct, that data must remain
-valid until the request has been successfully submitted. It need not remain
-valid until completion. Once a request has been submitted, the in-kernel
-state is stable. Very early kernels (5.4 and earlier) required state to be
-stable until the completion occurred. Applications can test for this
-behavior by inspecting the
-.B IORING_FEAT_SUBMIT_STABLE
-flag passed back from
-.BR io_uring_queue_init_params (3).
-
-Despite accepting an array of iovec's with a size_t number of bytes each,
-this function can transfer at most INT_MAX bytes per call (the maximum
-for the underlying syscall interface).
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_prep_write (3),
-.BR io_uring_prep_writev (3),
-.BR io_uring_submit (3)
diff --git a/man/io_uring_prep_writev2.3.md b/man/io_uring_prep_writev2.3.md
new file mode 100644
index 00000000..43e6a0aa
--- /dev/null
+++ b/man/io_uring_prep_writev2.3.md
@@ -0,0 +1,77 @@
+.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: November 15, 2021
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_prep_writev2
+---
+
+# NAME
+
+io_uring_prep_writev2 - prepare vector I/O write request with flags
+
+# SYNOPSIS
+
+ #include <sys/uio.h>
+ #include <liburing.h>
+
+ void io_uring_prep_writev2(struct io_uring_sqe * sqe ,
+ int fd ,
+ const struct iovec * iovecs ,
+ unsigned nr_vecs ,
+ __u64 offset ,
+ int flags );
+
+# DESCRIPTION
+
+The **io_uring_prep_writev2**(3) prepares a vectored IO write request. The submission queue entry *sqe* is setup to use the file descriptor *fd* to start writing *nr_vecs* from the *iovecs* array at the specified *offset*. The behavior of the function can be controlled with the *flags* parameter.
+
+Supported values for *flags* are:
+
+**RWF_HIPRI**
+
+: High priority request, poll if possible
+
+**RWF_DSYNC**
+
+: per-IO O_DSYNC
+
+**RWF_SYNC**
+
+: per-IO O_SYNC
+
+**RWF_NOWAIT**
+
+: per-IO, return **-EAGAIN** if operation would block
+
+**RWF_APPEND**
+
+: per-IO O_APPEND
+
+On files that support seeking, if the offset is set to **-1**, the write operation commences at the file offset, and the file offset is incremented by the number of bytes written. See **write**(2) for more details. Note that for an async API, reading and updating the current file offset may result in unpredictable behavior, unless access to the file is serialized. It is not encouraged to use this feature if it\'s possible to provide the desired IO offset from the application or library.
+
+On files that are not capable of seeking, the offset must be 0 or -1.
+
+After the write has been prepared, it can be submitted with one of the submit functions.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation. See the related man page for details on possible values. Note that where synchronous system calls will return **-1** on failure and set *errno* to the actual error value, io_uring never uses *errno*. Instead it returns the negated *errno* directly in the CQE *res* field.
+
+# NOTES
+
+Unless an application explicitly needs to pass in more than one iovec, it is more efficient to use **io_uring_prep_write**(3) rather than this function, as no state has to be maintained for a non-vectored IO request. As with any request that passes in data in a struct, that data must remain valid until the request has been successfully submitted. It need not remain valid until completion. Once a request has been submitted, the in-kernel state is stable. Very early kernels (5.4 and earlier) required state to be stable until the completion occurred. Applications can test for this behavior by inspecting the **IORING_FEAT_SUBMIT_STABLE** flag passed back from **io_uring_queue_init_params**(3).
+
+Despite accepting an array of iovec\'s with a size_t number of bytes each, this function can transfer at most INT_MAX bytes per call (the maximum for the underlying syscall interface).
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_prep_write**(3), **io_uring_prep_writev**(3), **io_uring_submit**(3)
diff --git a/man/io_uring_prep_writev_fixed.3 b/man/io_uring_prep_writev_fixed.3
deleted file mode 100644
index 3e62b230..00000000
--- a/man/io_uring_prep_writev_fixed.3
+++ /dev/null
@@ -1,71 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_prep_writev_fixed 3 "January 18, 2025" "liburing-2.10" "liburing Manual"
-.SH NAME
-io_uring_prep_writev_fixed \- prepare a vectored write using fixed buffers
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_prep_writev_fixed(struct io_uring_sqe *" sqe ","
-.BI " int " fd ","
-.BI " const struct iovec *" iovecs ","
-.BI " unsigned " nr_vecs ","
-.BI " __u64 " offset ","
-.BI " int " flags ","
-.BI " int " buf_index ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_writev_fixed (3)
-function prepares a vectored write request using fixed (registered) buffers.
-The submission queue entry
-.I sqe
-is setup to use the file descriptor
-.I fd
-to start writing
-.I nr_vecs
-iovecs from the file position
-.IR offset .
-
-The
-.I iovecs
-argument points to an array of iovec structures describing the write
-buffers. All buffers must be part of the registered buffer set at index
-.IR buf_index ,
-previously registered with
-.BR io_uring_register_buffers (3).
-
-The
-.I flags
-argument can contain any per-request flags, such as
-.B RWF_APPEND
-or other flags supported by
-.BR pwritev2 (2).
-
-Using fixed buffers avoids the overhead of mapping buffers for each I/O
-operation, improving performance for applications that reuse the same
-buffers.
-
-.SH RETURN VALUE
-None
-.SH ERRORS
-The CQE
-.I res
-field will contain the result of the operation, the number of bytes written
-on success. On error, a negative errno value is returned.
-.SH NOTES
-Despite accepting an array of iovec's with a size_t number of bytes each,
-this function can transfer at most INT_MAX bytes per call (the maximum
-for the underlying syscall interface).
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_prep_writev (3),
-.BR io_uring_prep_writev2 (3),
-.BR io_uring_prep_write_fixed (3),
-.BR io_uring_prep_readv_fixed (3),
-.BR io_uring_register_buffers (3)
diff --git a/man/io_uring_prep_writev_fixed.3.md b/man/io_uring_prep_writev_fixed.3.md
new file mode 100644
index 00000000..a4be7bd1
--- /dev/null
+++ b/man/io_uring_prep_writev_fixed.3.md
@@ -0,0 +1,53 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: liburing-2.10
+header: liburing Manual
+section: 3
+title: io_uring_prep_writev_fixed
+---
+
+# NAME
+
+io_uring_prep_writev_fixed - prepare a vectored write using fixed buffers
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_prep_writev_fixed(struct io_uring_sqe * sqe ,
+ int fd ,
+ const struct iovec * iovecs ,
+ unsigned nr_vecs ,
+ __u64 offset ,
+ int flags ,
+ int buf_index );
+
+# DESCRIPTION
+
+The **io_uring_prep_writev_fixed**(3) function prepares a vectored write request using fixed (registered) buffers. The submission queue entry *sqe* is setup to use the file descriptor *fd* to start writing *nr_vecs* iovecs from the file position *offset*.
+
+The *iovecs* argument points to an array of iovec structures describing the write buffers. All buffers must be part of the registered buffer set at index *buf_index*, previously registered with **io_uring_register_buffers**(3).
+
+The *flags* argument can contain any per-request flags, such as **RWF_APPEND** or other flags supported by **pwritev2**(2).
+
+Using fixed buffers avoids the overhead of mapping buffers for each I/O operation, improving performance for applications that reuse the same buffers.
+
+# RETURN VALUE
+
+None
+
+# ERRORS
+
+The CQE *res* field will contain the result of the operation, the number of bytes written on success. On error, a negative errno value is returned.
+
+# NOTES
+
+Despite accepting an array of iovec\'s with a size_t number of bytes each, this function can transfer at most INT_MAX bytes per call (the maximum for the underlying syscall interface).
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_prep_writev**(3), **io_uring_prep_writev2**(3), **io_uring_prep_write_fixed**(3), **io_uring_prep_readv_fixed**(3), **io_uring_register_buffers**(3)
diff --git a/man/io_uring_provided_buffers.7 b/man/io_uring_provided_buffers.7
deleted file mode 100644
index 57e91132..00000000
--- a/man/io_uring_provided_buffers.7
+++ /dev/null
@@ -1,266 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_provided_buffers 7 "January 18, 2025" "Linux" "Linux Programmer's Manual"
-.SH NAME
-io_uring_provided_buffers \- io_uring provided buffer rings overview
-.SH DESCRIPTION
-Provided buffer rings allow applications to supply a pool of buffers to
-the kernel that can be dynamically selected at operation completion time.
-This is particularly useful for operations where the buffer requirements
-are not known upfront, such as receiving data from network sockets or
-reading from pipes.
-.SS Why use provided buffers?
-Traditional I/O operations require the application to specify a buffer
-when submitting the request. For receive operations on sockets or reads
-from pipes, this presents a challenge: the application doesn't know how
-much data will arrive, so it must either:
-.IP \(bu 2
-Allocate a large buffer for each pending operation, wasting memory
-.IP \(bu
-Use small buffers and potentially require multiple operations
-.IP \(bu
-Limit the number of pending operations to control memory usage
-.PP
-Provided buffer rings solve this by letting the kernel select an
-appropriately-sized buffer from a shared pool at completion time.
-Multiple operations can share the same buffer pool, and buffers are only
-consumed when data actually arrives.
-
-Provided buffers are most beneficial for:
-.IP \(bu 2
-Network servers with many concurrent connections
-.IP \(bu
-Applications receiving variable-length messages
-.IP \(bu
-Scenarios where memory efficiency is important
-.SS Buffer ring concepts
-A provided buffer ring is a circular buffer shared between the
-application and kernel:
-.IP \(bu 2
-The application adds buffers to the ring by writing entries and
-advancing the tail
-.IP \(bu
-The kernel consumes buffers from the ring by reading entries and
-advancing the head
-.IP \(bu
-Each buffer has a unique buffer ID (bid) within its buffer group
-.IP \(bu
-Buffer groups are identified by a buffer group ID (bgid)
-.PP
-Multiple buffer rings can exist simultaneously, each with a different
-buffer group ID. Operations specify which buffer group to use.
-.SS Setting up a buffer ring
-Buffer rings are set up using
-.BR io_uring_setup_buf_ring (3),
-which handles allocation, registration, and initialization:
-.PP
-.in +4n
-.EX
-struct io_uring_buf_ring *br;
-int bgid = 1; /* buffer group ID */
-int err;
-
-br = io_uring_setup_buf_ring(ring, 128, bgid, 0, &err);
-if (!br) {
- fprintf(stderr, "buffer ring setup failed: %d\\n", err);
- return err;
-}
-.EE
-.in
-.PP
-The ring must have a power-of-two number of entries, up to a maximum of
-32768 (2^15).
-
-Alternatively, applications can use
-.BR io_uring_register_buf_ring (3)
-for more control over the setup process, including kernel-allocated
-rings using the
-.B IOU_PBUF_RING_MMAP
-flag.
-.SS Adding buffers to the ring
-Buffers are added using
-.BR io_uring_buf_ring_add (3)
-and made visible to the kernel with
-.BR io_uring_buf_ring_advance (3):
-.PP
-.in +4n
-.EX
-int mask = io_uring_buf_ring_mask(128);
-
-for (int i = 0; i < 128; i++) {
- void *buf = malloc(4096);
- io_uring_buf_ring_add(br, buf, 4096, i, mask, i);
-}
-io_uring_buf_ring_advance(br, 128);
-.EE
-.in
-.PP
-Each buffer is assigned a buffer ID (the third parameter). Buffer IDs
-should be unique within the buffer group but can be reused after a
-buffer is returned.
-.SS Using provided buffers in operations
-To use provided buffers, set the
-.B IOSQE_BUFFER_SELECT
-flag on the SQE and specify the buffer group ID:
-.PP
-.in +4n
-.EX
-struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
-io_uring_prep_recv(sqe, sockfd, NULL, 4096, 0);
-io_uring_sqe_set_flags(sqe, IOSQE_BUFFER_SELECT);
-io_uring_sqe_set_buf_group(sqe, bgid);
-.EE
-.in
-.PP
-Note that
-.I addr
-is set to NULL (or ignored) since the kernel will select the buffer.
-The
-.I len
-field specifies the maximum amount of data to receive.
-
-Operations that support provided buffers include:
-.IP \(bu 2
-.B IORING_OP_READ
-/
-.B IORING_OP_RECV
-.IP \(bu
-.B IORING_OP_READV
-(single vector only)
-.IP \(bu
-.B IORING_OP_RECVMSG
-.SS Handling completions
-When an operation using provided buffers completes, the CQE indicates
-which buffer was used:
-.IP \(bu 2
-.B IORING_CQE_F_BUFFER
-is set in
-.I cqe->flags
-.IP \(bu
-The buffer ID is in the upper 16 bits of
-.IR cqe->flags ,
-extractable via
-.B cqe->flags >> IORING_CQE_BUFFER_SHIFT
-.IP \(bu
-.I cqe->res
-contains the number of bytes transferred
-.PP
-.in +4n
-.EX
-struct io_uring_cqe *cqe;
-io_uring_wait_cqe(ring, &cqe);
-
-if (cqe->flags & IORING_CQE_F_BUFFER) {
- int bid = cqe->flags >> IORING_CQE_BUFFER_SHIFT;
- void *buf = buffers[bid]; /* application's buffer tracking */
- int len = cqe->res;
-
- /* process data in buf */
- process_data(buf, len);
-
- /* return buffer to ring for reuse */
- io_uring_buf_ring_add(br, buf, 4096, bid, mask, 0);
- io_uring_buf_ring_advance(br, 1);
-}
-io_uring_cqe_seen(ring, cqe);
-.EE
-.in
-.PP
-If no buffer was available when the operation completed, the operation
-fails with
-.BR -ENOBUFS .
-.SS Multishot operations
-Provided buffers are particularly powerful with multishot operations
-like
-.BR io_uring_prep_recv_multishot (3).
-A single SQE can generate multiple completions, each consuming a buffer
-from the ring:
-.PP
-.in +4n
-.EX
-struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
-io_uring_prep_recv_multishot(sqe, sockfd, NULL, 0, 0);
-io_uring_sqe_set_flags(sqe, IOSQE_BUFFER_SELECT);
-io_uring_sqe_set_buf_group(sqe, bgid);
-.EE
-.in
-.PP
-Completions with
-.B IORING_CQE_F_MORE
-set indicate more completions will follow. The multishot operation
-continues until an error occurs, the buffer ring is exhausted, or the
-operation is canceled.
-.SS Incremental buffer consumption
-Buffer rings can be set up with the
-.B IOU_PBUF_RING_INC
-flag to enable incremental consumption. With this mode, large buffers
-can be partially consumed across multiple operations:
-.IP \(bu 2
-Completions with
-.B IORING_CQE_F_BUF_MORE
-indicate the buffer will be used for more completions
-.IP \(bu
-Each completion picks up where the previous left off
-.IP \(bu
-The buffer is only returned when consumed completely or on error
-.PP
-This is useful for registering large buffer regions that are consumed
-in smaller chunks.
-.SS Returning buffers
-When finished with a buffer, return it to the ring using
-.BR io_uring_buf_ring_add (3)
-followed by
-.BR io_uring_buf_ring_advance (3).
-For efficiency when processing multiple CQEs, use
-.BR io_uring_buf_ring_cq_advance (3)
-to advance both the CQ and buffer ring in a single operation.
-.SS Buffer ring status
-Applications can query how many buffers are available using
-.BR io_uring_buf_ring_available (3),
-which returns the number of buffers the kernel has not yet consumed.
-The current kernel head position can be retrieved with
-.BR io_uring_buf_ring_head (3).
-.SS Cleaning up
-Buffer rings are freed using
-.BR io_uring_free_buf_ring (3),
-which unregisters the ring and frees the ring memory (if it was
-allocated by
-.BR io_uring_setup_buf_ring (3)).
-Applications must free the individual buffers themselves.
-.SH NOTES
-.IP \(bu 2
-Buffer ring entries must be a power of two, maximum 32768.
-.IP \(bu
-Buffer IDs are 16-bit values (0-65535).
-.IP \(bu
-If no buffer is available when an operation needs one, the operation
-fails with
-.BR -ENOBUFS .
-Applications should ensure the ring is adequately stocked.
-.IP \(bu
-Provided buffers cannot be used with registered (fixed) buffers. These
-are separate mechanisms.
-.IP \(bu
-For multishot receives, ensure buffers are returned to the ring promptly
-to avoid running out.
-.SS Legacy provided buffers
-Earlier kernels supported provided buffers via
-.B IORING_OP_PROVIDE_BUFFERS
-and
-.BR IORING_OP_REMOVE_BUFFERS .
-This mechanism required submitting SQEs to add or remove buffers,
-adding latency and overhead. The ring-based mechanism described above
-supersedes this approach and should be used for all new applications.
-The legacy interface remains for backwards compatibility.
-.SH SEE ALSO
-.BR io_uring (7),
-.BR io_uring_setup_buf_ring (3),
-.BR io_uring_free_buf_ring (3),
-.BR io_uring_register_buf_ring (3),
-.BR io_uring_unregister_buf_ring (3),
-.BR io_uring_buf_ring_add (3),
-.BR io_uring_buf_ring_advance (3),
-.BR io_uring_buf_ring_cq_advance (3),
-.BR io_uring_buf_ring_available (3),
-.BR io_uring_prep_recv_multishot (3)
diff --git a/man/io_uring_provided_buffers.7.md b/man/io_uring_provided_buffers.7.md
new file mode 100644
index 00000000..84e8a89c
--- /dev/null
+++ b/man/io_uring_provided_buffers.7.md
@@ -0,0 +1,189 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: Linux
+header: Linux Programmer\'s Manual
+section: 7
+title: io_uring_provided_buffers
+---
+
+# NAME
+
+io_uring_provided_buffers - io_uring provided buffer rings overview
+
+# DESCRIPTION
+
+Provided buffer rings allow applications to supply a pool of buffers to the kernel that can be dynamically selected at operation completion time. This is particularly useful for operations where the buffer requirements are not known upfront, such as receiving data from network sockets or reading from pipes.
+
+## Why use provided buffers?
+
+Traditional I/O operations require the application to specify a buffer when submitting the request. For receive operations on sockets or reads from pipes, this presents a challenge: the application doesn\'t know how much data will arrive, so it must either:
+
+- Allocate a large buffer for each pending operation, wasting memory
+
+- Use small buffers and potentially require multiple operations
+
+- Limit the number of pending operations to control memory usage
+
+Provided buffer rings solve this by letting the kernel select an appropriately-sized buffer from a shared pool at completion time. Multiple operations can share the same buffer pool, and buffers are only consumed when data actually arrives.
+
+Provided buffers are most beneficial for:
+
+- Network servers with many concurrent connections
+
+- Applications receiving variable-length messages
+
+- Scenarios where memory efficiency is important
+
+## Buffer ring concepts
+
+A provided buffer ring is a circular buffer shared between the application and kernel:
+
+- The application adds buffers to the ring by writing entries and advancing the tail
+
+- The kernel consumes buffers from the ring by reading entries and advancing the head
+
+- Each buffer has a unique buffer ID (bid) within its buffer group
+
+- Buffer groups are identified by a buffer group ID (bgid)
+
+Multiple buffer rings can exist simultaneously, each with a different buffer group ID. Operations specify which buffer group to use.
+
+## Setting up a buffer ring
+
+Buffer rings are set up using **io_uring_setup_buf_ring**(3), which handles allocation, registration, and initialization:
+
+ struct io_uring_buf_ring *br;
+ int bgid = 1; /* buffer group ID */
+ int err;
+
+ br = io_uring_setup_buf_ring(ring, 128, bgid, 0, &err);
+ if (!br) {
+ fprintf(stderr, "buffer ring setup failed: %d\n", err);
+ return err;
+ }
+
+The ring must have a power-of-two number of entries, up to a maximum of 32768 (2\^15).
+
+Alternatively, applications can use **io_uring_register_buf_ring**(3) for more control over the setup process, including kernel-allocated rings using the **IOU_PBUF_RING_MMAP** flag.
+
+## Adding buffers to the ring
+
+Buffers are added using **io_uring_buf_ring_add**(3) and made visible to the kernel with **io_uring_buf_ring_advance**(3):
+
+ int mask = io_uring_buf_ring_mask(128);
+
+ for (int i = 0; i < 128; i++) {
+ void *buf = malloc(4096);
+ io_uring_buf_ring_add(br, buf, 4096, i, mask, i);
+ }
+ io_uring_buf_ring_advance(br, 128);
+
+Each buffer is assigned a buffer ID (the third parameter). Buffer IDs should be unique within the buffer group but can be reused after a buffer is returned.
+
+## Using provided buffers in operations
+
+To use provided buffers, set the **IOSQE_BUFFER_SELECT** flag on the SQE and specify the buffer group ID:
+
+ struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
+ io_uring_prep_recv(sqe, sockfd, NULL, 4096, 0);
+ io_uring_sqe_set_flags(sqe, IOSQE_BUFFER_SELECT);
+ io_uring_sqe_set_buf_group(sqe, bgid);
+
+Note that *addr* is set to NULL (or ignored) since the kernel will select the buffer. The *len* field specifies the maximum amount of data to receive.
+
+Operations that support provided buffers include:
+
+- **IORING_OP_READ** / **IORING_OP_RECV**
+
+- **IORING_OP_READV** (single vector only)
+
+- **IORING_OP_RECVMSG**
+
+## Handling completions
+
+When an operation using provided buffers completes, the CQE indicates which buffer was used:
+
+- **IORING_CQE_F_BUFFER** is set in *cqe-\>flags*
+
+- The buffer ID is in the upper 16 bits of *cqe-\>flags*, extractable via **cqe-\>flags \>\> IORING_CQE_BUFFER_SHIFT**
+
+- *cqe-\>res* contains the number of bytes transferred
+
+<!-- -->
+
+ struct io_uring_cqe *cqe;
+ io_uring_wait_cqe(ring, &cqe);
+
+ if (cqe->flags & IORING_CQE_F_BUFFER) {
+ int bid = cqe->flags >> IORING_CQE_BUFFER_SHIFT;
+ void *buf = buffers[bid]; /* application's buffer tracking */
+ int len = cqe->res;
+
+ /* process data in buf */
+ process_data(buf, len);
+
+ /* return buffer to ring for reuse */
+ io_uring_buf_ring_add(br, buf, 4096, bid, mask, 0);
+ io_uring_buf_ring_advance(br, 1);
+ }
+ io_uring_cqe_seen(ring, cqe);
+
+If no buffer was available when the operation completed, the operation fails with **-ENOBUFS**.
+
+## Multishot operations
+
+Provided buffers are particularly powerful with multishot operations like **io_uring_prep_recv_multishot**(3). A single SQE can generate multiple completions, each consuming a buffer from the ring:
+
+ struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
+ io_uring_prep_recv_multishot(sqe, sockfd, NULL, 0, 0);
+ io_uring_sqe_set_flags(sqe, IOSQE_BUFFER_SELECT);
+ io_uring_sqe_set_buf_group(sqe, bgid);
+
+Completions with **IORING_CQE_F_MORE** set indicate more completions will follow. The multishot operation continues until an error occurs, the buffer ring is exhausted, or the operation is canceled.
+
+## Incremental buffer consumption
+
+Buffer rings can be set up with the **IOU_PBUF_RING_INC** flag to enable incremental consumption. With this mode, large buffers can be partially consumed across multiple operations:
+
+- Completions with **IORING_CQE_F_BUF_MORE** indicate the buffer will be used for more completions
+
+- Each completion picks up where the previous left off
+
+- The buffer is only returned when consumed completely or on error
+
+This is useful for registering large buffer regions that are consumed in smaller chunks.
+
+## Returning buffers
+
+When finished with a buffer, return it to the ring using **io_uring_buf_ring_add**(3) followed by **io_uring_buf_ring_advance**(3). For efficiency when processing multiple CQEs, use **io_uring_buf_ring_cq_advance**(3) to advance both the CQ and buffer ring in a single operation.
+
+## Buffer ring status
+
+Applications can query how many buffers are available using **io_uring_buf_ring_available**(3), which returns the number of buffers the kernel has not yet consumed. The current kernel head position can be retrieved with **io_uring_buf_ring_head**(3).
+
+## Cleaning up
+
+Buffer rings are freed using **io_uring_free_buf_ring**(3), which unregisters the ring and frees the ring memory (if it was allocated by **io_uring_setup_buf_ring**(3)). Applications must free the individual buffers themselves.
+
+# NOTES
+
+- Buffer ring entries must be a power of two, maximum 32768.
+
+- Buffer IDs are 16-bit values (0-65535).
+
+- If no buffer is available when an operation needs one, the operation fails with **-ENOBUFS**. Applications should ensure the ring is adequately stocked.
+
+- Provided buffers cannot be used with registered (fixed) buffers. These are separate mechanisms.
+
+- For multishot receives, ensure buffers are returned to the ring promptly to avoid running out.
+
+## Legacy provided buffers
+
+Earlier kernels supported provided buffers via **IORING_OP_PROVIDE_BUFFERS** and **IORING_OP_REMOVE_BUFFERS**. This mechanism required submitting SQEs to add or remove buffers, adding latency and overhead. The ring-based mechanism described above supersedes this approach and should be used for all new applications. The legacy interface remains for backwards compatibility.
+
+# SEE ALSO
+
+**io_uring**(7), **io_uring_setup_buf_ring**(3), **io_uring_free_buf_ring**(3), **io_uring_register_buf_ring**(3), **io_uring_unregister_buf_ring**(3), **io_uring_buf_ring_add**(3), **io_uring_buf_ring_advance**(3), **io_uring_buf_ring_cq_advance**(3), **io_uring_buf_ring_available**(3), **io_uring_prep_recv_multishot**(3)
diff --git a/man/io_uring_queue_exit.3 b/man/io_uring_queue_exit.3
deleted file mode 100644
index 6425ffcf..00000000
--- a/man/io_uring_queue_exit.3
+++ /dev/null
@@ -1,30 +0,0 @@
-.\" Copyright (C) 2020 Jens Axboe <axboe@kernel.dk>
-.\" Copyright (C) 2020 Red Hat, Inc.
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_queue_exit 3 "July 10, 2020" "liburing-0.7" "liburing Manual"
-.SH NAME
-io_uring_queue_exit \- tear down io_uring submission and completion queues
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_queue_exit(struct io_uring *" ring ");"
-.fi
-.SH DESCRIPTION
-.PP
-.BR io_uring_queue_exit (3)
-will release all resources acquired and initialized by
-.BR io_uring_queue_init (3).
-It first unmaps the memory shared between the application and the kernel and then closes the io_uring file descriptor.
-
-Some accounting is done asynchronously, so memory locked by
-.BR io_uring_queue_init (3)
-may remain locked for a few milliseconds after this function returns.
-.SH RETURN VALUE
-None
-.SH SEE ALSO
-.BR io_uring_setup (2),
-.BR mmap (2),
-.BR io_uring_queue_init (3)
diff --git a/man/io_uring_queue_exit.3.md b/man/io_uring_queue_exit.3.md
new file mode 100644
index 00000000..9dc149c5
--- /dev/null
+++ b/man/io_uring_queue_exit.3.md
@@ -0,0 +1,36 @@
+.\" Copyright (C) 2020 Jens Axboe <axboe@kernel.dk>
+.\" Copyright (C) 2020 Red Hat, Inc.
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: July 10, 2020
+footer: liburing-0.7
+header: liburing Manual
+section: 3
+title: io_uring_queue_exit
+---
+
+# NAME
+
+io_uring_queue_exit - tear down io_uring submission and completion queues
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_queue_exit(struct io_uring * ring );
+
+# DESCRIPTION
+
+**io_uring_queue_exit**(3) will release all resources acquired and initialized by **io_uring_queue_init**(3). It first unmaps the memory shared between the application and the kernel and then closes the io_uring file descriptor.
+
+Some accounting is done asynchronously, so memory locked by **io_uring_queue_init**(3) may remain locked for a few milliseconds after this function returns.
+
+# RETURN VALUE
+
+None
+
+# SEE ALSO
+
+**io_uring_setup**(2), **mmap**(2), **io_uring_queue_init**(3)
diff --git a/man/io_uring_queue_init.3 b/man/io_uring_queue_init.3
deleted file mode 100644
index 24015d69..00000000
--- a/man/io_uring_queue_init.3
+++ /dev/null
@@ -1,144 +0,0 @@
-.\" Copyright (C) 2020 Jens Axboe <axboe@kernel.dk>
-.\" Copyright (C) 2020 Red Hat, Inc.
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_queue_init 3 "July 10, 2020" "liburing-0.7" "liburing Manual"
-.SH NAME
-io_uring_queue_init \- setup io_uring submission and completion queues
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_queue_init(unsigned " entries ","
-.BI " struct io_uring *" ring ","
-.BI " unsigned " flags ");"
-.PP
-.BI "int io_uring_queue_init_params(unsigned " entries ","
-.BI " struct io_uring *" ring ","
-.BI " struct io_uring_params *" params ");"
-.PP
-.BI "int io_uring_queue_init_mem(unsigned " entries ","
-.BI " struct io_uring *" ring ","
-.BI " struct io_uring_params *" params ","
-.BI " void *" buf ", size_t " buf_size ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_queue_init (3)
-function executes the
-.BR io_uring_setup (2)
-system call to initialize the submission and completion queues in the kernel
-with at least
-.I entries
-entries in the submission queue and then maps the resulting file descriptor to
-memory shared between the application and the kernel.
-
-By default, the CQ ring will have twice the number of entries as specified by
-.I entries
-for the SQ ring. This is adequate for regular file or storage workloads, but
-may be too small for networked workloads. The SQ ring entries do not impose a
-limit on the number of in-flight requests that the ring can support, it merely
-limits the number that can be submitted to the kernel in one go (batch). If the
-CQ ring overflows, e.g. more entries are generated than fits in the ring before
-the application can reap them, then if the kernel supports
-.B IORING_FEAT_NODROP
-the ring enters a CQ ring overflow state. Otherwise it drops the CQEs and
-increments
-.I cq.koverflow
-in
-.I struct io_uring
-with the number of CQEs dropped. The overflow state is indicated by
-.B IORING_SQ_CQ_OVERFLOW
-being set in the SQ ring flags. Unless the kernel runs out of available memory,
-entries are not dropped, but it is a much slower completion path and will slow
-down request processing. For that reason it should be avoided and the CQ
-ring sized appropriately for the workload. Setting
-.I cq_entries
-in
-.I struct io_uring_params
-will tell the kernel to allocate this many entries for the CQ ring, independent
-of the SQ ring size in given in
-.IR entries .
-If the value isn't a power of 2, it will be rounded up to the nearest power of
-2.
-
-On success,
-.BR io_uring_queue_init (3)
-returns 0 and
-.I ring
-will point to the shared memory containing the io_uring queues. On failure
-.BR -errno
-is returned.
-
-.I flags
-will be passed through to the io_uring_setup syscall (see
-.BR io_uring_setup (2)).
-
-The
-.BR io_uring_queue_init_params (3)
-and
-.BR io_uring_queue_init_mem (3)
-variants will pass the parameters indicated by
-.I params
-straight through to the
-.BR io_uring_setup (2)
-system call.
-
-The
-.BR io_uring_queue_init_mem (3)
-variant uses the provided
-.I buf
-with associated size
-.I buf_size
-as the memory for the ring, using the
-.B IORING_SETUP_NO_MMAP
-flag to
-.BR io_uring_setup (2).
-The buffer passed to
-.BR io_uring_queue_init_mem (3)
-must be page size aligned on the host, and must already be zeroed.
-Typically, the caller should allocate a huge page and pass that in to
-.BR io_uring_queue_init_mem (3).
-Pages allocated by mmap are already zeroed.
-.BR io_uring_queue_init_mem (3)
-returns the number of bytes used from the provided buffer, so that the app can
-reuse the buffer with the returned offset to put more rings in the same huge
-page.
-
-On success, the resources held by
-.I ring
-should be released via a corresponding call to
-.BR io_uring_queue_exit (3).
-.SH RETURN VALUE
-.BR io_uring_queue_init (3)
-and
-.BR io_uring_queue_init_params (3)
-return 0 on success and
-.BR -errno
-on failure.
-A return value of
-.BR -ENOMEM
-indicates there is not enough locked memory available to hold the specified
-number of entries.
-Reduce the number of entries, or call
-.BR setrlimit (2)
-to increase the maximum number of bytes of memory that may be locked into RAM.
-Be aware that calling
-.BR io_uring_queue_init (3)
-and
-.BR io_uring_queue_exit (3)
-in a loop will temporarily lock a lot of memory, because
-.BR io_uring_queue_exit (3)
-does some of its accounting asynchronously.
-
-.BR io_uring_queue_init_mem (3)
-returns the number of bytes used from the provided buffer on success, and
-.BR -errno
-on failure.
-.SH SEE ALSO
-.BR io_uring_setup (2),
-.BR io_uring_register_ring_fd (3),
-.BR mmap (2),
-.BR io_uring_queue_exit (3)
diff --git a/man/io_uring_queue_init.3.md b/man/io_uring_queue_init.3.md
new file mode 100644
index 00000000..60e160af
--- /dev/null
+++ b/man/io_uring_queue_init.3.md
@@ -0,0 +1,59 @@
+.\" Copyright (C) 2020 Jens Axboe <axboe@kernel.dk>
+.\" Copyright (C) 2020 Red Hat, Inc.
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: July 10, 2020
+footer: liburing-0.7
+header: liburing Manual
+section: 3
+title: io_uring_queue_init
+---
+
+# NAME
+
+io_uring_queue_init - setup io_uring submission and completion queues
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_queue_init(unsigned entries ,
+ struct io_uring * ring ,
+ unsigned flags );
+
+ int io_uring_queue_init_params(unsigned entries ,
+ struct io_uring * ring ,
+ struct io_uring_params * params );
+
+ int io_uring_queue_init_mem(unsigned entries ,
+ struct io_uring * ring ,
+ struct io_uring_params * params ,
+ void * buf , size_t buf_size );
+
+# DESCRIPTION
+
+The **io_uring_queue_init**(3) function executes the **io_uring_setup**(2) system call to initialize the submission and completion queues in the kernel with at least *entries* entries in the submission queue and then maps the resulting file descriptor to memory shared between the application and the kernel.
+
+By default, the CQ ring will have twice the number of entries as specified by *entries* for the SQ ring. This is adequate for regular file or storage workloads, but may be too small for networked workloads. The SQ ring entries do not impose a limit on the number of in-flight requests that the ring can support, it merely limits the number that can be submitted to the kernel in one go (batch). If the CQ ring overflows, e.g. more entries are generated than fits in the ring before the application can reap them, then if the kernel supports **IORING_FEAT_NODROP** the ring enters a CQ ring overflow state. Otherwise it drops the CQEs and increments *cq.koverflow* in *struct io_uring* with the number of CQEs dropped. The overflow state is indicated by **IORING_SQ_CQ_OVERFLOW** being set in the SQ ring flags. Unless the kernel runs out of available memory, entries are not dropped, but it is a much slower completion path and will slow down request processing. For that reason it should be avoided and the CQ ring sized appropriately for the workload. Setting *cq_entries* in *struct io_uring_params* will tell the kernel to allocate this many entries for the CQ ring, independent of the SQ ring size in given in *entries*. If the value isn\'t a power of 2, it will be rounded up to the nearest power of 2.
+
+On success, **io_uring_queue_init**(3) returns 0 and *ring* will point to the shared memory containing the io_uring queues. On failure **-errno** is returned.
+
+*flags* will be passed through to the io_uring_setup syscall (see **io_uring_setup**(2)).
+
+The **io_uring_queue_init_params**(3) and **io_uring_queue_init_mem**(3) variants will pass the parameters indicated by *params* straight through to the **io_uring_setup**(2) system call.
+
+The **io_uring_queue_init_mem**(3) variant uses the provided *buf* with associated size *buf_size* as the memory for the ring, using the **IORING_SETUP_NO_MMAP** flag to **io_uring_setup**(2). The buffer passed to **io_uring_queue_init_mem**(3) must be page size aligned on the host, and must already be zeroed. Typically, the caller should allocate a huge page and pass that in to **io_uring_queue_init_mem**(3). Pages allocated by mmap are already zeroed. **io_uring_queue_init_mem**(3) returns the number of bytes used from the provided buffer, so that the app can reuse the buffer with the returned offset to put more rings in the same huge page.
+
+On success, the resources held by *ring* should be released via a corresponding call to **io_uring_queue_exit**(3).
+
+# RETURN VALUE
+
+**io_uring_queue_init**(3) and **io_uring_queue_init_params**(3) return 0 on success and **-errno** on failure. A return value of **-ENOMEM** indicates there is not enough locked memory available to hold the specified number of entries. Reduce the number of entries, or call **setrlimit**(2) to increase the maximum number of bytes of memory that may be locked into RAM. Be aware that calling **io_uring_queue_init**(3) and **io_uring_queue_exit**(3) in a loop will temporarily lock a lot of memory, because **io_uring_queue_exit**(3) does some of its accounting asynchronously.
+
+**io_uring_queue_init_mem**(3) returns the number of bytes used from the provided buffer on success, and **-errno** on failure.
+
+# SEE ALSO
+
+**io_uring_setup**(2), **io_uring_register_ring_fd**(3), **mmap**(2), **io_uring_queue_exit**(3)
diff --git a/man/io_uring_queue_init_mem.3 b/man/io_uring_queue_init_mem.3
deleted file mode 120000
index c91609e5..00000000
--- a/man/io_uring_queue_init_mem.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_queue_init.3
\ No newline at end of file
diff --git a/man/io_uring_queue_init_params.3 b/man/io_uring_queue_init_params.3
deleted file mode 120000
index c91609e5..00000000
--- a/man/io_uring_queue_init_params.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_queue_init.3
\ No newline at end of file
diff --git a/man/io_uring_queue_mmap.3 b/man/io_uring_queue_mmap.3
deleted file mode 100644
index 43351253..00000000
--- a/man/io_uring_queue_mmap.3
+++ /dev/null
@@ -1,49 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_queue_mmap 3 "January 18, 2025" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_queue_mmap \- mmap io_uring ring after setup
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_queue_mmap(int " fd ", struct io_uring_params *" p ","
-.BI " struct io_uring *" ring ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_queue_mmap (3)
-function maps the io_uring ring file descriptor
-.I fd
-into memory using the parameters in
-.IR p .
-The resulting ring is stored in
-.IR ring .
-
-This function is a helper for applications that need to customize the ring
-setup process. Most applications should use
-.BR io_uring_queue_init (3)
-or
-.BR io_uring_queue_init_params (3)
-instead, which call
-.BR io_uring_setup (2)
-and this function automatically.
-
-The
-.I fd
-argument should be a file descriptor returned by
-.BR io_uring_setup (2),
-and
-.I p
-should contain the parameters returned by the setup call.
-
-.SH RETURN VALUE
-Returns 0 on success, or a negative errno value on error.
-.SH SEE ALSO
-.BR io_uring_setup (2),
-.BR io_uring_queue_init (3),
-.BR io_uring_queue_init_params (3),
-.BR io_uring_queue_exit (3)
diff --git a/man/io_uring_queue_mmap.3.md b/man/io_uring_queue_mmap.3.md
new file mode 100644
index 00000000..155e0ff4
--- /dev/null
+++ b/man/io_uring_queue_mmap.3.md
@@ -0,0 +1,38 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_queue_mmap
+---
+
+# NAME
+
+io_uring_queue_mmap - mmap io_uring ring after setup
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_queue_mmap(int fd , struct io_uring_params * p ,
+ struct io_uring * ring );
+
+# DESCRIPTION
+
+The **io_uring_queue_mmap**(3) function maps the io_uring ring file descriptor *fd* into memory using the parameters in *p*. The resulting ring is stored in *ring*.
+
+This function is a helper for applications that need to customize the ring setup process. Most applications should use **io_uring_queue_init**(3) or **io_uring_queue_init_params**(3) instead, which call **io_uring_setup**(2) and this function automatically.
+
+The *fd* argument should be a file descriptor returned by **io_uring_setup**(2), and *p* should contain the parameters returned by the setup call.
+
+# RETURN VALUE
+
+Returns 0 on success, or a negative errno value on error.
+
+# SEE ALSO
+
+**io_uring_setup**(2), **io_uring_queue_init**(3), **io_uring_queue_init_params**(3), **io_uring_queue_exit**(3)
diff --git a/man/io_uring_recvmsg_cmsg_firsthdr.3 b/man/io_uring_recvmsg_cmsg_firsthdr.3
deleted file mode 120000
index 8eb17436..00000000
--- a/man/io_uring_recvmsg_cmsg_firsthdr.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_recvmsg_out.3
\ No newline at end of file
diff --git a/man/io_uring_recvmsg_cmsg_nexthdr.3 b/man/io_uring_recvmsg_cmsg_nexthdr.3
deleted file mode 120000
index 8eb17436..00000000
--- a/man/io_uring_recvmsg_cmsg_nexthdr.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_recvmsg_out.3
\ No newline at end of file
diff --git a/man/io_uring_recvmsg_name.3 b/man/io_uring_recvmsg_name.3
deleted file mode 120000
index 8eb17436..00000000
--- a/man/io_uring_recvmsg_name.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_recvmsg_out.3
\ No newline at end of file
diff --git a/man/io_uring_recvmsg_out.3 b/man/io_uring_recvmsg_out.3
deleted file mode 100644
index 8d605d81..00000000
--- a/man/io_uring_recvmsg_out.3
+++ /dev/null
@@ -1,82 +0,0 @@
-.\" Copyright (C), 2022 Dylan Yudaken <dylany@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_recvmsg_out 3 "July 26, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_recvmsg_out - access data from multishot recvmsg
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "struct io_uring_recvmsg_out *io_uring_recvmsg_validate(void *" buf ","
-.BI " int " buf_len ","
-.BI " struct msghdr *" msgh ");"
-.PP
-.BI "void *io_uring_recvmsg_name(struct io_uring_recvmsg_out *" o ");"
-.PP
-.BI "struct cmsghdr *io_uring_recvmsg_cmsg_firsthdr(struct io_uring_recvmsg_out *" o ","
-.BI " struct msghdr *" msgh ");"
-.BI "struct cmsghdr *io_uring_recvmsg_cmsg_nexthdr(struct io_uring_recvmsg_out *" o ","
-.BI " struct msghdr *" msgh ","
-.BI " struct cmsghdr *" cmsg ");"
-.PP
-.BI "void *io_uring_recvmsg_payload(struct io_uring_recvmsg_out *" o ","
-.BI " struct msghdr *" msgh ");"
-.BI "unsigned int io_uring_recvmsg_payload_length(struct io_uring_recvmsg_out *" o ","
-.BI " int " buf_len ","
-.BI " struct msghdr *" msgh ");"
-.PP
-.fi
-
-.SH DESCRIPTION
-
-These functions are used to access data in the payload delivered by
-.BR io_uring_prep_recvmsg_multishot (3).
-.PP
-.I msgh
-should point to the
-.I struct msghdr
-submitted with the request.
-.PP
-.BR io_uring_recvmsg_validate (3)
-will validate a buffer delivered by
-.BR io_uring_prep_recvmsg_multishot (3)
-and extract the
-.I io_uring_recvmsg_out
-if it is valid, returning a pointer to it or else NULL.
-.PP
-The structure is defined as follows:
-.PP
-.in +4n
-.EX
-
-struct io_uring_recvmsg_out {
- __u32 namelen; /* Name byte count as would have been populated
- * by recvmsg(2) */
- __u32 controllen; /* Control byte count */
- __u32 payloadlen; /* Payload byte count as would have been returned
- * by recvmsg(2) */
- __u32 flags; /* Flags result as would have been populated
- * by recvmsg(2) */
-};
-
-.IP * 3
-.BR io_uring_recvmsg_name (3)
-returns a pointer to the name in the buffer.
-.IP *
-.BR io_uring_recvmsg_cmsg_firsthdr (3)
-returns a pointer to the first cmsg in the buffer, or NULL.
-.IP *
-.BR io_uring_recvmsg_cmsg_nexthdr (3)
-returns a pointer to the next cmsg in the buffer, or NULL.
-.IP *
-.BR io_uring_recvmsg_payload (3)
-returns a pointer to the payload in the buffer.
-.IP *
-.BR io_uring_recvmsg_payload_length (3)
-Calculates the usable payload length in bytes.
-
-
-.SH "SEE ALSO"
-.BR io_uring_prep_recvmsg_multishot (3)
diff --git a/man/io_uring_recvmsg_out.3.md b/man/io_uring_recvmsg_out.3.md
new file mode 100644
index 00000000..4768d849
--- /dev/null
+++ b/man/io_uring_recvmsg_out.3.md
@@ -0,0 +1,72 @@
+.\" Copyright (C), 2022 Dylan Yudaken <dylany@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: July 26, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_recvmsg_out
+---
+
+# NAME
+
+io_uring_recvmsg_out - access data from multishot recvmsg
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ struct io_uring_recvmsg_out *io_uring_recvmsg_validate(void * buf ,
+ int buf_len ,
+ struct msghdr * msgh );
+
+ void *io_uring_recvmsg_name(struct io_uring_recvmsg_out * o );
+
+ struct cmsghdr *io_uring_recvmsg_cmsg_firsthdr(struct io_uring_recvmsg_out * o ,
+ struct msghdr * msgh );
+ struct cmsghdr *io_uring_recvmsg_cmsg_nexthdr(struct io_uring_recvmsg_out * o ,
+ struct msghdr * msgh ,
+ struct cmsghdr * cmsg );
+
+ void *io_uring_recvmsg_payload(struct io_uring_recvmsg_out * o ,
+ struct msghdr * msgh );
+ unsigned int io_uring_recvmsg_payload_length(struct io_uring_recvmsg_out * o ,
+ int buf_len ,
+ struct msghdr * msgh );
+
+# DESCRIPTION
+
+These functions are used to access data in the payload delivered by **io_uring_prep_recvmsg_multishot**(3).
+
+*msgh* should point to the *struct msghdr* submitted with the request.
+
+**io_uring_recvmsg_validate**(3) will validate a buffer delivered by **io_uring_prep_recvmsg_multishot**(3) and extract the *io_uring_recvmsg_out* if it is valid, returning a pointer to it or else NULL.
+
+The structure is defined as follows:
+
+ struct io_uring_recvmsg_out {
+ __u32 namelen; /* Name byte count as would have been populated
+ * by recvmsg(2) */
+ __u32 controllen; /* Control byte count */
+ __u32 payloadlen; /* Payload byte count as would have been returned
+ * by recvmsg(2) */
+ __u32 flags; /* Flags result as would have been populated
+ * by recvmsg(2) */
+ };
+
+ io_uring_recvmsg_name(3)
+ returns a pointer to the name in the buffer.
+ io_uring_recvmsg_cmsg_firsthdr(3)
+ returns a pointer to the first cmsg in the buffer, or NULL.
+ io_uring_recvmsg_cmsg_nexthdr(3)
+ returns a pointer to the next cmsg in the buffer, or NULL.
+ io_uring_recvmsg_payload(3)
+ returns a pointer to the payload in the buffer.
+ io_uring_recvmsg_payload_length(3)
+ Calculates the usable payload length in bytes.
+
+# SEE ALSO
+
+**io_uring_prep_recvmsg_multishot**(3)
diff --git a/man/io_uring_recvmsg_payload.3 b/man/io_uring_recvmsg_payload.3
deleted file mode 120000
index 8eb17436..00000000
--- a/man/io_uring_recvmsg_payload.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_recvmsg_out.3
\ No newline at end of file
diff --git a/man/io_uring_recvmsg_payload_length.3 b/man/io_uring_recvmsg_payload_length.3
deleted file mode 120000
index 8eb17436..00000000
--- a/man/io_uring_recvmsg_payload_length.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_recvmsg_out.3
\ No newline at end of file
diff --git a/man/io_uring_recvmsg_validate.3 b/man/io_uring_recvmsg_validate.3
deleted file mode 120000
index 8eb17436..00000000
--- a/man/io_uring_recvmsg_validate.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_recvmsg_out.3
\ No newline at end of file
diff --git a/man/io_uring_register.2 b/man/io_uring_register.2
deleted file mode 100644
index 1b36ce1f..00000000
--- a/man/io_uring_register.2
+++ /dev/null
@@ -1,1375 +0,0 @@
-.\" Copyright (C) 2019 Jens Axboe <axboe@kernel.dk>
-.\" Copyright (C) 2019 Red Hat, Inc.
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_register 2 "January 17, 2019" "Linux" "Linux Programmer's Manual"
-.SH NAME
-io_uring_register \- register files or user buffers for asynchronous I/O
-.SH SYNOPSIS
-.nf
-.BR "#include <liburing.h>"
-.PP
-.BI "int io_uring_register(unsigned int " fd ", unsigned int " opcode ,
-.BI " void *" arg ", unsigned int " nr_args );
-.fi
-.PP
-.SH DESCRIPTION
-.PP
-
-The
-.BR io_uring_register (2)
-system call registers resources (e.g. user buffers, files, eventfd,
-personality, restrictions) for use in an
-.BR io_uring (7)
-instance referenced by
-.IR fd .
-Registering files or user buffers allows the kernel to take long term
-references to internal data structures or create long term mappings of
-application memory, greatly reducing per-I/O overhead.
-
-.I fd
-is the file descriptor returned by a call to
-.BR io_uring_setup (2).
-If
-.I opcode
-has the flag
-.B IORING_REGISTER_USE_REGISTERED_RING
-ored into it,
-.I fd
-is instead the index of a registered ring fd.
-
-.I opcode
-can be one of:
-
-.TP
-.B IORING_REGISTER_BUFFERS
-.I arg
-points to a
-.I struct iovec
-array of
-.I nr_args
-entries. The buffers associated with the iovecs will be locked in
-memory and charged against the user's
-.B RLIMIT_MEMLOCK
-resource limit. See
-.BR getrlimit (2)
-for more information. Additionally, there is a size limit of 1GiB per
-buffer. Currently, the buffers must be anonymous, non-file-backed
-memory, such as that returned by
-.BR malloc (3)
-or
-.BR mmap (2)
-with the
-.B MAP_ANONYMOUS
-flag set. It is expected that this limitation will be lifted in the
-future. Huge pages are supported as well. Note that the entire huge
-page will be pinned in the kernel, even if only a portion of it is
-used.
-
-After a successful call, the supplied buffers are mapped into the
-kernel and eligible for I/O. To make use of them, the application
-must specify the
-.B IORING_OP_READ_FIXED
-or
-.B IORING_OP_WRITE_FIXED
-opcodes in the submission queue entry (see the
-.I struct io_uring_sqe
-definition in
-.BR io_uring_enter (2)),
-and set the
-.I buf_index
-field to the desired buffer index. The memory range described by the
-submission queue entry's
-.I addr
-and
-.I len
-fields must fall within the indexed buffer.
-
-It is perfectly valid to setup a large buffer and then only use part
-of it for an I/O, as long as the range is within the originally mapped
-region.
-
-An application can increase or decrease the size or number of
-registered buffers by first unregistering the existing buffers, and
-then issuing a new call to
-.BR io_uring_register (2)
-with the new buffers.
-
-Note that before 5.13 registering buffers would wait for the ring to idle.
-If the application currently has requests in-flight, the registration will
-wait for those to finish before proceeding.
-
-An application need not unregister buffers explicitly before shutting
-down the io_uring instance. Note, however, that shutdown processing may run
-asynchronously within the kernel. As a result, it is not guaranteed that
-pages are immediately unpinned in this case. Available since 5.1.
-
-.TP
-.B IORING_REGISTER_BUFFERS2
-Register buffers for I/O. Similar to
-.B IORING_REGISTER_BUFFERS
-but aims to have a more extensible ABI.
-
-.I arg
-points to a
-.I struct
-.IR io_uring_rsrc_register ,
-and
-.I nr_args
-should be set to the number of bytes in the structure.
-
-.IP
-.in +4n
-.EX
-struct io_uring_rsrc_register {
- __u32 nr;
- __u32 flags;
- __u64 resv2;
- __aligned_u64 data;
- __aligned_u64 tags;
-};
-.EE
-.in
-.IP
-
-The
-.I data
-field contains a pointer to a
-.I struct iovec
-array of
-.I nr
-entries.
-The
-.I tags
-field should either be 0, then tagging is disabled, or point to an array
-of
-.I nr
-"tags" (unsigned 64 bit integers). If a tag is zero, then tagging for this
-particular resource (a buffer in this case) is disabled. Otherwise, after the
-resource had been unregistered and it's not used anymore, a CQE will be
-posted with
-.I user_data
-set to the specified tag and all other fields zeroed.
-
-The
-.I flags
-field supports the following flags:
-
-.IP
-.in +4n
-.B IORING_RSRC_REGISTER_SPARSE
-If set, io_uring will register
-.I nr
-empty buffers, which need to be updated before use. When this flag is set,
-.I data
-and
-.I tags
-must be NULL. Available since 5.19.
-.in
-.IP
-
-Note that resource updates, e.g.
-.BR IORING_REGISTER_BUFFERS_UPDATE ,
-don't necessarily deallocate resources by the time it returns, but they might
-be held alive until all requests using it complete.
-
-Available since 5.13.
-
-.TP
-.B IORING_REGISTER_BUFFERS_UPDATE
-Updates registered buffers with new ones, either turning a sparse entry into
-a real one, or replacing an existing entry.
-
-.I arg
-must contain a pointer to a
-.I struct
-.IR io_uring_rsrc_update2 ,
-which contains
-an offset on which to start the update, and an array of
-.I struct
-.IR iovec .
-.I tags
-points to an array of tags.
-.I nr
-must contain the number of descriptors in the passed in arrays.
-See
-.B IORING_REGISTER_BUFFERS2
-for the resource tagging description.
-
-.PP
-.in +8n
-.EX
-
-struct io_uring_rsrc_update2 {
- __u32 offset;
- __u32 resv;
- __aligned_u64 data;
- __aligned_u64 tags;
- __u32 nr;
- __u32 resv2;
-};
-.EE
-.in
-.PP
-
-.in +8n
-
-Available since 5.13.
-
-.TP
-.B IORING_UNREGISTER_BUFFERS
-This operation takes no argument, and
-.I arg
-must be passed as NULL. All previously registered buffers associated
-with the io_uring instance will be released synchronously. Available since 5.1.
-
-.TP
-.B IORING_REGISTER_FILES
-Register files for I/O.
-.I arg
-contains a pointer to an array of
-.I nr_args
-file descriptors (signed 32 bit integers).
-
-To make use of the registered files, the
-.B IOSQE_FIXED_FILE
-flag must be set in the
-.I flags
-member of the
-.IR "struct io_uring_sqe" ,
-and the
-.I fd
-member is set to the index of the file in the file descriptor array.
-
-The file set may be sparse, meaning that the
-.B fd
-field in the array may be set to
-.BR -1 .
-See
-.B IORING_REGISTER_FILES_UPDATE
-for how to update files in place.
-
-Note that before 5.13 registering files would wait for the ring to idle.
-If the application currently has requests in-flight, the registration will
-wait for those to finish before proceeding. See
-.B IORING_REGISTER_FILES_UPDATE
-for how to update an existing set without that limitation.
-
-Files are automatically unregistered when the io_uring instance is
-torn down. An application needs only unregister if it wishes to
-register a new set of fds. Available since 5.1.
-
-.TP
-.B IORING_REGISTER_FILES2
-Register files for I/O. Similar to
-.BR IORING_REGISTER_FILES .
-
-.I arg
-points to a
-.I struct
-.IR io_uring_rsrc_register ,
-and
-.I nr_args
-should be set to the number of bytes in the structure.
-
-The
-.I data
-field contains a pointer to an array of
-.I nr
-file descriptors (signed 32 bit integers).
-.I tags
-field should either be 0 or or point to an array of
-.I nr
-"tags" (unsigned 64 bit integers). See
-.B IORING_REGISTER_BUFFERS2
-for more info on resource tagging.
-
-Note that resource updates, e.g.
-.BR IORING_REGISTER_FILES_UPDATE ,
-don't necessarily deallocate resources, they might be held until all requests
-using that resource complete.
-
-Available since 5.13.
-
-.TP
-.B IORING_REGISTER_FILES_UPDATE
-This operation replaces existing files in the registered file set with new
-ones, either turning a sparse entry (one where fd is equal to
-.BR -1 )
-into a real one, removing an existing entry (new one is set to
-.BR -1 ),
-or replacing an existing entry with a new existing entry.
-
-.I arg
-must contain a pointer to a
-.I struct
-.IR io_uring_rsrc_update ,
-which contains
-an offset on which to start the update, and an array of file descriptors to
-use for the update.
-.I nr_args
-must contain the number of descriptors in the passed in array. Available
-since 5.5.
-
-File descriptors can be skipped if they are set to
-.BR IORING_REGISTER_FILES_SKIP .
-Skipping an fd will not touch the file associated with the previous
-fd at that index. Available since 5.12.
-
-.TP
-.B IORING_REGISTER_FILES_UPDATE2
-Similar to
-.BR IORING_REGISTER_FILES_UPDATE ,
-replaces existing files in the
-registered file set with new ones, either turning a sparse entry (one where
-fd is equal to
-.BR -1 )
-into a real one, removing an existing entry (new one is set to
-.BR -1 ),
-or replacing an existing entry with a new existing entry.
-
-.I arg
-must contain a pointer to a
-.I struct
-.IR io_uring_rsrc_update2 ,
-which contains
-an offset on which to start the update, and an array of file descriptors to
-use for the update stored in
-.IR data .
-.I tags
-points to an array of tags.
-.I nr
-must contain the number of descriptors in the passed in arrays.
-See
-.B IORING_REGISTER_BUFFERS2
-for the resource tagging description.
-
-Available since 5.13.
-
-.TP
-.B IORING_UNREGISTER_FILES
-This operation requires no argument, and
-.I arg
-must be passed as NULL. All previously registered files associated
-with the io_uring instance will be unregistered. Available since 5.1.
-
-.TP
-.B IORING_REGISTER_EVENTFD
-It's possible to use
-.BR eventfd (2)
-to get notified of completion events on an
-io_uring instance. If this is desired, an eventfd file descriptor can be
-registered through this operation.
-.I arg
-must contain a pointer to the eventfd file descriptor, and
-.I nr_args
-must be 1. Note that while io_uring generally takes care to avoid spurious
-events, they can occur. Similarly, batched completions of CQEs may only trigger
-a single eventfd notification even if multiple CQEs are posted. The application
-should make no assumptions on number of events being available having a direct
-correlation to eventfd notifications posted. An eventfd notification must thus
-only be treated as a hint to check the CQ ring for completions. Available since
-5.2.
-
-An application can temporarily disable notifications, coming through the
-registered eventfd, by setting the
-.B IORING_CQ_EVENTFD_DISABLED
-bit in the
-.I flags
-field of the CQ ring.
-Available since 5.8.
-
-.TP
-.B IORING_REGISTER_EVENTFD_ASYNC
-This works just like
-.BR IORING_REGISTER_EVENTFD ,
-except notifications are only posted for events that complete in an async
-manner. This means that events that complete inline while being submitted
-do not trigger a notification event. The arguments supplied are the same as
-for
-.BR IORING_REGISTER_EVENTFD .
-Available since 5.6.
-
-.TP
-.B IORING_UNREGISTER_EVENTFD
-Unregister an eventfd file descriptor to stop notifications. Since only one
-eventfd descriptor is currently supported, this operation takes no argument,
-and
-.I arg
-must be passed as NULL and
-.I nr_args
-must be zero. Available since 5.2.
-
-.TP
-.B IORING_REGISTER_PROBE
-This operation returns a structure, io_uring_probe, which contains information
-about the opcodes supported by io_uring on the running kernel.
-.I arg
-must contain a pointer to a struct io_uring_probe, and
-.I nr_args
-must contain the size of the ops array in that probe struct. The ops array
-is of the type io_uring_probe_op, which holds the value of the opcode and
-a flags field. If the flags field has
-.B IO_URING_OP_SUPPORTED
-set, then this opcode is supported on the running kernel. Available since 5.6.
-
-.TP
-.B IORING_REGISTER_PERSONALITY
-This operation registers credentials of the running application with io_uring,
-and returns an id associated with these credentials. Applications wishing to
-share a ring between separate users/processes can pass in this credential id
-in the sqe
-.B personality
-field. If set, that particular sqe will be issued with these credentials. Must
-be invoked with
-.I arg
-set to NULL and
-.I nr_args
-set to zero. Available since 5.6.
-
-.TP
-.B IORING_UNREGISTER_PERSONALITY
-This operation unregisters a previously registered personality with io_uring.
-.I nr_args
-must be set to the id in question, and
-.I arg
-must be set to NULL. Available since 5.6.
-
-.TP
-.B IORING_REGISTER_ENABLE_RINGS
-This operation enables an io_uring ring started in a disabled state
-.RB ( IORING_SETUP_R_DISABLED
-was specified in the call to
-.BR io_uring_setup (2)).
-While the io_uring ring is disabled, submissions are not allowed and
-registrations are not restricted.
-
-After the execution of this operation, the io_uring ring is enabled:
-submissions and registration are allowed, but they will
-be validated following the registered restrictions (if any).
-This operation takes no argument, must be invoked with
-.I arg
-set to NULL and
-.I nr_args
-set to zero. Available since 5.10.
-
-.TP
-.B IORING_REGISTER_RESTRICTIONS
-.I arg
-points to a
-.I struct io_uring_restriction
-array of
-.I nr_args
-entries.
-
-With an entry it is possible to allow an
-.BR io_uring_register (2)
-.IR opcode ,
-or specify which
-.I opcode
-and
-.I flags
-of the submission queue entry are allowed,
-or require certain
-.I flags
-to be specified (these flags must be set on each submission queue entry).
-
-All the restrictions must be submitted with a single
-.BR io_uring_register (2)
-call and they are handled as an allowlist (opcodes and flags not registered,
-are not allowed).
-
-Restrictions can be registered only if the io_uring ring started in a disabled
-state
-.RB ( IORING_SETUP_R_DISABLED
-must be specified in the call to
-.BR io_uring_setup (2)).
-
-Available since 5.10.
-
-.TP
-.B IORING_REGISTER_IOWQ_AFF
-By default, async workers created by io_uring will inherit the CPU mask of its
-parent. This is usually all the CPUs in the system, unless the parent is being
-run with a limited set. If this isn't the desired outcome, the application
-may explicitly tell io_uring what CPUs the async workers may run on.
-.I arg
-must point to a
-.B cpu_set_t
-mask, and
-.I nr_args
-the byte size of that mask.
-
-Available since 5.14.
-
-.TP
-.B IORING_UNREGISTER_IOWQ_AFF
-Undoes a CPU mask previously set with
-.BR IORING_REGISTER_IOWQ_AFF .
-Must not have
-.I arg
-or
-.I nr_args
-set.
-
-Available since 5.14.
-
-.TP
-.B IORING_REGISTER_IOWQ_MAX_WORKERS
-By default, io_uring limits the unbounded workers created to the maximum
-processor count set by
-.I RLIMIT_NPROC
-and the bounded workers is a function of the SQ ring size and the number
-of CPUs in the system. Sometimes this can be excessive (or too little, for
-bounded), and this command provides a way to change the count per ring (per NUMA
-node) instead.
-
-.I arg
-must be set to an
-.I unsigned int
-pointer to an array of two values, with the values in the array being set to
-the maximum count of workers per NUMA node. Index 0 holds the bounded worker
-count, and index 1 holds the unbounded worker count. On successful return, the
-passed in array will contain the previous maximum values for each type. If the
-count being passed in is 0, then this command returns the current maximum values
-and doesn't modify the current setting.
-.I nr_args
-must be set to 2, as the command takes two values.
-
-Available since 5.15.
-
-.TP
-.B IORING_REGISTER_RING_FDS
-Whenever
-.BR io_uring_enter (2)
-is called to submit request or wait for completions, the kernel must grab a
-reference to the file descriptor. If the application using io_uring is threaded,
-the file table is marked as shared, and the reference grab and put of the file
-descriptor count is more expensive than it is for a non-threaded application.
-
-Similarly to how io_uring allows registration of files, this allow registration
-of the ring file descriptor itself. This reduces the overhead of the
-.BR io_uring_enter (2)
-system call.
-
-.I arg
-must be set to a pointer to an array of type
-.I struct io_uring_rsrc_update
-of
-.I nr_args
-number of entries. The
-.B data
-field of this struct must contain an io_uring file descriptor, and the
-.B offset
-field can be either
-.B -1
-or an explicit offset desired for the registered file descriptor value. If
-.B -1
-is used, then upon successful return of this system call, the field will
-contain the value of the registered file descriptor to be used for future
-.BR io_uring_enter (2)
-system calls.
-
-On successful completion of this request, the returned descriptors may be used
-instead of the real file descriptor for
-.BR io_uring_enter (2),
-provided that
-.B IORING_ENTER_REGISTERED_RING
-is set in the
-.I flags
-for the system call. This flag tells the kernel that a registered descriptor
-is used rather than a real file descriptor.
-
-Each thread or process using a ring must register the file descriptor directly
-by issuing this request.
-
-The maximum number of supported registered ring descriptors is currently
-limited to
-.B 16.
-
-Available since 5.18.
-
-.TP
-.B IORING_UNREGISTER_RING_FDS
-Unregister descriptors previously registered with
-.BR IORING_REGISTER_RING_FDS .
-
-.I arg
-must be set to a pointer to an array of type
-.I struct io_uring_rsrc_update
-of
-.I nr_args
-number of entries. Only the
-.B offset
-field should be set in the structure, containing the registered file descriptor
-offset previously returned from
-.B IORING_REGISTER_RING_FDS
-that the application wishes to unregister.
-
-Note that this isn't done automatically on ring exit, if the thread or task
-that previously registered a ring file descriptor isn't exiting. It is
-recommended to manually unregister any previously registered ring descriptors
-if the ring is closed and the task persists. This will free up a registration
-slot, making it available for future use.
-
-Available since 5.18.
-
-.TP
-.B IORING_REGISTER_PBUF_RING
-Registers a shared buffer ring to be used with provided buffers. This is a
-newer alternative to using
-.B IORING_OP_PROVIDE_BUFFERS
-which is more efficient, to be used with request types that support the
-.B IOSQE_BUFFER_SELECT
-flag.
-
-The
-.I arg
-argument must be filled in with the appropriate information. It looks as
-follows:
-.PP
-.in +12n
-.EX
-struct io_uring_buf_reg {
- __u64 ring_addr;
- __u32 ring_entries;
- __u16 bgid;
- __u16 flags;
- __u32 min_left;
- __u32 resv[5];
-};
-.EE
-.in
-.PP
-.in +8n
-The
-.I ring_addr
-field must contain the address to the memory allocated to fit this ring.
-The memory must be page aligned and hence allocated appropriately using eg
-.BR posix_memalign (3)
-or similar. The size of the ring is the product of
-.I ring_entries
-and the size of
-.IR "struct io_uring_buf" .
-.I ring_entries
-is the desired size of the ring, and must be a power-of-2 in size. The maximum
-size allowed is 2^15 (32768).
-.I bgid
-is the buffer group ID associated with this ring. SQEs that select a buffer
-have a buffer group associated with them in their
-.I buf_group
-field, and the associated CQEs will have
-.B IORING_CQE_F_BUFFER
-set in their
-.I flags
-member, which will also contain the specific ID of the buffer selected.
-.I min_left
-is the minimum value that should be left in an incrementally consumed buffer
-ring for the buffer to be considered valid. If not set, defaults to a single
-byte. Only valid with
-.B IOU_PBUF_RING_INC
-set in
-.I flags .
-The rest of the fields are reserved and must be cleared to zero.
-
-.I nr_args
-must be set to 1.
-
-Also see
-.BR io_uring_register_buf_ring (3)
-for more details. Available since 5.19.
-
-.TP
-.B IORING_UNREGISTER_PBUF_RING
-Unregister a previously registered provided buffer ring.
-.I arg
-must be set to the address of a struct io_uring_buf_reg, with just the
-.I bgid
-field set to the buffer group ID of the previously registered provided buffer
-group.
-.I nr_args
-must be set to 1. Also see
-.BR IORING_REGISTER_PBUF_RING .
-
-Available since 5.19.
-
-.TP
-.B IORING_REGISTER_SYNC_CANCEL
-Performs a synchronous cancelation request, which works in a similar fashion to
-.B IORING_OP_ASYNC_CANCEL
-except it completes inline. This can be useful for scenarios where cancelations
-should happen synchronously, rather than needing to issue an SQE and wait for
-completion of that specific CQE.
-
-.I arg
-must be set to a pointer to a struct io_uring_sync_cancel_reg structure, with
-the details filled in for what request(s) to target for cancelation. See
-.BR io_uring_register_sync_cancel (3)
-for details on that. The return values are the same, except they are passed
-back synchronously rather than through the CQE
-.I res
-field.
-.I nr_args
-must be set to 1.
-
-Available since 6.0.
-
-.TP
-.B IORING_REGISTER_FILE_ALLOC_RANGE
-sets the allowable range for fixed file index allocations within the
-kernel. When requests that can instantiate a new fixed file are used with
-.BR IORING_FILE_INDEX_ALLOC ,
-the application is asking the kernel to allocate a new fixed file descriptor
-rather than pass in a specific value for one. By default, the kernel will
-pick any available fixed file descriptor within the range available.
-This effectively allows the application to set aside a range just for dynamic
-allocations, with the remainder being used for specific values.
-
-.I nr_args
-must be set to 1 and
-.I arg
-must be set to a pointer to a struct io_uring_file_index_range:
-.PP
-.in +12n
-.EX
-struct io_uring_file_index_range {
- __u32 off;
- __u32 len;
- __u64 resv;
-};
-.EE
-.in
-.PP
-.in +8n
-with
-.I off
-being set to the starting value for the range, and
-.I len
-being set to the number of descriptors. The reserved
-.I resv
-field must be cleared to zero.
-
-The application must have registered a file table first.
-
-Available since 6.0.
-
-.TP
-.B IORING_REGISTER_PBUF_STATUS
-Can be used to retrieve the current head of a ringbuffer provided earlier via
-.BR IORING_REGISTER_PBUF_RING .
-.I arg
-must point to a
-.PP
-.in +12
-.EX
-struct io_uring_buf_status {
- __u32 buf_group; /* input */
- __u32 head; /* output */
- __u32 resv[8];
-};
-.EE
-.in
-.PP
-.in +8
-of which
-.I arg->buf_group
-should contain the buffer group ID for the buffer ring in question,
-.I nr_args
-should be set to 1 and
-.I arg->resv
-should be zeroed out.
-The current head of the ringbuffer will be returned in
-.IR arg->head .
-
-Available since 6.8.
-
-.TP
-.B IORING_REGISTER_NAPI
-Registers a napi instance with the io_uring instance of
-.IR fd .
-.I arg
-should point to a
-.PP
-.in +12
-.EX
-struct io_uring_napi {
- __u32 busy_poll_to;
- __u8 prefer_busy_poll;
- __u8 pad[3];
- __u64 resv;
-};
-.EE
-.in
-.PP
-.in +8
-in which
-.I arg->busy_poll_to
-should contain the busy poll timeout in micro seconds and
-.I arg->prefer_busy_poll
-should specify whether busy polling should be used rather than IRQs.
-.I nr_args
-should be set to 1 and
-.I arg->pad
-and
-.I arg->resv
-should be zeroed out.
-On successful return the
-.I io_uring_napi
-struct pointed to by
-.I arg
-will contain the previously used settings.
-
-Available since 6.9.
-
-.TP
-.B IORING_UNREGISTER_NAPI
-Unregisters a napi instance previously registered via
-.B IORING_REGISTER_NAPI
-to the io_uring instance of
-.IR fd .
-.I arg
-should point to a
-.I struct
-.IR io_uring_napi .
-On successful return the
-.I io_uring_napi
-struct pointed to by
-.I arg
-will contain the previously used settings.
-
-Available since 6.9.
-
-.TP
-.B IORING_REGISTER_CLOCK
-Specifies which clock id io_uring will use for timers while waiting for
-completion events with
-.BR IORING_ENTER_GETEVENTS .
-It's only effective if the timeout argument in
-.I struct io_uring_getevents_arg
-is passed, ignored otherwise.
-When used in conjunction with
-.BR IORING_ENTER_ABS_TIMER ,
-interprets the timeout argument as absolute time of the specified clock.
-
-The default clock is
-.BR CLOCK_MONOTONIC .
-
-Available since 6.12 and supports
-.B CLOCK_MONOTONIC
-and
-.BR CLOCK_BOOTTIME .
-
-.TP
-.B IORING_REGISTER_CLONE_BUFFERS
-Supports cloning buffers from a source ring to a destination ring, duplicating
-previously registered buffers from source to destination.
-.IR arg
-must be set to a pointer to a
-.I struct io_uring_clone_buffers
-and
-.IR nr_args
-must be set to
-.B 1 .
-.I struct io_uring_buf_reg
-looks as follows:
-.PP
-.in +12n
-.EX
-struct io_uring_clone_buffers {
- __u32 src_fd;
- __u32 flags;
- __u32 src_off;
- __u32 dst_off;
- __u32 nr;
- __u32 pad[3];
-};
-.EE
-.in
-.TP
-.PP
-where
-.IR src_fd
-indicates the fd of the source ring,
-.IR flags
-are modifier flags for the operation,
-.IR src_off
-indicates the offset from where to start the cloning from the source ring,
-.IR dst_off
-indicates the offset from where to start the cloning into the destination ring,
-and
-.IR nr
-indicates the number of buffers to clone at the given offsets.
-.IR pad
-must be zero filled.
-Kernel 6.12 added support for full range cloning, where
-.IR src_off ,
-.IR dst_off ,
-and
-.IR nr
-must all be set to 0, indicating cloning of the entire table in source to
-destination. Kernel 6.13 added support for specifying the offsets and
-how many buffers to clone. Additionally, it added support for cloning into
-a previously registered table in the destination as well, 6.12 would fail
-that operation with
-.B -EBUSY
-if attempted. To replace existing nodes, or clone into an existing table,
-.B IORING_REGISTER_DST_REPLACE
-must be set in the
-.IR flags
-member.
-
-.TP
-.B IORING_REGISTER_SEND_MSG_RING
-Supports sending of the equivalent of a
-.B IORING_OP_MSG_RING
-request, but without having a source ring available. Takes a pointer to a
-.IR struct io_uring_sqe
-which must be prepared with
-.BR io_uring_prep_msg_ring (3)
-before being submitted. Only supports
-.B IORING_MSG_DATA
-type of requests. Available since kernel 6.13.
-
-.TP
-.B IORING_REGISTER_RESIZE_RINGS
-Supports resizing the SQ and CQ rings. Takes a pointer to a
-.IR struct io_uring_params
-as the argument, where
-.IR sq_entries
-and
-.IR cq_entries
-may be set to the desired values. Only supports a limited set of flags set
-in the
-.IR struct io_uring_params
-argument, notably
-.B IORING_SETUP_CQSIZE
-and
-.B IORING_SETUP_CLAMP
-to modify the CQ ring sizing. See
-.BR io_uring_resize_rings (3)
-for details. Note that while liburing takes care of the ring unmap and mapping
-for a resize operation, manual users of this register syscall must perform
-those operations, similarly to when a new ring is created. The
-.IR struct io_uring_params
-structure will get the necessary offsets copied back upon successful completion
-of this system call, which can be used to memory map the ring just like how
-a new ring would've been mapped. Available since kernel 6.13.
-
-.TP
-.B IORING_REGISTER_MEM_REGION
-Supports registering multiple purposes memory regions, avoiding unnecessary
-copying in of
-.IR struct io_uring_getevents_arg
-for wait operations that specify a timeout or minimum timeout. Takes a pointer
-to a
-.IR struct io_uring_mem_region_reg
-structure, which looks as follows:
-.PP
-.in +12n
-.EX
-struct io_uring_mem_region_reg {
- __u64 region_uptr;
- __u64 flags;
- __u64 __resv[2];
-};
-.EE
-.in
-.TP
-.PP
-where
-.IR region_uptr
-must be set to the region being registered as memory regions,
-.IR flags
-specifies modifier flags (must currently be
-.B IORING_MEM_REGION_REG_WAIT_ARG ). The pad fields must all be cleared to
-.B 0 .
-Each memory regions looks as follows:
-.PP
-.in +12n
-.EX
-struct io_uring_region_desc {
- __u64 user_addr;
- __u64 size;
- __u32 flags;
- __u32 id;
- __u64 mmap_offset;
- __u64 __resv[4];
-};
-.EE
-.in
-.TP
-.PP
-where
-.IR user_addr
-points to userspace memory mappings,
-.IR size
-is the size of userspace memory. Current supported userspace memory regions
-looks as follows:
-.PP
-.in +12n
-.EX
-struct io_uring_reg_wait {
- struct __kernel_timespec ts;
- __u32 min_wait_usec;
- __u32 flags;
- __u64 sigmask;
- __u32 sigmask_sz;
- __u32 pad[3];
- __u64 pad2[2];
-};
-.EE
-.in
-.TP
-.PP
-where
-.IR ts
-holds the timeout information for this region
-.IR flags
-holds information about the timeout region,
-.IR sigmask
-is a pointer to a signal mask, if used, and
-.IR sigmask_sz
-is the size of that signal mask. The pad fields must all be cleared to
-.B 0 .
-Currently the only valid flag is
-.B IORING_REG_WAIT_TS ,
-which, if set, says that the values in
-.IR ts
-are valid and should be used for a timeout operation. The
-.IR user_addr
-field of
-.IR struct io_uring_region_desc
-must be set to an address of
-.IR struct io_uring_reg_wait
-members, an up to a page size can be mapped. At the size of 64 bytes per
-region, that allows at least 64 individual regions on a 4k page size system.
-The offsets of these regions are used for an
-.BR io_uring_enter (2)
-system call, with the first one being 0, second one 1, and so forth. After
-registration of the wait regions,
-.BR io_uring_enter (2)
-may be used with the enter flag of
-.B IORING_ENTER_EXT_ARG_REG and an
-.IR argp
-set to the wait region offset, rather than a pointer to a
-.IR struct io_uring_getevent_arg
-structure. If used with
-.B IORING_ENTER_GETEVENTS ,
-then the wait operation will use the information in the registered wait
-region rather than needing a io_uring_getevent_arg structure copied for each
-operation. For high frequency waits, this can save considerable CPU cycles.
-Note: once a region has been registered, it cannot get unregistered. It lives
-for the life of the ring. Individual wait region offset may be modified before
-any
-.BR io_uring_enter (2)
-system call. Available since kernel 6.13.
-
-.TP
-.B IORING_REGISTER_ZCRX_IFQ
-Registers a zero-copy receive interface queue for network receive operations.
-Zero-copy receive allows the kernel to place incoming network data directly
-into application-provided memory without copying, reducing CPU overhead for
-high-bandwidth network workloads.
-.I arg
-must point to a
-.I struct io_uring_zcrx_ifq_reg
-structure, and
-.I nr_args
-must be set to 1.
-.PP
-.in +12n
-.EX
-struct io_uring_zcrx_ifq_reg {
- __u32 if_idx;
- __u32 if_rxq;
- __u32 rq_entries;
- __u32 flags;
- __u64 area_ptr;
- __u64 region_ptr;
- struct io_uring_zcrx_offsets offsets;
- __u32 zcrx_id;
- __u32 __resv2;
- __u64 __resv[3];
-};
-.EE
-.in
-.PP
-.in +8n
-where
-.I if_idx
-is the network interface index,
-.I if_rxq
-is the receive queue index,
-.I rq_entries
-is the number of entries in the refill queue (will be rounded up to a power
-of two),
-.I flags
-contains modifier flags,
-.I area_ptr
-points to a
-.I struct io_uring_zcrx_area_reg
-describing the memory area to use,
-.I region_ptr
-points to a
-.I struct io_uring_region_desc
-describing the memory region, and upon successful return
-.I zcrx_id
-will contain the ID of the registered zero-copy receive context.
-The
-.I offsets
-field is filled in by the kernel and contains the ring offsets for the refill
-queue.
-
-The io_uring ring must have been created with
-.B IORING_SETUP_DEFER_TASKRUN
-and either
-.B IORING_SETUP_CQE32
-or
-.B IORING_SETUP_CQE_MIXED
-flags set. The caller must have the
-.B CAP_NET_ADMIN
-capability.
-
-Available since kernel 6.15.
-
-.TP
-.B IORING_REGISTER_QUERY
-Queries io_uring capabilities and feature support. This operation does not
-require an io_uring ring and can be called with
-.I fd
-set to -1. It provides information about supported opcodes, flags, and
-subsystem-specific capabilities.
-.I arg
-must point to a
-.I struct io_uring_query_hdr
-and
-.I nr_args
-must be 0.
-.PP
-.in +12n
-.EX
-struct io_uring_query_hdr {
- __u64 next_entry;
- __u64 query_data;
- __u32 query_op;
- __u32 size;
- __s32 result;
- __u32 __resv[3];
-};
-.EE
-.in
-.PP
-.in +8n
-Multiple queries can be chained together via
-.I next_entry
-which points to the next
-.I struct io_uring_query_hdr
-(or 0 for the last entry).
-.I query_data
-points to a data structure appropriate for the query type.
-.I query_op
-specifies the query type and can be one of:
-.IP \[bu] 2
-.B IO_URING_QUERY_OPCODES
-\- Returns information about supported opcodes and flags in a
-.I struct io_uring_query_opcode
-.IP \[bu]
-.B IO_URING_QUERY_ZCRX
-\- Returns information about zero-copy receive support in a
-.I struct io_uring_query_zcrx
-.IP \[bu]
-.B IO_URING_QUERY_SCQ
-\- Returns information about the SQ/CQ ring layout in a
-.I struct io_uring_query_scq
-.PP
-.in +8n
-.I size
-should be set to the size of the data structure pointed to by
-.IR query_data .
-Upon return,
-.I result
-will be 0 on success, or a negative error code.
-
-Available since kernel 6.15.
-
-.TP
-.B IORING_REGISTER_ZCRX_CTRL
-Performs control operations on a previously registered zero-copy receive
-context.
-.I arg
-must point to a
-.I struct zcrx_ctrl
-and
-.I nr_args
-must be 0.
-.PP
-.in +12n
-.EX
-struct zcrx_ctrl {
- __u32 zcrx_id;
- __u32 op;
- __u64 __resv[2];
- union {
- struct zcrx_ctrl_export zc_export;
- struct zcrx_ctrl_flush_rq zc_flush;
- };
-};
-.EE
-.in
-.PP
-.in +8n
-where
-.I zcrx_id
-is the ID of the zero-copy receive context returned from
-.BR IORING_REGISTER_ZCRX_IFQ ,
-and
-.I op
-specifies the control operation:
-.IP \[bu] 2
-.B ZCRX_CTRL_FLUSH_RQ
-\- Flushes pending buffers from the refill queue
-.IP \[bu]
-.B ZCRX_CTRL_EXPORT
-\- Exports the zero-copy receive context for use by other rings
-
-Available since kernel 6.15.
-
-.SH RETURN VALUE
-On success,
-.BR io_uring_register (2)
-returns either 0 or a positive value, depending on the
-.I opcode
-used. On error, a negative error value is returned. The caller should not rely
-on the
-.I errno
-variable.
-
-.SH ERRORS
-.TP
-.B EACCES
-The
-.I opcode
-field is not allowed due to registered restrictions.
-.TP
-.B EBADF
-One or more fds in the
-.I fd
-array are invalid.
-.TP
-.B EBADFD
-.B IORING_REGISTER_ENABLE_RINGS
-or
-.B IORING_REGISTER_RESTRICTIONS
-was specified, but the io_uring ring is not disabled.
-.TP
-.B EBUSY
-.B IORING_REGISTER_BUFFERS
-or
-.B IORING_REGISTER_FILES
-or
-.B IORING_REGISTER_RESTRICTIONS
-was specified, but there were already buffers, files, or restrictions
-registered.
-.TP
-.B EEXIST
-The thread performing the registration is invalid.
-.TP
-.B EFAULT
-buffer is outside of the process' accessible address space, or
-.I iov_len
-is greater than 1GiB.
-.TP
-.B EINVAL
-.B IORING_REGISTER_BUFFERS
-or
-.B IORING_REGISTER_FILES
-was specified, but
-.I nr_args
-is 0.
-.TP
-.B EINVAL
-.B IORING_REGISTER_BUFFERS
-was specified, but
-.I nr_args
-exceeds
-.B UIO_MAXIOV
-.TP
-.B EINVAL
-.B IORING_UNREGISTER_BUFFERS
-or
-.B IORING_UNREGISTER_FILES
-was specified, and
-.I nr_args
-is non-zero or
-.I arg
-is non-NULL.
-.TP
-.B EINVAL
-.B IORING_REGISTER_RESTRICTIONS
-was specified, but
-.I nr_args
-exceeds the maximum allowed number of restrictions or restriction
-.I opcode
-is invalid.
-.TP
-.B EMFILE
-.B IORING_REGISTER_FILES
-was specified and
-.I nr_args
-exceeds the maximum allowed number of files in a fixed file set.
-.TP
-.B EMFILE
-.B IORING_REGISTER_FILES
-was specified and adding
-.I nr_args
-file references would exceed the maximum allowed number of files the user
-is allowed to have according to the
-.B RLIMIT_NOFILE
-resource limit and the caller does not have
-.B CAP_SYS_RESOURCE
-capability. Note that this is a per user limit, not per process.
-.TP
-.B ENOMEM
-Insufficient kernel resources are available, or the caller had a
-non-zero
-.B RLIMIT_MEMLOCK
-soft resource limit, but tried to lock more memory than the limit
-permitted. This limit is not enforced if the process is privileged
-.RB ( CAP_IPC_LOCK ).
-.TP
-.B ENXIO
-.B IORING_UNREGISTER_BUFFERS
-or
-.B IORING_UNREGISTER_FILES
-was specified, but there were no buffers or files registered.
-.TP
-.B ENXIO
-Attempt to register files or buffers on an io_uring instance that is already
-undergoing file or buffer registration, or is being torn down.
-.TP
-.B EOPNOTSUPP
-User buffers point to file-backed memory.
-.TP
-.B EFAULT
-User buffers point to file-backed memory (newer kernels).
-.TP
-.B ENOENT
-.B IORING_REGISTER_PBUF_STATUS
-was specified, but
-.I buf_group
-did not refer to a currently valid buffer group.
-.TP
-.B EINVAL
-.B IORING_REGISTER_PBUF_STATUS
-was specified, but the valid buffer group specified by
-.I buf_group
-did not refer to a buffer group registered via
-.BR IORING_REGISTER_PBUF_RING .
-.TP
-.B EINVAL
-.B IORING_REGISTER_NAPI
-was specified, but the ring associated with
-.I fd
-has not been created with
-.BR IORING_SETUP_IOPOLL .
diff --git a/man/io_uring_register.2.md b/man/io_uring_register.2.md
new file mode 100644
index 00000000..54219343
--- /dev/null
+++ b/man/io_uring_register.2.md
@@ -0,0 +1,553 @@
+.\" Copyright (C) 2019 Jens Axboe <axboe@kernel.dk>
+.\" Copyright (C) 2019 Red Hat, Inc.
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 17, 2019
+footer: Linux
+header: Linux Programmer\'s Manual
+section: 2
+title: io_uring_register
+---
+
+# NAME
+
+io_uring_register - register files or user buffers for asynchronous I/O
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_register(unsigned int fd , unsigned int opcode ,
+ void * arg , unsigned int nr_args );
+
+# DESCRIPTION
+
+The **io_uring_register**(2) system call registers resources (e.g. user buffers, files, eventfd, personality, restrictions) for use in an **io_uring**(7) instance referenced by *fd*. Registering files or user buffers allows the kernel to take long term references to internal data structures or create long term mappings of application memory, greatly reducing per-I/O overhead.
+
+*fd* is the file descriptor returned by a call to **io_uring_setup**(2). If *opcode* has the flag **IORING_REGISTER_USE_REGISTERED_RING** ored into it, *fd* is instead the index of a registered ring fd.
+
+*opcode* can be one of:
+
+**IORING_REGISTER_BUFFERS**
+
+: *arg* points to a *struct iovec* array of *nr_args* entries. The buffers associated with the iovecs will be locked in memory and charged against the user\'s **RLIMIT_MEMLOCK** resource limit. See **getrlimit**(2) for more information. Additionally, there is a size limit of 1GiB per buffer. Currently, the buffers must be anonymous, non-file-backed memory, such as that returned by **malloc**(3) or **mmap**(2) with the **MAP_ANONYMOUS** flag set. It is expected that this limitation will be lifted in the future. Huge pages are supported as well. Note that the entire huge page will be pinned in the kernel, even if only a portion of it is used.
+
+ After a successful call, the supplied buffers are mapped into the kernel and eligible for I/O. To make use of them, the application must specify the **IORING_OP_READ_FIXED** or **IORING_OP_WRITE_FIXED** opcodes in the submission queue entry (see the *struct io_uring_sqe* definition in **io_uring_enter**(2)), and set the *buf_index* field to the desired buffer index. The memory range described by the submission queue entry\'s *addr* and *len* fields must fall within the indexed buffer.
+
+ It is perfectly valid to setup a large buffer and then only use part of it for an I/O, as long as the range is within the originally mapped region.
+
+ An application can increase or decrease the size or number of registered buffers by first unregistering the existing buffers, and then issuing a new call to **io_uring_register**(2) with the new buffers.
+
+ Note that before 5.13 registering buffers would wait for the ring to idle. If the application currently has requests in-flight, the registration will wait for those to finish before proceeding.
+
+ An application need not unregister buffers explicitly before shutting down the io_uring instance. Note, however, that shutdown processing may run asynchronously within the kernel. As a result, it is not guaranteed that pages are immediately unpinned in this case. Available since 5.1.
+
+**IORING_REGISTER_BUFFERS2** Register buffers for I/O. Similar to **IORING_REGISTER_BUFFERS** but aims to have a more extensible ABI.
+
+*arg* points to a *struct* *io_uring_rsrc_register*, and *nr_args* should be set to the number of bytes in the structure.
+
+ struct io_uring_rsrc_register {
+ __u32 nr;
+ __u32 flags;
+ __u64 resv2;
+ __aligned_u64 data;
+ __aligned_u64 tags;
+ };
+
+The *data* field contains a pointer to a *struct iovec* array of *nr* entries. The *tags* field should either be 0, then tagging is disabled, or point to an array of *nr* \"tags\" (unsigned 64 bit integers). If a tag is zero, then tagging for this particular resource (a buffer in this case) is disabled. Otherwise, after the resource had been unregistered and it\'s not used anymore, a CQE will be posted with *user_data* set to the specified tag and all other fields zeroed.
+
+The *flags* field supports the following flags:
+
+**IORING_RSRC_REGISTER_SPARSE** If set, io_uring will register *nr* empty buffers, which need to be updated before use. When this flag is set, *data* and *tags* must be NULL. Available since 5.19.
+
+Note that resource updates, e.g. **IORING_REGISTER_BUFFERS_UPDATE**, don\'t necessarily deallocate resources by the time it returns, but they might be held alive until all requests using it complete.
+
+Available since 5.13.
+
+**IORING_REGISTER_BUFFERS_UPDATE**
+
+: Updates registered buffers with new ones, either turning a sparse entry into a real one, or replacing an existing entry.
+
+ *arg* must contain a pointer to a *struct* *io_uring_rsrc_update2*, which contains an offset on which to start the update, and an array of *struct* *iovec*. *tags* points to an array of tags. *nr* must contain the number of descriptors in the passed in arrays. See **IORING_REGISTER_BUFFERS2** for the resource tagging description.
+
+<!-- -->
+
+
+ struct io_uring_rsrc_update2 {
+ __u32 offset;
+ __u32 resv;
+ __aligned_u64 data;
+ __aligned_u64 tags;
+ __u32 nr;
+ __u32 resv2;
+ };
+
+Available since 5.13.
+
+**IORING_UNREGISTER_BUFFERS**
+
+: This operation takes no argument, and *arg* must be passed as NULL. All previously registered buffers associated with the io_uring instance will be released synchronously. Available since 5.1.
+
+**IORING_REGISTER_FILES**
+
+: Register files for I/O. *arg* contains a pointer to an array of *nr_args* file descriptors (signed 32 bit integers).
+
+ To make use of the registered files, the **IOSQE_FIXED_FILE** flag must be set in the *flags* member of the *struct io_uring_sqe*, and the *fd* member is set to the index of the file in the file descriptor array.
+
+ The file set may be sparse, meaning that the **fd** field in the array may be set to **-1**. See **IORING_REGISTER_FILES_UPDATE** for how to update files in place.
+
+ Note that before 5.13 registering files would wait for the ring to idle. If the application currently has requests in-flight, the registration will wait for those to finish before proceeding. See **IORING_REGISTER_FILES_UPDATE** for how to update an existing set without that limitation.
+
+ Files are automatically unregistered when the io_uring instance is torn down. An application needs only unregister if it wishes to register a new set of fds. Available since 5.1.
+
+**IORING_REGISTER_FILES2**
+
+: Register files for I/O. Similar to **IORING_REGISTER_FILES**.
+
+ *arg* points to a *struct* *io_uring_rsrc_register*, and *nr_args* should be set to the number of bytes in the structure.
+
+ The *data* field contains a pointer to an array of *nr* file descriptors (signed 32 bit integers). *tags* field should either be 0 or or point to an array of *nr* \"tags\" (unsigned 64 bit integers). See **IORING_REGISTER_BUFFERS2** for more info on resource tagging.
+
+ Note that resource updates, e.g. **IORING_REGISTER_FILES_UPDATE**, don\'t necessarily deallocate resources, they might be held until all requests using that resource complete.
+
+ Available since 5.13.
+
+**IORING_REGISTER_FILES_UPDATE**
+
+: This operation replaces existing files in the registered file set with new ones, either turning a sparse entry (one where fd is equal to **-1**) into a real one, removing an existing entry (new one is set to **-1**), or replacing an existing entry with a new existing entry.
+
+ *arg* must contain a pointer to a *struct* *io_uring_rsrc_update*, which contains an offset on which to start the update, and an array of file descriptors to use for the update. *nr_args* must contain the number of descriptors in the passed in array. Available since 5.5.
+
+ File descriptors can be skipped if they are set to **IORING_REGISTER_FILES_SKIP**. Skipping an fd will not touch the file associated with the previous fd at that index. Available since 5.12.
+
+**IORING_REGISTER_FILES_UPDATE2**
+
+: Similar to **IORING_REGISTER_FILES_UPDATE**, replaces existing files in the registered file set with new ones, either turning a sparse entry (one where fd is equal to **-1**) into a real one, removing an existing entry (new one is set to **-1**), or replacing an existing entry with a new existing entry.
+
+ *arg* must contain a pointer to a *struct* *io_uring_rsrc_update2*, which contains an offset on which to start the update, and an array of file descriptors to use for the update stored in *data*. *tags* points to an array of tags. *nr* must contain the number of descriptors in the passed in arrays. See **IORING_REGISTER_BUFFERS2** for the resource tagging description.
+
+ Available since 5.13.
+
+**IORING_UNREGISTER_FILES**
+
+: This operation requires no argument, and *arg* must be passed as NULL. All previously registered files associated with the io_uring instance will be unregistered. Available since 5.1.
+
+**IORING_REGISTER_EVENTFD**
+
+: It\'s possible to use **eventfd**(2) to get notified of completion events on an io_uring instance. If this is desired, an eventfd file descriptor can be registered through this operation. *arg* must contain a pointer to the eventfd file descriptor, and *nr_args* must be 1. Note that while io_uring generally takes care to avoid spurious events, they can occur. Similarly, batched completions of CQEs may only trigger a single eventfd notification even if multiple CQEs are posted. The application should make no assumptions on number of events being available having a direct correlation to eventfd notifications posted. An eventfd notification must thus only be treated as a hint to check the CQ ring for completions. Available since 5.2.
+
+ An application can temporarily disable notifications, coming through the registered eventfd, by setting the **IORING_CQ_EVENTFD_DISABLED** bit in the *flags* field of the CQ ring. Available since 5.8.
+
+**IORING_REGISTER_EVENTFD_ASYNC**
+
+: This works just like **IORING_REGISTER_EVENTFD**, except notifications are only posted for events that complete in an async manner. This means that events that complete inline while being submitted do not trigger a notification event. The arguments supplied are the same as for **IORING_REGISTER_EVENTFD**. Available since 5.6.
+
+**IORING_UNREGISTER_EVENTFD**
+
+: Unregister an eventfd file descriptor to stop notifications. Since only one eventfd descriptor is currently supported, this operation takes no argument, and *arg* must be passed as NULL and *nr_args* must be zero. Available since 5.2.
+
+**IORING_REGISTER_PROBE**
+
+: This operation returns a structure, io_uring_probe, which contains information about the opcodes supported by io_uring on the running kernel. *arg* must contain a pointer to a struct io_uring_probe, and *nr_args* must contain the size of the ops array in that probe struct. The ops array is of the type io_uring_probe_op, which holds the value of the opcode and a flags field. If the flags field has **IO_URING_OP_SUPPORTED** set, then this opcode is supported on the running kernel. Available since 5.6.
+
+**IORING_REGISTER_PERSONALITY**
+
+: This operation registers credentials of the running application with io_uring, and returns an id associated with these credentials. Applications wishing to share a ring between separate users/processes can pass in this credential id in the sqe **personality** field. If set, that particular sqe will be issued with these credentials. Must be invoked with *arg* set to NULL and *nr_args* set to zero. Available since 5.6.
+
+**IORING_UNREGISTER_PERSONALITY**
+
+: This operation unregisters a previously registered personality with io_uring. *nr_args* must be set to the id in question, and *arg* must be set to NULL. Available since 5.6.
+
+**IORING_REGISTER_ENABLE_RINGS**
+
+: This operation enables an io_uring ring started in a disabled state (**IORING_SETUP_R_DISABLED** was specified in the call to **io_uring_setup**(2)). While the io_uring ring is disabled, submissions are not allowed and registrations are not restricted.
+
+ After the execution of this operation, the io_uring ring is enabled: submissions and registration are allowed, but they will be validated following the registered restrictions (if any). This operation takes no argument, must be invoked with *arg* set to NULL and *nr_args* set to zero. Available since 5.10.
+
+**IORING_REGISTER_RESTRICTIONS**
+
+: *arg* points to a *struct io_uring_restriction* array of *nr_args* entries.
+
+ With an entry it is possible to allow an **io_uring_register**(2) *opcode*, or specify which *opcode* and *flags* of the submission queue entry are allowed, or require certain *flags* to be specified (these flags must be set on each submission queue entry).
+
+ All the restrictions must be submitted with a single **io_uring_register**(2) call and they are handled as an allowlist (opcodes and flags not registered, are not allowed).
+
+ Restrictions can be registered only if the io_uring ring started in a disabled state (**IORING_SETUP_R_DISABLED** must be specified in the call to **io_uring_setup**(2)).
+
+ Available since 5.10.
+
+**IORING_REGISTER_IOWQ_AFF**
+
+: By default, async workers created by io_uring will inherit the CPU mask of its parent. This is usually all the CPUs in the system, unless the parent is being run with a limited set. If this isn\'t the desired outcome, the application may explicitly tell io_uring what CPUs the async workers may run on. *arg* must point to a **cpu_set_t** mask, and *nr_args* the byte size of that mask.
+
+ Available since 5.14.
+
+**IORING_UNREGISTER_IOWQ_AFF**
+
+: Undoes a CPU mask previously set with **IORING_REGISTER_IOWQ_AFF**. Must not have *arg* or *nr_args* set.
+
+ Available since 5.14.
+
+**IORING_REGISTER_IOWQ_MAX_WORKERS**
+
+: By default, io_uring limits the unbounded workers created to the maximum processor count set by *RLIMIT_NPROC* and the bounded workers is a function of the SQ ring size and the number of CPUs in the system. Sometimes this can be excessive (or too little, for bounded), and this command provides a way to change the count per ring (per NUMA node) instead.
+
+ *arg* must be set to an *unsigned int* pointer to an array of two values, with the values in the array being set to the maximum count of workers per NUMA node. Index 0 holds the bounded worker count, and index 1 holds the unbounded worker count. On successful return, the passed in array will contain the previous maximum values for each type. If the count being passed in is 0, then this command returns the current maximum values and doesn\'t modify the current setting. *nr_args* must be set to 2, as the command takes two values.
+
+ Available since 5.15.
+
+**IORING_REGISTER_RING_FDS**
+
+: Whenever **io_uring_enter**(2) is called to submit request or wait for completions, the kernel must grab a reference to the file descriptor. If the application using io_uring is threaded, the file table is marked as shared, and the reference grab and put of the file descriptor count is more expensive than it is for a non-threaded application.
+
+ Similarly to how io_uring allows registration of files, this allow registration of the ring file descriptor itself. This reduces the overhead of the **io_uring_enter**(2) system call.
+
+ *arg* must be set to a pointer to an array of type *struct io_uring_rsrc_update* of *nr_args* number of entries. The **data** field of this struct must contain an io_uring file descriptor, and the **offset** field can be either **-1** or an explicit offset desired for the registered file descriptor value. If **-1** is used, then upon successful return of this system call, the field will contain the value of the registered file descriptor to be used for future **io_uring_enter**(2) system calls.
+
+ On successful completion of this request, the returned descriptors may be used instead of the real file descriptor for **io_uring_enter**(2), provided that **IORING_ENTER_REGISTERED_RING** is set in the *flags* for the system call. This flag tells the kernel that a registered descriptor is used rather than a real file descriptor.
+
+ Each thread or process using a ring must register the file descriptor directly by issuing this request.
+
+ The maximum number of supported registered ring descriptors is currently limited to **16.**
+
+ Available since 5.18.
+
+**IORING_UNREGISTER_RING_FDS**
+
+: Unregister descriptors previously registered with **IORING_REGISTER_RING_FDS**.
+
+ *arg* must be set to a pointer to an array of type *struct io_uring_rsrc_update* of *nr_args* number of entries. Only the **offset** field should be set in the structure, containing the registered file descriptor offset previously returned from **IORING_REGISTER_RING_FDS** that the application wishes to unregister.
+
+ Note that this isn\'t done automatically on ring exit, if the thread or task that previously registered a ring file descriptor isn\'t exiting. It is recommended to manually unregister any previously registered ring descriptors if the ring is closed and the task persists. This will free up a registration slot, making it available for future use.
+
+ Available since 5.18.
+
+**IORING_REGISTER_PBUF_RING**
+
+: Registers a shared buffer ring to be used with provided buffers. This is a newer alternative to using **IORING_OP_PROVIDE_BUFFERS** which is more efficient, to be used with request types that support the **IOSQE_BUFFER_SELECT** flag.
+
+ The *arg* argument must be filled in with the appropriate information. It looks as follows:
+
+<!-- -->
+
+ struct io_uring_buf_reg {
+ __u64 ring_addr;
+ __u32 ring_entries;
+ __u16 bgid;
+ __u16 flags;
+ __u32 min_left;
+ __u32 resv[5];
+ };
+
+The *ring_addr* field must contain the address to the memory allocated to fit this ring. The memory must be page aligned and hence allocated appropriately using eg **posix_memalign**(3) or similar. The size of the ring is the product of *ring_entries* and the size of *struct io_uring_buf*. *ring_entries* is the desired size of the ring, and must be a power-of-2 in size. The maximum size allowed is 2\^15 (32768). *bgid* is the buffer group ID associated with this ring. SQEs that select a buffer have a buffer group associated with them in their *buf_group* field, and the associated CQEs will have **IORING_CQE_F_BUFFER** set in their *flags* member, which will also contain the specific ID of the buffer selected. *min_left* is the minimum value that should be left in an incrementally consumed buffer ring for the buffer to be considered valid. If not set, defaults to a single byte. Only valid with **IOU_PBUF_RING_INC** set in *flags .* The rest of the fields are reserved and must be cleared to zero.
+
+*nr_args* must be set to 1.
+
+Also see **io_uring_register_buf_ring**(3) for more details. Available since 5.19.
+
+**IORING_UNREGISTER_PBUF_RING**
+
+: Unregister a previously registered provided buffer ring. *arg* must be set to the address of a struct io_uring_buf_reg, with just the *bgid* field set to the buffer group ID of the previously registered provided buffer group. *nr_args* must be set to 1. Also see **IORING_REGISTER_PBUF_RING**.
+
+ Available since 5.19.
+
+**IORING_REGISTER_SYNC_CANCEL**
+
+: Performs a synchronous cancelation request, which works in a similar fashion to **IORING_OP_ASYNC_CANCEL** except it completes inline. This can be useful for scenarios where cancelations should happen synchronously, rather than needing to issue an SQE and wait for completion of that specific CQE.
+
+ *arg* must be set to a pointer to a struct io_uring_sync_cancel_reg structure, with the details filled in for what request(s) to target for cancelation. See **io_uring_register_sync_cancel**(3) for details on that. The return values are the same, except they are passed back synchronously rather than through the CQE *res* field. *nr_args* must be set to 1.
+
+ Available since 6.0.
+
+**IORING_REGISTER_FILE_ALLOC_RANGE**
+
+: sets the allowable range for fixed file index allocations within the kernel. When requests that can instantiate a new fixed file are used with **IORING_FILE_INDEX_ALLOC**, the application is asking the kernel to allocate a new fixed file descriptor rather than pass in a specific value for one. By default, the kernel will pick any available fixed file descriptor within the range available. This effectively allows the application to set aside a range just for dynamic allocations, with the remainder being used for specific values.
+
+ *nr_args* must be set to 1 and *arg* must be set to a pointer to a struct io_uring_file_index_range:
+
+<!-- -->
+
+ struct io_uring_file_index_range {
+ __u32 off;
+ __u32 len;
+ __u64 resv;
+ };
+
+with *off* being set to the starting value for the range, and *len* being set to the number of descriptors. The reserved *resv* field must be cleared to zero.
+
+The application must have registered a file table first.
+
+Available since 6.0.
+
+**IORING_REGISTER_PBUF_STATUS**
+
+: Can be used to retrieve the current head of a ringbuffer provided earlier via **IORING_REGISTER_PBUF_RING**. *arg* must point to a
+
+<!-- -->
+
+ struct io_uring_buf_status {
+ __u32 buf_group; /* input */
+ __u32 head; /* output */
+ __u32 resv[8];
+ };
+
+of which *arg-\>buf_group* should contain the buffer group ID for the buffer ring in question, *nr_args* should be set to 1 and *arg-\>resv* should be zeroed out. The current head of the ringbuffer will be returned in *arg-\>head*.
+
+Available since 6.8.
+
+**IORING_REGISTER_NAPI**
+
+: Registers a napi instance with the io_uring instance of *fd*. *arg* should point to a
+
+<!-- -->
+
+ struct io_uring_napi {
+ __u32 busy_poll_to;
+ __u8 prefer_busy_poll;
+ __u8 pad[3];
+ __u64 resv;
+ };
+
+in which *arg-\>busy_poll_to* should contain the busy poll timeout in micro seconds and *arg-\>prefer_busy_poll* should specify whether busy polling should be used rather than IRQs. *nr_args* should be set to 1 and *arg-\>pad* and *arg-\>resv* should be zeroed out. On successful return the *io_uring_napi* struct pointed to by *arg* will contain the previously used settings.
+
+Available since 6.9.
+
+**IORING_UNREGISTER_NAPI**
+
+: Unregisters a napi instance previously registered via **IORING_REGISTER_NAPI** to the io_uring instance of *fd*. *arg* should point to a *struct* *io_uring_napi*. On successful return the *io_uring_napi* struct pointed to by *arg* will contain the previously used settings.
+
+ Available since 6.9.
+
+**IORING_REGISTER_CLOCK**
+
+: Specifies which clock id io_uring will use for timers while waiting for completion events with **IORING_ENTER_GETEVENTS**. It\'s only effective if the timeout argument in *struct io_uring_getevents_arg* is passed, ignored otherwise. When used in conjunction with **IORING_ENTER_ABS_TIMER**, interprets the timeout argument as absolute time of the specified clock.
+
+ The default clock is **CLOCK_MONOTONIC**.
+
+ Available since 6.12 and supports **CLOCK_MONOTONIC** and **CLOCK_BOOTTIME**.
+
+**IORING_REGISTER_CLONE_BUFFERS**
+
+: Supports cloning buffers from a source ring to a destination ring, duplicating previously registered buffers from source to destination. *arg* must be set to a pointer to a *struct io_uring_clone_buffers* and *nr_args* must be set to **1 .** *struct io_uring_buf_reg* looks as follows:
+
+<!-- -->
+
+ struct io_uring_clone_buffers {
+ __u32 src_fd;
+ __u32 flags;
+ __u32 src_off;
+ __u32 dst_off;
+ __u32 nr;
+ __u32 pad[3];
+ };
+
+where *src_fd* indicates the fd of the source ring, *flags* are modifier flags for the operation, *src_off* indicates the offset from where to start the cloning from the source ring, *dst_off* indicates the offset from where to start the cloning into the destination ring, and *nr* indicates the number of buffers to clone at the given offsets. *pad* must be zero filled. Kernel 6.12 added support for full range cloning, where *src_off*, *dst_off*, and *nr* must all be set to 0, indicating cloning of the entire table in source to destination. Kernel 6.13 added support for specifying the offsets and how many buffers to clone. Additionally, it added support for cloning into a previously registered table in the destination as well, 6.12 would fail that operation with **-EBUSY** if attempted. To replace existing nodes, or clone into an existing table, **IORING_REGISTER_DST_REPLACE** must be set in the *flags* member.
+
+**IORING_REGISTER_SEND_MSG_RING**
+
+: Supports sending of the equivalent of a **IORING_OP_MSG_RING** request, but without having a source ring available. Takes a pointer to a *struct*io_uring_sqe which must be prepared with **io_uring_prep_msg_ring**(3) before being submitted. Only supports **IORING_MSG_DATA** type of requests. Available since kernel 6.13.
+
+**IORING_REGISTER_RESIZE_RINGS**
+
+: Supports resizing the SQ and CQ rings. Takes a pointer to a *struct*io_uring_params as the argument, where *sq_entries* and *cq_entries* may be set to the desired values. Only supports a limited set of flags set in the *struct*io_uring_params argument, notably **IORING_SETUP_CQSIZE** and **IORING_SETUP_CLAMP** to modify the CQ ring sizing. See **io_uring_resize_rings**(3) for details. Note that while liburing takes care of the ring unmap and mapping for a resize operation, manual users of this register syscall must perform those operations, similarly to when a new ring is created. The *struct*io_uring_params structure will get the necessary offsets copied back upon successful completion of this system call, which can be used to memory map the ring just like how a new ring would\'ve been mapped. Available since kernel 6.13.
+
+**IORING_REGISTER_MEM_REGION**
+
+: Supports registering multiple purposes memory regions, avoiding unnecessary copying in of *struct*io_uring_getevents_arg for wait operations that specify a timeout or minimum timeout. Takes a pointer to a *struct*io_uring_mem_region_reg structure, which looks as follows:
+
+<!-- -->
+
+ struct io_uring_mem_region_reg {
+ __u64 region_uptr;
+ __u64 flags;
+ __u64 __resv[2];
+ };
+
+where *region_uptr* must be set to the region being registered as memory regions, *flags* specifies modifier flags (must currently be **IORING_MEM_REGION_REG_WAIT_ARG ). The pad fields must all be cleared to** **0 .** Each memory regions looks as follows:
+
+ struct io_uring_region_desc {
+ __u64 user_addr;
+ __u64 size;
+ __u32 flags;
+ __u32 id;
+ __u64 mmap_offset;
+ __u64 __resv[4];
+ };
+
+where *user_addr* points to userspace memory mappings, *size* is the size of userspace memory. Current supported userspace memory regions looks as follows:
+
+ struct io_uring_reg_wait {
+ struct __kernel_timespec ts;
+ __u32 min_wait_usec;
+ __u32 flags;
+ __u64 sigmask;
+ __u32 sigmask_sz;
+ __u32 pad[3];
+ __u64 pad2[2];
+ };
+
+where *ts* holds the timeout information for this region *flags* holds information about the timeout region, *sigmask* is a pointer to a signal mask, if used, and *sigmask_sz* is the size of that signal mask. The pad fields must all be cleared to **0 .** Currently the only valid flag is **IORING_REG_WAIT_TS ,** which, if set, says that the values in *ts* are valid and should be used for a timeout operation. The *user_addr* field of *struct*io_uring_region_desc must be set to an address of *struct*io_uring_reg_wait members, an up to a page size can be mapped. At the size of 64 bytes per region, that allows at least 64 individual regions on a 4k page size system. The offsets of these regions are used for an **io_uring_enter**(2) system call, with the first one being 0, second one 1, and so forth. After registration of the wait regions, **io_uring_enter**(2) may be used with the enter flag of **IORING_ENTER_EXT_ARG_REG and an** *argp* set to the wait region offset, rather than a pointer to a *struct*io_uring_getevent_arg structure. If used with **IORING_ENTER_GETEVENTS ,** then the wait operation will use the information in the registered wait region rather than needing a io_uring_getevent_arg structure copied for each operation. For high frequency waits, this can save considerable CPU cycles. Note: once a region has been registered, it cannot get unregistered. It lives for the life of the ring. Individual wait region offset may be modified before any **io_uring_enter**(2) system call. Available since kernel 6.13.
+
+**IORING_REGISTER_ZCRX_IFQ**
+
+: Registers a zero-copy receive interface queue for network receive operations. Zero-copy receive allows the kernel to place incoming network data directly into application-provided memory without copying, reducing CPU overhead for high-bandwidth network workloads. *arg* must point to a *struct io_uring_zcrx_ifq_reg* structure, and *nr_args* must be set to 1.
+
+<!-- -->
+
+ struct io_uring_zcrx_ifq_reg {
+ __u32 if_idx;
+ __u32 if_rxq;
+ __u32 rq_entries;
+ __u32 flags;
+ __u64 area_ptr;
+ __u64 region_ptr;
+ struct io_uring_zcrx_offsets offsets;
+ __u32 zcrx_id;
+ __u32 __resv2;
+ __u64 __resv[3];
+ };
+
+where *if_idx* is the network interface index, *if_rxq* is the receive queue index, *rq_entries* is the number of entries in the refill queue (will be rounded up to a power of two), *flags* contains modifier flags, *area_ptr* points to a *struct io_uring_zcrx_area_reg* describing the memory area to use, *region_ptr* points to a *struct io_uring_region_desc* describing the memory region, and upon successful return *zcrx_id* will contain the ID of the registered zero-copy receive context. The *offsets* field is filled in by the kernel and contains the ring offsets for the refill queue.
+
+The io_uring ring must have been created with **IORING_SETUP_DEFER_TASKRUN** and either **IORING_SETUP_CQE32** or **IORING_SETUP_CQE_MIXED** flags set. The caller must have the **CAP_NET_ADMIN** capability.
+
+Available since kernel 6.15.
+
+**IORING_REGISTER_QUERY**
+
+: Queries io_uring capabilities and feature support. This operation does not require an io_uring ring and can be called with *fd* set to -1. It provides information about supported opcodes, flags, and subsystem-specific capabilities. *arg* must point to a *struct io_uring_query_hdr* and *nr_args* must be 0.
+
+<!-- -->
+
+ struct io_uring_query_hdr {
+ __u64 next_entry;
+ __u64 query_data;
+ __u32 query_op;
+ __u32 size;
+ __s32 result;
+ __u32 __resv[3];
+ };
+
+Multiple queries can be chained together via *next_entry* which points to the next *struct io_uring_query_hdr* (or 0 for the last entry). *query_data* points to a data structure appropriate for the query type. *query_op* specifies the query type and can be one of:
+
+- **IO_URING_QUERY_OPCODES** - Returns information about supported opcodes and flags in a *struct io_uring_query_opcode*
+
+- **IO_URING_QUERY_ZCRX** - Returns information about zero-copy receive support in a *struct io_uring_query_zcrx*
+
+- **IO_URING_QUERY_SCQ** - Returns information about the SQ/CQ ring layout in a *struct io_uring_query_scq*
+
+*size* should be set to the size of the data structure pointed to by *query_data*. Upon return, *result* will be 0 on success, or a negative error code.
+
+Available since kernel 6.15.
+
+**IORING_REGISTER_ZCRX_CTRL**
+
+: Performs control operations on a previously registered zero-copy receive context. *arg* must point to a *struct zcrx_ctrl* and *nr_args* must be 0.
+
+<!-- -->
+
+ struct zcrx_ctrl {
+ __u32 zcrx_id;
+ __u32 op;
+ __u64 __resv[2];
+ union {
+ struct zcrx_ctrl_export zc_export;
+ struct zcrx_ctrl_flush_rq zc_flush;
+ };
+ };
+
+where *zcrx_id* is the ID of the zero-copy receive context returned from **IORING_REGISTER_ZCRX_IFQ**, and *op* specifies the control operation:
+
+- **ZCRX_CTRL_FLUSH_RQ** - Flushes pending buffers from the refill queue
+
+- **ZCRX_CTRL_EXPORT** - Exports the zero-copy receive context for use by other rings
+
+ Available since kernel 6.15.
+
+# RETURN VALUE
+
+On success, **io_uring_register**(2) returns either 0 or a positive value, depending on the *opcode* used. On error, a negative error value is returned. The caller should not rely on the *errno* variable.
+
+# ERRORS
+
+**EACCES**
+
+: The *opcode* field is not allowed due to registered restrictions.
+
+**EBADF**
+
+: One or more fds in the *fd* array are invalid.
+
+**EBADFD**
+
+: **IORING_REGISTER_ENABLE_RINGS** or **IORING_REGISTER_RESTRICTIONS** was specified, but the io_uring ring is not disabled.
+
+**EBUSY**
+
+: **IORING_REGISTER_BUFFERS** or **IORING_REGISTER_FILES** or **IORING_REGISTER_RESTRICTIONS** was specified, but there were already buffers, files, or restrictions registered.
+
+**EEXIST**
+
+: The thread performing the registration is invalid.
+
+**EFAULT**
+
+: buffer is outside of the process\' accessible address space, or *iov_len* is greater than 1GiB.
+
+**EINVAL**
+
+: **IORING_REGISTER_BUFFERS** or **IORING_REGISTER_FILES** was specified, but *nr_args* is 0.
+
+**EINVAL**
+
+: **IORING_REGISTER_BUFFERS** was specified, but *nr_args* exceeds **UIO_MAXIOV**
+
+**EINVAL**
+
+: **IORING_UNREGISTER_BUFFERS** or **IORING_UNREGISTER_FILES** was specified, and *nr_args* is non-zero or *arg* is non-NULL.
+
+**EINVAL**
+
+: **IORING_REGISTER_RESTRICTIONS** was specified, but *nr_args* exceeds the maximum allowed number of restrictions or restriction *opcode* is invalid.
+
+**EMFILE**
+
+: **IORING_REGISTER_FILES** was specified and *nr_args* exceeds the maximum allowed number of files in a fixed file set.
+
+**EMFILE**
+
+: **IORING_REGISTER_FILES** was specified and adding *nr_args* file references would exceed the maximum allowed number of files the user is allowed to have according to the **RLIMIT_NOFILE** resource limit and the caller does not have **CAP_SYS_RESOURCE** capability. Note that this is a per user limit, not per process.
+
+**ENOMEM**
+
+: Insufficient kernel resources are available, or the caller had a non-zero **RLIMIT_MEMLOCK** soft resource limit, but tried to lock more memory than the limit permitted. This limit is not enforced if the process is privileged (**CAP_IPC_LOCK**).
+
+**ENXIO**
+
+: **IORING_UNREGISTER_BUFFERS** or **IORING_UNREGISTER_FILES** was specified, but there were no buffers or files registered.
+
+**ENXIO**
+
+: Attempt to register files or buffers on an io_uring instance that is already undergoing file or buffer registration, or is being torn down.
+
+**EOPNOTSUPP**
+
+: User buffers point to file-backed memory.
+
+**EFAULT**
+
+: User buffers point to file-backed memory (newer kernels).
+
+**ENOENT**
+
+: **IORING_REGISTER_PBUF_STATUS** was specified, but *buf_group* did not refer to a currently valid buffer group.
+
+**EINVAL**
+
+: **IORING_REGISTER_PBUF_STATUS** was specified, but the valid buffer group specified by *buf_group* did not refer to a buffer group registered via **IORING_REGISTER_PBUF_RING**.
+
+**EINVAL**
+
+: **IORING_REGISTER_NAPI** was specified, but the ring associated with *fd* has not been created with **IORING_SETUP_IOPOLL**.
diff --git a/man/io_uring_register_bpf_filter.3 b/man/io_uring_register_bpf_filter.3
deleted file mode 100644
index 440b88bb..00000000
--- a/man/io_uring_register_bpf_filter.3
+++ /dev/null
@@ -1,411 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_register_bpf_filter 3 "January 18, 2026" "liburing-2.14" "liburing Manual"
-.SH NAME
-io_uring_register_bpf_filter, io_uring_register_bpf_filter_task \- register classic BPF filters for io_uring operations
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.B #include <liburing/io_uring/bpf_filter.h>
-.B #include <linux/filter.h>
-.PP
-.BI "int io_uring_register_bpf_filter(struct io_uring *" ring ","
-.BI " struct io_uring_bpf *" bpf ");"
-.PP
-.BI "int io_uring_register_bpf_filter_task(struct io_uring_bpf *" bpf ");"
-.fi
-.SH DESCRIPTION
-.PP
-These functions register classic BPF (cBPF) filters to restrict io_uring
-operations. Filters can be used to implement security policies by allowing
-or denying specific operations based on their parameters.
-.PP
-.BR io_uring_register_bpf_filter (3)
-registers a filter on a specific
-.IR ring .
-The filter only applies to operations submitted through that ring.
-.PP
-.BR io_uring_register_bpf_filter_task (3)
-registers a filter on the calling task. The filter applies to all io_uring
-rings created by the task after the filter is registered, and is inherited
-by child processes created via
-.BR fork (2).
-Rings that were created before the filter was registered are not affected.
-Task-level filters cannot be removed and child processes cannot loosen
-restrictions set by their parent.
-.PP
-The
-.I bpf
-argument is a pointer to a
-.B struct io_uring_bpf
-with
-.I cmd_type
-set to
-.BR IO_URING_BPF_CMD_FILTER .
-The embedded
-.B struct io_uring_bpf_filter
-describes the filter to register:
-.PP
-.in +4n
-.EX
-struct io_uring_bpf_filter {
- __u32 opcode; /* io_uring opcode to filter */
- __u32 flags; /* IO_URING_BPF_FILTER_* */
- __u32 filter_len; /* number of BPF instructions */
- __u8 pdu_size; /* expected pdu size for opcode */
- __u8 resv[3];
- __u64 filter_ptr; /* pointer to BPF filter */
- __u64 resv2[5];
-};
-.EE
-.in
-.PP
-.I opcode
-specifies which io_uring operation the filter applies to (e.g.,
-.BR IORING_OP_SOCKET ", " IORING_OP_NOP ", " IORING_OP_READ ).
-.PP
-.I filter_ptr
-points to an array of
-.I filter_len
-BPF instructions
-.RB ( "struct sock_filter" ).
-The filter is executed for each matching operation and must return non-zero
-to allow the operation or zero to deny it (resulting in
-.B -EACCES
-being returned to the application).
-.PP
-.I pdu_size
-specifies the expected size in bytes of the operation-specific payload data
-for the given opcode (e.g., the socket or open structs inside
-.BR "struct io_uring_bpf_ctx" ).
-For opcodes that have no extra payload, this should be zero. For
-.B IORING_OP_SOCKET
-this would be 12 (three 4-byte members), and for
-.BR IORING_OP_OPENAT " and " IORING_OP_OPENAT2
-this would be 24 (three 8-byte members).
-.PP
-If the application's
-.I pdu_size
-matches the kernel's expected size for the opcode, registration succeeds.
-If the sizes differ, the behavior depends on whether
-.B IO_URING_BPF_FILTER_SZ_STRICT
-is set in
-.IR flags :
-.RS
-.IP \(bu 2
-If
-.B IO_URING_BPF_FILTER_SZ_STRICT
-is set, registration fails with
-.B -EMSGSIZE
-if the sizes differ.
-.IP \(bu
-If
-.B IO_URING_BPF_FILTER_SZ_STRICT
-is not set, registration is allowed if the application's
-.I pdu_size
-is smaller than the kernel's. This permits older applications that were
-compiled against a smaller payload to still load filters, as the kernel
-can safely evaluate the filter on the subset of data the application
-expects.
-.IP \(bu
-Regardless of
-.BR IO_URING_BPF_FILTER_SZ_STRICT ,
-registration always fails with
-.B -EMSGSIZE
-if the application's
-.I pdu_size
-is larger than the kernel's, since the kernel cannot provide data that
-it does not support.
-.RE
-.PP
-On an
-.B -EMSGSIZE
-failure, the kernel writes back the kernel's expected
-.I pdu_size
-into the
-.B struct io_uring_bpf_filter
-passed by the application. This allows the application to discover the
-kernel's expected payload size and adjust or retry accordingly.
-.PP
-.I flags
-can be zero or a bitwise OR of the following:
-.TP
-.B IO_URING_BPF_FILTER_DENY_REST
-When set, any opcode that does not have a filter registered will be denied.
-This allows creating an allowlist of permitted operations.
-.TP
-.B IO_URING_BPF_FILTER_SZ_STRICT
-When set, registration of a filter will fail with
-.B -EMSGSIZE
-if the application's
-.I pdu_size
-does not exactly match the kernel's expected payload size for the opcode.
-Without this flag, the kernel permits filters where the application's
-.I pdu_size
-is smaller than or equal to the kernel's.
-.SS Filter Context
-The BPF filter receives a context structure that can be inspected using
-.B BPF_LD
-instructions with absolute addressing. The context layout is:
-.PP
-.in +4n
-.EX
-struct io_uring_bpf_ctx {
- __u64 user_data; /* offset 0: user_data from SQE */
- __u8 opcode; /* offset 8: io_uring opcode */
- __u8 sqe_flags; /* offset 9: SQE flags */
- __u8 pdu_size; /* offset 10: aux data size for filter */
- __u8 pad[5]; /* offset 11-15: padding */
- union {
- struct {
- __u32 family; /* offset 16: socket family */
- __u32 type; /* offset 20: socket type */
- __u32 protocol; /* offset 24: socket protocol */
- } socket;
- struct {
- __u64 flags; /* offset 16: open flags */
- __u64 mode; /* offset 24: file mode */
- __u64 resolve; /* offset 32: resolve flags */
- } open;
- };
-};
-.EE
-.in
-.PP
-The
-.I pdu_size
-field indicates the size in bytes of the operation-specific data passed in
-the union. A filter can check this value to verify it is receiving the
-expected payload. This is useful for forward compatibility: if a future
-kernel adds new members to an operation's context, the filter can inspect
-.I pdu_size
-to determine whether those fields are present.
-.PP
-For
-.B IORING_OP_SOCKET
-operations, the socket family, type, and protocol fields are populated
-and can be used to filter based on socket parameters.
-.I pdu_size
-is set to 12 (three 4-byte members).
-.PP
-For
-.BR IORING_OP_OPENAT " and " IORING_OP_OPENAT2
-operations, the open flags, mode, and resolve fields are populated.
-The flags field contains the open flags (e.g.,
-.BR O_RDONLY ", " O_CREAT ).
-The resolve field is only meaningful for
-.B IORING_OP_OPENAT2
-and contains resolve flags (e.g.,
-.BR RESOLVE_IN_ROOT ")."
-.I pdu_size
-is set to 24 (three 8-byte members).
-.SS Filter Stacking
-Multiple filters can be registered for the same opcode. When multiple
-filters exist, they are evaluated in order and all must return non-zero
-for the operation to be allowed. For task-level filters, the child's
-filters are evaluated before the parent's filters.
-.SH RETURN VALUE
-On success, these functions return 0. On failure, they return a negative
-error code.
-.SH ERRORS
-.TP
-.B -EINVAL
-Invalid filter, opcode, or flags specified.
-.TP
-.B -EMSGSIZE
-The application's
-.I pdu_size
-does not match the kernel's expected payload size for the opcode. This
-occurs when
-.B IO_URING_BPF_FILTER_SZ_STRICT
-is set and the sizes differ, or when the application's
-.I pdu_size
-is larger than the kernel's regardless of flags.
-.TP
-.B -ENOMEM
-Insufficient memory to register the filter.
-.TP
-.B -EFAULT
-The filter pointer is invalid.
-.TP
-.B -EACCES
-The caller does not have the
-.B CAP_SYS_ADMIN
-capability and the
-.B no_new_privs
-attribute is not set on the calling task. See
-.BR prctl (2)
-with
-.BR PR_SET_NO_NEW_PRIVS .
-.SH EXAMPLES
-.SS Deny all NOP operations
-.PP
-.in +4n
-.EX
-#include <sys/prctl.h>
-#include <linux/filter.h>
-#include <liburing.h>
-#include <liburing/io_uring/bpf_filter.h>
-
-struct sock_filter deny_filter[] = {
- BPF_STMT(BPF_RET | BPF_K, 0), /* return 0 (deny) */
-};
-
-struct io_uring_bpf bpf = {
- .cmd_type = IO_URING_BPF_CMD_FILTER,
- .filter = {
- .opcode = IORING_OP_NOP,
- .filter_len = 1,
- .filter_ptr = (unsigned long) deny_filter,
- },
-};
-
-/* Must set no_new_privs before registering task filters */
-prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
-
-/* Register on a specific ring */
-io_uring_register_bpf_filter(&ring, &bpf);
-
-/* Or register on the task */
-io_uring_register_bpf_filter_task(&bpf);
-.EE
-.in
-.SS Allow only AF_INET sockets
-.PP
-.in +4n
-.EX
-#include <sys/prctl.h>
-#include <linux/filter.h>
-#include <sys/socket.h>
-#include <liburing.h>
-#include <liburing/io_uring/bpf_filter.h>
-
-#define CTX_OFF_SOCKET_FAMILY 16
-
-struct sock_filter inet_only_filter[] = {
- /* Load socket family from context */
- BPF_STMT(BPF_LD | BPF_W | BPF_ABS, CTX_OFF_SOCKET_FAMILY),
- /* If family == AF_INET, jump to allow */
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AF_INET, 0, 1),
- /* Allow: return 1 */
- BPF_STMT(BPF_RET | BPF_K, 1),
- /* Deny: return 0 */
- BPF_STMT(BPF_RET | BPF_K, 0),
-};
-
-struct io_uring_bpf bpf = {
- .cmd_type = IO_URING_BPF_CMD_FILTER,
- .filter = {
- .opcode = IORING_OP_SOCKET,
- .filter_len = 4,
- .filter_ptr = (unsigned long) inet_only_filter,
- .pdu_size = 12, /* 3x __u32: family, type, protocol */
- },
-};
-
-prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
-io_uring_register_bpf_filter_task(&bpf);
-.EE
-.in
-.SS Allow only NOP, deny everything else
-.PP
-.in +4n
-.EX
-struct sock_filter allow_filter[] = {
- BPF_STMT(BPF_RET | BPF_K, 1), /* return 1 (allow) */
-};
-
-struct io_uring_bpf bpf = {
- .cmd_type = IO_URING_BPF_CMD_FILTER,
- .filter = {
- .opcode = IORING_OP_NOP,
- .flags = IO_URING_BPF_FILTER_DENY_REST,
- .filter_len = 1,
- .filter_ptr = (unsigned long) allow_filter,
- },
-};
-
-prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
-io_uring_register_bpf_filter_task(&bpf);
-.EE
-.in
-.SS Discover kernel pdu_size for an opcode
-This example demonstrates how to use the
-.B -EMSGSIZE
-write-back to discover the kernel's expected payload size.
-.PP
-.in +4n
-.EX
-struct sock_filter allow[] = {
- BPF_STMT(BPF_RET | BPF_K, 1),
-};
-
-struct io_uring_bpf bpf = {
- .cmd_type = IO_URING_BPF_CMD_FILTER,
- .filter = {
- .opcode = IORING_OP_SOCKET,
- .flags = IO_URING_BPF_FILTER_SZ_STRICT,
- .filter_len = 1,
- .filter_ptr = (unsigned long) allow,
- .pdu_size = 0, /* intentionally wrong */
- },
-};
-int ret;
-
-ret = io_uring_register_bpf_filter(&ring, &bpf);
-if (ret == -EMSGSIZE) {
- /* kernel wrote back expected size */
- printf("kernel pdu_size for SOCKET: %u\\n",
- bpf.filter.pdu_size);
- /* retry with correct size */
- ret = io_uring_register_bpf_filter(&ring, &bpf);
-}
-.EE
-.in
-.SH NOTES
-.SS Privilege Requirements
-Similar to
-.BR seccomp (2),
-registering BPF filters requires either the
-.B CAP_SYS_ADMIN
-capability or the
-.B no_new_privs
-attribute to be set on the calling task. This prevents an unprivileged
-process from installing a filter and then executing a setuid binary,
-which would run with elevated privileges but under the attacker-controlled
-filter.
-.PP
-To set the
-.B no_new_privs
-attribute, call:
-.PP
-.in +4n
-.EX
-prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
-.EE
-.in
-.PP
-Once set,
-.B no_new_privs
-cannot be unset and is inherited by child processes across
-.BR fork (2)
-and preserved across
-.BR execve (2).
-.SS Inheritance
-Task-level filters registered with
-.BR io_uring_register_bpf_filter_task (3)
-are inherited by child processes. This allows a parent process to
-establish security restrictions that apply to all descendants.
-Children can add additional restrictions but cannot remove or
-weaken filters set by their ancestors.
-.PP
-Ring-level filters registered with
-.BR io_uring_register_bpf_filter (3)
-only apply to that specific ring and are not inherited.
-.SH SEE ALSO
-.BR io_uring_register (2),
-.BR io_uring_setup (2),
-.BR bpf (2),
-.BR seccomp (2)
diff --git a/man/io_uring_register_bpf_filter.3.md b/man/io_uring_register_bpf_filter.3.md
new file mode 100644
index 00000000..8664fe71
--- /dev/null
+++ b/man/io_uring_register_bpf_filter.3.md
@@ -0,0 +1,267 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2026
+footer: liburing-2.14
+header: liburing Manual
+section: 3
+title: io_uring_register_bpf_filter
+---
+
+# NAME
+
+io_uring_register_bpf_filter, io_uring_register_bpf_filter_task - register classic BPF filters for io_uring operations
+
+# SYNOPSIS
+
+ #include <liburing.h>
+ #include <liburing/io_uring/bpf_filter.h>
+ #include <linux/filter.h>
+
+ int io_uring_register_bpf_filter(struct io_uring * ring ,
+ struct io_uring_bpf * bpf );
+
+ int io_uring_register_bpf_filter_task(struct io_uring_bpf * bpf );
+
+# DESCRIPTION
+
+These functions register classic BPF (cBPF) filters to restrict io_uring operations. Filters can be used to implement security policies by allowing or denying specific operations based on their parameters.
+
+**io_uring_register_bpf_filter**(3) registers a filter on a specific *ring*. The filter only applies to operations submitted through that ring.
+
+**io_uring_register_bpf_filter_task**(3) registers a filter on the calling task. The filter applies to all io_uring rings created by the task after the filter is registered, and is inherited by child processes created via **fork**(2). Rings that were created before the filter was registered are not affected. Task-level filters cannot be removed and child processes cannot loosen restrictions set by their parent.
+
+The *bpf* argument is a pointer to a **struct io_uring_bpf** with *cmd_type* set to **IO_URING_BPF_CMD_FILTER**. The embedded **struct io_uring_bpf_filter** describes the filter to register:
+
+ struct io_uring_bpf_filter {
+ __u32 opcode; /* io_uring opcode to filter */
+ __u32 flags; /* IO_URING_BPF_FILTER_* */
+ __u32 filter_len; /* number of BPF instructions */
+ __u8 pdu_size; /* expected pdu size for opcode */
+ __u8 resv[3];
+ __u64 filter_ptr; /* pointer to BPF filter */
+ __u64 resv2[5];
+ };
+
+*opcode* specifies which io_uring operation the filter applies to (e.g., **IORING_OP_SOCKET**, **IORING_OP_NOP**, **IORING_OP_READ**).
+
+*filter_ptr* points to an array of *filter_len* BPF instructions (**struct sock_filter**). The filter is executed for each matching operation and must return non-zero to allow the operation or zero to deny it (resulting in **-EACCES** being returned to the application).
+
+*pdu_size* specifies the expected size in bytes of the operation-specific payload data for the given opcode (e.g., the socket or open structs inside **struct io_uring_bpf_ctx**). For opcodes that have no extra payload, this should be zero. For **IORING_OP_SOCKET** this would be 12 (three 4-byte members), and for **IORING_OP_OPENAT** and **IORING_OP_OPENAT2** this would be 24 (three 8-byte members).
+
+If the application\'s *pdu_size* matches the kernel\'s expected size for the opcode, registration succeeds. If the sizes differ, the behavior depends on whether **IO_URING_BPF_FILTER_SZ_STRICT** is set in *flags*:
+
+> - If **IO_URING_BPF_FILTER_SZ_STRICT** is set, registration fails with **-EMSGSIZE** if the sizes differ.
+>
+> - If **IO_URING_BPF_FILTER_SZ_STRICT** is not set, registration is allowed if the application\'s *pdu_size* is smaller than the kernel\'s. This permits older applications that were compiled against a smaller payload to still load filters, as the kernel can safely evaluate the filter on the subset of data the application expects.
+>
+> - Regardless of **IO_URING_BPF_FILTER_SZ_STRICT**, registration always fails with **-EMSGSIZE** if the application\'s *pdu_size* is larger than the kernel\'s, since the kernel cannot provide data that it does not support.
+
+On an **-EMSGSIZE** failure, the kernel writes back the kernel\'s expected *pdu_size* into the **struct io_uring_bpf_filter** passed by the application. This allows the application to discover the kernel\'s expected payload size and adjust or retry accordingly.
+
+*flags* can be zero or a bitwise OR of the following:
+
+**IO_URING_BPF_FILTER_DENY_REST**
+
+: When set, any opcode that does not have a filter registered will be denied. This allows creating an allowlist of permitted operations.
+
+**IO_URING_BPF_FILTER_SZ_STRICT**
+
+: When set, registration of a filter will fail with **-EMSGSIZE** if the application\'s *pdu_size* does not exactly match the kernel\'s expected payload size for the opcode. Without this flag, the kernel permits filters where the application\'s *pdu_size* is smaller than or equal to the kernel\'s.
+
+## Filter Context
+
+The BPF filter receives a context structure that can be inspected using **BPF_LD** instructions with absolute addressing. The context layout is:
+
+ struct io_uring_bpf_ctx {
+ __u64 user_data; /* offset 0: user_data from SQE */
+ __u8 opcode; /* offset 8: io_uring opcode */
+ __u8 sqe_flags; /* offset 9: SQE flags */
+ __u8 pdu_size; /* offset 10: aux data size for filter */
+ __u8 pad[5]; /* offset 11-15: padding */
+ union {
+ struct {
+ __u32 family; /* offset 16: socket family */
+ __u32 type; /* offset 20: socket type */
+ __u32 protocol; /* offset 24: socket protocol */
+ } socket;
+ struct {
+ __u64 flags; /* offset 16: open flags */
+ __u64 mode; /* offset 24: file mode */
+ __u64 resolve; /* offset 32: resolve flags */
+ } open;
+ };
+ };
+
+The *pdu_size* field indicates the size in bytes of the operation-specific data passed in the union. A filter can check this value to verify it is receiving the expected payload. This is useful for forward compatibility: if a future kernel adds new members to an operation\'s context, the filter can inspect *pdu_size* to determine whether those fields are present.
+
+For **IORING_OP_SOCKET** operations, the socket family, type, and protocol fields are populated and can be used to filter based on socket parameters. *pdu_size* is set to 12 (three 4-byte members).
+
+For **IORING_OP_OPENAT** and **IORING_OP_OPENAT2** operations, the open flags, mode, and resolve fields are populated. The flags field contains the open flags (e.g., **O_RDONLY**, **O_CREAT**). The resolve field is only meaningful for **IORING_OP_OPENAT2** and contains resolve flags (e.g., **RESOLVE_IN_ROOT**). *pdu_size* is set to 24 (three 8-byte members).
+
+## Filter Stacking
+
+Multiple filters can be registered for the same opcode. When multiple filters exist, they are evaluated in order and all must return non-zero for the operation to be allowed. For task-level filters, the child\'s filters are evaluated before the parent\'s filters.
+
+# RETURN VALUE
+
+On success, these functions return 0. On failure, they return a negative error code.
+
+# ERRORS
+
+**-EINVAL**
+
+: Invalid filter, opcode, or flags specified.
+
+**-EMSGSIZE**
+
+: The application\'s *pdu_size* does not match the kernel\'s expected payload size for the opcode. This occurs when **IO_URING_BPF_FILTER_SZ_STRICT** is set and the sizes differ, or when the application\'s *pdu_size* is larger than the kernel\'s regardless of flags.
+
+**-ENOMEM**
+
+: Insufficient memory to register the filter.
+
+**-EFAULT**
+
+: The filter pointer is invalid.
+
+**-EACCES**
+
+: The caller does not have the **CAP_SYS_ADMIN** capability and the **no_new_privs** attribute is not set on the calling task. See **prctl**(2) with **PR_SET_NO_NEW_PRIVS**.
+
+# EXAMPLES
+
+## Deny all NOP operations
+
+ #include <sys/prctl.h>
+ #include <linux/filter.h>
+ #include <liburing.h>
+ #include <liburing/io_uring/bpf_filter.h>
+
+ struct sock_filter deny_filter[] = {
+ BPF_STMT(BPF_RET | BPF_K, 0), /* return 0 (deny) */
+ };
+
+ struct io_uring_bpf bpf = {
+ .cmd_type = IO_URING_BPF_CMD_FILTER,
+ .filter = {
+ .opcode = IORING_OP_NOP,
+ .filter_len = 1,
+ .filter_ptr = (unsigned long) deny_filter,
+ },
+ };
+
+ /* Must set no_new_privs before registering task filters */
+ prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+
+ /* Register on a specific ring */
+ io_uring_register_bpf_filter(&ring, &bpf);
+
+ /* Or register on the task */
+ io_uring_register_bpf_filter_task(&bpf);
+
+## Allow only AF_INET sockets
+
+ #include <sys/prctl.h>
+ #include <linux/filter.h>
+ #include <sys/socket.h>
+ #include <liburing.h>
+ #include <liburing/io_uring/bpf_filter.h>
+
+ #define CTX_OFF_SOCKET_FAMILY 16
+
+ struct sock_filter inet_only_filter[] = {
+ /* Load socket family from context */
+ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, CTX_OFF_SOCKET_FAMILY),
+ /* If family == AF_INET, jump to allow */
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AF_INET, 0, 1),
+ /* Allow: return 1 */
+ BPF_STMT(BPF_RET | BPF_K, 1),
+ /* Deny: return 0 */
+ BPF_STMT(BPF_RET | BPF_K, 0),
+ };
+
+ struct io_uring_bpf bpf = {
+ .cmd_type = IO_URING_BPF_CMD_FILTER,
+ .filter = {
+ .opcode = IORING_OP_SOCKET,
+ .filter_len = 4,
+ .filter_ptr = (unsigned long) inet_only_filter,
+ .pdu_size = 12, /* 3x __u32: family, type, protocol */
+ },
+ };
+
+ prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+ io_uring_register_bpf_filter_task(&bpf);
+
+## Allow only NOP, deny everything else
+
+ struct sock_filter allow_filter[] = {
+ BPF_STMT(BPF_RET | BPF_K, 1), /* return 1 (allow) */
+ };
+
+ struct io_uring_bpf bpf = {
+ .cmd_type = IO_URING_BPF_CMD_FILTER,
+ .filter = {
+ .opcode = IORING_OP_NOP,
+ .flags = IO_URING_BPF_FILTER_DENY_REST,
+ .filter_len = 1,
+ .filter_ptr = (unsigned long) allow_filter,
+ },
+ };
+
+ prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+ io_uring_register_bpf_filter_task(&bpf);
+
+## Discover kernel pdu_size for an opcode
+
+This example demonstrates how to use the **-EMSGSIZE** write-back to discover the kernel\'s expected payload size.
+
+ struct sock_filter allow[] = {
+ BPF_STMT(BPF_RET | BPF_K, 1),
+ };
+
+ struct io_uring_bpf bpf = {
+ .cmd_type = IO_URING_BPF_CMD_FILTER,
+ .filter = {
+ .opcode = IORING_OP_SOCKET,
+ .flags = IO_URING_BPF_FILTER_SZ_STRICT,
+ .filter_len = 1,
+ .filter_ptr = (unsigned long) allow,
+ .pdu_size = 0, /* intentionally wrong */
+ },
+ };
+ int ret;
+
+ ret = io_uring_register_bpf_filter(&ring, &bpf);
+ if (ret == -EMSGSIZE) {
+ /* kernel wrote back expected size */
+ printf("kernel pdu_size for SOCKET: %u\n",
+ bpf.filter.pdu_size);
+ /* retry with correct size */
+ ret = io_uring_register_bpf_filter(&ring, &bpf);
+ }
+
+# NOTES
+
+## Privilege Requirements
+
+Similar to **seccomp**(2), registering BPF filters requires either the **CAP_SYS_ADMIN** capability or the **no_new_privs** attribute to be set on the calling task. This prevents an unprivileged process from installing a filter and then executing a setuid binary, which would run with elevated privileges but under the attacker-controlled filter.
+
+To set the **no_new_privs** attribute, call:
+
+ prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+
+Once set, **no_new_privs** cannot be unset and is inherited by child processes across **fork**(2) and preserved across **execve**(2).
+
+## Inheritance
+
+Task-level filters registered with **io_uring_register_bpf_filter_task**(3) are inherited by child processes. This allows a parent process to establish security restrictions that apply to all descendants. Children can add additional restrictions but cannot remove or weaken filters set by their ancestors.
+
+Ring-level filters registered with **io_uring_register_bpf_filter**(3) only apply to that specific ring and are not inherited.
+
+# SEE ALSO
+
+**io_uring_register**(2), **io_uring_setup**(2), **bpf**(2), **seccomp**(2)
diff --git a/man/io_uring_register_bpf_filter_task.3 b/man/io_uring_register_bpf_filter_task.3
deleted file mode 120000
index ed26b2aa..00000000
--- a/man/io_uring_register_bpf_filter_task.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_register_bpf_filter.3
\ No newline at end of file
diff --git a/man/io_uring_register_buf_ring.3 b/man/io_uring_register_buf_ring.3
deleted file mode 100644
index 14f5cdec..00000000
--- a/man/io_uring_register_buf_ring.3
+++ /dev/null
@@ -1,165 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_register_buf_ring 3 "May 18, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_register_buf_ring \- register buffer ring for provided buffers
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_register_buf_ring(struct io_uring *" ring ",
-.BI " struct io_uring_buf_reg *" reg ",
-.BI " unsigned int " flags ");"
-.BI "
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_register_buf_ring (3)
-function registers a shared buffer ring to be used with provided buffers. For
-the request types that support it, provided buffers are given to the ring and
-one is selected by a request if it has
-.B IOSQE_BUFFER_SELECT
-set in the SQE
-.IR flags ,
-when the request is ready to receive data. This allows both clear ownership
-of the buffer lifetime, and a way to have more read/receive type of operations
-in flight than buffers available.
-
-The
-.I reg
-argument must be filled in with the appropriate information. It looks as
-follows:
-.PP
-.in +4n
-.EX
-struct io_uring_buf_reg {
- __u64 ring_addr;
- __u32 ring_entries;
- __u16 bgid;
- __u16 flags;
- __u32 min_left;
- __u32 resv[5];
-};
-.EE
-.in
-.PP
-The
-.I ring_addr
-field must contain the address to the memory allocated to fit this ring.
-The memory must be page aligned and hence allocated appropriately using eg
-.BR posix_memalign (3)
-or similar. The size of the ring is the product of
-.I ring_entries
-and the size of
-.IR "struct io_uring_buf" .
-.I ring_entries
-is the desired size of the ring, and must be a power-of-2 in size. The maximum
-size allowed is 2^15 (32768).
-.I bgid
-is the buffer group ID associated with this ring. SQEs that select a buffer
-have a buffer group associated with them in their
-.I buf_group
-field, and the associated CQEs will have
-.B IORING_CQE_F_BUFFER
-set in their
-.I flags
-member, which will also contain the specific ID of the buffer selected.
-.I min_left
-is the minimum value that should be left in an incrementally consumed buffer
-ring for the buffer to be considered valid. If not set, defaults to a single
-byte. Only valid with
-.B IOU_PBUF_RING_INC
-set in
-.I flags .
-The rest of the fields are reserved and must be cleared to zero.
-
-The
-.I flags
-argument can be set to one of the following values:
-.TP
-.B IOU_PBUF_RING_INC
-The buffers in this ring can be incrementally consumed. With partial
-consumption, each completion of a given buffer ID will continue where the
-previous one left off, or from the start if no completions have been seen yet.
-When more completions should be expected for a given buffer ID, the CQE will
-have
-.B IORING_CQE_F_BUF_MORE
-set in the
-.I flags
-member. Available since 6.12.
-.PP
-
-A shared buffer ring looks as follows:
-.PP
-.in +4n
-.EX
-struct io_uring_buf_ring {
- union {
- struct {
- __u64 resv1;
- __u32 resv2;
- __u16 resv3;
- __u16 tail;
- };
- struct io_uring_buf bufs[0];
- };
-};
-.EE
-.in
-.PP
-where
-.I tail
-is the index at which the application can insert new buffers for consumption
-by requests, and
-.I struct io_uring_buf
-is buffer definition:
-.PP
-.in +4n
-.EX
-struct io_uring_buf {
- __u64 addr;
- __u32 len;
- __u16 bid;
- __u16 resv;
-};
-.EE
-.in
-.PP
-where
-.I addr
-is the address for the buffer,
-.I len
-is the length of the buffer in bytes, and
-.I bid
-is the buffer ID that will be returned in the CQE once consumed.
-
-Reserved fields must not be touched. Applications must use
-.BR io_uring_buf_ring_init (3)
-to initialise the buffer ring before use. Applications may use
-.BR io_uring_buf_ring_add (3)
-and
-.BR io_uring_buf_ring_advance (3)
-or
-.BR io_uring_buf_ring_cq_advance (3)
-to provide buffers, which will set these fields and update the tail.
-
-Available since 5.19.
-
-.SH RETURN VALUE
-On success
-.BR io_uring_register_buf_ring (3)
-returns 0. On failure it returns
-.BR -errno .
-.SH NOTES
-Unless manual setup is needed, it's recommended to use
-.BR io_uring_setup_buf_ring (3)
-as it provides a simpler way to setup a provided buffer ring.
-.SH SEE ALSO
-.BR io_uring_buf_ring_init (3),
-.BR io_uring_buf_ring_add (3),
-.BR io_uring_setup_buf_ring (3),
-.BR io_uring_buf_ring_advance (3),
-.BR io_uring_buf_ring_cq_advance (3)
diff --git a/man/io_uring_register_buf_ring.3.md b/man/io_uring_register_buf_ring.3.md
new file mode 100644
index 00000000..f4cfc0a3
--- /dev/null
+++ b/man/io_uring_register_buf_ring.3.md
@@ -0,0 +1,88 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: May 18, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_register_buf_ring
+---
+
+# NAME
+
+io_uring_register_buf_ring - register buffer ring for provided buffers
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_register_buf_ring(struct io_uring * ring ,
+ struct io_uring_buf_reg * reg ,
+ unsigned int flags );
+
+
+# DESCRIPTION
+
+The **io_uring_register_buf_ring**(3) function registers a shared buffer ring to be used with provided buffers. For the request types that support it, provided buffers are given to the ring and one is selected by a request if it has **IOSQE_BUFFER_SELECT** set in the SQE *flags*, when the request is ready to receive data. This allows both clear ownership of the buffer lifetime, and a way to have more read/receive type of operations in flight than buffers available.
+
+The *reg* argument must be filled in with the appropriate information. It looks as follows:
+
+ struct io_uring_buf_reg {
+ __u64 ring_addr;
+ __u32 ring_entries;
+ __u16 bgid;
+ __u16 flags;
+ __u32 min_left;
+ __u32 resv[5];
+ };
+
+The *ring_addr* field must contain the address to the memory allocated to fit this ring. The memory must be page aligned and hence allocated appropriately using eg **posix_memalign**(3) or similar. The size of the ring is the product of *ring_entries* and the size of *struct io_uring_buf*. *ring_entries* is the desired size of the ring, and must be a power-of-2 in size. The maximum size allowed is 2\^15 (32768). *bgid* is the buffer group ID associated with this ring. SQEs that select a buffer have a buffer group associated with them in their *buf_group* field, and the associated CQEs will have **IORING_CQE_F_BUFFER** set in their *flags* member, which will also contain the specific ID of the buffer selected. *min_left* is the minimum value that should be left in an incrementally consumed buffer ring for the buffer to be considered valid. If not set, defaults to a single byte. Only valid with **IOU_PBUF_RING_INC** set in *flags .* The rest of the fields are reserved and must be cleared to zero.
+
+The *flags* argument can be set to one of the following values:
+
+**IOU_PBUF_RING_INC**
+
+: The buffers in this ring can be incrementally consumed. With partial consumption, each completion of a given buffer ID will continue where the previous one left off, or from the start if no completions have been seen yet. When more completions should be expected for a given buffer ID, the CQE will have **IORING_CQE_F_BUF_MORE** set in the *flags* member. Available since 6.12.
+
+A shared buffer ring looks as follows:
+
+ struct io_uring_buf_ring {
+ union {
+ struct {
+ __u64 resv1;
+ __u32 resv2;
+ __u16 resv3;
+ __u16 tail;
+ };
+ struct io_uring_buf bufs[0];
+ };
+ };
+
+where *tail* is the index at which the application can insert new buffers for consumption by requests, and *struct io_uring_buf* is buffer definition:
+
+ struct io_uring_buf {
+ __u64 addr;
+ __u32 len;
+ __u16 bid;
+ __u16 resv;
+ };
+
+where *addr* is the address for the buffer, *len* is the length of the buffer in bytes, and *bid* is the buffer ID that will be returned in the CQE once consumed.
+
+Reserved fields must not be touched. Applications must use **io_uring_buf_ring_init**(3) to initialise the buffer ring before use. Applications may use **io_uring_buf_ring_add**(3) and **io_uring_buf_ring_advance**(3) or **io_uring_buf_ring_cq_advance**(3) to provide buffers, which will set these fields and update the tail.
+
+Available since 5.19.
+
+# RETURN VALUE
+
+On success **io_uring_register_buf_ring**(3) returns 0. On failure it returns **-errno**.
+
+# NOTES
+
+Unless manual setup is needed, it\'s recommended to use **io_uring_setup_buf_ring**(3) as it provides a simpler way to setup a provided buffer ring.
+
+# SEE ALSO
+
+**io_uring_buf_ring_init**(3), **io_uring_buf_ring_add**(3), **io_uring_setup_buf_ring**(3), **io_uring_buf_ring_advance**(3), **io_uring_buf_ring_cq_advance**(3)
diff --git a/man/io_uring_register_buffers.3 b/man/io_uring_register_buffers.3
deleted file mode 100644
index dfb292da..00000000
--- a/man/io_uring_register_buffers.3
+++ /dev/null
@@ -1,105 +0,0 @@
-.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_register_buffers 3 "November 15, 2021" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_register_buffers \- register buffers for fixed buffer operations
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_register_buffers(struct io_uring *" ring ","
-.BI " const struct iovec *" iovecs ","
-.BI " unsigned " nr_iovecs ");"
-.PP
-.BI "int io_uring_register_buffers_tags(struct io_uring *" ring ","
-.BI " const struct iovec *" iovecs ","
-.BI " const __u64 *" tags ","
-.BI " unsigned " nr ");"
-.PP
-.BI "int io_uring_register_buffers_sparse(struct io_uring *" ring ","
-.BI " unsigned " nr_iovecs ");"
-.PP
-.BI "int io_uring_register_buffers_update_tag(struct io_uring *" ring ","
-.BI " unsigned " off ","
-.BI " const struct iovec *" iovecs ","
-.BI " const __u64 *" tags ","
-.BI " unsigned " nr ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_register_buffers (3)
-function registers
-.I nr_iovecs
-number of buffers defined by the array
-.I iovecs
-belonging to the
-.IR ring .
-
-The
-.BR io_uring_register_buffers_tags (3)
-function behaves the same as
-.BR io_uring_register_buffers (3)
-function but additionally takes
-.I tags
-parameter. See
-.B IORING_REGISTER_BUFFERS2
-for the resource tagging description.
-
-The
-.BR io_uring_register_buffers_sparse (3)
-function registers
-.I nr_iovecs
-empty buffers belonging to the
-.IR ring .
-These buffers must be updated before use, using eg
-.BR io_uring_register_buffers_update_tag (3).
-
-After the caller has registered the buffers, they can be used with one of the
-fixed buffers functions.
-
-Registered buffers is an optimization that is useful in conjunction with
-.B O_DIRECT
-reads and writes, where it maps the specified range into the kernel once when
-the buffer is registered rather than doing a map and unmap for each IO
-every time IO is performed to that region. Additionally, it also avoids
-manipulating the page reference counts for each IO.
-
-The
-.BR io_uring_register_buffers_update_tag (3)
-function updates registered buffers with new ones, either turning a sparse
-entry into a real one, or replacing an existing entry. The
-.I off
-is offset on which to start the update
-.I nr
-number of buffers defined by the array
-.I iovecs
-belonging to the
-.IR ring .
-The
-.I tags
-points to an array of tags. See
-.B IORING_REGISTER_BUFFERS2
-for the resource tagging description.
-
-.SH RETURN VALUE
-On success
-.BR io_uring_register_buffers (3),
-.BR io_uring_register_buffers_tags (3)
-and
-.BR io_uring_register_buffers_sparse (3)
-return 0.
-.BR io_uring_register_buffers_update_tag (3)
-return number of buffers updated.
-On failure they return
-.BR -errno .
-.SH SEE ALSO
-.BR io_uring_register (2),
-.BR io_uring_get_sqe (3),
-.BR io_uring_unregister_buffers (3),
-.BR io_uring_clone_buffers (3),
-.BR io_uring_register_buf_ring (3),
-.BR io_uring_prep_read_fixed (3),
-.BR io_uring_prep_write_fixed (3)
diff --git a/man/io_uring_register_buffers.3.md b/man/io_uring_register_buffers.3.md
new file mode 100644
index 00000000..4447d711
--- /dev/null
+++ b/man/io_uring_register_buffers.3.md
@@ -0,0 +1,59 @@
+.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: November 15, 2021
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_register_buffers
+---
+
+# NAME
+
+io_uring_register_buffers - register buffers for fixed buffer operations
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ 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 ,
+ const struct iovec * iovecs ,
+ const __u64 * tags ,
+ unsigned nr );
+
+ int io_uring_register_buffers_sparse(struct io_uring * ring ,
+ unsigned nr_iovecs );
+
+ int io_uring_register_buffers_update_tag(struct io_uring * ring ,
+ unsigned off ,
+ const struct iovec * iovecs ,
+ const __u64 * tags ,
+ unsigned nr );
+
+# DESCRIPTION
+
+The **io_uring_register_buffers**(3) function registers *nr_iovecs* number of buffers defined by the array *iovecs* belonging to the *ring*.
+
+The **io_uring_register_buffers_tags**(3) function behaves the same as **io_uring_register_buffers**(3) function but additionally takes *tags* parameter. See **IORING_REGISTER_BUFFERS2** for the resource tagging description.
+
+The **io_uring_register_buffers_sparse**(3) function registers *nr_iovecs* empty buffers belonging to the *ring*. These buffers must be updated before use, using eg **io_uring_register_buffers_update_tag**(3).
+
+After the caller has registered the buffers, they can be used with one of the fixed buffers functions.
+
+Registered buffers is an optimization that is useful in conjunction with **O_DIRECT** reads and writes, where it maps the specified range into the kernel once when the buffer is registered rather than doing a map and unmap for each IO every time IO is performed to that region. Additionally, it also avoids manipulating the page reference counts for each IO.
+
+The **io_uring_register_buffers_update_tag**(3) function updates registered buffers with new ones, either turning a sparse entry into a real one, or replacing an existing entry. The *off* is offset on which to start the update *nr* number of buffers defined by the array *iovecs* belonging to the *ring*. The *tags* points to an array of tags. See **IORING_REGISTER_BUFFERS2** for the resource tagging description.
+
+# RETURN VALUE
+
+On success **io_uring_register_buffers**(3), **io_uring_register_buffers_tags**(3) and **io_uring_register_buffers_sparse**(3) return 0. **io_uring_register_buffers_update_tag**(3) return number of buffers updated. On failure they return **-errno**.
+
+# SEE ALSO
+
+**io_uring_register**(2), **io_uring_get_sqe**(3), **io_uring_unregister_buffers**(3), **io_uring_clone_buffers**(3), **io_uring_register_buf_ring**(3), **io_uring_prep_read_fixed**(3), **io_uring_prep_write_fixed**(3)
diff --git a/man/io_uring_register_buffers_sparse.3 b/man/io_uring_register_buffers_sparse.3
deleted file mode 120000
index 1019ce4f..00000000
--- a/man/io_uring_register_buffers_sparse.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_register_buffers.3
\ No newline at end of file
diff --git a/man/io_uring_register_buffers_tags.3 b/man/io_uring_register_buffers_tags.3
deleted file mode 120000
index 1019ce4f..00000000
--- a/man/io_uring_register_buffers_tags.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_register_buffers.3
\ No newline at end of file
diff --git a/man/io_uring_register_buffers_update_tag.3 b/man/io_uring_register_buffers_update_tag.3
deleted file mode 120000
index 1019ce4f..00000000
--- a/man/io_uring_register_buffers_update_tag.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_register_buffers.3
\ No newline at end of file
diff --git a/man/io_uring_register_clock.3 b/man/io_uring_register_clock.3
deleted file mode 100644
index 56ed1ac2..00000000
--- a/man/io_uring_register_clock.3
+++ /dev/null
@@ -1,72 +0,0 @@
-.\" Copyright (C) 2024 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_register_clock 3 "Aug 18, 2024" "liburing-2.8" "liburing Manual"
-.SH NAME
-io_uring_register_clock \- set clock source for event waiting
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_register_clock(struct io_uring *" ring ",
-.BI " struct io_uring_clock_register *" arg ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_register_clock (3)
-function registers which clock source should be used by io_uring, when an
-application waits for event completions. The
-.IR ring
-argument should point to the ring in question, and the
-.IR arg
-argument should be a pointer to a
-.B struct io_uring_clock_register .
-
-The
-.IR arg
-argument must be filled in with the appropriate information. It looks as
-follows:
-.PP
-.in +4n
-.EX
-struct io_uring_clock_register {
- __u32 clockid;
- __u32 __resv[3];
-};
-.EE
-.in
-.PP
-The
-.I clockid
-field must contain the clock source, with valid sources being:
-.TP
-.B CLOCK_MONOTONIC
-a nonsettable system-wide clock that represents monotonic time.
-.TP
-.B CLOCK_BOOTTIME
-A nonsettable system-wide clock that is identical to
-.B CLOCK_MONOTONIC ,
-except that is also icnludes any time that the system is suspended.
-.PP
-See
-.BR clock_gettime (3)
-for more details.
-
-The
-.I __resv
-fields must be filled with zeroes.
-
-Available since 6.12.
-
-.SH RETURN VALUE
-On success
-.BR io_uring_register_clock (3)
-returns 0. On failure it returns
-.BR -errno .
-.SH SEE ALSO
-.BR clock_gettime (3),
-.BR io_uring_register (2),
-.BR io_uring_wait_cqe (3),
-.BR io_uring_wait_cqe_timeout (3),
diff --git a/man/io_uring_register_clock.3.md b/man/io_uring_register_clock.3.md
new file mode 100644
index 00000000..0a3526bc
--- /dev/null
+++ b/man/io_uring_register_clock.3.md
@@ -0,0 +1,57 @@
+.\" Copyright (C) 2024 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: Aug 18, 2024
+footer: liburing-2.8
+header: liburing Manual
+section: 3
+title: io_uring_register_clock
+---
+
+# NAME
+
+io_uring_register_clock - set clock source for event waiting
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_register_clock(struct io_uring * ring ,
+ struct io_uring_clock_register * arg );
+
+# DESCRIPTION
+
+The **io_uring_register_clock**(3) function registers which clock source should be used by io_uring, when an application waits for event completions. The *ring* argument should point to the ring in question, and the *arg* argument should be a pointer to a **struct io_uring_clock_register .**
+
+The *arg* argument must be filled in with the appropriate information. It looks as follows:
+
+ struct io_uring_clock_register {
+ __u32 clockid;
+ __u32 __resv[3];
+ };
+
+The *clockid* field must contain the clock source, with valid sources being:
+
+**CLOCK_MONOTONIC**
+
+: a nonsettable system-wide clock that represents monotonic time.
+
+**CLOCK_BOOTTIME**
+
+: A nonsettable system-wide clock that is identical to **CLOCK_MONOTONIC ,** except that is also icnludes any time that the system is suspended.
+
+See **clock_gettime**(3) for more details.
+
+The *\_\_resv* fields must be filled with zeroes.
+
+Available since 6.12.
+
+# RETURN VALUE
+
+On success **io_uring_register_clock**(3) returns 0. On failure it returns **-errno**.
+
+# SEE ALSO
+
+**clock_gettime**(3), **io_uring_register**(2), **io_uring_wait_cqe**(3), **io_uring_wait_cqe_timeout**(3),
diff --git a/man/io_uring_register_eventfd.3 b/man/io_uring_register_eventfd.3
deleted file mode 100644
index d7b23ee4..00000000
--- a/man/io_uring_register_eventfd.3
+++ /dev/null
@@ -1,50 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_register_eventfd 3 "April 16, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_register_eventfd \- register an eventfd with a ring
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_register_eventfd(struct io_uring *" ring ","
-.BI " int " fd ");"
-.PP
-.BI "int io_uring_register_eventfd_async(struct io_uring *" ring ","
-.BI " int " fd ");"
-.PP
-.BI "int io_uring_unregister_eventfd(struct io_uring *" ring ");"
-.fi
-.SH DESCRIPTION
-.PP
-.BR io_uring_register_eventfd (3)
-registers the eventfd file descriptor
-.I fd
-with the ring identified by
-.IR ring .
-
-Whenever completions are posted to the CQ ring, an eventfd notification
-is generated with the registered eventfd descriptor. If
-.BR io_uring_register_eventfd_async (3)
-is used, only events that completed out-of-line will trigger a notification.
-
-It notifications are no longer desired,
-.BR io_uring_unregister_eventfd (3)
-may be called to remove the eventfd registration. No eventfd argument is
-needed, as a ring can only have a single eventfd registered.
-
-.SH NOTES
-While io_uring generally takes care to avoid spurious events, they can occur.
-Similarly, batched completions of CQEs may only trigger a single eventfd
-notification even if multiple CQEs are posted. The application should make no
-assumptions on number of events being available having a direct correlation to
-eventfd notifications posted. An eventfd notification must thus only be treated
-as a hint to check the CQ ring for completions.
-.SH RETURN VALUE
-Returns 0 on success, or
-.BR -errno
-on error.
-.SH SEE ALSO
-.BR eventfd (2)
diff --git a/man/io_uring_register_eventfd.3.md b/man/io_uring_register_eventfd.3.md
new file mode 100644
index 00000000..6efd702a
--- /dev/null
+++ b/man/io_uring_register_eventfd.3.md
@@ -0,0 +1,47 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: April 16, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_register_eventfd
+---
+
+# NAME
+
+io_uring_register_eventfd - register an eventfd with a ring
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_register_eventfd(struct io_uring * ring ,
+ int fd );
+
+ int io_uring_register_eventfd_async(struct io_uring * ring ,
+ int fd );
+
+ int io_uring_unregister_eventfd(struct io_uring * ring );
+
+# DESCRIPTION
+
+**io_uring_register_eventfd**(3) registers the eventfd file descriptor *fd* with the ring identified by *ring*.
+
+Whenever completions are posted to the CQ ring, an eventfd notification is generated with the registered eventfd descriptor. If **io_uring_register_eventfd_async**(3) is used, only events that completed out-of-line will trigger a notification.
+
+It notifications are no longer desired, **io_uring_unregister_eventfd**(3) may be called to remove the eventfd registration. No eventfd argument is needed, as a ring can only have a single eventfd registered.
+
+# NOTES
+
+While io_uring generally takes care to avoid spurious events, they can occur. Similarly, batched completions of CQEs may only trigger a single eventfd notification even if multiple CQEs are posted. The application should make no assumptions on number of events being available having a direct correlation to eventfd notifications posted. An eventfd notification must thus only be treated as a hint to check the CQ ring for completions.
+
+# RETURN VALUE
+
+Returns 0 on success, or **-errno** on error.
+
+# SEE ALSO
+
+**eventfd**(2)
diff --git a/man/io_uring_register_eventfd_async.3 b/man/io_uring_register_eventfd_async.3
deleted file mode 120000
index 66599571..00000000
--- a/man/io_uring_register_eventfd_async.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_register_eventfd.3
\ No newline at end of file
diff --git a/man/io_uring_register_file_alloc_range.3 b/man/io_uring_register_file_alloc_range.3
deleted file mode 100644
index b4a42678..00000000
--- a/man/io_uring_register_file_alloc_range.3
+++ /dev/null
@@ -1,52 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_register_file_alloc_range 3 "Oct 21, 2022" "liburing-2.3" "liburing Manual"
-.SH NAME
-io_uring_register_file_alloc_range \- set range for fixed file allocations
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_register_file_alloc_range(struct io_uring *" ring ",
-.BI " unsigned " off ","
-.BI " unsigned " len ");"
-.BI "
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_register_file_alloc_range (3)
-function sets the allowable range for fixed file index allocations within the
-kernel. When requests that can instantiate a new fixed file are used with
-.B IORING_FILE_INDEX_ALLOC ,
-the application is asking the kernel to allocate a new fixed file descriptor
-rather than pass in a specific value for one. By default, the kernel will
-pick any available fixed file descriptor within the range available. Calling
-this function with
-.I off
-set to the starting offset and
-.I len
-set to the number of descriptors, the application can limit the allocated
-descriptors to that particular range. This effectively allows the application
-to set aside a range just for dynamic allocations, with the remainder being
-used for specific values.
-
-The application must have registered a fixed file table upfront, e.g. through
-.BR io_uring_register_files (3)
-or
-.BR io_uring_register_files_sparse (3) .
-
-Available since 6.0.
-
-.SH RETURN VALUE
-On success
-.BR io_uring_register_file_alloc_range (3)
-returns 0. On failure it returns
-.BR -errno .
-.SH SEE ALSO
-.BR io_uring_register_files (3)
-.BR io_uring_prep_accept_direct (3)
-.BR io_uring_prep_openat_direct (3)
-.BR io_uring_prep_socket_direct (3)
diff --git a/man/io_uring_register_file_alloc_range.3.md b/man/io_uring_register_file_alloc_range.3.md
new file mode 100644
index 00000000..00290e88
--- /dev/null
+++ b/man/io_uring_register_file_alloc_range.3.md
@@ -0,0 +1,40 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: Oct 21, 2022
+footer: liburing-2.3
+header: liburing Manual
+section: 3
+title: io_uring_register_file_alloc_range
+---
+
+# NAME
+
+io_uring_register_file_alloc_range - set range for fixed file allocations
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_register_file_alloc_range(struct io_uring * ring ,
+ unsigned off ,
+ unsigned len );
+
+
+# DESCRIPTION
+
+The **io_uring_register_file_alloc_range**(3) function sets the allowable range for fixed file index allocations within the kernel. When requests that can instantiate a new fixed file are used with **IORING_FILE_INDEX_ALLOC ,** the application is asking the kernel to allocate a new fixed file descriptor rather than pass in a specific value for one. By default, the kernel will pick any available fixed file descriptor within the range available. Calling this function with *off* set to the starting offset and *len* set to the number of descriptors, the application can limit the allocated descriptors to that particular range. This effectively allows the application to set aside a range just for dynamic allocations, with the remainder being used for specific values.
+
+The application must have registered a fixed file table upfront, e.g. through **io_uring_register_files**(3) or **io_uring_register_files_sparse**(3)**.**
+
+Available since 6.0.
+
+# RETURN VALUE
+
+On success **io_uring_register_file_alloc_range**(3) returns 0. On failure it returns **-errno**.
+
+# SEE ALSO
+
+**io_uring_register_files**(3) **io_uring_prep_accept_direct**(3) **io_uring_prep_openat_direct**(3) **io_uring_prep_socket_direct**(3)
diff --git a/man/io_uring_register_files.3 b/man/io_uring_register_files.3
deleted file mode 100644
index c7f73e92..00000000
--- a/man/io_uring_register_files.3
+++ /dev/null
@@ -1,120 +0,0 @@
-.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_register_files 3 "November 15, 2021" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_register_files \- register file descriptors
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_register_files(struct io_uring *" ring ","
-.BI " const int *" files ","
-.BI " unsigned " nr_files ");"
-.PP
-.BI "int io_uring_register_files_tags(struct io_uring *" ring ","
-.BI " const int *" files ","
-.BI " const __u64 *" tags ","
-.BI " unsigned " nr ");"
-.PP
-.BI "int io_uring_register_files_sparse(struct io_uring *" ring ","
-.BI " unsigned " nr_files ");"
-.PP
-.BI "int io_uring_register_files_update(struct io_uring *" ring ","
-.BI " unsigned " off ","
-.BI " const int *" files ","
-.BI " unsigned " nr_files ");"
-.PP
-.BI "int io_uring_register_files_update_tag(struct io_uring *" ring ","
-.BI " unsigned " off ","
-.BI " const int *" files ","
-.BI " const __u64 *" tags ","
-.BI " unsigned " nr_files ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_register_files (3)
-function registers
-.I nr_files
-number of file descriptors defined by the array
-.I files
-belonging to the
-.I ring
-for subsequent operations.
-
-The
-.BR io_uring_register_files_tags (3)
-function behaves the same as
-.BR io_uring_register_files (3)
-function but additionally takes
-.I tags
-parameter. See
-.B IORING_REGISTER_BUFFERS2
-for the resource tagging description.
-
-The
-.BR io_uring_register_files_sparse (3)
-function registers an empty file table of
-.I nr_files
-number of file descriptors. These files must be updated before use, using eg
-.BR io_uring_register_files_update_tag (3).
-Note that if the size of the sparse table exceeds what
-.B RLIMIT_NOFILE
-allows, then
-.BR io_uring_register_files_sparse (3)
-will attempt to raise the limit using
-.B setrlimit (2)
-and retry the operation. If the registration fails after doing that, then an
-error will be returned.
-The sparse variant is available in kernels 5.19 and later.
-
-Registering a file table is a prerequisite for using any request that uses
-direct descriptors.
-
-Registered files have less overhead per operation than normal files. This
-is due to the kernel grabbing a reference count on a file when an operation
-begins, and dropping it when it's done. When the process file table is
-shared, for example if the process has ever created any threads, then this
-cost goes up even more. Using registered files reduces the overhead of
-file reference management across requests that operate on a file.
-
-The
-.BR io_uring_register_files_update (3)
-function updates existing registered files. The
-.I off
-is offset on which to start the update
-.I nr_files
-number of files defined by the array
-.I files
-belonging to the
-.IR ring .
-
-The
-.BR io_uring_register_files_update_tag (3)
-function behaves the same as
-.BR io_uring_register_files_update (3)
-function but additionally takes
-.I tags
-parameter. See
-.B IORING_REGISTER_BUFFERS2
-for the resource tagging description.
-
-.SH RETURN VALUE
-On success
-.BR io_uring_register_files (3),
-.BR io_uring_register_files_tags (3)
-and
-.BR io_uring_register_files_sparse (3)
-return 0.
-.BR io_uring_register_files_update (3)
-and
-.BR io_uring_register_files_update_tag (3)
-return number of files updated.
-On failure they return
-.BR -errno .
-.SH SEE ALSO
-.BR io_uring_register (2),
-.BR io_uring_get_sqe (3),
-.BR io_uring_unregister_files (3)
diff --git a/man/io_uring_register_files.3.md b/man/io_uring_register_files.3.md
new file mode 100644
index 00000000..d9f25257
--- /dev/null
+++ b/man/io_uring_register_files.3.md
@@ -0,0 +1,66 @@
+.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: November 15, 2021
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_register_files
+---
+
+# NAME
+
+io_uring_register_files - register file descriptors
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_register_files(struct io_uring * ring ,
+ const int * files ,
+ unsigned nr_files );
+
+ int io_uring_register_files_tags(struct io_uring * ring ,
+ const int * files ,
+ const __u64 * tags ,
+ unsigned nr );
+
+ int io_uring_register_files_sparse(struct io_uring * ring ,
+ unsigned nr_files );
+
+ int io_uring_register_files_update(struct io_uring * ring ,
+ unsigned off ,
+ const int * files ,
+ unsigned nr_files );
+
+ int io_uring_register_files_update_tag(struct io_uring * ring ,
+ unsigned off ,
+ const int * files ,
+ const __u64 * tags ,
+ unsigned nr_files );
+
+# DESCRIPTION
+
+The **io_uring_register_files**(3) function registers *nr_files* number of file descriptors defined by the array *files* belonging to the *ring* for subsequent operations.
+
+The **io_uring_register_files_tags**(3) function behaves the same as **io_uring_register_files**(3) function but additionally takes *tags* parameter. See **IORING_REGISTER_BUFFERS2** for the resource tagging description.
+
+The **io_uring_register_files_sparse**(3) function registers an empty file table of *nr_files* number of file descriptors. These files must be updated before use, using eg **io_uring_register_files_update_tag**(3). Note that if the size of the sparse table exceeds what **RLIMIT_NOFILE** allows, then **io_uring_register_files_sparse**(3) will attempt to raise the limit using **setrlimit (2)** and retry the operation. If the registration fails after doing that, then an error will be returned. The sparse variant is available in kernels 5.19 and later.
+
+Registering a file table is a prerequisite for using any request that uses direct descriptors.
+
+Registered files have less overhead per operation than normal files. This is due to the kernel grabbing a reference count on a file when an operation begins, and dropping it when it\'s done. When the process file table is shared, for example if the process has ever created any threads, then this cost goes up even more. Using registered files reduces the overhead of file reference management across requests that operate on a file.
+
+The **io_uring_register_files_update**(3) function updates existing registered files. The *off* is offset on which to start the update *nr_files* number of files defined by the array *files* belonging to the *ring*.
+
+The **io_uring_register_files_update_tag**(3) function behaves the same as **io_uring_register_files_update**(3) function but additionally takes *tags* parameter. See **IORING_REGISTER_BUFFERS2** for the resource tagging description.
+
+# RETURN VALUE
+
+On success **io_uring_register_files**(3), **io_uring_register_files_tags**(3) and **io_uring_register_files_sparse**(3) return 0. **io_uring_register_files_update**(3) and **io_uring_register_files_update_tag**(3) return number of files updated. On failure they return **-errno**.
+
+# SEE ALSO
+
+**io_uring_register**(2), **io_uring_get_sqe**(3), **io_uring_unregister_files**(3)
diff --git a/man/io_uring_register_files_sparse.3 b/man/io_uring_register_files_sparse.3
deleted file mode 120000
index db38b932..00000000
--- a/man/io_uring_register_files_sparse.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_register_files.3
\ No newline at end of file
diff --git a/man/io_uring_register_files_tags.3 b/man/io_uring_register_files_tags.3
deleted file mode 120000
index db38b932..00000000
--- a/man/io_uring_register_files_tags.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_register_files.3
\ No newline at end of file
diff --git a/man/io_uring_register_files_update.3 b/man/io_uring_register_files_update.3
deleted file mode 120000
index db38b932..00000000
--- a/man/io_uring_register_files_update.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_register_files.3
\ No newline at end of file
diff --git a/man/io_uring_register_files_update_tag.3 b/man/io_uring_register_files_update_tag.3
deleted file mode 120000
index db38b932..00000000
--- a/man/io_uring_register_files_update_tag.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_register_files.3
\ No newline at end of file
diff --git a/man/io_uring_register_ifq.3 b/man/io_uring_register_ifq.3
deleted file mode 100644
index e9aa7aac..00000000
--- a/man/io_uring_register_ifq.3
+++ /dev/null
@@ -1,49 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_register_ifq 3 "January 18, 2025" "liburing-2.10" "liburing Manual"
-.SH NAME
-io_uring_register_ifq \- register a zero-copy receive interface queue
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_register_ifq(struct io_uring *" ring ","
-.BI " struct io_uring_zcrx_ifq_reg *" reg ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_register_ifq (3)
-function registers a zero-copy receive interface queue with the io_uring
-instance specified by
-.IR ring .
-Zero-copy receive allows the kernel to place incoming network data directly
-into application-provided memory without copying.
-
-The
-.I reg
-argument is a pointer to a
-.I struct io_uring_zcrx_ifq_reg
-that describes the interface queue to register. See
-.BR io_uring_register (2)
-for a description of the
-.B IORING_REGISTER_ZCRX_IFQ
-operation and the structure fields.
-
-The io_uring ring must have been created with
-.B IORING_SETUP_DEFER_TASKRUN
-and either
-.B IORING_SETUP_CQE32
-or
-.B IORING_SETUP_CQE_MIXED
-flags set. The caller must have the
-.B CAP_NET_ADMIN
-capability.
-
-.SH RETURN VALUE
-Returns 0 on success. On error, a negative errno value is returned.
-.SH SEE ALSO
-.BR io_uring_register (2),
-.BR io_uring_setup (2)
diff --git a/man/io_uring_register_ifq.3.md b/man/io_uring_register_ifq.3.md
new file mode 100644
index 00000000..70779eae
--- /dev/null
+++ b/man/io_uring_register_ifq.3.md
@@ -0,0 +1,38 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: liburing-2.10
+header: liburing Manual
+section: 3
+title: io_uring_register_ifq
+---
+
+# NAME
+
+io_uring_register_ifq - register a zero-copy receive interface queue
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_register_ifq(struct io_uring * ring ,
+ struct io_uring_zcrx_ifq_reg * reg );
+
+# DESCRIPTION
+
+The **io_uring_register_ifq**(3) function registers a zero-copy receive interface queue with the io_uring instance specified by *ring*. Zero-copy receive allows the kernel to place incoming network data directly into application-provided memory without copying.
+
+The *reg* argument is a pointer to a *struct io_uring_zcrx_ifq_reg* that describes the interface queue to register. See **io_uring_register**(2) for a description of the **IORING_REGISTER_ZCRX_IFQ** operation and the structure fields.
+
+The io_uring ring must have been created with **IORING_SETUP_DEFER_TASKRUN** and either **IORING_SETUP_CQE32** or **IORING_SETUP_CQE_MIXED** flags set. The caller must have the **CAP_NET_ADMIN** capability.
+
+# RETURN VALUE
+
+Returns 0 on success. On error, a negative errno value is returned.
+
+# SEE ALSO
+
+**io_uring_register**(2), **io_uring_setup**(2)
diff --git a/man/io_uring_register_iowq_aff.3 b/man/io_uring_register_iowq_aff.3
deleted file mode 100644
index 686222c1..00000000
--- a/man/io_uring_register_iowq_aff.3
+++ /dev/null
@@ -1,67 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_register_iowq_aff 3 "March 13, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_register_iowq_aff \- register async worker CPU affinities
-.SH SYNOPSIS
-.nf
-.B #include <sched.h>
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_register_iowq_aff(struct io_uring *" ring ","
-.BI " size_t " cpusz ","
-.BI " const cpu_set_t *" mask ");
-.PP
-.BI "void io_uring_unregister_iowq_aff(struct io_uring *" ring ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_prep_register_iowq_aff (3)
-function registers a set of CPU affinities to be used by the io_uring async
-workers. By default, io_uring async workers are allowed to run on any CPU in
-the system. If this function is called with
-.I ring
-set to the ring in question and
-.I mask
-set to a pointer to a
-.B cpu_set_t
-value and
-.I cpusz
-set to the size of the CPU set, then async workers will only be allowed to run
-on the CPUs specified in the mask. Existing workers may need to hit a schedule
-point before they are migrated.
-
-For unregistration,
-.BR io_uring_unregister_iowq_aff (3)
-may be called to restore CPU affinities to the default.
-
-Applications must define
-.B _GNU_SOURCE
-to obtain the definition of this helper, as
-.I cpu_set_t
-will not be defined without it.
-
-.SH RETURN VALUE
-Returns
-.B 0
-on success, or any of the following values in case of error.
-.TP
-.B -EFAULT
-The kernel was unable to copy the memory pointer to by
-.I mask
-as it was invalid.
-.TP
-.B -ENOMEM
-The kernel was unable to allocate memory for the new CPU mask.
-.TP
-.B -EINVAL
-.I cpusz
-or
-.I mask
-was NULL/0, or any other value specified was invalid.
-.SH SEE ALSO
-.BR io_uring_queue_init (3),
-.BR io_uring_register (2)
diff --git a/man/io_uring_register_iowq_aff.3.md b/man/io_uring_register_iowq_aff.3.md
new file mode 100644
index 00000000..1cde6997
--- /dev/null
+++ b/man/io_uring_register_iowq_aff.3.md
@@ -0,0 +1,54 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 13, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_register_iowq_aff
+---
+
+# NAME
+
+io_uring_register_iowq_aff - register async worker CPU affinities
+
+# SYNOPSIS
+
+ #include <sched.h>
+ #include <liburing.h>
+
+ int io_uring_register_iowq_aff(struct io_uring * ring ,
+ size_t cpusz ,
+ const cpu_set_t * mask );
+
+ void io_uring_unregister_iowq_aff(struct io_uring * ring );
+
+# DESCRIPTION
+
+The **io_uring_prep_register_iowq_aff**(3) function registers a set of CPU affinities to be used by the io_uring async workers. By default, io_uring async workers are allowed to run on any CPU in the system. If this function is called with *ring* set to the ring in question and *mask* set to a pointer to a **cpu_set_t** value and *cpusz* set to the size of the CPU set, then async workers will only be allowed to run on the CPUs specified in the mask. Existing workers may need to hit a schedule point before they are migrated.
+
+For unregistration, **io_uring_unregister_iowq_aff**(3) may be called to restore CPU affinities to the default.
+
+Applications must define **\_GNU_SOURCE** to obtain the definition of this helper, as *cpu_set_t* will not be defined without it.
+
+# RETURN VALUE
+
+Returns **0** on success, or any of the following values in case of error.
+
+**-EFAULT**
+
+: The kernel was unable to copy the memory pointer to by *mask* as it was invalid.
+
+**-ENOMEM**
+
+: The kernel was unable to allocate memory for the new CPU mask.
+
+**-EINVAL**
+
+: *cpusz* or *mask* was NULL/0, or any other value specified was invalid.
+
+# SEE ALSO
+
+**io_uring_queue_init**(3), **io_uring_register**(2)
diff --git a/man/io_uring_register_iowq_max_workers.3 b/man/io_uring_register_iowq_max_workers.3
deleted file mode 100644
index 2557e216..00000000
--- a/man/io_uring_register_iowq_max_workers.3
+++ /dev/null
@@ -1,71 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_register_iowq_max_workers 3 "March 13, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_register_iowq_max_workers \- modify the maximum allowed async workers
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_register_iowq_max_workers(struct io_uring *" ring ","
-.BI " unsigned int *" values ");"
-.fi
-.SH DESCRIPTION
-.PP
-io_uring async workers are split into two types:
-.TP
-.B Bounded
-These workers have a bounded execution time. Examples of that are filesystem
-reads, which normally complete in a relatively short amount of time. In case
-of disk failures, they are still bounded by a timeout operation that will
-abort them if exceeded.
-.TP
-.B Unbounded
-Work items here may take an indefinite amount of time to complete. Examples
-include doing IO to sockets, pipes, or any other non-regular type of file.
-
-.PP
-By default, the amount of bounded IO workers is limited to how many SQ entries
-the ring was setup with, or 4 times the number of online CPUs in the system,
-whichever is smaller. Unbounded workers are only limited by the process task
-limit, as indicated by the rlimit
-.B RLIMIT_NPROC
-limit.
-
-This can be modified by calling
-.B io_uring_register_iowq_max_workers
-with
-.I ring
-set to the ring in question, and
-.I values
-pointing to an array of two values. The first element should contain the number
-of desired bounded workers, and the second element should contain the number
-of desired unbounded workers. These are both maximum values, io_uring will
-not maintain a high count of idle workers, they are reaped when they are not
-necessary anymore.
-
-If called with both values set to 0, the existing values are returned.
-
-.SH RETURN VALUE
-Returns
-.B 0
-on success, with
-.I values
-containing the previous values for the settings. On error, any of the following
-may be returned.
-.TP
-.B -EFAULT
-The kernel was unable to copy the memory pointer to by
-.I values
-as it was invalid.
-.TP
-.B -EINVAL
-.I values
-was
-.B NULL
-or the new values exceeded the maximum allowed value.
-.SH SEE ALSO
-.BR io_uring_queue_init (3),
-.BR io_uring_register (2)
diff --git a/man/io_uring_register_iowq_max_workers.3.md b/man/io_uring_register_iowq_max_workers.3.md
new file mode 100644
index 00000000..81e8c911
--- /dev/null
+++ b/man/io_uring_register_iowq_max_workers.3.md
@@ -0,0 +1,56 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 13, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_register_iowq_max_workers
+---
+
+# NAME
+
+io_uring_register_iowq_max_workers - modify the maximum allowed async workers
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_register_iowq_max_workers(struct io_uring * ring ,
+ unsigned int * values );
+
+# DESCRIPTION
+
+io_uring async workers are split into two types:
+
+**Bounded**
+
+: These workers have a bounded execution time. Examples of that are filesystem reads, which normally complete in a relatively short amount of time. In case of disk failures, they are still bounded by a timeout operation that will abort them if exceeded.
+
+**Unbounded**
+
+: Work items here may take an indefinite amount of time to complete. Examples include doing IO to sockets, pipes, or any other non-regular type of file.
+
+By default, the amount of bounded IO workers is limited to how many SQ entries the ring was setup with, or 4 times the number of online CPUs in the system, whichever is smaller. Unbounded workers are only limited by the process task limit, as indicated by the rlimit **RLIMIT_NPROC** limit.
+
+This can be modified by calling **io_uring_register_iowq_max_workers** with *ring* set to the ring in question, and *values* pointing to an array of two values. The first element should contain the number of desired bounded workers, and the second element should contain the number of desired unbounded workers. These are both maximum values, io_uring will not maintain a high count of idle workers, they are reaped when they are not necessary anymore.
+
+If called with both values set to 0, the existing values are returned.
+
+# RETURN VALUE
+
+Returns **0** on success, with *values* containing the previous values for the settings. On error, any of the following may be returned.
+
+**-EFAULT**
+
+: The kernel was unable to copy the memory pointer to by *values* as it was invalid.
+
+**-EINVAL**
+
+: *values* was **NULL** or the new values exceeded the maximum allowed value.
+
+# SEE ALSO
+
+**io_uring_queue_init**(3), **io_uring_register**(2)
diff --git a/man/io_uring_register_napi.3 b/man/io_uring_register_napi.3
deleted file mode 100644
index 6ce8cfff..00000000
--- a/man/io_uring_register_napi.3
+++ /dev/null
@@ -1,40 +0,0 @@
-.\" Copyright (C) 2022 Stefan Roesch <shr@devkernel.io>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_register_napi 3 "November 16, 2022" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_register_napi \- register NAPI busy poll settings
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_register_napi(struct io_uring *" ring ","
-.BI " struct io_uring_napi *" napi)
-.PP
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_register_napi (3)
-function registers the NAPI settings for subsequent operations. The NAPI
-settings are specified in the structure that is passed in the
-.I napi
-parameter. The structure consists of the napi timeout
-.I busy_poll_to
-(napi busy poll timeout in us) and
-.IR prefer_busy_poll .
-
-Registering a NAPI settings sets the mode when calling the function
-napi_busy_loop and corresponds to the SO_PREFER_BUSY_POLL socket
-option.
-
-NAPI busy poll can reduce the network roundtrip time.
-
-
-.SH RETURN VALUE
-On success
-.BR io_uring_register_napi (3)
-return 0. On failure they return
-.BR -errno .
-It also updates the napi structure with the current values.
diff --git a/man/io_uring_register_napi.3.md b/man/io_uring_register_napi.3.md
new file mode 100644
index 00000000..da864e79
--- /dev/null
+++ b/man/io_uring_register_napi.3.md
@@ -0,0 +1,34 @@
+.\" Copyright (C) 2022 Stefan Roesch <shr@devkernel.io>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: November 16, 2022
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_register_napi
+---
+
+# NAME
+
+io_uring_register_napi - register NAPI busy poll settings
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_register_napi(struct io_uring * ring ,
+ struct io_uring_napi * napi)
+
+# DESCRIPTION
+
+The **io_uring_register_napi**(3) function registers the NAPI settings for subsequent operations. The NAPI settings are specified in the structure that is passed in the *napi* parameter. The structure consists of the napi timeout *busy_poll_to* (napi busy poll timeout in us) and *prefer_busy_poll*.
+
+Registering a NAPI settings sets the mode when calling the function napi_busy_loop and corresponds to the SO_PREFER_BUSY_POLL socket option.
+
+NAPI busy poll can reduce the network roundtrip time.
+
+# RETURN VALUE
+
+On success **io_uring_register_napi**(3) return 0. On failure they return **-errno**. It also updates the napi structure with the current values.
diff --git a/man/io_uring_register_personality.3 b/man/io_uring_register_personality.3
deleted file mode 100644
index af3e1136..00000000
--- a/man/io_uring_register_personality.3
+++ /dev/null
@@ -1,34 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_register_personality 3 "January 18, 2025" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_register_personality \- register credentials with io_uring
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_register_personality(struct io_uring *" ring ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_register_personality (3)
-function registers the credentials of the calling application with the
-io_uring instance specified by
-.IR ring .
-This allows a ring to be shared between separate users or processes while
-maintaining credential separation.
-
-The returned personality ID can be used in the
-.I personality
-field of a submission queue entry to execute that request with the
-registered credentials.
-
-.SH RETURN VALUE
-Returns a positive personality ID on success that can be used in future
-operations. On error, a negative errno value is returned.
-.SH SEE ALSO
-.BR io_uring_unregister_personality (3),
-.BR io_uring_register (2)
diff --git a/man/io_uring_register_personality.3.md b/man/io_uring_register_personality.3.md
new file mode 100644
index 00000000..463f4965
--- /dev/null
+++ b/man/io_uring_register_personality.3.md
@@ -0,0 +1,35 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_register_personality
+---
+
+# NAME
+
+io_uring_register_personality - register credentials with io_uring
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_register_personality(struct io_uring * ring );
+
+# DESCRIPTION
+
+The **io_uring_register_personality**(3) function registers the credentials of the calling application with the io_uring instance specified by *ring*. This allows a ring to be shared between separate users or processes while maintaining credential separation.
+
+The returned personality ID can be used in the *personality* field of a submission queue entry to execute that request with the registered credentials.
+
+# RETURN VALUE
+
+Returns a positive personality ID on success that can be used in future operations. On error, a negative errno value is returned.
+
+# SEE ALSO
+
+**io_uring_unregister_personality**(3), **io_uring_register**(2)
diff --git a/man/io_uring_register_probe.3 b/man/io_uring_register_probe.3
deleted file mode 100644
index 587aa399..00000000
--- a/man/io_uring_register_probe.3
+++ /dev/null
@@ -1,47 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_register_probe 3 "January 18, 2025" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_register_probe \- register probe with io_uring
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_register_probe(struct io_uring *" ring ","
-.BI " struct io_uring_probe *" p ","
-.BI " unsigned " nr ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_register_probe (3)
-function queries the kernel for supported io_uring opcodes and fills in the
-probe structure
-.IR p .
-The
-.I ring
-argument specifies the io_uring instance to query, and
-.I nr
-specifies the maximum number of opcodes to query.
-
-The probe structure contains information about which opcodes are supported
-by the kernel. Applications can use
-.BR io_uring_opcode_supported (3)
-to check if a specific opcode is supported after calling this function.
-
-Most applications should use
-.BR io_uring_get_probe (3)
-or
-.BR io_uring_get_probe_ring (3)
-instead, which allocate and fill in the probe structure automatically.
-
-.SH RETURN VALUE
-Returns 0 on success. On error, a negative errno value is returned.
-.SH SEE ALSO
-.BR io_uring_get_probe (3),
-.BR io_uring_get_probe_ring (3),
-.BR io_uring_opcode_supported (3),
-.BR io_uring_free_probe (3),
-.BR io_uring_register (2)
diff --git a/man/io_uring_register_probe.3.md b/man/io_uring_register_probe.3.md
new file mode 100644
index 00000000..7b6ddd29
--- /dev/null
+++ b/man/io_uring_register_probe.3.md
@@ -0,0 +1,39 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_register_probe
+---
+
+# NAME
+
+io_uring_register_probe - register probe with io_uring
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_register_probe(struct io_uring * ring ,
+ struct io_uring_probe * p ,
+ unsigned nr );
+
+# DESCRIPTION
+
+The **io_uring_register_probe**(3) function queries the kernel for supported io_uring opcodes and fills in the probe structure *p*. The *ring* argument specifies the io_uring instance to query, and *nr* specifies the maximum number of opcodes to query.
+
+The probe structure contains information about which opcodes are supported by the kernel. Applications can use **io_uring_opcode_supported**(3) to check if a specific opcode is supported after calling this function.
+
+Most applications should use **io_uring_get_probe**(3) or **io_uring_get_probe_ring**(3) instead, which allocate and fill in the probe structure automatically.
+
+# RETURN VALUE
+
+Returns 0 on success. On error, a negative errno value is returned.
+
+# SEE ALSO
+
+**io_uring_get_probe**(3), **io_uring_get_probe_ring**(3), **io_uring_opcode_supported**(3), **io_uring_free_probe**(3), **io_uring_register**(2)
diff --git a/man/io_uring_register_query.3 b/man/io_uring_register_query.3
deleted file mode 100644
index e731910d..00000000
--- a/man/io_uring_register_query.3
+++ /dev/null
@@ -1,114 +0,0 @@
-.\" Copyright (C) 2026 Yitang Yang <yi1tang.yang@gmail.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_register_query 3 "March 26, 2026" "liburing-2.15" "liburing Manual"
-.SH NAME
-io_uring_register_query \- query io_uring capabilities and feature support
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_register_query(struct io_uring_query_hdr *" query ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_register_query (3)
-function queries io_uring capabilities and feature support. It provides
-information about supported opcodes, flags, and subsystem-specific
-capabilities.
-
-The
-.I query
-argument must point to a
-.I struct io_uring_query_hdr
-structure that describes the query to perform:
-
-.PP
-.in +4n
-.EX
-struct io_uring_query_hdr {
- __u64 next_entry;
- __u64 query_data;
- __u32 query_op;
- __u32 size;
- __s32 result;
- __u32 __resv[3];
-};
-.EE
-.in
-.PP
-
-The
-.I next_entry
-field can be used to chain multiple queries together. It should point to the
-next
-.I struct io_uring_query_hdr
-structure, or be set to 0 for the last entry in the chain.
-
-The
-.I query_data
-field must point to a data structure appropriate for the query type specified in
-.IR query_op .
-
-The
-.I query_op
-field specifies the type of query to perform and can be one of:
-
-.TP
-.B IO_URING_QUERY_OPCODES
-Returns information about supported opcodes and flags. The
-.I query_data
-field must point to a
-.I struct io_uring_query_opcode
-structure, which will be filled with information about supported request
-opcodes, register opcodes, feature flags, setup flags, enter flags, and SQE
-flags.
-
-.TP
-.B IO_URING_QUERY_ZCRX
-Returns information about zero-copy receive support. The
-.I query_data
-field must point to a
-.I struct io_uring_query_zcrx
-structure, which will be filled with information about supported zero-copy
-receive flags, features, and configuration details.
-
-.TP
-.B IO_URING_QUERY_SCQ
-Returns information about the SQ/CQ ring layout. The
-.I query_data
-field must point to a
-.I struct io_uring_query_scq
-structure, which will be filled with information about ring header size and
-alignment requirements.
-
-.PP
-The
-.I size
-field should be set to the size of the data structure pointed to by
-.IR query_data .
-
-Upon return, the
-.I result
-field will contain 0 on success, or a negative error code on failure.
-
-The reserved
-.I __resv
-fields must be cleared to zero.
-
-.SH RETURN VALUE
-Returns 0 on success. On error, a negative errno value is returned.
-
-.SH NOTES
-This function is available since Linux kernel 6.15.
-
-Multiple queries can be efficiently performed in a single system call by
-chaining them together using the
-.I next_entry
-field.
-
-.SH SEE ALSO
-.BR io_uring_register (2),
-.BR io_uring_setup (2)
diff --git a/man/io_uring_register_query.3.md b/man/io_uring_register_query.3.md
new file mode 100644
index 00000000..03860c3d
--- /dev/null
+++ b/man/io_uring_register_query.3.md
@@ -0,0 +1,74 @@
+.\" Copyright (C) 2026 Yitang Yang <yi1tang.yang@gmail.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 26, 2026
+footer: liburing-2.15
+header: liburing Manual
+section: 3
+title: io_uring_register_query
+---
+
+# NAME
+
+io_uring_register_query - query io_uring capabilities and feature support
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_register_query(struct io_uring_query_hdr * query );
+
+# DESCRIPTION
+
+The **io_uring_register_query**(3) function queries io_uring capabilities and feature support. It provides information about supported opcodes, flags, and subsystem-specific capabilities.
+
+The *query* argument must point to a *struct io_uring_query_hdr* structure that describes the query to perform:
+
+ struct io_uring_query_hdr {
+ __u64 next_entry;
+ __u64 query_data;
+ __u32 query_op;
+ __u32 size;
+ __s32 result;
+ __u32 __resv[3];
+ };
+
+The *next_entry* field can be used to chain multiple queries together. It should point to the next *struct io_uring_query_hdr* structure, or be set to 0 for the last entry in the chain.
+
+The *query_data* field must point to a data structure appropriate for the query type specified in *query_op*.
+
+The *query_op* field specifies the type of query to perform and can be one of:
+
+**IO_URING_QUERY_OPCODES**
+
+: Returns information about supported opcodes and flags. The *query_data* field must point to a *struct io_uring_query_opcode* structure, which will be filled with information about supported request opcodes, register opcodes, feature flags, setup flags, enter flags, and SQE flags.
+
+**IO_URING_QUERY_ZCRX**
+
+: Returns information about zero-copy receive support. The *query_data* field must point to a *struct io_uring_query_zcrx* structure, which will be filled with information about supported zero-copy receive flags, features, and configuration details.
+
+**IO_URING_QUERY_SCQ**
+
+: Returns information about the SQ/CQ ring layout. The *query_data* field must point to a *struct io_uring_query_scq* structure, which will be filled with information about ring header size and alignment requirements.
+
+The *size* field should be set to the size of the data structure pointed to by *query_data*.
+
+Upon return, the *result* field will contain 0 on success, or a negative error code on failure.
+
+The reserved *\_\_resv* fields must be cleared to zero.
+
+# RETURN VALUE
+
+Returns 0 on success. On error, a negative errno value is returned.
+
+# NOTES
+
+This function is available since Linux kernel 6.15.
+
+Multiple queries can be efficiently performed in a single system call by chaining them together using the *next_entry* field.
+
+# SEE ALSO
+
+**io_uring_register**(2), **io_uring_setup**(2)
diff --git a/man/io_uring_register_region.3 b/man/io_uring_register_region.3
deleted file mode 100644
index 43a47766..00000000
--- a/man/io_uring_register_region.3
+++ /dev/null
@@ -1,124 +0,0 @@
-.\" Copyright (C) 2026 Pavel Begunkov <asml.silence@gmail.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_register_region 3 "Jan 13, 2026" "liburing-2.14" "liburing Manual"
-.SH NAME
-io_uring_register_region \- register a memory region
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_register_region(struct io_uring *" ring ",
-.BI " struct io_uring_mem_region_reg *" reg ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_register_region (3)
-function registers a memory region to io_uring. Upon successful completion, the
-memory region may then be used, for example, to pass waiting parameters to the
-.BR io_uring_enter (2)
-system call in a more efficient manner as it avoids copying wait related data
-for each wait event. The
-.IR ring
-argument should point to the ring in question, and the
-.IR reg
-argument should be a pointer to a
-.B struct io_uring_mem_region_reg .
-
-The
-.IR reg
-argument must be filled in with the appropriate information. It looks as
-follows:
-.PP
-.in +4n
-.EX
-struct io_uring_mem_region_reg {
- __u64 region_uptr;
- __u64 flags;
- __u64 __resv[2];
-};
-.EE
-.in
-.PP
-The
-.I region_uptr
-field must contain a pointer to an appropriately filled
-.B struct io_uring_region_desc.
-.PP
-The
-.I flags
-field must contain a bitmask of the following values:
-.TP
-.B IORING_MEM_REGION_REG_WAIT_ARG
-allows use of the region to pass waiting parameters to the
-.BR io_uring_enter (2)
-system call. If set, the registration is only allowed while the ring
-is in a disabled mode. See
-.B IORING_SETUP_R_DISABLED.
-.PP
-The __resv fields must be filled with zeroes.
-
-.PP
-.B struct io_uring_region_desc
-is defined as following:
-.PP
-.in +4n
-.EX
-struct io_uring_region_desc {
- __u64 user_addr;
- __u64 size;
- __u32 flags;
- __u32 id;
- __u64 mmap_offset;
- __u64 __resv[4];
-};
-.EE
-.in
-
-.PP
-The
-.I user_addr
-field must contain a pointer to the memory the user wants to register. It's
-valid only if
-.B IORING_MEM_REGION_TYPE_USER
-is set, and should be zero otherwise.
-
-.PP
-The
-.I size
-field should contain the size of the region.
-
-The
-.I flags
-field must contain a bitmask of the following values:
-.TP
-.B IORING_MEM_REGION_TYPE_USER
-tells the kernel to use memory specified by the
-.I user_addr
-field. If not set, the kernel will allocate memory for the region, which can
-then be mapped into the user space.
-
-.PP
-On successful registration of a region with kernel provided memory, the
-.I mmap_offset
-field will contain an offset that can be passed to the
-.B mmap(2)
-system call to map the region into the user space.
-
-The
-.I id
-field is reserved and must be set to zero.
-
-The
-.I __resv
-fields must be filled with zeroes.
-
-Available since kernel 6.13.
-
-.SH RETURN VALUE
-On success
-.BR io_uring_register_region (3)
-returns 0. On failure it returns
-.BR -errno .
diff --git a/man/io_uring_register_region.3.md b/man/io_uring_register_region.3.md
new file mode 100644
index 00000000..db9dd3d2
--- /dev/null
+++ b/man/io_uring_register_region.3.md
@@ -0,0 +1,77 @@
+.\" Copyright (C) 2026 Pavel Begunkov <asml.silence@gmail.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: Jan 13, 2026
+footer: liburing-2.14
+header: liburing Manual
+section: 3
+title: io_uring_register_region
+---
+
+# NAME
+
+io_uring_register_region - register a memory region
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_register_region(struct io_uring * ring ,
+ struct io_uring_mem_region_reg * reg );
+
+# DESCRIPTION
+
+The **io_uring_register_region**(3) function registers a memory region to io_uring. Upon successful completion, the memory region may then be used, for example, to pass waiting parameters to the **io_uring_enter**(2) system call in a more efficient manner as it avoids copying wait related data for each wait event. The *ring* argument should point to the ring in question, and the *reg* argument should be a pointer to a **struct io_uring_mem_region_reg .**
+
+The *reg* argument must be filled in with the appropriate information. It looks as follows:
+
+ struct io_uring_mem_region_reg {
+ __u64 region_uptr;
+ __u64 flags;
+ __u64 __resv[2];
+ };
+
+The *region_uptr* field must contain a pointer to an appropriately filled **struct io_uring_region_desc.**
+
+The *flags* field must contain a bitmask of the following values:
+
+**IORING_MEM_REGION_REG_WAIT_ARG**
+
+: allows use of the region to pass waiting parameters to the **io_uring_enter**(2) system call. If set, the registration is only allowed while the ring is in a disabled mode. See **IORING_SETUP_R_DISABLED.**
+
+The \_\_resv fields must be filled with zeroes.
+
+**struct io_uring_region_desc** is defined as following:
+
+ struct io_uring_region_desc {
+ __u64 user_addr;
+ __u64 size;
+ __u32 flags;
+ __u32 id;
+ __u64 mmap_offset;
+ __u64 __resv[4];
+ };
+
+The *user_addr* field must contain a pointer to the memory the user wants to register. It\'s valid only if **IORING_MEM_REGION_TYPE_USER** is set, and should be zero otherwise.
+
+The *size* field should contain the size of the region.
+
+The *flags* field must contain a bitmask of the following values:
+
+**IORING_MEM_REGION_TYPE_USER**
+
+: tells the kernel to use memory specified by the *user_addr* field. If not set, the kernel will allocate memory for the region, which can then be mapped into the user space.
+
+On successful registration of a region with kernel provided memory, the *mmap_offset* field will contain an offset that can be passed to the **mmap(2)** system call to map the region into the user space.
+
+The *id* field is reserved and must be set to zero.
+
+The *\_\_resv* fields must be filled with zeroes.
+
+Available since kernel 6.13.
+
+# RETURN VALUE
+
+On success **io_uring_register_region**(3) returns 0. On failure it returns **-errno**.
diff --git a/man/io_uring_register_restrictions.3 b/man/io_uring_register_restrictions.3
deleted file mode 100644
index d99bf881..00000000
--- a/man/io_uring_register_restrictions.3
+++ /dev/null
@@ -1,53 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_register_restrictions 3 "January 18, 2025" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_register_restrictions \- register restrictions with io_uring
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_register_restrictions(struct io_uring *" ring ","
-.BI " struct io_uring_restriction *" res ","
-.BI " unsigned int " nr_res ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_register_restrictions (3)
-function registers restrictions with the io_uring instance specified by
-.IR ring .
-The
-.I res
-argument is a pointer to an array of
-.I struct io_uring_restriction
-of
-.I nr_res
-entries.
-
-Restrictions allow limiting which opcodes, register operations, or SQE flags
-are allowed on a ring. This can be used to sandbox io_uring usage.
-
-Restrictions can only be registered if the io_uring ring was started in a
-disabled state (with
-.B IORING_SETUP_R_DISABLED
-specified in the call to
-.BR io_uring_setup (2)).
-All restrictions must be registered in a single call before enabling the
-ring with
-.BR io_uring_enable_rings (3).
-
-See
-.BR io_uring_register (2)
-for a description of the
-.B IORING_REGISTER_RESTRICTIONS
-operation and the restriction structure.
-
-.SH RETURN VALUE
-Returns 0 on success. On error, a negative errno value is returned.
-.SH SEE ALSO
-.BR io_uring_enable_rings (3),
-.BR io_uring_register (2),
-.BR io_uring_setup (2)
diff --git a/man/io_uring_register_restrictions.3.md b/man/io_uring_register_restrictions.3.md
new file mode 100644
index 00000000..51e163cb
--- /dev/null
+++ b/man/io_uring_register_restrictions.3.md
@@ -0,0 +1,41 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_register_restrictions
+---
+
+# NAME
+
+io_uring_register_restrictions - register restrictions with io_uring
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_register_restrictions(struct io_uring * ring ,
+ struct io_uring_restriction * res ,
+ unsigned int nr_res );
+
+# DESCRIPTION
+
+The **io_uring_register_restrictions**(3) function registers restrictions with the io_uring instance specified by *ring*. The *res* argument is a pointer to an array of *struct io_uring_restriction* of *nr_res* entries.
+
+Restrictions allow limiting which opcodes, register operations, or SQE flags are allowed on a ring. This can be used to sandbox io_uring usage.
+
+Restrictions can only be registered if the io_uring ring was started in a disabled state (with **IORING_SETUP_R_DISABLED** specified in the call to **io_uring_setup**(2)). All restrictions must be registered in a single call before enabling the ring with **io_uring_enable_rings**(3).
+
+See **io_uring_register**(2) for a description of the **IORING_REGISTER_RESTRICTIONS** operation and the restriction structure.
+
+# RETURN VALUE
+
+Returns 0 on success. On error, a negative errno value is returned.
+
+# SEE ALSO
+
+**io_uring_enable_rings**(3), **io_uring_register**(2), **io_uring_setup**(2)
diff --git a/man/io_uring_register_ring_fd.3 b/man/io_uring_register_ring_fd.3
deleted file mode 100644
index 0284fe41..00000000
--- a/man/io_uring_register_ring_fd.3
+++ /dev/null
@@ -1,51 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_register_ring_fd 3 "March 11, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_register_ring_fd \- register a ring file descriptor
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_register_ring_fd(struct io_uring *" ring ");"
-.fi
-.SH DESCRIPTION
-.PP
-.BR io_uring_register_ring_fd (3)
-registers the file descriptor of the ring.
-
-Whenever
-.BR io_uring_enter (2)
-is called to submit request or wait for completions, the kernel must grab a
-reference to the file descriptor. If the application using io_uring is threaded,
-the file table is marked as shared, and the reference grab and put of the file
-descriptor count is more expensive than it is for a non-threaded application.
-
-Similarly to how io_uring allows registration of files, this allow registration
-of the ring file descriptor itself. This reduces the overhead of the
-.BR io_uring_enter (2)
-system call.
-
-If an application using liburing is threaded, then an application should call
-this function to register the ring descriptor when a ring is set up. See NOTES
-for restrictions when a ring is shared.
-
-Available since kernel 5.18.
-
-.SH NOTES
-When the ring descriptor is registered, it is stored internally in the
-.I struct io_uring
-structure. For applications that share a ring between threads, for example
-having one thread do submits and another reap events, then this optimization
-cannot be used as each thread may have a different index for the registered
-ring fd.
-.SH RETURN VALUE
-Returns 1 on success, indicating that one file descriptor was registered,
-or
-.BR -errno
-on error.
-.SH SEE ALSO
-.BR io_uring_unregister_ring_fd (3),
-.BR io_uring_register_files (3)
diff --git a/man/io_uring_register_ring_fd.3.md b/man/io_uring_register_ring_fd.3.md
new file mode 100644
index 00000000..70fb2db0
--- /dev/null
+++ b/man/io_uring_register_ring_fd.3.md
@@ -0,0 +1,45 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 11, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_register_ring_fd
+---
+
+# NAME
+
+io_uring_register_ring_fd - register a ring file descriptor
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_register_ring_fd(struct io_uring * ring );
+
+# DESCRIPTION
+
+**io_uring_register_ring_fd**(3) registers the file descriptor of the ring.
+
+Whenever **io_uring_enter**(2) is called to submit request or wait for completions, the kernel must grab a reference to the file descriptor. If the application using io_uring is threaded, the file table is marked as shared, and the reference grab and put of the file descriptor count is more expensive than it is for a non-threaded application.
+
+Similarly to how io_uring allows registration of files, this allow registration of the ring file descriptor itself. This reduces the overhead of the **io_uring_enter**(2) system call.
+
+If an application using liburing is threaded, then an application should call this function to register the ring descriptor when a ring is set up. See NOTES for restrictions when a ring is shared.
+
+Available since kernel 5.18.
+
+# NOTES
+
+When the ring descriptor is registered, it is stored internally in the *struct io_uring* structure. For applications that share a ring between threads, for example having one thread do submits and another reap events, then this optimization cannot be used as each thread may have a different index for the registered ring fd.
+
+# RETURN VALUE
+
+Returns 1 on success, indicating that one file descriptor was registered, or **-errno** on error.
+
+# SEE ALSO
+
+**io_uring_unregister_ring_fd**(3), **io_uring_register_files**(3)
diff --git a/man/io_uring_register_sync_cancel.3 b/man/io_uring_register_sync_cancel.3
deleted file mode 100644
index 449bc0ff..00000000
--- a/man/io_uring_register_sync_cancel.3
+++ /dev/null
@@ -1,73 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_register_sync_cancel 3 "September 21, 2022" "liburing-2.3" "liburing Manual"
-.SH NAME
-io_uring_register_sync_cancel \- issue a synchronous cancelation request
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_register_sync_cancel(struct io_uring *" ring ",
-.BI " struct io_uring_sync_cancel_reg *" reg ");
-.PP
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_register_sync_cancel (3)
-function performs a synchronous cancelation request based on the parameters
-specified in
-.I reg .
-
-The
-.I reg
-argument must be filled in with the appropriate information for the
-cancelation request. It looks as follows:
-.PP
-.in +4n
-.EX
-struct io_uring_sync_cancel_reg {
- __u64 addr;
- __s32 fd;
- __u32 flags;
- struct __kernel_timespec timeout;
- __u8 opcode;
- __u8 pad[7];
- __u64 pad2[3];
-};
-.EE
-.in
-.PP
-
-The arguments largely mirror what the async prep functions support, see
-.BR io_uring_prep_cancel (3)
-for details. Similarly, the return value is the same. The exception is the
-.I timeout
-argument, which can be used to limit the time that the kernel will wait for
-cancelations to be successful. If the
-.I tv_sec
-and
-.I tv_nsec
-values are set to anything but
-.B -1UL ,
-then they indicate a relative timeout upon which cancelations should be
-completed by.
-
-The
-.I pad
-values must be zero filled.
-
-.SH RETURN VALUE
-See
-.BR io_uring_prep_cancel (3)
-for details on the return value. If
-.I timeout
-is set to indicate a timeout, then
-.B -ETIME
-will be returned if exceeded. If an unknown value is set in the request,
-or if the pad values are not cleared to zero, then
-.I -EINVAL
-is returned.
-.SH SEE ALSO
-.BR io_uring_prep_cancel (3)
diff --git a/man/io_uring_register_sync_cancel.3.md b/man/io_uring_register_sync_cancel.3.md
new file mode 100644
index 00000000..2861e6e2
--- /dev/null
+++ b/man/io_uring_register_sync_cancel.3.md
@@ -0,0 +1,50 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: September 21, 2022
+footer: liburing-2.3
+header: liburing Manual
+section: 3
+title: io_uring_register_sync_cancel
+---
+
+# NAME
+
+io_uring_register_sync_cancel - issue a synchronous cancelation request
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_register_sync_cancel(struct io_uring * ring ,
+ struct io_uring_sync_cancel_reg * reg );
+
+# DESCRIPTION
+
+The **io_uring_register_sync_cancel**(3) function performs a synchronous cancelation request based on the parameters specified in *reg .*
+
+The *reg* argument must be filled in with the appropriate information for the cancelation request. It looks as follows:
+
+ struct io_uring_sync_cancel_reg {
+ __u64 addr;
+ __s32 fd;
+ __u32 flags;
+ struct __kernel_timespec timeout;
+ __u8 opcode;
+ __u8 pad[7];
+ __u64 pad2[3];
+ };
+
+The arguments largely mirror what the async prep functions support, see **io_uring_prep_cancel**(3) for details. Similarly, the return value is the same. The exception is the *timeout* argument, which can be used to limit the time that the kernel will wait for cancelations to be successful. If the *tv_sec* and *tv_nsec* values are set to anything but **-1UL ,** then they indicate a relative timeout upon which cancelations should be completed by.
+
+The *pad* values must be zero filled.
+
+# RETURN VALUE
+
+See **io_uring_prep_cancel**(3) for details on the return value. If *timeout* is set to indicate a timeout, then **-ETIME** will be returned if exceeded. If an unknown value is set in the request, or if the pad values are not cleared to zero, then *-EINVAL* is returned.
+
+# SEE ALSO
+
+**io_uring_prep_cancel**(3)
diff --git a/man/io_uring_register_sync_msg.3 b/man/io_uring_register_sync_msg.3
deleted file mode 100644
index bef56814..00000000
--- a/man/io_uring_register_sync_msg.3
+++ /dev/null
@@ -1,74 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_register_sync_msg 3 "July 10, 2025" "liburing-2.11" "liburing Manual"
-.SH NAME
-io_uring_register_sync_msg \- send a synchronous message to another ring
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_register_sync_msg(struct io_uring_sqe *" sqe ");"
-.fi
-.SH DESCRIPTION
-.PP
-.BR io_uring_register_sync_msg (3)
-issues a synchronous MSG_RING request. The
-.I sqe
-parameter must have been cleared and initialized with
-.BR io_uring_prep_msg_ring (3) .
-
-Normally message requests are sent from one ring to another ring. But there
-are also cases where a source ring is not available, yet it would be
-convenient to send a message to a destination ring.
-.BR io_uring_register_sync_msg (3)
-exists for that purpose. A source ring is not required to send a message to
-another ring, instead the
-.I sqe
-parameter can be placed on the stack and filled in using the normal message
-helpers, and then
-.BR io_uring_register_sync_msg (3)
-can be called. Since a source ring does not exist, the results of the operation
-is returned directly rather than via a CQE. On the destination/receiving end,
-a CQE is posted, as it would have been with a non-sync request.
-
-Only data request are supported, sending files such as setup by
-.BR io_uring_prep_msg_ring_fd (3)
-is not supported. The given SQE should be initialized by
-.BR io_uring_prep_msg_ring (3)
-or
-.BR io_uring_prep_msg_ring_cqe_flags (3) ,
-or any other helper that sets up a non-fd message request.
-
-The targeted ring may be any ring that the user has access to, even the ring
-itself. This request can be used for simple message passing to another ring,
-allowing 32+64 bits of data to be transferred through the
-.I len
-and
-.I data
-fields. The use case may be anything from simply waking up someone waiting
-on the targeted ring, or it can be used to pass messages between the two
-rings.
-
-.BR io_uring_prep_msg_ring_cqe_flags (3)
-is similar to
-.BR io_uring_prep_msg_ring (3) .
-But has an addition
-.I cqe_flags
-parameter, which is used to set
-.I flags
-field on CQE side. That way, you can set the CQE flags field
-.I cqe->flags
-when sending a message. Be aware that io_uring could potentially set additional
-bits into this field.
-
-Available since kernel 6.13.
-
-.SH RETURN VALUE
-Returns 0 on success, or
-.BR -errno
-on error.
-.SH SEE ALSO
-.BR io_uring_prep_msg_ring_cqe_flags (3) ,
-.BR io_uring_prep_msg_ring (3)
diff --git a/man/io_uring_register_sync_msg.3.md b/man/io_uring_register_sync_msg.3.md
new file mode 100644
index 00000000..edc50b7a
--- /dev/null
+++ b/man/io_uring_register_sync_msg.3.md
@@ -0,0 +1,43 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: July 10, 2025
+footer: liburing-2.11
+header: liburing Manual
+section: 3
+title: io_uring_register_sync_msg
+---
+
+# NAME
+
+io_uring_register_sync_msg - send a synchronous message to another ring
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_register_sync_msg(struct io_uring_sqe * sqe );
+
+# DESCRIPTION
+
+**io_uring_register_sync_msg**(3) issues a synchronous MSG_RING request. The *sqe* parameter must have been cleared and initialized with **io_uring_prep_msg_ring**(3)**.**
+
+Normally message requests are sent from one ring to another ring. But there are also cases where a source ring is not available, yet it would be convenient to send a message to a destination ring. **io_uring_register_sync_msg**(3) exists for that purpose. A source ring is not required to send a message to another ring, instead the *sqe* parameter can be placed on the stack and filled in using the normal message helpers, and then **io_uring_register_sync_msg**(3) can be called. Since a source ring does not exist, the results of the operation is returned directly rather than via a CQE. On the destination/receiving end, a CQE is posted, as it would have been with a non-sync request.
+
+Only data request are supported, sending files such as setup by **io_uring_prep_msg_ring_fd**(3) is not supported. The given SQE should be initialized by **io_uring_prep_msg_ring**(3) or **io_uring_prep_msg_ring_cqe_flags**(3)**,** or any other helper that sets up a non-fd message request.
+
+The targeted ring may be any ring that the user has access to, even the ring itself. This request can be used for simple message passing to another ring, allowing 32+64 bits of data to be transferred through the *len* and *data* fields. The use case may be anything from simply waking up someone waiting on the targeted ring, or it can be used to pass messages between the two rings.
+
+**io_uring_prep_msg_ring_cqe_flags**(3) is similar to **io_uring_prep_msg_ring**(3)**.** But has an addition *cqe_flags* parameter, which is used to set *flags* field on CQE side. That way, you can set the CQE flags field *cqe-\>flags* when sending a message. Be aware that io_uring could potentially set additional bits into this field.
+
+Available since kernel 6.13.
+
+# RETURN VALUE
+
+Returns 0 on success, or **-errno** on error.
+
+# SEE ALSO
+
+**io_uring_prep_msg_ring_cqe_flags**(3)**,** **io_uring_prep_msg_ring**(3)
diff --git a/man/io_uring_register_wait_reg.3 b/man/io_uring_register_wait_reg.3
deleted file mode 100644
index 122f00f0..00000000
--- a/man/io_uring_register_wait_reg.3
+++ /dev/null
@@ -1,45 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_register_wait_reg 3 "January 18, 2025" "liburing-2.9" "liburing Manual"
-.SH NAME
-io_uring_register_wait_reg \- register wait regions with io_uring
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_register_wait_reg(struct io_uring *" ring ","
-.BI " struct io_uring_reg_wait *" reg ","
-.BI " int " nr ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_register_wait_reg (3)
-function registers wait regions with the io_uring instance specified by
-.IR ring .
-The
-.I reg
-argument is a pointer to an array of
-.I struct io_uring_reg_wait
-of
-.I nr
-entries.
-
-Wait regions allow registering timeout and signal mask information that can
-be reused across multiple wait operations without copying the data for each
-call. This is used in conjunction with
-.BR io_uring_submit_and_wait_reg (3)
-to reduce the overhead of wait operations.
-
-See
-.BR io_uring_register_region (3)
-for registering the underlying memory region.
-
-.SH RETURN VALUE
-Returns 0 on success. On error, a negative errno value is returned.
-.SH SEE ALSO
-.BR io_uring_submit_and_wait_reg (3),
-.BR io_uring_register_region (3),
-.BR io_uring_register (2)
diff --git a/man/io_uring_register_wait_reg.3.md b/man/io_uring_register_wait_reg.3.md
new file mode 100644
index 00000000..6c6000d8
--- /dev/null
+++ b/man/io_uring_register_wait_reg.3.md
@@ -0,0 +1,39 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: liburing-2.9
+header: liburing Manual
+section: 3
+title: io_uring_register_wait_reg
+---
+
+# NAME
+
+io_uring_register_wait_reg - register wait regions with io_uring
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_register_wait_reg(struct io_uring * ring ,
+ struct io_uring_reg_wait * reg ,
+ int nr );
+
+# DESCRIPTION
+
+The **io_uring_register_wait_reg**(3) function registers wait regions with the io_uring instance specified by *ring*. The *reg* argument is a pointer to an array of *struct io_uring_reg_wait* of *nr* entries.
+
+Wait regions allow registering timeout and signal mask information that can be reused across multiple wait operations without copying the data for each call. This is used in conjunction with **io_uring_submit_and_wait_reg**(3) to reduce the overhead of wait operations.
+
+See **io_uring_register_region**(3) for registering the underlying memory region.
+
+# RETURN VALUE
+
+Returns 0 on success. On error, a negative errno value is returned.
+
+# SEE ALSO
+
+**io_uring_submit_and_wait_reg**(3), **io_uring_register_region**(3), **io_uring_register**(2)
diff --git a/man/io_uring_register_zcrx_ctrl.3 b/man/io_uring_register_zcrx_ctrl.3
deleted file mode 100644
index 64e3a913..00000000
--- a/man/io_uring_register_zcrx_ctrl.3
+++ /dev/null
@@ -1,84 +0,0 @@
-.\" Copyright (C) 2026 Yitang Yang <yi1tang.yang@gmail.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_register_zcrx_ctrl 3 "March 26, 2026" "liburing-2.15" "liburing Manual"
-.SH NAME
-io_uring_register_zcrx_ctrl \- perform control operations on a zero-copy receive context
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_register_zcrx_ctrl(struct io_uring *" ring ","
-.BI " struct zcrx_ctrl *" ctrl ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_register_zcrx_ctrl (3)
-function performs control operations on a previously registered zero-copy
-receive context. See
-.BR io_uring_register_ifq (3)
-for details on registering a zero-copy receive context.
-
-The
-.I ctrl
-argument must point to a
-.I struct zcrx_ctrl
-structure that describes the control operation to perform:
-
-.PP
-.in +4n
-.EX
-struct zcrx_ctrl {
- __u32 zcrx_id;
- __u32 op;
- __u64 __resv[2];
- union {
- struct zcrx_ctrl_export zc_export;
- struct zcrx_ctrl_flush_rq zc_flush;
- };
-};
-.EE
-.in
-.PP
-
-The
-.I zcrx_id
-field must be set to the ID of the zero-copy receive context returned from
-.BR io_uring_register_ifq (3).
-The
-.I op
-field specifies the control operation to perform and can be one of:
-
-.TP
-.B ZCRX_CTRL_FLUSH_RQ
-Flushes pending buffers from the refill queue. Uses the
-.I zc_flush
-member of the union.
-
-.TP
-.B ZCRX_CTRL_EXPORT
-Exports the zero-copy receive context for use by other rings. Uses the
-.I zc_export
-member of the union. Upon successful export, the
-.I zcrx_fd
-field in
-.I zc_export
-will contain the file descriptor that can be used to share this context
-with other io_uring instances.
-
-.PP
-The reserved
-.I __resv
-fields must be cleared to zero.
-
-.SH RETURN VALUE
-Returns 0 on success. On error, a negative errno value is returned.
-
-.SH NOTES
-This function is available since Linux kernel 6.15.
-
-.SH SEE ALSO
-.BR io_uring_register (2),
-.BR io_uring_register_ifq (3)
diff --git a/man/io_uring_register_zcrx_ctrl.3.md b/man/io_uring_register_zcrx_ctrl.3.md
new file mode 100644
index 00000000..1d7b13ca
--- /dev/null
+++ b/man/io_uring_register_zcrx_ctrl.3.md
@@ -0,0 +1,62 @@
+.\" Copyright (C) 2026 Yitang Yang <yi1tang.yang@gmail.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 26, 2026
+footer: liburing-2.15
+header: liburing Manual
+section: 3
+title: io_uring_register_zcrx_ctrl
+---
+
+# NAME
+
+io_uring_register_zcrx_ctrl - perform control operations on a zero-copy receive context
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_register_zcrx_ctrl(struct io_uring * ring ,
+ struct zcrx_ctrl * ctrl );
+
+# DESCRIPTION
+
+The **io_uring_register_zcrx_ctrl**(3) function performs control operations on a previously registered zero-copy receive context. See **io_uring_register_ifq**(3) for details on registering a zero-copy receive context.
+
+The *ctrl* argument must point to a *struct zcrx_ctrl* structure that describes the control operation to perform:
+
+ struct zcrx_ctrl {
+ __u32 zcrx_id;
+ __u32 op;
+ __u64 __resv[2];
+ union {
+ struct zcrx_ctrl_export zc_export;
+ struct zcrx_ctrl_flush_rq zc_flush;
+ };
+ };
+
+The *zcrx_id* field must be set to the ID of the zero-copy receive context returned from **io_uring_register_ifq**(3). The *op* field specifies the control operation to perform and can be one of:
+
+**ZCRX_CTRL_FLUSH_RQ**
+
+: Flushes pending buffers from the refill queue. Uses the *zc_flush* member of the union.
+
+**ZCRX_CTRL_EXPORT**
+
+: Exports the zero-copy receive context for use by other rings. Uses the *zc_export* member of the union. Upon successful export, the *zcrx_fd* field in *zc_export* will contain the file descriptor that can be used to share this context with other io_uring instances.
+
+The reserved *\_\_resv* fields must be cleared to zero.
+
+# RETURN VALUE
+
+Returns 0 on success. On error, a negative errno value is returned.
+
+# NOTES
+
+This function is available since Linux kernel 6.15.
+
+# SEE ALSO
+
+**io_uring_register**(2), **io_uring_register_ifq**(3)
diff --git a/man/io_uring_registered_buffers.7 b/man/io_uring_registered_buffers.7
deleted file mode 100644
index a76ae7e5..00000000
--- a/man/io_uring_registered_buffers.7
+++ /dev/null
@@ -1,238 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_registered_buffers 7 "January 18, 2025" "Linux" "Linux Programmer's Manual"
-.SH NAME
-io_uring_registered_buffers \- io_uring registered buffers overview
-.SH DESCRIPTION
-Registered buffers are a performance optimization feature of
-.B io_uring
-that allows applications to pre-register a set of buffers with the kernel.
-When buffers are registered, the kernel pins the memory and creates
-long-term mappings, eliminating the overhead of mapping and unmapping
-buffer memory for each I/O operation.
-.SS Why use registered buffers?
-For every I/O operation that transfers data between user space and the
-kernel, the kernel must perform several operations on the buffer memory:
-.IP \(bu 2
-Verify the memory is accessible to the process
-.IP \(bu
-Pin the pages in memory to prevent them from being swapped out
-.IP \(bu
-Set up kernel mappings to access the memory
-.PP
-These operations, while individually fast, add up when performing many
-small I/O operations. By registering buffers once upfront, these costs
-are paid only once, and subsequent I/O operations can use the pre-mapped
-buffers directly.
-
-Registered buffers are most beneficial for applications that:
-.IP \(bu 2
-Perform many small I/O operations
-.IP \(bu
-Reuse the same buffers repeatedly
-.IP \(bu
-Need the lowest possible per-I/O overhead
-.SS Registering buffers
-Buffers are registered using
-.BR io_uring_register_buffers (3)
-or
-.BR io_uring_register_buffers_tags (3).
-The buffers are described using an array of
-.I struct iovec
-structures:
-.PP
-.in +4n
-.EX
-struct iovec iovecs[2];
-iovecs[0].iov_base = buf1;
-iovecs[0].iov_len = 4096;
-iovecs[1].iov_base = buf2;
-iovecs[1].iov_len = 8192;
-
-ret = io_uring_register_buffers(ring, iovecs, 2);
-.EE
-.in
-.PP
-The buffers must be anonymous memory (allocated via
-.BR malloc (3),
-.BR mmap (2)
-with
-.BR MAP_ANONYMOUS ,
-or similar). File-backed memory is not supported.
-
-There is a limit of 1 GiB per individual buffer. Huge pages are supported
-and the entire huge page will be pinned even if only part of it is used.
-
-The buffers are charged against the user's
-.B RLIMIT_MEMLOCK
-resource limit on kernels before 5.12. On kernel 5.12 and later with
-.B IORING_FEAT_NATIVE_WORKERS
-support, cgroup memory accounting is used instead and no memlock limit
-applies.
-.PP
-Unless running as root, if buffer registration fails with
-.BR ENOMEM ,
-the memlock limit may need to be increased. The current limit can be
-checked with:
-.PP
-.in +4n
-.EX
-ulimit -l
-.EE
-.in
-.PP
-The limit can be increased for the current shell session with:
-.PP
-.in +4n
-.EX
-ulimit -l unlimited
-.EE
-.in
-.PP
-For a permanent change, edit
-.I /etc/security/limits.conf
-or use
-.BR setrlimit (2)
-programmatically with
-.BR RLIMIT_MEMLOCK .
-.SS Using registered buffers
-To use a registered buffer in an I/O operation, use the fixed buffer
-variants of the prep functions:
-.IP \(bu 2
-.BR io_uring_prep_read_fixed (3)
-instead of
-.BR io_uring_prep_read (3)
-.IP \(bu
-.BR io_uring_prep_write_fixed (3)
-instead of
-.BR io_uring_prep_write (3)
-.IP \(bu
-.BR io_uring_prep_readv_fixed (3)
-instead of
-.BR io_uring_prep_readv (3)
-.IP \(bu
-.BR io_uring_prep_writev_fixed (3)
-instead of
-.BR io_uring_prep_writev (3)
-.PP
-Zero-copy send operations can also use registered buffers:
-.IP \(bu 2
-.BR io_uring_prep_send_zc (3)
-with
-.B IORING_RECVSEND_FIXED_BUF
-.IP \(bu
-.BR io_uring_prep_sendmsg_zc (3)
-with
-.B IORING_RECVSEND_FIXED_BUF
-.PP
-These functions take a
-.I buf_index
-parameter that specifies which registered buffer to use (0-indexed into
-the array passed to
-.BR io_uring_register_buffers (3)).
-
-The memory range used for the I/O operation must fall within the bounds
-of the registered buffer. It is valid to use only a portion of a
-registered buffer for an operation.
-.PP
-.in +4n
-.EX
-/* Use first 1024 bytes of registered buffer 0 */
-io_uring_prep_read_fixed(sqe, fd, buf1, 1024, offset, 0);
-
-/* Use registered buffer 1 */
-io_uring_prep_write_fixed(sqe, fd, buf2, 2048, offset, 1);
-.EE
-.in
-.SS Sparse buffer registration
-Applications can register a sparse buffer table using
-.BR io_uring_register_buffers_sparse (3).
-This creates a table with empty slots that can be filled in later using
-.BR io_uring_register_buffers_update_tag (3).
-This is useful when the full set of buffers is not known at registration
-time.
-.PP
-.in +4n
-.EX
-/* Create sparse table with 10 slots */
-ret = io_uring_register_buffers_sparse(ring, 10);
-
-/* Later, fill in slot 3 */
-struct iovec iov = { .iov_base = buf, .iov_len = 4096 };
-ret = io_uring_register_buffers_update_tag(ring, 3, &iov, NULL, 1);
-.EE
-.in
-.SS Buffer tagging
-When using
-.BR io_uring_register_buffers_tags (3)
-or
-.BR io_uring_register_buffers_update_tag (3),
-each buffer can be associated with a tag value. When a buffer is
-unregistered (either explicitly or by replacing it), and there are no
-more in-flight operations using that buffer, a completion queue entry
-is posted with
-.I user_data
-set to the tag value and all other fields zeroed.
-
-This allows applications to know when it is safe to free or reuse the
-buffer memory.
-.SS Updating registered buffers
-Registered buffers can be updated in place using
-.BR io_uring_register_buffers_update_tag (3).
-This can:
-.IP \(bu 2
-Replace an existing buffer with a new one
-.IP \(bu
-Fill in a sparse slot
-.IP \(bu
-Remove a buffer by setting the iovec to zero length
-.PP
-Updating buffers does not immediately free resources. The old buffer
-remains valid until all in-flight operations complete.
-.SS Unregistering buffers
-Buffers are unregistered using
-.BR io_uring_unregister_buffers (3).
-This releases all registered buffers. Buffers are also automatically
-unregistered when the io_uring instance is destroyed.
-
-Applications do not need to explicitly unregister buffers before
-shutting down the ring. However, page unpinning may happen asynchronously,
-so pages may not be immediately available after ring destruction.
-.SS Cloning buffers
-Registered buffers can be cloned from one ring to another using
-.BR io_uring_clone_buffers (3)
-or
-.BR io_uring_clone_buffers_offset (3).
-This allows multiple rings to share the same set of registered buffers
-without re-registering them.
-.SH NOTES
-.IP \(bu 2
-Registered buffers provide the most benefit for small, frequent I/O
-operations where the per-operation overhead is significant.
-.IP \(bu
-For large I/O operations, the buffer mapping overhead is small relative
-to the actual I/O time, so registered buffers may not provide much benefit.
-.IP \(bu
-The maximum number of registered buffers is limited by available kernel
-memory and the
-.B RLIMIT_MEMLOCK
-limit (on older kernels).
-.IP \(bu
-Registered buffers cannot be used with provided buffer rings
-.RB ( IOSQE_BUFFER_SELECT ).
-These are separate mechanisms for different use cases.
-.SH SEE ALSO
-.BR io_uring (7),
-.BR io_uring_registered_files (7),
-.BR setrlimit (2),
-.BR io_uring_register_buffers (3),
-.BR io_uring_register_buffers_tags (3),
-.BR io_uring_register_buffers_sparse (3),
-.BR io_uring_register_buffers_update_tag (3),
-.BR io_uring_unregister_buffers (3),
-.BR io_uring_prep_read_fixed (3),
-.BR io_uring_prep_write_fixed (3),
-.BR io_uring_prep_send_zc (3),
-.BR io_uring_prep_sendmsg_zc (3),
-.BR io_uring_clone_buffers (3)
diff --git a/man/io_uring_registered_buffers.7.md b/man/io_uring_registered_buffers.7.md
new file mode 100644
index 00000000..ad30aee5
--- /dev/null
+++ b/man/io_uring_registered_buffers.7.md
@@ -0,0 +1,147 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: Linux
+header: Linux Programmer\'s Manual
+section: 7
+title: io_uring_registered_buffers
+---
+
+# NAME
+
+io_uring_registered_buffers - io_uring registered buffers overview
+
+# DESCRIPTION
+
+Registered buffers are a performance optimization feature of **io_uring** that allows applications to pre-register a set of buffers with the kernel. When buffers are registered, the kernel pins the memory and creates long-term mappings, eliminating the overhead of mapping and unmapping buffer memory for each I/O operation.
+
+## Why use registered buffers?
+
+For every I/O operation that transfers data between user space and the kernel, the kernel must perform several operations on the buffer memory:
+
+- Verify the memory is accessible to the process
+
+- Pin the pages in memory to prevent them from being swapped out
+
+- Set up kernel mappings to access the memory
+
+These operations, while individually fast, add up when performing many small I/O operations. By registering buffers once upfront, these costs are paid only once, and subsequent I/O operations can use the pre-mapped buffers directly.
+
+Registered buffers are most beneficial for applications that:
+
+- Perform many small I/O operations
+
+- Reuse the same buffers repeatedly
+
+- Need the lowest possible per-I/O overhead
+
+## Registering buffers
+
+Buffers are registered using **io_uring_register_buffers**(3) or **io_uring_register_buffers_tags**(3). The buffers are described using an array of *struct iovec* structures:
+
+ struct iovec iovecs[2];
+ iovecs[0].iov_base = buf1;
+ iovecs[0].iov_len = 4096;
+ iovecs[1].iov_base = buf2;
+ iovecs[1].iov_len = 8192;
+
+ ret = io_uring_register_buffers(ring, iovecs, 2);
+
+The buffers must be anonymous memory (allocated via **malloc**(3), **mmap**(2) with **MAP_ANONYMOUS**, or similar). File-backed memory is not supported.
+
+There is a limit of 1 GiB per individual buffer. Huge pages are supported and the entire huge page will be pinned even if only part of it is used.
+
+The buffers are charged against the user\'s **RLIMIT_MEMLOCK** resource limit on kernels before 5.12. On kernel 5.12 and later with **IORING_FEAT_NATIVE_WORKERS** support, cgroup memory accounting is used instead and no memlock limit applies.
+
+Unless running as root, if buffer registration fails with **ENOMEM**, the memlock limit may need to be increased. The current limit can be checked with:
+
+ ulimit -l
+
+The limit can be increased for the current shell session with:
+
+ ulimit -l unlimited
+
+For a permanent change, edit */etc/security/limits.conf* or use **setrlimit**(2) programmatically with **RLIMIT_MEMLOCK**.
+
+## Using registered buffers
+
+To use a registered buffer in an I/O operation, use the fixed buffer variants of the prep functions:
+
+- **io_uring_prep_read_fixed**(3) instead of **io_uring_prep_read**(3)
+
+- **io_uring_prep_write_fixed**(3) instead of **io_uring_prep_write**(3)
+
+- **io_uring_prep_readv_fixed**(3) instead of **io_uring_prep_readv**(3)
+
+- **io_uring_prep_writev_fixed**(3) instead of **io_uring_prep_writev**(3)
+
+Zero-copy send operations can also use registered buffers:
+
+- **io_uring_prep_send_zc**(3) with **IORING_RECVSEND_FIXED_BUF**
+
+- **io_uring_prep_sendmsg_zc**(3) with **IORING_RECVSEND_FIXED_BUF**
+
+These functions take a *buf_index* parameter that specifies which registered buffer to use (0-indexed into the array passed to **io_uring_register_buffers**(3)).
+
+The memory range used for the I/O operation must fall within the bounds of the registered buffer. It is valid to use only a portion of a registered buffer for an operation.
+
+ /* Use first 1024 bytes of registered buffer 0 */
+ io_uring_prep_read_fixed(sqe, fd, buf1, 1024, offset, 0);
+
+ /* Use registered buffer 1 */
+ io_uring_prep_write_fixed(sqe, fd, buf2, 2048, offset, 1);
+
+## Sparse buffer registration
+
+Applications can register a sparse buffer table using **io_uring_register_buffers_sparse**(3). This creates a table with empty slots that can be filled in later using **io_uring_register_buffers_update_tag**(3). This is useful when the full set of buffers is not known at registration time.
+
+ /* Create sparse table with 10 slots */
+ ret = io_uring_register_buffers_sparse(ring, 10);
+
+ /* Later, fill in slot 3 */
+ struct iovec iov = { .iov_base = buf, .iov_len = 4096 };
+ ret = io_uring_register_buffers_update_tag(ring, 3, &iov, NULL, 1);
+
+## Buffer tagging
+
+When using **io_uring_register_buffers_tags**(3) or **io_uring_register_buffers_update_tag**(3), each buffer can be associated with a tag value. When a buffer is unregistered (either explicitly or by replacing it), and there are no more in-flight operations using that buffer, a completion queue entry is posted with *user_data* set to the tag value and all other fields zeroed.
+
+This allows applications to know when it is safe to free or reuse the buffer memory.
+
+## Updating registered buffers
+
+Registered buffers can be updated in place using **io_uring_register_buffers_update_tag**(3). This can:
+
+- Replace an existing buffer with a new one
+
+- Fill in a sparse slot
+
+- Remove a buffer by setting the iovec to zero length
+
+Updating buffers does not immediately free resources. The old buffer remains valid until all in-flight operations complete.
+
+## Unregistering buffers
+
+Buffers are unregistered using **io_uring_unregister_buffers**(3). This releases all registered buffers. Buffers are also automatically unregistered when the io_uring instance is destroyed.
+
+Applications do not need to explicitly unregister buffers before shutting down the ring. However, page unpinning may happen asynchronously, so pages may not be immediately available after ring destruction.
+
+## Cloning buffers
+
+Registered buffers can be cloned from one ring to another using **io_uring_clone_buffers**(3) or **io_uring_clone_buffers_offset**(3). This allows multiple rings to share the same set of registered buffers without re-registering them.
+
+# NOTES
+
+- Registered buffers provide the most benefit for small, frequent I/O operations where the per-operation overhead is significant.
+
+- For large I/O operations, the buffer mapping overhead is small relative to the actual I/O time, so registered buffers may not provide much benefit.
+
+- The maximum number of registered buffers is limited by available kernel memory and the **RLIMIT_MEMLOCK** limit (on older kernels).
+
+- Registered buffers cannot be used with provided buffer rings (**IOSQE_BUFFER_SELECT**). These are separate mechanisms for different use cases.
+
+# SEE ALSO
+
+**io_uring**(7), **io_uring_registered_files**(7), **setrlimit**(2), **io_uring_register_buffers**(3), **io_uring_register_buffers_tags**(3), **io_uring_register_buffers_sparse**(3), **io_uring_register_buffers_update_tag**(3), **io_uring_unregister_buffers**(3), **io_uring_prep_read_fixed**(3), **io_uring_prep_write_fixed**(3), **io_uring_prep_send_zc**(3), **io_uring_prep_sendmsg_zc**(3), **io_uring_clone_buffers**(3)
diff --git a/man/io_uring_registered_files.7 b/man/io_uring_registered_files.7
deleted file mode 100644
index b280b009..00000000
--- a/man/io_uring_registered_files.7
+++ /dev/null
@@ -1,228 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_registered_files 7 "January 18, 2025" "Linux" "Linux Programmer's Manual"
-.SH NAME
-io_uring_registered_files \- io_uring registered files overview
-.SH DESCRIPTION
-Registered files (also known as fixed files) are a performance
-optimization feature of
-.B io_uring
-that allows applications to pre-register a set of file descriptors with
-the kernel. When files are registered, the kernel takes a reference to
-each file, avoiding the overhead of looking up file descriptors and
-taking references for each I/O operation.
-.SS Why use registered files?
-For every I/O operation that uses a file descriptor, the kernel must:
-.IP \(bu 2
-Look up the file descriptor in the process's file descriptor table
-.IP \(bu
-Take a reference to the file to ensure it remains valid during the
-operation
-.IP \(bu
-Release the reference when the operation completes
-.PP
-For applications performing many I/O operations, especially on threaded
-applications where the file table is shared (making reference counting
-more expensive), these overheads accumulate. By registering files once,
-the reference is held for the lifetime of the registration, and
-operations can use the file directly without per-operation lookups or
-reference counting.
-
-Registered files are most beneficial for applications that:
-.IP \(bu 2
-Perform many I/O operations on the same set of files
-.IP \(bu
-Are multi-threaded (where file table operations are more expensive)
-.IP \(bu
-Need the lowest possible per-I/O overhead
-.SS Registering files
-Files are registered using
-.BR io_uring_register_files (3)
-or
-.BR io_uring_register_files_tags (3).
-The files are described using an array of file descriptors:
-.PP
-.in +4n
-.EX
-int fds[3];
-fds[0] = open("file1", O_RDONLY);
-fds[1] = open("file2", O_RDONLY);
-fds[2] = open("file3", O_WRONLY | O_CREAT, 0644);
-
-ret = io_uring_register_files(ring, fds, 3);
-.EE
-.in
-.PP
-Once registered, the original file descriptors can be closed if desired.
-The kernel holds its own references to the underlying files.
-.SS Using registered files
-To use a registered file in an I/O operation, set the
-.B IOSQE_FIXED_FILE
-flag in the SQE's
-.I flags
-field, and use the index into the registered file array (not the original
-file descriptor) in the
-.I fd
-field:
-.PP
-.in +4n
-.EX
-struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
-io_uring_prep_read(sqe, 0, buf, len, offset); /* index 0, not fd */
-io_uring_sqe_set_flags(sqe, IOSQE_FIXED_FILE);
-.EE
-.in
-.PP
-The index is 0-based into the array passed to
-.BR io_uring_register_files (3).
-.SS Sparse file registration
-The file array can be sparse, meaning some slots can be empty. Empty
-slots are indicated by setting the file descriptor to \-1. Applications
-can create a fully sparse table using
-.BR io_uring_register_files_sparse (3)
-and fill in slots later:
-.PP
-.in +4n
-.EX
-/* Create sparse table with 100 slots */
-ret = io_uring_register_files_sparse(ring, 100);
-
-/* Later, fill in slot 5 */
-int fd = open("file", O_RDONLY);
-ret = io_uring_register_files_update(ring, 5, &fd, 1);
-.EE
-.in
-.SS Updating registered files
-Registered files can be updated using
-.BR io_uring_register_files_update (3)
-or
-.BR io_uring_register_files_update_tag (3).
-This can:
-.IP \(bu 2
-Replace an existing file with a new one
-.IP \(bu
-Fill in an empty slot
-.IP \(bu
-Remove a file by setting the descriptor to \-1
-.PP
-To skip updating certain slots while updating others, use the special
-value
-.BR IORING_REGISTER_FILES_SKIP .
-.PP
-.in +4n
-.EX
-int fds[3];
-fds[0] = new_fd; /* replace slot 0 */
-fds[1] = IORING_REGISTER_FILES_SKIP; /* leave slot 1 unchanged */
-fds[2] = -1; /* remove slot 2 */
-
-ret = io_uring_register_files_update(ring, 0, fds, 3);
-.EE
-.in
-.PP
-Updates do not require the ring to be idle on kernels 5.13 and later.
-On older kernels, updates would wait for in-flight operations to complete.
-.SS File tagging
-When using
-.BR io_uring_register_files_tags (3)
-or
-.BR io_uring_register_files_update_tag (3),
-each file can be associated with a tag value. When a file is unregistered
-(either explicitly or by replacement), and there are no more in-flight
-operations using that file, a completion queue entry is posted with
-.I user_data
-set to the tag value and all other fields zeroed.
-
-This notification mechanism allows applications to know when it is safe
-to perform cleanup actions associated with the file.
-.SS Direct file descriptors
-Some io_uring operations can allocate file descriptors directly into the
-registered file table, avoiding the regular file descriptor table
-entirely. This is done by setting the
-.I file_index
-field in the SQE (using
-.BR io_uring_sqe_set_target_fixed_file (3))
-to the desired slot, or using
-.B IORING_FILE_INDEX_ALLOC
-to have io_uring allocate the next available slot.
-
-Operations that support direct descriptors include:
-.IP \(bu 2
-.B IORING_OP_OPENAT
-/
-.B IORING_OP_OPENAT2
-.IP \(bu
-.B IORING_OP_ACCEPT
-.IP \(bu
-.B IORING_OP_SOCKET
-.IP \(bu
-.B IORING_OP_PIPE
-.PP
-When using
-.BR IORING_FILE_INDEX_ALLOC ,
-the application should use
-.BR io_uring_register_file_alloc_range (3)
-to specify which range of the file table should be used for allocations.
-.PP
-.in +4n
-.EX
-/* Reserve slots 50-99 for dynamic allocation */
-io_uring_register_file_alloc_range(ring, 50, 50);
-
-/* Accept with direct descriptor allocation */
-struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
-io_uring_prep_accept_direct(sqe, listen_fd, NULL, NULL, 0,
- IORING_FILE_INDEX_ALLOC);
-.EE
-.in
-.PP
-The allocated slot index is returned in the CQE
-.I res
-field on success.
-.SS Closing direct descriptors
-Direct descriptors (files that exist only in the registered file table)
-can be closed using
-.B IORING_OP_CLOSE
-with the
-.B IOSQE_FIXED_FILE
-flag set, or by updating the slot to \-1 using
-.BR io_uring_register_files_update (3).
-.SS Unregistering files
-Files are unregistered using
-.BR io_uring_unregister_files (3).
-This releases all registered files. Files are also automatically
-unregistered when the io_uring instance is destroyed.
-
-Applications do not need to explicitly unregister files before shutting
-down the ring.
-.SH NOTES
-.IP \(bu 2
-Registered files provide the most benefit for applications performing
-many operations on the same files, especially multi-threaded applications.
-.IP \(bu
-Direct descriptors (files that only exist in the registered table) are
-not visible to operations outside io_uring, such as
-.BR read (2)
-or
-.BR write (2).
-.IP \(bu
-The
-.B IOSQE_FIXED_FILE
-flag must be set when using a registered file index; without it, the
-.I fd
-field is interpreted as a regular file descriptor.
-.IP \(bu
-It is an error to use
-.B IOSQE_FIXED_FILE
-with an index that does not correspond to a registered file.
-.SH SEE ALSO
-.BR io_uring (7),
-.BR io_uring_registered_buffers (7),
-.BR io_uring_register_files (3),
-.BR io_uring_register_files_tags (3),
-.BR io_uring_register_files_sparse (3),
-.BR io_uring_register_files_update (3),
-.BR io_uring_register_files_update_tag (3),
-.BR io_uring_unregister_files (3),
-.BR io_uring_register_file_alloc_range (3)
diff --git a/man/io_uring_registered_files.7.md b/man/io_uring_registered_files.7.md
new file mode 100644
index 00000000..79034c43
--- /dev/null
+++ b/man/io_uring_registered_files.7.md
@@ -0,0 +1,149 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: Linux
+header: Linux Programmer\'s Manual
+section: 7
+title: io_uring_registered_files
+---
+
+# NAME
+
+io_uring_registered_files - io_uring registered files overview
+
+# DESCRIPTION
+
+Registered files (also known as fixed files) are a performance optimization feature of **io_uring** that allows applications to pre-register a set of file descriptors with the kernel. When files are registered, the kernel takes a reference to each file, avoiding the overhead of looking up file descriptors and taking references for each I/O operation.
+
+## Why use registered files?
+
+For every I/O operation that uses a file descriptor, the kernel must:
+
+- Look up the file descriptor in the process\'s file descriptor table
+
+- Take a reference to the file to ensure it remains valid during the operation
+
+- Release the reference when the operation completes
+
+For applications performing many I/O operations, especially on threaded applications where the file table is shared (making reference counting more expensive), these overheads accumulate. By registering files once, the reference is held for the lifetime of the registration, and operations can use the file directly without per-operation lookups or reference counting.
+
+Registered files are most beneficial for applications that:
+
+- Perform many I/O operations on the same set of files
+
+- Are multi-threaded (where file table operations are more expensive)
+
+- Need the lowest possible per-I/O overhead
+
+## Registering files
+
+Files are registered using **io_uring_register_files**(3) or **io_uring_register_files_tags**(3). The files are described using an array of file descriptors:
+
+ int fds[3];
+ fds[0] = open("file1", O_RDONLY);
+ fds[1] = open("file2", O_RDONLY);
+ fds[2] = open("file3", O_WRONLY | O_CREAT, 0644);
+
+ ret = io_uring_register_files(ring, fds, 3);
+
+Once registered, the original file descriptors can be closed if desired. The kernel holds its own references to the underlying files.
+
+## Using registered files
+
+To use a registered file in an I/O operation, set the **IOSQE_FIXED_FILE** flag in the SQE\'s *flags* field, and use the index into the registered file array (not the original file descriptor) in the *fd* field:
+
+ struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
+ io_uring_prep_read(sqe, 0, buf, len, offset); /* index 0, not fd */
+ io_uring_sqe_set_flags(sqe, IOSQE_FIXED_FILE);
+
+The index is 0-based into the array passed to **io_uring_register_files**(3).
+
+## Sparse file registration
+
+The file array can be sparse, meaning some slots can be empty. Empty slots are indicated by setting the file descriptor to -1. Applications can create a fully sparse table using **io_uring_register_files_sparse**(3) and fill in slots later:
+
+ /* Create sparse table with 100 slots */
+ ret = io_uring_register_files_sparse(ring, 100);
+
+ /* Later, fill in slot 5 */
+ int fd = open("file", O_RDONLY);
+ ret = io_uring_register_files_update(ring, 5, &fd, 1);
+
+## Updating registered files
+
+Registered files can be updated using **io_uring_register_files_update**(3) or **io_uring_register_files_update_tag**(3). This can:
+
+- Replace an existing file with a new one
+
+- Fill in an empty slot
+
+- Remove a file by setting the descriptor to -1
+
+To skip updating certain slots while updating others, use the special value **IORING_REGISTER_FILES_SKIP**.
+
+ int fds[3];
+ fds[0] = new_fd; /* replace slot 0 */
+ fds[1] = IORING_REGISTER_FILES_SKIP; /* leave slot 1 unchanged */
+ fds[2] = -1; /* remove slot 2 */
+
+ ret = io_uring_register_files_update(ring, 0, fds, 3);
+
+Updates do not require the ring to be idle on kernels 5.13 and later. On older kernels, updates would wait for in-flight operations to complete.
+
+## File tagging
+
+When using **io_uring_register_files_tags**(3) or **io_uring_register_files_update_tag**(3), each file can be associated with a tag value. When a file is unregistered (either explicitly or by replacement), and there are no more in-flight operations using that file, a completion queue entry is posted with *user_data* set to the tag value and all other fields zeroed.
+
+This notification mechanism allows applications to know when it is safe to perform cleanup actions associated with the file.
+
+## Direct file descriptors
+
+Some io_uring operations can allocate file descriptors directly into the registered file table, avoiding the regular file descriptor table entirely. This is done by setting the *file_index* field in the SQE (using **io_uring_sqe_set_target_fixed_file**(3)) to the desired slot, or using **IORING_FILE_INDEX_ALLOC** to have io_uring allocate the next available slot.
+
+Operations that support direct descriptors include:
+
+- **IORING_OP_OPENAT** / **IORING_OP_OPENAT2**
+
+- **IORING_OP_ACCEPT**
+
+- **IORING_OP_SOCKET**
+
+- **IORING_OP_PIPE**
+
+When using **IORING_FILE_INDEX_ALLOC**, the application should use **io_uring_register_file_alloc_range**(3) to specify which range of the file table should be used for allocations.
+
+ /* Reserve slots 50-99 for dynamic allocation */
+ io_uring_register_file_alloc_range(ring, 50, 50);
+
+ /* Accept with direct descriptor allocation */
+ struct io_uring_sqe *sqe = io_uring_get_sqe(ring);
+ io_uring_prep_accept_direct(sqe, listen_fd, NULL, NULL, 0,
+ IORING_FILE_INDEX_ALLOC);
+
+The allocated slot index is returned in the CQE *res* field on success.
+
+## Closing direct descriptors
+
+Direct descriptors (files that exist only in the registered file table) can be closed using **IORING_OP_CLOSE** with the **IOSQE_FIXED_FILE** flag set, or by updating the slot to -1 using **io_uring_register_files_update**(3).
+
+## Unregistering files
+
+Files are unregistered using **io_uring_unregister_files**(3). This releases all registered files. Files are also automatically unregistered when the io_uring instance is destroyed.
+
+Applications do not need to explicitly unregister files before shutting down the ring.
+
+# NOTES
+
+- Registered files provide the most benefit for applications performing many operations on the same files, especially multi-threaded applications.
+
+- Direct descriptors (files that only exist in the registered table) are not visible to operations outside io_uring, such as **read**(2) or **write**(2).
+
+- The **IOSQE_FIXED_FILE** flag must be set when using a registered file index; without it, the *fd* field is interpreted as a regular file descriptor.
+
+- It is an error to use **IOSQE_FIXED_FILE** with an index that does not correspond to a registered file.
+
+# SEE ALSO
+
+**io_uring**(7), **io_uring_registered_buffers**(7), **io_uring_register_files**(3), **io_uring_register_files_tags**(3), **io_uring_register_files_sparse**(3), **io_uring_register_files_update**(3), **io_uring_register_files_update_tag**(3), **io_uring_unregister_files**(3), **io_uring_register_file_alloc_range**(3)
diff --git a/man/io_uring_resize_rings.3 b/man/io_uring_resize_rings.3
deleted file mode 100644
index 4d4a9286..00000000
--- a/man/io_uring_resize_rings.3
+++ /dev/null
@@ -1,116 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_resize_rings 3 "October 29, 2024" "liburing-2.9" "liburing Manual"
-.SH NAME
-io_uring_resize_rings \- resize the SQ and CQ rings
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_resize_rings(struct io_uring *" ring ",
-.BI " struct io_uring_params *" p ");
-.PP
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_resize_rings (3)
-function performs resizes the SQ and/or CQ ring associated with
-.I ring
-by the parameters specified in
-.I p .
-
-The
-.I p
-argument must be filled in with the appropriate information for the resize
-operations, most notably the
-.IR sq_entries
-and
-.IR cq_entries
-fields must be filled out. The
-.IR flags
-field can also be set, see below for potential values that may be used with
-a resize operation.
-
-It's fairly uncommon to need to resize the SQ ring, but not that uncommon
-that the CQ ring would need resizing. For networked workloads, it can be
-hard to appropriately size the CQ ring upfront, as it's not always known what
-load a given ring will see. If overflow conditions are seen for the CQ ring,
-then resizing it larger may be a good idea.
-
-When a ring is resized, any pending SQ or CQ entries are copied along the
-way. It is not legal to resize a CQ ring that is in an overflow condition,
-and attempting to do so will fail.
-
-Currently doesn't support resizing rings setup with
-.B IORING_SETUP_NO_MMAP .
-This is purely a liburing limitation, the kernel does support it.
-
-Also note that ring resizing is currently only supported on rings setup
-with
-.B IORING_SETUP_DEFER_TASKRUN .
-Attempting to resize differently configured rings will result in an
-.BR -EINVAL
-error.
-
-Valid flags in
-.IR flags :
-.TP
-.B IORING_SETUP_CQSIZE
-If this isn't set, then the CQ ring size is set based on the specified
-SQ ring size. The default is twice as many CQ ring entries as there are
-SQ ring entries. If set, then
-.IR cq_entries
-will be used to size the CQ ring.
-.TP
-.B IORING_SETUP_CLAMP
-If set, then SQ and CQ ring entries are clamped to the maximum allowable
-size, if they exceed that. If not set, setting sizes too large will cause
-the operation to fail.
-.PP
-
-Other flags are inherited from the way the ring was setup, that includes flags
-like
-.B IORING_SETUP_NO_SQARRAY ,
-.B IORING_SETUP_SQE128 ,
-.B IORING_SETUP_CQE32 ,
-and
-.B IORING_SETUP_NO_MMAP .
-
-Other fields in
-.IR p
-should be cleared to zero.
-
-Available since kernel 6.13.
-
-Also see
-.BR io_uring_setup (2)
-for a detailed description of the setup flags.
-
-.SH RETURN VALUE
-.PP
-Returns 0 on success, and < 0 on failure. Potential common failure cases:
-.TP
-.B -EEXIST
-Attempting to resize a ring setup with
-.B IORING_SETUP_SINGLE_ISSUER
-and the resizing task is different from the one that created/enabled the ring.
-.TP
-.B -EFAULT
-Copying of
-.I p
-was unsuccessful.
-.TP
-.B -EINVAL
-Invalid flags were specified for the operation
-.TP
-.B -EINVAL
-Attempt to resize a ring not setup with
-.BR IORING_SETUP_DEFER_TASKRUN .
-.TP
-.B -EOVERFLOW
-The values specified for SQ or CQ entries would cause an overflow.
-
-.SH SEE ALSO
-.BR io_uring_setup (2)
diff --git a/man/io_uring_resize_rings.3.md b/man/io_uring_resize_rings.3.md
new file mode 100644
index 00000000..258e9ab5
--- /dev/null
+++ b/man/io_uring_resize_rings.3.md
@@ -0,0 +1,82 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: October 29, 2024
+footer: liburing-2.9
+header: liburing Manual
+section: 3
+title: io_uring_resize_rings
+---
+
+# NAME
+
+io_uring_resize_rings - resize the SQ and CQ rings
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_resize_rings(struct io_uring * ring ,
+ struct io_uring_params * p );
+
+# DESCRIPTION
+
+The **io_uring_resize_rings**(3) function performs resizes the SQ and/or CQ ring associated with *ring* by the parameters specified in *p .*
+
+The *p* argument must be filled in with the appropriate information for the resize operations, most notably the *sq_entries* and *cq_entries* fields must be filled out. The *flags* field can also be set, see below for potential values that may be used with a resize operation.
+
+It\'s fairly uncommon to need to resize the SQ ring, but not that uncommon that the CQ ring would need resizing. For networked workloads, it can be hard to appropriately size the CQ ring upfront, as it\'s not always known what load a given ring will see. If overflow conditions are seen for the CQ ring, then resizing it larger may be a good idea.
+
+When a ring is resized, any pending SQ or CQ entries are copied along the way. It is not legal to resize a CQ ring that is in an overflow condition, and attempting to do so will fail.
+
+Currently doesn\'t support resizing rings setup with **IORING_SETUP_NO_MMAP .** This is purely a liburing limitation, the kernel does support it.
+
+Also note that ring resizing is currently only supported on rings setup with **IORING_SETUP_DEFER_TASKRUN .** Attempting to resize differently configured rings will result in an **-EINVAL** error.
+
+Valid flags in *flags*:
+
+**IORING_SETUP_CQSIZE**
+
+: If this isn\'t set, then the CQ ring size is set based on the specified SQ ring size. The default is twice as many CQ ring entries as there are SQ ring entries. If set, then *cq_entries* will be used to size the CQ ring.
+
+**IORING_SETUP_CLAMP**
+
+: If set, then SQ and CQ ring entries are clamped to the maximum allowable size, if they exceed that. If not set, setting sizes too large will cause the operation to fail.
+
+Other flags are inherited from the way the ring was setup, that includes flags like **IORING_SETUP_NO_SQARRAY ,** **IORING_SETUP_SQE128 ,** **IORING_SETUP_CQE32 ,** and **IORING_SETUP_NO_MMAP .**
+
+Other fields in *p* should be cleared to zero.
+
+Available since kernel 6.13.
+
+Also see **io_uring_setup**(2) for a detailed description of the setup flags.
+
+# RETURN VALUE
+
+Returns 0 on success, and \< 0 on failure. Potential common failure cases:
+
+**-EEXIST**
+
+: Attempting to resize a ring setup with **IORING_SETUP_SINGLE_ISSUER** and the resizing task is different from the one that created/enabled the ring.
+
+**-EFAULT**
+
+: Copying of *p* was unsuccessful.
+
+**-EINVAL**
+
+: Invalid flags were specified for the operation
+
+**-EINVAL**
+
+: Attempt to resize a ring not setup with **IORING_SETUP_DEFER_TASKRUN**.
+
+**-EOVERFLOW**
+
+: The values specified for SQ or CQ entries would cause an overflow.
+
+# SEE ALSO
+
+**io_uring_setup**(2)
diff --git a/man/io_uring_ring_dontfork.3 b/man/io_uring_ring_dontfork.3
deleted file mode 100644
index 3fca48bf..00000000
--- a/man/io_uring_ring_dontfork.3
+++ /dev/null
@@ -1,36 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_ring_dontfork 3 "January 18, 2025" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_ring_dontfork \- prevent ring memory from being shared after fork
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_ring_dontfork(struct io_uring *" ring ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_ring_dontfork (3)
-function ensures that the mmap'ed rings for the io_uring instance
-.I ring
-are not available to a child process after a
-.BR fork (2).
-
-This function uses
-.BR madvise (2)
-with
-.B MADV_DONTFORK
-on the mmap'ed ranges to prevent them from being shared with child
-processes. This is useful when the parent wants exclusive access to the
-ring and doesn't want the child to be able to access or interfere with it.
-
-.SH RETURN VALUE
-Returns 0 on success. On error, a negative errno value is returned.
-.SH SEE ALSO
-.BR io_uring_queue_init (3),
-.BR madvise (2),
-.BR fork (2)
diff --git a/man/io_uring_ring_dontfork.3.md b/man/io_uring_ring_dontfork.3.md
new file mode 100644
index 00000000..ce64b14f
--- /dev/null
+++ b/man/io_uring_ring_dontfork.3.md
@@ -0,0 +1,35 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_ring_dontfork
+---
+
+# NAME
+
+io_uring_ring_dontfork - prevent ring memory from being shared after fork
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_ring_dontfork(struct io_uring * ring );
+
+# DESCRIPTION
+
+The **io_uring_ring_dontfork**(3) function ensures that the mmap\'ed rings for the io_uring instance *ring* are not available to a child process after a **fork**(2).
+
+This function uses **madvise**(2) with **MADV_DONTFORK** on the mmap\'ed ranges to prevent them from being shared with child processes. This is useful when the parent wants exclusive access to the ring and doesn\'t want the child to be able to access or interfere with it.
+
+# RETURN VALUE
+
+Returns 0 on success. On error, a negative errno value is returned.
+
+# SEE ALSO
+
+**io_uring_queue_init**(3), **madvise**(2), **fork**(2)
diff --git a/man/io_uring_set_iowait.3 b/man/io_uring_set_iowait.3
deleted file mode 100644
index 5caf0a3a..00000000
--- a/man/io_uring_set_iowait.3
+++ /dev/null
@@ -1,57 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\" Copyright (C) 2025 Ammar Faizi <ammarfaizi2@gnuweeb.org>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_set_iowait 3 "July 27, 2025" "liburing-2.12" "liburing Manual"
-.SH NAME
-io_uring_set_iowait \- toggle of iowait usage when waiting on CQEs
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_set_iowait(struct io_uring *" ring ",
-.BI " bool " enable_iowait ");"
-.fi
-.SH DESCRIPTION
-.PP
-By default, io_uring marks a waiting task as being in iowait if it's
-sleeping waiting on events and there are pending requests. This isn't
-necessarily always useful, and may be confusing on non-storage setups
-where iowait isn't expected. It can also cause extra power usage by
-preventing the CPU from entering lower sleep states.
-
-The
-.BR io_uring_set_iowait (3)
-function allows the user to toggle this behavior. If
-.BI enable_iowait
-is set to true, the iowait behavior is enabled. If it is set to false,
-the iowait behavior is disabled. The iowait behavior is enabled by
-default when a ring is created.
-
-If the iowait is disabled, the submit functions will set
-.B IORING_ENTER_NO_IOWAIT
-in the
-.BI flags
-argument to
-.BR io_uring_enter (2).
-
-If the kernel supports this feature, it will be marked by having
-the
-.B IORING_FEAT_NO_IOWAIT
-feature flag set.
-
-Available since kernel 6.15.
-
-
-.SH RETURN VALUE
-On success,
-.BR io_uring_set_iowait (3)
-returns 0. On failure, it returns
-.BR -EOPNOTSUPP .
-
-
-.SH SEE ALSO
-.BR io_uring_enter (2),
-.BR io_uring_submit (3),
-.BR io_uring_submit_and_wait (3)
diff --git a/man/io_uring_set_iowait.3.md b/man/io_uring_set_iowait.3.md
new file mode 100644
index 00000000..38a0559c
--- /dev/null
+++ b/man/io_uring_set_iowait.3.md
@@ -0,0 +1,43 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\" Copyright (C) 2025 Ammar Faizi <ammarfaizi2@gnuweeb.org>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: July 27, 2025
+footer: liburing-2.12
+header: liburing Manual
+section: 3
+title: io_uring_set_iowait
+---
+
+# NAME
+
+io_uring_set_iowait - toggle of iowait usage when waiting on CQEs
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_set_iowait(struct io_uring * ring ,
+ bool enable_iowait );
+
+# DESCRIPTION
+
+By default, io_uring marks a waiting task as being in iowait if it\'s sleeping waiting on events and there are pending requests. This isn\'t necessarily always useful, and may be confusing on non-storage setups where iowait isn\'t expected. It can also cause extra power usage by preventing the CPU from entering lower sleep states.
+
+The **io_uring_set_iowait**(3) function allows the user to toggle this behavior. If enable_iowait is set to true, the iowait behavior is enabled. If it is set to false, the iowait behavior is disabled. The iowait behavior is enabled by default when a ring is created.
+
+If the iowait is disabled, the submit functions will set **IORING_ENTER_NO_IOWAIT** in the flags argument to **io_uring_enter**(2).
+
+If the kernel supports this feature, it will be marked by having the **IORING_FEAT_NO_IOWAIT** feature flag set.
+
+Available since kernel 6.15.
+
+# RETURN VALUE
+
+On success, **io_uring_set_iowait**(3) returns 0. On failure, it returns **-EOPNOTSUPP**.
+
+# SEE ALSO
+
+**io_uring_enter**(2), **io_uring_submit**(3), **io_uring_submit_and_wait**(3)
diff --git a/man/io_uring_setup.2 b/man/io_uring_setup.2
deleted file mode 100644
index 66d302b2..00000000
--- a/man/io_uring_setup.2
+++ /dev/null
@@ -1,820 +0,0 @@
-.\" Copyright (C) 2019 Jens Axboe <axboe@kernel.dk>
-.\" Copyright (C) 2019 Jon Corbet <corbet@lwn.net>
-.\" Copyright (C) 2019 Red Hat, Inc.
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_setup 2 "January 29, 2019" "Linux" "Linux Programmer's Manual"
-.SH NAME
-io_uring_setup \- setup a context for performing asynchronous I/O
-.SH SYNOPSIS
-.nf
-.BR "#include <liburing.h>"
-.PP
-.BI "int io_uring_setup(u32 " entries ", struct io_uring_params *" params );
-.fi
-.PP
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_setup (2)
-system call sets up a submission queue (SQ) and completion queue (CQ) with at
-least
-.I entries
-entries, and returns a file descriptor which can be used to perform
-subsequent operations on the io_uring instance. The submission and
-completion queues are shared between userspace and the kernel, which
-eliminates the need to copy data when initiating and completing I/O.
-
-.I params
-is used by the application to pass options to the kernel, and by the
-kernel to convey information about the ring buffers.
-.PP
-.in +4n
-.EX
-struct io_uring_params {
- __u32 sq_entries;
- __u32 cq_entries;
- __u32 flags;
- __u32 sq_thread_cpu;
- __u32 sq_thread_idle;
- __u32 features;
- __u32 wq_fd;
- __u32 resv[3];
- struct io_sqring_offsets sq_off;
- struct io_cqring_offsets cq_off;
-};
-.EE
-.in
-.PP
-The
-.IR flags ,
-.IR sq_thread_cpu ,
-and
-.I sq_thread_idle
-fields are used to configure the io_uring instance.
-.I flags
-is a bit mask of 0 or more of the following values ORed
-together:
-.TP
-.B IORING_SETUP_IOPOLL
-Perform busy-waiting for an I/O completion, as opposed to getting
-notifications via an asynchronous IRQ (Interrupt Request). The file
-system (if any) and block device must support polling in order for
-this to work. Busy-waiting provides lower latency, but may consume
-more CPU resources than interrupt driven I/O. Currently, this feature
-is usable only on a file descriptor opened using the
-.B O_DIRECT
-flag
-(if using the
-.B IORING_OP_{READ,WRITE}(V)(_FIXED)
-opcodes). When a read or write is submitted to a polled context, the
-application must poll for completions on the CQ ring by calling
-.BR io_uring_enter (2).
-Most non-polled I/O requests are forbidden on
-.B IORING_SETUP_IOPOLL
-io_uring instances (see
-.BR io_uring_setup_flags (7)
-for the allowed opcodes).
-
-This is only applicable for storage devices for now, and the storage device
-must be configured for polling. How to do that depends on the device type
-in question. For NVMe devices, the nvme driver must be loaded with the
-.I poll_queues
-parameter set to the desired number of polling queues. The polling queues
-will be shared appropriately between the CPUs in the system, if the number
-is less than the number of online CPU threads.
-.TP
-.B IORING_SETUP_HYBRID_IOPOLL
-This flag must be used with
-.B IORING_SETUP_IOPOLL
-flag. Hybrid io polling is a feature based on iopoll, it differs from strict
-polling in that it will delay a bit before doing completion side polling, to
-avoid wasting too much CPU resources. Like
-.B IOPOLL
-, it requires that devices support polling.
-.TP
-.B IORING_SETUP_SQPOLL
-When this flag is specified, a kernel thread is created to perform
-submission queue polling. An io_uring instance configured in this way
-enables an application to issue I/O without ever context switching
-into the kernel. By using the submission queue to fill in new
-submission queue entries and watching for completions on the
-completion queue, the application can submit and reap I/Os without
-doing a single system call.
-
-If the kernel thread is idle for more than
-.I sq_thread_idle
-milliseconds, it will set the
-.B IORING_SQ_NEED_WAKEUP
-bit in the
-.I flags
-field of the
-.IR "struct io_sq_ring" .
-When this happens, the application must call
-.BR io_uring_enter (2)
-to wake the kernel thread. If I/O is kept busy, the kernel thread
-will never sleep. An application making use of this feature will need
-to guard the
-.BR io_uring_enter (2)
-call with the following code sequence:
-
-.in +4n
-.EX
-/*
- * Ensure that the wakeup flag is read after the tail pointer
- * has been written. It's important to use memory load acquire
- * semantics for the flags read, as otherwise the application
- * and the kernel might not agree on the consistency of the
- * wakeup flag.
- */
-unsigned flags = atomic_load_relaxed(sq_ring->flags);
-if (flags & IORING_SQ_NEED_WAKEUP)
- io_uring_enter(fd, 0, 0, IORING_ENTER_SQ_WAKEUP);
-.EE
-.in
-
-where
-.I sq_ring
-is a submission queue ring setup using the
-.I struct io_sqring_offsets
-described below.
-.TP
-.BR
-Note that, when using a ring setup with
-.BR IORING_SETUP_SQPOLL ,
-you never directly call the
-.BR io_uring_enter (2)
-system call. That is usually taken care of by liburing's
-.BR io_uring_submit (3)
-function. It automatically determines if you are using
-polling mode or not and deals with when your program needs to call
-.BR io_uring_enter (2)
-without you having to bother about it.
-.TP
-.BR
-Note that while this may sound immediately appealing
-as an automatic "go faster" flag, evaluations should be done on a case-by-case
-basis to check if it makes sense for the application.
-.TP
-.BR
-Before version 5.11 of the Linux kernel, to successfully use this feature, the
-application must register a set of files to be used for IO through
-.BR io_uring_register (2)
-using the
-.B IORING_REGISTER_FILES
-opcode. Failure to do so will result in submitted IO being errored with
-.BR EBADF .
-The presence of this feature can be detected by the
-.B IORING_FEAT_SQPOLL_NONFIXED
-feature flag.
-In version 5.11 and later, it is no longer necessary to register files to use
-this feature. 5.11 also allows using this as non-root, if the user has the
-.B CAP_SYS_NICE
-capability. In 5.13 this requirement was also relaxed, and no special privileges
-are needed for SQPOLL in newer kernels. Certain stable kernels older than 5.13
-may also support unprivileged SQPOLL.
-.TP
-.B IORING_SETUP_SQ_AFF
-If this flag is specified, then the poll thread will be bound to the
-cpu set in the
-.I sq_thread_cpu
-field of the
-.IR "struct io_uring_params" .
-This flag is only meaningful when
-.B IORING_SETUP_SQPOLL
-is specified. When cgroup setting
-.I cpuset.cpus
-changes (typically in container environment), the bounded cpu set may be
-changed as well.
-.TP
-.B IORING_SETUP_CQSIZE
-Create the completion queue with
-.I "struct io_uring_params.cq_entries"
-entries. The value must be greater than
-.IR entries ,
-and may be rounded up to the next power-of-two.
-.TP
-.B IORING_SETUP_CLAMP
-If this flag is specified, and if
-.IR entries
-exceeds
-.BR IORING_MAX_ENTRIES ,
-then
-.I entries
-will be clamped at
-.BR IORING_MAX_ENTRIES .
-If the flag
-.B IORING_SETUP_CQSIZE
-is set, and if the value of
-.I "struct io_uring_params.cq_entries"
-exceeds
-.BR IORING_MAX_CQ_ENTRIES ,
-then it will be clamped at
-.BR IORING_MAX_CQ_ENTRIES .
-.TP
-.B IORING_SETUP_ATTACH_WQ
-This flag should be set in conjunction with
-.I "struct io_uring_params.wq_fd"
-being set to an existing io_uring ring file descriptor. When set, the
-io_uring instance being created will share the asynchronous worker
-thread backend of the specified io_uring ring, rather than create a new
-separate thread pool. Additionally the sq polling thread will be shared,
-if
-.B IORING_SETUP_SQPOLL
-is set.
-.TP
-.B IORING_SETUP_R_DISABLED
-If this flag is specified, the io_uring ring starts in a disabled state.
-In this state, restrictions can be registered, but submissions are not allowed.
-See
-.BR io_uring_register (2)
-for details on how to enable the ring. Available since 5.10.
-.TP
-.B IORING_SETUP_SUBMIT_ALL
-Normally io_uring stops submitting a batch of requests, if one of these requests
-results in an error. This can cause submission of less than what is expected,
-if a request ends in error while being submitted. If the ring is created with
-this flag,
-.BR io_uring_enter (2)
-will continue submitting requests even if it encounters an error submitting
-a request. CQEs are still posted for errored request regardless of whether or
-not this flag is set at ring creation time, the only difference is if the
-submit sequence is halted or continued when an error is observed. Available
-since 5.18.
-.TP
-.B IORING_SETUP_COOP_TASKRUN
-By default, io_uring will interrupt a task running in userspace when a
-completion event comes in. This is to ensure that completions run in a timely
-manner. For a lot of use cases, this is overkill and can cause reduced
-performance from both the inter-processor interrupt used to do this, the
-kernel/user transition, the needless interruption of the tasks userspace
-activities, and reduced batching if completions come in at a rapid rate. Most
-applications don't need the forceful interruption, as the events are processed
-at any kernel/user transition. The exception are setups where the application
-uses multiple threads operating on the same ring, where the application
-waiting on completions isn't the one that submitted them. For most other
-use cases, setting this flag will improve performance. Available since 5.19.
-.TP
-.B IORING_SETUP_TASKRUN_FLAG
-Used in conjunction with
-.BR IORING_SETUP_COOP_TASKRUN
-or
-.BR IORING_SETUP_DEFER_TASKRUN ,
-this provides a flag,
-.BR IORING_SQ_TASKRUN ,
-which is set in the SQ ring
-.I flags
-whenever completions are pending that should be processed. liburing will check
-for this flag even when doing
-.BR io_uring_peek_cqe (3)
-and enter the kernel to process them, and applications can do the same. This
-makes
-.B IORING_SETUP_TASKRUN_FLAG
-safe to use even when applications rely on a peek style operation on the CQ
-ring to see if anything might be pending to reap. Available since 5.19.
-.TP
-.B IORING_SETUP_SQE128
-If set, io_uring will use 128-byte SQEs rather than the normal 64-byte sized
-variant. This is a requirement for using certain request types, as of 5.19
-only the
-.B IORING_OP_URING_CMD
-passthrough command for NVMe passthrough needs this. Available since 5.19.
-.TP
-.B IORING_SETUP_CQE32
-If set, io_uring will use 32-byte CQEs rather than the normal 16-byte sized
-variant. This is a requirement for using certain request types, as of 5.19
-only the
-.B IORING_OP_URING_CMD
-passthrough command for NVMe passthrough needs this. Also see
-.B IORING_SETUP_CQE_MIXED
-for an alternative to this flag. Available since 5.19.
-.TP
-.B IORING_SETUP_SINGLE_ISSUER
-A hint to the kernel that only a single task (or thread) will submit requests, which is
-used for internal optimisations. The submission task is either the task that created the
-ring, or if
-.B IORING_SETUP_R_DISABLED
-is specified then it is the task that enables the ring through
-.BR io_uring_register (2) .
-The kernel enforces this rule, failing requests with
-.B -EEXIST
-if the restriction is violated.
-Note that when
-.B IORING_SETUP_SQPOLL
-is set it is considered that the polling task is doing all submissions
-on behalf of the userspace and so it always complies with the rule disregarding
-how many userspace tasks do
-.BR io_uring_enter (2).
-Available since 6.0.
-.TP
-.B IORING_SETUP_DEFER_TASKRUN
-By default, io_uring will process all outstanding work at the end of any system
-call or thread interrupt. This can delay the application from making other progress.
-Setting this flag will hint to io_uring that it should defer work until an
-.BR io_uring_enter (2)
-call with the
-.B IORING_ENTER_GETEVENTS
-flag set. This allows the application to request work to run just before it wants to
-process completions.
-This flag requires the
-.B IORING_SETUP_SINGLE_ISSUER
-flag to be set, and also enforces that the call to
-.BR io_uring_enter (2)
-is called from the same thread that submitted requests.
-Note that if this flag is set then it is the application's responsibility to periodically
-trigger work (for example via any of the CQE waiting functions) or else completions may
-not be delivered.
-Available since 6.1.
-.TP
-.B IORING_SETUP_NO_MMAP
-By default, io_uring allocates kernel memory that callers must subsequently
-.BR mmap (2).
-If this flag is set, io_uring instead uses caller-allocated buffers;
-.I p->cq_off.user_addr
-must point to the memory for the sq/cq rings, and
-.I p->sq_off.user_addr
-must point to the memory for the sqes.
-Each allocation must be contiguous memory.
-Typically, callers should allocate this memory by using
-.BR mmap (2)
-to allocate a huge page.
-If this flag is set, a subsequent attempt to
-.BR mmap (2)
-the io_uring file descriptor will fail.
-Available since 6.5.
-.TP
-.B IORING_SETUP_REGISTERED_FD_ONLY
-If this flag is set, io_uring will register the ring file descriptor, and
-return the registered descriptor index, without ever allocating an unregistered
-file descriptor. The caller will need to use
-.B IORING_REGISTER_USE_REGISTERED_RING
-when calling
-.BR io_uring_register (2).
-This flag only makes sense when used alongside with
-.BR IORING_SETUP_NO_MMAP ,
-which also needs to be set.
-Available since 6.5.
-
-.TP
-.B IORING_SETUP_NO_SQARRAY
-If this flag is set, entries in the submission queue will be submitted in order,
-wrapping around to the first entry after reaching the end of the queue. In other
-words, there will be no more indirection via the array of submission entries,
-and the queue will be indexed directly by the submission queue tail and the
-range of indexed represented by it modulo queue size. Subsequently, the user
-should not map the array of submission queue entries, and the corresponding
-offset in
-.I struct io_sqring_offsets
-will be set to zero. Available since 6.6.
-
-.TP
-.B IORING_SETUP_CQE_MIXED
-If this flag is set, the ring supports posting both the normal 16b sized CQEs
-as well as the larger 32b CQEs. Normally a ring is setup to only allow posting
-of normal 16b CQEs, or if
-.B IORING_SETUP_CQE32
-has been set, only 32b CQEs. With this flag, the kernel may post both types.
-If a 32b CQE is posted, the CQE
-.I flags
-member will have
-.B IORING_CQE_F_32
-set to indicate that this CQE is of the larger type. The kernel may also set
-.B IORING_CQE_F_SKIP
-in the CQE
-.I flags
-member, in case it needs to post a filler 16b CQE. This will happen if a 32b
-CQE needs posting and the current CQ ring offset is such that the 32b CQE
-would wrap around. Applications should simply skip/ignore such CQEs, they
-contain no information and serve only as placeholder to facilitate advancing
-the CQ ring such that a large CQE can get posted. The use case of the
-.B IORING_SETUP_CQE_MIXED
-flag is to allow more efficient setups of workloads that may post both normal
-and large CQEs. Opcodes that previously required the use of
-.B IORING_SETUP_CQE32
-may now use this flag instead, and potentially save some memory for the CQ
-ring. If used with liburing 2.12 or newer, the handling of variably sized CQEs
-is fully transparent. Available since 6.18.
-
-.TP
-.B IORING_SETUP_SQ_REWIND
-If this flag is set, the kernel ignores the submission queue head and tail
-and instead fetches SQEs starting from index 0. The application places all
-SQEs at the beginning of the SQ ring before each submit call, and the
-.I sq_entries
-parameter to
-.BR io_uring_enter (2)
-determines how many SQEs are submitted. This is a non-circular queue mode
-where the kernel always starts from the beginning.
-.PP
-This flag requires
-.B IORING_SETUP_NO_SQARRAY
-to be set. It is not compatible with
-.BR IORING_SETUP_SQPOLL .
-.PP
-This mode helps keep SQEs hot in cache by always accessing the same memory
-locations at the start of the ring, which can improve performance for
-workloads that submit small batches frequently.
-Available since 7.0.
-
-.PP
-If no flags are specified, the io_uring instance is setup for
-interrupt driven I/O. I/O may be submitted using
-.BR io_uring_enter (2)
-and can be reaped by polling the completion queue.
-
-The
-.I resv
-array must be initialized to zero.
-
-.I features
-is filled in by the kernel, which specifies various features supported
-by current kernel version.
-.TP
-.B IORING_FEAT_SINGLE_MMAP
-If this flag is set, the two SQ and CQ rings can be mapped with a single
-.BR mmap (2)
-call. The SQEs must still be allocated separately. This brings the necessary
-.BR mmap (2)
-calls down from three to two. Available since kernel 5.4.
-.TP
-.B IORING_FEAT_NODROP
-If this flag is set, io_uring supports almost never dropping completion events.
-A dropped event can only occur if the kernel runs out of memory, in which case
-you have worse problems than a lost event. Your application and others will
-likely get OOM killed anyway. If a completion event occurs and the CQ ring is
-full, the kernel stores the event internally until such a time that the CQ ring
-has room for more entries. In earlier kernels, if this overflow condition is
-entered, attempting to submit more IO would fail with the
-.B -EBUSY
-error value, if it can't flush the overflown events to the CQ ring. If this
-happens, the application must reap events from the CQ ring and attempt the
-submit again. If the kernel has no free memory to store the event internally
-it will be visible by an increase in the overflow value on the cqring.
-Available since kernel 5.5. Additionally
-.BR io_uring_enter (2)
-will return
-.B -EBADR
-the next time it would otherwise sleep waiting for completions (since kernel 5.19).
-
-.TP
-.B IORING_FEAT_SUBMIT_STABLE
-If this flag is set, applications can be certain that any data for
-async offload has been consumed when the kernel has consumed the SQE. Available
-since kernel 5.5.
-.TP
-.B IORING_FEAT_RW_CUR_POS
-If this flag is set, applications can specify
-.I offset
-==
-.B -1
-with
-.BR IORING_OP_{READV,WRITEV} ,
-.BR IORING_OP_{READ,WRITE}_FIXED ,
-and
-.B IORING_OP_{READ,WRITE}
-to mean current file position, which behaves like
-.BR preadv2 (2)
-and
-.BR pwritev2 (2)
-with
-.I offset
-==
-.BR -1 .
-It'll use (and update) the current file position. This obviously comes
-with the caveat that if the application has multiple reads or writes in flight,
-then the end result will not be as expected. This is similar to threads sharing
-a file descriptor and doing IO using the current file position. Available since
-kernel 5.6.
-.TP
-.B IORING_FEAT_CUR_PERSONALITY
-If this flag is set, then io_uring guarantees that both sync and async
-execution of a request assumes the credentials of the task that called
-.BR io_uring_enter (2)
-to queue the requests. If this flag isn't set, then requests are issued with
-the credentials of the task that originally registered the io_uring. If only
-one task is using a ring, then this flag doesn't matter as the credentials
-will always be the same. Note that this is the default behavior, tasks can
-still register different personalities through
-.BR io_uring_register (2)
-with
-.B IORING_REGISTER_PERSONALITY
-and specify the personality to use in the sqe. Available since kernel 5.6.
-.TP
-.B IORING_FEAT_FAST_POLL
-If this flag is set, then io_uring supports using an internal poll mechanism
-to drive data/space readiness. This means that requests that cannot read or
-write data to a file no longer need to be punted to an async thread for
-handling, instead they will begin operation when the file is ready. This is
-similar to doing poll + read/write in userspace, but eliminates the need to do
-so. If this flag is set, requests waiting on space/data consume a lot less
-resources doing so as they are not blocking a thread. Available since kernel
-5.7.
-.TP
-.B IORING_FEAT_POLL_32BITS
-If this flag is set, the
-.B IORING_OP_POLL_ADD
-command accepts the full 32-bit range of epoll based flags. Most notably
-.B EPOLLEXCLUSIVE
-which allows exclusive (waking single waiters) behavior. Available since kernel
-5.9.
-.TP
-.B IORING_FEAT_SQPOLL_NONFIXED
-If this flag is set, the
-.B IORING_SETUP_SQPOLL
-feature no longer requires the use of fixed files. Any normal file descriptor
-can be used for IO commands without needing registration. Available since
-kernel 5.11.
-.TP
-.B IORING_FEAT_EXT_ARG
-If this flag is set, then the
-.BR io_uring_enter (2)
-system call supports passing in an extended argument instead of just the
-.I "sigset_t"
-of earlier kernels. This extended argument is of type
-.I "struct io_uring_getevents_arg"
-and allows the caller to pass in both a
-.I sigset_t
-and a timeout argument for waiting on events. The struct layout is as follows:
-.TP
-.in +8n
-.EX
-struct io_uring_getevents_arg {
- __u64 sigmask;
- __u32 sigmask_sz;
- __u32 pad;
- __u64 ts;
-};
-.EE
-
-and a pointer to this struct must be passed in if
-.B IORING_ENTER_EXT_ARG
-is set in the flags for the enter system call. Available since kernel 5.11.
-.TP
-.B IORING_FEAT_NATIVE_WORKERS
-If this flag is set, io_uring is using native workers for its async helpers.
-Previous kernels used kernel threads that assumed the identity of the
-original io_uring owning task, but later kernels will actively create what
-looks more like regular process threads instead. Available since kernel
-5.12.
-.TP
-.B IORING_FEAT_RSRC_TAGS
-If this flag is set, then io_uring supports a variety of features related
-to fixed files and buffers. In particular, it indicates that registered
-buffers can be updated in-place, whereas before the full set would have to
-be unregistered first. Available since kernel 5.13.
-.TP
-.B IORING_FEAT_CQE_SKIP
-If this flag is set, then io_uring supports setting
-.B IOSQE_CQE_SKIP_SUCCESS
-in the submitted SQE, indicating that no CQE should be generated for this
-SQE if it executes normally. If an error happens processing the SQE, a
-CQE with the appropriate error value will still be generated. Available since
-kernel 5.17.
-.TP
-.B IORING_FEAT_LINKED_FILE
-If this flag is set, then io_uring supports sane assignment of files for SQEs
-that have dependencies. For example, if a chain of SQEs are submitted with
-.BR IOSQE_IO_LINK ,
-then kernels without this flag will prepare the file for each link upfront.
-If a previous link opens a file with a known index, e.g. if direct descriptors
-are used with open or accept, then file assignment needs to happen post
-execution of that SQE. If this flag is set, then the kernel will defer
-file assignment until execution of a given request is started. Available since
-kernel 5.17.
-.TP
-.B IORING_FEAT_REG_REG_RING
-If this flag is set, then io_uring supports calling
-.BR io_uring_register (2)
-using a registered ring fd, via
-.BR IORING_REGISTER_USE_REGISTERED_RING .
-Available since kernel 6.3.
-.TP
-.B IORING_FEAT_MIN_TIMEOUT
-If this flag is set, then io_uring supports passing in a minimum batch wait
-timeout. See
-.BR io_uring_submit_and_wait_min_timeout (3)
-for more details.
-
-.TP
-.B IORING_FEAT_RECVSEND_BUNDLE
-If this flag is set, then io_uring supports bundled send and recv operations.
-See
-.BR io_uring_prep_send_bundle (3)
-for more information. Also implies support for provided buffers in send
-operations.
-.PP
-The rest of the fields in the
-.I struct io_uring_params
-are filled in by the kernel, and provide the information necessary to
-memory map the submission queue, completion queue, and the array of
-submission queue entries.
-.I sq_entries
-specifies the number of submission queue entries allocated.
-.I sq_off
-describes the offsets of various ring buffer fields:
-.PP
-.in +4n
-.EX
-struct io_sqring_offsets {
- __u32 head;
- __u32 tail;
- __u32 ring_mask;
- __u32 ring_entries;
- __u32 flags;
- __u32 dropped;
- __u32 array;
- __u32 resv1;
- __u64 user_addr;
-};
-.EE
-.in
-.PP
-Taken together,
-.I sq_entries
-and
-.I sq_off
-provide all of the information necessary for accessing the submission
-queue ring buffer and the submission queue entry array. The submission queue can
-be mapped with a call like:
-.PP
-.in +4n
-.EX
-ptr = mmap(0, sq_off.array + sq_entries * sizeof(__u32),
- PROT_READ|PROT_WRITE, MAP_SHARED|MAP_POPULATE,
- ring_fd, IORING_OFF_SQ_RING);
-.EE
-.in
-.PP
-where
-.I sq_off
-is the
-.I io_sqring_offsets
-structure, and
-.I ring_fd
-is the file descriptor returned from
-.BR io_uring_setup (2).
-The addition of
-.I sq_off.array
-to the length of the region accounts for the fact that the ring is
-located at the end of the data structure. As an example, the ring
-buffer head pointer can be accessed by adding
-.I sq_off.head
-to the address returned from
-.BR mmap (2):
-.PP
-.in +4n
-.EX
-head = ptr + sq_off.head;
-.EE
-.in
-
-The
-.I flags
-field is used by the kernel to communicate state information to the
-application. Currently, it is used to inform the application when a
-call to
-.BR io_uring_enter (2)
-is necessary. See the documentation for the
-.B IORING_SETUP_SQPOLL
-flag above.
-The
-.I dropped
-member is incremented for each invalid submission queue entry
-encountered in the ring buffer.
-
-The head and tail track the ring buffer state. The tail is
-incremented by the application when submitting new I/O, and the head
-is incremented by the kernel when the I/O has been successfully
-submitted. Determining the index of the head or tail into the ring is
-accomplished by applying a mask:
-.PP
-.in +4n
-.EX
-index = tail & ring_mask;
-.EE
-.in
-.PP
-The array of submission queue entries is mapped with:
-.PP
-.in +4n
-.EX
-sqentries = mmap(0, sq_entries * sizeof(struct io_uring_sqe),
- PROT_READ|PROT_WRITE, MAP_SHARED|MAP_POPULATE,
- ring_fd, IORING_OFF_SQES);
-.EE
-.in
-.PP
-The completion queue is described by
-.I cq_entries
-and
-.I cq_off
-shown here:
-.PP
-.in +4n
-.EX
-struct io_cqring_offsets {
- __u32 head;
- __u32 tail;
- __u32 ring_mask;
- __u32 ring_entries;
- __u32 overflow;
- __u32 cqes;
- __u32 flags;
- __u32 resv1;
- __u64 user_addr;
-};
-.EE
-.in
-.PP
-The completion queue is simpler, since the entries are not separated
-from the queue itself, and can be mapped with:
-.PP
-.in +4n
-.EX
-ptr = mmap(0, cq_off.cqes + cq_entries * sizeof(struct io_uring_cqe),
- PROT_READ|PROT_WRITE, MAP_SHARED|MAP_POPULATE, ring_fd,
- IORING_OFF_CQ_RING);
-.EE
-.in
-.PP
-Closing the file descriptor returned by
-.BR io_uring_setup (2)
-will free all resources associated with the io_uring context. Note that this
-may happen asynchronously within the kernel, so it is not guaranteed that
-resources are freed immediately.
-.PP
-.SH RETURN VALUE
-.BR io_uring_setup (2)
-returns a new file descriptor on success. The application may then
-provide the file descriptor in a subsequent
-.BR mmap (2)
-call to map the submission and completion queues, or to the
-.BR io_uring_register (2)
-or
-.BR io_uring_enter (2)
-system calls.
-
-On error, a negative error code is returned. The caller should not rely on
-.I errno
-variable.
-.PP
-.SH ERRORS
-.TP
-.B EFAULT
-.I params
-is outside your accessible address space.
-.TP
-.B EINVAL
-The resv array contains non-zero data, p.flags contains an unsupported
-flag,
-.I entries
-is out of bounds,
-.B IORING_SETUP_SQ_AFF
-was specified, but
-.B IORING_SETUP_SQPOLL
-was not, or
-.B IORING_SETUP_CQSIZE
-was specified, but
-.I io_uring_params.cq_entries
-was invalid.
-.B IORING_SETUP_REGISTERED_FD_ONLY
-was specified, but
-.B IORING_SETUP_NO_MMAP
-was not.
-.TP
-.B EMFILE
-The per-process limit on the number of open file descriptors has been
-reached (see the description of
-.B RLIMIT_NOFILE
-in
-.BR getrlimit (2)).
-.TP
-.B ENFILE
-The system-wide limit on the total number of open files has been
-reached.
-.TP
-.B ENOMEM
-Insufficient kernel resources are available.
-.TP
-.B EPERM
-.B IORING_SETUP_SQPOLL
-was specified, but the effective user ID of the caller did not have sufficient
-privileges.
-.TP
-.B EPERM
-.I /proc/sys/kernel/io_uring_disabled
-has the value 2, or it has the value 1 and the calling process does not hold the
-.B CAP_SYS_ADMIN
-capability or is not a member of
-.IR /proc/sys/kernel/io_uring_group .
-.TP
-.B ENXIO
-.B IORING_SETUP_ATTACH_WQ
-was set, but
-.I params.wq_fd
-did not refer to an io_uring instance or refers to an instance that is in the
-process of shutting down.
-.SH SEE ALSO
-.BR io_uring_register (2),
-.BR io_uring_enter (2)
diff --git a/man/io_uring_setup.2.md b/man/io_uring_setup.2.md
new file mode 100644
index 00000000..2af88160
--- /dev/null
+++ b/man/io_uring_setup.2.md
@@ -0,0 +1,334 @@
+.\" Copyright (C) 2019 Jens Axboe <axboe@kernel.dk>
+.\" Copyright (C) 2019 Jon Corbet <corbet@lwn.net>
+.\" Copyright (C) 2019 Red Hat, Inc.
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 29, 2019
+footer: Linux
+header: Linux Programmer\'s Manual
+section: 2
+title: io_uring_setup
+---
+
+# NAME
+
+io_uring_setup - setup a context for performing asynchronous I/O
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_setup(u32 entries , struct io_uring_params * params );
+
+# DESCRIPTION
+
+The **io_uring_setup**(2) system call sets up a submission queue (SQ) and completion queue (CQ) with at least *entries* entries, and returns a file descriptor which can be used to perform subsequent operations on the io_uring instance. The submission and completion queues are shared between userspace and the kernel, which eliminates the need to copy data when initiating and completing I/O.
+
+*params* is used by the application to pass options to the kernel, and by the kernel to convey information about the ring buffers.
+
+ struct io_uring_params {
+ __u32 sq_entries;
+ __u32 cq_entries;
+ __u32 flags;
+ __u32 sq_thread_cpu;
+ __u32 sq_thread_idle;
+ __u32 features;
+ __u32 wq_fd;
+ __u32 resv[3];
+ struct io_sqring_offsets sq_off;
+ struct io_cqring_offsets cq_off;
+ };
+
+The *flags*, *sq_thread_cpu*, and *sq_thread_idle* fields are used to configure the io_uring instance. *flags* is a bit mask of 0 or more of the following values ORed together:
+
+**IORING_SETUP_IOPOLL**
+
+: Perform busy-waiting for an I/O completion, as opposed to getting notifications via an asynchronous IRQ (Interrupt Request). The file system (if any) and block device must support polling in order for this to work. Busy-waiting provides lower latency, but may consume more CPU resources than interrupt driven I/O. Currently, this feature is usable only on a file descriptor opened using the **O_DIRECT** flag (if using the **IORING_OP\_{READ,WRITE}(V)(\_FIXED)** opcodes). When a read or write is submitted to a polled context, the application must poll for completions on the CQ ring by calling **io_uring_enter**(2). Most non-polled I/O requests are forbidden on **IORING_SETUP_IOPOLL** io_uring instances (see **io_uring_setup_flags**(7) for the allowed opcodes).
+
+ This is only applicable for storage devices for now, and the storage device must be configured for polling. How to do that depends on the device type in question. For NVMe devices, the nvme driver must be loaded with the *poll_queues* parameter set to the desired number of polling queues. The polling queues will be shared appropriately between the CPUs in the system, if the number is less than the number of online CPU threads.
+
+**IORING_SETUP_HYBRID_IOPOLL**
+
+: This flag must be used with **IORING_SETUP_IOPOLL** flag. Hybrid io polling is a feature based on iopoll, it differs from strict polling in that it will delay a bit before doing completion side polling, to avoid wasting too much CPU resources. Like **IOPOLL** , it requires that devices support polling.
+
+**IORING_SETUP_SQPOLL**
+
+: When this flag is specified, a kernel thread is created to perform submission queue polling. An io_uring instance configured in this way enables an application to issue I/O without ever context switching into the kernel. By using the submission queue to fill in new submission queue entries and watching for completions on the completion queue, the application can submit and reap I/Os without doing a single system call.
+
+ If the kernel thread is idle for more than *sq_thread_idle* milliseconds, it will set the **IORING_SQ_NEED_WAKEUP** bit in the *flags* field of the *struct io_sq_ring*. When this happens, the application must call **io_uring_enter**(2) to wake the kernel thread. If I/O is kept busy, the kernel thread will never sleep. An application making use of this feature will need to guard the **io_uring_enter**(2) call with the following code sequence:
+
+ /*
+ * Ensure that the wakeup flag is read after the tail pointer
+ * has been written. It's important to use memory load acquire
+ * semantics for the flags read, as otherwise the application
+ * and the kernel might not agree on the consistency of the
+ * wakeup flag.
+ */
+ unsigned flags = atomic_load_relaxed(sq_ring->flags);
+ if (flags & IORING_SQ_NEED_WAKEUP)
+ io_uring_enter(fd, 0, 0, IORING_ENTER_SQ_WAKEUP);
+
+ where *sq_ring* is a submission queue ring setup using the *struct io_sqring_offsets* described below.
+
+: Note that, when using a ring setup with **IORING_SETUP_SQPOLL**, you never directly call the **io_uring_enter**(2) system call. That is usually taken care of by liburing\'s **io_uring_submit**(3) function. It automatically determines if you are using polling mode or not and deals with when your program needs to call **io_uring_enter**(2) without you having to bother about it.
+
+: Note that while this may sound immediately appealing as an automatic \"go faster\" flag, evaluations should be done on a case-by-case basis to check if it makes sense for the application.
+
+: Before version 5.11 of the Linux kernel, to successfully use this feature, the application must register a set of files to be used for IO through **io_uring_register**(2) using the **IORING_REGISTER_FILES** opcode. Failure to do so will result in submitted IO being errored with **EBADF**. The presence of this feature can be detected by the **IORING_FEAT_SQPOLL_NONFIXED** feature flag. In version 5.11 and later, it is no longer necessary to register files to use this feature. 5.11 also allows using this as non-root, if the user has the **CAP_SYS_NICE** capability. In 5.13 this requirement was also relaxed, and no special privileges are needed for SQPOLL in newer kernels. Certain stable kernels older than 5.13 may also support unprivileged SQPOLL.
+
+**IORING_SETUP_SQ_AFF**
+
+: If this flag is specified, then the poll thread will be bound to the cpu set in the *sq_thread_cpu* field of the *struct io_uring_params*. This flag is only meaningful when **IORING_SETUP_SQPOLL** is specified. When cgroup setting *cpuset.cpus* changes (typically in container environment), the bounded cpu set may be changed as well.
+
+**IORING_SETUP_CQSIZE**
+
+: Create the completion queue with *struct io_uring_params.cq_entries* entries. The value must be greater than *entries*, and may be rounded up to the next power-of-two.
+
+**IORING_SETUP_CLAMP**
+
+: If this flag is specified, and if *entries* exceeds **IORING_MAX_ENTRIES**, then *entries* will be clamped at **IORING_MAX_ENTRIES**. If the flag **IORING_SETUP_CQSIZE** is set, and if the value of *struct io_uring_params.cq_entries* exceeds **IORING_MAX_CQ_ENTRIES**, then it will be clamped at **IORING_MAX_CQ_ENTRIES**.
+
+**IORING_SETUP_ATTACH_WQ**
+
+: This flag should be set in conjunction with *struct io_uring_params.wq_fd* being set to an existing io_uring ring file descriptor. When set, the io_uring instance being created will share the asynchronous worker thread backend of the specified io_uring ring, rather than create a new separate thread pool. Additionally the sq polling thread will be shared, if **IORING_SETUP_SQPOLL** is set.
+
+**IORING_SETUP_R_DISABLED**
+
+: If this flag is specified, the io_uring ring starts in a disabled state. In this state, restrictions can be registered, but submissions are not allowed. See **io_uring_register**(2) for details on how to enable the ring. Available since 5.10.
+
+**IORING_SETUP_SUBMIT_ALL**
+
+: Normally io_uring stops submitting a batch of requests, if one of these requests results in an error. This can cause submission of less than what is expected, if a request ends in error while being submitted. If the ring is created with this flag, **io_uring_enter**(2) will continue submitting requests even if it encounters an error submitting a request. CQEs are still posted for errored request regardless of whether or not this flag is set at ring creation time, the only difference is if the submit sequence is halted or continued when an error is observed. Available since 5.18.
+
+**IORING_SETUP_COOP_TASKRUN**
+
+: By default, io_uring will interrupt a task running in userspace when a completion event comes in. This is to ensure that completions run in a timely manner. For a lot of use cases, this is overkill and can cause reduced performance from both the inter-processor interrupt used to do this, the kernel/user transition, the needless interruption of the tasks userspace activities, and reduced batching if completions come in at a rapid rate. Most applications don\'t need the forceful interruption, as the events are processed at any kernel/user transition. The exception are setups where the application uses multiple threads operating on the same ring, where the application waiting on completions isn\'t the one that submitted them. For most other use cases, setting this flag will improve performance. Available since 5.19.
+
+**IORING_SETUP_TASKRUN_FLAG**
+
+: Used in conjunction with **IORING_SETUP_COOP_TASKRUN** or **IORING_SETUP_DEFER_TASKRUN**, this provides a flag, **IORING_SQ_TASKRUN**, which is set in the SQ ring *flags* whenever completions are pending that should be processed. liburing will check for this flag even when doing **io_uring_peek_cqe**(3) and enter the kernel to process them, and applications can do the same. This makes **IORING_SETUP_TASKRUN_FLAG** safe to use even when applications rely on a peek style operation on the CQ ring to see if anything might be pending to reap. Available since 5.19.
+
+**IORING_SETUP_SQE128**
+
+: If set, io_uring will use 128-byte SQEs rather than the normal 64-byte sized variant. This is a requirement for using certain request types, as of 5.19 only the **IORING_OP_URING_CMD** passthrough command for NVMe passthrough needs this. Available since 5.19.
+
+**IORING_SETUP_CQE32**
+
+: If set, io_uring will use 32-byte CQEs rather than the normal 16-byte sized variant. This is a requirement for using certain request types, as of 5.19 only the **IORING_OP_URING_CMD** passthrough command for NVMe passthrough needs this. Also see **IORING_SETUP_CQE_MIXED** for an alternative to this flag. Available since 5.19.
+
+**IORING_SETUP_SINGLE_ISSUER**
+
+: A hint to the kernel that only a single task (or thread) will submit requests, which is used for internal optimisations. The submission task is either the task that created the ring, or if **IORING_SETUP_R_DISABLED** is specified then it is the task that enables the ring through **io_uring_register**(2)**.** The kernel enforces this rule, failing requests with **-EEXIST** if the restriction is violated. Note that when **IORING_SETUP_SQPOLL** is set it is considered that the polling task is doing all submissions on behalf of the userspace and so it always complies with the rule disregarding how many userspace tasks do **io_uring_enter**(2). Available since 6.0.
+
+**IORING_SETUP_DEFER_TASKRUN**
+
+: By default, io_uring will process all outstanding work at the end of any system call or thread interrupt. This can delay the application from making other progress. Setting this flag will hint to io_uring that it should defer work until an **io_uring_enter**(2) call with the **IORING_ENTER_GETEVENTS** flag set. This allows the application to request work to run just before it wants to process completions. This flag requires the **IORING_SETUP_SINGLE_ISSUER** flag to be set, and also enforces that the call to **io_uring_enter**(2) is called from the same thread that submitted requests. Note that if this flag is set then it is the application\'s responsibility to periodically trigger work (for example via any of the CQE waiting functions) or else completions may not be delivered. Available since 6.1.
+
+**IORING_SETUP_NO_MMAP**
+
+: By default, io_uring allocates kernel memory that callers must subsequently **mmap**(2). If this flag is set, io_uring instead uses caller-allocated buffers; *p-\>cq_off.user_addr* must point to the memory for the sq/cq rings, and *p-\>sq_off.user_addr* must point to the memory for the sqes. Each allocation must be contiguous memory. Typically, callers should allocate this memory by using **mmap**(2) to allocate a huge page. If this flag is set, a subsequent attempt to **mmap**(2) the io_uring file descriptor will fail. Available since 6.5.
+
+**IORING_SETUP_REGISTERED_FD_ONLY**
+
+: If this flag is set, io_uring will register the ring file descriptor, and return the registered descriptor index, without ever allocating an unregistered file descriptor. The caller will need to use **IORING_REGISTER_USE_REGISTERED_RING** when calling **io_uring_register**(2). This flag only makes sense when used alongside with **IORING_SETUP_NO_MMAP**, which also needs to be set. Available since 6.5.
+
+**IORING_SETUP_NO_SQARRAY**
+
+: If this flag is set, entries in the submission queue will be submitted in order, wrapping around to the first entry after reaching the end of the queue. In other words, there will be no more indirection via the array of submission entries, and the queue will be indexed directly by the submission queue tail and the range of indexed represented by it modulo queue size. Subsequently, the user should not map the array of submission queue entries, and the corresponding offset in *struct io_sqring_offsets* will be set to zero. Available since 6.6.
+
+**IORING_SETUP_CQE_MIXED**
+
+: If this flag is set, the ring supports posting both the normal 16b sized CQEs as well as the larger 32b CQEs. Normally a ring is setup to only allow posting of normal 16b CQEs, or if **IORING_SETUP_CQE32** has been set, only 32b CQEs. With this flag, the kernel may post both types. If a 32b CQE is posted, the CQE *flags* member will have **IORING_CQE_F_32** set to indicate that this CQE is of the larger type. The kernel may also set **IORING_CQE_F_SKIP** in the CQE *flags* member, in case it needs to post a filler 16b CQE. This will happen if a 32b CQE needs posting and the current CQ ring offset is such that the 32b CQE would wrap around. Applications should simply skip/ignore such CQEs, they contain no information and serve only as placeholder to facilitate advancing the CQ ring such that a large CQE can get posted. The use case of the **IORING_SETUP_CQE_MIXED** flag is to allow more efficient setups of workloads that may post both normal and large CQEs. Opcodes that previously required the use of **IORING_SETUP_CQE32** may now use this flag instead, and potentially save some memory for the CQ ring. If used with liburing 2.12 or newer, the handling of variably sized CQEs is fully transparent. Available since 6.18.
+
+**IORING_SETUP_SQ_REWIND**
+
+: If this flag is set, the kernel ignores the submission queue head and tail and instead fetches SQEs starting from index 0. The application places all SQEs at the beginning of the SQ ring before each submit call, and the *sq_entries* parameter to **io_uring_enter**(2) determines how many SQEs are submitted. This is a non-circular queue mode where the kernel always starts from the beginning.
+
+This flag requires **IORING_SETUP_NO_SQARRAY** to be set. It is not compatible with **IORING_SETUP_SQPOLL**.
+
+This mode helps keep SQEs hot in cache by always accessing the same memory locations at the start of the ring, which can improve performance for workloads that submit small batches frequently. Available since 7.0.
+
+If no flags are specified, the io_uring instance is setup for interrupt driven I/O. I/O may be submitted using **io_uring_enter**(2) and can be reaped by polling the completion queue.
+
+The *resv* array must be initialized to zero.
+
+*features* is filled in by the kernel, which specifies various features supported by current kernel version.
+
+**IORING_FEAT_SINGLE_MMAP**
+
+: If this flag is set, the two SQ and CQ rings can be mapped with a single **mmap**(2) call. The SQEs must still be allocated separately. This brings the necessary **mmap**(2) calls down from three to two. Available since kernel 5.4.
+
+**IORING_FEAT_NODROP**
+
+: If this flag is set, io_uring supports almost never dropping completion events. A dropped event can only occur if the kernel runs out of memory, in which case you have worse problems than a lost event. Your application and others will likely get OOM killed anyway. If a completion event occurs and the CQ ring is full, the kernel stores the event internally until such a time that the CQ ring has room for more entries. In earlier kernels, if this overflow condition is entered, attempting to submit more IO would fail with the **-EBUSY** error value, if it can\'t flush the overflown events to the CQ ring. If this happens, the application must reap events from the CQ ring and attempt the submit again. If the kernel has no free memory to store the event internally it will be visible by an increase in the overflow value on the cqring. Available since kernel 5.5. Additionally **io_uring_enter**(2) will return **-EBADR** the next time it would otherwise sleep waiting for completions (since kernel 5.19).
+
+**IORING_FEAT_SUBMIT_STABLE**
+
+: If this flag is set, applications can be certain that any data for async offload has been consumed when the kernel has consumed the SQE. Available since kernel 5.5.
+
+**IORING_FEAT_RW_CUR_POS**
+
+: If this flag is set, applications can specify *offset* == **-1** with **IORING_OP\_{READV,WRITEV}**, **IORING_OP\_{READ,WRITE}\_FIXED**, and **IORING_OP\_{READ,WRITE}** to mean current file position, which behaves like **preadv2**(2) and **pwritev2**(2) with *offset* == **-1**. It\'ll use (and update) the current file position. This obviously comes with the caveat that if the application has multiple reads or writes in flight, then the end result will not be as expected. This is similar to threads sharing a file descriptor and doing IO using the current file position. Available since kernel 5.6.
+
+**IORING_FEAT_CUR_PERSONALITY**
+
+: If this flag is set, then io_uring guarantees that both sync and async execution of a request assumes the credentials of the task that called **io_uring_enter**(2) to queue the requests. If this flag isn\'t set, then requests are issued with the credentials of the task that originally registered the io_uring. If only one task is using a ring, then this flag doesn\'t matter as the credentials will always be the same. Note that this is the default behavior, tasks can still register different personalities through **io_uring_register**(2) with **IORING_REGISTER_PERSONALITY** and specify the personality to use in the sqe. Available since kernel 5.6.
+
+**IORING_FEAT_FAST_POLL**
+
+: If this flag is set, then io_uring supports using an internal poll mechanism to drive data/space readiness. This means that requests that cannot read or write data to a file no longer need to be punted to an async thread for handling, instead they will begin operation when the file is ready. This is similar to doing poll + read/write in userspace, but eliminates the need to do so. If this flag is set, requests waiting on space/data consume a lot less resources doing so as they are not blocking a thread. Available since kernel 5.7.
+
+**IORING_FEAT_POLL_32BITS**
+
+: If this flag is set, the **IORING_OP_POLL_ADD** command accepts the full 32-bit range of epoll based flags. Most notably **EPOLLEXCLUSIVE** which allows exclusive (waking single waiters) behavior. Available since kernel 5.9.
+
+**IORING_FEAT_SQPOLL_NONFIXED**
+
+: If this flag is set, the **IORING_SETUP_SQPOLL** feature no longer requires the use of fixed files. Any normal file descriptor can be used for IO commands without needing registration. Available since kernel 5.11.
+
+**IORING_FEAT_EXT_ARG**
+
+: If this flag is set, then the **io_uring_enter**(2) system call supports passing in an extended argument instead of just the *sigset_t* of earlier kernels. This extended argument is of type *struct io_uring_getevents_arg* and allows the caller to pass in both a *sigset_t* and a timeout argument for waiting on events. The struct layout is as follows:
+
+<!-- -->
+
+ struct io_uring_getevents_arg {
+ __u64 sigmask;
+ __u32 sigmask_sz;
+ __u32 pad;
+ __u64 ts;
+ };
+
+and a pointer to this struct must be passed in if **IORING_ENTER_EXT_ARG** is set in the flags for the enter system call. Available since kernel 5.11.
+
+**IORING_FEAT_NATIVE_WORKERS**
+
+: If this flag is set, io_uring is using native workers for its async helpers. Previous kernels used kernel threads that assumed the identity of the original io_uring owning task, but later kernels will actively create what looks more like regular process threads instead. Available since kernel 5.12.
+
+**IORING_FEAT_RSRC_TAGS**
+
+: If this flag is set, then io_uring supports a variety of features related to fixed files and buffers. In particular, it indicates that registered buffers can be updated in-place, whereas before the full set would have to be unregistered first. Available since kernel 5.13.
+
+**IORING_FEAT_CQE_SKIP**
+
+: If this flag is set, then io_uring supports setting **IOSQE_CQE_SKIP_SUCCESS** in the submitted SQE, indicating that no CQE should be generated for this SQE if it executes normally. If an error happens processing the SQE, a CQE with the appropriate error value will still be generated. Available since kernel 5.17.
+
+**IORING_FEAT_LINKED_FILE**
+
+: If this flag is set, then io_uring supports sane assignment of files for SQEs that have dependencies. For example, if a chain of SQEs are submitted with **IOSQE_IO_LINK**, then kernels without this flag will prepare the file for each link upfront. If a previous link opens a file with a known index, e.g. if direct descriptors are used with open or accept, then file assignment needs to happen post execution of that SQE. If this flag is set, then the kernel will defer file assignment until execution of a given request is started. Available since kernel 5.17.
+
+**IORING_FEAT_REG_REG_RING**
+
+: If this flag is set, then io_uring supports calling **io_uring_register**(2) using a registered ring fd, via **IORING_REGISTER_USE_REGISTERED_RING**. Available since kernel 6.3.
+
+**IORING_FEAT_MIN_TIMEOUT**
+
+: If this flag is set, then io_uring supports passing in a minimum batch wait timeout. See **io_uring_submit_and_wait_min_timeout**(3) for more details.
+
+**IORING_FEAT_RECVSEND_BUNDLE**
+
+: If this flag is set, then io_uring supports bundled send and recv operations. See **io_uring_prep_send_bundle**(3) for more information. Also implies support for provided buffers in send operations.
+
+The rest of the fields in the *struct io_uring_params* are filled in by the kernel, and provide the information necessary to memory map the submission queue, completion queue, and the array of submission queue entries. *sq_entries* specifies the number of submission queue entries allocated. *sq_off* describes the offsets of various ring buffer fields:
+
+ struct io_sqring_offsets {
+ __u32 head;
+ __u32 tail;
+ __u32 ring_mask;
+ __u32 ring_entries;
+ __u32 flags;
+ __u32 dropped;
+ __u32 array;
+ __u32 resv1;
+ __u64 user_addr;
+ };
+
+Taken together, *sq_entries* and *sq_off* provide all of the information necessary for accessing the submission queue ring buffer and the submission queue entry array. The submission queue can be mapped with a call like:
+
+ ptr = mmap(0, sq_off.array + sq_entries * sizeof(__u32),
+ PROT_READ|PROT_WRITE, MAP_SHARED|MAP_POPULATE,
+ ring_fd, IORING_OFF_SQ_RING);
+
+where *sq_off* is the *io_sqring_offsets* structure, and *ring_fd* is the file descriptor returned from **io_uring_setup**(2). The addition of *sq_off.array* to the length of the region accounts for the fact that the ring is located at the end of the data structure. As an example, the ring buffer head pointer can be accessed by adding *sq_off.head* to the address returned from **mmap**(2):
+
+ head = ptr + sq_off.head;
+
+The *flags* field is used by the kernel to communicate state information to the application. Currently, it is used to inform the application when a call to **io_uring_enter**(2) is necessary. See the documentation for the **IORING_SETUP_SQPOLL** flag above. The *dropped* member is incremented for each invalid submission queue entry encountered in the ring buffer.
+
+The head and tail track the ring buffer state. The tail is incremented by the application when submitting new I/O, and the head is incremented by the kernel when the I/O has been successfully submitted. Determining the index of the head or tail into the ring is accomplished by applying a mask:
+
+ index = tail & ring_mask;
+
+The array of submission queue entries is mapped with:
+
+ sqentries = mmap(0, sq_entries * sizeof(struct io_uring_sqe),
+ PROT_READ|PROT_WRITE, MAP_SHARED|MAP_POPULATE,
+ ring_fd, IORING_OFF_SQES);
+
+The completion queue is described by *cq_entries* and *cq_off* shown here:
+
+ struct io_cqring_offsets {
+ __u32 head;
+ __u32 tail;
+ __u32 ring_mask;
+ __u32 ring_entries;
+ __u32 overflow;
+ __u32 cqes;
+ __u32 flags;
+ __u32 resv1;
+ __u64 user_addr;
+ };
+
+The completion queue is simpler, since the entries are not separated from the queue itself, and can be mapped with:
+
+ ptr = mmap(0, cq_off.cqes + cq_entries * sizeof(struct io_uring_cqe),
+ PROT_READ|PROT_WRITE, MAP_SHARED|MAP_POPULATE, ring_fd,
+ IORING_OFF_CQ_RING);
+
+Closing the file descriptor returned by **io_uring_setup**(2) will free all resources associated with the io_uring context. Note that this may happen asynchronously within the kernel, so it is not guaranteed that resources are freed immediately.
+
+# RETURN VALUE
+
+**io_uring_setup**(2) returns a new file descriptor on success. The application may then provide the file descriptor in a subsequent **mmap**(2) call to map the submission and completion queues, or to the **io_uring_register**(2) or **io_uring_enter**(2) system calls.
+
+On error, a negative error code is returned. The caller should not rely on *errno* variable.
+
+# ERRORS
+
+**EFAULT**
+
+: *params* is outside your accessible address space.
+
+**EINVAL**
+
+: The resv array contains non-zero data, p.flags contains an unsupported flag, *entries* is out of bounds, **IORING_SETUP_SQ_AFF** was specified, but **IORING_SETUP_SQPOLL** was not, or **IORING_SETUP_CQSIZE** was specified, but *io_uring_params.cq_entries* was invalid. **IORING_SETUP_REGISTERED_FD_ONLY** was specified, but **IORING_SETUP_NO_MMAP** was not.
+
+**EMFILE**
+
+: The per-process limit on the number of open file descriptors has been reached (see the description of **RLIMIT_NOFILE** in **getrlimit**(2)).
+
+**ENFILE**
+
+: The system-wide limit on the total number of open files has been reached.
+
+**ENOMEM**
+
+: Insufficient kernel resources are available.
+
+**EPERM**
+
+: **IORING_SETUP_SQPOLL** was specified, but the effective user ID of the caller did not have sufficient privileges.
+
+**EPERM**
+
+: */proc/sys/kernel/io_uring_disabled* has the value 2, or it has the value 1 and the calling process does not hold the **CAP_SYS_ADMIN** capability or is not a member of */proc/sys/kernel/io_uring_group*.
+
+**ENXIO**
+
+: **IORING_SETUP_ATTACH_WQ** was set, but *params.wq_fd* did not refer to an io_uring instance or refers to an instance that is in the process of shutting down.
+
+# SEE ALSO
+
+**io_uring_register**(2), **io_uring_enter**(2)
diff --git a/man/io_uring_setup_buf_ring.3 b/man/io_uring_setup_buf_ring.3
deleted file mode 100644
index 63175ee4..00000000
--- a/man/io_uring_setup_buf_ring.3
+++ /dev/null
@@ -1,94 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_setup_buf_ring 3 "Mar 07, 2023" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_setup_buf_ring \- setup and register buffer ring for provided buffers
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "struct io_uring_buf_ring *io_uring_setup_buf_ring(struct io_uring *" ring ",
-.BI " unsigned int " nentries ",
-.BI " int " bgid ",
-.BI " unsigned int " flags ",
-.BI " int *" err ");"
-.BI "
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_setup_buf_ring (3)
-function registers a shared buffer ring to be used with provided buffers. For
-the request types that support it, provided buffers are given to the ring and
-one is selected by a request if it has
-.B IOSQE_BUFFER_SELECT
-set in the SQE
-.IR flags ,
-when the request is ready to receive data. This allows both clear ownership
-of the buffer lifetime, and a way to have more read/receive type of operations
-in flight than buffers available.
-
-The
-.I ring
-argument must be a pointer to the ring for which the provided buffer ring is being
-registered,
-.I nentries
-is the number of entries requested in the buffer ring. This argument must be
-a power-of 2 in size, and can be up to 32768 in size.
-.I bgid
-is the chosen buffer group ID,
-.I flags
-are modifier flags for the operation, and
-.I *err
-is a pointer to an integer for the error value if any part of the ring
-allocation and registration fails.
-
-The
-.I flags
-argument can be set to one of the following values:
-.TP
-.B IOU_PBUF_RING_INC
-The buffers in this ring can be incrementally consumed. With partial
-consumption, each completion of a given buffer ID will continue where the
-previous one left off, or from the start if no completions have been seen yet.
-When more completions should be expected for a given buffer ID, the CQE will
-have
-.B IORING_CQE_F_BUF_MORE
-set in the
-.I flags
-member. Available since 6.12.
-.PP
-
-Under the covers, this function uses
-.BR io_uring_register_buf_ring (3)
-to register the ring, and handles the allocation of the ring rather than
-letting the application open code it.
-
-To unregister and free a buffer group ID setup with this function, the
-application must call
-.BR io_uring_free_buf_ring (3) .
-
-Available since 5.19.
-
-.SH RETURN VALUE
-On success
-.BR io_uring_setup_buf_ring (3)
-returns a pointer to the buffer ring. On failure it returns
-.BR NULL
-and sets
-.I *err
-to -errno.
-.SH NOTES
-Note that even if the kernel supports this feature, registering a provided
-buffer ring may still fail with
-.B -EINVAL
-if the host is a 32-bit architecture and the memory being passed in resides in
-high memory.
-.SH SEE ALSO
-.BR io_uring_register_buf_ring (3),
-.BR io_uring_buf_ring_init (3),
-.BR io_uring_buf_ring_add (3),
-.BR io_uring_buf_ring_advance (3),
-.BR io_uring_buf_ring_cq_advance (3)
diff --git a/man/io_uring_setup_buf_ring.3.md b/man/io_uring_setup_buf_ring.3.md
new file mode 100644
index 00000000..77d955b4
--- /dev/null
+++ b/man/io_uring_setup_buf_ring.3.md
@@ -0,0 +1,56 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: Mar 07, 2023
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_setup_buf_ring
+---
+
+# NAME
+
+io_uring_setup_buf_ring - setup and register buffer ring for provided buffers
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ struct io_uring_buf_ring *io_uring_setup_buf_ring(struct io_uring * ring ,
+ unsigned int nentries ,
+ int bgid ,
+ unsigned int flags ,
+ int * err );
+
+
+# DESCRIPTION
+
+The **io_uring_setup_buf_ring**(3) function registers a shared buffer ring to be used with provided buffers. For the request types that support it, provided buffers are given to the ring and one is selected by a request if it has **IOSQE_BUFFER_SELECT** set in the SQE *flags*, when the request is ready to receive data. This allows both clear ownership of the buffer lifetime, and a way to have more read/receive type of operations in flight than buffers available.
+
+The *ring* argument must be a pointer to the ring for which the provided buffer ring is being registered, *nentries* is the number of entries requested in the buffer ring. This argument must be a power-of 2 in size, and can be up to 32768 in size. *bgid* is the chosen buffer group ID, *flags* are modifier flags for the operation, and *\*err* is a pointer to an integer for the error value if any part of the ring allocation and registration fails.
+
+The *flags* argument can be set to one of the following values:
+
+**IOU_PBUF_RING_INC**
+
+: The buffers in this ring can be incrementally consumed. With partial consumption, each completion of a given buffer ID will continue where the previous one left off, or from the start if no completions have been seen yet. When more completions should be expected for a given buffer ID, the CQE will have **IORING_CQE_F_BUF_MORE** set in the *flags* member. Available since 6.12.
+
+Under the covers, this function uses **io_uring_register_buf_ring**(3) to register the ring, and handles the allocation of the ring rather than letting the application open code it.
+
+To unregister and free a buffer group ID setup with this function, the application must call **io_uring_free_buf_ring**(3)**.**
+
+Available since 5.19.
+
+# RETURN VALUE
+
+On success **io_uring_setup_buf_ring**(3) returns a pointer to the buffer ring. On failure it returns **NULL** and sets *\*err* to -errno.
+
+# NOTES
+
+Note that even if the kernel supports this feature, registering a provided buffer ring may still fail with **-EINVAL** if the host is a 32-bit architecture and the memory being passed in resides in high memory.
+
+# SEE ALSO
+
+**io_uring_register_buf_ring**(3), **io_uring_buf_ring_init**(3), **io_uring_buf_ring_add**(3), **io_uring_buf_ring_advance**(3), **io_uring_buf_ring_cq_advance**(3)
diff --git a/man/io_uring_setup_flags.7 b/man/io_uring_setup_flags.7
deleted file mode 100644
index 7d117c47..00000000
--- a/man/io_uring_setup_flags.7
+++ /dev/null
@@ -1,451 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_setup_flags 7 "January 18, 2025" "Linux" "Linux Programmer's Manual"
-.SH NAME
-io_uring_setup_flags \- io_uring ring setup flags overview
-.SH DESCRIPTION
-When creating an io_uring instance with
-.BR io_uring_queue_init_params (3)
-or
-.BR io_uring_setup (2),
-various flags control the ring's behavior. These flags are set in the
-.I flags
-field of
-.IR "struct io_uring_params" .
-.PP
-Choosing the right flags can significantly impact performance. This page
-provides an overview of available flags, their purposes, and common
-combinations.
-.SS Polling flags
-These flags control how I/O completion and submission polling works.
-.PP
-.B IORING_SETUP_IOPOLL
-.RS 4
-Enable I/O polling mode for file descriptors that support it. Instead of
-relying on interrupts, the kernel polls for completions. This reduces
-latency for high-performance storage devices (NVMe, etc.) but requires:
-.IP \(bu 2
-Files opened with
-.B O_DIRECT
-(if using the
-.B IORING_OP_{READ,WRITE}(V)(_FIXED)
-opcodes)
-.IP \(bu
-Hardware and drivers that support polling
-.IP \(bu
-The application to call
-.BR io_uring_enter (2)
-to reap completions (busy-polling)
-.IP \(bu
-Storage device configuration for polling support
-.PP
-Only the following opcodes are allowed on IOPOLL rings:
-.IP \(bu 2
-.B IORING_OP_NOP(128)
-.IP \(bu
-.B IORING_OP_{READ,WRITE}(V)(_FIXED)
-(if the file supports busy-polling)
-.IP \(bu
-.B IORING_OP_FILES_UPDATE
-.IP \(bu
-.B IORING_OP_{PROVIDE,REMOVE}_BUFFERS
-.IP \(bu
-.B IORING_OP_MSG_RING
-.IP \(bu
-.B IORING_OP_URING_CMD(128)
-.PP
-Since kernel 7.1, an
-.B IORING_OP_URING_CMD(128)
-request will use busy-polling if the file supports it (i.e., NVMe passthrough
-I/O commands).
-Previously,
-.B IORING_OP_URING_CMD(128)
-was only allowed on files that supported busy-polling.
-.PP
-Using IOPOLL generally requires storage device setup. For NVMe devices,
-the kernel parameter
-.B nvme.poll_queues=X
-must be set, where X is the number of completion queues on the NVMe
-device to set aside for polling operations.
-.RE
-.PP
-.B IORING_SETUP_SQPOLL
-.RS 4
-Create a kernel thread that polls the submission queue. Eliminates the
-need for system calls to submit I/O. See
-.BR io_uring_sqpoll (7)
-for details.
-.RE
-.PP
-.B IORING_SETUP_SQ_AFF
-.RS 4
-Pin the SQPOLL thread to a specific CPU. Requires
-.BR IORING_SETUP_SQPOLL .
-The CPU is specified in
-.I sq_thread_cpu
-of
-.IR "struct io_uring_params" .
-.RE
-.PP
-.B IORING_SETUP_HYBRID_IOPOLL
-.RS 4
-Enable hybrid polling mode. Instead of pure busy-polling, the kernel
-uses an adaptive approach that may sleep briefly, reducing CPU usage
-while still providing low latency. This is a middle ground between
-interrupt-driven and pure polling modes.
-.RE
-.SS Task run flags
-These flags control when and how completion processing runs.
-.PP
-.B IORING_SETUP_COOP_TASKRUN
-.RS 4
-Disable interrupting the application for completion processing. Normally,
-the kernel signals the application when completions are ready, which can
-interrupt system calls. With this flag, completions are only processed
-when the application returns to userspace from any system call, not just
-io_uring-related ones. This means completions may be processed after
-.BR read (2),
-.BR write (2),
-.BR poll (2),
-or any other syscall returns.
-.PP
-This improves performance by eliminating asynchronous interrupts but
-requires the application to regularly enter the kernel to process
-completions. Recommended for most applications that have an event loop.
-.RE
-.PP
-.B IORING_SETUP_TASKRUN_FLAG
-.RS 4
-When completions are pending, set
-.B IORING_SQ_TASKRUN
-in the SQ ring flags. This allows applications to check if there is
-completion work to process without making a system call. Typically used
-with
-.BR IORING_SETUP_COOP_TASKRUN .
-.RE
-.PP
-.B IORING_SETUP_DEFER_TASKRUN
-.RS 4
-Defer completion task work to when the application explicitly enters the
-kernel via
-.BR io_uring_enter (2).
-Unlike
-.BR IORING_SETUP_COOP_TASKRUN ,
-completions are only processed during io_uring-related syscalls, not on
-return from arbitrary syscalls. This provides the tightest and most
-predictable control over when completion processing occurs, as well as
-optimal cache behavior since work runs in the application's context.
-.PP
-This flag should be considered the default mode for applications setting
-up a ring. It requires
-.B IORING_SETUP_SINGLE_ISSUER
-and a ring created per-thread. The application must regularly call
-.BR io_uring_enter (2)
-(via
-.BR io_uring_submit (3),
-.BR io_uring_wait_cqe (3),
-or similar) to process deferred work; failing to do so will stall
-completions.
-.PP
-Some features require this flag:
-.IP \(bu 2
-Ring resizing
-.RB ( io_uring_register_resize_rings (3))
-.IP \(bu
-Zero-copy receive
-.RB ( IORING_OP_RECV_ZC )
-.RE
-.PP
-.B IORING_SETUP_SINGLE_ISSUER
-.RS 4
-Hint that only one task will submit requests to this ring. Enables
-internal optimizations including reduced locking overhead. The first
-task to submit a request becomes the designated submitter; others
-attempting to submit will get
-.BR -EEXIST .
-.PP
-Each thread or task having its own ring is the idiomatic use case for
-io_uring. Sharing a ring between multiple threads or tasks is
-discouraged as it requires additional synchronization and prevents
-many optimizations. Applications should create a ring per thread rather
-than sharing rings.
-.RE
-.SS Ring sizing flags
-These flags control the size and layout of the submission and completion
-queues.
-.PP
-.B IORING_SETUP_CQSIZE
-.RS 4
-Override the default completion queue size. By default, the CQ has twice
-as many entries as the SQ. Set
-.I cq_entries
-in
-.I struct io_uring_params
-to specify a custom CQ size. Must be a power of 2.
-.PP
-Larger CQ sizes are useful when the application may submit many requests
-before processing completions, avoiding CQ overflow.
-.RE
-.PP
-.B IORING_SETUP_CLAMP
-.RS 4
-Clamp the SQ and CQ sizes to the maximum allowed values instead of
-returning
-.B -EINVAL
-if the requested sizes are too large. Useful when the application wants
-the largest possible rings without querying limits.
-.RE
-.PP
-.B IORING_SETUP_SQE128
-.RS 4
-Use 128-byte SQEs instead of the default 64 bytes. Required for some
-operations that need extra space, such as
-.B IORING_OP_URING_CMD
-passthrough commands.
-.RE
-.PP
-.B IORING_SETUP_CQE32
-.RS 4
-Use 32-byte CQEs instead of the default 16 bytes. Required for
-operations that return extra data, such as some passthrough commands
-or when using
-.BR IORING_OP_MSG_RING .
-.RE
-.PP
-.B IORING_SETUP_NO_SQARRAY
-.RS 4
-Do not create the SQ array. The SQ array is a level of indirection that
-allows SQEs to be submitted in a different order than they appear in
-the ring. Most applications submit SQEs in order and do not need this.
-This flag saves memory and is required for some modes like
-.BR IORING_SETUP_REGISTERED_FD_ONLY .
-.RE
-.PP
-.B IORING_SETUP_SQ_REWIND
-.RS 4
-Use non-circular submission queue mode. The kernel ignores the SQ head
-and tail pointers and instead fetches SQEs starting from index 0 on each
-submit. The application places all SQEs at the beginning of the ring
-before calling
-.BR io_uring_enter (2),
-and the
-.I sq_entries
-parameter determines how many SQEs are submitted.
-.PP
-Requires
-.BR IORING_SETUP_NO_SQARRAY .
-Not compatible with
-.BR IORING_SETUP_SQPOLL .
-.PP
-This mode keeps SQEs hot in cache by always accessing the same memory
-locations at the start of the ring, improving performance for workloads
-that submit small batches frequently.
-.RE
-.PP
-.B IORING_SETUP_CQE_MIXED
-.RS 4
-Allow the ring to return a mix of 16-byte and 32-byte CQEs, controlled
-per-request. When a request needs a 32-byte CQE, it sets
-.B IOSQE_BIG_CQE
-in its flags. Otherwise, a 16-byte CQE is used. Requires
-.BR IORING_SETUP_CQE32 .
-.PP
-This is useful when certain operations require 32-byte CQEs (such as
-some passthrough commands) but most operations do not. Using mixed mode
-instead of
-.B IORING_SETUP_CQE32
-alone provides efficiency benefits in terms of memory bandwidth and
-usage, since the smaller 16-byte CQEs are used for operations that do
-not need the extra space.
-.RE
-.PP
-.B IORING_SETUP_SQE_MIXED
-.RS 4
-Allow the ring to accept a mix of 64-byte and 128-byte SQEs. When a
-request needs a 128-byte SQE, it sets
-.B IOSQE_BIG_SQE
-in its flags. Requires
-.BR IORING_SETUP_SQE128 .
-.PP
-This is useful when certain operations require 128-byte SQEs (such as
-.BR IORING_OP_URING_CMD )
-but most operations do not. Using mixed mode instead of
-.B IORING_SETUP_SQE128
-alone provides efficiency benefits in terms of memory bandwidth and
-usage, since the smaller 64-byte SQEs are used for operations that do
-not need the extra space.
-.RE
-.SS Memory and setup flags
-These flags control memory allocation and ring initialization.
-.PP
-.B IORING_SETUP_NO_MMAP
-.RS 4
-The application provides its own memory for the rings instead of the
-kernel allocating and the application mmap'ing it. The application
-fills in
-.IR sq_off.user_addr ,
-.IR cq_off.user_addr ,
-and
-.I sq_sqes.user_addr
-in
-.I struct io_uring_params
-with addresses of application-allocated memory.
-.PP
-This is useful for placing rings in specific memory (huge pages, shared
-memory, etc.) or for creating rings without mmap.
-.RE
-.PP
-.B IORING_SETUP_REGISTERED_FD_ONLY
-.RS 4
-The ring file descriptor is not installed in the process's file
-descriptor table. Instead, a "registered ring" index is returned in
-.I ring_fd
-that can be used with
-.BR io_uring_enter (2)
-when
-.B IORING_ENTER_REGISTERED_RING
-is set. This reduces per-operation overhead.
-.PP
-Requires
-.BR IORING_SETUP_NO_SQARRAY .
-The application must use
-.BR io_uring_register_ring_fd (3)
-to use the ring or access it via the registered index.
-.RE
-.PP
-.B IORING_SETUP_R_DISABLED
-.RS 4
-Create the ring in a disabled state. The ring will not accept submissions
-until it is enabled via
-.BR io_uring_enable_rings (3).
-This is useful when setting up restrictions or registered resources
-before allowing I/O. See
-.BR io_uring_register_restrictions (3).
-.RE
-.SS Submission flags
-These flags control submission behavior.
-.PP
-.B IORING_SETUP_SUBMIT_ALL
-.RS 4
-Continue processing submissions even if one fails. Normally, if an
-SQE fails during submission (not execution), subsequent SQEs in the
-same submit call are not processed. With this flag, all SQEs are
-processed regardless of earlier failures.
-.PP
-The failed SQE still generates a CQE with the error; this flag only
-affects whether subsequent SQEs are submitted. This is probably the
-behavior most applications expect, since CQEs are generated for failed
-submissions anyway and the application must handle them regardless.
-.RE
-.SS Workqueue flags
-These flags control the async worker threads.
-.PP
-.B IORING_SETUP_ATTACH_WQ
-.RS 4
-Share the async worker thread pool with another ring. Set
-.I wq_fd
-in
-.I struct io_uring_params
-to the file descriptor of the ring to share with. This reduces resource
-usage when an application uses multiple rings.
-.PP
-When combined with
-.BR IORING_SETUP_SQPOLL ,
-the SQPOLL thread is also shared.
-.RE
-.SS Common flag combinations
-.PP
-.B High-performance single-threaded application:
-.RS 4
-.PP
-.in +4n
-.EX
-\&.flags = IORING_SETUP_SINGLE_ISSUER |
- IORING_SETUP_DEFER_TASKRUN |
- IORING_SETUP_COOP_TASKRUN
-.EE
-.in
-.PP
-This combination provides the best latency and throughput for applications
-where each thread has its own ring and processes completions in a dedicated
-event loop.
-.RE
-.PP
-.B Low-latency storage with polling:
-.RS 4
-.PP
-.in +4n
-.EX
-\&.flags = IORING_SETUP_IOPOLL |
- IORING_SETUP_SINGLE_ISSUER |
- IORING_SETUP_DEFER_TASKRUN
-.EE
-.in
-.PP
-For NVMe or other devices that support polling, this eliminates interrupt
-overhead. Combined with DEFER_TASKRUN for optimal completion handling.
-.RE
-.PP
-.B System call-free submission:
-.RS 4
-.PP
-.in +4n
-.EX
-\&.flags = IORING_SETUP_SQPOLL |
- IORING_SETUP_SQ_AFF
-\&.sq_thread_cpu = preferred_cpu
-\&.sq_thread_idle = 1000
-.EE
-.in
-.PP
-For workloads that benefit from eliminating submission syscall overhead.
-See
-.BR io_uring_sqpoll (7).
-.RE
-.PP
-.B Multiple rings sharing resources:
-.RS 4
-.PP
-.in +4n
-.EX
-/* First ring */
-p1.flags = IORING_SETUP_SQPOLL;
-
-/* Subsequent rings */
-p2.flags = IORING_SETUP_SQPOLL | IORING_SETUP_ATTACH_WQ;
-p2.wq_fd = ring1_fd;
-.EE
-.in
-.PP
-Reduces kernel thread and workqueue overhead when using multiple rings.
-.RE
-.SH NOTES
-.IP \(bu 2
-Not all flag combinations are valid. The kernel returns
-.B -EINVAL
-for incompatible combinations.
-.IP \(bu
-Some flags require specific kernel versions. Check
-.BR io_uring_setup (2)
-for version requirements.
-.IP \(bu
-The
-.BR io_uring_queue_init_params (3)
-function handles the complexity of ring setup. Using the raw
-.BR io_uring_setup (2)
-syscall requires careful mmap setup.
-.IP \(bu
-For most applications with a proper event loop,
-.B IORING_SETUP_DEFER_TASKRUN
-combined with
-.B IORING_SETUP_SINGLE_ISSUER
-is the recommended default. This provides the best control over when
-completion work runs and optimal cache locality.
-.SH SEE ALSO
-.BR io_uring (7),
-.BR io_uring_sqpoll (7),
-.BR io_uring_setup (2),
-.BR io_uring_queue_init_params (3),
-.BR io_uring_register_restrictions (3),
-.BR io_uring_enable_rings (3)
diff --git a/man/io_uring_setup_flags.7.md b/man/io_uring_setup_flags.7.md
new file mode 100644
index 00000000..8cb3facd
--- /dev/null
+++ b/man/io_uring_setup_flags.7.md
@@ -0,0 +1,236 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: Linux
+header: Linux Programmer\'s Manual
+section: 7
+title: io_uring_setup_flags
+---
+
+# NAME
+
+io_uring_setup_flags - io_uring ring setup flags overview
+
+# DESCRIPTION
+
+When creating an io_uring instance with **io_uring_queue_init_params**(3) or **io_uring_setup**(2), various flags control the ring\'s behavior. These flags are set in the *flags* field of *struct io_uring_params*.
+
+Choosing the right flags can significantly impact performance. This page provides an overview of available flags, their purposes, and common combinations.
+
+## Polling flags
+
+These flags control how I/O completion and submission polling works.
+
+**IORING_SETUP_IOPOLL**
+
+> Enable I/O polling mode for file descriptors that support it. Instead of relying on interrupts, the kernel polls for completions. This reduces latency for high-performance storage devices (NVMe, etc.) but requires:
+>
+> - Files opened with **O_DIRECT** (if using the **IORING_OP\_{READ,WRITE}(V)(\_FIXED)** opcodes)
+>
+> - Hardware and drivers that support polling
+>
+> - The application to call **io_uring_enter**(2) to reap completions (busy-polling)
+>
+> - Storage device configuration for polling support
+>
+> Only the following opcodes are allowed on IOPOLL rings:
+>
+> - **IORING_OP_NOP(128)**
+>
+> - **IORING_OP\_{READ,WRITE}(V)(\_FIXED)** (if the file supports busy-polling)
+>
+> - **IORING_OP_FILES_UPDATE**
+>
+> - **IORING_OP\_{PROVIDE,REMOVE}\_BUFFERS**
+>
+> - **IORING_OP_MSG_RING**
+>
+> - **IORING_OP_URING_CMD(128)**
+>
+> Since kernel 7.1, an **IORING_OP_URING_CMD(128)** request will use busy-polling if the file supports it (i.e., NVMe passthrough I/O commands). Previously, **IORING_OP_URING_CMD(128)** was only allowed on files that supported busy-polling.
+>
+> Using IOPOLL generally requires storage device setup. For NVMe devices, the kernel parameter **nvme.poll_queues=X** must be set, where X is the number of completion queues on the NVMe device to set aside for polling operations.
+
+**IORING_SETUP_SQPOLL**
+
+> Create a kernel thread that polls the submission queue. Eliminates the need for system calls to submit I/O. See **io_uring_sqpoll**(7) for details.
+
+**IORING_SETUP_SQ_AFF**
+
+> Pin the SQPOLL thread to a specific CPU. Requires **IORING_SETUP_SQPOLL**. The CPU is specified in *sq_thread_cpu* of *struct io_uring_params*.
+
+**IORING_SETUP_HYBRID_IOPOLL**
+
+> Enable hybrid polling mode. Instead of pure busy-polling, the kernel uses an adaptive approach that may sleep briefly, reducing CPU usage while still providing low latency. This is a middle ground between interrupt-driven and pure polling modes.
+
+## Task run flags
+
+These flags control when and how completion processing runs.
+
+**IORING_SETUP_COOP_TASKRUN**
+
+> Disable interrupting the application for completion processing. Normally, the kernel signals the application when completions are ready, which can interrupt system calls. With this flag, completions are only processed when the application returns to userspace from any system call, not just io_uring-related ones. This means completions may be processed after **read**(2), **write**(2), **poll**(2), or any other syscall returns.
+>
+> This improves performance by eliminating asynchronous interrupts but requires the application to regularly enter the kernel to process completions. Recommended for most applications that have an event loop.
+
+**IORING_SETUP_TASKRUN_FLAG**
+
+> When completions are pending, set **IORING_SQ_TASKRUN** in the SQ ring flags. This allows applications to check if there is completion work to process without making a system call. Typically used with **IORING_SETUP_COOP_TASKRUN**.
+
+**IORING_SETUP_DEFER_TASKRUN**
+
+> Defer completion task work to when the application explicitly enters the kernel via **io_uring_enter**(2). Unlike **IORING_SETUP_COOP_TASKRUN**, completions are only processed during io_uring-related syscalls, not on return from arbitrary syscalls. This provides the tightest and most predictable control over when completion processing occurs, as well as optimal cache behavior since work runs in the application\'s context.
+>
+> This flag should be considered the default mode for applications setting up a ring. It requires **IORING_SETUP_SINGLE_ISSUER** and a ring created per-thread. The application must regularly call **io_uring_enter**(2) (via **io_uring_submit**(3), **io_uring_wait_cqe**(3), or similar) to process deferred work; failing to do so will stall completions.
+>
+> Some features require this flag:
+>
+> - Ring resizing (**io_uring_register_resize_rings**(3))
+>
+> - Zero-copy receive (**IORING_OP_RECV_ZC**)
+
+**IORING_SETUP_SINGLE_ISSUER**
+
+> Hint that only one task will submit requests to this ring. Enables internal optimizations including reduced locking overhead. The first task to submit a request becomes the designated submitter; others attempting to submit will get **-EEXIST**.
+>
+> Each thread or task having its own ring is the idiomatic use case for io_uring. Sharing a ring between multiple threads or tasks is discouraged as it requires additional synchronization and prevents many optimizations. Applications should create a ring per thread rather than sharing rings.
+
+## Ring sizing flags
+
+These flags control the size and layout of the submission and completion queues.
+
+**IORING_SETUP_CQSIZE**
+
+> Override the default completion queue size. By default, the CQ has twice as many entries as the SQ. Set *cq_entries* in *struct io_uring_params* to specify a custom CQ size. Must be a power of 2.
+>
+> Larger CQ sizes are useful when the application may submit many requests before processing completions, avoiding CQ overflow.
+
+**IORING_SETUP_CLAMP**
+
+> Clamp the SQ and CQ sizes to the maximum allowed values instead of returning **-EINVAL** if the requested sizes are too large. Useful when the application wants the largest possible rings without querying limits.
+
+**IORING_SETUP_SQE128**
+
+> Use 128-byte SQEs instead of the default 64 bytes. Required for some operations that need extra space, such as **IORING_OP_URING_CMD** passthrough commands.
+
+**IORING_SETUP_CQE32**
+
+> Use 32-byte CQEs instead of the default 16 bytes. Required for operations that return extra data, such as some passthrough commands or when using **IORING_OP_MSG_RING**.
+
+**IORING_SETUP_NO_SQARRAY**
+
+> Do not create the SQ array. The SQ array is a level of indirection that allows SQEs to be submitted in a different order than they appear in the ring. Most applications submit SQEs in order and do not need this. This flag saves memory and is required for some modes like **IORING_SETUP_REGISTERED_FD_ONLY**.
+
+**IORING_SETUP_SQ_REWIND**
+
+> Use non-circular submission queue mode. The kernel ignores the SQ head and tail pointers and instead fetches SQEs starting from index 0 on each submit. The application places all SQEs at the beginning of the ring before calling **io_uring_enter**(2), and the *sq_entries* parameter determines how many SQEs are submitted.
+>
+> Requires **IORING_SETUP_NO_SQARRAY**. Not compatible with **IORING_SETUP_SQPOLL**.
+>
+> This mode keeps SQEs hot in cache by always accessing the same memory locations at the start of the ring, improving performance for workloads that submit small batches frequently.
+
+**IORING_SETUP_CQE_MIXED**
+
+> Allow the ring to return a mix of 16-byte and 32-byte CQEs, controlled per-request. When a request needs a 32-byte CQE, it sets **IOSQE_BIG_CQE** in its flags. Otherwise, a 16-byte CQE is used. Requires **IORING_SETUP_CQE32**.
+>
+> This is useful when certain operations require 32-byte CQEs (such as some passthrough commands) but most operations do not. Using mixed mode instead of **IORING_SETUP_CQE32** alone provides efficiency benefits in terms of memory bandwidth and usage, since the smaller 16-byte CQEs are used for operations that do not need the extra space.
+
+**IORING_SETUP_SQE_MIXED**
+
+> Allow the ring to accept a mix of 64-byte and 128-byte SQEs. When a request needs a 128-byte SQE, it sets **IOSQE_BIG_SQE** in its flags. Requires **IORING_SETUP_SQE128**.
+>
+> This is useful when certain operations require 128-byte SQEs (such as **IORING_OP_URING_CMD**) but most operations do not. Using mixed mode instead of **IORING_SETUP_SQE128** alone provides efficiency benefits in terms of memory bandwidth and usage, since the smaller 64-byte SQEs are used for operations that do not need the extra space.
+
+## Memory and setup flags
+
+These flags control memory allocation and ring initialization.
+
+**IORING_SETUP_NO_MMAP**
+
+> The application provides its own memory for the rings instead of the kernel allocating and the application mmap\'ing it. The application fills in *sq_off.user_addr*, *cq_off.user_addr*, and *sq_sqes.user_addr* in *struct io_uring_params* with addresses of application-allocated memory.
+>
+> This is useful for placing rings in specific memory (huge pages, shared memory, etc.) or for creating rings without mmap.
+
+**IORING_SETUP_REGISTERED_FD_ONLY**
+
+> The ring file descriptor is not installed in the process\'s file descriptor table. Instead, a \"registered ring\" index is returned in *ring_fd* that can be used with **io_uring_enter**(2) when **IORING_ENTER_REGISTERED_RING** is set. This reduces per-operation overhead.
+>
+> Requires **IORING_SETUP_NO_SQARRAY**. The application must use **io_uring_register_ring_fd**(3) to use the ring or access it via the registered index.
+
+**IORING_SETUP_R_DISABLED**
+
+> Create the ring in a disabled state. The ring will not accept submissions until it is enabled via **io_uring_enable_rings**(3). This is useful when setting up restrictions or registered resources before allowing I/O. See **io_uring_register_restrictions**(3).
+
+## Submission flags
+
+These flags control submission behavior.
+
+**IORING_SETUP_SUBMIT_ALL**
+
+> Continue processing submissions even if one fails. Normally, if an SQE fails during submission (not execution), subsequent SQEs in the same submit call are not processed. With this flag, all SQEs are processed regardless of earlier failures.
+>
+> The failed SQE still generates a CQE with the error; this flag only affects whether subsequent SQEs are submitted. This is probably the behavior most applications expect, since CQEs are generated for failed submissions anyway and the application must handle them regardless.
+
+## Workqueue flags
+
+These flags control the async worker threads.
+
+**IORING_SETUP_ATTACH_WQ**
+
+> Share the async worker thread pool with another ring. Set *wq_fd* in *struct io_uring_params* to the file descriptor of the ring to share with. This reduces resource usage when an application uses multiple rings.
+>
+> When combined with **IORING_SETUP_SQPOLL**, the SQPOLL thread is also shared.
+
+## Common flag combinations
+
+**High-performance single-threaded application:**
+
+> .flags = IORING_SETUP_SINGLE_ISSUER |
+> IORING_SETUP_DEFER_TASKRUN |
+> IORING_SETUP_COOP_TASKRUN
+>
+> This combination provides the best latency and throughput for applications where each thread has its own ring and processes completions in a dedicated event loop.
+
+**Low-latency storage with polling:**
+
+> .flags = IORING_SETUP_IOPOLL |
+> IORING_SETUP_SINGLE_ISSUER |
+> IORING_SETUP_DEFER_TASKRUN
+>
+> For NVMe or other devices that support polling, this eliminates interrupt overhead. Combined with DEFER_TASKRUN for optimal completion handling.
+
+**System call-free submission:**
+
+> .flags = IORING_SETUP_SQPOLL |
+> IORING_SETUP_SQ_AFF
+> .sq_thread_cpu = preferred_cpu
+> .sq_thread_idle = 1000
+>
+> For workloads that benefit from eliminating submission syscall overhead. See **io_uring_sqpoll**(7).
+
+**Multiple rings sharing resources:**
+
+> /* First ring */
+> p1.flags = IORING_SETUP_SQPOLL;
+>
+> /* Subsequent rings */
+> p2.flags = IORING_SETUP_SQPOLL | IORING_SETUP_ATTACH_WQ;
+> p2.wq_fd = ring1_fd;
+>
+> Reduces kernel thread and workqueue overhead when using multiple rings.
+
+# NOTES
+
+- Not all flag combinations are valid. The kernel returns **-EINVAL** for incompatible combinations.
+
+- Some flags require specific kernel versions. Check **io_uring_setup**(2) for version requirements.
+
+- The **io_uring_queue_init_params**(3) function handles the complexity of ring setup. Using the raw **io_uring_setup**(2) syscall requires careful mmap setup.
+
+- For most applications with a proper event loop, **IORING_SETUP_DEFER_TASKRUN** combined with **IORING_SETUP_SINGLE_ISSUER** is the recommended default. This provides the best control over when completion work runs and optimal cache locality.
+
+# SEE ALSO
+
+**io_uring**(7), **io_uring_sqpoll**(7), **io_uring_setup**(2), **io_uring_queue_init_params**(3), **io_uring_register_restrictions**(3), **io_uring_enable_rings**(3)
diff --git a/man/io_uring_sq_ready.3 b/man/io_uring_sq_ready.3
deleted file mode 100644
index ba155b32..00000000
--- a/man/io_uring_sq_ready.3
+++ /dev/null
@@ -1,31 +0,0 @@
-.\" Copyright (C) 2022 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_sq_ready 3 "January 25, 2022" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_sq_ready \- number of unconsumed or unsubmitted entries in the SQ ring
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "unsigned io_uring_sq_ready(const struct io_uring *" ring ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_sq_ready (3)
-function returns the number of unconsumed (if SQPOLL) or unsubmitted entries
-that exist in the SQ ring belonging to the
-.I ring
-param.
-
-Usage of this function only applies if the ring has been setup with
-.B IORING_SETUP_SQPOLL,
-where request submissions, and hence consumption from the SQ ring, happens
-through a polling thread.
-
-.SH RETURN VALUE
-Returns the number of unconsumed or unsubmitted entries in the SQ ring.
-.SH SEE ALSO
-.BR io_uring_cq_ready (3)
diff --git a/man/io_uring_sq_ready.3.md b/man/io_uring_sq_ready.3.md
new file mode 100644
index 00000000..80d6ead0
--- /dev/null
+++ b/man/io_uring_sq_ready.3.md
@@ -0,0 +1,35 @@
+.\" Copyright (C) 2022 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 25, 2022
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_sq_ready
+---
+
+# NAME
+
+io_uring_sq_ready - number of unconsumed or unsubmitted entries in the SQ ring
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ unsigned io_uring_sq_ready(const struct io_uring * ring );
+
+# DESCRIPTION
+
+The **io_uring_sq_ready**(3) function returns the number of unconsumed (if SQPOLL) or unsubmitted entries that exist in the SQ ring belonging to the *ring* param.
+
+Usage of this function only applies if the ring has been setup with **IORING_SETUP_SQPOLL,** where request submissions, and hence consumption from the SQ ring, happens through a polling thread.
+
+# RETURN VALUE
+
+Returns the number of unconsumed or unsubmitted entries in the SQ ring.
+
+# SEE ALSO
+
+**io_uring_cq_ready**(3)
diff --git a/man/io_uring_sq_space_left.3 b/man/io_uring_sq_space_left.3
deleted file mode 100644
index 74872d8b..00000000
--- a/man/io_uring_sq_space_left.3
+++ /dev/null
@@ -1,25 +0,0 @@
-.\" Copyright (C) 2022 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_sq_space_left 3 "January 25, 2022" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_sq_space_left \- free space in the SQ ring
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "unsigned io_uring_sq_space_left(const struct io_uring *" ring ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_sq_space_left (3)
-function returns how much space is left in the SQ ring belonging to the
-.I ring
-param.
-
-.SH RETURN VALUE
-Returns the number of availables entries in the SQ ring.
-.SH SEE ALSO
-.BR io_uring_sq_ready (3)
diff --git a/man/io_uring_sq_space_left.3.md b/man/io_uring_sq_space_left.3.md
new file mode 100644
index 00000000..f70eb4a2
--- /dev/null
+++ b/man/io_uring_sq_space_left.3.md
@@ -0,0 +1,33 @@
+.\" Copyright (C) 2022 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 25, 2022
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_sq_space_left
+---
+
+# NAME
+
+io_uring_sq_space_left - free space in the SQ ring
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ unsigned io_uring_sq_space_left(const struct io_uring * ring );
+
+# DESCRIPTION
+
+The **io_uring_sq_space_left**(3) function returns how much space is left in the SQ ring belonging to the *ring* param.
+
+# RETURN VALUE
+
+Returns the number of availables entries in the SQ ring.
+
+# SEE ALSO
+
+**io_uring_sq_ready**(3)
diff --git a/man/io_uring_sqe_set_buf_group.3 b/man/io_uring_sqe_set_buf_group.3
deleted file mode 100644
index 5299051d..00000000
--- a/man/io_uring_sqe_set_buf_group.3
+++ /dev/null
@@ -1,32 +0,0 @@
-.\" Copyright (C) 2024 Christian Mazakas <christian.mazakas@gmail.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_sqe_set_buf_group 3 "December 9, 2024" "liburing-2.9" "liburing Manual"
-.SH NAME
-io_uring_sqe_set_buf_group \- set buf group for submission queue event
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_sqe_set_buf_group(struct io_uring_sqe *" sqe ","
-.BI " int " bgid ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_sqe_set_buf_group (3)
-function sets the associated buf_group of the
-.I sqe
-to
-.IR bgid .
-
-After the caller has requested a submission queue entry (SQE) with
-.BR io_uring_get_sqe (3) ,
-they can associate a buf_group with the SQE used for multishot operations.
-
-.SH RETURN VALUE
-None
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_cqe_set_data (3)
diff --git a/man/io_uring_sqe_set_buf_group.3.md b/man/io_uring_sqe_set_buf_group.3.md
new file mode 100644
index 00000000..adab3db5
--- /dev/null
+++ b/man/io_uring_sqe_set_buf_group.3.md
@@ -0,0 +1,36 @@
+.\" Copyright (C) 2024 Christian Mazakas <christian.mazakas@gmail.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: December 9, 2024
+footer: liburing-2.9
+header: liburing Manual
+section: 3
+title: io_uring_sqe_set_buf_group
+---
+
+# NAME
+
+io_uring_sqe_set_buf_group - set buf group for submission queue event
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_sqe_set_buf_group(struct io_uring_sqe * sqe ,
+ int bgid );
+
+# DESCRIPTION
+
+The **io_uring_sqe_set_buf_group**(3) function sets the associated buf_group of the *sqe* to *bgid*.
+
+After the caller has requested a submission queue entry (SQE) with **io_uring_get_sqe**(3)**,** they can associate a buf_group with the SQE used for multishot operations.
+
+# RETURN VALUE
+
+None
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_cqe_set_data**(3)
diff --git a/man/io_uring_sqe_set_data.3 b/man/io_uring_sqe_set_data.3
deleted file mode 100644
index 0a91f57f..00000000
--- a/man/io_uring_sqe_set_data.3
+++ /dev/null
@@ -1,57 +0,0 @@
-.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_sqe_set_data 3 "November 15, 2021" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_sqe_set_data \- set user data for submission queue event
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_sqe_set_data(struct io_uring_sqe *" sqe ","
-.BI " void *" user_data ");"
-.BI "
-.BI "void io_uring_sqe_set_data64(struct io_uring_sqe *" sqe ","
-.BI " __u64 " data ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_sqe_set_data (3)
-function stores a
-.I user_data
-pointer with the submission queue entry
-.IR sqe .
-
-The
-.BR io_uring_sqe_set_data64 (3)
-function stores a 64-bit
-.I data
-value with the submission queue entry
-.IR sqe .
-
-After the caller has requested a submission queue entry (SQE) with
-.BR io_uring_get_sqe (3) ,
-they can associate a data pointer or value with the SQE. Once the completion
-arrives, the function
-.BR io_uring_cqe_get_data (3)
-or
-.BR io_uring_cqe_get_data64 (3)
-can be called to retrieve the data pointer or value associated with the
-submitted request.
-
-Note that if neither of these functions are called, or the
-.I user_data
-field in the
-.IR sqe
-isn't set manually either, then the field may contain a value from a previous
-use of this sqe. If an application relies on always having a valid
-.I user_data
-value present, it must always assign one to each sqe.
-
-.SH RETURN VALUE
-None
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_cqe_get_data (3)
diff --git a/man/io_uring_sqe_set_data.3.md b/man/io_uring_sqe_set_data.3.md
new file mode 100644
index 00000000..26ccb765
--- /dev/null
+++ b/man/io_uring_sqe_set_data.3.md
@@ -0,0 +1,43 @@
+.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: November 15, 2021
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_sqe_set_data
+---
+
+# NAME
+
+io_uring_sqe_set_data - set user data for submission queue event
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_sqe_set_data(struct io_uring_sqe * sqe ,
+ void * user_data );
+
+ void io_uring_sqe_set_data64(struct io_uring_sqe * sqe ,
+ __u64 data );
+
+# DESCRIPTION
+
+The **io_uring_sqe_set_data**(3) function stores a *user_data* pointer with the submission queue entry *sqe*.
+
+The **io_uring_sqe_set_data64**(3) function stores a 64-bit *data* value with the submission queue entry *sqe*.
+
+After the caller has requested a submission queue entry (SQE) with **io_uring_get_sqe**(3)**,** they can associate a data pointer or value with the SQE. Once the completion arrives, the function **io_uring_cqe_get_data**(3) or **io_uring_cqe_get_data64**(3) can be called to retrieve the data pointer or value associated with the submitted request.
+
+Note that if neither of these functions are called, or the *user_data* field in the *sqe* isn\'t set manually either, then the field may contain a value from a previous use of this sqe. If an application relies on always having a valid *user_data* value present, it must always assign one to each sqe.
+
+# RETURN VALUE
+
+None
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_cqe_get_data**(3)
diff --git a/man/io_uring_sqe_set_data64.3 b/man/io_uring_sqe_set_data64.3
deleted file mode 120000
index 8bbd6927..00000000
--- a/man/io_uring_sqe_set_data64.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_sqe_set_data.3
\ No newline at end of file
diff --git a/man/io_uring_sqe_set_flags.3 b/man/io_uring_sqe_set_flags.3
deleted file mode 100644
index ab0bb8e7..00000000
--- a/man/io_uring_sqe_set_flags.3
+++ /dev/null
@@ -1,87 +0,0 @@
-.\" Copyright (C) 2022 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_sqe_set_flags 3 "January 25, 2022" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_sqe_set_flags \- set flags for submission queue entry
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "void io_uring_sqe_set_flags(struct io_uring_sqe *" sqe ","
-.BI " unsigned " flags ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_sqe_set_flags (3)
-function allows the caller to change the behavior of the submission queue entry
-by specifying flags. It enables the
-.I flags
-belonging to the
-.I sqe
-submission queue entry param.
-
-.I flags
-is a bit mask of 0 or more of the following values ORed together:
-.TP
-.B IOSQE_FIXED_FILE
-The file descriptor in the SQE refers to the index of a previously registered
-file or direct file descriptor, not a normal file descriptor.
-.TP
-.B IOSQE_ASYNC
-Normal operation for io_uring is to try and issue an sqe as non-blocking first,
-and if that fails, execute it in an async manner. To support more efficient
-overlapped operation of requests that the application knows/assumes will
-always (or most of the time) block, the application can ask for an sqe to be
-issued async from the start. Note that this flag immediately causes the SQE
-to be offloaded to an async helper thread with no initial non-blocking attempt.
-This may be less efficient and should not be used liberally or without
-understanding the performance and efficiency tradeoffs.
-.TP
-.B IOSQE_IO_LINK
-When this flag is specified, the SQE forms a link with the next SQE in the
-submission ring. That next SQE will not be started before the previous request
-completes. This, in effect, forms a chain of SQEs, which can be arbitrarily
-long. The tail of the chain is denoted by the first SQE that does not have this
-flag set. Chains are not supported across submission boundaries. Even if the
-last SQE in a submission has this flag set, it will still terminate the current
-chain. This flag has no effect on previous SQE submissions, nor does it impact
-SQEs that are outside of the chain tail. This means that multiple chains can be
-executing in parallel, or chains and individual SQEs. Only members inside the
-chain are serialized. A chain of SQEs will be broken if any request in that
-chain ends in error.
-.TP
-.B IOSQE_IO_HARDLINK
-Like
-.B IOSQE_IO_LINK ,
-except the links aren't severed if an error or unexpected result occurs.
-.TP
-.B IOSQE_IO_DRAIN
-When this flag is specified, the SQE will not be started before previously
-submitted SQEs have completed, and new SQEs will not be started before this
-one completes.
-.TP
-.B IOSQE_CQE_SKIP_SUCCESS
-Request that no CQE be generated for this request, if it completes successfully.
-This can be useful in cases where the application doesn't need to know when
-a specific request completed, if it completed successfully.
-.TP
-.B IOSQE_BUFFER_SELECT
-If set, and if the request types supports it, select an IO buffer from the
-indicated buffer group. This can be used with requests that read or receive
-data from a file or socket, where buffer selection is deferred until the kernel
-is ready to transfer data, instead of when the IO is originally submitted. The
-application must also set the
-.I buf_group
-field in the SQE, indicating which previously registered buffer group to select
-a buffer from.
-
-.SH RETURN VALUE
-None
-.SH SEE ALSO
-.BR io_uring_submit (3),
-.BR io_uring_register (3)
-.BR io_uring_register_buffers (3)
-.BR io_uring_register_buf_ring (3)
diff --git a/man/io_uring_sqe_set_flags.3.md b/man/io_uring_sqe_set_flags.3.md
new file mode 100644
index 00000000..1a732bb5
--- /dev/null
+++ b/man/io_uring_sqe_set_flags.3.md
@@ -0,0 +1,64 @@
+.\" Copyright (C) 2022 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 25, 2022
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_sqe_set_flags
+---
+
+# NAME
+
+io_uring_sqe_set_flags - set flags for submission queue entry
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ void io_uring_sqe_set_flags(struct io_uring_sqe * sqe ,
+ unsigned flags );
+
+# DESCRIPTION
+
+The **io_uring_sqe_set_flags**(3) function allows the caller to change the behavior of the submission queue entry by specifying flags. It enables the *flags* belonging to the *sqe* submission queue entry param.
+
+*flags* is a bit mask of 0 or more of the following values ORed together:
+
+**IOSQE_FIXED_FILE**
+
+: The file descriptor in the SQE refers to the index of a previously registered file or direct file descriptor, not a normal file descriptor.
+
+**IOSQE_ASYNC**
+
+: Normal operation for io_uring is to try and issue an sqe as non-blocking first, and if that fails, execute it in an async manner. To support more efficient overlapped operation of requests that the application knows/assumes will always (or most of the time) block, the application can ask for an sqe to be issued async from the start. Note that this flag immediately causes the SQE to be offloaded to an async helper thread with no initial non-blocking attempt. This may be less efficient and should not be used liberally or without understanding the performance and efficiency tradeoffs.
+
+**IOSQE_IO_LINK**
+
+: When this flag is specified, the SQE forms a link with the next SQE in the submission ring. That next SQE will not be started before the previous request completes. This, in effect, forms a chain of SQEs, which can be arbitrarily long. The tail of the chain is denoted by the first SQE that does not have this flag set. Chains are not supported across submission boundaries. Even if the last SQE in a submission has this flag set, it will still terminate the current chain. This flag has no effect on previous SQE submissions, nor does it impact SQEs that are outside of the chain tail. This means that multiple chains can be executing in parallel, or chains and individual SQEs. Only members inside the chain are serialized. A chain of SQEs will be broken if any request in that chain ends in error.
+
+**IOSQE_IO_HARDLINK**
+
+: Like **IOSQE_IO_LINK ,** except the links aren\'t severed if an error or unexpected result occurs.
+
+**IOSQE_IO_DRAIN**
+
+: When this flag is specified, the SQE will not be started before previously submitted SQEs have completed, and new SQEs will not be started before this one completes.
+
+**IOSQE_CQE_SKIP_SUCCESS**
+
+: Request that no CQE be generated for this request, if it completes successfully. This can be useful in cases where the application doesn\'t need to know when a specific request completed, if it completed successfully.
+
+**IOSQE_BUFFER_SELECT**
+
+: If set, and if the request types supports it, select an IO buffer from the indicated buffer group. This can be used with requests that read or receive data from a file or socket, where buffer selection is deferred until the kernel is ready to transfer data, instead of when the IO is originally submitted. The application must also set the *buf_group* field in the SQE, indicating which previously registered buffer group to select a buffer from.
+
+# RETURN VALUE
+
+None
+
+# SEE ALSO
+
+**io_uring_submit**(3), **io_uring_register**(3) **io_uring_register_buffers**(3) **io_uring_register_buf_ring**(3)
diff --git a/man/io_uring_sqpoll.7 b/man/io_uring_sqpoll.7
deleted file mode 100644
index ce24b537..00000000
--- a/man/io_uring_sqpoll.7
+++ /dev/null
@@ -1,259 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_sqpoll 7 "January 18, 2025" "Linux" "Linux Programmer's Manual"
-.SH NAME
-io_uring_sqpoll \- io_uring submission queue polling overview
-.SH DESCRIPTION
-Submission queue polling (SQPOLL) is a mode of operation where an
-io_uring created userspace thread that remains in the kernel monitors
-the submission queue and submits requests on behalf of the application. This eliminates the need for
-the application to make system calls to submit I/O, reducing latency
-and CPU overhead for high-throughput workloads.
-.SS Why use SQPOLL?
-In normal io_uring operation, applications must call
-.BR io_uring_enter (2)
-(typically via
-.BR io_uring_submit (3))
-to notify the kernel of new submissions. While efficient, this still
-incurs system call overhead.
-
-With SQPOLL enabled, the kernel thread continuously polls the
-submission queue for new entries. As soon as the application writes
-an SQE to the ring, the kernel thread picks it up and submits it.
-This provides:
-.IP \(bu 2
-Elimination of submission system call overhead
-.IP \(bu
-Lower and more predictable latency
-.IP \(bu
-Better CPU utilization for high-IOPS workloads
-.PP
-SQPOLL is most beneficial for:
-.IP \(bu 2
-High-throughput storage workloads (NVMe, etc.)
-.IP \(bu
-Latency-sensitive applications
-.IP \(bu
-Workloads with continuous I/O streams
-.IP \(bu
-Applications already running at high CPU utilization
-.SS When SQPOLL may not help
-SQPOLL is not universally beneficial and each use case should be
-benchmarked to determine if it provides value. Situations where
-SQPOLL may not help or may hurt performance:
-.IP \(bu 2
-.B Low-IOPS workloads:
-If the application submits I/O infrequently, the system call overhead
-being saved is negligible, and the polling thread wastes CPU cycles.
-.IP \(bu
-.B CPU-constrained systems:
-The polling thread consumes CPU. If the system is already CPU-bound,
-adding a polling thread may compete with the application for CPU
-resources, reducing overall performance.
-.IP \(bu
-.B Bursty workloads:
-If I/O comes in bursts with idle periods, the polling thread may
-frequently sleep and wake, adding latency when it needs to wake up.
-Regular submission may be more efficient.
-.IP \(bu
-.B Single-threaded applications on single-CPU systems:
-The polling thread and application will compete for the same CPU,
-potentially causing context switches that negate any benefits.
-.IP \(bu
-.B Workloads dominated by completion handling:
-SQPOLL only optimizes submissions. If the application spends most
-of its time processing completions, SQPOLL provides little benefit.
-.PP
-Always benchmark with and without SQPOLL under realistic conditions.
-The performance difference can vary significantly based on hardware,
-kernel version, and workload characteristics.
-.SS Enabling SQPOLL
-SQPOLL is enabled by setting the
-.B IORING_SETUP_SQPOLL
-flag when creating the ring:
-.PP
-.in +4n
-.EX
-struct io_uring ring;
-struct io_uring_params params = {
- .flags = IORING_SETUP_SQPOLL,
- .sq_thread_idle = 2000, /* 2 seconds */
-};
-
-ret = io_uring_queue_init_params(entries, &ring, ¶ms);
-.EE
-.in
-.PP
-The
-.I sq_thread_idle
-field specifies how long (in milliseconds) the kernel thread will
-poll before going to sleep if no submissions are pending. A value of
-0 means the thread never sleeps (uses more CPU but provides lowest
-latency).
-.SS The polling thread lifecycle
-When the ring is created with SQPOLL, a kernel thread is spawned to
-service it. The thread's behavior is:
-.IP 1. 4
-Poll the submission queue for new entries
-.IP 2.
-Submit any new requests found
-.IP 3.
-If no new entries are found for
-.I sq_thread_idle
-milliseconds, go to sleep
-.IP 4.
-Wake up when signaled by the application
-.PP
-The application can check if the thread is sleeping by examining
-.I sq->kflags
-for the
-.B IORING_SQ_NEED_WAKEUP
-flag using
-.BR io_uring_sq_ready (3).
-If set, the application must call
-.BR io_uring_enter (2)
-with
-.B IORING_ENTER_SQ_WAKEUP
-to wake the thread:
-.PP
-.in +4n
-.EX
-/* After adding SQEs */
-io_uring_smp_store_release(ring->sq.ktail, tail);
-
-if (IO_URING_READ_ONCE(*ring->sq.kflags) & IORING_SQ_NEED_WAKEUP)
- io_uring_enter(ring->ring_fd, 0, 0, IORING_ENTER_SQ_WAKEUP, NULL);
-.EE
-.in
-.PP
-The
-.BR io_uring_submit (3)
-function handles this automatically.
-.SS CPU affinity
-By default, the kernel schedules the polling thread on any available
-CPU. For better cache locality and reduced latency, the thread can be
-pinned to a specific CPU:
-.PP
-.in +4n
-.EX
-struct io_uring_params params = {
- .flags = IORING_SETUP_SQPOLL | IORING_SETUP_SQ_AFF,
- .sq_thread_cpu = 3, /* pin to CPU 3 */
- .sq_thread_idle = 1000,
-};
-.EE
-.in
-.PP
-The
-.B IORING_SETUP_SQ_AFF
-flag enables CPU affinity, and
-.I sq_thread_cpu
-specifies which CPU to use.
-.SS Credential requirements
-Creating an SQPOLL ring traditionally required elevated privileges
-because the kernel thread runs on behalf of the application. The
-requirements have evolved:
-.IP \(bu 2
-Kernel 5.11 and earlier: requires
-.B CAP_SYS_ADMIN
-or
-.B CAP_SYS_NICE
-.IP \(bu
-Kernel 5.12 and later: unprivileged users can create SQPOLL rings,
-but the polling thread runs with reduced capabilities
-.IP \(bu
-The
-.B IORING_SETUP_NO_SQARRAY
-flag (kernel 6.6+) can simplify setup for SQPOLL-only rings
-.SS Sharing the polling thread
-Multiple rings can share a single polling thread using
-.BR IORING_SETUP_ATTACH_WQ .
-This reduces resource usage when an application uses multiple rings:
-.PP
-.in +4n
-.EX
-/* Create first ring with SQPOLL */
-struct io_uring_params p1 = { .flags = IORING_SETUP_SQPOLL };
-io_uring_queue_init_params(entries, &ring1, &p1);
-
-/* Create second ring, attach to first ring's thread */
-struct io_uring_params p2 = {
- .flags = IORING_SETUP_SQPOLL | IORING_SETUP_ATTACH_WQ,
- .wq_fd = ring1.ring_fd,
-};
-io_uring_queue_init_params(entries, &ring2, &p2);
-.EE
-.in
-.SS Completion handling
-SQPOLL only affects submissions. Completions are still handled
-normally \(em the application must either:
-.IP \(bu 2
-Poll the completion queue directly (busy-wait)
-.IP \(bu
-Use
-.BR io_uring_enter (2)
-with
-.B IORING_ENTER_GETEVENTS
-to wait for completions
-.IP \(bu
-Use an eventfd for notification
-.PP
-For full polling on both submission and completion, combine SQPOLL
-with completion queue polling using
-.BR io_uring_peek_cqe (3)
-or similar functions.
-.SS Performance considerations
-.IP \(bu 2
-.B CPU usage:
-The polling thread consumes CPU while active. If I/O is sporadic,
-the thread may waste cycles polling an empty queue. Set
-.I sq_thread_idle
-appropriately for your workload.
-.IP \(bu
-.B Idle timeout tradeoff:
-A shorter idle timeout saves CPU but may increase latency when the
-thread needs to wake up. A longer timeout (or 0 for never sleeping)
-uses more CPU but provides consistent low latency.
-.IP \(bu
-.B Batching:
-Even with SQPOLL, batching submissions by adding multiple SQEs before
-updating the tail pointer can improve throughput.
-.IP \(bu
-.B CPU affinity:
-Pinning the polling thread to a CPU near the application's CPU can
-improve cache behavior and reduce cross-CPU communication.
-.SH NOTES
-.IP \(bu 2
-The polling thread is per-ring (unless shared via
-.BR IORING_SETUP_ATTACH_WQ ).
-Creating many SQPOLL rings without sharing can consume significant
-kernel resources.
-.IP \(bu
-SQPOLL rings still require system calls for:
-.RS 4
-.IP \(bu 2
-Waiting for completions (unless busy-polling the CQ)
-.IP \(bu
-Waking the thread when it has gone idle
-.IP \(bu
-Registration operations
-.RE
-.IP \(bu
-The polling thread inherits resource limits and cgroup membership
-from the creating process.
-.IP \(bu
-If the polling thread encounters an error it cannot recover from,
-.B IORING_SQ_CQ_OVERFLOW
-may be set in
-.IR sq->kflags .
-.IP \(bu
-SQPOLL works well in combination with registered files and buffers,
-which further reduce per-I/O overhead.
-.SH SEE ALSO
-.BR io_uring (7),
-.BR io_uring_setup (2),
-.BR io_uring_enter (2),
-.BR io_uring_queue_init_params (3),
-.BR io_uring_register_files (3),
-.BR io_uring_registered_buffers (7)
diff --git a/man/io_uring_sqpoll.7.md b/man/io_uring_sqpoll.7.md
new file mode 100644
index 00000000..fc3cee6f
--- /dev/null
+++ b/man/io_uring_sqpoll.7.md
@@ -0,0 +1,173 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: Linux
+header: Linux Programmer\'s Manual
+section: 7
+title: io_uring_sqpoll
+---
+
+# NAME
+
+io_uring_sqpoll - io_uring submission queue polling overview
+
+# DESCRIPTION
+
+Submission queue polling (SQPOLL) is a mode of operation where an io_uring created userspace thread that remains in the kernel monitors the submission queue and submits requests on behalf of the application. This eliminates the need for the application to make system calls to submit I/O, reducing latency and CPU overhead for high-throughput workloads.
+
+## Why use SQPOLL?
+
+In normal io_uring operation, applications must call **io_uring_enter**(2) (typically via **io_uring_submit**(3)) to notify the kernel of new submissions. While efficient, this still incurs system call overhead.
+
+With SQPOLL enabled, the kernel thread continuously polls the submission queue for new entries. As soon as the application writes an SQE to the ring, the kernel thread picks it up and submits it. This provides:
+
+- Elimination of submission system call overhead
+
+- Lower and more predictable latency
+
+- Better CPU utilization for high-IOPS workloads
+
+SQPOLL is most beneficial for:
+
+- High-throughput storage workloads (NVMe, etc.)
+
+- Latency-sensitive applications
+
+- Workloads with continuous I/O streams
+
+- Applications already running at high CPU utilization
+
+## When SQPOLL may not help
+
+SQPOLL is not universally beneficial and each use case should be benchmarked to determine if it provides value. Situations where SQPOLL may not help or may hurt performance:
+
+- **Low-IOPS workloads:** If the application submits I/O infrequently, the system call overhead being saved is negligible, and the polling thread wastes CPU cycles.
+
+- **CPU-constrained systems:** The polling thread consumes CPU. If the system is already CPU-bound, adding a polling thread may compete with the application for CPU resources, reducing overall performance.
+
+- **Bursty workloads:** If I/O comes in bursts with idle periods, the polling thread may frequently sleep and wake, adding latency when it needs to wake up. Regular submission may be more efficient.
+
+- **Single-threaded applications on single-CPU systems:** The polling thread and application will compete for the same CPU, potentially causing context switches that negate any benefits.
+
+- **Workloads dominated by completion handling:** SQPOLL only optimizes submissions. If the application spends most of its time processing completions, SQPOLL provides little benefit.
+
+Always benchmark with and without SQPOLL under realistic conditions. The performance difference can vary significantly based on hardware, kernel version, and workload characteristics.
+
+## Enabling SQPOLL
+
+SQPOLL is enabled by setting the **IORING_SETUP_SQPOLL** flag when creating the ring:
+
+ struct io_uring ring;
+ struct io_uring_params params = {
+ .flags = IORING_SETUP_SQPOLL,
+ .sq_thread_idle = 2000, /* 2 seconds */
+ };
+
+ ret = io_uring_queue_init_params(entries, &ring, ¶ms);
+
+The *sq_thread_idle* field specifies how long (in milliseconds) the kernel thread will poll before going to sleep if no submissions are pending. A value of 0 means the thread never sleeps (uses more CPU but provides lowest latency).
+
+## The polling thread lifecycle
+
+When the ring is created with SQPOLL, a kernel thread is spawned to service it. The thread\'s behavior is:
+
+1. Poll the submission queue for new entries
+
+2. Submit any new requests found
+
+3. If no new entries are found for *sq_thread_idle* milliseconds, go to sleep
+
+4. Wake up when signaled by the application
+
+The application can check if the thread is sleeping by examining *sq-\>kflags* for the **IORING_SQ_NEED_WAKEUP** flag using **io_uring_sq_ready**(3). If set, the application must call **io_uring_enter**(2) with **IORING_ENTER_SQ_WAKEUP** to wake the thread:
+
+ /* After adding SQEs */
+ io_uring_smp_store_release(ring->sq.ktail, tail);
+
+ if (IO_URING_READ_ONCE(*ring->sq.kflags) & IORING_SQ_NEED_WAKEUP)
+ io_uring_enter(ring->ring_fd, 0, 0, IORING_ENTER_SQ_WAKEUP, NULL);
+
+The **io_uring_submit**(3) function handles this automatically.
+
+## CPU affinity
+
+By default, the kernel schedules the polling thread on any available CPU. For better cache locality and reduced latency, the thread can be pinned to a specific CPU:
+
+ struct io_uring_params params = {
+ .flags = IORING_SETUP_SQPOLL | IORING_SETUP_SQ_AFF,
+ .sq_thread_cpu = 3, /* pin to CPU 3 */
+ .sq_thread_idle = 1000,
+ };
+
+The **IORING_SETUP_SQ_AFF** flag enables CPU affinity, and *sq_thread_cpu* specifies which CPU to use.
+
+## Credential requirements
+
+Creating an SQPOLL ring traditionally required elevated privileges because the kernel thread runs on behalf of the application. The requirements have evolved:
+
+- Kernel 5.11 and earlier: requires **CAP_SYS_ADMIN** or **CAP_SYS_NICE**
+
+- Kernel 5.12 and later: unprivileged users can create SQPOLL rings, but the polling thread runs with reduced capabilities
+
+- The **IORING_SETUP_NO_SQARRAY** flag (kernel 6.6+) can simplify setup for SQPOLL-only rings
+
+## Sharing the polling thread
+
+Multiple rings can share a single polling thread using **IORING_SETUP_ATTACH_WQ**. This reduces resource usage when an application uses multiple rings:
+
+ /* Create first ring with SQPOLL */
+ struct io_uring_params p1 = { .flags = IORING_SETUP_SQPOLL };
+ io_uring_queue_init_params(entries, &ring1, &p1);
+
+ /* Create second ring, attach to first ring's thread */
+ struct io_uring_params p2 = {
+ .flags = IORING_SETUP_SQPOLL | IORING_SETUP_ATTACH_WQ,
+ .wq_fd = ring1.ring_fd,
+ };
+ io_uring_queue_init_params(entries, &ring2, &p2);
+
+## Completion handling
+
+SQPOLL only affects submissions. Completions are still handled normally --- the application must either:
+
+- Poll the completion queue directly (busy-wait)
+
+- Use **io_uring_enter**(2) with **IORING_ENTER_GETEVENTS** to wait for completions
+
+- Use an eventfd for notification
+
+For full polling on both submission and completion, combine SQPOLL with completion queue polling using **io_uring_peek_cqe**(3) or similar functions.
+
+## Performance considerations
+
+- **CPU usage:** The polling thread consumes CPU while active. If I/O is sporadic, the thread may waste cycles polling an empty queue. Set *sq_thread_idle* appropriately for your workload.
+
+- **Idle timeout tradeoff:** A shorter idle timeout saves CPU but may increase latency when the thread needs to wake up. A longer timeout (or 0 for never sleeping) uses more CPU but provides consistent low latency.
+
+- **Batching:** Even with SQPOLL, batching submissions by adding multiple SQEs before updating the tail pointer can improve throughput.
+
+- **CPU affinity:** Pinning the polling thread to a CPU near the application\'s CPU can improve cache behavior and reduce cross-CPU communication.
+
+# NOTES
+
+- The polling thread is per-ring (unless shared via **IORING_SETUP_ATTACH_WQ**). Creating many SQPOLL rings without sharing can consume significant kernel resources.
+
+- SQPOLL rings still require system calls for:
+
+ - Waiting for completions (unless busy-polling the CQ)
+
+ - Waking the thread when it has gone idle
+
+ - Registration operations
+
+- The polling thread inherits resource limits and cgroup membership from the creating process.
+
+- If the polling thread encounters an error it cannot recover from, **IORING_SQ_CQ_OVERFLOW** may be set in *sq-\>kflags*.
+
+- SQPOLL works well in combination with registered files and buffers, which further reduce per-I/O overhead.
+
+# SEE ALSO
+
+**io_uring**(7), **io_uring_setup**(2), **io_uring_enter**(2), **io_uring_queue_init_params**(3), **io_uring_register_files**(3), **io_uring_registered_buffers**(7)
diff --git a/man/io_uring_sqring_wait.3 b/man/io_uring_sqring_wait.3
deleted file mode 100644
index 4d3a5676..00000000
--- a/man/io_uring_sqring_wait.3
+++ /dev/null
@@ -1,34 +0,0 @@
-.\" Copyright (C) 2022 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_sqring_wait 3 "January 25, 2022" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_sqring_wait \- wait for free space in the SQ ring
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_sqring_wait(struct io_uring *" ring ");"
-.fi
-.SH DESCRIPTION
-.PP
-The function
-.BR io_uring_sqring_wait (3)
-allows the caller to wait for space to free up in the SQ ring belonging to the
-.I ring
-param, which happens when the kernel side thread
-has consumed one or more entries. If the SQ ring is currently non-full,
-no action is taken.
-
-This feature can only be used when the ring has been setup with
-.B IORING_SETUP_SQPOLL
-and hence is using an offloaded approach to request submissions.
-
-.SH RETURN VALUE
-On success it returns the free space. If the kernel does not support the
-feature, -EINVAL is returned.
-.SH SEE ALSO
-.BR io_uring_submit (3),
-.BR io_uring_wait_cqe (3),
-.BR io_uring_wait_cqes (3)
diff --git a/man/io_uring_sqring_wait.3.md b/man/io_uring_sqring_wait.3.md
new file mode 100644
index 00000000..a87f567d
--- /dev/null
+++ b/man/io_uring_sqring_wait.3.md
@@ -0,0 +1,35 @@
+.\" Copyright (C) 2022 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 25, 2022
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_sqring_wait
+---
+
+# NAME
+
+io_uring_sqring_wait - wait for free space in the SQ ring
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_sqring_wait(struct io_uring * ring );
+
+# DESCRIPTION
+
+The function **io_uring_sqring_wait**(3) allows the caller to wait for space to free up in the SQ ring belonging to the *ring* param, which happens when the kernel side thread has consumed one or more entries. If the SQ ring is currently non-full, no action is taken.
+
+This feature can only be used when the ring has been setup with **IORING_SETUP_SQPOLL** and hence is using an offloaded approach to request submissions.
+
+# RETURN VALUE
+
+On success it returns the free space. If the kernel does not support the feature, -EINVAL is returned.
+
+# SEE ALSO
+
+**io_uring_submit**(3), **io_uring_wait_cqe**(3), **io_uring_wait_cqes**(3)
diff --git a/man/io_uring_submit.3 b/man/io_uring_submit.3
deleted file mode 100644
index c7dbbed2..00000000
--- a/man/io_uring_submit.3
+++ /dev/null
@@ -1,51 +0,0 @@
-.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_submit 3 "November 15, 2021" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_submit \- submit requests to the submission queue
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_submit(struct io_uring *" ring ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_submit (3)
-function submits the next events to the submission queue belonging to the
-.IR ring .
-
-After the caller retrieves a submission queue entry (SQE) with
-.BR io_uring_get_sqe (3)
-and prepares the SQE using one of the provided helpers, it can be submitted with
-.BR io_uring_submit (3) .
-
-.SH RETURN VALUE
-On success
-.BR io_uring_submit (3)
-returns the number of submitted submission queue entries, if SQPOLL is not used.
-If SQPOLL is used, the return value may report a higher number of submitted
-entries than actually submitted. If the user requires accurate information
-about how many submission queue entries have been successfully submitted, while
-using SQPOLL, the user must fall back to repeatedly submitting a single submission
-queue entry. On failure it returns
-.BR -errno .
-.SH NOTES
-For any request that passes in data in a struct, that data must remain
-valid until the request has been successfully submitted. It need not remain
-valid until completion. Once a request has been submitted, the in-kernel
-state is stable. Very early kernels (5.4 and earlier) required state to be
-stable until the completion occurred. Applications can test for this
-behavior by inspecting the
-.B IORING_FEAT_SUBMIT_STABLE
-flag passed back from
-.BR io_uring_queue_init_params (3).
-In general, the man pages for the individual prep helpers will have a note
-mentioning this fact as well, if required for the given command.
-.SH SEE ALSO
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit_and_wait (3),
-.BR io_uring_submit_and_wait_timeout (3)
diff --git a/man/io_uring_submit.3.md b/man/io_uring_submit.3.md
new file mode 100644
index 00000000..c286d41a
--- /dev/null
+++ b/man/io_uring_submit.3.md
@@ -0,0 +1,39 @@
+.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: November 15, 2021
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_submit
+---
+
+# NAME
+
+io_uring_submit - submit requests to the submission queue
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_submit(struct io_uring * ring );
+
+# DESCRIPTION
+
+The **io_uring_submit**(3) function submits the next events to the submission queue belonging to the *ring*.
+
+After the caller retrieves a submission queue entry (SQE) with **io_uring_get_sqe**(3) and prepares the SQE using one of the provided helpers, it can be submitted with **io_uring_submit**(3)**.**
+
+# RETURN VALUE
+
+On success **io_uring_submit**(3) returns the number of submitted submission queue entries, if SQPOLL is not used. If SQPOLL is used, the return value may report a higher number of submitted entries than actually submitted. If the user requires accurate information about how many submission queue entries have been successfully submitted, while using SQPOLL, the user must fall back to repeatedly submitting a single submission queue entry. On failure it returns **-errno**.
+
+# NOTES
+
+For any request that passes in data in a struct, that data must remain valid until the request has been successfully submitted. It need not remain valid until completion. Once a request has been submitted, the in-kernel state is stable. Very early kernels (5.4 and earlier) required state to be stable until the completion occurred. Applications can test for this behavior by inspecting the **IORING_FEAT_SUBMIT_STABLE** flag passed back from **io_uring_queue_init_params**(3). In general, the man pages for the individual prep helpers will have a note mentioning this fact as well, if required for the given command.
+
+# SEE ALSO
+
+**io_uring_get_sqe**(3), **io_uring_submit_and_wait**(3), **io_uring_submit_and_wait_timeout**(3)
diff --git a/man/io_uring_submit_and_get_events.3 b/man/io_uring_submit_and_get_events.3
deleted file mode 100644
index 9e143d1d..00000000
--- a/man/io_uring_submit_and_get_events.3
+++ /dev/null
@@ -1,31 +0,0 @@
-.\" Copyright (C), 2022 dylany
-.\" You may distribute this file under the terms of the GNU Free
-.\" Documentation License.
-.TH io_uring_submit_and_get_events 3 "September 5, 2022" "liburing-2.3" "liburing Manual"
-.SH NAME
-io_uring_submit_and_get_events \- submit requests to the submission queue and flush completions
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_submit_and_get_events(struct io_uring *" ring ");"
-.fi
-
-.SH DESCRIPTION
-The
-.BR io_uring_submit_and_get_events (3)
-function submits the next events to the submission queue as with
-.BR io_uring_submit (3) .
-After submission it will flush CQEs as with
-.BR io_uring_get_events (3) .
-
-The benefit of this function is that it does both with only one system call.
-
-.SH RETURN VALUE
-On success
-.BR io_uring_submit_and_get_events (3)
-returns the number of submitted submission queue entries. On failure it returns
-.BR -errno .
-.SH SEE ALSO
-.BR io_uring_submit (3),
-.BR io_uring_get_events (3)
diff --git a/man/io_uring_submit_and_get_events.3.md b/man/io_uring_submit_and_get_events.3.md
new file mode 100644
index 00000000..7583c78c
--- /dev/null
+++ b/man/io_uring_submit_and_get_events.3.md
@@ -0,0 +1,34 @@
+.\" Copyright (C), 2022 dylany
+.\" You may distribute this file under the terms of the GNU Free
+.\" Documentation License.
+---
+date: September 5, 2022
+footer: liburing-2.3
+header: liburing Manual
+section: 3
+title: io_uring_submit_and_get_events
+---
+
+# NAME
+
+io_uring_submit_and_get_events - submit requests to the submission queue and flush completions
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_submit_and_get_events(struct io_uring * ring );
+
+# DESCRIPTION
+
+The **io_uring_submit_and_get_events**(3) function submits the next events to the submission queue as with **io_uring_submit**(3)**.** After submission it will flush CQEs as with **io_uring_get_events**(3)**.**
+
+The benefit of this function is that it does both with only one system call.
+
+# RETURN VALUE
+
+On success **io_uring_submit_and_get_events**(3) returns the number of submitted submission queue entries. On failure it returns **-errno**.
+
+# SEE ALSO
+
+**io_uring_submit**(3), **io_uring_get_events**(3)
diff --git a/man/io_uring_submit_and_wait.3 b/man/io_uring_submit_and_wait.3
deleted file mode 100644
index 2351f335..00000000
--- a/man/io_uring_submit_and_wait.3
+++ /dev/null
@@ -1,44 +0,0 @@
-.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_submit_and_wait 3 "November 15, 2021" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_submit_and_wait \- submit requests to the submission queue and wait for completion
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_submit_and_wait(struct io_uring *" ring ","
-.BI " unsigned " wait_nr ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_submit_and_wait (3)
-function submits the next requests from the submission queue belonging to the
-.I ring
-and waits for
-.I wait_nr
-completion events.
-
-After the caller retrieves a submission queue entry (SQE) with
-.BR io_uring_get_sqe (3)
-and prepares the SQE, it can be submitted with
-.BR io_uring_submit_and_wait (3) .
-
-Ideally used with a ring setup with
-.BR IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN
-as that will greatly reduce the number of context switches that an application
-will see waiting on multiple requests.
-
-.SH RETURN VALUE
-On success
-.BR io_uring_submit_and_wait (3)
-returns the number of submitted submission queue entries. On failure it returns
-.BR -errno .
-.SH SEE ALSO
-.BR io_uring_queue_init_params (3),
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_submit_and_wait_timeout (3)
diff --git a/man/io_uring_submit_and_wait.3.md b/man/io_uring_submit_and_wait.3.md
new file mode 100644
index 00000000..0cb019a9
--- /dev/null
+++ b/man/io_uring_submit_and_wait.3.md
@@ -0,0 +1,38 @@
+.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: November 15, 2021
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_submit_and_wait
+---
+
+# NAME
+
+io_uring_submit_and_wait - submit requests to the submission queue and wait for completion
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_submit_and_wait(struct io_uring * ring ,
+ unsigned wait_nr );
+
+# DESCRIPTION
+
+The **io_uring_submit_and_wait**(3) function submits the next requests from the submission queue belonging to the *ring* and waits for *wait_nr* completion events.
+
+After the caller retrieves a submission queue entry (SQE) with **io_uring_get_sqe**(3) and prepares the SQE, it can be submitted with **io_uring_submit_and_wait**(3)**.**
+
+Ideally used with a ring setup with **IORING_SETUP_SINGLE_ISSUER**\|**IORING_SETUP_DEFER_TASKRUN** as that will greatly reduce the number of context switches that an application will see waiting on multiple requests.
+
+# RETURN VALUE
+
+On success **io_uring_submit_and_wait**(3) returns the number of submitted submission queue entries. On failure it returns **-errno**.
+
+# SEE ALSO
+
+**io_uring_queue_init_params**(3), **io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_submit_and_wait_timeout**(3)
diff --git a/man/io_uring_submit_and_wait_min_timeout.3 b/man/io_uring_submit_and_wait_min_timeout.3
deleted file mode 100644
index 6a52806f..00000000
--- a/man/io_uring_submit_and_wait_min_timeout.3
+++ /dev/null
@@ -1,119 +0,0 @@
-.\" Copyright (C) 2024 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_submit_and_wait_min_timeout 3 "Jan 11, 2024" "liburing-2.8" "liburing Manual"
-.SH NAME
-io_uring_submit_and_wait_min_timeout \- submit requests to the submission queue and
-wait for the completion with both batch and normal timeout
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_submit_and_wait_min_timeout(struct io_uring *" ring ","
-.BI " struct io_uring_cqe **" cqe_ptr ","
-.BI " unsigned " wait_nr ","
-.BI " struct __kernel_timespec *" ts ","
-.BI " unsigned int " min_wait_usec ",
-.BI " sigset_t *" sigmask ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_submit_and_wait_min_timeout (3)
-function submits the next requests from the submission queue belonging to the
-.I ring
-and waits for
-.I wait_nr
-completion events, or until the timeout
-.I ts
-expires. The completion events are stored in the
-.I cqe_ptr
-array. If non-zero,
-.I min_wait_usec
-denotes a timeout for the
-.I wait_nr
-batch.
-
-The
-.I sigmask
-specifies the set of signals to block. If set, it is equivalent to atomically
-executing the following calls:
-.PP
-.in +4n
-.EX
-sigset_t origmask;
-
-pthread_sigmask(SIG_SETMASK, &sigmask, &origmask);
-ret = io_uring_submit_and_wait_min_timeout(ring, cqe, wait_nr, ts, min_wait, NULL);
-pthread_sigmask(SIG_SETMASK, &origmask, NULL);
-.EE
-.in
-.PP
-This works like
-.BR io_uring_submit_and_wait_timeout (3)
-with the twist that it applies a minimum timeout for the requested batch size
-of requests to wait for. While
-.BR io_uring_submit_and_wait_timeout (3)
-waits for as long as
-.IR ts
-specifies, or until
-.IR wait_nr
-of request completions have been received, if
-.IR min_wait_usec
-is set, then this is the timeout for the
-.IR wait_nr
-number of requests. If the requested number of completions have been received
-within
-.IR min_wait_usec
-number of microseconds, then the function returns successfully. If that isn't
-the case, once
-.IR min_wait_usec
-time has passed, control is returned if any completions have been posted. If
-no completions have been posted, the kernel switches to a normal wait of up
-to
-.IR ts
-specified amount of time, subtracting the time already waited. If any
-completions are posted after this happens, control is returned immediately to
-the application.
-
-This differs from the normal timeout waiting in that waiting continues post
-the initial timeout, if and only if no completions have been posted. It's meant
-to be used to optimize batch waiting for requests, where the application
-allots a budget of
-.IR min_wait_usec
-amount of time to receive
-.IR wait_nr
-number of completions, but if none are received, then waiting can continue
-without incurring extra context switches or extra kernel/user transitions.
-
-Can be used with any ring, as long as the kernel supports it. Support is
-indicated by checking the
-.BR IORING_FEAT_MIN_TIMEOUT
-feature flag after the ring has been setup. Ideally used with a ring setup
-with
-.BR IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN
-as that will greatly reduce the number of context switches that an application
-will see waiting on multiple requests.
-
-Available since 6.12.
-
-.SH RETURN VALUE
-On success
-.BR io_uring_submit_and_wait_min_timeout (3)
-returns the number of submitted submission queue entries. On failure it returns
-.BR -errno .
-If the kernel doesn't support this functionality,
-.BR -EINVAL
-will be returned. See note on the feature flag.
-The most common failure case is not receiving a completion within the specified
-timeout,
-.B -ETIME
-is returned in this case.
-.SH SEE ALSO
-.BR io_uring_queue_init_params (3),
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_submit_and_wait (3),
-.BR io_uring_submit_and_wait_timeout (3),
-.BR io_uring_wait_cqe (3)
diff --git a/man/io_uring_submit_and_wait_min_timeout.3.md b/man/io_uring_submit_and_wait_min_timeout.3.md
new file mode 100644
index 00000000..c2f07729
--- /dev/null
+++ b/man/io_uring_submit_and_wait_min_timeout.3.md
@@ -0,0 +1,54 @@
+.\" Copyright (C) 2024 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: Jan 11, 2024
+footer: liburing-2.8
+header: liburing Manual
+section: 3
+title: io_uring_submit_and_wait_min_timeout
+---
+
+# NAME
+
+io_uring_submit_and_wait_min_timeout - submit requests to the submission queue and wait for the completion with both batch and normal timeout
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ 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 int min_wait_usec ,
+ sigset_t * sigmask );
+
+# DESCRIPTION
+
+The **io_uring_submit_and_wait_min_timeout**(3) function submits the next requests from the submission queue belonging to the *ring* and waits for *wait_nr* completion events, or until the timeout *ts* expires. The completion events are stored in the *cqe_ptr* array. If non-zero, *min_wait_usec* denotes a timeout for the *wait_nr* batch.
+
+The *sigmask* specifies the set of signals to block. If set, it is equivalent to atomically executing the following calls:
+
+ sigset_t origmask;
+
+ pthread_sigmask(SIG_SETMASK, &sigmask, &origmask);
+ ret = io_uring_submit_and_wait_min_timeout(ring, cqe, wait_nr, ts, min_wait, NULL);
+ pthread_sigmask(SIG_SETMASK, &origmask, NULL);
+
+This works like **io_uring_submit_and_wait_timeout**(3) with the twist that it applies a minimum timeout for the requested batch size of requests to wait for. While **io_uring_submit_and_wait_timeout**(3) waits for as long as *ts* specifies, or until *wait_nr* of request completions have been received, if *min_wait_usec* is set, then this is the timeout for the *wait_nr* number of requests. If the requested number of completions have been received within *min_wait_usec* number of microseconds, then the function returns successfully. If that isn\'t the case, once *min_wait_usec* time has passed, control is returned if any completions have been posted. If no completions have been posted, the kernel switches to a normal wait of up to *ts* specified amount of time, subtracting the time already waited. If any completions are posted after this happens, control is returned immediately to the application.
+
+This differs from the normal timeout waiting in that waiting continues post the initial timeout, if and only if no completions have been posted. It\'s meant to be used to optimize batch waiting for requests, where the application allots a budget of *min_wait_usec* amount of time to receive *wait_nr* number of completions, but if none are received, then waiting can continue without incurring extra context switches or extra kernel/user transitions.
+
+Can be used with any ring, as long as the kernel supports it. Support is indicated by checking the **IORING_FEAT_MIN_TIMEOUT** feature flag after the ring has been setup. Ideally used with a ring setup with **IORING_SETUP_SINGLE_ISSUER**\|**IORING_SETUP_DEFER_TASKRUN** as that will greatly reduce the number of context switches that an application will see waiting on multiple requests.
+
+Available since 6.12.
+
+# RETURN VALUE
+
+On success **io_uring_submit_and_wait_min_timeout**(3) returns the number of submitted submission queue entries. On failure it returns **-errno**. If the kernel doesn\'t support this functionality, **-EINVAL** will be returned. See note on the feature flag. The most common failure case is not receiving a completion within the specified timeout, **-ETIME** is returned in this case.
+
+# SEE ALSO
+
+**io_uring_queue_init_params**(3), **io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_submit_and_wait**(3), **io_uring_submit_and_wait_timeout**(3), **io_uring_wait_cqe**(3)
diff --git a/man/io_uring_submit_and_wait_reg.3 b/man/io_uring_submit_and_wait_reg.3
deleted file mode 100644
index fc0bd76a..00000000
--- a/man/io_uring_submit_and_wait_reg.3
+++ /dev/null
@@ -1,64 +0,0 @@
-.\" Copyright (C) 2024 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_submit_and_wait_reg 3 "November 2, 2024" "liburing-2.9" "liburing Manual"
-.SH NAME
-io_uring_submit_and_wait_reg \- Sets up and registers fixed wait regions
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_submit_and_wait_reg(struct io_uring *" ring ","
-.BI " struct io_uring_cqe **"cqe_ptr ","
-.BI " unsigned "wait_nr ","
-.BI " int "reg_index ");"
-.PP
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_submit_and_wait_reg (3)
-submits previously prepared requests in the ring
-.IR ring
-and waits for
-.IR wait_nr
-completions using the registered wait index of
-.IR reg_index .
-Upon successful return, the completion events are stored in the
-.IR cqe_ptr
-array.
-
-This function works like
-.BR io_uring_submit_and_wait_min_timeout (3)
-in that it supports all the features of that helper, but rather than pass in
-all the information in a struct that needs copying, it references a registered
-wait index for which previously registered wait region holds information
-about how the wait should be performed. That includes information such as
-the overall timeout, the minimum timeout to be used, and so forth. See
-.BR io_uring_setup_register_region (3)
-for the details on registered regions, specifically for registered wait
-regions.
-
-Using registered wait regions has less overhead then other wait methods, as
-no copying of data is needed.
-
-It's valid to use this function purely for waiting on events, even if no
-new requests should be submitted.
-
-.SH RETURN VALUE
-On success
-.BR io_uring_submit_and_wait_reg (3)
-returns the number of new requests submitted. On failure it returns
-.BR -errno .
-If the kernel doesn't support this functionality,
-.BR -EINVAL
-will be returned. If no events are submitted and the wait operation times
-out, then
-.BR -ETIME
-will be returned.
-
-.SH SEE ALSO
-.BR io_uring_register_region (3) ,
-.BR io_uring_submit_and_wait_min_timeout (3) ,
-.BR io_uring_submit_and_wait_timeout (3)
diff --git a/man/io_uring_submit_and_wait_reg.3.md b/man/io_uring_submit_and_wait_reg.3.md
new file mode 100644
index 00000000..edcee717
--- /dev/null
+++ b/man/io_uring_submit_and_wait_reg.3.md
@@ -0,0 +1,42 @@
+.\" Copyright (C) 2024 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: November 2, 2024
+footer: liburing-2.9
+header: liburing Manual
+section: 3
+title: io_uring_submit_and_wait_reg
+---
+
+# NAME
+
+io_uring_submit_and_wait_reg - Sets up and registers fixed wait regions
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_submit_and_wait_reg(struct io_uring * ring ,
+ struct io_uring_cqe **cqe_ptr ,
+ unsigned wait_nr ,
+ int reg_index );
+
+# DESCRIPTION
+
+The **io_uring_submit_and_wait_reg**(3) submits previously prepared requests in the ring *ring* and waits for *wait_nr* completions using the registered wait index of *reg_index*. Upon successful return, the completion events are stored in the *cqe_ptr* array.
+
+This function works like **io_uring_submit_and_wait_min_timeout**(3) in that it supports all the features of that helper, but rather than pass in all the information in a struct that needs copying, it references a registered wait index for which previously registered wait region holds information about how the wait should be performed. That includes information such as the overall timeout, the minimum timeout to be used, and so forth. See **io_uring_setup_register_region**(3) for the details on registered regions, specifically for registered wait regions.
+
+Using registered wait regions has less overhead then other wait methods, as no copying of data is needed.
+
+It\'s valid to use this function purely for waiting on events, even if no new requests should be submitted.
+
+# RETURN VALUE
+
+On success **io_uring_submit_and_wait_reg**(3) returns the number of new requests submitted. On failure it returns **-errno**. If the kernel doesn\'t support this functionality, **-EINVAL** will be returned. If no events are submitted and the wait operation times out, then **-ETIME** will be returned.
+
+# SEE ALSO
+
+**io_uring_register_region**(3)**,** **io_uring_submit_and_wait_min_timeout**(3)**,** **io_uring_submit_and_wait_timeout**(3)
diff --git a/man/io_uring_submit_and_wait_timeout.3 b/man/io_uring_submit_and_wait_timeout.3
deleted file mode 100644
index 74611766..00000000
--- a/man/io_uring_submit_and_wait_timeout.3
+++ /dev/null
@@ -1,74 +0,0 @@
-.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_submit_and_wait_timeout 3 "November 15, 2021" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_submit_and_wait_timeout \- submit requests to the submission queue and
-wait for the completion with timeout
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_submit_and_wait_timeout(struct io_uring *" ring ","
-.BI " struct io_uring_cqe **" cqe_ptr ","
-.BI " unsigned " wait_nr ","
-.BI " struct __kernel_timespec *" ts ","
-.BI " sigset_t *" sigmask ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_submit_and_wait_timeout (3)
-function submits the next requests from the submission queue belonging to the
-.I ring
-and waits for
-.I wait_nr
-completion events, or until the timeout
-.I ts
-expires. The completion events are stored in the
-.I cqe_ptr
-array.
-.PP
-The
-.I sigmask
-specifies the set of signals to block. If set, it is equivalent to atomically
-executing the following calls:
-.PP
-.in +4n
-.EX
-sigset_t origmask;
-
-pthread_sigmask(SIG_SETMASK, &sigmask, &origmask);
-ret = io_uring_submit_and_wait_timeout(ring, cqe, wait_nr, ts, NULL);
-pthread_sigmask(SIG_SETMASK, &origmask, NULL);
-.EE
-.in
-.PP
-After the caller retrieves a submission queue entry (SQE) with
-.BR io_uring_get_sqe (3)
-and prepares the SQE, it can be submitted with
-.BR io_uring_submit_and_wait_timeout (3) .
-
-Ideally used with a ring setup with
-.BR IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN
-as that will greatly reduce the number of context switches that an application
-will see waiting on multiple requests.
-
-.SH RETURN VALUE
-On success
-.BR io_uring_submit_and_wait_timeout (3)
-returns the number of submitted submission queue entries. On failure it returns
-.BR -errno .
-Note that in earlier versions of the liburing library, the return value was 0
-on success.
-The most common failure case is not receiving a completion within the specified
-timeout,
-.B -ETIME
-is returned in this case.
-.SH SEE ALSO
-.BR io_uring_queue_init_params (3),
-.BR io_uring_get_sqe (3),
-.BR io_uring_submit (3),
-.BR io_uring_submit_and_wait (3),
-.BR io_uring_wait_cqe (3)
diff --git a/man/io_uring_submit_and_wait_timeout.3.md b/man/io_uring_submit_and_wait_timeout.3.md
new file mode 100644
index 00000000..235b96d7
--- /dev/null
+++ b/man/io_uring_submit_and_wait_timeout.3.md
@@ -0,0 +1,49 @@
+.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: November 15, 2021
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_submit_and_wait_timeout
+---
+
+# NAME
+
+io_uring_submit_and_wait_timeout - submit requests to the submission queue and wait for the completion with timeout
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ 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 );
+
+# DESCRIPTION
+
+The **io_uring_submit_and_wait_timeout**(3) function submits the next requests from the submission queue belonging to the *ring* and waits for *wait_nr* completion events, or until the timeout *ts* expires. The completion events are stored in the *cqe_ptr* array.
+
+The *sigmask* specifies the set of signals to block. If set, it is equivalent to atomically executing the following calls:
+
+ sigset_t origmask;
+
+ pthread_sigmask(SIG_SETMASK, &sigmask, &origmask);
+ ret = io_uring_submit_and_wait_timeout(ring, cqe, wait_nr, ts, NULL);
+ pthread_sigmask(SIG_SETMASK, &origmask, NULL);
+
+After the caller retrieves a submission queue entry (SQE) with **io_uring_get_sqe**(3) and prepares the SQE, it can be submitted with **io_uring_submit_and_wait_timeout**(3)**.**
+
+Ideally used with a ring setup with **IORING_SETUP_SINGLE_ISSUER**\|**IORING_SETUP_DEFER_TASKRUN** as that will greatly reduce the number of context switches that an application will see waiting on multiple requests.
+
+# RETURN VALUE
+
+On success **io_uring_submit_and_wait_timeout**(3) returns the number of submitted submission queue entries. On failure it returns **-errno**. Note that in earlier versions of the liburing library, the return value was 0 on success. The most common failure case is not receiving a completion within the specified timeout, **-ETIME** is returned in this case.
+
+# SEE ALSO
+
+**io_uring_queue_init_params**(3), **io_uring_get_sqe**(3), **io_uring_submit**(3), **io_uring_submit_and_wait**(3), **io_uring_wait_cqe**(3)
diff --git a/man/io_uring_unregister_buf_ring.3 b/man/io_uring_unregister_buf_ring.3
deleted file mode 100644
index ee87e860..00000000
--- a/man/io_uring_unregister_buf_ring.3
+++ /dev/null
@@ -1,30 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_unregister_buf_ring 3 "May 18, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_unregister_buf_ring \- unregister a previously registered buffer ring
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_unregister_buf_ring(struct io_uring *" ring ",
-.BI " int " bgid ");"
-.BI "
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_unregister_buf_ring (3)
-function unregisters a previously registered shared buffer ring indicated by
-.IR bgid .
-
-.SH RETURN VALUE
-On success
-.BR io_uring_unregister_buf_ring (3)
-returns 0. On failure it returns
-.BR -errno .
-.SH SEE ALSO
-.BR io_uring_register_buf_ring (3),
-.BR io_uring_buf_ring_free (3)
diff --git a/man/io_uring_unregister_buf_ring.3.md b/man/io_uring_unregister_buf_ring.3.md
new file mode 100644
index 00000000..d08eb064
--- /dev/null
+++ b/man/io_uring_unregister_buf_ring.3.md
@@ -0,0 +1,35 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: May 18, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_unregister_buf_ring
+---
+
+# NAME
+
+io_uring_unregister_buf_ring - unregister a previously registered buffer ring
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_unregister_buf_ring(struct io_uring * ring ,
+ int bgid );
+
+
+# DESCRIPTION
+
+The **io_uring_unregister_buf_ring**(3) function unregisters a previously registered shared buffer ring indicated by *bgid*.
+
+# RETURN VALUE
+
+On success **io_uring_unregister_buf_ring**(3) returns 0. On failure it returns **-errno**.
+
+# SEE ALSO
+
+**io_uring_register_buf_ring**(3), **io_uring_buf_ring_free**(3)
diff --git a/man/io_uring_unregister_buffers.3 b/man/io_uring_unregister_buffers.3
deleted file mode 100644
index f066679b..00000000
--- a/man/io_uring_unregister_buffers.3
+++ /dev/null
@@ -1,27 +0,0 @@
-.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_unregister_buffers 3 "November 15, 2021" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_unregister_buffers \- unregister buffers for fixed buffer operations
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_unregister_buffers(struct io_uring *" ring ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_unregister_buffers (3)
-function unregisters the fixed buffers previously registered to the
-.IR ring .
-
-.SH RETURN VALUE
-On success
-.BR io_uring_unregister_buffers (3)
-returns 0. On failure it returns
-.BR -errno .
-.SH SEE ALSO
-.BR io_uring_register_buffers (3)
diff --git a/man/io_uring_unregister_buffers.3.md b/man/io_uring_unregister_buffers.3.md
new file mode 100644
index 00000000..0b61468b
--- /dev/null
+++ b/man/io_uring_unregister_buffers.3.md
@@ -0,0 +1,33 @@
+.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: November 15, 2021
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_unregister_buffers
+---
+
+# NAME
+
+io_uring_unregister_buffers - unregister buffers for fixed buffer operations
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_unregister_buffers(struct io_uring * ring );
+
+# DESCRIPTION
+
+The **io_uring_unregister_buffers**(3) function unregisters the fixed buffers previously registered to the *ring*.
+
+# RETURN VALUE
+
+On success **io_uring_unregister_buffers**(3) returns 0. On failure it returns **-errno**.
+
+# SEE ALSO
+
+**io_uring_register_buffers**(3)
diff --git a/man/io_uring_unregister_eventfd.3 b/man/io_uring_unregister_eventfd.3
deleted file mode 120000
index 66599571..00000000
--- a/man/io_uring_unregister_eventfd.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_register_eventfd.3
\ No newline at end of file
diff --git a/man/io_uring_unregister_files.3 b/man/io_uring_unregister_files.3
deleted file mode 100644
index c468d081..00000000
--- a/man/io_uring_unregister_files.3
+++ /dev/null
@@ -1,27 +0,0 @@
-.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_unregister_files 3 "November 15, 2021" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_unregister_files \- unregister file descriptors
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_unregister_files(struct io_uring *" ring ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_unregister_files (3)
-function unregisters the file descriptors previously registered to the
-.IR ring .
-
-.SH RETURN VALUE
-On success
-.BR io_uring_unregister_files (3)
-returns 0. On failure it returns
-.BR -errno .
-.SH SEE ALSO
-.BR io_uring_register_files (3)
diff --git a/man/io_uring_unregister_files.3.md b/man/io_uring_unregister_files.3.md
new file mode 100644
index 00000000..24e0c44a
--- /dev/null
+++ b/man/io_uring_unregister_files.3.md
@@ -0,0 +1,33 @@
+.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: November 15, 2021
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_unregister_files
+---
+
+# NAME
+
+io_uring_unregister_files - unregister file descriptors
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_unregister_files(struct io_uring * ring );
+
+# DESCRIPTION
+
+The **io_uring_unregister_files**(3) function unregisters the file descriptors previously registered to the *ring*.
+
+# RETURN VALUE
+
+On success **io_uring_unregister_files**(3) returns 0. On failure it returns **-errno**.
+
+# SEE ALSO
+
+**io_uring_register_files**(3)
diff --git a/man/io_uring_unregister_iowq_aff.3 b/man/io_uring_unregister_iowq_aff.3
deleted file mode 120000
index c29bd44e..00000000
--- a/man/io_uring_unregister_iowq_aff.3
+++ /dev/null
@@ -1 +0,0 @@
-io_uring_register_iowq_aff.3
\ No newline at end of file
diff --git a/man/io_uring_unregister_napi.3 b/man/io_uring_unregister_napi.3
deleted file mode 100644
index f7087ef7..00000000
--- a/man/io_uring_unregister_napi.3
+++ /dev/null
@@ -1,27 +0,0 @@
-.\" Copyright (C) 2022 Stefan Roesch <shr@devkernel.io>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_unregister_napi 3 "November 16, 2022" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_unregister_napi \- unregister NAPI busy poll settings
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_unregister_napi(struct io_uring *" ring ","
-.BI " struct io_uring_napi *" napi)
-.PP
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_unregister_napi (3)
-function unregisters the NAPI busy poll settings for subsequent operations.
-
-.SH RETURN VALUE
-On success
-.BR io_uring_unregister_napi (3)
-return 0. On failure they return
-.BR -errno .
-It also updates the napi structure with the current values.
diff --git a/man/io_uring_unregister_napi.3.md b/man/io_uring_unregister_napi.3.md
new file mode 100644
index 00000000..53765b37
--- /dev/null
+++ b/man/io_uring_unregister_napi.3.md
@@ -0,0 +1,30 @@
+.\" Copyright (C) 2022 Stefan Roesch <shr@devkernel.io>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: November 16, 2022
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_unregister_napi
+---
+
+# NAME
+
+io_uring_unregister_napi - unregister NAPI busy poll settings
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_unregister_napi(struct io_uring * ring ,
+ struct io_uring_napi * napi)
+
+# DESCRIPTION
+
+The **io_uring_unregister_napi**(3) function unregisters the NAPI busy poll settings for subsequent operations.
+
+# RETURN VALUE
+
+On success **io_uring_unregister_napi**(3) return 0. On failure they return **-errno**. It also updates the napi structure with the current values.
diff --git a/man/io_uring_unregister_personality.3 b/man/io_uring_unregister_personality.3
deleted file mode 100644
index 14a808e2..00000000
--- a/man/io_uring_unregister_personality.3
+++ /dev/null
@@ -1,33 +0,0 @@
-.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_unregister_personality 3 "January 18, 2025" "liburing-2.4" "liburing Manual"
-.SH NAME
-io_uring_unregister_personality \- unregister a personality from io_uring
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_unregister_personality(struct io_uring *" ring ", int " id ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_unregister_personality (3)
-function unregisters a previously registered personality from the io_uring
-instance specified by
-.IR ring .
-The
-.I id
-argument is the personality ID returned from a previous call to
-.BR io_uring_register_personality (3).
-
-After unregistering, the personality ID is no longer valid and must not be
-used in future submissions.
-
-.SH RETURN VALUE
-Returns 0 on success. On error, a negative errno value is returned.
-.SH SEE ALSO
-.BR io_uring_register_personality (3),
-.BR io_uring_register (2)
diff --git a/man/io_uring_unregister_personality.3.md b/man/io_uring_unregister_personality.3.md
new file mode 100644
index 00000000..5c6b6257
--- /dev/null
+++ b/man/io_uring_unregister_personality.3.md
@@ -0,0 +1,35 @@
+.\" Copyright (C) 2025 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: January 18, 2025
+footer: liburing-2.4
+header: liburing Manual
+section: 3
+title: io_uring_unregister_personality
+---
+
+# NAME
+
+io_uring_unregister_personality - unregister a personality from io_uring
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_unregister_personality(struct io_uring * ring , int id );
+
+# DESCRIPTION
+
+The **io_uring_unregister_personality**(3) function unregisters a previously registered personality from the io_uring instance specified by *ring*. The *id* argument is the personality ID returned from a previous call to **io_uring_register_personality**(3).
+
+After unregistering, the personality ID is no longer valid and must not be used in future submissions.
+
+# RETURN VALUE
+
+Returns 0 on success. On error, a negative errno value is returned.
+
+# SEE ALSO
+
+**io_uring_register_personality**(3), **io_uring_register**(2)
diff --git a/man/io_uring_unregister_ring_fd.3 b/man/io_uring_unregister_ring_fd.3
deleted file mode 100644
index 85aca141..00000000
--- a/man/io_uring_unregister_ring_fd.3
+++ /dev/null
@@ -1,32 +0,0 @@
-.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_unregister_ring_fd 3 "March 11, 2022" "liburing-2.2" "liburing Manual"
-.SH NAME
-io_uring_unregister_ring_fd \- unregister a ring file descriptor
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_unregister_ring_fd(struct io_uring *" ring ");"
-.fi
-.SH DESCRIPTION
-.PP
-.BR io_uring_unregister_ring_fd (3)
-unregisters the file descriptor of the ring.
-
-Unregisters a ring descriptor previously registered with the task. This is
-done automatically when
-.BR io_uring_queue_exit (3)
-is called, but can also be done to free up space for new ring registrations.
-For more information on ring descriptor registration, see
-.BR io_uring_register_ring_fd (3)
-
-.SH RETURN VALUE
-Returns 1 on success, indicating that one file descriptor was unregistered, or
-.BR -errno
-on error.
-.SH SEE ALSO
-.BR io_uring_register_ring_fd (3),
-.BR io_uring_register_files (3)
diff --git a/man/io_uring_unregister_ring_fd.3.md b/man/io_uring_unregister_ring_fd.3.md
new file mode 100644
index 00000000..8ca15bcb
--- /dev/null
+++ b/man/io_uring_unregister_ring_fd.3.md
@@ -0,0 +1,35 @@
+.\" Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: March 11, 2022
+footer: liburing-2.2
+header: liburing Manual
+section: 3
+title: io_uring_unregister_ring_fd
+---
+
+# NAME
+
+io_uring_unregister_ring_fd - unregister a ring file descriptor
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_unregister_ring_fd(struct io_uring * ring );
+
+# DESCRIPTION
+
+**io_uring_unregister_ring_fd**(3) unregisters the file descriptor of the ring.
+
+Unregisters a ring descriptor previously registered with the task. This is done automatically when **io_uring_queue_exit**(3) is called, but can also be done to free up space for new ring registrations. For more information on ring descriptor registration, see **io_uring_register_ring_fd**(3)
+
+# RETURN VALUE
+
+Returns 1 on success, indicating that one file descriptor was unregistered, or **-errno** on error.
+
+# SEE ALSO
+
+**io_uring_register_ring_fd**(3), **io_uring_register_files**(3)
diff --git a/man/io_uring_wait_cqe.3 b/man/io_uring_wait_cqe.3
deleted file mode 100644
index c2fffede..00000000
--- a/man/io_uring_wait_cqe.3
+++ /dev/null
@@ -1,41 +0,0 @@
-.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_wait_cqe 3 "November 15, 2021" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_wait_cqe \- wait for one io_uring completion event
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_wait_cqe(struct io_uring *" ring ","
-.BI " struct io_uring_cqe **" cqe_ptr ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_wait_cqe (3)
-function waits for an IO completion from the queue belonging to the
-.I ring
-param, waiting for it if necessary. If an event is already available in
-the ring when invoked, no waiting will occur. The
-.I cqe_ptr
-param is filled in on success.
-
-After the caller has submitted a request with
-.BR io_uring_submit (3),
-the application can retrieve the completion with
-.BR io_uring_wait_cqe (3).
-
-.SH RETURN VALUE
-On success
-.BR io_uring_wait_cqe (3)
-returns 0 and the cqe_ptr param is filled in. On failure it returns
-.BR -errno .
-The return value indicates the result of waiting for a CQE, and it has no
-relation to the CQE result itself.
-.SH SEE ALSO
-.BR io_uring_submit (3),
-.BR io_uring_wait_cqe_timeout (3),
-.BR io_uring_wait_cqes (3)
diff --git a/man/io_uring_wait_cqe.3.md b/man/io_uring_wait_cqe.3.md
new file mode 100644
index 00000000..73f5299a
--- /dev/null
+++ b/man/io_uring_wait_cqe.3.md
@@ -0,0 +1,36 @@
+.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: November 15, 2021
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_wait_cqe
+---
+
+# NAME
+
+io_uring_wait_cqe - wait for one io_uring completion event
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_wait_cqe(struct io_uring * ring ,
+ struct io_uring_cqe ** cqe_ptr );
+
+# DESCRIPTION
+
+The **io_uring_wait_cqe**(3) function waits for an IO completion from the queue belonging to the *ring* param, waiting for it if necessary. If an event is already available in the ring when invoked, no waiting will occur. The *cqe_ptr* param is filled in on success.
+
+After the caller has submitted a request with **io_uring_submit**(3), the application can retrieve the completion with **io_uring_wait_cqe**(3).
+
+# RETURN VALUE
+
+On success **io_uring_wait_cqe**(3) returns 0 and the cqe_ptr param is filled in. On failure it returns **-errno**. The return value indicates the result of waiting for a CQE, and it has no relation to the CQE result itself.
+
+# SEE ALSO
+
+**io_uring_submit**(3), **io_uring_wait_cqe_timeout**(3), **io_uring_wait_cqes**(3)
diff --git a/man/io_uring_wait_cqe_nr.3 b/man/io_uring_wait_cqe_nr.3
deleted file mode 100644
index 9e19098f..00000000
--- a/man/io_uring_wait_cqe_nr.3
+++ /dev/null
@@ -1,49 +0,0 @@
-.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_wait_cqe_nr 3 "November 15, 2021" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_wait_cqe_nr \- wait for one or more io_uring completion events
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_wait_cqe_nr(struct io_uring *" ring ","
-.BI " struct io_uring_cqe **" cqe_ptr ","
-.BI " unsigned " wait_nr ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_wait_cqe_nr (3)
-function returns
-.I wait_nr
-IO completion events from the queue belonging to the
-.I ring
-param, waiting for it if necessary. If the requested number of events are
-already available in the ring when invoked, no waiting will occur. The
-.I cqe_ptr
-param is filled in on success.
-
-After the caller has submitted a request with
-.BR io_uring_submit (3),
-the application can retrieve the completion with
-.BR io_uring_wait_cqe (3).
-
-Ideally used with a ring setup with
-.BR IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN
-as that will greatly reduce the number of context switches that an application
-will see waiting on multiple requests.
-
-.SH RETURN VALUE
-On success
-.BR io_uring_wait_cqe_nr (3)
-returns 0 and the cqe_ptr param is filled in. On failure it returns
-.BR -errno .
-The return value indicates the result of waiting for a CQE, and it has no
-relation to the CQE result itself.
-.SH SEE ALSO
-.BR io_uring_queue_init_params (3),
-.BR io_uring_submit (3),
-.BR io_uring_wait_cqes (3)
diff --git a/man/io_uring_wait_cqe_nr.3.md b/man/io_uring_wait_cqe_nr.3.md
new file mode 100644
index 00000000..9f797194
--- /dev/null
+++ b/man/io_uring_wait_cqe_nr.3.md
@@ -0,0 +1,39 @@
+.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: November 15, 2021
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_wait_cqe_nr
+---
+
+# NAME
+
+io_uring_wait_cqe_nr - wait for one or more io_uring completion events
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_wait_cqe_nr(struct io_uring * ring ,
+ struct io_uring_cqe ** cqe_ptr ,
+ unsigned wait_nr );
+
+# DESCRIPTION
+
+The **io_uring_wait_cqe_nr**(3) function returns *wait_nr* IO completion events from the queue belonging to the *ring* param, waiting for it if necessary. If the requested number of events are already available in the ring when invoked, no waiting will occur. The *cqe_ptr* param is filled in on success.
+
+After the caller has submitted a request with **io_uring_submit**(3), the application can retrieve the completion with **io_uring_wait_cqe**(3).
+
+Ideally used with a ring setup with **IORING_SETUP_SINGLE_ISSUER**\|**IORING_SETUP_DEFER_TASKRUN** as that will greatly reduce the number of context switches that an application will see waiting on multiple requests.
+
+# RETURN VALUE
+
+On success **io_uring_wait_cqe_nr**(3) returns 0 and the cqe_ptr param is filled in. On failure it returns **-errno**. The return value indicates the result of waiting for a CQE, and it has no relation to the CQE result itself.
+
+# SEE ALSO
+
+**io_uring_queue_init_params**(3), **io_uring_submit**(3), **io_uring_wait_cqes**(3)
diff --git a/man/io_uring_wait_cqe_timeout.3 b/man/io_uring_wait_cqe_timeout.3
deleted file mode 100644
index d4cfe508..00000000
--- a/man/io_uring_wait_cqe_timeout.3
+++ /dev/null
@@ -1,62 +0,0 @@
-.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_wait_cqe_timeout 3 "November 15, 2021" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_wait_cqe_timeout \- wait for one io_uring completion event with timeout
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_wait_cqe_timeout(struct io_uring *" ring ","
-.BI " struct io_uring_cqe **" cqe_ptr ","
-.BI " struct __kernel_timespec *" ts ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_wait_cqe_timeout (3)
-function waits for one IO completion to be available from the queue belonging
-to the
-.I ring
-param, waiting for it if necessary or until the timeout
-.I ts
-expires. If an event is already available in the ring when invoked, no waiting
-will occur.
-
-The
-.I cqe_ptr
-param is filled in on success.
-
-If
-.I ts
-is specified and an older kernel without
-.B IORING_FEAT_EXT_ARG
-is used, the application does not need to call
-.BR io_uring_submit (3)
-before calling
-.BR io_uring_wait_cqes (3).
-For newer kernels with that feature flag set, there is no implied submit
-when waiting for a request.
-
-If
-.I ts
-is
-.B NULL ,
-then this behaves like
-.BR io_uring_wait_cqe (3)
-in that it will wait forever for an event.
-
-.SH RETURN VALUE
-On success
-.BR io_uring_wait_cqe_timeout (3)
-returns 0 and the cqe_ptr param is filled in. On failure it returns
-.BR -errno .
-The return value indicates the result of waiting for a CQE, and it has no
-relation to the CQE result itself. If a timeout occurs, it will return
-.BR -ETIME .
-.SH SEE ALSO
-.BR io_uring_submit (3),
-.BR io_uring_wait_cqes (3),
-.BR io_uring_wait_cqe (3)
diff --git a/man/io_uring_wait_cqe_timeout.3.md b/man/io_uring_wait_cqe_timeout.3.md
new file mode 100644
index 00000000..148035b2
--- /dev/null
+++ b/man/io_uring_wait_cqe_timeout.3.md
@@ -0,0 +1,41 @@
+.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: November 15, 2021
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_wait_cqe_timeout
+---
+
+# NAME
+
+io_uring_wait_cqe_timeout - wait for one io_uring completion event with timeout
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ int io_uring_wait_cqe_timeout(struct io_uring * ring ,
+ struct io_uring_cqe ** cqe_ptr ,
+ struct __kernel_timespec * ts );
+
+# DESCRIPTION
+
+The **io_uring_wait_cqe_timeout**(3) function waits for one IO completion to be available from the queue belonging to the *ring* param, waiting for it if necessary or until the timeout *ts* expires. If an event is already available in the ring when invoked, no waiting will occur.
+
+The *cqe_ptr* param is filled in on success.
+
+If *ts* is specified and an older kernel without **IORING_FEAT_EXT_ARG** is used, the application does not need to call **io_uring_submit**(3) before calling **io_uring_wait_cqes**(3). For newer kernels with that feature flag set, there is no implied submit when waiting for a request.
+
+If *ts* is **NULL ,** then this behaves like **io_uring_wait_cqe**(3) in that it will wait forever for an event.
+
+# RETURN VALUE
+
+On success **io_uring_wait_cqe_timeout**(3) returns 0 and the cqe_ptr param is filled in. On failure it returns **-errno**. The return value indicates the result of waiting for a CQE, and it has no relation to the CQE result itself. If a timeout occurs, it will return **-ETIME**.
+
+# SEE ALSO
+
+**io_uring_submit**(3), **io_uring_wait_cqes**(3), **io_uring_wait_cqe**(3)
diff --git a/man/io_uring_wait_cqes.3 b/man/io_uring_wait_cqes.3
deleted file mode 100644
index 37ea1f08..00000000
--- a/man/io_uring_wait_cqes.3
+++ /dev/null
@@ -1,82 +0,0 @@
-.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_wait_cqes 3 "November 15, 2021" "liburing-2.1" "liburing Manual"
-.SH NAME
-io_uring_wait_cqes \- wait for one or more io_uring completion events
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_wait_cqes(struct io_uring *" ring ","
-.BI " struct io_uring_cqe **" cqe_ptr ","
-.BI " unsigned " wait_nr ","
-.BI " struct __kernel_timespec *" ts ","
-.BI " sigset_t *" sigmask ");
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_wait_cqes (3)
-function returns
-.I wait_nr
-IO completions from the queue belonging to the
-.I ring
-param, waiting for them if necessary or until the timeout
-.I ts
-expires.
-.PP
-The
-.I sigmask
-specifies the set of signals to block. If set, it is equivalent to atomically
-executing the following calls:
-.PP
-.in +4n
-.EX
-sigset_t origmask;
-
-pthread_sigmask(SIG_SETMASK, &sigmask, &origmask);
-ret = io_uring_wait_cqes(ring, cqe, wait_nr, ts, NULL);
-pthread_sigmask(SIG_SETMASK, &origmask, NULL);
-.EE
-.in
-.PP
-The
-.I cqe_ptr
-param is filled in on success with the first CQE. Callers of this function
-should use
-.BR io_uring_for_each_cqe (3)
-to iterate all available CQEs.
-
-If
-.I ts
-is specified and an older kernel without
-.B IORING_FEAT_EXT_ARG
-is used, the application does not need to call
-.BR io_uring_submit (3)
-before calling
-.BR io_uring_wait_cqes (3).
-For newer kernels with that feature flag set, there is no implied submit
-when waiting for a request.
-
-If
-.I ts
-is
-.B NULL ,
-then this behaves like
-.BR io_uring_wait_cqe (3)
-in that it will wait forever for an event.
-
-.SH RETURN VALUE
-On success
-.BR io_uring_wait_cqes (3)
-returns 0 and the cqe_ptr param is filled in. On failure it returns
-.BR -errno .
-If a timeout occurs, it will return
-.BR -ETIME .
-.SH SEE ALSO
-.BR io_uring_submit (3),
-.BR io_uring_for_each_cqe (3),
-.BR io_uring_wait_cqe_timeout (3),
-.BR io_uring_wait_cqe (3)
diff --git a/man/io_uring_wait_cqes.3.md b/man/io_uring_wait_cqes.3.md
new file mode 100644
index 00000000..440bef0b
--- /dev/null
+++ b/man/io_uring_wait_cqes.3.md
@@ -0,0 +1,51 @@
+.\" Copyright (C) 2021 Stefan Roesch <shr@fb.com>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: November 15, 2021
+footer: liburing-2.1
+header: liburing Manual
+section: 3
+title: io_uring_wait_cqes
+---
+
+# NAME
+
+io_uring_wait_cqes - wait for one or more io_uring completion events
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ 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 );
+
+# DESCRIPTION
+
+The **io_uring_wait_cqes**(3) function returns *wait_nr* IO completions from the queue belonging to the *ring* param, waiting for them if necessary or until the timeout *ts* expires.
+
+The *sigmask* specifies the set of signals to block. If set, it is equivalent to atomically executing the following calls:
+
+ sigset_t origmask;
+
+ pthread_sigmask(SIG_SETMASK, &sigmask, &origmask);
+ ret = io_uring_wait_cqes(ring, cqe, wait_nr, ts, NULL);
+ pthread_sigmask(SIG_SETMASK, &origmask, NULL);
+
+The *cqe_ptr* param is filled in on success with the first CQE. Callers of this function should use **io_uring_for_each_cqe**(3) to iterate all available CQEs.
+
+If *ts* is specified and an older kernel without **IORING_FEAT_EXT_ARG** is used, the application does not need to call **io_uring_submit**(3) before calling **io_uring_wait_cqes**(3). For newer kernels with that feature flag set, there is no implied submit when waiting for a request.
+
+If *ts* is **NULL ,** then this behaves like **io_uring_wait_cqe**(3) in that it will wait forever for an event.
+
+# RETURN VALUE
+
+On success **io_uring_wait_cqes**(3) returns 0 and the cqe_ptr param is filled in. On failure it returns **-errno**. If a timeout occurs, it will return **-ETIME**.
+
+# SEE ALSO
+
+**io_uring_submit**(3), **io_uring_for_each_cqe**(3), **io_uring_wait_cqe_timeout**(3), **io_uring_wait_cqe**(3)
diff --git a/man/io_uring_wait_cqes_min_timeout.3 b/man/io_uring_wait_cqes_min_timeout.3
deleted file mode 100644
index e3d9849d..00000000
--- a/man/io_uring_wait_cqes_min_timeout.3
+++ /dev/null
@@ -1,76 +0,0 @@
-.\" Copyright (C) 2024 Jens Axboe <axboe@kernel.dk>
-.\"
-.\" SPDX-License-Identifier: LGPL-2.0-or-later
-.\"
-.TH io_uring_wait_cqes_min_timeout 3 "Feb 13, 2024" "liburing-2.8" "liburing Manual"
-.SH NAME
-io_uring_wait_cqes_min_timeout \- wait for completions with both batch and normal timeout
-.SH SYNOPSIS
-.nf
-.B #include <liburing.h>
-.PP
-.BI "int io_uring_wait_cqes_min_timeout(struct io_uring *" ring ","
-.BI " struct io_uring_cqe **" cqe_ptr ","
-.BI " unsigned " wait_nr ","
-.BI " struct __kernel_timespec *" ts ","
-.BI " unsigned int " min_wait_usec ",
-.BI " sigset_t *" sigmask ");"
-.fi
-.SH DESCRIPTION
-.PP
-The
-.BR io_uring_wait_cqes_min_timeout (3)
-waits for completions from the submission queue belonging to the
-.I ring
-and waits for
-.I wait_nr
-completion events, or until the timeout
-.I ts
-expires. The completion events are stored in the
-.I cqe_ptr
-array. If non-zero,
-.I min_wait_usec
-denotes a timeout for the
-.I wait_nr
-batch.
-
-The
-.I sigmask
-specifies the set of signals to block. If set, it is equivalent to atomically
-executing the following calls:
-.PP
-.in +4n
-.EX
-sigset_t origmask;
-
-pthread_sigmask(SIG_SETMASK, &sigmask, &origmask);
-ret = io_uring_wait_cqes_min_timeout(ring, cqe, wait_nr, ts, min_wait, NULL);
-pthread_sigmask(SIG_SETMASK, &origmask, NULL);
-.EE
-.in
-.PP
-This works like
-.BR io_uring_submit_and_wait_min_timeout (3)
-except that it doesn't submit requests. See that man page for a description
-for how the min timeout waiting works.
-
-Available since 6.12.
-
-.SH RETURN VALUE
-On success
-.BR io_uring_wait_cqes_min_timeout (3)
-returns the 0.On failure it returns
-.BR -errno .
-If the kernel doesn't support this functionality,
-.BR -EINVAL
-will be returned. See note on the feature flag.
-The most common failure case is not receiving a completion within the specified
-timeout,
-.B -ETIME
-is returned in this case.
-.SH SEE ALSO
-.BR io_uring_wait_cqe (3),
-.BR io_uring_wait_cqes (3),
-.BR io_uring_wait_cqe_timeout (3),
-.BR io_uring_wait_cqes (3),
-.BR io_uring_submit_and_wait_min_timeout (3)
diff --git a/man/io_uring_wait_cqes_min_timeout.3.md b/man/io_uring_wait_cqes_min_timeout.3.md
new file mode 100644
index 00000000..8e5891c0
--- /dev/null
+++ b/man/io_uring_wait_cqes_min_timeout.3.md
@@ -0,0 +1,50 @@
+.\" Copyright (C) 2024 Jens Axboe <axboe@kernel.dk>
+.\"
+.\" SPDX-License-Identifier: LGPL-2.0-or-later
+.\"
+---
+date: Feb 13, 2024
+footer: liburing-2.8
+header: liburing Manual
+section: 3
+title: io_uring_wait_cqes_min_timeout
+---
+
+# NAME
+
+io_uring_wait_cqes_min_timeout - wait for completions with both batch and normal timeout
+
+# SYNOPSIS
+
+ #include <liburing.h>
+
+ 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 );
+
+# DESCRIPTION
+
+The **io_uring_wait_cqes_min_timeout**(3) waits for completions from the submission queue belonging to the *ring* and waits for *wait_nr* completion events, or until the timeout *ts* expires. The completion events are stored in the *cqe_ptr* array. If non-zero, *min_wait_usec* denotes a timeout for the *wait_nr* batch.
+
+The *sigmask* specifies the set of signals to block. If set, it is equivalent to atomically executing the following calls:
+
+ sigset_t origmask;
+
+ pthread_sigmask(SIG_SETMASK, &sigmask, &origmask);
+ ret = io_uring_wait_cqes_min_timeout(ring, cqe, wait_nr, ts, min_wait, NULL);
+ pthread_sigmask(SIG_SETMASK, &origmask, NULL);
+
+This works like **io_uring_submit_and_wait_min_timeout**(3) except that it doesn\'t submit requests. See that man page for a description for how the min timeout waiting works.
+
+Available since 6.12.
+
+# RETURN VALUE
+
+On success **io_uring_wait_cqes_min_timeout**(3) returns the 0.On failure it returns **-errno**. If the kernel doesn\'t support this functionality, **-EINVAL** will be returned. See note on the feature flag. The most common failure case is not receiving a completion within the specified timeout, **-ETIME** is returned in this case.
+
+# SEE ALSO
+
+**io_uring_wait_cqe**(3), **io_uring_wait_cqes**(3), **io_uring_wait_cqe_timeout**(3), **io_uring_wait_cqes**(3), **io_uring_submit_and_wait_min_timeout**(3)
--
2.54.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [RFC PATCH liburing] man: Convert manpages to markdown
2026-06-18 23:05 [RFC PATCH liburing] man: Convert manpages to markdown Gabriel Krisman Bertazi
@ 2026-06-18 23:53 ` Ammar Faizi
2026-06-19 17:05 ` Gabriel Krisman Bertazi
0 siblings, 1 reply; 3+ messages in thread
From: Ammar Faizi @ 2026-06-18 23:53 UTC (permalink / raw)
To: Gabriel Krisman Bertazi; +Cc: Jens Axboe, io-uring Mailing List
On 6/19/26 6:05 AM, Gabriel Krisman Bertazi wrote:
> This has been discussed for a while due to the ongoing pain of writing
> groff. Now that we just had a release, convert the manpages to markdown
> and add infrastructure to generate back the groff automatically during
> compilation.
Wow, big changes:
399 files changed, 11719 insertions(+), 18975 deletions(-)
Yeah, I agree that writing in GNU roff is more painful than writing in
markdown. Interesting patch.
Can we also word-wrap the markdown files? It's easier to read them in
raw if they're word-wrapped as well.
--
Ammar Faizi
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [RFC PATCH liburing] man: Convert manpages to markdown
2026-06-18 23:53 ` Ammar Faizi
@ 2026-06-19 17:05 ` Gabriel Krisman Bertazi
0 siblings, 0 replies; 3+ messages in thread
From: Gabriel Krisman Bertazi @ 2026-06-19 17:05 UTC (permalink / raw)
To: Ammar Faizi; +Cc: Jens Axboe, io-uring Mailing List
Ammar Faizi <ammarfaizi2@gnuweeb.org> writes:
> On 6/19/26 6:05 AM, Gabriel Krisman Bertazi wrote:
>> This has been discussed for a while due to the ongoing pain of writing
>> groff. Now that we just had a release, convert the manpages to markdown
>> and add infrastructure to generate back the groff automatically during
>> compilation.
>
> Wow, big changes:
>
> 399 files changed, 11719 insertions(+), 18975 deletions(-)
>
> Yeah, I agree that writing in GNU roff is more painful than writing in
> markdown. Interesting patch.
Yeah, this is gonna be shitty to review. The conversion was done
mostly automatically though, you can review Makefile for that.
I'll split it up into manageable chunks.
>
> Can we also word-wrap the markdown files? It's easier to read them in
> raw if they're word-wrapped as well.
Let me see if I can get the right pandoc incantation.
--
Gabriel Krisman Bertazi
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-06-19 17:06 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-18 23:05 [RFC PATCH liburing] man: Convert manpages to markdown Gabriel Krisman Bertazi
2026-06-18 23:53 ` Ammar Faizi
2026-06-19 17:05 ` Gabriel Krisman Bertazi
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.