1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2020 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker
5*bb4ee6a4SAndroid Build Coastguard Worker // This file makes several casts from u8 pointers into more-aligned pointer types.
6*bb4ee6a4SAndroid Build Coastguard Worker // We assume that the kernel will give us suitably aligned memory.
7*bb4ee6a4SAndroid Build Coastguard Worker #![allow(clippy::cast_ptr_alignment)]
8*bb4ee6a4SAndroid Build Coastguard Worker
9*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::BTreeMap;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::File;
11*bb4ee6a4SAndroid Build Coastguard Worker use std::io;
12*bb4ee6a4SAndroid Build Coastguard Worker use std::os::unix::io::AsRawFd;
13*bb4ee6a4SAndroid Build Coastguard Worker use std::os::unix::io::FromRawFd;
14*bb4ee6a4SAndroid Build Coastguard Worker use std::os::unix::io::RawFd;
15*bb4ee6a4SAndroid Build Coastguard Worker use std::pin::Pin;
16*bb4ee6a4SAndroid Build Coastguard Worker use std::ptr::null;
17*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::AtomicPtr;
18*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::AtomicU32;
19*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::Ordering;
20*bb4ee6a4SAndroid Build Coastguard Worker
21*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptor;
22*bb4ee6a4SAndroid Build Coastguard Worker use base::EventType;
23*bb4ee6a4SAndroid Build Coastguard Worker use base::IoBufMut;
24*bb4ee6a4SAndroid Build Coastguard Worker use base::MappedRegion;
25*bb4ee6a4SAndroid Build Coastguard Worker use base::MemoryMapping;
26*bb4ee6a4SAndroid Build Coastguard Worker use base::MemoryMappingBuilder;
27*bb4ee6a4SAndroid Build Coastguard Worker use base::Protection;
28*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor;
29*bb4ee6a4SAndroid Build Coastguard Worker use libc::c_void;
30*bb4ee6a4SAndroid Build Coastguard Worker use remain::sorted;
31*bb4ee6a4SAndroid Build Coastguard Worker use sync::Mutex;
32*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error as ThisError;
33*bb4ee6a4SAndroid Build Coastguard Worker
34*bb4ee6a4SAndroid Build Coastguard Worker use crate::bindings::*;
35*bb4ee6a4SAndroid Build Coastguard Worker use crate::syscalls::*;
36*bb4ee6a4SAndroid Build Coastguard Worker
37*bb4ee6a4SAndroid Build Coastguard Worker /// Holds per-operation, user specified data. The usage is up to the caller. The most common use is
38*bb4ee6a4SAndroid Build Coastguard Worker /// for callers to identify each request.
39*bb4ee6a4SAndroid Build Coastguard Worker pub type UserData = u64;
40*bb4ee6a4SAndroid Build Coastguard Worker
41*bb4ee6a4SAndroid Build Coastguard Worker #[sorted]
42*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, ThisError)]
43*bb4ee6a4SAndroid Build Coastguard Worker pub enum Error {
44*bb4ee6a4SAndroid Build Coastguard Worker /// Failed to map the completion ring.
45*bb4ee6a4SAndroid Build Coastguard Worker #[error("Failed to mmap completion ring {0}")]
46*bb4ee6a4SAndroid Build Coastguard Worker MappingCompleteRing(base::MmapError),
47*bb4ee6a4SAndroid Build Coastguard Worker /// Failed to map submit entries.
48*bb4ee6a4SAndroid Build Coastguard Worker #[error("Failed to mmap submit entries {0}")]
49*bb4ee6a4SAndroid Build Coastguard Worker MappingSubmitEntries(base::MmapError),
50*bb4ee6a4SAndroid Build Coastguard Worker /// Failed to map the submit ring.
51*bb4ee6a4SAndroid Build Coastguard Worker #[error("Failed to mmap submit ring {0}")]
52*bb4ee6a4SAndroid Build Coastguard Worker MappingSubmitRing(base::MmapError),
53*bb4ee6a4SAndroid Build Coastguard Worker /// Too many ops are already queued.
54*bb4ee6a4SAndroid Build Coastguard Worker #[error("No space for more ring entries, try increasing the size passed to `new`")]
55*bb4ee6a4SAndroid Build Coastguard Worker NoSpace,
56*bb4ee6a4SAndroid Build Coastguard Worker /// The call to `io_uring_enter` failed with the given errno.
57*bb4ee6a4SAndroid Build Coastguard Worker #[error("Failed to enter io uring: {0}")]
58*bb4ee6a4SAndroid Build Coastguard Worker RingEnter(libc::c_int),
59*bb4ee6a4SAndroid Build Coastguard Worker /// The call to `io_uring_register` failed with the given errno.
60*bb4ee6a4SAndroid Build Coastguard Worker #[error("Failed to register operations for io uring: {0}")]
61*bb4ee6a4SAndroid Build Coastguard Worker RingRegister(libc::c_int),
62*bb4ee6a4SAndroid Build Coastguard Worker /// The call to `io_uring_setup` failed with the given errno.
63*bb4ee6a4SAndroid Build Coastguard Worker #[error("Failed to setup io uring {0}")]
64*bb4ee6a4SAndroid Build Coastguard Worker Setup(libc::c_int),
65*bb4ee6a4SAndroid Build Coastguard Worker }
66*bb4ee6a4SAndroid Build Coastguard Worker pub type Result<T> = std::result::Result<T, Error>;
67*bb4ee6a4SAndroid Build Coastguard Worker
68*bb4ee6a4SAndroid Build Coastguard Worker impl From<Error> for io::Error {
from(e: Error) -> Self69*bb4ee6a4SAndroid Build Coastguard Worker fn from(e: Error) -> Self {
70*bb4ee6a4SAndroid Build Coastguard Worker use Error::*;
71*bb4ee6a4SAndroid Build Coastguard Worker match e {
72*bb4ee6a4SAndroid Build Coastguard Worker RingEnter(errno) => io::Error::from_raw_os_error(errno),
73*bb4ee6a4SAndroid Build Coastguard Worker Setup(errno) => io::Error::from_raw_os_error(errno),
74*bb4ee6a4SAndroid Build Coastguard Worker e => io::Error::new(io::ErrorKind::Other, e),
75*bb4ee6a4SAndroid Build Coastguard Worker }
76*bb4ee6a4SAndroid Build Coastguard Worker }
77*bb4ee6a4SAndroid Build Coastguard Worker }
78*bb4ee6a4SAndroid Build Coastguard Worker
79*bb4ee6a4SAndroid Build Coastguard Worker pub struct SubmitQueue {
80*bb4ee6a4SAndroid Build Coastguard Worker submit_ring: SubmitQueueState,
81*bb4ee6a4SAndroid Build Coastguard Worker submit_queue_entries: SubmitQueueEntries,
82*bb4ee6a4SAndroid Build Coastguard Worker submitting: usize, // The number of ops in the process of being submitted.
83*bb4ee6a4SAndroid Build Coastguard Worker pub added: usize, // The number of ops added since the last call to `io_uring_enter`.
84*bb4ee6a4SAndroid Build Coastguard Worker num_sqes: usize, // The total number of sqes allocated in shared memory.
85*bb4ee6a4SAndroid Build Coastguard Worker }
86*bb4ee6a4SAndroid Build Coastguard Worker
87*bb4ee6a4SAndroid Build Coastguard Worker // Helper functions to set io_uring_sqe bindgen union members in a less verbose manner.
88*bb4ee6a4SAndroid Build Coastguard Worker impl io_uring_sqe {
set_addr(&mut self, val: u64)89*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_addr(&mut self, val: u64) {
90*bb4ee6a4SAndroid Build Coastguard Worker self.__bindgen_anon_2.addr = val;
91*bb4ee6a4SAndroid Build Coastguard Worker }
set_off(&mut self, val: u64)92*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_off(&mut self, val: u64) {
93*bb4ee6a4SAndroid Build Coastguard Worker self.__bindgen_anon_1.off = val;
94*bb4ee6a4SAndroid Build Coastguard Worker }
95*bb4ee6a4SAndroid Build Coastguard Worker
set_buf_index(&mut self, val: u16)96*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_buf_index(&mut self, val: u16) {
97*bb4ee6a4SAndroid Build Coastguard Worker self.__bindgen_anon_4.buf_index = val;
98*bb4ee6a4SAndroid Build Coastguard Worker }
99*bb4ee6a4SAndroid Build Coastguard Worker
set_rw_flags(&mut self, val: libc::c_int)100*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_rw_flags(&mut self, val: libc::c_int) {
101*bb4ee6a4SAndroid Build Coastguard Worker self.__bindgen_anon_3.rw_flags = val;
102*bb4ee6a4SAndroid Build Coastguard Worker }
103*bb4ee6a4SAndroid Build Coastguard Worker
set_poll_events(&mut self, val: u32)104*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_poll_events(&mut self, val: u32) {
105*bb4ee6a4SAndroid Build Coastguard Worker let val = if cfg!(target_endian = "big") {
106*bb4ee6a4SAndroid Build Coastguard Worker // Swap words on big-endian platforms to match the original ABI where poll_events was 16
107*bb4ee6a4SAndroid Build Coastguard Worker // bits wide.
108*bb4ee6a4SAndroid Build Coastguard Worker val.rotate_left(16)
109*bb4ee6a4SAndroid Build Coastguard Worker } else {
110*bb4ee6a4SAndroid Build Coastguard Worker val
111*bb4ee6a4SAndroid Build Coastguard Worker };
112*bb4ee6a4SAndroid Build Coastguard Worker self.__bindgen_anon_3.poll32_events = val;
113*bb4ee6a4SAndroid Build Coastguard Worker }
114*bb4ee6a4SAndroid Build Coastguard Worker }
115*bb4ee6a4SAndroid Build Coastguard Worker
116*bb4ee6a4SAndroid Build Coastguard Worker // Convert a file offset to the raw io_uring offset format.
117*bb4ee6a4SAndroid Build Coastguard Worker // Some => explicit offset
118*bb4ee6a4SAndroid Build Coastguard Worker // None => use current file position
file_offset_to_raw_offset(offset: Option<u64>) -> u64119*bb4ee6a4SAndroid Build Coastguard Worker fn file_offset_to_raw_offset(offset: Option<u64>) -> u64 {
120*bb4ee6a4SAndroid Build Coastguard Worker // File offsets are interpretted as off64_t inside io_uring, with -1 representing the current
121*bb4ee6a4SAndroid Build Coastguard Worker // file position.
122*bb4ee6a4SAndroid Build Coastguard Worker const USE_CURRENT_FILE_POS: libc::off64_t = -1;
123*bb4ee6a4SAndroid Build Coastguard Worker offset.unwrap_or(USE_CURRENT_FILE_POS as u64)
124*bb4ee6a4SAndroid Build Coastguard Worker }
125*bb4ee6a4SAndroid Build Coastguard Worker
126*bb4ee6a4SAndroid Build Coastguard Worker impl SubmitQueue {
127*bb4ee6a4SAndroid Build Coastguard Worker // Call `f` with the next available sqe or return an error if none are available.
128*bb4ee6a4SAndroid Build Coastguard Worker // After `f` returns, the sqe is appended to the kernel's queue.
prep_next_sqe<F>(&mut self, mut f: F) -> Result<()> where F: FnMut(&mut io_uring_sqe),129*bb4ee6a4SAndroid Build Coastguard Worker fn prep_next_sqe<F>(&mut self, mut f: F) -> Result<()>
130*bb4ee6a4SAndroid Build Coastguard Worker where
131*bb4ee6a4SAndroid Build Coastguard Worker F: FnMut(&mut io_uring_sqe),
132*bb4ee6a4SAndroid Build Coastguard Worker {
133*bb4ee6a4SAndroid Build Coastguard Worker if self.added == self.num_sqes {
134*bb4ee6a4SAndroid Build Coastguard Worker return Err(Error::NoSpace);
135*bb4ee6a4SAndroid Build Coastguard Worker }
136*bb4ee6a4SAndroid Build Coastguard Worker
137*bb4ee6a4SAndroid Build Coastguard Worker // Find the next free submission entry in the submit ring and fill it with an iovec.
138*bb4ee6a4SAndroid Build Coastguard Worker // The below raw pointer derefs are safe because the memory the pointers use lives as long
139*bb4ee6a4SAndroid Build Coastguard Worker // as the mmap in self.
140*bb4ee6a4SAndroid Build Coastguard Worker let tail = self.submit_ring.pointers.tail(Ordering::Relaxed);
141*bb4ee6a4SAndroid Build Coastguard Worker let next_tail = tail.wrapping_add(1);
142*bb4ee6a4SAndroid Build Coastguard Worker if next_tail == self.submit_ring.pointers.head(Ordering::Acquire) {
143*bb4ee6a4SAndroid Build Coastguard Worker return Err(Error::NoSpace);
144*bb4ee6a4SAndroid Build Coastguard Worker }
145*bb4ee6a4SAndroid Build Coastguard Worker // `tail` is the next sqe to use.
146*bb4ee6a4SAndroid Build Coastguard Worker let index = (tail & self.submit_ring.ring_mask) as usize;
147*bb4ee6a4SAndroid Build Coastguard Worker let sqe = self.submit_queue_entries.get_mut(index).unwrap();
148*bb4ee6a4SAndroid Build Coastguard Worker
149*bb4ee6a4SAndroid Build Coastguard Worker f(sqe);
150*bb4ee6a4SAndroid Build Coastguard Worker
151*bb4ee6a4SAndroid Build Coastguard Worker // Tells the kernel to use the new index when processing the entry at that index.
152*bb4ee6a4SAndroid Build Coastguard Worker self.submit_ring.set_array_entry(index, index as u32);
153*bb4ee6a4SAndroid Build Coastguard Worker // Ensure the above writes to sqe are seen before the tail is updated.
154*bb4ee6a4SAndroid Build Coastguard Worker // set_tail uses Release ordering when storing to the ring.
155*bb4ee6a4SAndroid Build Coastguard Worker self.submit_ring.pointers.set_tail(next_tail);
156*bb4ee6a4SAndroid Build Coastguard Worker
157*bb4ee6a4SAndroid Build Coastguard Worker self.added += 1;
158*bb4ee6a4SAndroid Build Coastguard Worker
159*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
160*bb4ee6a4SAndroid Build Coastguard Worker }
161*bb4ee6a4SAndroid Build Coastguard Worker
162*bb4ee6a4SAndroid Build Coastguard Worker // Returns the number of entries that have been added to this SubmitQueue since the last time
163*bb4ee6a4SAndroid Build Coastguard Worker // `prepare_submit` was called.
prepare_submit(&mut self) -> usize164*bb4ee6a4SAndroid Build Coastguard Worker fn prepare_submit(&mut self) -> usize {
165*bb4ee6a4SAndroid Build Coastguard Worker let out = self.added - self.submitting;
166*bb4ee6a4SAndroid Build Coastguard Worker self.submitting = self.added;
167*bb4ee6a4SAndroid Build Coastguard Worker
168*bb4ee6a4SAndroid Build Coastguard Worker out
169*bb4ee6a4SAndroid Build Coastguard Worker }
170*bb4ee6a4SAndroid Build Coastguard Worker
171*bb4ee6a4SAndroid Build Coastguard Worker // Indicates that we failed to submit `count` entries to the kernel and that they should be
172*bb4ee6a4SAndroid Build Coastguard Worker // retried.
fail_submit(&mut self, count: usize)173*bb4ee6a4SAndroid Build Coastguard Worker fn fail_submit(&mut self, count: usize) {
174*bb4ee6a4SAndroid Build Coastguard Worker debug_assert!(count <= self.submitting);
175*bb4ee6a4SAndroid Build Coastguard Worker self.submitting -= count;
176*bb4ee6a4SAndroid Build Coastguard Worker }
177*bb4ee6a4SAndroid Build Coastguard Worker
178*bb4ee6a4SAndroid Build Coastguard Worker // Indicates that `count` entries have been submitted to the kernel and so the space may be
179*bb4ee6a4SAndroid Build Coastguard Worker // reused for new entries.
complete_submit(&mut self, count: usize)180*bb4ee6a4SAndroid Build Coastguard Worker fn complete_submit(&mut self, count: usize) {
181*bb4ee6a4SAndroid Build Coastguard Worker debug_assert!(count <= self.submitting);
182*bb4ee6a4SAndroid Build Coastguard Worker self.submitting -= count;
183*bb4ee6a4SAndroid Build Coastguard Worker self.added -= count;
184*bb4ee6a4SAndroid Build Coastguard Worker }
185*bb4ee6a4SAndroid Build Coastguard Worker }
186*bb4ee6a4SAndroid Build Coastguard Worker
187*bb4ee6a4SAndroid Build Coastguard Worker /// Enum to represent all io_uring operations
188*bb4ee6a4SAndroid Build Coastguard Worker #[repr(u32)]
189*bb4ee6a4SAndroid Build Coastguard Worker pub enum URingOperation {
190*bb4ee6a4SAndroid Build Coastguard Worker Nop = io_uring_op_IORING_OP_NOP,
191*bb4ee6a4SAndroid Build Coastguard Worker Readv = io_uring_op_IORING_OP_READV,
192*bb4ee6a4SAndroid Build Coastguard Worker Writev = io_uring_op_IORING_OP_WRITEV,
193*bb4ee6a4SAndroid Build Coastguard Worker Fsync = io_uring_op_IORING_OP_FSYNC,
194*bb4ee6a4SAndroid Build Coastguard Worker ReadFixed = io_uring_op_IORING_OP_READ_FIXED,
195*bb4ee6a4SAndroid Build Coastguard Worker WriteFixed = io_uring_op_IORING_OP_WRITE_FIXED,
196*bb4ee6a4SAndroid Build Coastguard Worker PollAdd = io_uring_op_IORING_OP_POLL_ADD,
197*bb4ee6a4SAndroid Build Coastguard Worker PollRemove = io_uring_op_IORING_OP_POLL_REMOVE,
198*bb4ee6a4SAndroid Build Coastguard Worker SyncFileRange = io_uring_op_IORING_OP_SYNC_FILE_RANGE,
199*bb4ee6a4SAndroid Build Coastguard Worker Sendmsg = io_uring_op_IORING_OP_SENDMSG,
200*bb4ee6a4SAndroid Build Coastguard Worker Recvmsg = io_uring_op_IORING_OP_RECVMSG,
201*bb4ee6a4SAndroid Build Coastguard Worker Timeout = io_uring_op_IORING_OP_TIMEOUT,
202*bb4ee6a4SAndroid Build Coastguard Worker TimeoutRemove = io_uring_op_IORING_OP_TIMEOUT_REMOVE,
203*bb4ee6a4SAndroid Build Coastguard Worker Accept = io_uring_op_IORING_OP_ACCEPT,
204*bb4ee6a4SAndroid Build Coastguard Worker AsyncCancel = io_uring_op_IORING_OP_ASYNC_CANCEL,
205*bb4ee6a4SAndroid Build Coastguard Worker LinkTimeout = io_uring_op_IORING_OP_LINK_TIMEOUT,
206*bb4ee6a4SAndroid Build Coastguard Worker Connect = io_uring_op_IORING_OP_CONNECT,
207*bb4ee6a4SAndroid Build Coastguard Worker Fallocate = io_uring_op_IORING_OP_FALLOCATE,
208*bb4ee6a4SAndroid Build Coastguard Worker Openat = io_uring_op_IORING_OP_OPENAT,
209*bb4ee6a4SAndroid Build Coastguard Worker Close = io_uring_op_IORING_OP_CLOSE,
210*bb4ee6a4SAndroid Build Coastguard Worker FilesUpdate = io_uring_op_IORING_OP_FILES_UPDATE,
211*bb4ee6a4SAndroid Build Coastguard Worker Statx = io_uring_op_IORING_OP_STATX,
212*bb4ee6a4SAndroid Build Coastguard Worker Read = io_uring_op_IORING_OP_READ,
213*bb4ee6a4SAndroid Build Coastguard Worker Write = io_uring_op_IORING_OP_WRITE,
214*bb4ee6a4SAndroid Build Coastguard Worker Fadvise = io_uring_op_IORING_OP_FADVISE,
215*bb4ee6a4SAndroid Build Coastguard Worker Madvise = io_uring_op_IORING_OP_MADVISE,
216*bb4ee6a4SAndroid Build Coastguard Worker Send = io_uring_op_IORING_OP_SEND,
217*bb4ee6a4SAndroid Build Coastguard Worker Recv = io_uring_op_IORING_OP_RECV,
218*bb4ee6a4SAndroid Build Coastguard Worker Openat2 = io_uring_op_IORING_OP_OPENAT2,
219*bb4ee6a4SAndroid Build Coastguard Worker EpollCtl = io_uring_op_IORING_OP_EPOLL_CTL,
220*bb4ee6a4SAndroid Build Coastguard Worker Splice = io_uring_op_IORING_OP_SPLICE,
221*bb4ee6a4SAndroid Build Coastguard Worker ProvideBuffers = io_uring_op_IORING_OP_PROVIDE_BUFFERS,
222*bb4ee6a4SAndroid Build Coastguard Worker RemoveBuffers = io_uring_op_IORING_OP_REMOVE_BUFFERS,
223*bb4ee6a4SAndroid Build Coastguard Worker Tee = io_uring_op_IORING_OP_TEE,
224*bb4ee6a4SAndroid Build Coastguard Worker Shutdown = io_uring_op_IORING_OP_SHUTDOWN,
225*bb4ee6a4SAndroid Build Coastguard Worker Renameat = io_uring_op_IORING_OP_RENAMEAT,
226*bb4ee6a4SAndroid Build Coastguard Worker Unlinkat = io_uring_op_IORING_OP_UNLINKAT,
227*bb4ee6a4SAndroid Build Coastguard Worker Mkdirat = io_uring_op_IORING_OP_MKDIRAT,
228*bb4ee6a4SAndroid Build Coastguard Worker Symlinkat = io_uring_op_IORING_OP_SYMLINKAT,
229*bb4ee6a4SAndroid Build Coastguard Worker Linkat = io_uring_op_IORING_OP_LINKAT,
230*bb4ee6a4SAndroid Build Coastguard Worker }
231*bb4ee6a4SAndroid Build Coastguard Worker
232*bb4ee6a4SAndroid Build Coastguard Worker /// Represents an allowlist of the restrictions to be registered to a uring.
233*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Default)]
234*bb4ee6a4SAndroid Build Coastguard Worker pub struct URingAllowlist(Vec<io_uring_restriction>);
235*bb4ee6a4SAndroid Build Coastguard Worker
236*bb4ee6a4SAndroid Build Coastguard Worker impl URingAllowlist {
237*bb4ee6a4SAndroid Build Coastguard Worker /// Create a new `UringAllowList` which allows no operation.
new() -> Self238*bb4ee6a4SAndroid Build Coastguard Worker pub fn new() -> Self {
239*bb4ee6a4SAndroid Build Coastguard Worker URingAllowlist::default()
240*bb4ee6a4SAndroid Build Coastguard Worker }
241*bb4ee6a4SAndroid Build Coastguard Worker
242*bb4ee6a4SAndroid Build Coastguard Worker /// Allow `operation` to be submitted to the submit queue of the io_uring.
allow_submit_operation(&mut self, operation: URingOperation) -> &mut Self243*bb4ee6a4SAndroid Build Coastguard Worker pub fn allow_submit_operation(&mut self, operation: URingOperation) -> &mut Self {
244*bb4ee6a4SAndroid Build Coastguard Worker self.0.push(io_uring_restriction {
245*bb4ee6a4SAndroid Build Coastguard Worker opcode: IORING_RESTRICTION_SQE_OP as u16,
246*bb4ee6a4SAndroid Build Coastguard Worker __bindgen_anon_1: io_uring_restriction__bindgen_ty_1 {
247*bb4ee6a4SAndroid Build Coastguard Worker sqe_op: operation as u8,
248*bb4ee6a4SAndroid Build Coastguard Worker },
249*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default()
250*bb4ee6a4SAndroid Build Coastguard Worker });
251*bb4ee6a4SAndroid Build Coastguard Worker self
252*bb4ee6a4SAndroid Build Coastguard Worker }
253*bb4ee6a4SAndroid Build Coastguard Worker }
254*bb4ee6a4SAndroid Build Coastguard Worker
255*bb4ee6a4SAndroid Build Coastguard Worker /// Unsafe wrapper for the kernel's io_uring interface. Allows for queueing multiple I/O operations
256*bb4ee6a4SAndroid Build Coastguard Worker /// to the kernel and asynchronously handling the completion of these operations.
257*bb4ee6a4SAndroid Build Coastguard Worker /// Use the various `add_*` functions to configure operations, then call `wait` to start
258*bb4ee6a4SAndroid Build Coastguard Worker /// the operations and get any completed results. Each op is given a u64 user_data argument that is
259*bb4ee6a4SAndroid Build Coastguard Worker /// used to identify the result when returned in the iterator provided by `wait`.
260*bb4ee6a4SAndroid Build Coastguard Worker ///
261*bb4ee6a4SAndroid Build Coastguard Worker /// # Example polling an FD for readable status.
262*bb4ee6a4SAndroid Build Coastguard Worker ///
263*bb4ee6a4SAndroid Build Coastguard Worker /// ```no_run
264*bb4ee6a4SAndroid Build Coastguard Worker /// # use std::fs::File;
265*bb4ee6a4SAndroid Build Coastguard Worker /// # use std::os::unix::io::AsRawFd;
266*bb4ee6a4SAndroid Build Coastguard Worker /// # use std::path::Path;
267*bb4ee6a4SAndroid Build Coastguard Worker /// # use base::EventType;
268*bb4ee6a4SAndroid Build Coastguard Worker /// # use io_uring::URingContext;
269*bb4ee6a4SAndroid Build Coastguard Worker /// let f = File::open(Path::new("/dev/zero")).unwrap();
270*bb4ee6a4SAndroid Build Coastguard Worker /// let uring = URingContext::new(16, None).unwrap();
271*bb4ee6a4SAndroid Build Coastguard Worker /// uring
272*bb4ee6a4SAndroid Build Coastguard Worker /// .add_poll_fd(f.as_raw_fd(), EventType::Read, 454)
273*bb4ee6a4SAndroid Build Coastguard Worker /// .unwrap();
274*bb4ee6a4SAndroid Build Coastguard Worker /// let (user_data, res) = uring.wait().unwrap().next().unwrap();
275*bb4ee6a4SAndroid Build Coastguard Worker /// assert_eq!(user_data, 454 as io_uring::UserData);
276*bb4ee6a4SAndroid Build Coastguard Worker /// assert_eq!(res.unwrap(), 1 as u32);
277*bb4ee6a4SAndroid Build Coastguard Worker /// ```
278*bb4ee6a4SAndroid Build Coastguard Worker pub struct URingContext {
279*bb4ee6a4SAndroid Build Coastguard Worker ring_file: File, // Holds the io_uring context FD returned from io_uring_setup.
280*bb4ee6a4SAndroid Build Coastguard Worker pub submit_ring: Mutex<SubmitQueue>,
281*bb4ee6a4SAndroid Build Coastguard Worker pub complete_ring: CompleteQueueState,
282*bb4ee6a4SAndroid Build Coastguard Worker }
283*bb4ee6a4SAndroid Build Coastguard Worker
284*bb4ee6a4SAndroid Build Coastguard Worker impl URingContext {
285*bb4ee6a4SAndroid Build Coastguard Worker /// Creates a `URingContext` where the underlying uring has a space for `num_entries`
286*bb4ee6a4SAndroid Build Coastguard Worker /// simultaneous operations. If `allowlist` is given, all operations other
287*bb4ee6a4SAndroid Build Coastguard Worker /// than those explicitly permitted by `allowlist` are prohibited.
new(num_entries: usize, allowlist: Option<&URingAllowlist>) -> Result<URingContext>288*bb4ee6a4SAndroid Build Coastguard Worker pub fn new(num_entries: usize, allowlist: Option<&URingAllowlist>) -> Result<URingContext> {
289*bb4ee6a4SAndroid Build Coastguard Worker let mut ring_params = io_uring_params::default();
290*bb4ee6a4SAndroid Build Coastguard Worker if allowlist.is_some() {
291*bb4ee6a4SAndroid Build Coastguard Worker // To register restrictions, a uring must start in a disabled state.
292*bb4ee6a4SAndroid Build Coastguard Worker ring_params.flags |= IORING_SETUP_R_DISABLED;
293*bb4ee6a4SAndroid Build Coastguard Worker }
294*bb4ee6a4SAndroid Build Coastguard Worker
295*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
296*bb4ee6a4SAndroid Build Coastguard Worker // The below unsafe block isolates the creation of the URingContext. Each step on it's own
297*bb4ee6a4SAndroid Build Coastguard Worker // is unsafe. Using the uring FD for the mapping and the offsets returned by the kernel for
298*bb4ee6a4SAndroid Build Coastguard Worker // base addresses maintains safety guarantees assuming the kernel API guarantees are
299*bb4ee6a4SAndroid Build Coastguard Worker // trusted.
300*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
301*bb4ee6a4SAndroid Build Coastguard Worker // Safe because the kernel is trusted to only modify params and `File` is created with
302*bb4ee6a4SAndroid Build Coastguard Worker // an FD that it takes complete ownership of.
303*bb4ee6a4SAndroid Build Coastguard Worker let fd = io_uring_setup(num_entries, &ring_params).map_err(Error::Setup)?;
304*bb4ee6a4SAndroid Build Coastguard Worker let ring_file = File::from_raw_fd(fd);
305*bb4ee6a4SAndroid Build Coastguard Worker
306*bb4ee6a4SAndroid Build Coastguard Worker // Register the restrictions if it's given
307*bb4ee6a4SAndroid Build Coastguard Worker if let Some(restrictions) = allowlist {
308*bb4ee6a4SAndroid Build Coastguard Worker // safe because IORING_REGISTER_RESTRICTIONS does not modify the memory and
309*bb4ee6a4SAndroid Build Coastguard Worker // `restrictions` contains a valid pointer and length.
310*bb4ee6a4SAndroid Build Coastguard Worker io_uring_register(
311*bb4ee6a4SAndroid Build Coastguard Worker fd,
312*bb4ee6a4SAndroid Build Coastguard Worker IORING_REGISTER_RESTRICTIONS,
313*bb4ee6a4SAndroid Build Coastguard Worker restrictions.0.as_ptr() as *const c_void,
314*bb4ee6a4SAndroid Build Coastguard Worker restrictions.0.len() as u32,
315*bb4ee6a4SAndroid Build Coastguard Worker )
316*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::RingRegister)?;
317*bb4ee6a4SAndroid Build Coastguard Worker
318*bb4ee6a4SAndroid Build Coastguard Worker // enables the URingContext since it was started in a disabled state.
319*bb4ee6a4SAndroid Build Coastguard Worker // safe because IORING_REGISTER_RESTRICTIONS does not modify the memory
320*bb4ee6a4SAndroid Build Coastguard Worker io_uring_register(fd, IORING_REGISTER_ENABLE_RINGS, null::<c_void>(), 0)
321*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::RingRegister)?;
322*bb4ee6a4SAndroid Build Coastguard Worker }
323*bb4ee6a4SAndroid Build Coastguard Worker
324*bb4ee6a4SAndroid Build Coastguard Worker // Mmap the submit and completion queues.
325*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we trust the kernel to set valid sizes in `io_uring_setup` and any error
326*bb4ee6a4SAndroid Build Coastguard Worker // is checked.
327*bb4ee6a4SAndroid Build Coastguard Worker let submit_ring = SubmitQueueState::new(
328*bb4ee6a4SAndroid Build Coastguard Worker MemoryMappingBuilder::new(
329*bb4ee6a4SAndroid Build Coastguard Worker ring_params.sq_off.array as usize
330*bb4ee6a4SAndroid Build Coastguard Worker + ring_params.sq_entries as usize * std::mem::size_of::<u32>(),
331*bb4ee6a4SAndroid Build Coastguard Worker )
332*bb4ee6a4SAndroid Build Coastguard Worker .from_file(&ring_file)
333*bb4ee6a4SAndroid Build Coastguard Worker .offset(u64::from(IORING_OFF_SQ_RING))
334*bb4ee6a4SAndroid Build Coastguard Worker .protection(Protection::read_write())
335*bb4ee6a4SAndroid Build Coastguard Worker .populate()
336*bb4ee6a4SAndroid Build Coastguard Worker .build()
337*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::MappingSubmitRing)?,
338*bb4ee6a4SAndroid Build Coastguard Worker &ring_params,
339*bb4ee6a4SAndroid Build Coastguard Worker );
340*bb4ee6a4SAndroid Build Coastguard Worker
341*bb4ee6a4SAndroid Build Coastguard Worker let num_sqe = ring_params.sq_entries as usize;
342*bb4ee6a4SAndroid Build Coastguard Worker let submit_queue_entries = SubmitQueueEntries {
343*bb4ee6a4SAndroid Build Coastguard Worker mmap: MemoryMappingBuilder::new(
344*bb4ee6a4SAndroid Build Coastguard Worker ring_params.sq_entries as usize * std::mem::size_of::<io_uring_sqe>(),
345*bb4ee6a4SAndroid Build Coastguard Worker )
346*bb4ee6a4SAndroid Build Coastguard Worker .from_file(&ring_file)
347*bb4ee6a4SAndroid Build Coastguard Worker .offset(u64::from(IORING_OFF_SQES))
348*bb4ee6a4SAndroid Build Coastguard Worker .protection(Protection::read_write())
349*bb4ee6a4SAndroid Build Coastguard Worker .populate()
350*bb4ee6a4SAndroid Build Coastguard Worker .build()
351*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::MappingSubmitEntries)?,
352*bb4ee6a4SAndroid Build Coastguard Worker len: num_sqe,
353*bb4ee6a4SAndroid Build Coastguard Worker };
354*bb4ee6a4SAndroid Build Coastguard Worker
355*bb4ee6a4SAndroid Build Coastguard Worker let complete_ring = CompleteQueueState::new(
356*bb4ee6a4SAndroid Build Coastguard Worker MemoryMappingBuilder::new(
357*bb4ee6a4SAndroid Build Coastguard Worker ring_params.cq_off.cqes as usize
358*bb4ee6a4SAndroid Build Coastguard Worker + ring_params.cq_entries as usize * std::mem::size_of::<io_uring_cqe>(),
359*bb4ee6a4SAndroid Build Coastguard Worker )
360*bb4ee6a4SAndroid Build Coastguard Worker .from_file(&ring_file)
361*bb4ee6a4SAndroid Build Coastguard Worker .offset(u64::from(IORING_OFF_CQ_RING))
362*bb4ee6a4SAndroid Build Coastguard Worker .protection(Protection::read_write())
363*bb4ee6a4SAndroid Build Coastguard Worker .populate()
364*bb4ee6a4SAndroid Build Coastguard Worker .build()
365*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::MappingCompleteRing)?,
366*bb4ee6a4SAndroid Build Coastguard Worker &ring_params,
367*bb4ee6a4SAndroid Build Coastguard Worker );
368*bb4ee6a4SAndroid Build Coastguard Worker
369*bb4ee6a4SAndroid Build Coastguard Worker Ok(URingContext {
370*bb4ee6a4SAndroid Build Coastguard Worker ring_file,
371*bb4ee6a4SAndroid Build Coastguard Worker submit_ring: Mutex::new(SubmitQueue {
372*bb4ee6a4SAndroid Build Coastguard Worker submit_ring,
373*bb4ee6a4SAndroid Build Coastguard Worker submit_queue_entries,
374*bb4ee6a4SAndroid Build Coastguard Worker submitting: 0,
375*bb4ee6a4SAndroid Build Coastguard Worker added: 0,
376*bb4ee6a4SAndroid Build Coastguard Worker num_sqes: ring_params.sq_entries as usize,
377*bb4ee6a4SAndroid Build Coastguard Worker }),
378*bb4ee6a4SAndroid Build Coastguard Worker complete_ring,
379*bb4ee6a4SAndroid Build Coastguard Worker })
380*bb4ee6a4SAndroid Build Coastguard Worker }
381*bb4ee6a4SAndroid Build Coastguard Worker }
382*bb4ee6a4SAndroid Build Coastguard Worker
383*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
384*bb4ee6a4SAndroid Build Coastguard Worker /// See 'writev' but accepts an iterator instead of a vector if there isn't already a vector in
385*bb4ee6a4SAndroid Build Coastguard Worker /// existence.
add_writev_iter<I>( &self, iovecs: I, fd: RawFd, offset: Option<u64>, user_data: UserData, ) -> Result<()> where I: Iterator<Item = libc::iovec>,386*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe fn add_writev_iter<I>(
387*bb4ee6a4SAndroid Build Coastguard Worker &self,
388*bb4ee6a4SAndroid Build Coastguard Worker iovecs: I,
389*bb4ee6a4SAndroid Build Coastguard Worker fd: RawFd,
390*bb4ee6a4SAndroid Build Coastguard Worker offset: Option<u64>,
391*bb4ee6a4SAndroid Build Coastguard Worker user_data: UserData,
392*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()>
393*bb4ee6a4SAndroid Build Coastguard Worker where
394*bb4ee6a4SAndroid Build Coastguard Worker I: Iterator<Item = libc::iovec>,
395*bb4ee6a4SAndroid Build Coastguard Worker {
396*bb4ee6a4SAndroid Build Coastguard Worker self.add_writev(
397*bb4ee6a4SAndroid Build Coastguard Worker Pin::from(
398*bb4ee6a4SAndroid Build Coastguard Worker // Safe because the caller is required to guarantee that the memory pointed to by
399*bb4ee6a4SAndroid Build Coastguard Worker // `iovecs` lives until the transaction is complete and the completion has been
400*bb4ee6a4SAndroid Build Coastguard Worker // returned from `wait()`.
401*bb4ee6a4SAndroid Build Coastguard Worker iovecs
402*bb4ee6a4SAndroid Build Coastguard Worker .map(|iov| IoBufMut::from_raw_parts(iov.iov_base as *mut u8, iov.iov_len))
403*bb4ee6a4SAndroid Build Coastguard Worker .collect::<Vec<_>>()
404*bb4ee6a4SAndroid Build Coastguard Worker .into_boxed_slice(),
405*bb4ee6a4SAndroid Build Coastguard Worker ),
406*bb4ee6a4SAndroid Build Coastguard Worker fd,
407*bb4ee6a4SAndroid Build Coastguard Worker offset,
408*bb4ee6a4SAndroid Build Coastguard Worker user_data,
409*bb4ee6a4SAndroid Build Coastguard Worker )
410*bb4ee6a4SAndroid Build Coastguard Worker }
411*bb4ee6a4SAndroid Build Coastguard Worker
412*bb4ee6a4SAndroid Build Coastguard Worker /// Asynchronously writes to `fd` from the addresses given in `iovecs`.
413*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
414*bb4ee6a4SAndroid Build Coastguard Worker /// `add_writev` will write to the address given by `iovecs`. This is only safe if the caller
415*bb4ee6a4SAndroid Build Coastguard Worker /// guarantees there are no other references to that memory and that the memory lives until the
416*bb4ee6a4SAndroid Build Coastguard Worker /// transaction is complete and that completion has been returned from the `wait` function. In
417*bb4ee6a4SAndroid Build Coastguard Worker /// addition there must not be any mutable references to the data pointed to by `iovecs` until
418*bb4ee6a4SAndroid Build Coastguard Worker /// the operation completes. Ensure that the fd remains open until the op completes as well.
419*bb4ee6a4SAndroid Build Coastguard Worker /// The iovecs reference must be kept alive until the op returns.
add_writev( &self, iovecs: Pin<Box<[IoBufMut<'static>]>>, fd: RawFd, offset: Option<u64>, user_data: UserData, ) -> Result<()>420*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe fn add_writev(
421*bb4ee6a4SAndroid Build Coastguard Worker &self,
422*bb4ee6a4SAndroid Build Coastguard Worker iovecs: Pin<Box<[IoBufMut<'static>]>>,
423*bb4ee6a4SAndroid Build Coastguard Worker fd: RawFd,
424*bb4ee6a4SAndroid Build Coastguard Worker offset: Option<u64>,
425*bb4ee6a4SAndroid Build Coastguard Worker user_data: UserData,
426*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> {
427*bb4ee6a4SAndroid Build Coastguard Worker self.submit_ring.lock().prep_next_sqe(|sqe| {
428*bb4ee6a4SAndroid Build Coastguard Worker sqe.opcode = io_uring_op_IORING_OP_WRITEV as u8;
429*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_addr(iovecs.as_ptr() as *const _ as *const libc::c_void as u64);
430*bb4ee6a4SAndroid Build Coastguard Worker sqe.len = iovecs.len() as u32;
431*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_off(file_offset_to_raw_offset(offset));
432*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_buf_index(0);
433*bb4ee6a4SAndroid Build Coastguard Worker sqe.ioprio = 0;
434*bb4ee6a4SAndroid Build Coastguard Worker sqe.user_data = user_data;
435*bb4ee6a4SAndroid Build Coastguard Worker sqe.flags = 0;
436*bb4ee6a4SAndroid Build Coastguard Worker sqe.fd = fd;
437*bb4ee6a4SAndroid Build Coastguard Worker })?;
438*bb4ee6a4SAndroid Build Coastguard Worker self.complete_ring.add_op_data(user_data, iovecs);
439*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
440*bb4ee6a4SAndroid Build Coastguard Worker }
441*bb4ee6a4SAndroid Build Coastguard Worker
442*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
443*bb4ee6a4SAndroid Build Coastguard Worker /// See 'readv' but accepts an iterator instead of a vector if there isn't already a vector in
444*bb4ee6a4SAndroid Build Coastguard Worker /// existence.
add_readv_iter<I>( &self, iovecs: I, fd: RawFd, offset: Option<u64>, user_data: UserData, ) -> Result<()> where I: Iterator<Item = libc::iovec>,445*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe fn add_readv_iter<I>(
446*bb4ee6a4SAndroid Build Coastguard Worker &self,
447*bb4ee6a4SAndroid Build Coastguard Worker iovecs: I,
448*bb4ee6a4SAndroid Build Coastguard Worker fd: RawFd,
449*bb4ee6a4SAndroid Build Coastguard Worker offset: Option<u64>,
450*bb4ee6a4SAndroid Build Coastguard Worker user_data: UserData,
451*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()>
452*bb4ee6a4SAndroid Build Coastguard Worker where
453*bb4ee6a4SAndroid Build Coastguard Worker I: Iterator<Item = libc::iovec>,
454*bb4ee6a4SAndroid Build Coastguard Worker {
455*bb4ee6a4SAndroid Build Coastguard Worker self.add_readv(
456*bb4ee6a4SAndroid Build Coastguard Worker Pin::from(
457*bb4ee6a4SAndroid Build Coastguard Worker // Safe because the caller is required to guarantee that the memory pointed to by
458*bb4ee6a4SAndroid Build Coastguard Worker // `iovecs` lives until the transaction is complete and the completion has been
459*bb4ee6a4SAndroid Build Coastguard Worker // returned from `wait()`.
460*bb4ee6a4SAndroid Build Coastguard Worker iovecs
461*bb4ee6a4SAndroid Build Coastguard Worker .map(|iov| IoBufMut::from_raw_parts(iov.iov_base as *mut u8, iov.iov_len))
462*bb4ee6a4SAndroid Build Coastguard Worker .collect::<Vec<_>>()
463*bb4ee6a4SAndroid Build Coastguard Worker .into_boxed_slice(),
464*bb4ee6a4SAndroid Build Coastguard Worker ),
465*bb4ee6a4SAndroid Build Coastguard Worker fd,
466*bb4ee6a4SAndroid Build Coastguard Worker offset,
467*bb4ee6a4SAndroid Build Coastguard Worker user_data,
468*bb4ee6a4SAndroid Build Coastguard Worker )
469*bb4ee6a4SAndroid Build Coastguard Worker }
470*bb4ee6a4SAndroid Build Coastguard Worker
471*bb4ee6a4SAndroid Build Coastguard Worker /// Asynchronously reads from `fd` to the addresses given in `iovecs`.
472*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
473*bb4ee6a4SAndroid Build Coastguard Worker /// `add_readv` will write to the address given by `iovecs`. This is only safe if the caller
474*bb4ee6a4SAndroid Build Coastguard Worker /// guarantees there are no other references to that memory and that the memory lives until the
475*bb4ee6a4SAndroid Build Coastguard Worker /// transaction is complete and that completion has been returned from the `wait` function. In
476*bb4ee6a4SAndroid Build Coastguard Worker /// addition there must not be any references to the data pointed to by `iovecs` until the
477*bb4ee6a4SAndroid Build Coastguard Worker /// operation completes. Ensure that the fd remains open until the op completes as well.
478*bb4ee6a4SAndroid Build Coastguard Worker /// The iovecs reference must be kept alive until the op returns.
add_readv( &self, iovecs: Pin<Box<[IoBufMut<'static>]>>, fd: RawFd, offset: Option<u64>, user_data: UserData, ) -> Result<()>479*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe fn add_readv(
480*bb4ee6a4SAndroid Build Coastguard Worker &self,
481*bb4ee6a4SAndroid Build Coastguard Worker iovecs: Pin<Box<[IoBufMut<'static>]>>,
482*bb4ee6a4SAndroid Build Coastguard Worker fd: RawFd,
483*bb4ee6a4SAndroid Build Coastguard Worker offset: Option<u64>,
484*bb4ee6a4SAndroid Build Coastguard Worker user_data: UserData,
485*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> {
486*bb4ee6a4SAndroid Build Coastguard Worker self.submit_ring.lock().prep_next_sqe(|sqe| {
487*bb4ee6a4SAndroid Build Coastguard Worker sqe.opcode = io_uring_op_IORING_OP_READV as u8;
488*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_addr(iovecs.as_ptr() as *const _ as *const libc::c_void as u64);
489*bb4ee6a4SAndroid Build Coastguard Worker sqe.len = iovecs.len() as u32;
490*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_off(file_offset_to_raw_offset(offset));
491*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_buf_index(0);
492*bb4ee6a4SAndroid Build Coastguard Worker sqe.ioprio = 0;
493*bb4ee6a4SAndroid Build Coastguard Worker sqe.user_data = user_data;
494*bb4ee6a4SAndroid Build Coastguard Worker sqe.flags = 0;
495*bb4ee6a4SAndroid Build Coastguard Worker sqe.fd = fd;
496*bb4ee6a4SAndroid Build Coastguard Worker })?;
497*bb4ee6a4SAndroid Build Coastguard Worker self.complete_ring.add_op_data(user_data, iovecs);
498*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
499*bb4ee6a4SAndroid Build Coastguard Worker }
500*bb4ee6a4SAndroid Build Coastguard Worker
501*bb4ee6a4SAndroid Build Coastguard Worker /// Add a no-op operation that doesn't perform any IO. Useful for testing the performance of the
502*bb4ee6a4SAndroid Build Coastguard Worker /// io_uring itself and for waking up a thread that's blocked inside a wait() call.
add_nop(&self, user_data: UserData) -> Result<()>503*bb4ee6a4SAndroid Build Coastguard Worker pub fn add_nop(&self, user_data: UserData) -> Result<()> {
504*bb4ee6a4SAndroid Build Coastguard Worker self.submit_ring.lock().prep_next_sqe(|sqe| {
505*bb4ee6a4SAndroid Build Coastguard Worker sqe.opcode = io_uring_op_IORING_OP_NOP as u8;
506*bb4ee6a4SAndroid Build Coastguard Worker sqe.fd = -1;
507*bb4ee6a4SAndroid Build Coastguard Worker sqe.user_data = user_data;
508*bb4ee6a4SAndroid Build Coastguard Worker
509*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_addr(0);
510*bb4ee6a4SAndroid Build Coastguard Worker sqe.len = 0;
511*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_off(0);
512*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_buf_index(0);
513*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_rw_flags(0);
514*bb4ee6a4SAndroid Build Coastguard Worker sqe.ioprio = 0;
515*bb4ee6a4SAndroid Build Coastguard Worker sqe.flags = 0;
516*bb4ee6a4SAndroid Build Coastguard Worker })
517*bb4ee6a4SAndroid Build Coastguard Worker }
518*bb4ee6a4SAndroid Build Coastguard Worker
519*bb4ee6a4SAndroid Build Coastguard Worker /// Syncs all completed operations, the ordering with in-flight async ops is not
520*bb4ee6a4SAndroid Build Coastguard Worker /// defined.
add_fsync(&self, fd: RawFd, user_data: UserData) -> Result<()>521*bb4ee6a4SAndroid Build Coastguard Worker pub fn add_fsync(&self, fd: RawFd, user_data: UserData) -> Result<()> {
522*bb4ee6a4SAndroid Build Coastguard Worker self.submit_ring.lock().prep_next_sqe(|sqe| {
523*bb4ee6a4SAndroid Build Coastguard Worker sqe.opcode = io_uring_op_IORING_OP_FSYNC as u8;
524*bb4ee6a4SAndroid Build Coastguard Worker sqe.fd = fd;
525*bb4ee6a4SAndroid Build Coastguard Worker sqe.user_data = user_data;
526*bb4ee6a4SAndroid Build Coastguard Worker
527*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_addr(0);
528*bb4ee6a4SAndroid Build Coastguard Worker sqe.len = 0;
529*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_off(0);
530*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_buf_index(0);
531*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_rw_flags(0);
532*bb4ee6a4SAndroid Build Coastguard Worker sqe.ioprio = 0;
533*bb4ee6a4SAndroid Build Coastguard Worker sqe.flags = 0;
534*bb4ee6a4SAndroid Build Coastguard Worker })
535*bb4ee6a4SAndroid Build Coastguard Worker }
536*bb4ee6a4SAndroid Build Coastguard Worker
537*bb4ee6a4SAndroid Build Coastguard Worker /// See the usage of `fallocate`, this asynchronously performs the same operations.
add_fallocate( &self, fd: RawFd, offset: u64, len: u64, mode: u32, user_data: UserData, ) -> Result<()>538*bb4ee6a4SAndroid Build Coastguard Worker pub fn add_fallocate(
539*bb4ee6a4SAndroid Build Coastguard Worker &self,
540*bb4ee6a4SAndroid Build Coastguard Worker fd: RawFd,
541*bb4ee6a4SAndroid Build Coastguard Worker offset: u64,
542*bb4ee6a4SAndroid Build Coastguard Worker len: u64,
543*bb4ee6a4SAndroid Build Coastguard Worker mode: u32,
544*bb4ee6a4SAndroid Build Coastguard Worker user_data: UserData,
545*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> {
546*bb4ee6a4SAndroid Build Coastguard Worker // Note that len for fallocate in passed in the addr field of the sqe and the mode uses the
547*bb4ee6a4SAndroid Build Coastguard Worker // len field.
548*bb4ee6a4SAndroid Build Coastguard Worker self.submit_ring.lock().prep_next_sqe(|sqe| {
549*bb4ee6a4SAndroid Build Coastguard Worker sqe.opcode = io_uring_op_IORING_OP_FALLOCATE as u8;
550*bb4ee6a4SAndroid Build Coastguard Worker
551*bb4ee6a4SAndroid Build Coastguard Worker sqe.fd = fd;
552*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_addr(len);
553*bb4ee6a4SAndroid Build Coastguard Worker sqe.len = mode;
554*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_off(offset);
555*bb4ee6a4SAndroid Build Coastguard Worker sqe.user_data = user_data;
556*bb4ee6a4SAndroid Build Coastguard Worker
557*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_buf_index(0);
558*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_rw_flags(0);
559*bb4ee6a4SAndroid Build Coastguard Worker sqe.ioprio = 0;
560*bb4ee6a4SAndroid Build Coastguard Worker sqe.flags = 0;
561*bb4ee6a4SAndroid Build Coastguard Worker })
562*bb4ee6a4SAndroid Build Coastguard Worker }
563*bb4ee6a4SAndroid Build Coastguard Worker
564*bb4ee6a4SAndroid Build Coastguard Worker /// Adds an FD to be polled based on the given flags.
565*bb4ee6a4SAndroid Build Coastguard Worker /// The user must keep the FD open until the operation completion is returned from
566*bb4ee6a4SAndroid Build Coastguard Worker /// `wait`.
567*bb4ee6a4SAndroid Build Coastguard Worker /// Note that io_uring is always a one shot poll. After the fd is returned, it must be re-added
568*bb4ee6a4SAndroid Build Coastguard Worker /// to get future events.
add_poll_fd(&self, fd: RawFd, events: EventType, user_data: UserData) -> Result<()>569*bb4ee6a4SAndroid Build Coastguard Worker pub fn add_poll_fd(&self, fd: RawFd, events: EventType, user_data: UserData) -> Result<()> {
570*bb4ee6a4SAndroid Build Coastguard Worker self.submit_ring.lock().prep_next_sqe(|sqe| {
571*bb4ee6a4SAndroid Build Coastguard Worker sqe.opcode = io_uring_op_IORING_OP_POLL_ADD as u8;
572*bb4ee6a4SAndroid Build Coastguard Worker sqe.fd = fd;
573*bb4ee6a4SAndroid Build Coastguard Worker sqe.user_data = user_data;
574*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_poll_events(events.into());
575*bb4ee6a4SAndroid Build Coastguard Worker
576*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_addr(0);
577*bb4ee6a4SAndroid Build Coastguard Worker sqe.len = 0;
578*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_off(0);
579*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_buf_index(0);
580*bb4ee6a4SAndroid Build Coastguard Worker sqe.ioprio = 0;
581*bb4ee6a4SAndroid Build Coastguard Worker sqe.flags = 0;
582*bb4ee6a4SAndroid Build Coastguard Worker })
583*bb4ee6a4SAndroid Build Coastguard Worker }
584*bb4ee6a4SAndroid Build Coastguard Worker
585*bb4ee6a4SAndroid Build Coastguard Worker /// Removes an FD that was previously added with `add_poll_fd`.
remove_poll_fd(&self, fd: RawFd, events: EventType, user_data: UserData) -> Result<()>586*bb4ee6a4SAndroid Build Coastguard Worker pub fn remove_poll_fd(&self, fd: RawFd, events: EventType, user_data: UserData) -> Result<()> {
587*bb4ee6a4SAndroid Build Coastguard Worker self.submit_ring.lock().prep_next_sqe(|sqe| {
588*bb4ee6a4SAndroid Build Coastguard Worker sqe.opcode = io_uring_op_IORING_OP_POLL_REMOVE as u8;
589*bb4ee6a4SAndroid Build Coastguard Worker sqe.fd = fd;
590*bb4ee6a4SAndroid Build Coastguard Worker sqe.user_data = user_data;
591*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_poll_events(events.into());
592*bb4ee6a4SAndroid Build Coastguard Worker
593*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_addr(0);
594*bb4ee6a4SAndroid Build Coastguard Worker sqe.len = 0;
595*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_off(0);
596*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_buf_index(0);
597*bb4ee6a4SAndroid Build Coastguard Worker sqe.ioprio = 0;
598*bb4ee6a4SAndroid Build Coastguard Worker sqe.flags = 0;
599*bb4ee6a4SAndroid Build Coastguard Worker })
600*bb4ee6a4SAndroid Build Coastguard Worker }
601*bb4ee6a4SAndroid Build Coastguard Worker
602*bb4ee6a4SAndroid Build Coastguard Worker /// Attempt to cancel an already issued request. addr must contain the user_data field of the
603*bb4ee6a4SAndroid Build Coastguard Worker /// request that should be cancelled. The cancellation request will complete with one of the
604*bb4ee6a4SAndroid Build Coastguard Worker /// following results codes. If found, the res field of the cqe will contain 0. If not found,
605*bb4ee6a4SAndroid Build Coastguard Worker /// res will contain -ENOENT. If found and attempted cancelled, the res field will contain
606*bb4ee6a4SAndroid Build Coastguard Worker /// -EALREADY. In this case, the request may or may not terminate. In general, requests that
607*bb4ee6a4SAndroid Build Coastguard Worker /// are interruptible (like socket IO) will get cancelled, while disk IO requests cannot be
608*bb4ee6a4SAndroid Build Coastguard Worker /// cancelled if already started.
async_cancel(&self, addr: UserData, user_data: UserData) -> Result<()>609*bb4ee6a4SAndroid Build Coastguard Worker pub fn async_cancel(&self, addr: UserData, user_data: UserData) -> Result<()> {
610*bb4ee6a4SAndroid Build Coastguard Worker self.submit_ring.lock().prep_next_sqe(|sqe| {
611*bb4ee6a4SAndroid Build Coastguard Worker sqe.opcode = io_uring_op_IORING_OP_ASYNC_CANCEL as u8;
612*bb4ee6a4SAndroid Build Coastguard Worker sqe.user_data = user_data;
613*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_addr(addr);
614*bb4ee6a4SAndroid Build Coastguard Worker
615*bb4ee6a4SAndroid Build Coastguard Worker sqe.len = 0;
616*bb4ee6a4SAndroid Build Coastguard Worker sqe.fd = 0;
617*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_off(0);
618*bb4ee6a4SAndroid Build Coastguard Worker sqe.set_buf_index(0);
619*bb4ee6a4SAndroid Build Coastguard Worker sqe.ioprio = 0;
620*bb4ee6a4SAndroid Build Coastguard Worker sqe.flags = 0;
621*bb4ee6a4SAndroid Build Coastguard Worker })
622*bb4ee6a4SAndroid Build Coastguard Worker }
623*bb4ee6a4SAndroid Build Coastguard Worker
624*bb4ee6a4SAndroid Build Coastguard Worker // Calls io_uring_enter, submitting any new sqes that have been added to the submit queue and
625*bb4ee6a4SAndroid Build Coastguard Worker // waiting for `wait_nr` operations to complete.
enter(&self, wait_nr: u64) -> Result<()>626*bb4ee6a4SAndroid Build Coastguard Worker fn enter(&self, wait_nr: u64) -> Result<()> {
627*bb4ee6a4SAndroid Build Coastguard Worker let added = self.submit_ring.lock().prepare_submit();
628*bb4ee6a4SAndroid Build Coastguard Worker if added == 0 && wait_nr == 0 {
629*bb4ee6a4SAndroid Build Coastguard Worker return Ok(());
630*bb4ee6a4SAndroid Build Coastguard Worker }
631*bb4ee6a4SAndroid Build Coastguard Worker
632*bb4ee6a4SAndroid Build Coastguard Worker let flags = if wait_nr > 0 {
633*bb4ee6a4SAndroid Build Coastguard Worker IORING_ENTER_GETEVENTS
634*bb4ee6a4SAndroid Build Coastguard Worker } else {
635*bb4ee6a4SAndroid Build Coastguard Worker 0
636*bb4ee6a4SAndroid Build Coastguard Worker };
637*bb4ee6a4SAndroid Build Coastguard Worker let res =
638*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
639*bb4ee6a4SAndroid Build Coastguard Worker // Safe because the only memory modified is in the completion queue.
640*bb4ee6a4SAndroid Build Coastguard Worker unsafe { io_uring_enter(self.ring_file.as_raw_fd(), added as u64, wait_nr, flags) };
641*bb4ee6a4SAndroid Build Coastguard Worker
642*bb4ee6a4SAndroid Build Coastguard Worker // An EINTR means we did successfully submit the events.
643*bb4ee6a4SAndroid Build Coastguard Worker if res.is_ok() || res == Err(libc::EINTR) {
644*bb4ee6a4SAndroid Build Coastguard Worker self.submit_ring.lock().complete_submit(added);
645*bb4ee6a4SAndroid Build Coastguard Worker } else {
646*bb4ee6a4SAndroid Build Coastguard Worker self.submit_ring.lock().fail_submit(added);
647*bb4ee6a4SAndroid Build Coastguard Worker }
648*bb4ee6a4SAndroid Build Coastguard Worker
649*bb4ee6a4SAndroid Build Coastguard Worker match res {
650*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) => Ok(()),
651*bb4ee6a4SAndroid Build Coastguard Worker // EBUSY means that some completed events need to be processed before more can
652*bb4ee6a4SAndroid Build Coastguard Worker // be submitted, so wait for some sqes to finish without submitting new ones.
653*bb4ee6a4SAndroid Build Coastguard Worker // EINTR means we were interrupted while waiting, so start waiting again.
654*bb4ee6a4SAndroid Build Coastguard Worker Err(libc::EBUSY) | Err(libc::EINTR) if wait_nr != 0 => {
655*bb4ee6a4SAndroid Build Coastguard Worker loop {
656*bb4ee6a4SAndroid Build Coastguard Worker let res =
657*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
658*bb4ee6a4SAndroid Build Coastguard Worker // Safe because the only memory modified is in the completion queue.
659*bb4ee6a4SAndroid Build Coastguard Worker unsafe { io_uring_enter(self.ring_file.as_raw_fd(), 0, wait_nr, flags) };
660*bb4ee6a4SAndroid Build Coastguard Worker if res != Err(libc::EINTR) {
661*bb4ee6a4SAndroid Build Coastguard Worker return res.map_err(Error::RingEnter);
662*bb4ee6a4SAndroid Build Coastguard Worker }
663*bb4ee6a4SAndroid Build Coastguard Worker }
664*bb4ee6a4SAndroid Build Coastguard Worker }
665*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => Err(Error::RingEnter(e)),
666*bb4ee6a4SAndroid Build Coastguard Worker }
667*bb4ee6a4SAndroid Build Coastguard Worker }
668*bb4ee6a4SAndroid Build Coastguard Worker
669*bb4ee6a4SAndroid Build Coastguard Worker /// Sends operations added with the `add_*` functions to the kernel.
submit(&self) -> Result<()>670*bb4ee6a4SAndroid Build Coastguard Worker pub fn submit(&self) -> Result<()> {
671*bb4ee6a4SAndroid Build Coastguard Worker self.enter(0)
672*bb4ee6a4SAndroid Build Coastguard Worker }
673*bb4ee6a4SAndroid Build Coastguard Worker
674*bb4ee6a4SAndroid Build Coastguard Worker /// Sends operations added with the `add_*` functions to the kernel and return an iterator to
675*bb4ee6a4SAndroid Build Coastguard Worker /// any completed operations. `wait` blocks until at least one completion is ready. If
676*bb4ee6a4SAndroid Build Coastguard Worker /// called without any new events added, this simply waits for any existing events to
677*bb4ee6a4SAndroid Build Coastguard Worker /// complete and returns as soon an one or more is ready.
wait(&self) -> Result<impl Iterator<Item = (UserData, std::io::Result<u32>)> + '_>678*bb4ee6a4SAndroid Build Coastguard Worker pub fn wait(&self) -> Result<impl Iterator<Item = (UserData, std::io::Result<u32>)> + '_> {
679*bb4ee6a4SAndroid Build Coastguard Worker // We only want to wait for events if there aren't already events in the completion queue.
680*bb4ee6a4SAndroid Build Coastguard Worker let wait_nr = if self.complete_ring.num_ready() > 0 {
681*bb4ee6a4SAndroid Build Coastguard Worker 0
682*bb4ee6a4SAndroid Build Coastguard Worker } else {
683*bb4ee6a4SAndroid Build Coastguard Worker 1
684*bb4ee6a4SAndroid Build Coastguard Worker };
685*bb4ee6a4SAndroid Build Coastguard Worker
686*bb4ee6a4SAndroid Build Coastguard Worker // The CompletionQueue will iterate all completed ops.
687*bb4ee6a4SAndroid Build Coastguard Worker match self.enter(wait_nr) {
688*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) => Ok(&self.complete_ring),
689*bb4ee6a4SAndroid Build Coastguard Worker // If we cannot submit any more entries then we need to pull stuff out of the completion
690*bb4ee6a4SAndroid Build Coastguard Worker // ring, so just return the completion ring. This can only happen when `wait_nr` is 0 so
691*bb4ee6a4SAndroid Build Coastguard Worker // we know there are already entries in the completion queue.
692*bb4ee6a4SAndroid Build Coastguard Worker Err(Error::RingEnter(libc::EBUSY)) => Ok(&self.complete_ring),
693*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => Err(e),
694*bb4ee6a4SAndroid Build Coastguard Worker }
695*bb4ee6a4SAndroid Build Coastguard Worker }
696*bb4ee6a4SAndroid Build Coastguard Worker }
697*bb4ee6a4SAndroid Build Coastguard Worker
698*bb4ee6a4SAndroid Build Coastguard Worker impl AsRawFd for URingContext {
as_raw_fd(&self) -> RawFd699*bb4ee6a4SAndroid Build Coastguard Worker fn as_raw_fd(&self) -> RawFd {
700*bb4ee6a4SAndroid Build Coastguard Worker self.ring_file.as_raw_fd()
701*bb4ee6a4SAndroid Build Coastguard Worker }
702*bb4ee6a4SAndroid Build Coastguard Worker }
703*bb4ee6a4SAndroid Build Coastguard Worker
704*bb4ee6a4SAndroid Build Coastguard Worker impl AsRawDescriptor for URingContext {
as_raw_descriptor(&self) -> RawDescriptor705*bb4ee6a4SAndroid Build Coastguard Worker fn as_raw_descriptor(&self) -> RawDescriptor {
706*bb4ee6a4SAndroid Build Coastguard Worker self.ring_file.as_raw_descriptor()
707*bb4ee6a4SAndroid Build Coastguard Worker }
708*bb4ee6a4SAndroid Build Coastguard Worker }
709*bb4ee6a4SAndroid Build Coastguard Worker
710*bb4ee6a4SAndroid Build Coastguard Worker struct SubmitQueueEntries {
711*bb4ee6a4SAndroid Build Coastguard Worker mmap: MemoryMapping,
712*bb4ee6a4SAndroid Build Coastguard Worker len: usize,
713*bb4ee6a4SAndroid Build Coastguard Worker }
714*bb4ee6a4SAndroid Build Coastguard Worker
715*bb4ee6a4SAndroid Build Coastguard Worker impl SubmitQueueEntries {
get_mut(&mut self, index: usize) -> Option<&mut io_uring_sqe>716*bb4ee6a4SAndroid Build Coastguard Worker fn get_mut(&mut self, index: usize) -> Option<&mut io_uring_sqe> {
717*bb4ee6a4SAndroid Build Coastguard Worker if index >= self.len {
718*bb4ee6a4SAndroid Build Coastguard Worker return None;
719*bb4ee6a4SAndroid Build Coastguard Worker }
720*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
721*bb4ee6a4SAndroid Build Coastguard Worker // Safe because the mut borrow of self resticts to one mutable reference at a time and
722*bb4ee6a4SAndroid Build Coastguard Worker // we trust that the kernel has returned enough memory in io_uring_setup and mmap.
723*bb4ee6a4SAndroid Build Coastguard Worker let mut_ref = unsafe { &mut *(self.mmap.as_ptr() as *mut io_uring_sqe).add(index) };
724*bb4ee6a4SAndroid Build Coastguard Worker // Clear any state.
725*bb4ee6a4SAndroid Build Coastguard Worker *mut_ref = io_uring_sqe::default();
726*bb4ee6a4SAndroid Build Coastguard Worker Some(mut_ref)
727*bb4ee6a4SAndroid Build Coastguard Worker }
728*bb4ee6a4SAndroid Build Coastguard Worker }
729*bb4ee6a4SAndroid Build Coastguard Worker
730*bb4ee6a4SAndroid Build Coastguard Worker struct SubmitQueueState {
731*bb4ee6a4SAndroid Build Coastguard Worker _mmap: MemoryMapping,
732*bb4ee6a4SAndroid Build Coastguard Worker pointers: QueuePointers,
733*bb4ee6a4SAndroid Build Coastguard Worker ring_mask: u32,
734*bb4ee6a4SAndroid Build Coastguard Worker array: AtomicPtr<u32>,
735*bb4ee6a4SAndroid Build Coastguard Worker }
736*bb4ee6a4SAndroid Build Coastguard Worker
737*bb4ee6a4SAndroid Build Coastguard Worker impl SubmitQueueState {
738*bb4ee6a4SAndroid Build Coastguard Worker // # Safety
739*bb4ee6a4SAndroid Build Coastguard Worker // Safe iff `mmap` is created by mapping from a uring FD at the SQ_RING offset and params is
740*bb4ee6a4SAndroid Build Coastguard Worker // the params struct passed to io_uring_setup.
new(mmap: MemoryMapping, params: &io_uring_params) -> SubmitQueueState741*bb4ee6a4SAndroid Build Coastguard Worker unsafe fn new(mmap: MemoryMapping, params: &io_uring_params) -> SubmitQueueState {
742*bb4ee6a4SAndroid Build Coastguard Worker let ptr = mmap.as_ptr();
743*bb4ee6a4SAndroid Build Coastguard Worker // Transmutes are safe because a u32 is atomic on all supported architectures and the
744*bb4ee6a4SAndroid Build Coastguard Worker // pointer will live until after self is dropped because the mmap is owned.
745*bb4ee6a4SAndroid Build Coastguard Worker let head = ptr.add(params.sq_off.head as usize) as *const AtomicU32;
746*bb4ee6a4SAndroid Build Coastguard Worker let tail = ptr.add(params.sq_off.tail as usize) as *const AtomicU32;
747*bb4ee6a4SAndroid Build Coastguard Worker // This offset is guaranteed to be within the mmap so unwrap the result.
748*bb4ee6a4SAndroid Build Coastguard Worker let ring_mask = mmap.read_obj(params.sq_off.ring_mask as usize).unwrap();
749*bb4ee6a4SAndroid Build Coastguard Worker let array = AtomicPtr::new(ptr.add(params.sq_off.array as usize) as *mut u32);
750*bb4ee6a4SAndroid Build Coastguard Worker SubmitQueueState {
751*bb4ee6a4SAndroid Build Coastguard Worker _mmap: mmap,
752*bb4ee6a4SAndroid Build Coastguard Worker pointers: QueuePointers { head, tail },
753*bb4ee6a4SAndroid Build Coastguard Worker ring_mask,
754*bb4ee6a4SAndroid Build Coastguard Worker array,
755*bb4ee6a4SAndroid Build Coastguard Worker }
756*bb4ee6a4SAndroid Build Coastguard Worker }
757*bb4ee6a4SAndroid Build Coastguard Worker
758*bb4ee6a4SAndroid Build Coastguard Worker // Sets the kernel's array entry at the given `index` to `value`.
set_array_entry(&self, index: usize, value: u32)759*bb4ee6a4SAndroid Build Coastguard Worker fn set_array_entry(&self, index: usize, value: u32) {
760*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
761*bb4ee6a4SAndroid Build Coastguard Worker // Safe because self being constructed from the correct mmap guaratees that the memory is
762*bb4ee6a4SAndroid Build Coastguard Worker // valid to written.
763*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
764*bb4ee6a4SAndroid Build Coastguard Worker std::ptr::write_volatile(self.array.load(Ordering::Relaxed).add(index), value);
765*bb4ee6a4SAndroid Build Coastguard Worker }
766*bb4ee6a4SAndroid Build Coastguard Worker }
767*bb4ee6a4SAndroid Build Coastguard Worker }
768*bb4ee6a4SAndroid Build Coastguard Worker
769*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Default)]
770*bb4ee6a4SAndroid Build Coastguard Worker struct CompleteQueueData {
771*bb4ee6a4SAndroid Build Coastguard Worker //For ops that pass in arrays of iovecs, they need to be valid for the duration of the
772*bb4ee6a4SAndroid Build Coastguard Worker //operation because the kernel might read them at any time.
773*bb4ee6a4SAndroid Build Coastguard Worker pending_op_addrs: BTreeMap<UserData, Pin<Box<[IoBufMut<'static>]>>>,
774*bb4ee6a4SAndroid Build Coastguard Worker }
775*bb4ee6a4SAndroid Build Coastguard Worker
776*bb4ee6a4SAndroid Build Coastguard Worker pub struct CompleteQueueState {
777*bb4ee6a4SAndroid Build Coastguard Worker mmap: MemoryMapping,
778*bb4ee6a4SAndroid Build Coastguard Worker pointers: QueuePointers,
779*bb4ee6a4SAndroid Build Coastguard Worker ring_mask: u32,
780*bb4ee6a4SAndroid Build Coastguard Worker cqes_offset: u32,
781*bb4ee6a4SAndroid Build Coastguard Worker data: Mutex<CompleteQueueData>,
782*bb4ee6a4SAndroid Build Coastguard Worker }
783*bb4ee6a4SAndroid Build Coastguard Worker
784*bb4ee6a4SAndroid Build Coastguard Worker impl CompleteQueueState {
785*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
786*bb4ee6a4SAndroid Build Coastguard Worker /// Safe iff `mmap` is created by mapping from a uring FD at the CQ_RING offset and params is
787*bb4ee6a4SAndroid Build Coastguard Worker /// the params struct passed to io_uring_setup.
new(mmap: MemoryMapping, params: &io_uring_params) -> CompleteQueueState788*bb4ee6a4SAndroid Build Coastguard Worker unsafe fn new(mmap: MemoryMapping, params: &io_uring_params) -> CompleteQueueState {
789*bb4ee6a4SAndroid Build Coastguard Worker let ptr = mmap.as_ptr();
790*bb4ee6a4SAndroid Build Coastguard Worker let head = ptr.add(params.cq_off.head as usize) as *const AtomicU32;
791*bb4ee6a4SAndroid Build Coastguard Worker let tail = ptr.add(params.cq_off.tail as usize) as *const AtomicU32;
792*bb4ee6a4SAndroid Build Coastguard Worker let ring_mask = mmap.read_obj(params.cq_off.ring_mask as usize).unwrap();
793*bb4ee6a4SAndroid Build Coastguard Worker CompleteQueueState {
794*bb4ee6a4SAndroid Build Coastguard Worker mmap,
795*bb4ee6a4SAndroid Build Coastguard Worker pointers: QueuePointers { head, tail },
796*bb4ee6a4SAndroid Build Coastguard Worker ring_mask,
797*bb4ee6a4SAndroid Build Coastguard Worker cqes_offset: params.cq_off.cqes,
798*bb4ee6a4SAndroid Build Coastguard Worker data: Default::default(),
799*bb4ee6a4SAndroid Build Coastguard Worker }
800*bb4ee6a4SAndroid Build Coastguard Worker }
801*bb4ee6a4SAndroid Build Coastguard Worker
add_op_data(&self, user_data: UserData, addrs: Pin<Box<[IoBufMut<'static>]>>)802*bb4ee6a4SAndroid Build Coastguard Worker fn add_op_data(&self, user_data: UserData, addrs: Pin<Box<[IoBufMut<'static>]>>) {
803*bb4ee6a4SAndroid Build Coastguard Worker self.data.lock().pending_op_addrs.insert(user_data, addrs);
804*bb4ee6a4SAndroid Build Coastguard Worker }
805*bb4ee6a4SAndroid Build Coastguard Worker
get_cqe(&self, head: u32) -> &io_uring_cqe806*bb4ee6a4SAndroid Build Coastguard Worker fn get_cqe(&self, head: u32) -> &io_uring_cqe {
807*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
808*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we trust that the kernel has returned enough memory in io_uring_setup
809*bb4ee6a4SAndroid Build Coastguard Worker // and mmap and index is checked within range by the ring_mask.
810*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
811*bb4ee6a4SAndroid Build Coastguard Worker let cqes = (self.mmap.as_ptr() as *const u8).add(self.cqes_offset as usize)
812*bb4ee6a4SAndroid Build Coastguard Worker as *const io_uring_cqe;
813*bb4ee6a4SAndroid Build Coastguard Worker
814*bb4ee6a4SAndroid Build Coastguard Worker let index = head & self.ring_mask;
815*bb4ee6a4SAndroid Build Coastguard Worker
816*bb4ee6a4SAndroid Build Coastguard Worker &*cqes.add(index as usize)
817*bb4ee6a4SAndroid Build Coastguard Worker }
818*bb4ee6a4SAndroid Build Coastguard Worker }
819*bb4ee6a4SAndroid Build Coastguard Worker
num_ready(&self) -> u32820*bb4ee6a4SAndroid Build Coastguard Worker pub fn num_ready(&self) -> u32 {
821*bb4ee6a4SAndroid Build Coastguard Worker let tail = self.pointers.tail(Ordering::Acquire);
822*bb4ee6a4SAndroid Build Coastguard Worker let head = self.pointers.head(Ordering::Relaxed);
823*bb4ee6a4SAndroid Build Coastguard Worker
824*bb4ee6a4SAndroid Build Coastguard Worker tail.saturating_sub(head)
825*bb4ee6a4SAndroid Build Coastguard Worker }
826*bb4ee6a4SAndroid Build Coastguard Worker
pop_front(&self) -> Option<(UserData, std::io::Result<u32>)>827*bb4ee6a4SAndroid Build Coastguard Worker fn pop_front(&self) -> Option<(UserData, std::io::Result<u32>)> {
828*bb4ee6a4SAndroid Build Coastguard Worker // Take the lock on self.data first so that 2 threads don't try to pop the same completed op
829*bb4ee6a4SAndroid Build Coastguard Worker // from the queue.
830*bb4ee6a4SAndroid Build Coastguard Worker let mut data = self.data.lock();
831*bb4ee6a4SAndroid Build Coastguard Worker
832*bb4ee6a4SAndroid Build Coastguard Worker // Safe because the pointers to the atomics are valid and the cqe must be in range
833*bb4ee6a4SAndroid Build Coastguard Worker // because the kernel provided mask is applied to the index.
834*bb4ee6a4SAndroid Build Coastguard Worker let head = self.pointers.head(Ordering::Relaxed);
835*bb4ee6a4SAndroid Build Coastguard Worker
836*bb4ee6a4SAndroid Build Coastguard Worker // Synchronize the read of tail after the read of head.
837*bb4ee6a4SAndroid Build Coastguard Worker if head == self.pointers.tail(Ordering::Acquire) {
838*bb4ee6a4SAndroid Build Coastguard Worker return None;
839*bb4ee6a4SAndroid Build Coastguard Worker }
840*bb4ee6a4SAndroid Build Coastguard Worker
841*bb4ee6a4SAndroid Build Coastguard Worker let cqe = self.get_cqe(head);
842*bb4ee6a4SAndroid Build Coastguard Worker let user_data = cqe.user_data;
843*bb4ee6a4SAndroid Build Coastguard Worker let res = cqe.res;
844*bb4ee6a4SAndroid Build Coastguard Worker
845*bb4ee6a4SAndroid Build Coastguard Worker // free the addrs saved for this op.
846*bb4ee6a4SAndroid Build Coastguard Worker let _ = data.pending_op_addrs.remove(&user_data);
847*bb4ee6a4SAndroid Build Coastguard Worker
848*bb4ee6a4SAndroid Build Coastguard Worker // Store the new head and ensure the reads above complete before the kernel sees the
849*bb4ee6a4SAndroid Build Coastguard Worker // update to head, `set_head` uses `Release` ordering
850*bb4ee6a4SAndroid Build Coastguard Worker let new_head = head.wrapping_add(1);
851*bb4ee6a4SAndroid Build Coastguard Worker self.pointers.set_head(new_head);
852*bb4ee6a4SAndroid Build Coastguard Worker
853*bb4ee6a4SAndroid Build Coastguard Worker let io_res = match res {
854*bb4ee6a4SAndroid Build Coastguard Worker r if r < 0 => Err(std::io::Error::from_raw_os_error(-r)),
855*bb4ee6a4SAndroid Build Coastguard Worker r => Ok(r as u32),
856*bb4ee6a4SAndroid Build Coastguard Worker };
857*bb4ee6a4SAndroid Build Coastguard Worker Some((user_data, io_res))
858*bb4ee6a4SAndroid Build Coastguard Worker }
859*bb4ee6a4SAndroid Build Coastguard Worker }
860*bb4ee6a4SAndroid Build Coastguard Worker
861*bb4ee6a4SAndroid Build Coastguard Worker // Return the completed ops with their result.
862*bb4ee6a4SAndroid Build Coastguard Worker impl<'c> Iterator for &'c CompleteQueueState {
863*bb4ee6a4SAndroid Build Coastguard Worker type Item = (UserData, std::io::Result<u32>);
864*bb4ee6a4SAndroid Build Coastguard Worker
next(&mut self) -> Option<Self::Item>865*bb4ee6a4SAndroid Build Coastguard Worker fn next(&mut self) -> Option<Self::Item> {
866*bb4ee6a4SAndroid Build Coastguard Worker self.pop_front()
867*bb4ee6a4SAndroid Build Coastguard Worker }
868*bb4ee6a4SAndroid Build Coastguard Worker }
869*bb4ee6a4SAndroid Build Coastguard Worker
870*bb4ee6a4SAndroid Build Coastguard Worker struct QueuePointers {
871*bb4ee6a4SAndroid Build Coastguard Worker head: *const AtomicU32,
872*bb4ee6a4SAndroid Build Coastguard Worker tail: *const AtomicU32,
873*bb4ee6a4SAndroid Build Coastguard Worker }
874*bb4ee6a4SAndroid Build Coastguard Worker
875*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
876*bb4ee6a4SAndroid Build Coastguard Worker // Rust pointers don't implement Send or Sync but in this case both fields are atomics and so it's
877*bb4ee6a4SAndroid Build Coastguard Worker // safe to send the pointers between threads or access them concurrently from multiple threads.
878*bb4ee6a4SAndroid Build Coastguard Worker unsafe impl Send for QueuePointers {}
879*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: See safety comments for impl Send
880*bb4ee6a4SAndroid Build Coastguard Worker unsafe impl Sync for QueuePointers {}
881*bb4ee6a4SAndroid Build Coastguard Worker
882*bb4ee6a4SAndroid Build Coastguard Worker impl QueuePointers {
883*bb4ee6a4SAndroid Build Coastguard Worker // Loads the tail pointer atomically with the given ordering.
tail(&self, ordering: Ordering) -> u32884*bb4ee6a4SAndroid Build Coastguard Worker fn tail(&self, ordering: Ordering) -> u32 {
885*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
886*bb4ee6a4SAndroid Build Coastguard Worker // Safe because self being constructed from the correct mmap guaratees that the memory is
887*bb4ee6a4SAndroid Build Coastguard Worker // valid to read.
888*bb4ee6a4SAndroid Build Coastguard Worker unsafe { (*self.tail).load(ordering) }
889*bb4ee6a4SAndroid Build Coastguard Worker }
890*bb4ee6a4SAndroid Build Coastguard Worker
891*bb4ee6a4SAndroid Build Coastguard Worker // Stores the new value of the tail in the submit queue. This allows the kernel to start
892*bb4ee6a4SAndroid Build Coastguard Worker // processing entries that have been added up until the given tail pointer.
893*bb4ee6a4SAndroid Build Coastguard Worker // Always stores with release ordering as that is the only valid way to use the pointer.
set_tail(&self, next_tail: u32)894*bb4ee6a4SAndroid Build Coastguard Worker fn set_tail(&self, next_tail: u32) {
895*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
896*bb4ee6a4SAndroid Build Coastguard Worker // Safe because self being constructed from the correct mmap guaratees that the memory is
897*bb4ee6a4SAndroid Build Coastguard Worker // valid to read and it's used as an atomic to cover mutability concerns.
898*bb4ee6a4SAndroid Build Coastguard Worker unsafe { (*self.tail).store(next_tail, Ordering::Release) }
899*bb4ee6a4SAndroid Build Coastguard Worker }
900*bb4ee6a4SAndroid Build Coastguard Worker
901*bb4ee6a4SAndroid Build Coastguard Worker // Loads the head pointer atomically with the given ordering.
head(&self, ordering: Ordering) -> u32902*bb4ee6a4SAndroid Build Coastguard Worker fn head(&self, ordering: Ordering) -> u32 {
903*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
904*bb4ee6a4SAndroid Build Coastguard Worker // Safe because self being constructed from the correct mmap guaratees that the memory is
905*bb4ee6a4SAndroid Build Coastguard Worker // valid to read.
906*bb4ee6a4SAndroid Build Coastguard Worker unsafe { (*self.head).load(ordering) }
907*bb4ee6a4SAndroid Build Coastguard Worker }
908*bb4ee6a4SAndroid Build Coastguard Worker
909*bb4ee6a4SAndroid Build Coastguard Worker // Stores the new value of the head in the submit queue. This allows the kernel to start
910*bb4ee6a4SAndroid Build Coastguard Worker // processing entries that have been added up until the given head pointer.
911*bb4ee6a4SAndroid Build Coastguard Worker // Always stores with release ordering as that is the only valid way to use the pointer.
set_head(&self, next_head: u32)912*bb4ee6a4SAndroid Build Coastguard Worker fn set_head(&self, next_head: u32) {
913*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
914*bb4ee6a4SAndroid Build Coastguard Worker // Safe because self being constructed from the correct mmap guaratees that the memory is
915*bb4ee6a4SAndroid Build Coastguard Worker // valid to read and it's used as an atomic to cover mutability concerns.
916*bb4ee6a4SAndroid Build Coastguard Worker unsafe { (*self.head).store(next_head, Ordering::Release) }
917*bb4ee6a4SAndroid Build Coastguard Worker }
918*bb4ee6a4SAndroid Build Coastguard Worker }
919