mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
block: qcow: Use aligned I/O in QcowAsync
Store the alignment from the data file in QcowAsync. Use aligned_pread in scatter_read_sync and aligned_pwrite with gather_from_iovecs_into in cow_write_sync, matching the QcowSync approach. Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
This commit is contained in:
committed by
Rob Bradford
parent
fd8495b342
commit
cfa60a95b9
+58
-10
@@ -27,7 +27,8 @@ use crate::qcow::metadata::{
|
|||||||
use crate::qcow::qcow_raw_file::QcowRawFile;
|
use crate::qcow::qcow_raw_file::QcowRawFile;
|
||||||
use crate::qcow::{MAX_NESTING_DEPTH, RawFile, parse_qcow};
|
use crate::qcow::{MAX_NESTING_DEPTH, RawFile, parse_qcow};
|
||||||
use crate::qcow_common::{
|
use crate::qcow_common::{
|
||||||
gather_from_iovecs, pread_exact, pwrite_all, scatter_to_iovecs, zero_fill_iovecs,
|
AlignedBuf, aligned_pread, aligned_pwrite, gather_from_iovecs_into, pread_exact, pwrite_all,
|
||||||
|
scatter_to_iovecs, zero_fill_iovecs,
|
||||||
};
|
};
|
||||||
use crate::{BatchRequest, RequestType, disk_file};
|
use crate::{BatchRequest, RequestType, disk_file};
|
||||||
|
|
||||||
@@ -172,6 +173,8 @@ pub struct QcowAsync {
|
|||||||
data_file: QcowRawFile,
|
data_file: QcowRawFile,
|
||||||
backing_file: Option<Arc<dyn BackingRead>>,
|
backing_file: Option<Arc<dyn BackingRead>>,
|
||||||
sparse: bool,
|
sparse: bool,
|
||||||
|
/// O_DIRECT alignment requirement (0 = no alignment needed).
|
||||||
|
alignment: usize,
|
||||||
io_uring: IoUring,
|
io_uring: IoUring,
|
||||||
eventfd: EventFd,
|
eventfd: EventFd,
|
||||||
completion_list: VecDeque<(u64, i32)>,
|
completion_list: VecDeque<(u64, i32)>,
|
||||||
@@ -185,6 +188,7 @@ impl QcowAsync {
|
|||||||
sparse: bool,
|
sparse: bool,
|
||||||
ring_depth: u32,
|
ring_depth: u32,
|
||||||
) -> io::Result<Self> {
|
) -> io::Result<Self> {
|
||||||
|
let alignment = data_file.file().alignment();
|
||||||
let io_uring = IoUring::new(ring_depth)?;
|
let io_uring = IoUring::new(ring_depth)?;
|
||||||
let eventfd = EventFd::new(libc::EFD_NONBLOCK)?;
|
let eventfd = EventFd::new(libc::EFD_NONBLOCK)?;
|
||||||
io_uring.submitter().register_eventfd(eventfd.as_raw_fd())?;
|
io_uring.submitter().register_eventfd(eventfd.as_raw_fd())?;
|
||||||
@@ -194,6 +198,7 @@ impl QcowAsync {
|
|||||||
data_file,
|
data_file,
|
||||||
backing_file,
|
backing_file,
|
||||||
sparse,
|
sparse,
|
||||||
|
alignment,
|
||||||
io_uring,
|
io_uring,
|
||||||
eventfd,
|
eventfd,
|
||||||
completion_list: VecDeque::new(),
|
completion_list: VecDeque::new(),
|
||||||
@@ -241,6 +246,7 @@ impl AsyncIo for QcowAsync {
|
|||||||
offset as u64,
|
offset as u64,
|
||||||
iovecs,
|
iovecs,
|
||||||
total_len,
|
total_len,
|
||||||
|
self.alignment,
|
||||||
)? {
|
)? {
|
||||||
let fd = self.data_file.as_raw_fd();
|
let fd = self.data_file.as_raw_fd();
|
||||||
let (submitter, mut sq, _) = self.io_uring.split();
|
let (submitter, mut sq, _) = self.io_uring.split();
|
||||||
@@ -285,6 +291,7 @@ impl AsyncIo for QcowAsync {
|
|||||||
&self.metadata,
|
&self.metadata,
|
||||||
&self.data_file,
|
&self.data_file,
|
||||||
&self.backing_file,
|
&self.backing_file,
|
||||||
|
self.alignment,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let total_len: usize = iovecs.iter().map(|v| v.iov_len).sum();
|
let total_len: usize = iovecs.iter().map(|v| v.iov_len).sum();
|
||||||
@@ -377,6 +384,7 @@ impl AsyncIo for QcowAsync {
|
|||||||
req.offset as u64,
|
req.offset as u64,
|
||||||
&req.iovecs,
|
&req.iovecs,
|
||||||
total_len,
|
total_len,
|
||||||
|
self.alignment,
|
||||||
)? {
|
)? {
|
||||||
let fd = self.data_file.as_raw_fd();
|
let fd = self.data_file.as_raw_fd();
|
||||||
// SAFETY: fd is valid and iovecs point to valid guest memory.
|
// SAFETY: fd is valid and iovecs point to valid guest memory.
|
||||||
@@ -408,6 +416,7 @@ impl AsyncIo for QcowAsync {
|
|||||||
&self.metadata,
|
&self.metadata,
|
||||||
&self.data_file,
|
&self.data_file,
|
||||||
&self.backing_file,
|
&self.backing_file,
|
||||||
|
self.alignment,
|
||||||
)?;
|
)?;
|
||||||
sync_completions.push((req.user_data, total_len as i32));
|
sync_completions.push((req.user_data, total_len as i32));
|
||||||
}
|
}
|
||||||
@@ -448,6 +457,7 @@ impl QcowAsync {
|
|||||||
address: u64,
|
address: u64,
|
||||||
iovecs: &[libc::iovec],
|
iovecs: &[libc::iovec],
|
||||||
total_len: usize,
|
total_len: usize,
|
||||||
|
alignment: usize,
|
||||||
) -> AsyncIoResult<Option<u64>> {
|
) -> AsyncIoResult<Option<u64>> {
|
||||||
let has_backing = backing_file.is_some();
|
let has_backing = backing_file.is_some();
|
||||||
let mappings = metadata
|
let mappings = metadata
|
||||||
@@ -464,7 +474,7 @@ impl QcowAsync {
|
|||||||
return Ok(Some(*host_offset));
|
return Ok(Some(*host_offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::scatter_read_sync(mappings, iovecs, data_file, backing_file)?;
|
Self::scatter_read_sync(mappings, iovecs, data_file, backing_file, alignment)?;
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -474,6 +484,7 @@ impl QcowAsync {
|
|||||||
iovecs: &[libc::iovec],
|
iovecs: &[libc::iovec],
|
||||||
data_file: &QcowRawFile,
|
data_file: &QcowRawFile,
|
||||||
backing_file: &Option<Arc<dyn BackingRead>>,
|
backing_file: &Option<Arc<dyn BackingRead>>,
|
||||||
|
alignment: usize,
|
||||||
) -> AsyncIoResult<()> {
|
) -> AsyncIoResult<()> {
|
||||||
let mut buf_offset = 0usize;
|
let mut buf_offset = 0usize;
|
||||||
for mapping in mappings {
|
for mapping in mappings {
|
||||||
@@ -489,12 +500,27 @@ impl QcowAsync {
|
|||||||
offset: host_offset,
|
offset: host_offset,
|
||||||
length,
|
length,
|
||||||
} => {
|
} => {
|
||||||
let mut buf = vec![0u8; length as usize];
|
let len = length as usize;
|
||||||
pread_exact(data_file.as_raw_fd(), &mut buf, host_offset)
|
if alignment > 0 {
|
||||||
|
let mut abuf =
|
||||||
|
AlignedBuf::new(len, alignment).map_err(AsyncIoError::ReadVectored)?;
|
||||||
|
aligned_pread(
|
||||||
|
data_file.as_raw_fd(),
|
||||||
|
abuf.as_mut_slice(len),
|
||||||
|
host_offset,
|
||||||
|
alignment,
|
||||||
|
)
|
||||||
.map_err(AsyncIoError::ReadVectored)?;
|
.map_err(AsyncIoError::ReadVectored)?;
|
||||||
// SAFETY: iovecs point to valid guest memory buffers.
|
// SAFETY: iovecs point to valid guest memory buffers.
|
||||||
unsafe { scatter_to_iovecs(iovecs, buf_offset, &buf) };
|
unsafe { scatter_to_iovecs(iovecs, buf_offset, abuf.as_slice(len)) };
|
||||||
buf_offset += length as usize;
|
} else {
|
||||||
|
let mut buf = vec![0u8; len];
|
||||||
|
pread_exact(data_file.as_raw_fd(), &mut buf, host_offset)
|
||||||
|
.map_err(AsyncIoError::ReadVectored)?;
|
||||||
|
// SAFETY: iovecs point to valid guest memory buffers.
|
||||||
|
unsafe { scatter_to_iovecs(iovecs, buf_offset, &buf) };
|
||||||
|
}
|
||||||
|
buf_offset += len;
|
||||||
}
|
}
|
||||||
ClusterReadMapping::Compressed { data } => {
|
ClusterReadMapping::Compressed { data } => {
|
||||||
let len = data.len();
|
let len = data.len();
|
||||||
@@ -528,6 +554,7 @@ impl QcowAsync {
|
|||||||
metadata: &QcowMetadata,
|
metadata: &QcowMetadata,
|
||||||
data_file: &QcowRawFile,
|
data_file: &QcowRawFile,
|
||||||
backing_file: &Option<Arc<dyn BackingRead>>,
|
backing_file: &Option<Arc<dyn BackingRead>>,
|
||||||
|
alignment: usize,
|
||||||
) -> AsyncIoResult<()> {
|
) -> AsyncIoResult<()> {
|
||||||
let total_len: usize = iovecs.iter().map(|v| v.iov_len).sum();
|
let total_len: usize = iovecs.iter().map(|v| v.iov_len).sum();
|
||||||
let cluster_size = metadata.cluster_size();
|
let cluster_size = metadata.cluster_size();
|
||||||
@@ -561,10 +588,31 @@ impl QcowAsync {
|
|||||||
ClusterWriteMapping::Allocated {
|
ClusterWriteMapping::Allocated {
|
||||||
offset: host_offset,
|
offset: host_offset,
|
||||||
} => {
|
} => {
|
||||||
// SAFETY: iovecs point to valid guest memory buffers.
|
if alignment > 0 {
|
||||||
let buf = unsafe { gather_from_iovecs(iovecs, buf_offset, count) };
|
// O_DIRECT, gather directly into aligned buffer.
|
||||||
pwrite_all(data_file.as_raw_fd(), &buf, host_offset)
|
let mut abuf = AlignedBuf::new(count, alignment)
|
||||||
|
.map_err(AsyncIoError::WriteVectored)?;
|
||||||
|
// SAFETY: iovecs point to valid guest memory buffers
|
||||||
|
unsafe {
|
||||||
|
gather_from_iovecs_into(iovecs, buf_offset, abuf.as_mut_slice(count));
|
||||||
|
}
|
||||||
|
aligned_pwrite(
|
||||||
|
data_file.as_raw_fd(),
|
||||||
|
abuf.as_slice(count),
|
||||||
|
host_offset,
|
||||||
|
alignment,
|
||||||
|
)
|
||||||
.map_err(AsyncIoError::WriteVectored)?;
|
.map_err(AsyncIoError::WriteVectored)?;
|
||||||
|
} else {
|
||||||
|
// No O_DIRECT, plain buffer is fine.
|
||||||
|
let mut buf = vec![0u8; count];
|
||||||
|
// SAFETY: iovecs point to valid guest memory buffers.
|
||||||
|
unsafe {
|
||||||
|
gather_from_iovecs_into(iovecs, buf_offset, &mut buf);
|
||||||
|
}
|
||||||
|
pwrite_all(data_file.as_raw_fd(), &buf, host_offset)
|
||||||
|
.map_err(AsyncIoError::WriteVectored)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf_offset += count;
|
buf_offset += count;
|
||||||
|
|||||||
Reference in New Issue
Block a user