Skip to main content

io_uring/
opcode.rs

1//! Operation codes that can be used to construct [`squeue::Entry`](crate::squeue::Entry)s.
2
3#![allow(clippy::new_without_default)]
4
5use std::convert::TryInto;
6use std::mem;
7use std::os::unix::io::RawFd;
8
9use crate::squeue::Entry;
10use crate::squeue::Entry128;
11use crate::sys;
12use crate::types::{self, sealed};
13
14macro_rules! assign_fd {
15    ( $sqe:ident . fd = $opfd:expr ) => {
16        match $opfd {
17            sealed::Target::Fd(fd) => $sqe.fd = fd,
18            sealed::Target::Fixed(idx) => {
19                $sqe.fd = idx as _;
20                $sqe.flags |= crate::squeue::Flags::FIXED_FILE.bits();
21            }
22        }
23    };
24}
25
26macro_rules! opcode {
27    (@type impl sealed::UseFixed ) => {
28        sealed::Target
29    };
30    (@type impl sealed::UseFd ) => {
31        RawFd
32    };
33    (@type $name:ty ) => {
34        $name
35    };
36    (
37        $( #[$outer:meta] )*
38        pub struct $name:ident {
39            $( #[$new_meta:meta] )*
40
41            $( $field:ident : { $( $tnt:tt )+ } ),*
42
43            $(,)?
44
45            ;;
46
47            $(
48                $( #[$opt_meta:meta] )*
49                $opt_field:ident : $opt_tname:ty = $default:expr
50            ),*
51
52            $(,)?
53        }
54
55        pub const CODE = $opcode:expr;
56
57        $( #[$build_meta:meta] )*
58        pub fn build($self:ident) -> $entry:ty $build_block:block
59    ) => {
60        $( #[$outer] )*
61        pub struct $name {
62            $( $field : opcode!(@type $( $tnt )*), )*
63            $( $opt_field : $opt_tname, )*
64        }
65
66        impl $name {
67            $( #[$new_meta] )*
68            #[inline]
69            pub fn new($( $field : $( $tnt )* ),*) -> Self {
70                $name {
71                    $( $field: $field.into(), )*
72                    $( $opt_field: $default, )*
73                }
74            }
75
76            /// The opcode of the operation. This can be passed to
77            /// [`Probe::is_supported`](crate::Probe::is_supported) to check if this operation is
78            /// supported with the current kernel.
79            pub const CODE: u8 = $opcode as _;
80
81            $(
82                $( #[$opt_meta] )*
83                #[inline]
84                pub const fn $opt_field(mut self, $opt_field: $opt_tname) -> Self {
85                    self.$opt_field = $opt_field;
86                    self
87                }
88            )*
89
90            $( #[$build_meta] )*
91            #[inline]
92            pub fn build($self) -> $entry $build_block
93        }
94    }
95}
96
97/// inline zeroed to improve codegen
98#[inline(always)]
99fn sqe_zeroed() -> sys::io_uring_sqe {
100    unsafe { mem::zeroed() }
101}
102
103opcode! {
104    /// Do not perform any I/O.
105    ///
106    /// This is useful for testing the performance of the io_uring implementation itself.
107    #[derive(Debug)]
108    pub struct Nop { ;; }
109
110    pub const CODE = sys::IORING_OP_NOP;
111
112    pub fn build(self) -> Entry {
113        let Nop {} = self;
114
115        let mut sqe = sqe_zeroed();
116        sqe.opcode = Self::CODE;
117        sqe.fd = -1;
118        Entry(sqe)
119    }
120}
121
122opcode! {
123    /// Vectored read, equivalent to `preadv2(2)`.
124    #[derive(Debug)]
125    pub struct Readv {
126        fd: { impl sealed::UseFixed },
127        iovec: { *const libc::iovec },
128        len: { u32 },
129        ;;
130        ioprio: u16 = 0,
131        offset: u64 = 0,
132        /// specified for read operations, contains a bitwise OR of per-I/O flags,
133        /// as described in the `preadv2(2)` man page.
134        rw_flags: i32 = 0,
135        buf_group: u16 = 0
136    }
137
138    pub const CODE = sys::IORING_OP_READV;
139
140    pub fn build(self) -> Entry {
141        let Readv {
142            fd,
143            iovec, len, offset,
144            ioprio, rw_flags,
145            buf_group
146        } = self;
147
148        let mut sqe = sqe_zeroed();
149        sqe.opcode = Self::CODE;
150        assign_fd!(sqe.fd = fd);
151        sqe.ioprio = ioprio;
152        sqe.__bindgen_anon_2.addr = iovec as _;
153        sqe.len = len;
154        sqe.__bindgen_anon_1.off = offset;
155        sqe.__bindgen_anon_3.rw_flags = rw_flags as _;
156        sqe.__bindgen_anon_4.buf_group = buf_group;
157        Entry(sqe)
158    }
159}
160
161opcode! {
162    /// Vectored write, equivalent to `pwritev2(2)`.
163    #[derive(Debug)]
164    pub struct Writev {
165        fd: { impl sealed::UseFixed },
166        iovec: { *const libc::iovec },
167        len: { u32 },
168        ;;
169        ioprio: u16 = 0,
170        offset: u64 = 0,
171        /// specified for write operations, contains a bitwise OR of per-I/O flags,
172        /// as described in the `preadv2(2)` man page.
173        rw_flags: i32 = 0
174    }
175
176    pub const CODE = sys::IORING_OP_WRITEV;
177
178    pub fn build(self) -> Entry {
179        let Writev {
180            fd,
181            iovec, len, offset,
182            ioprio, rw_flags
183        } = self;
184
185        let mut sqe = sqe_zeroed();
186        sqe.opcode = Self::CODE;
187        assign_fd!(sqe.fd = fd);
188        sqe.ioprio = ioprio;
189        sqe.__bindgen_anon_2.addr = iovec as _;
190        sqe.len = len;
191        sqe.__bindgen_anon_1.off = offset;
192        sqe.__bindgen_anon_3.rw_flags = rw_flags as _;
193        Entry(sqe)
194    }
195}
196
197opcode! {
198    /// File sync, equivalent to `fsync(2)`.
199    ///
200    /// Note that, while I/O is initiated in the order in which it appears in the submission queue,
201    /// completions are unordered. For example, an application which places a write I/O followed by
202    /// an fsync in the submission queue cannot expect the fsync to apply to the write. The two
203    /// operations execute in parallel, so the fsync may complete before the write is issued to the
204    /// storage. The same is also true for previously issued writes that have not completed prior to
205    /// the fsync.
206    #[derive(Debug)]
207    pub struct Fsync {
208        fd: { impl sealed::UseFixed },
209        ;;
210        /// The `flags` bit mask may contain either 0, for a normal file integrity sync,
211        /// or [types::FsyncFlags::DATASYNC] to provide data sync only semantics.
212        /// See the descriptions of `O_SYNC` and `O_DSYNC` in the `open(2)` manual page for more information.
213        flags: types::FsyncFlags = types::FsyncFlags::empty()
214    }
215
216    pub const CODE = sys::IORING_OP_FSYNC;
217
218    pub fn build(self) -> Entry {
219        let Fsync { fd, flags } = self;
220
221        let mut sqe = sqe_zeroed();
222        sqe.opcode = Self::CODE;
223        assign_fd!(sqe.fd = fd);
224        sqe.__bindgen_anon_3.fsync_flags = flags.bits();
225        Entry(sqe)
226    }
227}
228
229opcode! {
230    /// Read from a file into a fixed buffer that has been previously registered with
231    /// [`Submitter::register_buffers`](crate::Submitter::register_buffers).
232    ///
233    /// The return values match those documented in the `preadv2(2)` man pages.
234    #[derive(Debug)]
235    pub struct ReadFixed {
236        fd: { impl sealed::UseFixed },
237        buf: { *mut u8 },
238        len: { u32 },
239        buf_index: { u16 },
240        ;;
241        ioprio: u16 = 0,
242        /// The offset of the file to read from.
243        offset: u64 = 0,
244        /// Specified for read operations, contains a bitwise OR of per-I/O flags, as described in
245        /// the `preadv2(2)` man page.
246        rw_flags: i32 = 0
247    }
248
249    pub const CODE = sys::IORING_OP_READ_FIXED;
250
251    pub fn build(self) -> Entry {
252        let ReadFixed {
253            fd,
254            buf, len, offset,
255            buf_index,
256            ioprio, rw_flags
257        } = self;
258
259        let mut sqe = sqe_zeroed();
260        sqe.opcode = Self::CODE;
261        assign_fd!(sqe.fd = fd);
262        sqe.ioprio = ioprio;
263        sqe.__bindgen_anon_2.addr = buf as _;
264        sqe.len = len;
265        sqe.__bindgen_anon_1.off = offset;
266        sqe.__bindgen_anon_3.rw_flags = rw_flags as _;
267        sqe.__bindgen_anon_4.buf_index = buf_index;
268        Entry(sqe)
269    }
270}
271
272opcode! {
273    /// Write to a file from a fixed buffer that have been previously registered with
274    /// [`Submitter::register_buffers`](crate::Submitter::register_buffers).
275    ///
276    /// The return values match those documented in the `pwritev2(2)` man pages.
277    #[derive(Debug)]
278    pub struct WriteFixed {
279        fd: { impl sealed::UseFixed },
280        buf: { *const u8 },
281        len: { u32 },
282        buf_index: { u16 },
283        ;;
284        ioprio: u16 = 0,
285        /// The offset of the file to write to.
286        offset: u64 = 0,
287        /// Specified for write operations, contains a bitwise OR of per-I/O flags, as described in
288        /// the `pwritev2(2)` man page.
289        rw_flags: i32 = 0
290    }
291
292    pub const CODE = sys::IORING_OP_WRITE_FIXED;
293
294    pub fn build(self) -> Entry {
295        let WriteFixed {
296            fd,
297            buf, len, offset,
298            buf_index,
299            ioprio, rw_flags
300        } = self;
301
302        let mut sqe = sqe_zeroed();
303        sqe.opcode = Self::CODE;
304        assign_fd!(sqe.fd = fd);
305        sqe.ioprio = ioprio;
306        sqe.__bindgen_anon_2.addr = buf as _;
307        sqe.len = len;
308        sqe.__bindgen_anon_1.off = offset;
309        sqe.__bindgen_anon_3.rw_flags = rw_flags as _;
310        sqe.__bindgen_anon_4.buf_index = buf_index;
311        Entry(sqe)
312    }
313}
314
315opcode! {
316    /// Poll the specified fd.
317    ///
318    /// Unlike poll or epoll without `EPOLLONESHOT`, this interface defaults to work in one shot mode.
319    /// That is, once the poll operation is completed, it will have to be resubmitted.
320    ///
321    /// If multi is set, the poll will work in multi shot mode instead. That means it will
322    /// repeatedly trigger when the requested event becomes true, and hence multiple CQEs can be
323    /// generated from this single submission. The CQE flags field will have IORING_CQE_F_MORE set
324    /// on completion if the application should expect further CQE entries from the original
325    /// request. If this flag isn't set on completion, then the poll request has been terminated
326    /// and no further events will be generated. This mode is available since 5.13.
327    #[derive(Debug)]
328    pub struct PollAdd {
329        /// The bits that may be set in `flags` are defined in `<poll.h>`,
330        /// and documented in `poll(2)`.
331        fd: { impl sealed::UseFixed },
332        flags: { u32 },
333        ;;
334        multi: bool = false
335    }
336
337    pub const CODE = sys::IORING_OP_POLL_ADD;
338
339    pub fn build(self) -> Entry {
340        let PollAdd { fd, flags, multi } = self;
341
342        let mut sqe = sqe_zeroed();
343        sqe.opcode = Self::CODE;
344        assign_fd!(sqe.fd = fd);
345        if multi {
346            sqe.len = sys::IORING_POLL_ADD_MULTI;
347        }
348
349        #[cfg(target_endian = "little")] {
350            sqe.__bindgen_anon_3.poll32_events = flags;
351        }
352
353        #[cfg(target_endian = "big")] {
354            let x = flags << 16;
355            let y = flags >> 16;
356            let flags = x | y;
357            sqe.__bindgen_anon_3.poll32_events = flags;
358        }
359
360        Entry(sqe)
361    }
362}
363
364opcode! {
365    /// Remove an existing [poll](PollAdd) request.
366    ///
367    /// If found, the `result` method of the `cqueue::Entry` will return 0.
368    /// If not found, `result` will return `-libc::ENOENT`.
369    #[derive(Debug)]
370    pub struct PollRemove {
371        user_data: { u64 }
372        ;;
373    }
374
375    pub const CODE = sys::IORING_OP_POLL_REMOVE;
376
377    pub fn build(self) -> Entry {
378        let PollRemove { user_data } = self;
379
380        let mut sqe = sqe_zeroed();
381        sqe.opcode = Self::CODE;
382        sqe.fd = -1;
383        sqe.__bindgen_anon_2.addr = user_data;
384        Entry(sqe)
385    }
386}
387
388opcode! {
389    /// Sync a file segment with disk, equivalent to `sync_file_range(2)`.
390    #[derive(Debug)]
391    pub struct SyncFileRange {
392        fd: { impl sealed::UseFixed },
393        len: { u32 },
394        ;;
395        /// the offset method holds the offset in bytes
396        offset: u64 = 0,
397        /// the flags method holds the flags for the command
398        flags: u32 = 0
399    }
400
401    pub const CODE = sys::IORING_OP_SYNC_FILE_RANGE;
402
403    pub fn build(self) -> Entry {
404        let SyncFileRange {
405            fd,
406            len, offset,
407            flags
408        } = self;
409
410        let mut sqe = sqe_zeroed();
411        sqe.opcode = Self::CODE;
412        assign_fd!(sqe.fd = fd);
413        sqe.len = len;
414        sqe.__bindgen_anon_1.off = offset;
415        sqe.__bindgen_anon_3.sync_range_flags = flags;
416        Entry(sqe)
417    }
418}
419
420opcode! {
421    /// Send a message on a socket, equivalent to `send(2)`.
422    ///
423    /// fd must be set to the socket file descriptor, addr must contains a pointer to the msghdr
424    /// structure, and flags holds the flags associated with the system call.
425    #[derive(Debug)]
426    pub struct SendMsg {
427        fd: { impl sealed::UseFixed },
428        msg: { *const libc::msghdr },
429        ;;
430        ioprio: u16 = 0,
431        flags: u32 = 0
432    }
433
434    pub const CODE = sys::IORING_OP_SENDMSG;
435
436    pub fn build(self) -> Entry {
437        let SendMsg { fd, msg, ioprio, flags } = self;
438
439        let mut sqe = sqe_zeroed();
440        sqe.opcode = Self::CODE;
441        assign_fd!(sqe.fd = fd);
442        sqe.ioprio = ioprio;
443        sqe.__bindgen_anon_2.addr = msg as _;
444        sqe.len = 1;
445        sqe.__bindgen_anon_3.msg_flags = flags;
446        Entry(sqe)
447    }
448}
449
450opcode! {
451    /// Receive a message on a socket, equivalent to `recvmsg(2)`.
452    ///
453    /// See also the description of [`SendMsg`].
454    #[derive(Debug)]
455    pub struct RecvMsg {
456        fd: { impl sealed::UseFixed },
457        msg: { *mut libc::msghdr },
458        ;;
459        ioprio: u16 = 0,
460        flags: u32 = 0,
461        buf_group: u16 = 0
462    }
463
464    pub const CODE = sys::IORING_OP_RECVMSG;
465
466    pub fn build(self) -> Entry {
467        let RecvMsg { fd, msg, ioprio, flags, buf_group } = self;
468
469        let mut sqe = sqe_zeroed();
470        sqe.opcode = Self::CODE;
471        assign_fd!(sqe.fd = fd);
472        sqe.ioprio = ioprio;
473        sqe.__bindgen_anon_2.addr = msg as _;
474        sqe.len = 1;
475        sqe.__bindgen_anon_3.msg_flags = flags;
476        sqe.__bindgen_anon_4.buf_group = buf_group;
477        Entry(sqe)
478    }
479}
480
481opcode! {
482    /// Receive multiple messages on a socket, equivalent to `recvmsg(2)`.
483    ///
484    /// Parameters:
485    ///     msg:       For this multishot variant of ResvMsg, only the msg_namelen and msg_controllen
486    ///                fields are relevant.
487    ///     buf_group: The id of the provided buffer pool to use for each received message.
488    ///
489    /// See also the description of [`SendMsg`] and [`types::RecvMsgOut`].
490    ///
491    /// The multishot version allows the application to issue a single receive request, which
492    /// repeatedly posts a CQE when data is available. It requires the MSG_WAITALL flag is not set.
493    /// Each CQE will take a buffer out of a provided buffer pool for receiving. The application
494    /// should check the flags of each CQE, regardless of its result. If a posted CQE does not have
495    /// the IORING_CQE_F_MORE flag set then the multishot receive will be done and the application
496    /// should issue a new request.
497    ///
498    /// Unlike [`RecvMsg`], this multishot recvmsg will prepend a struct which describes the layout
499    /// of the rest of the buffer in combination with the initial msghdr structure submitted with
500    /// the request. Use [`types::RecvMsgOut`] to parse the data received and access its
501    /// components.
502    ///
503    /// The recvmsg multishot variant is available since kernel 6.0.
504    #[derive(Debug)]
505    pub struct RecvMsgMulti {
506        fd: { impl sealed::UseFixed },
507        msg: { *const libc::msghdr },
508        buf_group: { u16 },
509        ;;
510        ioprio: u16 = 0,
511        flags: u32 = 0
512    }
513
514    pub const CODE = sys::IORING_OP_RECVMSG;
515
516    pub fn build(self) -> Entry {
517        let RecvMsgMulti { fd, msg, buf_group, ioprio, flags } = self;
518
519        let mut sqe = sqe_zeroed();
520        sqe.opcode = Self::CODE;
521        assign_fd!(sqe.fd = fd);
522        sqe.__bindgen_anon_2.addr = msg as _;
523        sqe.len = 1;
524        sqe.__bindgen_anon_3.msg_flags = flags;
525        sqe.__bindgen_anon_4.buf_group = buf_group;
526        sqe.flags |= crate::squeue::Flags::BUFFER_SELECT.bits();
527        sqe.ioprio = ioprio | (sys::IORING_RECV_MULTISHOT as u16);
528        Entry(sqe)
529    }
530}
531
532opcode! {
533    /// Register a timeout operation.
534    ///
535    /// A timeout will trigger a wakeup event on the completion ring for anyone waiting for events.
536    /// A timeout condition is met when either the specified timeout expires, or the specified number of events have completed.
537    /// Either condition will trigger the event.
538    /// The request will complete with `-ETIME` if the timeout got completed through expiration of the timer,
539    /// or 0 if the timeout got completed through requests completing on their own.
540    /// If the timeout was cancelled before it expired, the request will complete with `-ECANCELED`.
541    #[derive(Debug)]
542    pub struct Timeout {
543        timespec: { *const types::Timespec },
544        ;;
545        /// `count` may contain a completion event count.
546        /// If [`TimeoutFlags::MULTISHOT`](types::TimeoutFlags::MULTISHOT) is set in `flags`, this is the number of repeats.
547        /// A value of 0 means the timeout is indefinite and can only be stopped by a removal request.
548        count: u32 = 0,
549
550        flags: types::TimeoutFlags = types::TimeoutFlags::empty()
551    }
552
553    pub const CODE = sys::IORING_OP_TIMEOUT;
554
555    pub fn build(self) -> Entry {
556        let Timeout { timespec, count, flags } = self;
557
558        let mut sqe = sqe_zeroed();
559        sqe.opcode = Self::CODE;
560        sqe.fd = -1;
561        sqe.__bindgen_anon_2.addr = timespec as _;
562        sqe.len = 1;
563        sqe.__bindgen_anon_1.off = count as _;
564        sqe.__bindgen_anon_3.timeout_flags = flags.bits();
565        Entry(sqe)
566    }
567}
568
569// === 5.5 ===
570
571opcode! {
572    /// Attempt to remove an existing [timeout operation](Timeout).
573    pub struct TimeoutRemove {
574        user_data: { u64 },
575        ;;
576    }
577
578    pub const CODE = sys::IORING_OP_TIMEOUT_REMOVE;
579
580    pub fn build(self) -> Entry {
581        let TimeoutRemove { user_data } = self;
582
583        let mut sqe = sqe_zeroed();
584        sqe.opcode = Self::CODE;
585        sqe.fd = -1;
586        sqe.__bindgen_anon_2.addr = user_data;
587        Entry(sqe)
588    }
589}
590
591opcode! {
592    /// Attempt to update an existing [timeout operation](Timeout) with a new timespec.
593    /// The optional `count` value of the original timeout value cannot be updated.
594    pub struct TimeoutUpdate {
595        user_data: { u64 },
596        timespec: { *const types::Timespec },
597        ;;
598        flags: types::TimeoutFlags = types::TimeoutFlags::empty()
599    }
600
601    pub const CODE = sys::IORING_OP_TIMEOUT_REMOVE;
602
603    pub fn build(self) -> Entry {
604        let TimeoutUpdate { user_data, timespec, flags } = self;
605
606        let mut sqe = sqe_zeroed();
607        sqe.opcode = Self::CODE;
608        sqe.fd = -1;
609        sqe.__bindgen_anon_1.off = timespec as _;
610        sqe.__bindgen_anon_2.addr = user_data;
611        sqe.__bindgen_anon_3.timeout_flags = flags.bits() | sys::IORING_TIMEOUT_UPDATE;
612        Entry(sqe)
613    }
614}
615
616opcode! {
617    /// Accept a new connection on a socket, equivalent to `accept4(2)`.
618    pub struct Accept {
619        fd: { impl sealed::UseFixed },
620        addr: { *mut libc::sockaddr },
621        addrlen: { *mut libc::socklen_t },
622        ;;
623        file_index: Option<types::DestinationSlot> = None,
624        flags: i32 = 0
625    }
626
627    pub const CODE = sys::IORING_OP_ACCEPT;
628
629    pub fn build(self) -> Entry {
630        let Accept { fd, addr, addrlen, file_index, flags } = self;
631
632        let mut sqe = sqe_zeroed();
633        sqe.opcode = Self::CODE;
634        assign_fd!(sqe.fd = fd);
635        sqe.__bindgen_anon_2.addr = addr as _;
636        sqe.__bindgen_anon_1.addr2 = addrlen as _;
637        sqe.__bindgen_anon_3.accept_flags = flags as _;
638        if let Some(dest) = file_index {
639            sqe.__bindgen_anon_5.file_index = dest.kernel_index_arg();
640        }
641        Entry(sqe)
642    }
643}
644
645opcode! {
646    /// Set a socket option.
647    pub struct SetSockOpt {
648        fd: { impl sealed::UseFixed },
649        level: { u32 },
650        optname: { u32 },
651        optval: { *const libc::c_void },
652        optlen: { u32 },
653        ;;
654        flags: u32 = 0
655    }
656
657    pub const CODE = sys::IORING_OP_URING_CMD;
658
659    pub fn build(self) -> Entry {
660        let SetSockOpt { fd, level, optname, optval, optlen, flags } = self;
661        let mut sqe = sqe_zeroed();
662        sqe.opcode = Self::CODE;
663        assign_fd!(sqe.fd = fd);
664        sqe.__bindgen_anon_1.__bindgen_anon_1.cmd_op = sys::SOCKET_URING_OP_SETSOCKOPT;
665
666        sqe.__bindgen_anon_2.__bindgen_anon_1.level = level;
667        sqe.__bindgen_anon_2.__bindgen_anon_1.optname = optname;
668        sqe.__bindgen_anon_3.uring_cmd_flags = flags;
669        sqe.__bindgen_anon_5.optlen = optlen;
670        unsafe { *sqe.__bindgen_anon_6.optval.as_mut() = optval as u64 };
671        Entry(sqe)
672    }
673}
674
675opcode! {
676    /// Attempt to cancel an already issued request.
677    pub struct AsyncCancel {
678        user_data: { u64 }
679        ;;
680
681        // TODO flags
682    }
683
684    pub const CODE = sys::IORING_OP_ASYNC_CANCEL;
685
686    pub fn build(self) -> Entry {
687        let AsyncCancel { user_data } = self;
688
689        let mut sqe = sqe_zeroed();
690        sqe.opcode = Self::CODE;
691        sqe.fd = -1;
692        sqe.__bindgen_anon_2.addr = user_data;
693        Entry(sqe)
694    }
695}
696
697opcode! {
698    /// This request must be linked with another request through
699    /// [`Flags::IO_LINK`](crate::squeue::Flags::IO_LINK) which is described below.
700    /// Unlike [`Timeout`], [`LinkTimeout`] acts on the linked request, not the completion queue.
701    pub struct LinkTimeout {
702        timespec: { *const types::Timespec },
703        ;;
704        flags: types::TimeoutFlags = types::TimeoutFlags::empty()
705    }
706
707    pub const CODE = sys::IORING_OP_LINK_TIMEOUT;
708
709    pub fn build(self) -> Entry {
710        let LinkTimeout { timespec, flags } = self;
711
712        let mut sqe = sqe_zeroed();
713        sqe.opcode = Self::CODE;
714        sqe.fd = -1;
715        sqe.__bindgen_anon_2.addr = timespec as _;
716        sqe.len = 1;
717        sqe.__bindgen_anon_3.timeout_flags = flags.bits();
718        Entry(sqe)
719    }
720}
721
722opcode! {
723    /// Connect a socket, equivalent to `connect(2)`.
724    pub struct Connect {
725        fd: { impl sealed::UseFixed },
726        addr: { *const libc::sockaddr },
727        addrlen: { libc::socklen_t }
728        ;;
729    }
730
731    pub const CODE = sys::IORING_OP_CONNECT;
732
733    pub fn build(self) -> Entry {
734        let Connect { fd, addr, addrlen } = self;
735
736        let mut sqe = sqe_zeroed();
737        sqe.opcode = Self::CODE;
738        assign_fd!(sqe.fd = fd);
739        sqe.__bindgen_anon_2.addr = addr as _;
740        sqe.__bindgen_anon_1.off = addrlen as _;
741        Entry(sqe)
742    }
743}
744
745// === 5.6 ===
746
747opcode! {
748    /// Preallocate or deallocate space to a file, equivalent to `fallocate(2)`.
749    pub struct Fallocate {
750        fd: { impl sealed::UseFixed },
751        len: { u64 },
752        ;;
753        offset: u64 = 0,
754        mode: i32 = 0
755    }
756
757    pub const CODE = sys::IORING_OP_FALLOCATE;
758
759    pub fn build(self) -> Entry {
760        let Fallocate { fd, len, offset, mode } = self;
761
762        let mut sqe = sqe_zeroed();
763        sqe.opcode = Self::CODE;
764        assign_fd!(sqe.fd = fd);
765        sqe.__bindgen_anon_2.addr = len;
766        sqe.len = mode as _;
767        sqe.__bindgen_anon_1.off = offset;
768        Entry(sqe)
769    }
770}
771
772opcode! {
773    /// Open a file, equivalent to `openat(2)`.
774    pub struct OpenAt {
775        dirfd: { impl sealed::UseFd },
776        pathname: { *const libc::c_char },
777        ;;
778        file_index: Option<types::DestinationSlot> = None,
779        flags: i32 = 0,
780        mode: libc::mode_t = 0
781    }
782
783    pub const CODE = sys::IORING_OP_OPENAT;
784
785    pub fn build(self) -> Entry {
786        let OpenAt { dirfd, pathname, file_index, flags, mode } = self;
787
788        let mut sqe = sqe_zeroed();
789        sqe.opcode = Self::CODE;
790        sqe.fd = dirfd;
791        sqe.__bindgen_anon_2.addr = pathname as _;
792        sqe.len = mode;
793        sqe.__bindgen_anon_3.open_flags = flags as _;
794        if let Some(dest) = file_index {
795            sqe.__bindgen_anon_5.file_index = dest.kernel_index_arg();
796        }
797        Entry(sqe)
798    }
799}
800
801opcode! {
802    /// Close a file descriptor, equivalent to `close(2)`.
803    ///
804    /// Use a types::Fixed(fd) argument to close an io_uring direct descriptor.
805    pub struct Close {
806        fd: { impl sealed::UseFixed },
807        ;;
808    }
809
810    pub const CODE = sys::IORING_OP_CLOSE;
811
812    pub fn build(self) -> Entry {
813        let Close { fd } = self;
814
815        let mut sqe = sqe_zeroed();
816        sqe.opcode = Self::CODE;
817        match fd {
818            sealed::Target::Fd(fd) => sqe.fd = fd,
819            sealed::Target::Fixed(idx) => {
820                sqe.fd = 0;
821                sqe.__bindgen_anon_5.file_index = idx + 1;
822            }
823        }
824        Entry(sqe)
825    }
826}
827
828opcode! {
829    /// This command is an alternative to using
830    /// [`Submitter::register_files_update`](crate::Submitter::register_files_update) which then
831    /// works in an async fashion, like the rest of the io_uring commands.
832    pub struct FilesUpdate {
833        fds: { *const RawFd },
834        len: { u32 },
835        ;;
836        offset: i32 = 0
837    }
838
839    pub const CODE = sys::IORING_OP_FILES_UPDATE;
840
841    pub fn build(self) -> Entry {
842        let FilesUpdate { fds, len, offset } = self;
843
844        let mut sqe = sqe_zeroed();
845        sqe.opcode = Self::CODE;
846        sqe.fd = -1;
847        sqe.__bindgen_anon_2.addr = fds as _;
848        sqe.len = len;
849        sqe.__bindgen_anon_1.off = offset as _;
850        Entry(sqe)
851    }
852}
853
854opcode! {
855    /// Get file status, equivalent to `statx(2)`.
856    pub struct Statx {
857        dirfd: { impl sealed::UseFd },
858        pathname: { *const libc::c_char },
859        statxbuf: { *mut types::statx },
860        ;;
861        flags: i32 = 0,
862        mask: u32 = 0
863    }
864
865    pub const CODE = sys::IORING_OP_STATX;
866
867    pub fn build(self) -> Entry {
868        let Statx {
869            dirfd, pathname, statxbuf,
870            flags, mask
871        } = self;
872
873        let mut sqe = sqe_zeroed();
874        sqe.opcode = Self::CODE;
875        sqe.fd = dirfd;
876        sqe.__bindgen_anon_2.addr = pathname as _;
877        sqe.len = mask;
878        sqe.__bindgen_anon_1.off = statxbuf as _;
879        sqe.__bindgen_anon_3.statx_flags = flags as _;
880        Entry(sqe)
881    }
882}
883
884opcode! {
885    /// Issue the equivalent of a `pread(2)` or `pwrite(2)` system call
886    ///
887    /// * `fd` is the file descriptor to be operated on,
888    /// * `addr` contains the buffer in question,
889    /// * `len` contains the length of the IO operation,
890    ///
891    /// These are non-vectored versions of the `IORING_OP_READV` and `IORING_OP_WRITEV` opcodes.
892    /// See also `read(2)` and `write(2)` for the general description of the related system call.
893    ///
894    /// Available since 5.6.
895    pub struct Read {
896        fd: { impl sealed::UseFixed },
897        buf: { *mut u8 },
898        len: { u32 },
899        ;;
900        /// `offset` contains the read or write offset.
901        ///
902        /// If `fd` does not refer to a seekable file, `offset` must be set to zero.
903        /// If `offset` is set to `-1`, the offset will use (and advance) the file position,
904        /// like the `read(2)` and `write(2)` system calls.
905        offset: u64 = 0,
906        ioprio: u16 = 0,
907        rw_flags: i32 = 0,
908        buf_group: u16 = 0
909    }
910
911    pub const CODE = sys::IORING_OP_READ;
912
913    pub fn build(self) -> Entry {
914        let Read {
915            fd,
916            buf, len, offset,
917            ioprio, rw_flags,
918            buf_group
919        } = self;
920
921        let mut sqe = sqe_zeroed();
922        sqe.opcode = Self::CODE;
923        assign_fd!(sqe.fd = fd);
924        sqe.ioprio = ioprio;
925        sqe.__bindgen_anon_2.addr = buf as _;
926        sqe.len = len;
927        sqe.__bindgen_anon_1.off = offset;
928        sqe.__bindgen_anon_3.rw_flags = rw_flags as _;
929        sqe.__bindgen_anon_4.buf_group = buf_group;
930        Entry(sqe)
931    }
932}
933
934opcode! {
935    /// Issue the equivalent of a `pread(2)` or `pwrite(2)` system call
936    ///
937    /// * `fd` is the file descriptor to be operated on,
938    /// * `addr` contains the buffer in question,
939    /// * `len` contains the length of the IO operation,
940    ///
941    /// These are non-vectored versions of the `IORING_OP_READV` and `IORING_OP_WRITEV` opcodes.
942    /// See also `read(2)` and `write(2)` for the general description of the related system call.
943    ///
944    /// Available since 5.6.
945    pub struct Write {
946        fd: { impl sealed::UseFixed },
947        buf: { *const u8 },
948        len: { u32 },
949        ;;
950        /// `offset` contains the read or write offset.
951        ///
952        /// If `fd` does not refer to a seekable file, `offset` must be set to zero.
953        /// If `offsett` is set to `-1`, the offset will use (and advance) the file position,
954        /// like the `read(2)` and `write(2)` system calls.
955        offset: u64 = 0,
956        ioprio: u16 = 0,
957        rw_flags: i32 = 0
958    }
959
960    pub const CODE = sys::IORING_OP_WRITE;
961
962    pub fn build(self) -> Entry {
963        let Write {
964            fd,
965            buf, len, offset,
966            ioprio, rw_flags
967        } = self;
968
969        let mut sqe = sqe_zeroed();
970        sqe.opcode = Self::CODE;
971        assign_fd!(sqe.fd = fd);
972        sqe.ioprio = ioprio;
973        sqe.__bindgen_anon_2.addr = buf as _;
974        sqe.len = len;
975        sqe.__bindgen_anon_1.off = offset;
976        sqe.__bindgen_anon_3.rw_flags = rw_flags as _;
977        Entry(sqe)
978    }
979}
980
981opcode! {
982    /// Predeclare an access pattern for file data, equivalent to `posix_fadvise(2)`.
983    pub struct Fadvise {
984        fd: { impl sealed::UseFixed },
985        len: { libc::off_t },
986        advice: { i32 },
987        ;;
988        offset: u64 = 0,
989    }
990
991    pub const CODE = sys::IORING_OP_FADVISE;
992
993    pub fn build(self) -> Entry {
994        let Fadvise { fd, len, advice, offset } = self;
995
996        let mut sqe = sqe_zeroed();
997        sqe.opcode = Self::CODE;
998        assign_fd!(sqe.fd = fd);
999        sqe.len = len as _;
1000        sqe.__bindgen_anon_1.off = offset;
1001        sqe.__bindgen_anon_3.fadvise_advice = advice as _;
1002        Entry(sqe)
1003    }
1004}
1005
1006opcode! {
1007    /// Give advice about use of memory, equivalent to `madvise(2)`.
1008    pub struct Madvise {
1009        addr: { *const libc::c_void },
1010        len: { libc::off_t },
1011        advice: { i32 },
1012        ;;
1013    }
1014
1015    pub const CODE = sys::IORING_OP_MADVISE;
1016
1017    pub fn build(self) -> Entry {
1018        let Madvise { addr, len, advice } = self;
1019
1020        let mut sqe = sqe_zeroed();
1021        sqe.opcode = Self::CODE;
1022        sqe.fd = -1;
1023        sqe.__bindgen_anon_2.addr = addr as _;
1024        sqe.len = len as _;
1025        sqe.__bindgen_anon_3.fadvise_advice = advice as _;
1026        Entry(sqe)
1027    }
1028}
1029
1030opcode! {
1031    /// Send a message on a socket, equivalent to `send(2)`.
1032    pub struct Send {
1033        fd: { impl sealed::UseFixed },
1034        buf: { *const u8 },
1035        len: { u32 },
1036        ;;
1037        ioprio: u16 = 0,
1038        flags: i32 = 0,
1039
1040        /// Set the destination address, for sending from an unconnected socket.
1041        ///
1042        /// When set, `dest_addr_len` must be set as well.
1043        /// See also `man 3 io_uring_prep_send_set_addr`.
1044        dest_addr: *const libc::sockaddr = core::ptr::null(),
1045        dest_addr_len: libc::socklen_t = 0,
1046    }
1047
1048    pub const CODE = sys::IORING_OP_SEND;
1049
1050    pub fn build(self) -> Entry {
1051        let Send { fd, buf, len, ioprio, flags, dest_addr, dest_addr_len } = self;
1052
1053        let mut sqe = sqe_zeroed();
1054        sqe.opcode = Self::CODE;
1055        assign_fd!(sqe.fd = fd);
1056        sqe.__bindgen_anon_2.addr = buf as _;
1057        sqe.__bindgen_anon_1.addr2 = dest_addr as _;
1058        sqe.__bindgen_anon_5.__bindgen_anon_1.addr_len = dest_addr_len as _;
1059        sqe.len = len;
1060        sqe.ioprio = ioprio;
1061        sqe.__bindgen_anon_3.msg_flags = flags as _;
1062        Entry(sqe)
1063    }
1064}
1065
1066opcode! {
1067    /// Receive a message from a socket, equivalent to `recv(2)`.
1068    pub struct Recv {
1069        fd: { impl sealed::UseFixed },
1070        buf: { *mut u8 },
1071        len: { u32 },
1072        ;;
1073        ioprio: u16 = 0,
1074        flags: i32 = 0,
1075        buf_group: u16 = 0
1076    }
1077
1078    pub const CODE = sys::IORING_OP_RECV;
1079
1080    pub fn build(self) -> Entry {
1081        let Recv { fd, buf, len, ioprio, flags, buf_group } = self;
1082
1083        let mut sqe = sqe_zeroed();
1084        sqe.opcode = Self::CODE;
1085        assign_fd!(sqe.fd = fd);
1086        sqe.__bindgen_anon_2.addr = buf as _;
1087        sqe.len = len;
1088        sqe.ioprio = ioprio;
1089        sqe.__bindgen_anon_3.msg_flags = flags as _;
1090        sqe.__bindgen_anon_4.buf_group = buf_group;
1091        Entry(sqe)
1092    }
1093}
1094
1095opcode! {
1096    /// Receive multiple messages from a socket, equivalent to `recv(2)`.
1097    ///
1098    /// Parameter:
1099    ///     buf_group: The id of the provided buffer pool to use for each received message.
1100    ///
1101    /// MSG_WAITALL should not be set in flags.
1102    ///
1103    /// The multishot version allows the application to issue a single receive request, which
1104    /// repeatedly posts a CQE when data is available. Each CQE will take a buffer out of a
1105    /// provided buffer pool for receiving. The application should check the flags of each CQE,
1106    /// regardless of its result. If a posted CQE does not have the IORING_CQE_F_MORE flag set then
1107    /// the multishot receive will be done and the application should issue a new request.
1108    ///
1109    /// Multishot variants are available since kernel 6.0.
1110
1111    pub struct RecvMulti {
1112        fd: { impl sealed::UseFixed },
1113        buf_group: { u16 },
1114        ;;
1115        flags: i32 = 0,
1116        len: u32 = 0,
1117    }
1118
1119    pub const CODE = sys::IORING_OP_RECV;
1120
1121    pub fn build(self) -> Entry {
1122        let RecvMulti { fd, buf_group, flags, len } = self;
1123
1124        let mut sqe = sqe_zeroed();
1125        sqe.opcode = Self::CODE;
1126        assign_fd!(sqe.fd = fd);
1127        sqe.len = len;
1128        sqe.__bindgen_anon_3.msg_flags = flags as _;
1129        sqe.__bindgen_anon_4.buf_group = buf_group;
1130        sqe.flags |= crate::squeue::Flags::BUFFER_SELECT.bits();
1131        sqe.ioprio = sys::IORING_RECV_MULTISHOT as _;
1132        Entry(sqe)
1133    }
1134}
1135
1136opcode! {
1137    /// Open a file, equivalent to `openat2(2)`.
1138    pub struct OpenAt2 {
1139        dirfd: { impl sealed::UseFd },
1140        pathname: { *const libc::c_char },
1141        how: { *const types::OpenHow }
1142        ;;
1143        file_index: Option<types::DestinationSlot> = None,
1144    }
1145
1146    pub const CODE = sys::IORING_OP_OPENAT2;
1147
1148    pub fn build(self) -> Entry {
1149        let OpenAt2 { dirfd, pathname, how, file_index } = self;
1150
1151        let mut sqe = sqe_zeroed();
1152        sqe.opcode = Self::CODE;
1153        sqe.fd = dirfd;
1154        sqe.__bindgen_anon_2.addr = pathname as _;
1155        sqe.len = mem::size_of::<sys::open_how>() as _;
1156        sqe.__bindgen_anon_1.off = how as _;
1157        if let Some(dest) = file_index {
1158            sqe.__bindgen_anon_5.file_index = dest.kernel_index_arg();
1159        }
1160        Entry(sqe)
1161    }
1162}
1163
1164opcode! {
1165    /// Modify an epoll file descriptor, equivalent to `epoll_ctl(2)`.
1166    pub struct EpollCtl {
1167        epfd: { impl sealed::UseFixed },
1168        fd: { impl sealed::UseFd },
1169        op: { i32 },
1170        ev: { *const types::epoll_event },
1171        ;;
1172    }
1173
1174    pub const CODE = sys::IORING_OP_EPOLL_CTL;
1175
1176    pub fn build(self) -> Entry {
1177        let EpollCtl { epfd, fd, op, ev } = self;
1178
1179        let mut sqe = sqe_zeroed();
1180        sqe.opcode = Self::CODE;
1181        assign_fd!(sqe.fd = epfd);
1182        sqe.__bindgen_anon_2.addr = ev as _;
1183        sqe.len = op as _;
1184        sqe.__bindgen_anon_1.off = fd as _;
1185        Entry(sqe)
1186    }
1187}
1188
1189// === 5.7 ===
1190
1191opcode! {
1192    /// Splice data to/from a pipe, equivalent to `splice(2)`.
1193    ///
1194    /// if `fd_in` refers to a pipe, `off_in` must be `-1`;
1195    /// The description of `off_in` also applied to `off_out`.
1196    pub struct Splice {
1197        fd_in: { impl sealed::UseFixed },
1198        off_in: { i64 },
1199        fd_out: { impl sealed::UseFixed },
1200        off_out: { i64 },
1201        len: { u32 },
1202        ;;
1203        /// see man `splice(2)` for description of flags.
1204        flags: u32 = 0
1205    }
1206
1207    pub const CODE = sys::IORING_OP_SPLICE;
1208
1209    pub fn build(self) -> Entry {
1210        let Splice { fd_in, off_in, fd_out, off_out, len, mut flags } = self;
1211
1212        let mut sqe = sqe_zeroed();
1213        sqe.opcode = Self::CODE;
1214        assign_fd!(sqe.fd = fd_out);
1215        sqe.len = len;
1216        sqe.__bindgen_anon_1.off = off_out as _;
1217
1218        sqe.__bindgen_anon_5.splice_fd_in = match fd_in {
1219            sealed::Target::Fd(fd) => fd,
1220            sealed::Target::Fixed(idx) => {
1221                flags |= sys::SPLICE_F_FD_IN_FIXED;
1222                idx as _
1223            }
1224        };
1225
1226        sqe.__bindgen_anon_2.splice_off_in = off_in as _;
1227        sqe.__bindgen_anon_3.splice_flags = flags;
1228        Entry(sqe)
1229    }
1230}
1231
1232opcode! {
1233    /// Register `nbufs` buffers that each have the length `len` with ids starting from `bid` in the
1234    /// group `bgid` that can be used for any request. See
1235    /// [`BUFFER_SELECT`](crate::squeue::Flags::BUFFER_SELECT) for more info.
1236    pub struct ProvideBuffers {
1237        addr: { *mut u8 },
1238        len: { i32 },
1239        nbufs: { u16 },
1240        bgid: { u16 },
1241        bid: { u16 }
1242        ;;
1243    }
1244
1245    pub const CODE = sys::IORING_OP_PROVIDE_BUFFERS;
1246
1247    pub fn build(self) -> Entry {
1248        let ProvideBuffers { addr, len, nbufs, bgid, bid } = self;
1249
1250        let mut sqe = sqe_zeroed();
1251        sqe.opcode = Self::CODE;
1252        sqe.fd = nbufs as _;
1253        sqe.__bindgen_anon_2.addr = addr as _;
1254        sqe.len = len as _;
1255        sqe.__bindgen_anon_1.off = bid as _;
1256        sqe.__bindgen_anon_4.buf_group = bgid;
1257        Entry(sqe)
1258    }
1259}
1260
1261opcode! {
1262    /// Remove some number of buffers from a buffer group. See
1263    /// [`BUFFER_SELECT`](crate::squeue::Flags::BUFFER_SELECT) for more info.
1264    pub struct RemoveBuffers {
1265        nbufs: { u16 },
1266        bgid: { u16 }
1267        ;;
1268    }
1269
1270    pub const CODE = sys::IORING_OP_REMOVE_BUFFERS;
1271
1272    pub fn build(self) -> Entry {
1273        let RemoveBuffers { nbufs, bgid } = self;
1274
1275        let mut sqe = sqe_zeroed();
1276        sqe.opcode = Self::CODE;
1277        sqe.fd = nbufs as _;
1278        sqe.__bindgen_anon_4.buf_group = bgid;
1279        Entry(sqe)
1280    }
1281}
1282
1283// === 5.8 ===
1284
1285opcode! {
1286    /// Duplicate pipe content, equivalent to `tee(2)`.
1287    pub struct Tee {
1288        fd_in: { impl sealed::UseFixed },
1289        fd_out: { impl sealed::UseFixed },
1290        len: { u32 }
1291        ;;
1292        flags: u32 = 0
1293    }
1294
1295    pub const CODE = sys::IORING_OP_TEE;
1296
1297    pub fn build(self) -> Entry {
1298        let Tee { fd_in, fd_out, len, mut flags } = self;
1299
1300        let mut sqe = sqe_zeroed();
1301        sqe.opcode = Self::CODE;
1302
1303        assign_fd!(sqe.fd = fd_out);
1304        sqe.len = len;
1305
1306        sqe.__bindgen_anon_5.splice_fd_in = match fd_in {
1307            sealed::Target::Fd(fd) => fd,
1308            sealed::Target::Fixed(idx) => {
1309                flags |= sys::SPLICE_F_FD_IN_FIXED;
1310                idx as _
1311            }
1312        };
1313
1314        sqe.__bindgen_anon_3.splice_flags = flags;
1315
1316        Entry(sqe)
1317    }
1318}
1319
1320// === 5.11 ===
1321
1322opcode! {
1323    /// Shut down all or part of a full duplex connection on a socket, equivalent to `shutdown(2)`.
1324    /// Available since kernel 5.11.
1325    pub struct Shutdown {
1326        fd: { impl sealed::UseFixed },
1327        how: { i32 },
1328        ;;
1329    }
1330
1331    pub const CODE = sys::IORING_OP_SHUTDOWN;
1332
1333    pub fn build(self) -> Entry {
1334        let Shutdown { fd, how } = self;
1335
1336        let mut sqe = sqe_zeroed();
1337        sqe.opcode = Self::CODE;
1338        assign_fd!(sqe.fd = fd);
1339        sqe.len = how as _;
1340        Entry(sqe)
1341    }
1342}
1343
1344opcode! {
1345    // Change the name or location of a file, equivalent to `renameat2(2)`.
1346    // Available since kernel 5.11.
1347    pub struct RenameAt {
1348        olddirfd: { impl sealed::UseFd },
1349        oldpath: { *const libc::c_char },
1350        newdirfd: { impl sealed::UseFd },
1351        newpath: { *const libc::c_char },
1352        ;;
1353        flags: u32 = 0
1354    }
1355
1356    pub const CODE = sys::IORING_OP_RENAMEAT;
1357
1358    pub fn build(self) -> Entry {
1359        let RenameAt {
1360            olddirfd, oldpath,
1361            newdirfd, newpath,
1362            flags
1363        } = self;
1364
1365        let mut sqe = sqe_zeroed();
1366        sqe.opcode = Self::CODE;
1367        sqe.fd = olddirfd;
1368        sqe.__bindgen_anon_2.addr = oldpath as _;
1369        sqe.len = newdirfd as _;
1370        sqe.__bindgen_anon_1.off = newpath as _;
1371        sqe.__bindgen_anon_3.rename_flags = flags;
1372        Entry(sqe)
1373    }
1374}
1375
1376opcode! {
1377    // Delete a name and possible the file it refers to, equivalent to `unlinkat(2)`.
1378    // Available since kernel 5.11.
1379    pub struct UnlinkAt {
1380        dirfd: { impl sealed::UseFd },
1381        pathname: { *const libc::c_char },
1382        ;;
1383        flags: i32 = 0
1384    }
1385
1386    pub const CODE = sys::IORING_OP_UNLINKAT;
1387
1388    pub fn build(self) -> Entry {
1389        let UnlinkAt { dirfd, pathname, flags } = self;
1390
1391        let mut sqe = sqe_zeroed();
1392        sqe.opcode = Self::CODE;
1393        sqe.fd = dirfd;
1394        sqe.__bindgen_anon_2.addr = pathname as _;
1395        sqe.__bindgen_anon_3.unlink_flags = flags as _;
1396        Entry(sqe)
1397    }
1398}
1399
1400// === 5.15 ===
1401
1402opcode! {
1403    /// Make a directory, equivalent to `mkdirat(2)`.
1404    pub struct MkDirAt {
1405        dirfd: { impl sealed::UseFd },
1406        pathname: { *const libc::c_char },
1407        ;;
1408        mode: libc::mode_t = 0
1409    }
1410
1411    pub const CODE = sys::IORING_OP_MKDIRAT;
1412
1413    pub fn build(self) -> Entry {
1414        let MkDirAt { dirfd, pathname, mode } = self;
1415
1416        let mut sqe = sqe_zeroed();
1417        sqe.opcode = Self::CODE;
1418        sqe.fd = dirfd;
1419        sqe.__bindgen_anon_2.addr = pathname as _;
1420        sqe.len = mode;
1421        Entry(sqe)
1422    }
1423}
1424
1425opcode! {
1426    /// Create a symlink, equivalent to `symlinkat(2)`.
1427    pub struct SymlinkAt {
1428        newdirfd: { impl sealed::UseFd },
1429        target: { *const libc::c_char },
1430        linkpath: { *const libc::c_char },
1431        ;;
1432    }
1433
1434    pub const CODE = sys::IORING_OP_SYMLINKAT;
1435
1436    pub fn build(self) -> Entry {
1437        let SymlinkAt { newdirfd, target, linkpath } = self;
1438
1439        let mut sqe = sqe_zeroed();
1440        sqe.opcode = Self::CODE;
1441        sqe.fd = newdirfd;
1442        sqe.__bindgen_anon_2.addr = target as _;
1443        sqe.__bindgen_anon_1.addr2 = linkpath as _;
1444        Entry(sqe)
1445    }
1446}
1447
1448opcode! {
1449    /// Create a hard link, equivalent to `linkat(2)`.
1450    pub struct LinkAt {
1451        olddirfd: { impl sealed::UseFd },
1452        oldpath: { *const libc::c_char },
1453        newdirfd: { impl sealed::UseFd },
1454        newpath: { *const libc::c_char },
1455        ;;
1456        flags: i32 = 0
1457    }
1458
1459    pub const CODE = sys::IORING_OP_LINKAT;
1460
1461    pub fn build(self) -> Entry {
1462        let LinkAt { olddirfd, oldpath, newdirfd, newpath, flags } = self;
1463
1464        let mut sqe = sqe_zeroed();
1465        sqe.opcode = Self::CODE;
1466        sqe.fd = olddirfd as _;
1467        sqe.__bindgen_anon_2.addr = oldpath as _;
1468        sqe.len = newdirfd as _;
1469        sqe.__bindgen_anon_1.addr2 = newpath as _;
1470        sqe.__bindgen_anon_3.hardlink_flags = flags as _;
1471        Entry(sqe)
1472    }
1473}
1474
1475// === 5.17 ===
1476
1477opcode! {
1478    /// Get extended attribute, equivalent to `getxattr(2)`.
1479    pub struct GetXattr {
1480        name: { *const libc::c_char },
1481        value: { *mut libc::c_void },
1482        path: { *const libc::c_char },
1483        len: { u32 },
1484        ;;
1485    }
1486
1487    pub const CODE = sys::IORING_OP_GETXATTR;
1488
1489    pub fn build(self) -> Entry {
1490        let GetXattr { name, value, path, len } = self;
1491
1492        let mut sqe = sqe_zeroed();
1493        sqe.opcode = Self::CODE;
1494        sqe.__bindgen_anon_2.addr = name as _;
1495        sqe.len = len;
1496        sqe.__bindgen_anon_1.off = value as _;
1497        unsafe { sqe.__bindgen_anon_6.__bindgen_anon_1.as_mut().addr3 = path as _ };
1498        sqe.__bindgen_anon_3.xattr_flags = 0;
1499        Entry(sqe)
1500    }
1501}
1502
1503opcode! {
1504    /// Set extended attribute, equivalent to `setxattr(2)`.
1505    pub struct SetXattr {
1506        name: { *const libc::c_char },
1507        value: { *const libc::c_void },
1508        path: { *const libc::c_char },
1509        len: { u32 },
1510        ;;
1511        flags: i32 = 0
1512    }
1513
1514    pub const CODE = sys::IORING_OP_SETXATTR;
1515
1516    pub fn build(self) -> Entry {
1517        let SetXattr { name, value, path, flags, len } = self;
1518
1519        let mut sqe = sqe_zeroed();
1520        sqe.opcode = Self::CODE;
1521        sqe.__bindgen_anon_2.addr = name as _;
1522        sqe.len = len;
1523        sqe.__bindgen_anon_1.off = value as _;
1524        unsafe { sqe.__bindgen_anon_6.__bindgen_anon_1.as_mut().addr3 = path as _ };
1525        sqe.__bindgen_anon_3.xattr_flags = flags as _;
1526        Entry(sqe)
1527    }
1528}
1529
1530opcode! {
1531    /// Get extended attribute from a file descriptor, equivalent to `fgetxattr(2)`.
1532    pub struct FGetXattr {
1533        fd: { impl sealed::UseFixed },
1534        name: { *const libc::c_char },
1535        value: { *mut libc::c_void },
1536        len: { u32 },
1537        ;;
1538    }
1539
1540    pub const CODE = sys::IORING_OP_FGETXATTR;
1541
1542    pub fn build(self) -> Entry {
1543        let FGetXattr { fd, name, value, len } = self;
1544
1545        let mut sqe = sqe_zeroed();
1546        sqe.opcode = Self::CODE;
1547        assign_fd!(sqe.fd = fd);
1548        sqe.__bindgen_anon_2.addr = name as _;
1549        sqe.len = len;
1550        sqe.__bindgen_anon_1.off = value as _;
1551        sqe.__bindgen_anon_3.xattr_flags = 0;
1552        Entry(sqe)
1553    }
1554}
1555
1556opcode! {
1557    /// Set extended attribute on a file descriptor, equivalent to `fsetxattr(2)`.
1558    pub struct FSetXattr {
1559        fd: { impl sealed::UseFixed },
1560        name: { *const libc::c_char },
1561        value: { *const libc::c_void },
1562        len: { u32 },
1563        ;;
1564        flags: i32 = 0
1565    }
1566
1567    pub const CODE = sys::IORING_OP_FSETXATTR;
1568
1569    pub fn build(self) -> Entry {
1570        let FSetXattr { fd, name, value, flags, len } = self;
1571
1572        let mut sqe = sqe_zeroed();
1573        sqe.opcode = Self::CODE;
1574        assign_fd!(sqe.fd = fd);
1575        sqe.__bindgen_anon_2.addr = name as _;
1576        sqe.len = len;
1577        sqe.__bindgen_anon_1.off = value as _;
1578        sqe.__bindgen_anon_3.xattr_flags = flags as _;
1579        Entry(sqe)
1580    }
1581}
1582
1583// === 5.18 ===
1584
1585opcode! {
1586    /// Send a message (with data) to a target ring.
1587    pub struct MsgRingData {
1588        ring_fd: { impl sealed::UseFd },
1589        result: { i32 },
1590        user_data: { u64 },
1591        user_flags: { Option<u32> },
1592        ;;
1593        opcode_flags: u32 = 0
1594    }
1595
1596    pub const CODE = sys::IORING_OP_MSG_RING;
1597
1598    pub fn build(self) -> Entry {
1599        let MsgRingData { ring_fd, result, user_data, user_flags, opcode_flags } = self;
1600
1601        let mut sqe = sqe_zeroed();
1602        sqe.opcode = Self::CODE;
1603        sqe.__bindgen_anon_2.addr = sys::IORING_MSG_DATA.into();
1604        sqe.fd = ring_fd;
1605        sqe.len = result as u32;
1606        sqe.__bindgen_anon_1.off = user_data;
1607        sqe.__bindgen_anon_3.msg_ring_flags = opcode_flags;
1608        if let Some(flags) = user_flags {
1609            sqe.__bindgen_anon_5.file_index = flags;
1610            unsafe {sqe.__bindgen_anon_3.msg_ring_flags |= sys::IORING_MSG_RING_FLAGS_PASS};
1611        }
1612        Entry(sqe)
1613    }
1614}
1615
1616// === 5.19 ===
1617
1618opcode! {
1619    /// Attempt to cancel an already issued request, receiving a cancellation
1620    /// builder, which allows for the new cancel criterias introduced since
1621    /// 5.19.
1622    pub struct AsyncCancel2 {
1623        builder: { types::CancelBuilder }
1624        ;;
1625    }
1626
1627    pub const CODE = sys::IORING_OP_ASYNC_CANCEL;
1628
1629    pub fn build(self) -> Entry {
1630        let AsyncCancel2 { builder } = self;
1631
1632        let mut sqe = sqe_zeroed();
1633        sqe.opcode = Self::CODE;
1634        sqe.fd = builder.to_fd();
1635        sqe.__bindgen_anon_2.addr = builder.user_data.unwrap_or(0);
1636        sqe.__bindgen_anon_3.cancel_flags = builder.flags.bits();
1637        Entry(sqe)
1638    }
1639}
1640
1641opcode! {
1642    /// A file/device-specific 16-byte command, akin (but not equivalent) to `ioctl(2)`.
1643    pub struct UringCmd16 {
1644        fd: { impl sealed::UseFixed },
1645        cmd_op: { u32 },
1646        ;;
1647        /// The `buf_index` is an index into an array of fixed buffers,
1648        /// and is only valid if fixed buffers were registered.
1649        buf_index: Option<u16> = None,
1650        /// Arbitrary command data.
1651        cmd: [u8; 16] = [0u8; 16],
1652        /// The `addr` is typically a pointer to buffer or iovecs,
1653        /// but some file/device command also need to pass an addr.
1654        /// For example, the [ublk](https://docs.kernel.org/block/ublk.html#usage-requirements)
1655        /// needs to set `addr` to some special value.
1656        addr: Option<u64> = None,
1657    }
1658
1659    pub const CODE = sys::IORING_OP_URING_CMD;
1660
1661    pub fn build(self) -> Entry {
1662        let UringCmd16 { fd, cmd_op, cmd, buf_index, addr } = self;
1663
1664        let mut sqe = sqe_zeroed();
1665        sqe.opcode = Self::CODE;
1666        assign_fd!(sqe.fd = fd);
1667        sqe.__bindgen_anon_1.__bindgen_anon_1.cmd_op = cmd_op;
1668        unsafe { *sqe.__bindgen_anon_6.cmd.as_mut().as_mut_ptr().cast::<[u8; 16]>() = cmd };
1669        if let Some(buf_index) = buf_index {
1670            sqe.__bindgen_anon_4.buf_index = buf_index;
1671            unsafe {
1672                sqe.__bindgen_anon_3.uring_cmd_flags |= sys::IORING_URING_CMD_FIXED;
1673            }
1674        }
1675        if let Some(addr) = addr {
1676            sqe.__bindgen_anon_2.addr = addr;
1677        }
1678        Entry(sqe)
1679    }
1680}
1681
1682opcode! {
1683    /// A file/device-specific 80-byte command, akin (but not equivalent) to `ioctl(2)`.
1684    pub struct UringCmd80 {
1685        fd: { impl sealed::UseFixed },
1686        cmd_op: { u32 },
1687        ;;
1688        /// The `buf_index` is an index into an array of fixed buffers,
1689        /// and is only valid if fixed buffers were registered.
1690        buf_index: Option<u16> = None,
1691        /// Arbitrary command data.
1692        cmd: [u8; 80] = [0u8; 80],
1693        /// The `addr` is typically a pointer to buffer or iovecs,
1694        /// but some file/device command also need to pass an addr.
1695        /// For example, the [ublk](https://docs.kernel.org/block/ublk.html#usage-requirements)
1696        /// needs to set `addr` to some special value.
1697        addr: Option<u64> = None,
1698    }
1699
1700    pub const CODE = sys::IORING_OP_URING_CMD;
1701
1702    pub fn build(self) -> Entry128 {
1703        let UringCmd80 { fd, cmd_op, cmd, buf_index, addr } = self;
1704
1705        let cmd1 = cmd[..16].try_into().unwrap();
1706        let cmd2 = cmd[16..].try_into().unwrap();
1707
1708        let mut sqe = sqe_zeroed();
1709        sqe.opcode = Self::CODE;
1710        assign_fd!(sqe.fd = fd);
1711        sqe.__bindgen_anon_1.__bindgen_anon_1.cmd_op = cmd_op;
1712        unsafe { *sqe.__bindgen_anon_6.cmd.as_mut().as_mut_ptr().cast::<[u8; 16]>() = cmd1 };
1713        if let Some(buf_index) = buf_index {
1714            sqe.__bindgen_anon_4.buf_index = buf_index;
1715            unsafe {
1716                sqe.__bindgen_anon_3.uring_cmd_flags |= sys::IORING_URING_CMD_FIXED;
1717            }
1718        }
1719        if let Some(addr) = addr {
1720            sqe.__bindgen_anon_2.addr = addr;
1721        }
1722        Entry128(Entry(sqe), cmd2)
1723    }
1724}
1725
1726opcode! {
1727    /// Create an endpoint for communication, equivalent to `socket(2)`.
1728    ///
1729    /// If the `file_index` argument is set, the resulting socket is
1730    /// directly mapped to the given fixed-file slot instead of being
1731    /// returned as a normal file descriptor. The application must first
1732    /// have registered a file table, and the target slot should fit into
1733    /// it.
1734    ///
1735    /// Available since 5.19.
1736    pub struct Socket {
1737        domain: { i32 },
1738        socket_type: { i32 },
1739        protocol: { i32 },
1740        ;;
1741        file_index: Option<types::DestinationSlot> = None,
1742        flags: i32 = 0,
1743    }
1744
1745    pub const CODE = sys::IORING_OP_SOCKET;
1746
1747    pub fn build(self) -> Entry {
1748        let Socket { domain, socket_type, protocol, file_index, flags } = self;
1749
1750        let mut sqe = sqe_zeroed();
1751        sqe.opcode = Self::CODE;
1752        sqe.fd = domain as _;
1753        sqe.__bindgen_anon_1.off = socket_type as _;
1754        sqe.len = protocol as _;
1755        sqe.__bindgen_anon_3.rw_flags = flags as _;
1756        if let Some(dest) = file_index {
1757            sqe.__bindgen_anon_5.file_index = dest.kernel_index_arg();
1758        }
1759        Entry(sqe)
1760    }
1761}
1762
1763opcode! {
1764    /// Accept multiple new connections on a socket.
1765    ///
1766    /// Set the `allocate_file_index` property if fixed file table entries should be used.
1767    ///
1768    /// Available since 5.19.
1769    pub struct AcceptMulti {
1770        fd: { impl sealed::UseFixed },
1771        ;;
1772        allocate_file_index: bool = false,
1773        flags: i32 = 0
1774    }
1775
1776    pub const CODE = sys::IORING_OP_ACCEPT;
1777
1778    pub fn build(self) -> Entry {
1779        let AcceptMulti { fd, allocate_file_index, flags } = self;
1780
1781        let mut sqe = sqe_zeroed();
1782        sqe.opcode = Self::CODE;
1783        assign_fd!(sqe.fd = fd);
1784        sqe.ioprio = sys::IORING_ACCEPT_MULTISHOT as u16;
1785        // No out SockAddr is passed for the multishot accept case.
1786        // The user should perform a syscall to get any resulting connection's remote address.
1787        sqe.__bindgen_anon_3.accept_flags = flags as _;
1788        if allocate_file_index {
1789            sqe.__bindgen_anon_5.file_index = sys::IORING_FILE_INDEX_ALLOC as u32;
1790        }
1791        Entry(sqe)
1792    }
1793}
1794
1795// === 6.0 ===
1796
1797opcode! {
1798    /// Send a message (with fixed FD) to a target ring.
1799    pub struct MsgRingSendFd {
1800        ring_fd: { impl sealed::UseFd },
1801        fixed_slot_src: { types::Fixed },
1802        dest_slot_index: { types::DestinationSlot },
1803        user_data: { u64 },
1804        ;;
1805        opcode_flags: u32 = 0
1806    }
1807
1808    pub const CODE = sys::IORING_OP_MSG_RING;
1809
1810    pub fn build(self) -> Entry {
1811        let MsgRingSendFd { ring_fd, fixed_slot_src, dest_slot_index, user_data, opcode_flags } = self;
1812
1813        let mut sqe = sqe_zeroed();
1814        sqe.opcode = Self::CODE;
1815        sqe.__bindgen_anon_2.addr = sys::IORING_MSG_SEND_FD.into();
1816        sqe.fd = ring_fd;
1817        sqe.__bindgen_anon_1.off = user_data;
1818        unsafe { sqe.__bindgen_anon_6.__bindgen_anon_1.as_mut().addr3 = fixed_slot_src.0 as u64 };
1819        sqe.__bindgen_anon_5.file_index = dest_slot_index.kernel_index_arg();
1820        sqe.__bindgen_anon_3.msg_ring_flags = opcode_flags;
1821        Entry(sqe)
1822    }
1823}
1824
1825// === 6.0 ===
1826
1827opcode! {
1828    /// Send a zerocopy message on a socket, equivalent to `send(2)`.
1829    ///
1830    /// When `dest_addr` is non-zero it points to the address of the target with `dest_addr_len`
1831    /// specifying its size, turning the request into a `sendto(2)`
1832    ///
1833    /// A fixed (pre-mapped) buffer can optionally be used from pre-mapped buffers that have been
1834    /// previously registered with [`Submitter::register_buffers`](crate::Submitter::register_buffers).
1835    ///
1836    /// This operation might result in two completion queue entries.
1837    /// See the `IORING_OP_SEND_ZC` section at [io_uring_enter][] for the exact semantics.
1838    /// Notifications posted by this operation can be checked with [notif](crate::cqueue::notif).
1839    ///
1840    /// [io_uring_enter]: https://man7.org/linux/man-pages/man2/io_uring_enter.2.html
1841    pub struct SendZc {
1842        fd: { impl sealed::UseFixed },
1843        buf: { *const u8 },
1844        len: { u32 },
1845        ;;
1846        /// The `buf_index` is an index into an array of fixed buffers, and is only valid if fixed
1847        /// buffers were registered.
1848        ///
1849        /// The buf and len arguments must fall within a region specified by buf_index in the
1850        /// previously registered buffer. The buffer need not be aligned with the start of the
1851        /// registered buffer.
1852        buf_index: Option<u16> = None,
1853        dest_addr: *const libc::sockaddr = core::ptr::null(),
1854        dest_addr_len: libc::socklen_t = 0,
1855        flags: i32 = 0,
1856        zc_flags: u16 = 0,
1857    }
1858
1859    pub const CODE = sys::IORING_OP_SEND_ZC;
1860
1861    pub fn build(self) -> Entry {
1862        let SendZc { fd, buf, len, buf_index, dest_addr, dest_addr_len, flags, zc_flags } = self;
1863
1864        let mut sqe = sqe_zeroed();
1865        sqe.opcode = Self::CODE;
1866        assign_fd!(sqe.fd = fd);
1867        sqe.__bindgen_anon_2.addr = buf as _;
1868        sqe.len = len;
1869        sqe.__bindgen_anon_3.msg_flags = flags as _;
1870        sqe.ioprio = zc_flags;
1871        if let Some(buf_index) = buf_index {
1872            sqe.__bindgen_anon_4.buf_index = buf_index;
1873            sqe.ioprio |= sys::IORING_RECVSEND_FIXED_BUF as u16;
1874        }
1875        sqe.__bindgen_anon_1.addr2 = dest_addr as _;
1876        sqe.__bindgen_anon_5.__bindgen_anon_1.addr_len = dest_addr_len as _;
1877        Entry(sqe)
1878    }
1879}
1880
1881// === 6.1 ===
1882
1883opcode! {
1884    /// Send a zerocopy message on a socket, equivalent to `send(2)`.
1885    ///
1886    /// fd must be set to the socket file descriptor, addr must contains a pointer to the msghdr
1887    /// structure, and flags holds the flags associated with the system call.
1888    #[derive(Debug)]
1889    pub struct SendMsgZc {
1890        fd: { impl sealed::UseFixed },
1891        msg: { *const libc::msghdr },
1892        ;;
1893        ioprio: u16 = 0,
1894        flags: u32 = 0
1895    }
1896
1897    pub const CODE = sys::IORING_OP_SENDMSG_ZC;
1898
1899    pub fn build(self) -> Entry {
1900        let SendMsgZc { fd, msg, ioprio, flags } = self;
1901
1902        let mut sqe = sqe_zeroed();
1903        sqe.opcode = Self::CODE;
1904        assign_fd!(sqe.fd = fd);
1905        sqe.ioprio = ioprio;
1906        sqe.__bindgen_anon_2.addr = msg as _;
1907        sqe.len = 1;
1908        sqe.__bindgen_anon_3.msg_flags = flags;
1909        Entry(sqe)
1910    }
1911}
1912
1913// === 6.7 ===
1914
1915opcode! {
1916    /// Issue the equivalent of `pread(2)` with multi-shot semantics.
1917    pub struct ReadMulti {
1918        fd: { impl sealed::UseFixed },
1919        len: { u32 },
1920        buf_group: { u16 },
1921        ;;
1922        offset: u64 = 0,
1923    }
1924
1925    pub const CODE = sys::IORING_OP_READ_MULTISHOT;
1926
1927    pub fn build(self) -> Entry {
1928        let Self { fd, len, buf_group, offset } = self;
1929
1930        let mut sqe = sqe_zeroed();
1931        sqe.opcode = Self::CODE;
1932        assign_fd!(sqe.fd = fd);
1933        sqe.__bindgen_anon_1.off = offset;
1934        sqe.len = len;
1935        sqe.__bindgen_anon_4.buf_group = buf_group;
1936        sqe.flags = crate::squeue::Flags::BUFFER_SELECT.bits();
1937        Entry(sqe)
1938    }
1939}
1940
1941opcode! {
1942    /// Wait on a futex, like but not equivalant to `futex(2)`'s `FUTEX_WAIT_BITSET`.
1943    ///
1944    /// Wait on a futex at address `futex` and which still has the value `val` and with `futex2(2)`
1945    /// flags of `futex_flags`. `musk` can be set to a specific bitset mask, which will be matched
1946    /// by the waking side to decide who to wake up. To always get woken, an application may use
1947    /// `FUTEX_BITSET_MATCH_ANY` (truncated to futex bits). `futex_flags` follows the `futex2(2)`
1948    /// flags, not the `futex(2)` v1 interface flags. `flags` are currently unused and hence `0`
1949    /// must be passed.
1950    #[derive(Debug)]
1951    pub struct FutexWait {
1952        futex: { *const u32 },
1953        val: { u64 },
1954        mask: { u64 },
1955        futex_flags: { u32 },
1956        ;;
1957        flags: u32 = 0
1958    }
1959
1960    pub const CODE = sys::IORING_OP_FUTEX_WAIT;
1961
1962    pub fn build(self) -> Entry {
1963        let FutexWait { futex, val, mask, futex_flags, flags } = self;
1964
1965        let mut sqe = sqe_zeroed();
1966        sqe.opcode = Self::CODE;
1967        sqe.fd = futex_flags as _;
1968        sqe.__bindgen_anon_2.addr = futex as usize as _;
1969        sqe.__bindgen_anon_1.off = val;
1970        unsafe { sqe.__bindgen_anon_6.__bindgen_anon_1.as_mut().addr3 = mask };
1971        sqe.__bindgen_anon_3.futex_flags = flags;
1972        Entry(sqe)
1973    }
1974}
1975
1976opcode! {
1977    /// Wake up waiters on a futex, like but not equivalant to `futex(2)`'s `FUTEX_WAKE_BITSET`.
1978    ///
1979    /// Wake any waiters on the futex indicated by `futex` and at most `val` futexes. `futex_flags`
1980    /// indicates the `futex2(2)` modifier flags. If a given bitset for who to wake is desired,
1981    /// then that must be set in `mask`. Use `FUTEX_BITSET_MATCH_ANY` (truncated to futex bits) to
1982    /// match any waiter on the given futex. `flags` are currently unused and hence `0` must be
1983    /// passed.
1984    #[derive(Debug)]
1985    pub struct FutexWake {
1986        futex: { *const u32 },
1987        val: { u64 },
1988        mask: { u64 },
1989        futex_flags: { u32 },
1990        ;;
1991        flags: u32 = 0
1992    }
1993
1994    pub const CODE = sys::IORING_OP_FUTEX_WAKE;
1995
1996    pub fn build(self) -> Entry {
1997        let FutexWake { futex, val, mask, futex_flags, flags } = self;
1998
1999        let mut sqe = sqe_zeroed();
2000        sqe.opcode = Self::CODE;
2001        sqe.fd = futex_flags as _;
2002        sqe.__bindgen_anon_2.addr = futex as usize as _;
2003        sqe.__bindgen_anon_1.off = val;
2004        unsafe { sqe.__bindgen_anon_6.__bindgen_anon_1.as_mut().addr3 = mask };
2005        sqe.__bindgen_anon_3.futex_flags = flags;
2006        Entry(sqe)
2007    }
2008}
2009
2010opcode! {
2011    /// Wait on multiple futexes.
2012    ///
2013    /// Wait on multiple futexes at the same time. Futexes are given by `futexv` and `nr_futex` is
2014    /// the number of futexes in that array. Unlike `FutexWait`, the desired bitset mask and values
2015    /// are passed in `futexv`. `flags` are currently unused and hence `0` must be passed.
2016    #[derive(Debug)]
2017    pub struct FutexWaitV {
2018        futexv: { *const types::FutexWaitV },
2019        nr_futex: { u32 },
2020        ;;
2021        flags: u32 = 0
2022    }
2023
2024    pub const CODE = sys::IORING_OP_FUTEX_WAITV;
2025
2026    pub fn build(self) -> Entry {
2027        let FutexWaitV { futexv, nr_futex, flags } = self;
2028
2029        let mut sqe = sqe_zeroed();
2030        sqe.opcode = Self::CODE;
2031        sqe.__bindgen_anon_2.addr = futexv as usize as _;
2032        sqe.len = nr_futex;
2033        sqe.__bindgen_anon_3.futex_flags = flags;
2034        Entry(sqe)
2035    }
2036}
2037
2038opcode! {
2039    /// Issue the equivalent of a `waitid(2)` system call.
2040    ///
2041    /// Available since kernel 6.7.
2042    #[derive(Debug)]
2043    pub struct WaitId {
2044        idtype: { libc::idtype_t },
2045        id: { libc::id_t },
2046        options: { libc::c_int },
2047        ;;
2048        infop: *const libc::siginfo_t = std::ptr::null(),
2049        flags: libc::c_uint = 0,
2050    }
2051
2052    pub const CODE = sys::IORING_OP_WAITID;
2053
2054    pub fn build(self) -> Entry {
2055        let mut sqe = sqe_zeroed();
2056        sqe.opcode = Self::CODE;
2057        sqe.fd = self.id as _;
2058        sqe.len = self.idtype as _;
2059        sqe.__bindgen_anon_3.waitid_flags = self.flags;
2060        sqe.__bindgen_anon_5.file_index = self.options as _;
2061        sqe.__bindgen_anon_1.addr2 = self.infop as _;
2062        Entry(sqe)
2063    }
2064}
2065
2066// === 6.8 ===
2067
2068opcode! {
2069    /// Install a fixed file descriptor
2070    ///
2071    /// Turns a direct descriptor into a regular file descriptor that can be later used by regular
2072    /// system calls that take a normal raw file descriptor
2073    #[derive(Debug)]
2074    pub struct FixedFdInstall {
2075        fd: { types::Fixed },
2076        file_flags: { u32 },
2077        ;;
2078    }
2079
2080    pub const CODE = sys::IORING_OP_FIXED_FD_INSTALL;
2081
2082    pub fn build(self) -> Entry {
2083        let FixedFdInstall { fd, file_flags } = self;
2084
2085        let mut sqe = sqe_zeroed();
2086        sqe.opcode = Self::CODE;
2087        sqe.fd = fd.0 as _;
2088        sqe.flags = crate::squeue::Flags::FIXED_FILE.bits();
2089        sqe.__bindgen_anon_3.install_fd_flags = file_flags;
2090        Entry(sqe)
2091    }
2092}
2093
2094// === 6.9 ===
2095
2096opcode! {
2097    /// Perform file truncation, equivalent to `ftruncate(2)`.
2098    #[derive(Debug)]
2099    pub struct Ftruncate {
2100        fd: { impl sealed::UseFixed },
2101        len: { u64 },
2102        ;;
2103    }
2104
2105    pub const CODE = sys::IORING_OP_FTRUNCATE;
2106
2107    pub fn build(self) -> Entry {
2108        let Ftruncate { fd, len } = self;
2109
2110        let mut sqe = sqe_zeroed();
2111        sqe.opcode = Self::CODE;
2112        assign_fd!(sqe.fd = fd);
2113        sqe.__bindgen_anon_1.off = len;
2114        Entry(sqe)
2115    }
2116}
2117
2118// === 6.10 ===
2119
2120opcode! {
2121    /// Send a bundle of messages on a socket in a single request.
2122    pub struct SendBundle {
2123        fd: { impl sealed::UseFixed },
2124        buf_group: { u16 },
2125        ;;
2126        flags: i32 = 0,
2127        len: u32 = 0
2128    }
2129
2130    pub const CODE = sys::IORING_OP_SEND;
2131
2132    pub fn build(self) -> Entry {
2133        let SendBundle { fd, len, flags, buf_group } = self;
2134
2135        let mut sqe = sqe_zeroed();
2136        sqe.opcode = Self::CODE;
2137        assign_fd!(sqe.fd = fd);
2138        sqe.len = len;
2139        sqe.__bindgen_anon_3.msg_flags = flags as _;
2140        sqe.ioprio |= sys::IORING_RECVSEND_BUNDLE as u16;
2141        sqe.flags |= crate::squeue::Flags::BUFFER_SELECT.bits();
2142        sqe.__bindgen_anon_4.buf_group = buf_group;
2143        Entry(sqe)
2144    }
2145}
2146
2147opcode! {
2148    /// Receive a bundle of buffers from a socket.
2149    ///
2150    /// Parameter
2151    ///     buf_group: The id of the provided buffer pool to use for the bundle.
2152    ///
2153    /// Note that as of kernel 6.10 first recv always gets a single buffer, while second
2154    /// obtains the bundle of remaining buffers. This behavior may change in the future.
2155    ///
2156    /// Bundle variant is available since kernel 6.10
2157    pub struct RecvBundle {
2158        fd: { impl sealed::UseFixed },
2159        buf_group: { u16 },
2160        ;;
2161        flags: i32 = 0
2162    }
2163
2164    pub const CODE = sys::IORING_OP_RECV;
2165
2166    pub fn build(self) -> Entry {
2167        let RecvBundle { fd, buf_group, flags } = self;
2168
2169        let mut sqe = sqe_zeroed();
2170        sqe.opcode = Self::CODE;
2171        assign_fd!(sqe.fd = fd);
2172        sqe.__bindgen_anon_3.msg_flags = flags as _;
2173        sqe.__bindgen_anon_4.buf_group = buf_group;
2174        sqe.flags |= crate::squeue::Flags::BUFFER_SELECT.bits();
2175        sqe.ioprio |= sys::IORING_RECVSEND_BUNDLE as u16;
2176        Entry(sqe)
2177    }
2178}
2179
2180opcode! {
2181    /// Receive multiple messages from a socket as a bundle.
2182    ///
2183    /// Parameter:
2184    ///     buf_group: The id of the provided buffer pool to use for each received message.
2185    ///
2186    /// MSG_WAITALL should not be set in flags.
2187    ///
2188    /// The multishot version allows the application to issue a single receive request, which
2189    /// repeatedly posts a CQE when data is available. Each CQE will take a bundle of buffers
2190    /// out of a provided buffer pool for receiving. The application should check the flags of each CQE,
2191    /// regardless of its result. If a posted CQE does not have the IORING_CQE_F_MORE flag set then
2192    /// the multishot receive will be done and the application should issue a new request.
2193    ///
2194    /// Note that as of kernel 6.10 first CQE always gets a single buffer, while second
2195    /// obtains the bundle of remaining buffers. This behavior may change in the future.
2196    ///
2197    /// Multishot bundle variant is available since kernel 6.10.
2198    pub struct RecvMultiBundle {
2199        fd: { impl sealed::UseFixed },
2200        buf_group: { u16 },
2201        ;;
2202        flags: i32 = 0
2203    }
2204
2205    pub const CODE = sys::IORING_OP_RECV;
2206
2207    pub fn build(self) -> Entry {
2208        let RecvMultiBundle { fd, buf_group, flags } = self;
2209
2210        let mut sqe = sqe_zeroed();
2211        sqe.opcode = Self::CODE;
2212        assign_fd!(sqe.fd = fd);
2213        sqe.__bindgen_anon_3.msg_flags = flags as _;
2214        sqe.__bindgen_anon_4.buf_group = buf_group;
2215        sqe.flags |= crate::squeue::Flags::BUFFER_SELECT.bits();
2216        sqe.ioprio = sys::IORING_RECV_MULTISHOT as _;
2217        sqe.ioprio |= sys::IORING_RECVSEND_BUNDLE as u16;
2218        Entry(sqe)
2219    }
2220}
2221
2222// === 6.11 ===
2223
2224opcode! {
2225    /// Bind a socket, equivalent to `bind(2)`.
2226    pub struct Bind {
2227        fd: { impl sealed::UseFixed },
2228        addr: { *const libc::sockaddr },
2229        addrlen: { libc::socklen_t }
2230        ;;
2231    }
2232
2233    pub const CODE = sys::IORING_OP_BIND;
2234
2235    pub fn build(self) -> Entry {
2236        let Bind { fd, addr, addrlen } = self;
2237
2238        let mut sqe = sqe_zeroed();
2239        sqe.opcode = Self::CODE;
2240        assign_fd!(sqe.fd = fd);
2241        sqe.__bindgen_anon_2.addr = addr as _;
2242        sqe.__bindgen_anon_1.off = addrlen as _;
2243        Entry(sqe)
2244    }
2245}
2246
2247opcode! {
2248    /// Listen on a socket, equivalent to `listen(2)`.
2249    pub struct Listen {
2250        fd: { impl sealed::UseFixed },
2251        backlog: { i32 },
2252        ;;
2253    }
2254
2255    pub const CODE = sys::IORING_OP_LISTEN;
2256
2257    pub fn build(self) -> Entry {
2258        let Listen { fd, backlog } = self;
2259
2260        let mut sqe = sqe_zeroed();
2261        sqe.opcode = Self::CODE;
2262        assign_fd!(sqe.fd = fd);
2263        sqe.len = backlog as _;
2264        Entry(sqe)
2265    }
2266}
2267
2268// === 6.15 ===
2269
2270opcode! {
2271    /// Issue the zerocopy equivalent of a `recv(2)` system call.
2272    pub struct RecvZc {
2273        fd: { impl sealed::UseFixed },
2274        len: { u32 },
2275        ;;
2276        ifq: u32 = 0,
2277        ioprio: u16 = 0,
2278    }
2279
2280    pub const CODE = sys::IORING_OP_RECV_ZC;
2281
2282    pub fn build(self) -> Entry {
2283        let Self { fd, len, ifq, ioprio } = self;
2284
2285        let mut sqe = sqe_zeroed();
2286        sqe.opcode = Self::CODE;
2287        assign_fd!(sqe.fd = fd);
2288        sqe.len = len;
2289        sqe.ioprio = ioprio | sys::IORING_RECV_MULTISHOT as u16;
2290        sqe.__bindgen_anon_5.zcrx_ifq_idx = ifq;
2291        Entry(sqe)
2292    }
2293}
2294
2295opcode! {
2296    /// Issue the equivalent of a `epoll_wait(2)` system call.
2297    pub struct EpollWait {
2298        fd: { impl sealed::UseFixed },
2299        events: { *mut types::epoll_event },
2300        max_events: { u32 },
2301        ;;
2302        flags: u32 = 0,
2303    }
2304
2305    pub const CODE = sys::IORING_OP_EPOLL_WAIT;
2306
2307    pub fn build(self) -> Entry {
2308        let Self { fd, events, max_events, flags } = self;
2309
2310        let mut sqe = sqe_zeroed();
2311        sqe.opcode = Self::CODE;
2312        assign_fd!(sqe.fd = fd);
2313        sqe.__bindgen_anon_2.addr = events as u64;
2314        sqe.len = max_events;
2315        sqe.__bindgen_anon_3.poll32_events = flags;
2316        Entry(sqe)
2317    }
2318}
2319
2320opcode! {
2321    /// Vectored read into a fixed buffer, equivalent to `preadv2(2)`.
2322    pub struct ReadvFixed {
2323        fd: { impl sealed::UseFixed },
2324        iovec: { *const ::libc::iovec },
2325        len: { u32 },
2326        buf_index: { u16 },
2327        ;;
2328        ioprio: u16 = 0,
2329        offset: u64 = 0,
2330        rw_flags: i32 = 0,
2331    }
2332
2333    pub const CODE = sys::IORING_OP_READV_FIXED;
2334
2335    pub fn build(self) -> Entry {
2336        let Self { fd, iovec, len, buf_index, offset, ioprio, rw_flags } = self;
2337
2338        let mut sqe = sqe_zeroed();
2339        sqe.opcode = Self::CODE;
2340        assign_fd!(sqe.fd = fd);
2341        sqe.__bindgen_anon_1.off = offset as _;
2342        sqe.__bindgen_anon_2.addr = iovec as _;
2343        sqe.len = len;
2344        sqe.__bindgen_anon_4.buf_index = buf_index;
2345        sqe.ioprio = ioprio;
2346        sqe.__bindgen_anon_3.rw_flags = rw_flags as _;
2347        Entry(sqe)
2348    }
2349}
2350
2351opcode! {
2352    /// Vectored write from a fixed buffer, equivalent to `pwritev2(2)`.
2353    pub struct WritevFixed {
2354        fd: { impl sealed::UseFixed },
2355        iovec: { *const ::libc::iovec },
2356        len: { u32 },
2357        buf_index: { u16 },
2358        ;;
2359        ioprio: u16 = 0,
2360        offset: u64 = 0,
2361        rw_flags: i32 = 0,
2362    }
2363
2364    pub const CODE = sys::IORING_OP_WRITEV_FIXED;
2365
2366    pub fn build(self) -> Entry {
2367        let Self { fd, iovec, len, buf_index, offset, ioprio, rw_flags } = self;
2368
2369        let mut sqe = sqe_zeroed();
2370        sqe.opcode = Self::CODE;
2371        assign_fd!(sqe.fd = fd);
2372        sqe.__bindgen_anon_1.off = offset as _;
2373        sqe.__bindgen_anon_2.addr = iovec as _;
2374        sqe.len = len;
2375        sqe.__bindgen_anon_4.buf_index = buf_index;
2376        sqe.ioprio = ioprio;
2377        sqe.__bindgen_anon_3.rw_flags = rw_flags as _;
2378        Entry(sqe)
2379    }
2380}
2381
2382// === 6.16 ===
2383
2384opcode! {
2385    // Create a pipe, equivalent to `pipe(2)`.
2386    pub struct Pipe {
2387        fds: { *mut RawFd },
2388        ;;
2389        flags: u32 = 0,
2390        file_index: Option<types::DestinationSlot> = None,
2391    }
2392
2393    pub const CODE = sys::IORING_OP_PIPE;
2394
2395    pub fn build(self) -> Entry {
2396        let Self { fds, flags, file_index } = self;
2397
2398        let mut sqe = sqe_zeroed();
2399        sqe.opcode = Self::CODE;
2400        sqe.fd = 0;
2401        sqe.__bindgen_anon_2.addr = fds as _;
2402        sqe.__bindgen_anon_3.pipe_flags = flags;
2403        if let Some(dest) = file_index {
2404            sqe.__bindgen_anon_5.file_index = dest.kernel_index_arg();
2405        }
2406        Entry(sqe)
2407    }
2408}