mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
block: Use logical block size for alignment
O_DIRECT requires buffer addresses to be aligned to the backend device's logical block size. The existing bounce buffer logic in execute_async() hardcodes SECTOR_SIZE (512) for the alignment check and bounce buffer allocation. This is insufficient for devices with a 4096-byte logical block size, where misaligned buffers cause -EINVAL from the host kernel. Add an alignment() method to the AsyncIo trait that returns the backend's logical block size, defaulting to SECTOR_SIZE. The three raw I/O backends (io_uring, AIO, synchronous) probe the device topology via DiskTopology::probe() at creation time and return the actual logical block size. All image format backends would simply use the default value of 512 bytes since their underlying are not block devices. execute_async() now queries disk_image.alignment() instead of using the hardcoded SECTOR_SIZE Fixes: #7720 Signed-off-by: Saravanan D <saravanand@crusoe.ai>
This commit is contained in:
committed by
Rob Bradford
parent
272fa624ef
commit
00c05f4761
@@ -8,7 +8,7 @@ use std::os::fd::{AsRawFd, OwnedFd, RawFd};
|
||||
use thiserror::Error;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
use crate::{BatchRequest, DiskTopology};
|
||||
use crate::{BatchRequest, DiskTopology, SECTOR_SIZE};
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum DiskFileError {
|
||||
@@ -145,4 +145,7 @@ pub trait AsyncIo: Send {
|
||||
fn submit_batch_requests(&mut self, _batch_request: &[BatchRequest]) -> AsyncIoResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn alignment(&self) -> u64 {
|
||||
SECTOR_SIZE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,6 +436,7 @@ impl Request {
|
||||
let sector = self.sector;
|
||||
let request_type = self.request_type;
|
||||
let offset = (sector << SECTOR_SHIFT) as libc::off_t;
|
||||
let alignment = disk_image.alignment();
|
||||
|
||||
let mut iovecs: SmallVec<[libc::iovec; DEFAULT_DESCRIPTOR_VEC_SIZE]> =
|
||||
SmallVec::with_capacity(self.data_descriptors.len());
|
||||
@@ -466,14 +467,15 @@ impl Request {
|
||||
assert!(origin_ptr.len() >= data_len);
|
||||
let origin_ptr = origin_ptr.ptr_guard();
|
||||
|
||||
// Verify the buffer alignment.
|
||||
// In case it's not properly aligned, an intermediate buffer is
|
||||
// created with the correct alignment, and a copy from/to the
|
||||
// origin buffer is performed, depending on the type of operation.
|
||||
let iov_base = if (origin_ptr.as_ptr() as u64).is_multiple_of(SECTOR_SIZE) {
|
||||
// O_DIRECT requires buffer addresses to be aligned to the
|
||||
// backend device's logical block size. In case it's not properly
|
||||
// aligned, an intermediate buffer is created with the correct
|
||||
// alignment, and a copy from/to the origin buffer is performed,
|
||||
// depending on the type of operation.
|
||||
let iov_base = if (origin_ptr.as_ptr() as u64).is_multiple_of(alignment) {
|
||||
origin_ptr.as_ptr() as *mut libc::c_void
|
||||
} else {
|
||||
let layout = Layout::from_size_align(data_len, SECTOR_SIZE as usize).unwrap();
|
||||
let layout = Layout::from_size_align(data_len, alignment as usize).unwrap();
|
||||
// SAFETY: layout has non-zero size
|
||||
let aligned_ptr = unsafe { alloc_zeroed(layout) };
|
||||
if aligned_ptr.is_null() {
|
||||
|
||||
@@ -13,7 +13,7 @@ use vmm_sys_util::eventfd::EventFd;
|
||||
use crate::async_io::{
|
||||
AsyncIo, AsyncIoError, AsyncIoResult, BorrowedDiskFd, DiskFile, DiskFileError, DiskFileResult,
|
||||
};
|
||||
use crate::{BatchRequest, DiskTopology, RequestType, probe_sparse_support};
|
||||
use crate::{BatchRequest, DiskTopology, RequestType, SECTOR_SIZE, probe_sparse_support};
|
||||
|
||||
pub struct RawFileDisk {
|
||||
file: File,
|
||||
@@ -40,10 +40,12 @@ impl DiskFile for RawFileDisk {
|
||||
}
|
||||
|
||||
fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
|
||||
Ok(Box::new(
|
||||
RawFileAsync::new(self.file.as_raw_fd(), ring_depth)
|
||||
.map_err(DiskFileError::NewAsyncIo)?,
|
||||
) as Box<dyn AsyncIo>)
|
||||
let mut raw = RawFileAsync::new(self.file.as_raw_fd(), ring_depth)
|
||||
.map_err(DiskFileError::NewAsyncIo)?;
|
||||
raw.alignment = DiskTopology::probe(&self.file)
|
||||
.map(|t| t.logical_block_size)
|
||||
.unwrap_or(SECTOR_SIZE);
|
||||
Ok(Box::new(raw) as Box<dyn AsyncIo>)
|
||||
}
|
||||
|
||||
fn topology(&mut self) -> DiskTopology {
|
||||
@@ -72,6 +74,7 @@ pub struct RawFileAsync {
|
||||
fd: RawFd,
|
||||
io_uring: IoUring,
|
||||
eventfd: EventFd,
|
||||
alignment: u64,
|
||||
}
|
||||
|
||||
impl RawFileAsync {
|
||||
@@ -87,6 +90,7 @@ impl RawFileAsync {
|
||||
fd,
|
||||
io_uring,
|
||||
eventfd,
|
||||
alignment: SECTOR_SIZE,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -96,6 +100,10 @@ impl AsyncIo for RawFileAsync {
|
||||
&self.eventfd
|
||||
}
|
||||
|
||||
fn alignment(&self) -> u64 {
|
||||
self.alignment
|
||||
}
|
||||
|
||||
fn read_vectored(
|
||||
&mut self,
|
||||
offset: libc::off_t,
|
||||
|
||||
@@ -16,7 +16,7 @@ use vmm_sys_util::eventfd::EventFd;
|
||||
use crate::async_io::{
|
||||
AsyncIo, AsyncIoError, AsyncIoResult, BorrowedDiskFd, DiskFile, DiskFileError, DiskFileResult,
|
||||
};
|
||||
use crate::{DiskTopology, probe_sparse_support};
|
||||
use crate::{DiskTopology, SECTOR_SIZE, probe_sparse_support};
|
||||
|
||||
pub struct RawFileDiskAio {
|
||||
file: File,
|
||||
@@ -43,10 +43,12 @@ impl DiskFile for RawFileDiskAio {
|
||||
}
|
||||
|
||||
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>)
|
||||
let mut raw = RawFileAsyncAio::new(self.file.as_raw_fd(), ring_depth)
|
||||
.map_err(DiskFileError::NewAsyncIo)?;
|
||||
raw.alignment = DiskTopology::probe(&self.file)
|
||||
.map(|t| t.logical_block_size)
|
||||
.unwrap_or(SECTOR_SIZE);
|
||||
Ok(Box::new(raw) as Box<dyn AsyncIo>)
|
||||
}
|
||||
|
||||
fn topology(&mut self) -> DiskTopology {
|
||||
@@ -71,6 +73,7 @@ pub struct RawFileAsyncAio {
|
||||
fd: RawFd,
|
||||
ctx: aio::IoContext,
|
||||
eventfd: EventFd,
|
||||
alignment: u64,
|
||||
}
|
||||
|
||||
impl RawFileAsyncAio {
|
||||
@@ -78,7 +81,12 @@ impl RawFileAsyncAio {
|
||||
let eventfd = EventFd::new(libc::EFD_NONBLOCK)?;
|
||||
let ctx = aio::IoContext::new(queue_depth)?;
|
||||
|
||||
Ok(RawFileAsyncAio { fd, ctx, eventfd })
|
||||
Ok(RawFileAsyncAio {
|
||||
fd,
|
||||
ctx,
|
||||
eventfd,
|
||||
alignment: SECTOR_SIZE,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +95,10 @@ impl AsyncIo for RawFileAsyncAio {
|
||||
&self.eventfd
|
||||
}
|
||||
|
||||
fn alignment(&self) -> u64 {
|
||||
self.alignment
|
||||
}
|
||||
|
||||
fn read_vectored(
|
||||
&mut self,
|
||||
offset: libc::off_t,
|
||||
|
||||
@@ -13,7 +13,7 @@ use vmm_sys_util::eventfd::EventFd;
|
||||
use crate::async_io::{
|
||||
AsyncIo, AsyncIoError, AsyncIoResult, BorrowedDiskFd, DiskFile, DiskFileError, DiskFileResult,
|
||||
};
|
||||
use crate::{DiskTopology, probe_sparse_support};
|
||||
use crate::{DiskTopology, SECTOR_SIZE, probe_sparse_support};
|
||||
|
||||
pub struct RawFileDiskSync {
|
||||
file: File,
|
||||
@@ -40,7 +40,11 @@ impl DiskFile for RawFileDiskSync {
|
||||
}
|
||||
|
||||
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
|
||||
Ok(Box::new(RawFileSync::new(self.file.as_raw_fd())) as Box<dyn AsyncIo>)
|
||||
let mut raw = RawFileSync::new(self.file.as_raw_fd());
|
||||
raw.alignment = DiskTopology::probe(&self.file)
|
||||
.map(|t| t.logical_block_size)
|
||||
.unwrap_or(SECTOR_SIZE);
|
||||
Ok(Box::new(raw) as Box<dyn AsyncIo>)
|
||||
}
|
||||
|
||||
fn topology(&mut self) -> DiskTopology {
|
||||
@@ -65,6 +69,7 @@ pub struct RawFileSync {
|
||||
fd: RawFd,
|
||||
eventfd: EventFd,
|
||||
completion_list: VecDeque<(u64, i32)>,
|
||||
alignment: u64,
|
||||
}
|
||||
|
||||
impl RawFileSync {
|
||||
@@ -73,6 +78,7 @@ impl RawFileSync {
|
||||
fd,
|
||||
eventfd: EventFd::new(libc::EFD_NONBLOCK).expect("Failed creating EventFd for RawFile"),
|
||||
completion_list: VecDeque::new(),
|
||||
alignment: SECTOR_SIZE,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,6 +88,10 @@ impl AsyncIo for RawFileSync {
|
||||
&self.eventfd
|
||||
}
|
||||
|
||||
fn alignment(&self) -> u64 {
|
||||
self.alignment
|
||||
}
|
||||
|
||||
fn read_vectored(
|
||||
&mut self,
|
||||
offset: libc::off_t,
|
||||
|
||||
Reference in New Issue
Block a user