mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
block: add aio disk backend
Signed-off-by: Thomas Barrett <tbarrett@crusoeenergy.com>
This commit is contained in:
@@ -24,6 +24,7 @@ pub mod qcow_sync;
|
||||
///
|
||||
/// Enabled with the `"io_uring"` feature
|
||||
pub mod raw_async;
|
||||
pub mod raw_async_aio;
|
||||
pub mod raw_sync;
|
||||
pub mod vhd;
|
||||
pub mod vhdx;
|
||||
@@ -61,6 +62,7 @@ use vm_memory::{
|
||||
GuestMemoryError, GuestMemoryLoadGuard,
|
||||
};
|
||||
use vm_virtio::{AccessPlatform, Translatable};
|
||||
use vmm_sys_util::aio;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
use vmm_sys_util::{ioctl_io_nr, ioctl_ioc_nr};
|
||||
|
||||
@@ -565,6 +567,11 @@ unsafe impl ByteValued for VirtioBlockConfig {}
|
||||
// SAFETY: data structure only contain a series of integers
|
||||
unsafe impl ByteValued for VirtioBlockGeometry {}
|
||||
|
||||
/// Check if aio can be used on the current system.
|
||||
pub fn block_aio_is_supported() -> bool {
|
||||
aio::IoContext::new(1).is_ok()
|
||||
}
|
||||
|
||||
/// Check if io_uring for block device can be used on the current system, as
|
||||
/// it correctly supports the expected io_uring features.
|
||||
pub fn block_io_uring_is_supported() -> bool {
|
||||
|
||||
138
block/src/raw_async_aio.rs
Normal file
138
block/src/raw_async_aio.rs
Normal file
@@ -0,0 +1,138 @@
|
||||
use crate::async_io::{
|
||||
AsyncIo, AsyncIoError, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult,
|
||||
};
|
||||
use crate::DiskTopology;
|
||||
use std::fs::File;
|
||||
use std::io::{Seek, SeekFrom};
|
||||
use std::os::unix::io::{AsRawFd, RawFd};
|
||||
use vmm_sys_util::aio;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
pub struct RawFileDiskAio {
|
||||
file: File,
|
||||
}
|
||||
|
||||
impl RawFileDiskAio {
|
||||
pub fn new(file: File) -> Self {
|
||||
RawFileDiskAio { file }
|
||||
}
|
||||
}
|
||||
|
||||
impl DiskFile for RawFileDiskAio {
|
||||
fn size(&mut self) -> DiskFileResult<u64> {
|
||||
self.file
|
||||
.seek(SeekFrom::End(0))
|
||||
.map_err(DiskFileError::Size)
|
||||
}
|
||||
|
||||
fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
|
||||
Ok(Box::new(
|
||||
RawFileAsyncAio::new(self.file.as_raw_fd(), ring_depth)
|
||||
.map_err(DiskFileError::NewAsyncIo)?,
|
||||
) as Box<dyn AsyncIo>)
|
||||
}
|
||||
|
||||
fn topology(&mut self) -> DiskTopology {
|
||||
if let Ok(topology) = DiskTopology::probe(&self.file) {
|
||||
topology
|
||||
} else {
|
||||
warn!("Unable to get device topology. Using default topology");
|
||||
DiskTopology::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RawFileAsyncAio {
|
||||
fd: RawFd,
|
||||
ctx: aio::IoContext,
|
||||
eventfd: EventFd,
|
||||
}
|
||||
|
||||
impl RawFileAsyncAio {
|
||||
pub fn new(fd: RawFd, queue_depth: u32) -> std::io::Result<Self> {
|
||||
let eventfd = EventFd::new(libc::EFD_NONBLOCK)?;
|
||||
let ctx = aio::IoContext::new(queue_depth)?;
|
||||
|
||||
Ok(RawFileAsyncAio { fd, ctx, eventfd })
|
||||
}
|
||||
}
|
||||
|
||||
impl AsyncIo for RawFileAsyncAio {
|
||||
fn notifier(&self) -> &EventFd {
|
||||
&self.eventfd
|
||||
}
|
||||
|
||||
fn read_vectored(
|
||||
&mut self,
|
||||
offset: libc::off_t,
|
||||
iovecs: &[libc::iovec],
|
||||
user_data: u64,
|
||||
) -> AsyncIoResult<()> {
|
||||
let iocbs = [&mut aio::IoControlBlock {
|
||||
aio_fildes: self.fd.as_raw_fd() as u32,
|
||||
aio_lio_opcode: aio::IOCB_CMD_PREADV as u16,
|
||||
aio_buf: iovecs.as_ptr() as u64,
|
||||
aio_nbytes: iovecs.len() as u64,
|
||||
aio_offset: offset,
|
||||
aio_data: user_data,
|
||||
aio_flags: aio::IOCB_FLAG_RESFD,
|
||||
aio_resfd: self.eventfd.as_raw_fd() as u32,
|
||||
..Default::default()
|
||||
}];
|
||||
let _ = self
|
||||
.ctx
|
||||
.submit(&iocbs[..])
|
||||
.map_err(AsyncIoError::ReadVectored)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_vectored(
|
||||
&mut self,
|
||||
offset: libc::off_t,
|
||||
iovecs: &[libc::iovec],
|
||||
user_data: u64,
|
||||
) -> AsyncIoResult<()> {
|
||||
let iocbs = [&mut aio::IoControlBlock {
|
||||
aio_fildes: self.fd.as_raw_fd() as u32,
|
||||
aio_lio_opcode: aio::IOCB_CMD_PWRITEV as u16,
|
||||
aio_buf: iovecs.as_ptr() as u64,
|
||||
aio_nbytes: iovecs.len() as u64,
|
||||
aio_offset: offset,
|
||||
aio_data: user_data,
|
||||
aio_flags: aio::IOCB_FLAG_RESFD,
|
||||
aio_resfd: self.eventfd.as_raw_fd() as u32,
|
||||
..Default::default()
|
||||
}];
|
||||
let _ = self
|
||||
.ctx
|
||||
.submit(&iocbs[..])
|
||||
.map_err(AsyncIoError::WriteVectored)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fsync(&mut self, user_data: Option<u64>) -> AsyncIoResult<()> {
|
||||
let iocbs = [&mut aio::IoControlBlock {
|
||||
aio_fildes: self.fd.as_raw_fd() as u32,
|
||||
aio_lio_opcode: aio::IOCB_CMD_FSYNC as u16,
|
||||
aio_data: user_data.unwrap_or(0),
|
||||
aio_flags: aio::IOCB_FLAG_RESFD,
|
||||
aio_resfd: self.eventfd.as_raw_fd() as u32,
|
||||
..Default::default()
|
||||
}];
|
||||
let _ = self.ctx.submit(&iocbs[..]).map_err(AsyncIoError::Fsync)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn next_completed_request(&mut self) -> Option<(u64, i32)> {
|
||||
let mut events: [aio::IoEvent; 1] = [aio::IoEvent::default()];
|
||||
let rc = self.ctx.get_events(0, &mut events, None).unwrap();
|
||||
if rc == 0 {
|
||||
None
|
||||
} else {
|
||||
Some((events[0].data, events[0].res as i32))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user