1use 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
22pub 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 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 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#[repr(transparent)]
95pub struct Restriction(sys::io_uring_restriction);
96
97#[inline(always)]
99fn res_zeroed() -> sys::io_uring_restriction {
100 Default::default()
101}
102
103impl Restriction {
104 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 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 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 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
138pub 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}