rustix_uring/
register.rs

1//! Some register syscall related types or parameters.
2
3use core::fmt;
4use rustix::fd::{AsFd, BorrowedFd};
5
6use rustix::io;
7
8use crate::sys;
9
10pub(crate) fn execute<Fd: AsFd>(
11    fd: Fd,
12    opcode: sys::IoringRegisterOp,
13    arg: *const core::ffi::c_void,
14    len: u32,
15) -> io::Result<()> {
16    unsafe {
17        sys::io_uring_register(fd.as_fd(), opcode, arg, len)?;
18    }
19    Ok(())
20}
21
22/// Information about what `io_uring` features the kernel supports.
23///
24/// You can fill this in with [`register_probe`](crate::Submitter::register_probe).
25pub struct Probe(ProbeAndOps);
26
27#[repr(C)]
28struct ProbeAndOps(sys::io_uring_probe, [sys::io_uring_probe_op; Probe::COUNT]);
29
30impl Probe {
31    pub(crate) const COUNT: usize = 256;
32
33    /// Create a new probe with no features enabled.
34    pub fn new() -> Probe {
35        Probe(ProbeAndOps(
36            sys::io_uring_probe::default(),
37            [sys::io_uring_probe_op::default(); Probe::COUNT],
38        ))
39    }
40
41    #[inline]
42    pub(crate) fn as_mut_ptr(&mut self) -> *mut sys::io_uring_probe {
43        &mut (self.0).0
44    }
45
46    /// Get whether a specific opcode is supported.
47    pub fn is_supported(&self, opcode: sys::IoringOp) -> bool {
48        unsafe {
49            let probe = &(self.0).0;
50
51            if opcode as u32 <= probe.last_op as u32 {
52                let ops = probe.ops.as_slice(Self::COUNT);
53                ops[opcode as usize]
54                    .flags
55                    .contains(sys::IoringOpFlags::SUPPORTED)
56            } else {
57                false
58            }
59        }
60    }
61}
62
63impl Default for Probe {
64    #[inline]
65    fn default() -> Probe {
66        Probe::new()
67    }
68}
69
70impl fmt::Debug for Probe {
71    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72        struct Op<'a>(&'a sys::io_uring_probe_op);
73
74        impl fmt::Debug for Op<'_> {
75            #[inline]
76            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77                f.debug_struct("Op").field("code", &self.0.op).finish()
78            }
79        }
80
81        let probe = &(self.0).0;
82        let list = unsafe { probe.ops.as_slice(probe.last_op as usize + 1) };
83        let list = list
84            .iter()
85            .filter(|op| op.flags.contains(sys::IoringOpFlags::SUPPORTED))
86            .map(Op);
87
88        f.debug_set().entries(list).finish()
89    }
90}
91
92/// An allowed feature of io_uring. You can set the allowed features with
93/// [`register_restrictions`](crate::Submitter::register_restrictions).
94#[repr(transparent)]
95pub struct Restriction(sys::io_uring_restriction);
96
97/// inline zeroed to improve codegen
98#[inline(always)]
99fn res_zeroed() -> sys::io_uring_restriction {
100    Default::default()
101}
102
103impl Restriction {
104    /// Allow an `io_uring_register` opcode.
105    pub fn register_op(op: sys::IoringRegisterOp) -> Restriction {
106        let mut res = res_zeroed();
107        res.opcode = sys::IoringRestrictionOp::RegisterOp;
108        res.register_or_sqe_op_or_sqe_flags.register_op = op;
109        Restriction(res)
110    }
111
112    /// Allow a submission queue event opcode.
113    pub fn sqe_op(op: sys::IoringOp) -> Restriction {
114        let mut res = res_zeroed();
115        res.opcode = sys::IoringRestrictionOp::SqeOp;
116        res.register_or_sqe_op_or_sqe_flags.sqe_op = op;
117        Restriction(res)
118    }
119
120    /// Allow the given [submission queue event flags](crate::squeue::Flags).
121    pub fn sqe_flags_allowed(flags: sys::IoringSqeFlags) -> Restriction {
122        let mut res = res_zeroed();
123        res.opcode = sys::IoringRestrictionOp::SqeFlagsAllowed;
124        res.register_or_sqe_op_or_sqe_flags.sqe_flags = flags;
125        Restriction(res)
126    }
127
128    /// Require the given [submission queue event flags](crate::squeue::Flags). These flags must be
129    /// set on every submission.
130    pub fn sqe_flags_required(flags: sys::IoringSqeFlags) -> Restriction {
131        let mut res = res_zeroed();
132        res.opcode = sys::IoringRestrictionOp::SqeFlagsRequired;
133        res.register_or_sqe_op_or_sqe_flags.sqe_flags = flags;
134        Restriction(res)
135    }
136}
137
138/// A RawFd, which can be used for
139/// [register_files_update](crate::Submitter::register_files_update).
140///
141/// File descriptors can be skipped if they are set to `SKIP_FILE`.
142/// Skipping an fd will not touch the file associated with the previous fd at that index.
143pub const SKIP_FILE: BorrowedFd<'static> = rustix::io_uring::IORING_REGISTER_FILES_SKIP;
144
145#[test]
146fn test_probe_layout() {
147    use core::alloc::Layout;
148
149    let probe = Probe::new();
150    assert_eq!(
151        Layout::new::<sys::io_uring_probe>().size() + size_of::<sys::io_uring_probe_op>() * 256,
152        Layout::for_value(&probe.0).size()
153    );
154    assert_eq!(
155        Layout::new::<sys::io_uring_probe>().align(),
156        Layout::for_value(&probe.0).align()
157    );
158}