Skip to main content

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