block_util: provide and use AsyncAdaptor trait

The observation is that the code in question was used to bridge
synchronized and asynchronized code.

We can group the functions for that purpose under an adaptor trait. To
limit the scope of locking, the users of the trait are required to
implement a method to return a MutexGuard for the underlying file.

This then allows us to use concrete types (QcowFile and Vhdx) in code,
which is easier to read than a bunch of traits.

No functional change intended.

Signed-off-by: Wei Liu <liuwe@microsoft.com>
This commit is contained in:
Wei Liu 2021-12-06 10:57:42 +00:00 committed by Sebastien Boeuf
parent a29e53e436
commit af770c814b
3 changed files with 118 additions and 133 deletions

View File

@ -23,7 +23,6 @@ pub mod vhdx_sync;
use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult}; use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult};
#[cfg(feature = "io_uring")] #[cfg(feature = "io_uring")]
use io_uring::{opcode, IoUring, Probe}; use io_uring::{opcode, IoUring, Probe};
use std::any::Any;
use std::cmp; use std::cmp;
use std::convert::TryInto; use std::convert::TryInto;
use std::fs::File; use std::fs::File;
@ -31,7 +30,7 @@ use std::io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
use std::os::linux::fs::MetadataExt; use std::os::linux::fs::MetadataExt;
use std::path::Path; use std::path::Path;
use std::result; use std::result;
use std::sync::{Arc, Mutex}; use std::sync::MutexGuard;
use versionize::{VersionMap, Versionize, VersionizeResult}; use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize; use versionize_derive::Versionize;
use virtio_bindings::bindings::virtio_blk::*; use virtio_bindings::bindings::virtio_blk::*;
@ -477,103 +476,98 @@ pub fn block_io_uring_is_supported() -> bool {
false false
} }
pub trait ReadWriteSeekFile: Read + Write + Seek { pub trait AsyncAdaptor<F>
// Provides a mutable reference to the Any trait. This is useful to let where
// the caller have access to the underlying type behind the trait. F: Read + Write + Seek,
fn as_any(&mut self) -> &mut dyn Any; {
} fn read_vectored_sync(
&mut self,
offset: libc::off_t,
iovecs: Vec<libc::iovec>,
user_data: u64,
eventfd: &EventFd,
completion_list: &mut Vec<(u64, i32)>,
) -> AsyncIoResult<()> {
// Convert libc::iovec into IoSliceMut
let mut slices = Vec::new();
for iovec in iovecs.iter() {
slices.push(IoSliceMut::new(unsafe { std::mem::transmute(*iovec) }));
}
impl<F: Read + Write + Seek + 'static> ReadWriteSeekFile for F { let result = {
fn as_any(&mut self) -> &mut dyn Any { let mut file = self.file();
self
}
}
pub fn read_vectored_sync( // Move the cursor to the right offset
offset: libc::off_t, file.seek(SeekFrom::Start(offset as u64))
iovecs: Vec<libc::iovec>, .map_err(AsyncIoError::ReadVectored)?;
user_data: u64,
file: &mut Arc<Mutex<dyn ReadWriteSeekFile + Send + Sync>>,
eventfd: &EventFd,
completion_list: &mut Vec<(u64, i32)>,
) -> AsyncIoResult<()> {
// Convert libc::iovec into IoSliceMut
let mut slices = Vec::new();
for iovec in iovecs.iter() {
slices.push(IoSliceMut::new(unsafe { std::mem::transmute(*iovec) }));
}
let result = { // Read vectored
let mut file = file.lock().unwrap(); file.read_vectored(slices.as_mut_slice())
.map_err(AsyncIoError::ReadVectored)?
};
// Move the cursor to the right offset completion_list.push((user_data, result as i32));
file.seek(SeekFrom::Start(offset as u64))
.map_err(AsyncIoError::ReadVectored)?;
// Read vectored
file.read_vectored(slices.as_mut_slice())
.map_err(AsyncIoError::ReadVectored)?
};
completion_list.push((user_data, result as i32));
eventfd.write(1).unwrap();
Ok(())
}
pub fn write_vectored_sync(
offset: libc::off_t,
iovecs: Vec<libc::iovec>,
user_data: u64,
file: &mut Arc<Mutex<dyn ReadWriteSeekFile + Sync + Send>>,
eventfd: &EventFd,
completion_list: &mut Vec<(u64, i32)>,
) -> AsyncIoResult<()> {
// Convert libc::iovec into IoSlice
let mut slices = Vec::new();
for iovec in iovecs.iter() {
slices.push(IoSlice::new(unsafe { std::mem::transmute(*iovec) }));
}
let result = {
let mut file = file.lock().unwrap();
// Move the cursor to the right offset
file.seek(SeekFrom::Start(offset as u64))
.map_err(AsyncIoError::WriteVectored)?;
// Write vectored
file.write_vectored(slices.as_slice())
.map_err(AsyncIoError::WriteVectored)?
};
completion_list.push((user_data, result as i32));
eventfd.write(1).unwrap();
Ok(())
}
pub fn fsync_sync(
user_data: Option<u64>,
file: &mut Arc<Mutex<dyn ReadWriteSeekFile + Sync + Send>>,
eventfd: &EventFd,
completion_list: &mut Vec<(u64, i32)>,
) -> AsyncIoResult<()> {
let result: i32 = {
let mut file = file.lock().unwrap();
// Flush
file.flush().map_err(AsyncIoError::Fsync)?;
0
};
if let Some(user_data) = user_data {
completion_list.push((user_data, result));
eventfd.write(1).unwrap(); eventfd.write(1).unwrap();
Ok(())
} }
Ok(()) fn write_vectored_sync(
&mut self,
offset: libc::off_t,
iovecs: Vec<libc::iovec>,
user_data: u64,
eventfd: &EventFd,
completion_list: &mut Vec<(u64, i32)>,
) -> AsyncIoResult<()> {
// Convert libc::iovec into IoSlice
let mut slices = Vec::new();
for iovec in iovecs.iter() {
slices.push(IoSlice::new(unsafe { std::mem::transmute(*iovec) }));
}
let result = {
let mut file = self.file();
// Move the cursor to the right offset
file.seek(SeekFrom::Start(offset as u64))
.map_err(AsyncIoError::WriteVectored)?;
// Write vectored
file.write_vectored(slices.as_slice())
.map_err(AsyncIoError::WriteVectored)?
};
completion_list.push((user_data, result as i32));
eventfd.write(1).unwrap();
Ok(())
}
fn fsync_sync(
&mut self,
user_data: Option<u64>,
eventfd: &EventFd,
completion_list: &mut Vec<(u64, i32)>,
) -> AsyncIoResult<()> {
let result: i32 = {
let mut file = self.file();
// Flush
file.flush().map_err(AsyncIoError::Fsync)?;
0
};
if let Some(user_data) = user_data {
completion_list.push((user_data, result));
eventfd.write(1).unwrap();
}
Ok(())
}
fn file(&mut self) -> MutexGuard<F>;
} }
pub enum ImageType { pub enum ImageType {

View File

@ -3,15 +3,15 @@
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult}; use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult};
use crate::{fsync_sync, read_vectored_sync, write_vectored_sync, ReadWriteSeekFile}; use crate::AsyncAdaptor;
use qcow::{QcowFile, RawFile, Result as QcowResult}; use qcow::{QcowFile, RawFile, Result as QcowResult};
use std::fs::File; use std::fs::File;
use std::io::SeekFrom; use std::io::{Seek, SeekFrom};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex, MutexGuard};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
pub struct QcowDiskSync { pub struct QcowDiskSync {
qcow_file: Arc<Mutex<dyn ReadWriteSeekFile + Send + Sync>>, qcow_file: Arc<Mutex<QcowFile>>,
} }
impl QcowDiskSync { impl QcowDiskSync {
@ -35,13 +35,13 @@ impl DiskFile for QcowDiskSync {
} }
pub struct QcowSync { pub struct QcowSync {
qcow_file: Arc<Mutex<dyn ReadWriteSeekFile + Send + Sync>>, qcow_file: Arc<Mutex<QcowFile>>,
eventfd: EventFd, eventfd: EventFd,
completion_list: Vec<(u64, i32)>, completion_list: Vec<(u64, i32)>,
} }
impl QcowSync { impl QcowSync {
pub fn new(qcow_file: Arc<Mutex<dyn ReadWriteSeekFile + Send + Sync>>) -> Self { pub fn new(qcow_file: Arc<Mutex<QcowFile>>) -> Self {
QcowSync { QcowSync {
qcow_file, qcow_file,
eventfd: EventFd::new(libc::EFD_NONBLOCK) eventfd: EventFd::new(libc::EFD_NONBLOCK)
@ -51,6 +51,12 @@ impl QcowSync {
} }
} }
impl AsyncAdaptor<QcowFile> for Arc<Mutex<QcowFile>> {
fn file(&mut self) -> MutexGuard<QcowFile> {
self.lock().unwrap()
}
}
impl AsyncIo for QcowSync { impl AsyncIo for QcowSync {
fn notifier(&self) -> &EventFd { fn notifier(&self) -> &EventFd {
&self.eventfd &self.eventfd
@ -62,11 +68,10 @@ impl AsyncIo for QcowSync {
iovecs: Vec<libc::iovec>, iovecs: Vec<libc::iovec>,
user_data: u64, user_data: u64,
) -> AsyncIoResult<()> { ) -> AsyncIoResult<()> {
read_vectored_sync( self.qcow_file.read_vectored_sync(
offset, offset,
iovecs, iovecs,
user_data, user_data,
&mut self.qcow_file,
&self.eventfd, &self.eventfd,
&mut self.completion_list, &mut self.completion_list,
) )
@ -78,23 +83,18 @@ impl AsyncIo for QcowSync {
iovecs: Vec<libc::iovec>, iovecs: Vec<libc::iovec>,
user_data: u64, user_data: u64,
) -> AsyncIoResult<()> { ) -> AsyncIoResult<()> {
write_vectored_sync( self.qcow_file.write_vectored_sync(
offset, offset,
iovecs, iovecs,
user_data, user_data,
&mut self.qcow_file,
&self.eventfd, &self.eventfd,
&mut self.completion_list, &mut self.completion_list,
) )
} }
fn fsync(&mut self, user_data: Option<u64>) -> AsyncIoResult<()> { fn fsync(&mut self, user_data: Option<u64>) -> AsyncIoResult<()> {
fsync_sync( self.qcow_file
user_data, .fsync_sync(user_data, &self.eventfd, &mut self.completion_list)
&mut self.qcow_file,
&self.eventfd,
&mut self.completion_list,
)
} }
fn complete(&mut self) -> Vec<(u64, i32)> { fn complete(&mut self) -> Vec<(u64, i32)> {

View File

@ -3,14 +3,14 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult}; use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult};
use crate::{fsync_sync, read_vectored_sync, write_vectored_sync, ReadWriteSeekFile}; use crate::AsyncAdaptor;
use std::fs::File; use std::fs::File;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex, MutexGuard};
use vhdx::vhdx::{Result as VhdxResult, Vhdx}; use vhdx::vhdx::{Result as VhdxResult, Vhdx};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
pub struct VhdxDiskSync { pub struct VhdxDiskSync {
vhdx_file: Arc<Mutex<dyn ReadWriteSeekFile + Sync + Send>>, vhdx_file: Arc<Mutex<Vhdx>>,
} }
impl VhdxDiskSync { impl VhdxDiskSync {
@ -23,14 +23,7 @@ impl VhdxDiskSync {
impl DiskFile for VhdxDiskSync { impl DiskFile for VhdxDiskSync {
fn size(&mut self) -> DiskFileResult<u64> { fn size(&mut self) -> DiskFileResult<u64> {
Ok(self Ok(self.vhdx_file.lock().unwrap().virtual_disk_size())
.vhdx_file
.lock()
.unwrap()
.as_any()
.downcast_ref::<Vhdx>()
.unwrap()
.virtual_disk_size())
} }
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> { fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
@ -42,15 +35,13 @@ impl DiskFile for VhdxDiskSync {
} }
pub struct VhdxSync { pub struct VhdxSync {
vhdx_file: Arc<Mutex<dyn ReadWriteSeekFile + Sync + Send>>, vhdx_file: Arc<Mutex<Vhdx>>,
eventfd: EventFd, eventfd: EventFd,
completion_list: Vec<(u64, i32)>, completion_list: Vec<(u64, i32)>,
} }
impl VhdxSync { impl VhdxSync {
pub fn new( pub fn new(vhdx_file: Arc<Mutex<Vhdx>>) -> std::io::Result<Self> {
vhdx_file: Arc<Mutex<dyn ReadWriteSeekFile + Sync + Send>>,
) -> std::io::Result<Self> {
Ok(VhdxSync { Ok(VhdxSync {
vhdx_file, vhdx_file,
eventfd: EventFd::new(libc::EFD_NONBLOCK)?, eventfd: EventFd::new(libc::EFD_NONBLOCK)?,
@ -59,6 +50,12 @@ impl VhdxSync {
} }
} }
impl AsyncAdaptor<Vhdx> for Arc<Mutex<Vhdx>> {
fn file(&mut self) -> MutexGuard<Vhdx> {
self.lock().unwrap()
}
}
impl AsyncIo for VhdxSync { impl AsyncIo for VhdxSync {
fn notifier(&self) -> &EventFd { fn notifier(&self) -> &EventFd {
&self.eventfd &self.eventfd
@ -70,11 +67,10 @@ impl AsyncIo for VhdxSync {
iovecs: Vec<libc::iovec>, iovecs: Vec<libc::iovec>,
user_data: u64, user_data: u64,
) -> AsyncIoResult<()> { ) -> AsyncIoResult<()> {
read_vectored_sync( self.vhdx_file.read_vectored_sync(
offset, offset,
iovecs, iovecs,
user_data, user_data,
&mut self.vhdx_file,
&self.eventfd, &self.eventfd,
&mut self.completion_list, &mut self.completion_list,
) )
@ -86,23 +82,18 @@ impl AsyncIo for VhdxSync {
iovecs: Vec<libc::iovec>, iovecs: Vec<libc::iovec>,
user_data: u64, user_data: u64,
) -> AsyncIoResult<()> { ) -> AsyncIoResult<()> {
write_vectored_sync( self.vhdx_file.write_vectored_sync(
offset, offset,
iovecs, iovecs,
user_data, user_data,
&mut self.vhdx_file,
&self.eventfd, &self.eventfd,
&mut self.completion_list, &mut self.completion_list,
) )
} }
fn fsync(&mut self, user_data: Option<u64>) -> AsyncIoResult<()> { fn fsync(&mut self, user_data: Option<u64>) -> AsyncIoResult<()> {
fsync_sync( self.vhdx_file
user_data, .fsync_sync(user_data, &self.eventfd, &mut self.completion_list)
&mut self.vhdx_file,
&self.eventfd,
&mut self.completion_list,
)
} }
fn complete(&mut self) -> Vec<(u64, i32)> { fn complete(&mut self) -> Vec<(u64, i32)> {