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