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