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 QcowSync
Store the alignment from the data file in QcowSync. Use AlignedBuf directly in read_vectored and write_vectored as the intermediate buffer so that aligned_pread/aligned_pwrite can skip the bounce copy when offset and length are naturally aligned. Use gather_from_iovecs_into to gather iovec data directly into the aligned buffer. Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
This commit is contained in:
committed by
Rob Bradford
parent
f50b5ab1f2
commit
fd8495b342
+49
-9
@@ -22,7 +22,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, gather_from_iovecs_into,
|
||||||
|
pread_exact, pwrite_all, scatter_to_iovecs, zero_fill_iovecs,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct QcowDiskSync {
|
pub struct QcowDiskSync {
|
||||||
@@ -153,6 +154,8 @@ pub struct QcowSync {
|
|||||||
/// See the backing_file field on QcowDiskSync.
|
/// See the backing_file field on QcowDiskSync.
|
||||||
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,
|
||||||
eventfd: EventFd,
|
eventfd: EventFd,
|
||||||
completion_list: VecDeque<(u64, i32)>,
|
completion_list: VecDeque<(u64, i32)>,
|
||||||
}
|
}
|
||||||
@@ -164,11 +167,13 @@ impl QcowSync {
|
|||||||
backing_file: Option<Arc<dyn BackingRead>>,
|
backing_file: Option<Arc<dyn BackingRead>>,
|
||||||
sparse: bool,
|
sparse: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let alignment = data_file.file().alignment();
|
||||||
QcowSync {
|
QcowSync {
|
||||||
metadata,
|
metadata,
|
||||||
data_file,
|
data_file,
|
||||||
backing_file,
|
backing_file,
|
||||||
sparse,
|
sparse,
|
||||||
|
alignment,
|
||||||
eventfd: EventFd::new(libc::EFD_NONBLOCK)
|
eventfd: EventFd::new(libc::EFD_NONBLOCK)
|
||||||
.expect("Failed creating EventFd for QcowSync"),
|
.expect("Failed creating EventFd for QcowSync"),
|
||||||
completion_list: VecDeque::new(),
|
completion_list: VecDeque::new(),
|
||||||
@@ -208,12 +213,29 @@ impl AsyncIo for QcowSync {
|
|||||||
offset: host_offset,
|
offset: host_offset,
|
||||||
length,
|
length,
|
||||||
} => {
|
} => {
|
||||||
let mut buf = vec![0u8; length as usize];
|
let len = length as usize;
|
||||||
pread_exact(self.data_file.as_raw_fd(), &mut buf, host_offset)
|
if self.alignment > 0 {
|
||||||
|
// O_DIRECT, aligned buffer avoids bounce copy.
|
||||||
|
let mut abuf = AlignedBuf::new(len, self.alignment)
|
||||||
|
.map_err(AsyncIoError::ReadVectored)?;
|
||||||
|
aligned_pread(
|
||||||
|
self.data_file.as_raw_fd(),
|
||||||
|
abuf.as_mut_slice(len),
|
||||||
|
host_offset,
|
||||||
|
self.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 {
|
||||||
|
// No O_DIRECT, plain buffer is fine.
|
||||||
|
let mut buf = vec![0u8; len];
|
||||||
|
pread_exact(self.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();
|
||||||
@@ -287,10 +309,28 @@ impl AsyncIo for QcowSync {
|
|||||||
ClusterWriteMapping::Allocated {
|
ClusterWriteMapping::Allocated {
|
||||||
offset: host_offset,
|
offset: host_offset,
|
||||||
} => {
|
} => {
|
||||||
// SAFETY: iovecs point to valid guest memory buffers
|
if self.alignment > 0 {
|
||||||
let buf = unsafe { gather_from_iovecs(iovecs, buf_offset, count) };
|
// O_DIRECT, gather directly into aligned buffer.
|
||||||
pwrite_all(self.data_file.as_raw_fd(), &buf, host_offset)
|
let mut abuf = AlignedBuf::new(count, self.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(
|
||||||
|
self.data_file.as_raw_fd(),
|
||||||
|
abuf.as_slice(count),
|
||||||
|
host_offset,
|
||||||
|
self.alignment,
|
||||||
|
)
|
||||||
.map_err(AsyncIoError::WriteVectored)?;
|
.map_err(AsyncIoError::WriteVectored)?;
|
||||||
|
} else {
|
||||||
|
// No O_DIRECT, plain buffer is fine.
|
||||||
|
// SAFETY: iovecs point to valid guest memory buffers
|
||||||
|
let buf = unsafe { gather_from_iovecs(iovecs, buf_offset, count) };
|
||||||
|
pwrite_all(self.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