diff --git a/src/io_uring/kernel_types.rs b/src/io_uring/kernel_types.rs index f7ed435..22a7060 100644 --- a/src/io_uring/kernel_types.rs +++ b/src/io_uring/kernel_types.rs @@ -46,6 +46,7 @@ pub struct io_uring_sqe { } impl io_uring_sqe { + pub(crate) fn prep_rw( &mut self, opcode: u8, @@ -53,10 +54,47 @@ impl io_uring_sqe { len: usize, off: u64, ordering: Ordering, + ) { + self.prep_rw_with_flags( + opcode, + 0, + file_descriptor, + len, + off, + ordering + ) + } + + pub(crate) fn registered_file_prep_rw( + &mut self, + opcode: u8, + file_descriptor: i32, + len: usize, + off: u64, + ordering: Ordering, + ) { + self.prep_rw_with_flags( + opcode, + IOSQE_FIXED_FILE, + file_descriptor, + len, + off, + ordering + ) + } + + pub fn prep_rw_with_flags( + &mut self, + opcode: u8, + flags: u8, + file_descriptor: i32, + len: usize, + off: u64, + ordering: Ordering, ) { *self = io_uring_sqe { opcode, - flags: 0, + flags, ioprio: 0, fd: file_descriptor, len: u32::try_from(len).unwrap(), diff --git a/src/io_uring/mod.rs b/src/io_uring/mod.rs index 283f6c1..7d9df44 100644 --- a/src/io_uring/mod.rs +++ b/src/io_uring/mod.rs @@ -5,7 +5,7 @@ use std::{ io, net::{TcpListener, TcpStream}, ops::Neg, - os::unix::io::{AsRawFd, FromRawFd}, + os::unix::io::{AsRawFd, FromRawFd, RawFd}, sync::{ atomic::{ AtomicU32, AtomicU64, diff --git a/src/io_uring/uring.rs b/src/io_uring/uring.rs index ae6972b..4d52eed 100644 --- a/src/io_uring/uring.rs +++ b/src/io_uring/uring.rs @@ -12,6 +12,16 @@ impl std::ops::Deref for Rio { } } +/// Helper to +struct RegisteredIdx(usize); + +impl AsRawFd for RegisteredIdx { + fn as_raw_fd(&self) -> RawFd { + self.0 as RawFd + } +} + + /// The top-level `io_uring` structure. #[derive(Debug)] pub struct Uring { @@ -75,7 +85,7 @@ impl Uring { loaded: 0.into(), submitted: 0.into(), } - } + } pub(crate) fn ensure_submitted( &self, @@ -112,6 +122,20 @@ impl Uring { Ok(()) } + + /// Registers a file for use with SQPULL + pub fn register(&self, fds: &[RawFd]) -> io::Result + { + use core::ffi::c_void; + syscall::register( + self.ring_fd, + IORING_REGISTER_FILES, + fds.as_ptr() as *const c_void, + fds.len() as u32 + ) + } + + /// Asynchronously accepts a `TcpStream` from /// a provided `TcpListener`. /// @@ -604,6 +628,57 @@ impl Uring { ) } + /// This is a version of `read_at` that + /// can be used to read from a registered file. + /// + /// To register a file use `register_files`. + /// + /// `file_idx` refers to the element in the + /// slice passed to `register_files`. + pub fn registered_file_read_at<'a, B>( + &'a self, + file_idx: usize, + iov: &'a B, + at: u64, + ) -> Completion<'a, usize> + where + B: AsIoVec + AsIoVecMut, + { + self.registered_file_read_at_ordered(file_idx, iov, at, Ordering::None) + } + + /// This is a version of `read_at_ordered` that + /// can be used to read from a registered file. + /// + /// To register a file use `register_files`. + /// + /// `file_idx` refers to the element in the + /// slice passed to `register_files`. + pub fn registered_file_read_at_ordered<'a, B>( + &'a self, + file_idx: usize, + iov: &'a B, + at: u64, + ordering: Ordering, + ) -> Completion<'a, usize> + where + B: AsIoVec + AsIoVecMut, + { + self.with_sqe( + Some(iov.into_new_iovec()), + false, + |sqe| { + sqe.registered_file_prep_rw( + IORING_OP_READV, + RegisteredIdx(file_idx).as_raw_fd(), + 1, + at, + ordering, + ) + }, + ) + } + /// Don't do anything. This is /// mostly for debugging and tuning. pub fn nop<'a>(&'a self) -> Completion<'a, ()> {