1 //! Linux [io_uring].
2 //!
3 //! This API is very low-level. The main adaptations it makes from the raw
4 //! Linux io_uring API are the use of appropriately-sized `bitflags`, `enum`,
5 //! `Result`, `OwnedFd`, `AsFd`, `RawFd`, and `*mut c_void` in place of plain
6 //! integers.
7 //!
8 //! # Safety
9 //!
10 //! io_uring operates on raw pointers and raw file descriptors. Rustix does not
11 //! attempt to provide a safe API for these, because the abstraction level is
12 //! too low for this to be practical. Safety should be introduced in
13 //! higher-level abstraction layers.
14 //!
15 //! # References
16 //!  - [Linux]
17 //!
18 //! [Linux]: https://man.archlinux.org/man/io_uring.7.en
19 //! [io_uring]: https://en.wikipedia.org/wiki/Io_uring
20 #![allow(unsafe_code)]
21 
22 use crate::fd::{AsFd, BorrowedFd, OwnedFd, RawFd};
23 use crate::{backend, io};
24 use core::ffi::c_void;
25 use core::ptr::null_mut;
26 use linux_raw_sys::general as sys;
27 
28 /// `io_uring_setup(entries, params)`—Setup a context for performing
29 /// asynchronous I/O.
30 ///
31 /// # References
32 ///  - [Linux]
33 ///
34 /// [Linux]: https://man.archlinux.org/man/io_uring_setup.2.en
35 #[inline]
io_uring_setupnull36 pub fn io_uring_setup(entries: u32, params: &mut io_uring_params) -> io::Result<OwnedFd> {
37     backend::io_uring::syscalls::io_uring_setup(entries, params)
38 }
39 
40 /// `io_uring_register(fd, opcode, arg, nr_args)`—Register files or user
41 /// buffers for asynchronous I/O.
42 ///
43 /// # Safety
44 ///
45 /// io_uring operates on raw pointers and raw file descriptors. Users are
46 /// responsible for ensuring that memory and resources are only accessed in
47 /// valid ways.
48 ///
49 /// # References
50 ///  - [Linux]
51 ///
52 /// [Linux]: https://man.archlinux.org/man/io_uring_register.2.en
53 #[inline]
io_uring_registernull54 pub unsafe fn io_uring_register<Fd: AsFd>(
55     fd: Fd,
56     opcode: IoringRegisterOp,
57     arg: *const c_void,
58     nr_args: u32,
59 ) -> io::Result<()> {
60     backend::io_uring::syscalls::io_uring_register(fd.as_fd(), opcode, arg, nr_args)
61 }
62 
63 /// `io_uring_enter(fd, to_submit, min_complete, flags, arg, size)`—Initiate
64 /// and/or complete asynchronous I/O.
65 ///
66 /// # Safety
67 ///
68 /// io_uring operates on raw pointers and raw file descriptors. Users are
69 /// responsible for ensuring that memory and resources are only accessed in
70 /// valid ways.
71 ///
72 /// # References
73 ///  - [Linux]
74 ///
75 /// [Linux]: https://man.archlinux.org/man/io_uring_enter.2.en
76 #[inline]
io_uring_enternull77 pub unsafe fn io_uring_enter<Fd: AsFd>(
78     fd: Fd,
79     to_submit: u32,
80     min_complete: u32,
81     flags: IoringEnterFlags,
82     arg: *const c_void,
83     size: usize,
84 ) -> io::Result<u32> {
85     backend::io_uring::syscalls::io_uring_enter(
86         fd.as_fd(),
87         to_submit,
88         min_complete,
89         flags,
90         arg,
91         size,
92     )
93 }
94 
95 bitflags::bitflags! {
96     /// `IORING_ENTER_*` flags for use with [`io_uring_enter`].
97     #[derive(Default)]
98     pub struct IoringEnterFlags: u32 {
99         /// `IORING_ENTER_GETEVENTS`
100         const GETEVENTS = sys::IORING_ENTER_GETEVENTS;
101 
102         /// `IORING_ENTER_SQ_WAKEUP`
103         const SQ_WAKEUP = sys::IORING_ENTER_SQ_WAKEUP;
104 
105         /// `IORING_ENTER_SQ_WAIT`
106         const SQ_WAIT = sys::IORING_ENTER_SQ_WAIT;
107 
108         /// `IORING_ENTER_EXT_ARG`
109         const EXT_ARG = sys::IORING_ENTER_EXT_ARG;
110     }
111 }
112 
113 /// `IORING_REGISTER_*` and `IORING_UNREGISTER_*` constants for use with
114 /// [`io_uring_register`].
115 #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
116 #[repr(u8)]
117 #[non_exhaustive]
118 pub enum IoringRegisterOp {
119     /// `IORING_REGISTER_BUFFERS`
120     RegisterBuffers = sys::IORING_REGISTER_BUFFERS as _,
121 
122     /// `IORING_UNREGISTER_BUFFERS`
123     UnregisterBuffers = sys::IORING_UNREGISTER_BUFFERS as _,
124 
125     /// `IORING_REGISTER_FILES`
126     RegisterFiles = sys::IORING_REGISTER_FILES as _,
127 
128     /// `IORING_UNREGISTER_FILES`
129     UnregisterFiles = sys::IORING_UNREGISTER_FILES as _,
130 
131     /// `IORING_REGISTER_EVENTFD`
132     RegisterEventfd = sys::IORING_REGISTER_EVENTFD as _,
133 
134     /// `IORING_UNREGISTER_EVENTFD`
135     UnregisterEventfd = sys::IORING_UNREGISTER_EVENTFD as _,
136 
137     /// `IORING_REGISTER_FILES_UPDATE`
138     RegisterFilesUpdate = sys::IORING_REGISTER_FILES_UPDATE as _,
139 
140     /// `IORING_REGISTER_EVENTFD_ASYNC`
141     RegisterEventfdAsync = sys::IORING_REGISTER_EVENTFD_ASYNC as _,
142 
143     /// `IORING_REGISTER_PROBE`
144     RegisterProbe = sys::IORING_REGISTER_PROBE as _,
145 
146     /// `IORING_REGISTER_PERSONALITY`
147     RegisterPersonality = sys::IORING_REGISTER_PERSONALITY as _,
148 
149     /// `IORING_UNREGISTER_PERSONALITY`
150     UnregisterPersonality = sys::IORING_UNREGISTER_PERSONALITY as _,
151 
152     /// `IORING_REGISTER_RESTRICTIONS`
153     RegisterRestrictions = sys::IORING_REGISTER_RESTRICTIONS as _,
154 
155     /// `IORING_REGISTER_ENABLE_RINGS`
156     RegisterEnableRings = sys::IORING_REGISTER_ENABLE_RINGS as _,
157 
158     /// `IORING_REGISTER_BUFFERS2`
159     RegisterBuffers2 = sys::IORING_REGISTER_BUFFERS2 as _,
160 
161     /// `IORING_REGISTER_BUFFERS_UPDATE`
162     RegisterBuffersUpdate = sys::IORING_REGISTER_BUFFERS_UPDATE as _,
163 
164     /// `IORING_REGISTER_FILES2`
165     RegisterFiles2 = sys::IORING_REGISTER_FILES2 as _,
166 
167     /// `IORING_REGISTER_FILES_SKIP`
168     RegisterFilesSkip = sys::IORING_REGISTER_FILES_SKIP as _,
169 
170     /// `IORING_REGISTER_FILES_UPDATE2`
171     RegisterFilesUpdate2 = sys::IORING_REGISTER_FILES_UPDATE2 as _,
172 
173     /// `IORING_REGISTER_IOWQ_AFF`
174     RegisterIowqAff = sys::IORING_REGISTER_IOWQ_AFF as _,
175 
176     /// `IORING_UNREGISTER_IOWQ_AFF`
177     UnregisterIowqAff = sys::IORING_UNREGISTER_IOWQ_AFF as _,
178 
179     /// `IORING_REGISTER_IOWQ_MAX_WORKERS`
180     RegisterIowqMaxWorkers = sys::IORING_REGISTER_IOWQ_MAX_WORKERS as _,
181 }
182 
183 /// `IORING_OP_*` constants for use with [`io_uring_sqe`].
184 #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
185 #[repr(u8)]
186 #[non_exhaustive]
187 pub enum IoringOp {
188     /// `IORING_OP_NOP`
189     Nop = sys::IORING_OP_NOP as _,
190 
191     /// `IORING_OP_ACCEPT`
192     Accept = sys::IORING_OP_ACCEPT as _,
193 
194     /// `IORING_OP_ASYNC_CANCEL`
195     AsyncCancel = sys::IORING_OP_ASYNC_CANCEL as _,
196 
197     /// `IORING_OP_CLOSE`
198     Close = sys::IORING_OP_CLOSE as _,
199 
200     /// `IORING_OP_CONNECT`
201     Connect = sys::IORING_OP_CONNECT as _,
202 
203     /// `IORING_OP_EPOLL_CTL`
204     EpollCtl = sys::IORING_OP_EPOLL_CTL as _,
205 
206     /// `IORING_OP_FADVISE`
207     Fadvise = sys::IORING_OP_FADVISE as _,
208 
209     /// `IORING_OP_FALLOCATE`
210     Fallocate = sys::IORING_OP_FALLOCATE as _,
211 
212     /// `IORING_OP_FILES_UPDATE`
213     FilesUpdate = sys::IORING_OP_FILES_UPDATE as _,
214 
215     /// `IORING_OP_FSYNC`
216     Fsync = sys::IORING_OP_FSYNC as _,
217 
218     /// `IORING_OP_LINKAT`
219     Linkat = sys::IORING_OP_LINKAT as _,
220 
221     /// `IORING_OP_LINK_TIMEOUT`
222     LinkTimeout = sys::IORING_OP_LINK_TIMEOUT as _,
223 
224     /// `IORING_OP_MADVISE`
225     Madvise = sys::IORING_OP_MADVISE as _,
226 
227     /// `IORING_OP_MKDIRAT`
228     Mkdirat = sys::IORING_OP_MKDIRAT as _,
229 
230     /// `IORING_OP_OPENAT`
231     Openat = sys::IORING_OP_OPENAT as _,
232 
233     /// `IORING_OP_OPENAT2`
234     Openat2 = sys::IORING_OP_OPENAT2 as _,
235 
236     /// `IORING_OP_POLL_ADD`
237     PollAdd = sys::IORING_OP_POLL_ADD as _,
238 
239     /// `IORING_OP_POLL_REMOVE`
240     PollRemove = sys::IORING_OP_POLL_REMOVE as _,
241 
242     /// `IORING_OP_PROVIDE_BUFFERS`
243     ProvideBuffers = sys::IORING_OP_PROVIDE_BUFFERS as _,
244 
245     /// `IORING_OP_READ`
246     Read = sys::IORING_OP_READ as _,
247 
248     /// `IORING_OP_READV`
249     Readv = sys::IORING_OP_READV as _,
250 
251     /// `IORING_OP_READ_FIXED`
252     ReadFixed = sys::IORING_OP_READ_FIXED as _,
253 
254     /// `IORING_OP_RECV`
255     Recv = sys::IORING_OP_RECV as _,
256 
257     /// `IORING_OP_RECVMSG`
258     Recvmsg = sys::IORING_OP_RECVMSG as _,
259 
260     /// `IORING_OP_REMOVE_BUFFERS`
261     RemoveBuffers = sys::IORING_OP_REMOVE_BUFFERS as _,
262 
263     /// `IORING_OP_RENAMEAT`
264     Renameat = sys::IORING_OP_RENAMEAT as _,
265 
266     /// `IORING_OP_SEND`
267     Send = sys::IORING_OP_SEND as _,
268 
269     /// `IORING_OP_SENDMSG`
270     Sendmsg = sys::IORING_OP_SENDMSG as _,
271 
272     /// `IORING_OP_SHUTDOWN`
273     Shutdown = sys::IORING_OP_SHUTDOWN as _,
274 
275     /// `IORING_OP_SPLICE`
276     Splice = sys::IORING_OP_SPLICE as _,
277 
278     /// `IORING_OP_STATX`
279     Statx = sys::IORING_OP_STATX as _,
280 
281     /// `IORING_OP_SYMLINKAT`
282     Symlinkat = sys::IORING_OP_SYMLINKAT as _,
283 
284     /// `IORING_OP_SYNC_FILE_RANGE`
285     SyncFileRange = sys::IORING_OP_SYNC_FILE_RANGE as _,
286 
287     /// `IORING_OP_TEE`
288     Tee = sys::IORING_OP_TEE as _,
289 
290     /// `IORING_OP_TIMEOUT`
291     Timeout = sys::IORING_OP_TIMEOUT as _,
292 
293     /// `IORING_OP_TIMEOUT_REMOVE`
294     TimeoutRemove = sys::IORING_OP_TIMEOUT_REMOVE as _,
295 
296     /// `IORING_OP_UNLINKAT`
297     Unlinkat = sys::IORING_OP_UNLINKAT as _,
298 
299     /// `IORING_OP_WRITE`
300     Write = sys::IORING_OP_WRITE as _,
301 
302     /// `IORING_OP_WRITEV`
303     Writev = sys::IORING_OP_WRITEV as _,
304 
305     /// `IORING_OP_WRITE_FIXED`
306     WriteFixed = sys::IORING_OP_WRITE_FIXED as _,
307 }
308 
309 impl Default for IoringOp {
310     #[inline]
defaultnull311     fn default() -> Self {
312         Self::Nop
313     }
314 }
315 
316 /// `IORING_RESTRICTION_*` constants for use with [`io_uring_restriction`].
317 #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
318 #[repr(u16)]
319 #[non_exhaustive]
320 pub enum IoringRestrictionOp {
321     /// `IORING_RESTRICTION_REGISTER_OP`
322     RegisterOp = sys::IORING_RESTRICTION_REGISTER_OP as _,
323 
324     /// `IORING_RESTRICTION_SQE_FLAGS_ALLOWED`
325     SqeFlagsAllowed = sys::IORING_RESTRICTION_SQE_FLAGS_ALLOWED as _,
326 
327     /// `IORING_RESTRICTION_SQE_FLAGS_REQUIRED`
328     SqeFlagsRequired = sys::IORING_RESTRICTION_SQE_FLAGS_REQUIRED as _,
329 
330     /// `IORING_RESTRICTION_SQE_OP`
331     SqeOp = sys::IORING_RESTRICTION_SQE_OP as _,
332 }
333 
334 impl Default for IoringRestrictionOp {
335     #[inline]
defaultnull336     fn default() -> Self {
337         Self::RegisterOp
338     }
339 }
340 
341 bitflags::bitflags! {
342     /// `IORING_SETUP_*` flags for use with [`io_uring_params`].
343     #[derive(Default)]
344     pub struct IoringSetupFlags: u32 {
345         /// `IORING_SETUP_ATTACH_WQ`
346         const ATTACH_WQ = sys::IORING_SETUP_ATTACH_WQ;
347 
348         /// `IORING_SETUP_CLAMP`
349         const CLAMP = sys::IORING_SETUP_CLAMP;
350 
351         /// `IORING_SETUP_CQSIZE`
352         const CQSIZE = sys::IORING_SETUP_CQSIZE;
353 
354         /// `IORING_SETUP_IOPOLL`
355         const IOPOLL = sys::IORING_SETUP_IOPOLL;
356 
357         /// `IORING_SETUP_R_DISABLED`
358         const R_DISABLED = sys::IORING_SETUP_R_DISABLED;
359 
360         /// `IORING_SETUP_SQPOLL`
361         const SQPOLL = sys::IORING_SETUP_SQPOLL;
362 
363         /// `IORING_SETUP_SQ_AFF`
364         const SQ_AFF = sys::IORING_SETUP_SQ_AFF;
365     }
366 }
367 
368 bitflags::bitflags! {
369     /// `IOSQE_*` flags for use with [`io_uring_sqe`].
370     #[derive(Default)]
371     pub struct IoringSqeFlags: u8 {
372         /// `1 << IOSQE_ASYNC_BIT`
373         const ASYNC = 1 << sys::IOSQE_ASYNC_BIT as u8;
374 
375         /// `1 << IOSQE_BUFFER_SELECT_BIT`
376         const BUFFER_SELECT = 1 << sys::IOSQE_BUFFER_SELECT_BIT as u8;
377 
378         /// `1 << IOSQE_FIXED_FILE_BIT`
379         const FIXED_FILE = 1 << sys::IOSQE_FIXED_FILE_BIT as u8;
380 
381         /// 1 << `IOSQE_IO_DRAIN_BIT`
382         const IO_DRAIN = 1 << sys::IOSQE_IO_DRAIN_BIT as u8;
383 
384         /// `1 << IOSQE_IO_HARDLINK_BIT`
385         const IO_HARDLINK = 1 << sys::IOSQE_IO_HARDLINK_BIT as u8;
386 
387         /// `1 << IOSQE_IO_LINK_BIT`
388         const IO_LINK = 1 << sys::IOSQE_IO_LINK_BIT as u8;
389     }
390 }
391 
392 bitflags::bitflags! {
393     /// `IORING_CQE_F_*` flags for use with [`io_uring_cqe`].
394     #[derive(Default)]
395     pub struct IoringCqeFlags: u32 {
396         /// `IORING_CQE_F_BUFFER`
397         const BUFFER = sys::IORING_CQE_F_BUFFER as _;
398 
399         /// `IORING_CQE_F_MORE`
400         const MORE = sys::IORING_CQE_F_MORE as _;
401     }
402 }
403 
404 bitflags::bitflags! {
405     /// `IORING_FSYNC_*` flags for use with [`io_uring_sqe`].
406     #[derive(Default)]
407     pub struct IoringFsyncFlags: u32 {
408         /// `IORING_FSYNC_DATASYNC`
409         const DATASYNC = sys::IORING_FSYNC_DATASYNC;
410     }
411 }
412 
413 bitflags::bitflags! {
414     /// `IORING_TIMEOUT_*` and `IORING_LINK_TIMEOUT_UPDATE` flags for use with
415     /// [`io_uring_sqe`].
416     #[derive(Default)]
417     pub struct IoringTimeoutFlags: u32 {
418         /// `IORING_TIMEOUT_ABS`
419         const ABS = sys::IORING_TIMEOUT_ABS;
420 
421         /// `IORING_TIMEOUT_UPDATE`
422         const UPDATE = sys::IORING_TIMEOUT_UPDATE;
423 
424         /// `IORING_TIMEOUT_BOOTTIME`
425         const BOOTTIME = sys::IORING_TIMEOUT_BOOTTIME;
426 
427         /// `IORING_TIMEOUT_ETIME_SUCCESS`
428         const ETIME_SUCCESS = sys::IORING_TIMEOUT_ETIME_SUCCESS;
429 
430         /// `IORING_TIMEOUT_REALTIME`
431         const REALTIME = sys::IORING_TIMEOUT_REALTIME;
432 
433         /// `IORING_TIMEOUT_CLOCK_MASK`
434         const CLOCK_MASK = sys::IORING_TIMEOUT_CLOCK_MASK;
435 
436         /// `IORING_TIMEOUT_UPDATE_MASK`
437         const UPDATE_MASK = sys::IORING_TIMEOUT_UPDATE_MASK;
438 
439         /// `IORING_LINK_TIMEOUT_UPDATE`
440         const LINK_TIMEOUT_UPDATE = sys::IORING_LINK_TIMEOUT_UPDATE;
441     }
442 }
443 
444 bitflags::bitflags! {
445     /// `SPLICE_F_*` flags for use with [`io_uring_sqe`].
446     #[derive(Default)]
447     pub struct SpliceFlags: u32 {
448         /// `SPLICE_F_FD_IN_FIXED`
449         const FD_IN_FIXED = sys::SPLICE_F_FD_IN_FIXED;
450     }
451 }
452 
453 bitflags::bitflags! {
454     /// `IORING_FEAT_*` flags for use with [`io_uring_params`].
455     #[derive(Default)]
456     pub struct IoringFeatureFlags: u32 {
457         /// `IORING_FEAT_CQE_SKIP`
458         const CQE_SKIP = sys::IORING_FEAT_CQE_SKIP;
459 
460         /// `IORING_FEAT_CUR_PERSONALITY`
461         const CUR_PERSONALITY = sys::IORING_FEAT_CUR_PERSONALITY;
462 
463         /// `IORING_FEAT_EXT_ARG`
464         const EXT_ARG = sys::IORING_FEAT_EXT_ARG;
465 
466         /// `IORING_FEAT_FAST_POLL`
467         const FAST_POLL = sys::IORING_FEAT_FAST_POLL;
468 
469         /// `IORING_FEAT_NATIVE_WORKERS`
470         const NATIVE_WORKERS = sys::IORING_FEAT_NATIVE_WORKERS;
471 
472         /// `IORING_FEAT_NODROP`
473         const NODROP = sys::IORING_FEAT_NODROP;
474 
475         /// `IORING_FEAT_POLL_32BITS`
476         const POLL_32BITS = sys::IORING_FEAT_POLL_32BITS;
477 
478         /// `IORING_FEAT_RSRC_TAGS`
479         const RSRC_TAGS = sys::IORING_FEAT_RSRC_TAGS;
480 
481         /// `IORING_FEAT_RW_CUR_POS`
482         const RW_CUR_POS = sys::IORING_FEAT_RW_CUR_POS;
483 
484         /// `IORING_FEAT_SINGLE_MMAP`
485         const SINGLE_MMAP = sys::IORING_FEAT_SINGLE_MMAP;
486 
487         /// `IORING_FEAT_SQPOLL_NONFIXED`
488         const SQPOLL_NONFIXED = sys::IORING_FEAT_SQPOLL_NONFIXED;
489 
490         /// `IORING_FEAT_SUBMIT_STABLE`
491         const SUBMIT_STABLE = sys::IORING_FEAT_SUBMIT_STABLE;
492     }
493 }
494 
495 bitflags::bitflags! {
496     /// `IO_URING_OP_*` flags for use with [`io_uring_probe_op`].
497     #[derive(Default)]
498     pub struct IoringOpFlags: u16 {
499         /// `IO_URING_OP_SUPPORTED`
500         const SUPPORTED = sys::IO_URING_OP_SUPPORTED as _;
501     }
502 }
503 
504 bitflags::bitflags! {
505     /// `IORING_SQ_*` flags.
506     #[derive(Default)]
507     pub struct IoringSqFlags: u32 {
508         /// `IORING_SQ_NEED_WAKEUP`
509         const NEED_WAKEUP = sys::IORING_SQ_NEED_WAKEUP;
510 
511         /// `IORING_SQ_CQ_OVERFLOW`
512         const CQ_OVERFLOW = sys::IORING_SQ_CQ_OVERFLOW;
513     }
514 }
515 
516 bitflags::bitflags! {
517     /// `IORING_CQ_*` flags.
518     #[derive(Default)]
519     pub struct IoringCqFlags: u32 {
520         /// `IORING_CQ_EVENTFD_DISABLED`
521         const EVENTFD_DISABLED = sys::IORING_CQ_EVENTFD_DISABLED;
522     }
523 }
524 
525 bitflags::bitflags! {
526     /// `IORING_POLL_*` flags.
527     #[derive(Default)]
528     pub struct IoringPollFlags: u32 {
529         /// `IORING_POLL_ADD_MULTI`
530         const ADD_MULTI = sys::IORING_POLL_ADD_MULTI;
531 
532         /// `IORING_POLL_UPDATE_EVENTS`
533         const UPDATE_EVENTS = sys::IORING_POLL_UPDATE_EVENTS;
534 
535         /// `IORING_POLL_UPDATE_USER_DATA`
536         const UPDATE_USER_DATA = sys::IORING_POLL_UPDATE_USER_DATA;
537     }
538 }
539 
540 #[allow(missing_docs)]
541 pub const IORING_CQE_BUFFER_SHIFT: u32 = sys::IORING_CQE_BUFFER_SHIFT as _;
542 
543 // Re-export these as `u64`, which is the `offset` type in `rustix::io::mmap`.
544 #[allow(missing_docs)]
545 pub const IORING_OFF_SQ_RING: u64 = sys::IORING_OFF_SQ_RING as _;
546 #[allow(missing_docs)]
547 pub const IORING_OFF_CQ_RING: u64 = sys::IORING_OFF_CQ_RING as _;
548 #[allow(missing_docs)]
549 pub const IORING_OFF_SQES: u64 = sys::IORING_OFF_SQES as _;
550 
551 /// `IORING_REGISTER_FILES_SKIP`
552 #[inline]
553 #[doc(alias = "IORING_REGISTER_FILES_SKIP")]
554 pub const fn io_uring_register_files_skip() -> BorrowedFd<'static> {
555     let files_skip = sys::IORING_REGISTER_FILES_SKIP as RawFd;
556 
557     // Safety: `IORING_REGISTER_FILES_SKIP` is a reserved value that is never
558     // dynamically allocated, so it'll remain valid for the duration of
559     // `'static`.
560     unsafe { BorrowedFd::<'static>::borrow_raw(files_skip) }
561 }
562 
563 /// A pointer in the io_uring API.
564 ///
565 /// `io_uring`'s native API represents pointers as `u64` values. In order to
566 /// preserve strict-provenance, use a `*mut c_void`. On platforms where
567 /// pointers are narrower than 64 bits, this requires additional padding.
568 #[repr(C)]
569 #[derive(Copy, Clone)]
570 pub struct io_uring_ptr {
571     #[cfg(all(target_pointer_width = "32", target_endian = "big"))]
572     #[doc(hidden)]
573     pub __pad32: u32,
574     #[cfg(all(target_pointer_width = "16", target_endian = "big"))]
575     #[doc(hidden)]
576     pub __pad16: u16,
577 
578     /// The pointer value.
579     pub ptr: *mut c_void,
580 
581     #[cfg(all(target_pointer_width = "16", target_endian = "little"))]
582     #[doc(hidden)]
583     pub __pad16: u16,
584     #[cfg(all(target_pointer_width = "32", target_endian = "little"))]
585     #[doc(hidden)]
586     pub __pad32: u32,
587 }
588 
589 impl From<*mut c_void> for io_uring_ptr {
590     #[inline]
fromnull591     fn from(ptr: *mut c_void) -> Self {
592         Self {
593             ptr,
594 
595             #[cfg(target_pointer_width = "16")]
596             __pad16: Default::default(),
597             #[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
598             __pad32: Default::default(),
599         }
600     }
601 }
602 
603 impl Default for io_uring_ptr {
604     #[inline]
defaultnull605     fn default() -> Self {
606         Self::from(null_mut())
607     }
608 }
609 
610 /// User data in the io_uring API.
611 ///
612 /// `io_uring`'s native API represents `user_data` fields as `u64` values. In
613 /// order to preserve strict-provenance, use a union which allows users to
614 /// optionally store pointers.
615 #[repr(C)]
616 #[derive(Copy, Clone)]
617 pub union io_uring_user_data {
618     /// An arbitrary `u64`.
619     pub u64_: u64,
620 
621     /// A pointer.
622     pub ptr: io_uring_ptr,
623 }
624 
625 impl io_uring_user_data {
626     /// Return the `u64` value.
627     #[inline]
u64_null628     pub fn u64_(self) -> u64 {
629         // Safety: All the fields have the same underlying representation.
630         unsafe { self.u64_ }
631     }
632 
633     /// Create a `Self` from a `u64` value.
634     #[inline]
from_u64null635     pub fn from_u64(u64_: u64) -> Self {
636         Self { u64_ }
637     }
638 
639     /// Return the `ptr` pointer value.
640     #[inline]
ptrnull641     pub fn ptr(self) -> *mut c_void {
642         // Safety: All the fields have the same underlying representation.
643         unsafe { self.ptr }.ptr
644     }
645 
646     /// Create a `Self` from a pointer value.
647     #[inline]
from_ptrnull648     pub fn from_ptr(ptr: *mut c_void) -> Self {
649         Self {
650             ptr: io_uring_ptr::from(ptr),
651         }
652     }
653 }
654 
655 impl Default for io_uring_user_data {
656     #[inline]
defaultnull657     fn default() -> Self {
658         let mut s = ::core::mem::MaybeUninit::<Self>::uninit();
659         // Safety: All of Linux's io_uring structs may be zero-initialized.
660         unsafe {
661             ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
662             s.assume_init()
663         }
664     }
665 }
666 
667 impl core::fmt::Debug for io_uring_user_data {
fmtnull668     fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
669         // Safety: Just format as a `u64`, since formatting doesn't preserve
670         // provenance, and we don't have a discriminant.
671         unsafe { self.u64_.fmt(fmt) }
672     }
673 }
674 
675 /// An io_uring Submission Queue Entry.
676 #[allow(missing_docs)]
677 #[repr(C)]
678 #[derive(Copy, Clone, Default)]
679 pub struct io_uring_sqe {
680     pub opcode: IoringOp,
681     pub flags: IoringSqeFlags,
682     pub ioprio: u16,
683     pub fd: RawFd,
684     pub off_or_addr2: off_or_addr2_union,
685     pub addr_or_splice_off_in: addr_or_splice_off_in_union,
686     pub len: u32,
687     pub op_flags: op_flags_union,
688     pub user_data: io_uring_user_data,
689     pub buf: buf_union,
690     pub personality: u16,
691     pub splice_fd_in_or_file_index: splice_fd_in_or_file_index_union,
692     pub __pad2: [u64; 2],
693 }
694 
695 #[allow(missing_docs)]
696 #[repr(C)]
697 #[derive(Copy, Clone)]
698 pub union off_or_addr2_union {
699     pub off: u64,
700     pub addr2: io_uring_ptr,
701 }
702 
703 #[allow(missing_docs)]
704 #[repr(C)]
705 #[derive(Copy, Clone)]
706 pub union addr_or_splice_off_in_union {
707     pub addr: io_uring_ptr,
708     pub splice_off_in: u64,
709 }
710 
711 #[allow(missing_docs)]
712 #[repr(C)]
713 #[derive(Copy, Clone)]
714 pub union op_flags_union {
715     pub rw_flags: crate::io::ReadWriteFlags,
716     pub fsync_flags: IoringFsyncFlags,
717     pub poll_events: u16,
718     pub poll32_events: u32,
719     pub sync_range_flags: u32,
720     /// `msg_flags` is split into `send_flags` and `recv_flags`.
721     #[doc(alias = "msg_flags")]
722     pub send_flags: crate::net::SendFlags,
723     /// `msg_flags` is split into `send_flags` and `recv_flags`.
724     #[doc(alias = "msg_flags")]
725     pub recv_flags: crate::net::RecvFlags,
726     pub timeout_flags: IoringTimeoutFlags,
727     pub accept_flags: crate::net::AcceptFlags,
728     pub cancel_flags: u32,
729     pub open_flags: crate::fs::AtFlags,
730     pub statx_flags: crate::fs::AtFlags,
731     pub fadvise_advice: crate::fs::Advice,
732     pub splice_flags: SpliceFlags,
733     pub rename_flags: crate::fs::RenameFlags,
734     pub unlink_flags: crate::fs::AtFlags,
735     pub hardlink_flags: crate::fs::AtFlags,
736 }
737 
738 #[allow(missing_docs)]
739 #[repr(C, packed)]
740 #[derive(Copy, Clone)]
741 pub union buf_union {
742     pub buf_index: u16,
743     pub buf_group: u16,
744 }
745 
746 #[allow(missing_docs)]
747 #[repr(C)]
748 #[derive(Copy, Clone)]
749 pub union splice_fd_in_or_file_index_union {
750     pub splice_fd_in: i32,
751     pub file_index: u32,
752 }
753 
754 /// An io_uring Completion Queue Entry.
755 #[allow(missing_docs)]
756 #[repr(C)]
757 #[derive(Debug, Copy, Clone, Default)]
758 pub struct io_uring_cqe {
759     pub user_data: io_uring_user_data,
760     pub res: i32,
761     pub flags: IoringCqeFlags,
762 }
763 
764 #[allow(missing_docs)]
765 #[repr(C)]
766 #[derive(Copy, Clone, Default)]
767 pub struct io_uring_restriction {
768     pub opcode: IoringRestrictionOp,
769     pub register_or_sqe_op_or_sqe_flags: register_or_sqe_op_or_sqe_flags_union,
770     pub resv: u8,
771     pub resv2: [u32; 3],
772 }
773 
774 #[allow(missing_docs)]
775 #[repr(C)]
776 #[derive(Copy, Clone)]
777 pub union register_or_sqe_op_or_sqe_flags_union {
778     pub register_op: IoringRegisterOp,
779     pub sqe_op: IoringOp,
780     pub sqe_flags: IoringSqeFlags,
781 }
782 
783 #[allow(missing_docs)]
784 #[repr(C)]
785 #[derive(Debug, Copy, Clone, Default)]
786 pub struct io_uring_params {
787     pub sq_entries: u32,
788     pub cq_entries: u32,
789     pub flags: IoringSetupFlags,
790     pub sq_thread_cpu: u32,
791     pub sq_thread_idle: u32,
792     pub features: IoringFeatureFlags,
793     pub wq_fd: u32,
794     pub resv: [u32; 3],
795     pub sq_off: io_sqring_offsets,
796     pub cq_off: io_cqring_offsets,
797 }
798 
799 #[allow(missing_docs)]
800 #[repr(C)]
801 #[derive(Debug, Copy, Clone, Default)]
802 pub struct io_sqring_offsets {
803     pub head: u32,
804     pub tail: u32,
805     pub ring_mask: u32,
806     pub ring_entries: u32,
807     pub flags: u32,
808     pub dropped: u32,
809     pub array: u32,
810     pub resv1: u32,
811     pub resv2: u64,
812 }
813 
814 #[allow(missing_docs)]
815 #[repr(C)]
816 #[derive(Debug, Copy, Clone, Default)]
817 pub struct io_cqring_offsets {
818     pub head: u32,
819     pub tail: u32,
820     pub ring_mask: u32,
821     pub ring_entries: u32,
822     pub overflow: u32,
823     pub cqes: u32,
824     pub flags: u32,
825     pub resv1: u32,
826     pub resv2: u64,
827 }
828 
829 #[allow(missing_docs)]
830 #[repr(C)]
831 #[derive(Debug, Default)]
832 pub struct io_uring_probe {
833     pub last_op: IoringOp,
834     pub ops_len: u8,
835     pub resv: u16,
836     pub resv2: [u32; 3],
837     pub ops: sys::__IncompleteArrayField<io_uring_probe_op>,
838 }
839 
840 #[allow(missing_docs)]
841 #[repr(C)]
842 #[derive(Debug, Copy, Clone, Default)]
843 pub struct io_uring_probe_op {
844     pub op: IoringOp,
845     pub resv: u8,
846     pub flags: IoringOpFlags,
847     pub resv2: u32,
848 }
849 
850 #[allow(missing_docs)]
851 #[repr(C, align(8))]
852 #[derive(Debug, Copy, Clone, Default)]
853 pub struct io_uring_files_update {
854     pub offset: u32,
855     pub resv: u32,
856     pub fds: u64,
857 }
858 
859 #[allow(missing_docs)]
860 #[repr(C, align(8))]
861 #[derive(Debug, Copy, Clone, Default)]
862 pub struct io_uring_rsrc_register {
863     pub nr: u32,
864     pub resv: u32,
865     pub resv2: u64,
866     pub data: u64,
867     pub tags: u64,
868 }
869 
870 #[allow(missing_docs)]
871 #[repr(C, align(8))]
872 #[derive(Debug, Copy, Clone, Default)]
873 pub struct io_uring_rsrc_update {
874     pub offset: u32,
875     pub resv: u32,
876     pub data: u64,
877 }
878 
879 #[allow(missing_docs)]
880 #[repr(C, align(8))]
881 #[derive(Debug, Copy, Clone, Default)]
882 pub struct io_uring_rsrc_update2 {
883     pub offset: u32,
884     pub resv: u32,
885     pub data: u64,
886     pub tags: u64,
887     pub nr: u32,
888     pub resv2: u32,
889 }
890 
891 #[allow(missing_docs)]
892 #[repr(C)]
893 #[derive(Debug, Copy, Clone, Default)]
894 pub struct io_uring_getevents_arg {
895     pub sigmask: u64,
896     pub sigmask_sz: u32,
897     pub pad: u32,
898     pub ts: u64,
899 }
900 
901 #[allow(missing_docs)]
902 #[repr(C)]
903 #[derive(Debug, Copy, Clone)]
904 pub struct iovec {
905     pub iov_base: *mut c_void,
906     pub iov_len: usize,
907 }
908 
909 #[allow(missing_docs)]
910 #[repr(C)]
911 #[derive(Debug, Copy, Clone, Default)]
912 pub struct open_how {
913     /// An [`OFlags`] value represented as a `u64`.
914     ///
915     /// [`OFlags`]: crate::fs::OFlags
916     pub flags: u64,
917 
918     /// A [`Mode`] value represented as a `u64`.
919     ///
920     /// [`Mode`]: crate::fs::Mode
921     pub mode: u64,
922 
923     pub resolve: crate::fs::ResolveFlags,
924 }
925 
926 impl Default for off_or_addr2_union {
927     #[inline]
defaultnull928     fn default() -> Self {
929         let mut s = ::core::mem::MaybeUninit::<Self>::uninit();
930         // Safety: All of Linux's io_uring structs may be zero-initialized.
931         unsafe {
932             ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
933             s.assume_init()
934         }
935     }
936 }
937 
938 impl Default for addr_or_splice_off_in_union {
939     #[inline]
defaultnull940     fn default() -> Self {
941         let mut s = ::core::mem::MaybeUninit::<Self>::uninit();
942         // Safety: All of Linux's io_uring structs may be zero-initialized.
943         unsafe {
944             ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
945             s.assume_init()
946         }
947     }
948 }
949 
950 impl Default for op_flags_union {
951     #[inline]
defaultnull952     fn default() -> Self {
953         let mut s = ::core::mem::MaybeUninit::<Self>::uninit();
954         // Safety: All of Linux's io_uring structs may be zero-initialized.
955         unsafe {
956             ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
957             s.assume_init()
958         }
959     }
960 }
961 
962 impl Default for buf_union {
963     #[inline]
defaultnull964     fn default() -> Self {
965         let mut s = ::core::mem::MaybeUninit::<Self>::uninit();
966         // Safety: All of Linux's io_uring structs may be zero-initialized.
967         unsafe {
968             ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
969             s.assume_init()
970         }
971     }
972 }
973 
974 impl Default for splice_fd_in_or_file_index_union {
975     #[inline]
defaultnull976     fn default() -> Self {
977         let mut s = ::core::mem::MaybeUninit::<Self>::uninit();
978         // Safety: All of Linux's io_uring structs may be zero-initialized.
979         unsafe {
980             ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
981             s.assume_init()
982         }
983     }
984 }
985 
986 impl Default for register_or_sqe_op_or_sqe_flags_union {
987     #[inline]
defaultnull988     fn default() -> Self {
989         let mut s = ::core::mem::MaybeUninit::<Self>::uninit();
990         // Safety: All of Linux's io_uring structs may be zero-initialized.
991         unsafe {
992             ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
993             s.assume_init()
994         }
995     }
996 }
997 
998 /// Check that our custom structs and unions have the same layout as the
999 /// kernel's versions.
1000 #[test]
io_uring_layoutsnull1001 fn io_uring_layouts() {
1002     use core::mem::{align_of, size_of};
1003     use memoffset::{offset_of, span_of};
1004 
1005     // Check that the size and alignment of a type match the `sys` bindings.
1006     macro_rules! check_type {
1007         ($struct:ident) => {
1008             assert_eq!(
1009                 (size_of::<$struct>(), align_of::<$struct>()),
1010                 (size_of::<sys::$struct>(), align_of::<sys::$struct>())
1011             );
1012         };
1013     }
1014 
1015     // The same as `check_type`, but for unions we've renamed to avoid having
1016     // types like "bindgen_ty_1" in the API.
1017     macro_rules! check_renamed_union {
1018         ($to:ident, $from:ident) => {
1019             assert_eq!(
1020                 (size_of::<$to>(), align_of::<$to>()),
1021                 (size_of::<sys::$from>(), align_of::<sys::$from>())
1022             );
1023         };
1024     }
1025 
1026     // Check that the field of a struct has the same offset as the
1027     // corresponding field in the `sys` bindings.
1028     macro_rules! check_struct_field {
1029         ($struct:ident, $field:ident) => {
1030             assert_eq!(
1031                 offset_of!($struct, $field),
1032                 offset_of!(sys::$struct, $field)
1033             );
1034             assert_eq!(span_of!($struct, $field), span_of!(sys::$struct, $field));
1035         };
1036     }
1037 
1038     // The same as `check_struct_field`, but for unions we've renamed to avoid
1039     // having types like "bindgen_ty_1" in the API.
1040     macro_rules! check_struct_renamed_union_field {
1041         ($struct:ident, $to:ident, $from:ident) => {
1042             assert_eq!(offset_of!($struct, $to), offset_of!(sys::$struct, $from));
1043             assert_eq!(span_of!($struct, $to), span_of!(sys::$struct, $from));
1044         };
1045     }
1046 
1047     // For the common case of no renaming, check all fields of a struct.
1048     macro_rules! check_struct {
1049         ($name:ident, $($field:ident),*) => {
1050             // Check the size and alignment.
1051             check_type!($name);
1052 
1053             // Check that we have all the fields.
1054             let _test = $name {
1055                 // Safety: All of io_uring's types can be zero-initialized.
1056                 $($field: unsafe { core::mem::zeroed() }),*
1057             };
1058 
1059             // Check that the fields have the right sizes and offsets.
1060             $(check_struct_field!($name, $field));*
1061         };
1062     }
1063 
1064     check_renamed_union!(off_or_addr2_union, io_uring_sqe__bindgen_ty_1);
1065     check_renamed_union!(addr_or_splice_off_in_union, io_uring_sqe__bindgen_ty_2);
1066     check_renamed_union!(op_flags_union, io_uring_sqe__bindgen_ty_3);
1067     check_renamed_union!(buf_union, io_uring_sqe__bindgen_ty_4);
1068     check_renamed_union!(splice_fd_in_or_file_index_union, io_uring_sqe__bindgen_ty_5);
1069     check_renamed_union!(
1070         register_or_sqe_op_or_sqe_flags_union,
1071         io_uring_restriction__bindgen_ty_1
1072     );
1073 
1074     check_type!(io_uring_sqe);
1075     check_struct_field!(io_uring_sqe, opcode);
1076     check_struct_field!(io_uring_sqe, flags);
1077     check_struct_field!(io_uring_sqe, ioprio);
1078     check_struct_field!(io_uring_sqe, fd);
1079     check_struct_renamed_union_field!(io_uring_sqe, off_or_addr2, __bindgen_anon_1);
1080     check_struct_renamed_union_field!(io_uring_sqe, addr_or_splice_off_in, __bindgen_anon_2);
1081     check_struct_field!(io_uring_sqe, len);
1082     check_struct_renamed_union_field!(io_uring_sqe, op_flags, __bindgen_anon_3);
1083     check_struct_field!(io_uring_sqe, user_data);
1084     check_struct_renamed_union_field!(io_uring_sqe, buf, __bindgen_anon_4);
1085     check_struct_field!(io_uring_sqe, personality);
1086     check_struct_renamed_union_field!(io_uring_sqe, splice_fd_in_or_file_index, __bindgen_anon_5);
1087     check_struct_field!(io_uring_sqe, __pad2);
1088 
1089     check_type!(io_uring_restriction);
1090     check_struct_field!(io_uring_restriction, opcode);
1091     check_struct_renamed_union_field!(
1092         io_uring_restriction,
1093         register_or_sqe_op_or_sqe_flags,
1094         __bindgen_anon_1
1095     );
1096     check_struct_field!(io_uring_restriction, resv);
1097     check_struct_field!(io_uring_restriction, resv2);
1098 
1099     check_struct!(io_uring_cqe, user_data, res, flags);
1100     check_struct!(
1101         io_uring_params,
1102         sq_entries,
1103         cq_entries,
1104         flags,
1105         sq_thread_cpu,
1106         sq_thread_idle,
1107         features,
1108         wq_fd,
1109         resv,
1110         sq_off,
1111         cq_off
1112     );
1113     check_struct!(
1114         io_sqring_offsets,
1115         head,
1116         tail,
1117         ring_mask,
1118         ring_entries,
1119         flags,
1120         dropped,
1121         array,
1122         resv1,
1123         resv2
1124     );
1125     check_struct!(
1126         io_cqring_offsets,
1127         head,
1128         tail,
1129         ring_mask,
1130         ring_entries,
1131         overflow,
1132         cqes,
1133         flags,
1134         resv1,
1135         resv2
1136     );
1137     check_struct!(io_uring_probe, last_op, ops_len, resv, resv2, ops);
1138     check_struct!(io_uring_probe_op, op, resv, flags, resv2);
1139     check_struct!(io_uring_files_update, offset, resv, fds);
1140     check_struct!(io_uring_rsrc_register, nr, resv, resv2, data, tags);
1141     check_struct!(io_uring_rsrc_update, offset, resv, data);
1142     check_struct!(io_uring_rsrc_update2, offset, resv, data, tags, nr, resv2);
1143     check_struct!(io_uring_getevents_arg, sigmask, sigmask_sz, pad, ts);
1144     check_struct!(iovec, iov_base, iov_len);
1145     check_struct!(open_how, flags, mode, resolve);
1146 }
1147