Skip to main content

io_uring/
register.rs

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