core: Switch io_ring to Readv and Writev

The Readv and Writev opcodes are available on all Linux kernel versions
so let's switch to them.
This commit is contained in:
Pekka Enberg 2024-07-16 14:24:12 +03:00
parent 7fa8f5c62e
commit 812a8b9ea2

View file

@ -1,24 +1,51 @@
use super::{Completion, File, WriteCompletion, IO};
use anyhow::Result;
use libc::iovec;
use log::trace;
use std::cell::RefCell;
use std::cell::{Ref, RefCell};
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::AsRawFd;
use std::rc::Rc;
const MAX_IOVECS: usize = 128;
pub struct LinuxIO {
ring: Rc<RefCell<io_uring::IoUring>>,
inner: Rc<RefCell<InnerLinuxIO>>,
}
pub struct InnerLinuxIO {
ring: io_uring::IoUring,
iovecs: [iovec; MAX_IOVECS],
next_iovec: usize,
}
impl LinuxIO {
pub fn new() -> Result<Self> {
let ring = io_uring::IoUring::new(128)?;
let ring = io_uring::IoUring::new(MAX_IOVECS as u32)?;
let inner = InnerLinuxIO {
ring: ring,
iovecs: [iovec {
iov_base: std::ptr::null_mut(),
iov_len: 0,
}; MAX_IOVECS],
next_iovec: 0,
};
Ok(Self {
ring: Rc::new(RefCell::new(ring)),
inner: Rc::new(RefCell::new(inner)),
})
}
}
impl InnerLinuxIO {
pub fn get_iovec<'a>(&'a mut self, buf: *const u8, len: usize) -> &'a iovec {
let iovec = &mut self.iovecs[self.next_iovec];
iovec.iov_base = buf as *mut std::ffi::c_void;
iovec.iov_len = len;
self.next_iovec = (self.next_iovec + 1) % MAX_IOVECS;
iovec
}
}
impl IO for LinuxIO {
fn open_file(&self, path: &str) -> Result<Rc<dyn File>> {
trace!("open_file(path = {})", path);
@ -28,14 +55,15 @@ impl IO for LinuxIO {
.custom_flags(libc::O_DIRECT)
.open(path)?;
Ok(Rc::new(LinuxFile {
ring: self.ring.clone(),
io: self.inner.clone(),
file,
}))
}
fn run_once(&self) -> Result<()> {
trace!("run_once()");
let mut ring = self.ring.borrow_mut();
let mut inner = self.inner.borrow_mut();
let mut ring = &mut inner.ring;
ring.submit_and_wait(1)?;
while let Some(cqe) = ring.completion().next() {
let c = unsafe { Rc::from_raw(cqe.user_data() as *const Completion) };
@ -46,7 +74,7 @@ impl IO for LinuxIO {
}
pub struct LinuxFile {
ring: Rc<RefCell<io_uring::IoUring>>,
io: Rc<RefCell<InnerLinuxIO>>,
file: std::fs::File,
}
@ -54,17 +82,19 @@ impl File for LinuxFile {
fn pread(&self, pos: usize, c: Rc<Completion>) -> Result<()> {
trace!("pread(pos = {}, length = {})", pos, c.buf().len());
let fd = io_uring::types::Fd(self.file.as_raw_fd());
let mut io = self.io.borrow_mut();
let read_e = {
let mut buf = c.buf_mut();
let len = buf.len();
let buf = buf.as_mut_ptr();
let ptr = Rc::into_raw(c.clone());
io_uring::opcode::Read::new(fd, buf, len as u32)
let iovec = io.get_iovec(buf, len);
io_uring::opcode::Readv::new(fd, iovec, 1)
.offset(pos as u64)
.build()
.user_data(ptr as u64)
};
let mut ring = self.ring.borrow_mut();
let mut ring = &mut io.ring;
unsafe {
ring.submission()
.push(&read_e)
@ -79,16 +109,18 @@ impl File for LinuxFile {
buffer: Rc<RefCell<crate::Buffer>>,
c: Rc<WriteCompletion>,
) -> Result<()> {
let mut io = self.io.borrow_mut();
let fd = io_uring::types::Fd(self.file.as_raw_fd());
let write = {
let buf = buffer.borrow();
let ptr = Rc::into_raw(c.clone());
io_uring::opcode::Write::new(fd, buf.as_ptr(), buf.len() as u32)
let iovec = io.get_iovec(buf.as_ptr(), buf.len());
io_uring::opcode::Writev::new(fd, iovec, 1)
.offset(pos as u64)
.build()
.user_data(ptr as u64)
};
let mut ring = self.ring.borrow_mut();
let mut ring = &mut io.ring;
unsafe {
ring.submission()
.push(&write)