1use 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
29pub 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 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 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#[repr(transparent)]
100pub struct Restriction(sys::io_uring_restriction);
101
102#[inline(always)]
104fn res_zeroed() -> sys::io_uring_restriction {
105 unsafe { std::mem::zeroed() }
106}
107
108impl Restriction {
109 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 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 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 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
143pub 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}