Skip to content

Commit 9ca75f5

Browse files
authored
Add more 6.13 io_uring features (#1373)
Also, change `io_uring_enter` to have separate `io_uring_enter_sigmask` and `io_uring_enter_arg` variants, for better ergonomics, and to better prepare for `IORING_ENTER_EXT_ARG_REG` in the future.
1 parent da8342c commit 9ca75f5

File tree

2 files changed

+260
-29
lines changed

2 files changed

+260
-29
lines changed

CHANGES.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -251,11 +251,15 @@ advice applies to the end of the file. To convert an arbitrary `u64` value to
251251

252252
[`rustix::fs::fadvise`]: https://docs.rs/rustix/1.0.0/rustix/fs/fn.fadvise.html
253253

254-
[`rustix::io_uring::io_uring_enter`] has a new signature; instead of `arg` and
255-
`size` providing a raw `*mut c_void` and `usize`, it now takes any `&T` and
256-
infers the size.
254+
[`rustix::io_uring::io_uring_enter`] no longer has `arg` and `size` arguments
255+
providing a raw `*mut c_void` and `usize` describing the argument value. To
256+
pass argumentts, there are now additional functions, `io_uring_enter_sigmask`,
257+
and `io_uring_enter_arg`, which take a [`KernelSigSet`] or an
258+
`io_uring_getevents_arg`, respectively. These are more ergonomic, and provide
259+
a better path to adding `IORING_ENTER_EXT_ARG_REG` support in the future.
257260

258261
[`rustix::io_uring::io_uring_enter`]: https://docs.rs/rustix/1.0.0/rustix/io_uring/fn.io_uring_enter.html
262+
[`KernelSigSet`]: https://docs.rs/rustix/1.0.0/rustix/io_uring/struct.KernelSigSet.html
259263

260264
The [`sigmask`] and [`ts`] fields of [`rustix::io_uring::getevents_arg`]
261265
changed from `u64` to [`rustix::io_uring::io_uring_ptr`], to better preserve

src/io_uring/mod.rs

Lines changed: 253 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -144,48 +144,174 @@ pub unsafe fn io_uring_register_with<Fd: AsFd>(
144144
backend::io_uring::syscalls::io_uring_register_with(fd.as_fd(), opcode, flags, arg, nr_args)
145145
}
146146

147-
/// `io_uring_enter2(fd, to_submit, min_complete, flags, arg,
148-
/// size_of_val(arg))`—Initiate and/or complete asynchronous I/O.
147+
/// `io_uring_enter(fd, to_submit, min_complete, flags, 0, 0)`—Initiate
148+
/// and/or complete asynchronous I/O.
149+
///
150+
/// This version has no `arg` argument. To pass:
151+
/// - a signal mask, use [`io_uring_enter_sigmask`].
152+
/// - an [`io_uring_getevents_arg`], use [`io_uring_enter_arg`] (aka
153+
/// `io_uring_enter2`).
154+
///
155+
/// # Safety
156+
///
157+
/// io_uring operates on raw pointers and raw file descriptors. Users are
158+
/// responsible for ensuring that memory and resources are only accessed in
159+
/// valid ways.
160+
///
161+
/// And, `flags` must not have [`IoringEnterFlags::EXT_ARG`] or
162+
/// [`IoringEnterFlags::EXT_ARG_REG`] set.
163+
///
164+
/// # References
165+
/// - [Linux]
166+
///
167+
/// [Linux]: https://www.man7.org/linux/man-pages/man2/io_uring_enter.2.html
168+
#[doc(alias = "io_uring_enter2")]
169+
#[inline]
170+
pub unsafe fn io_uring_enter<Fd: AsFd>(
171+
fd: Fd,
172+
to_submit: u32,
173+
min_complete: u32,
174+
flags: IoringEnterFlags,
175+
) -> io::Result<u32> {
176+
debug_assert!(!flags.contains(IoringEnterFlags::EXT_ARG));
177+
debug_assert!(!flags.contains(IoringEnterFlags::EXT_ARG_REG));
178+
179+
backend::io_uring::syscalls::io_uring_enter(
180+
fd.as_fd(),
181+
to_submit,
182+
min_complete,
183+
flags,
184+
null_mut(),
185+
0,
186+
)
187+
}
188+
189+
/// `io_uring_enter(fd, to_submit, min_complete, flags, sigmask,
190+
/// sizeof(*sigmask))`— Initiate and/or complete asynchronous I/O, with a
191+
/// signal mask.
192+
///
193+
/// # Safety
194+
///
195+
/// io_uring operates on raw pointers and raw file descriptors. Users are
196+
/// responsible for ensuring that memory and resources are only accessed in
197+
/// valid ways.
198+
///
199+
/// And, `flags` must not have [`IoringEnterFlags::EXT_ARG`] or
200+
/// [`IoringEnterFlags::EXT_ARG_REG`] set.
201+
///
202+
/// And, the `KernelSigSet` referred to by `arg` must not contain any signal
203+
/// numbers reserved by libc.
204+
///
205+
/// # References
206+
/// - [Linux]
207+
///
208+
/// [Linux]: https://www.man7.org/linux/man-pages/man2/io_uring_enter.2.html
209+
#[doc(alias = "io_uring_enter")]
210+
#[inline]
211+
pub unsafe fn io_uring_enter_sigmask<Fd: AsFd>(
212+
fd: Fd,
213+
to_submit: u32,
214+
min_complete: u32,
215+
flags: IoringEnterFlags,
216+
sigmask: Option<&KernelSigSet>,
217+
) -> io::Result<u32> {
218+
debug_assert!(!flags.contains(IoringEnterFlags::EXT_ARG));
219+
debug_assert!(!flags.contains(IoringEnterFlags::EXT_ARG_REG));
220+
221+
backend::io_uring::syscalls::io_uring_enter(
222+
fd.as_fd(),
223+
to_submit,
224+
min_complete,
225+
flags,
226+
option_as_ptr(sigmask).cast::<c_void>(),
227+
size_of::<KernelSigSet>(),
228+
)
229+
}
230+
231+
/// `io_uring_enter2(fd, to_submit, min_complete, flags, arg, sizeof(*arg))`—
232+
/// Initiate and/or complete asynchronous I/O, with a signal mask and a
233+
/// timeout.
149234
///
150235
/// # Safety
151236
///
152237
/// io_uring operates on raw pointers and raw file descriptors. Users are
153238
/// responsible for ensuring that memory and resources are only accessed in
154239
/// valid ways.
155240
///
156-
/// And, `arg` must either be a [`SigSet`] or a [`io_uring_getevents_arg`], and
157-
/// `flags` must contain [`IoringEnterFlags::EXT_ARG`] if and only if it's a
158-
/// `io_uring_getevents_arg`.
241+
/// And, `flags` must have [`IoringEnterFlags::EXT_ARG`] set, and must not have
242+
/// [`IoringEnterFlags::EXT_ARG_REG`] set.
243+
///
244+
/// And, the `KernelSigSet` pointed to by the `io_uring_getenvets_arg` referred
245+
/// to by `arg` must not contain any signal numbers reserved by libc.
159246
///
160247
/// # References
161248
/// - [Linux]
162249
///
163250
/// [Linux]: https://www.man7.org/linux/man-pages/man2/io_uring_enter.2.html
251+
#[doc(alias = "io_uring_enter")]
164252
#[doc(alias = "io_uring_enter2")]
165253
#[inline]
166-
pub unsafe fn io_uring_enter<Fd: AsFd, T>(
254+
pub unsafe fn io_uring_enter_arg<Fd: AsFd>(
167255
fd: Fd,
168256
to_submit: u32,
169257
min_complete: u32,
170258
flags: IoringEnterFlags,
171-
arg: Option<&T>,
259+
arg: Option<&io_uring_getevents_arg>,
172260
) -> io::Result<u32> {
173-
debug_assert!(
174-
size_of::<T>() == size_of::<KernelSigSet>()
175-
|| size_of::<T>() == size_of::<io_uring_getevents_arg>()
176-
);
177-
debug_assert!(
178-
(size_of::<T>() == size_of::<io_uring_getevents_arg>())
179-
== (flags.contains(IoringEnterFlags::EXT_ARG))
180-
);
261+
debug_assert!(flags.contains(IoringEnterFlags::EXT_ARG));
262+
debug_assert!(!flags.contains(IoringEnterFlags::EXT_ARG_REG));
181263

182264
backend::io_uring::syscalls::io_uring_enter(
183265
fd.as_fd(),
184266
to_submit,
185267
min_complete,
186268
flags,
187269
option_as_ptr(arg).cast::<c_void>(),
188-
size_of::<T>(),
270+
size_of::<io_uring_getevents_arg>(),
271+
)
272+
}
273+
274+
/// `io_uring_enter2(fd, to_submit, min_complete, flags, offset,
275+
/// sizeof(io_uring_reg_wait))`— Initiate and/or complete asynchronous I/O,
276+
/// using a previously regisered `io_uring_reg_wait`.
277+
///
278+
/// `offset` is an offset into an area of wait regions previously registered
279+
/// with [`io_uring_register`] using the [`IoringRegisterOp::CQWAIT_REG`]
280+
/// operation.
281+
///
282+
/// # Safety
283+
///
284+
/// io_uring operates on raw pointers and raw file descriptors. Users are
285+
/// responsible for ensuring that memory and resources are only accessed in
286+
/// valid ways.
287+
///
288+
/// And, `flags` must have [`IoringEnterFlags::EXT_ARG_REG`] set, and must not
289+
/// have [`IoringEnterFlags::EXT_ARG`] set.
290+
///
291+
/// # References
292+
/// - [Linux]
293+
///
294+
/// [Linux]: https://www.man7.org/linux/man-pages/man2/io_uring_enter.2.html
295+
#[doc(alias = "io_uring_enter")]
296+
#[doc(alias = "io_uring_enter2")]
297+
#[inline]
298+
pub unsafe fn io_uring_enter_reg_wait<Fd: AsFd>(
299+
fd: Fd,
300+
to_submit: u32,
301+
min_complete: u32,
302+
flags: IoringEnterFlags,
303+
reg_wait: usize,
304+
) -> io::Result<u32> {
305+
debug_assert!(!flags.contains(IoringEnterFlags::EXT_ARG));
306+
debug_assert!(flags.contains(IoringEnterFlags::EXT_ARG_REG));
307+
308+
backend::io_uring::syscalls::io_uring_enter(
309+
fd.as_fd(),
310+
to_submit,
311+
min_complete,
312+
flags,
313+
reg_wait as *mut c_void,
314+
size_of::<io_uring_reg_wait>(),
189315
)
190316
}
191317

@@ -203,12 +329,18 @@ bitflags::bitflags! {
203329
/// `IORING_ENTER_SQ_WAIT`
204330
const SQ_WAIT = sys::IORING_ENTER_SQ_WAIT;
205331

206-
/// `IORING_ENTER_EXT_ARG`
332+
/// `IORING_ENTER_EXT_ARG` (since Linux 5.11)
207333
const EXT_ARG = sys::IORING_ENTER_EXT_ARG;
208334

209335
/// `IORING_ENTER_REGISTERED_RING`
210336
const REGISTERED_RING = sys::IORING_ENTER_REGISTERED_RING;
211337

338+
/// `IORING_ENTER_ABS_TIMER` (since Linux 6.12)
339+
const ABS_TIMER = sys::IORING_ENTER_ABS_TIMER;
340+
341+
/// `IORING_ENTER_EXT_ARG_REG` (since Linux 6.12)
342+
const EXT_ARG_REG = sys::IORING_ENTER_EXT_ARG_REG;
343+
212344
/// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
213345
const _ = !0;
214346
}
@@ -297,6 +429,27 @@ pub enum IoringRegisterOp {
297429

298430
/// `IORING_REGISTER_FILE_ALLOC_RANGE`
299431
RegisterFileAllocRange = sys::io_uring_register_op::IORING_REGISTER_FILE_ALLOC_RANGE as _,
432+
433+
/// `IORING_REGISTER_PBUF_STATUS` (since Linux 6.8)
434+
RegisterPbufStatus = sys::io_uring_register_op::IORING_REGISTER_PBUF_STATUS as _,
435+
436+
/// `IORING_REGISTER_NAPI` (since Linux 6.9)
437+
RegisterNapi = sys::io_uring_register_op::IORING_REGISTER_NAPI as _,
438+
439+
/// `IORING_UNREGISTER_NAPI` (since Linux 6.9)
440+
UnregisterNapi = sys::io_uring_register_op::IORING_UNREGISTER_NAPI as _,
441+
442+
/// `IORING_REGISTER_CLOCK` (since Linux 6.12)
443+
RegisterClock = sys::io_uring_register_op::IORING_REGISTER_CLOCK as _,
444+
445+
/// `IORING_REGISTER_CLONE_BUFFERS ` (since Linux 6.12)
446+
RegisterCloneBuffers = sys::io_uring_register_op::IORING_REGISTER_CLONE_BUFFERS as _,
447+
448+
/// `IORING_REGISTER_SEND_MSG_RING` (since Linux 6.12)
449+
RegisterSendMsgRing = sys::io_uring_register_op::IORING_REGISTER_SEND_MSG_RING as _,
450+
451+
/// `IORING_REGISTER_RESIZE_RINGS`(since Linux 6.13)
452+
RegisterResizeRings = sys::io_uring_register_op::IORING_REGISTER_RESIZE_RINGS as _,
300453
}
301454

302455
bitflags::bitflags! {
@@ -464,31 +617,31 @@ pub enum IoringOp {
464617
/// `IORING_OP_SENDMSG_ZC`
465618
SendmsgZc = sys::io_uring_op::IORING_OP_SENDMSG_ZC as _,
466619

467-
/// `IORING_OP_READ_MULTISHOT`
620+
/// `IORING_OP_READ_MULTISHOT` (since Linux 6.7)
468621
ReadMultishot = sys::io_uring_op::IORING_OP_READ_MULTISHOT as _,
469622

470-
/// `IORING_OP_WAITID`
623+
/// `IORING_OP_WAITID` (since Linux 6.5)
471624
Waitid = sys::io_uring_op::IORING_OP_WAITID as _,
472625

473-
/// `IORING_OP_FUTEX_WAIT`
626+
/// `IORING_OP_FUTEX_WAIT` (since Linux 6.7)
474627
FutexWait = sys::io_uring_op::IORING_OP_FUTEX_WAIT as _,
475628

476-
/// `IORING_OP_FUTEX_WAKE`
629+
/// `IORING_OP_FUTEX_WAKE` (since Linux 6.7)
477630
FutexWake = sys::io_uring_op::IORING_OP_FUTEX_WAKE as _,
478631

479-
/// `IORING_OP_FUTEX_WAITV`
632+
/// `IORING_OP_FUTEX_WAITV` (since Linux 6.7)
480633
FutexWaitv = sys::io_uring_op::IORING_OP_FUTEX_WAITV as _,
481634

482-
/// `IORING_OP_FIXED_FD_INSTALL`
635+
/// `IORING_OP_FIXED_FD_INSTALL` (since Linux 6.8)
483636
FixedFdInstall = sys::io_uring_op::IORING_OP_FIXED_FD_INSTALL as _,
484637

485-
/// `IORING_OP_FTRUNCATE`
638+
/// `IORING_OP_FTRUNCATE` (since Linux 6.9)
486639
Ftruncate = sys::io_uring_op::IORING_OP_FTRUNCATE as _,
487640

488-
/// `IORING_OP_BIND`
641+
/// `IORING_OP_BIND` (since Linux 6.11)
489642
Bind = sys::io_uring_op::IORING_OP_BIND as _,
490643

491-
/// `IORING_OP_LISTEN`
644+
/// `IORING_OP_LISTEN` (since Linux 6.11)
492645
Listen = sys::io_uring_op::IORING_OP_LISTEN as _,
493646
}
494647

@@ -1702,6 +1855,51 @@ pub struct io_uring_buf_ring {
17021855
pub tail_or_bufs: tail_or_bufs_struct,
17031856
}
17041857

1858+
#[allow(missing_docs)]
1859+
#[repr(C)]
1860+
#[derive(Debug, Default)]
1861+
#[non_exhaustive]
1862+
pub struct io_uring_napi {
1863+
pub busy_poll_to: u32,
1864+
pub prefer_busy_poll: u8,
1865+
pub opcode: u8,
1866+
#[doc(hidden)]
1867+
pub pad: [u8; 2],
1868+
pub op_param: u32,
1869+
#[doc(hidden)]
1870+
pub resv: u32,
1871+
}
1872+
1873+
#[allow(missing_docs)]
1874+
#[repr(C)]
1875+
#[derive(Debug, Default)]
1876+
#[non_exhaustive]
1877+
pub struct io_uring_clone_buffers {
1878+
pub src_fd: u32,
1879+
pub flags: u32,
1880+
pub src_off: u32,
1881+
pub dst_off: u32,
1882+
pub nr: u32,
1883+
#[doc(hidden)]
1884+
pub pad: [u32; 3],
1885+
}
1886+
1887+
#[allow(missing_docs)]
1888+
#[repr(C)]
1889+
#[derive(Debug, Default)]
1890+
#[non_exhaustive]
1891+
pub struct io_uring_reg_wait {
1892+
pub ts: Timespec,
1893+
pub min_wait_usec: u32,
1894+
pub flags: u32,
1895+
pub sigmask: io_uring_ptr,
1896+
pub sigmask_sz: u32,
1897+
#[doc(hidden)]
1898+
pub pad: [u32; 3],
1899+
#[doc(hidden)]
1900+
pub pad2: [u64; 2],
1901+
}
1902+
17051903
impl Default for ioprio_union {
17061904
#[inline]
17071905
fn default() -> Self {
@@ -1940,6 +2138,35 @@ mod tests {
19402138
);
19412139
check_struct_renamed_field!(io_uring_buf_ring, tail_or_bufs, __bindgen_anon_1);
19422140

2141+
check_struct!(
2142+
io_uring_napi,
2143+
busy_poll_to,
2144+
prefer_busy_poll,
2145+
opcode,
2146+
pad,
2147+
op_param,
2148+
resv
2149+
);
2150+
check_struct!(
2151+
io_uring_clone_buffers,
2152+
src_fd,
2153+
flags,
2154+
src_off,
2155+
dst_off,
2156+
nr,
2157+
pad
2158+
);
2159+
check_struct!(
2160+
io_uring_reg_wait,
2161+
ts,
2162+
min_wait_usec,
2163+
flags,
2164+
sigmask,
2165+
sigmask_sz,
2166+
pad,
2167+
pad2
2168+
);
2169+
19432170
check_renamed_struct!(
19442171
MsgHdr,
19452172
msghdr,

0 commit comments

Comments
 (0)