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:
Saravanan D
2026-02-18 14:23:03 -08:00
committed by Rob Bradford
parent 272fa624ef
commit 00c05f4761
5 changed files with 55 additions and 20 deletions
+18 -6
View File
@@ -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,