diff --git a/block_util/src/lib.rs b/block_util/src/lib.rs index 818f1ee1c..b2954453c 100644 --- a/block_util/src/lib.rs +++ b/block_util/src/lib.rs @@ -18,21 +18,21 @@ pub mod qcow_sync; pub mod raw_async; pub mod raw_sync; -use crate::async_io::{AsyncIo, AsyncIoError}; +use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult, DiskFileError, DiskFileResult}; #[cfg(feature = "io_uring")] use io_uring::{opcode, IoUring, Probe}; use serde::ser::{Serialize, SerializeStruct, Serializer}; use std::cmp; -use std::io::{self, Read, Seek, SeekFrom, Write}; +use std::io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; use std::os::linux::fs::MetadataExt; #[cfg(feature = "io_uring")] use std::os::unix::io::AsRawFd; use std::path::PathBuf; use std::result; +use std::sync::{Arc, Mutex}; use virtio_bindings::bindings::virtio_blk::*; use vm_memory::{ByteValued, Bytes, GuestAddress, GuestMemory, GuestMemoryError, GuestMemoryMmap}; use vm_virtio::DescriptorChain; -#[cfg(feature = "io_uring")] use vmm_sys_util::eventfd::EventFd; const SECTOR_SHIFT: u8 = 9; @@ -542,3 +542,113 @@ pub fn block_io_uring_is_supported() -> bool { pub fn block_io_uring_is_supported() -> bool { false } + +pub fn disk_size(file: &mut dyn Seek, semaphore: &mut Arc>) -> DiskFileResult { + // Take the semaphore to ensure other threads are not interacting with + // the underlying file. + let _lock = semaphore.lock().unwrap(); + + Ok(file.seek(SeekFrom::End(0)).map_err(DiskFileError::Size)? as u64) +} + +pub trait ReadSeekFile: Read + Seek {} +impl ReadSeekFile for F {} + +pub fn read_vectored_sync( + offset: libc::off_t, + iovecs: Vec, + user_data: u64, + file: &mut dyn ReadSeekFile, + eventfd: &EventFd, + completion_list: &mut Vec<(u64, i32)>, + semaphore: &mut Arc>, +) -> 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 = { + // Take the semaphore to ensure other threads are not interacting + // with the underlying file. + let _lock = semaphore.lock().unwrap(); + + // Move the cursor to the right offset + 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 trait WriteSeekFile: Write + Seek {} +impl WriteSeekFile for F {} + +pub fn write_vectored_sync( + offset: libc::off_t, + iovecs: Vec, + user_data: u64, + file: &mut dyn WriteSeekFile, + eventfd: &EventFd, + completion_list: &mut Vec<(u64, i32)>, + semaphore: &mut Arc>, +) -> 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 = { + // Take the semaphore to ensure other threads are not interacting + // with the underlying file. + let _lock = semaphore.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, + file: &mut dyn Write, + eventfd: &EventFd, + completion_list: &mut Vec<(u64, i32)>, + semaphore: &mut Arc>, +) -> AsyncIoResult<()> { + let result: i32 = { + // Take the semaphore to ensure other threads are not interacting + // with the underlying file. + let _lock = semaphore.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(); + } + + Ok(()) +} diff --git a/block_util/src/qcow_sync.rs b/block_util/src/qcow_sync.rs index e7c048e52..1590f3754 100644 --- a/block_util/src/qcow_sync.rs +++ b/block_util/src/qcow_sync.rs @@ -2,12 +2,10 @@ // // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause -use crate::async_io::{ - AsyncIo, AsyncIoError, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult, -}; +use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileResult}; +use crate::{disk_size, fsync_sync, read_vectored_sync, write_vectored_sync}; use qcow::{QcowFile, RawFile}; use std::fs::File; -use std::io::{IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; use std::sync::{Arc, Mutex}; use vmm_sys_util::eventfd::EventFd; @@ -28,14 +26,7 @@ impl QcowDiskSync { impl DiskFile for QcowDiskSync { fn size(&mut self) -> DiskFileResult { - // Take the semaphore to ensure other threads are not interacting with - // the underlying file. - let _lock = self.semaphore.lock().unwrap(); - - Ok(self - .qcow_file - .seek(SeekFrom::End(0)) - .map_err(DiskFileError::Size)? as u64) + disk_size(&mut self.qcow_file, &mut self.semaphore) } fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult> { @@ -76,32 +67,15 @@ impl AsyncIo for QcowSync { iovecs: Vec, user_data: u64, ) -> 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 = { - // Take the semaphore to ensure other threads are not interacting - // with the underlying file. - let _lock = self.semaphore.lock().unwrap(); - - // Move the cursor to the right offset - self.qcow_file - .seek(SeekFrom::Start(offset as u64)) - .map_err(AsyncIoError::ReadVectored)?; - - // Read vectored - self.qcow_file - .read_vectored(slices.as_mut_slice()) - .map_err(AsyncIoError::ReadVectored)? - }; - - self.completion_list.push((user_data, result as i32)); - self.eventfd.write(1).unwrap(); - - Ok(()) + read_vectored_sync( + offset, + iovecs, + user_data, + &mut self.qcow_file, + &self.eventfd, + &mut self.completion_list, + &mut self.semaphore, + ) } fn write_vectored( @@ -110,52 +84,25 @@ impl AsyncIo for QcowSync { iovecs: Vec, user_data: u64, ) -> 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 = { - // Take the semaphore to ensure other threads are not interacting - // with the underlying file. - let _lock = self.semaphore.lock().unwrap(); - - // Move the cursor to the right offset - self.qcow_file - .seek(SeekFrom::Start(offset as u64)) - .map_err(AsyncIoError::WriteVectored)?; - - // Write vectored - self.qcow_file - .write_vectored(slices.as_slice()) - .map_err(AsyncIoError::WriteVectored)? - }; - - self.completion_list.push((user_data, result as i32)); - self.eventfd.write(1).unwrap(); - - Ok(()) + write_vectored_sync( + offset, + iovecs, + user_data, + &mut self.qcow_file, + &self.eventfd, + &mut self.completion_list, + &mut self.semaphore, + ) } fn fsync(&mut self, user_data: Option) -> AsyncIoResult<()> { - let result: i32 = { - // Take the semaphore to ensure other threads are not interacting - // with the underlying file. - let _lock = self.semaphore.lock().unwrap(); - - // Flush - self.qcow_file.flush().map_err(AsyncIoError::Fsync)?; - - 0 - }; - - if let Some(user_data) = user_data { - self.completion_list.push((user_data, result)); - self.eventfd.write(1).unwrap(); - } - - Ok(()) + fsync_sync( + user_data, + &mut self.qcow_file, + &self.eventfd, + &mut self.completion_list, + &mut self.semaphore, + ) } fn complete(&mut self) -> Vec<(u64, i32)> { diff --git a/block_util/src/raw_sync.rs b/block_util/src/raw_sync.rs index 069b8296d..1175d6c67 100644 --- a/block_util/src/raw_sync.rs +++ b/block_util/src/raw_sync.rs @@ -2,12 +2,10 @@ // // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause -use crate::async_io::{ - AsyncIo, AsyncIoError, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult, -}; +use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileResult}; +use crate::{disk_size, fsync_sync, read_vectored_sync, write_vectored_sync}; use qcow::RawFile; use std::fs::File; -use std::io::{IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; use std::sync::{Arc, Mutex}; use vmm_sys_util::eventfd::EventFd; @@ -27,14 +25,7 @@ impl RawFileDiskSync { impl DiskFile for RawFileDiskSync { fn size(&mut self) -> DiskFileResult { - // Take the semaphore to ensure other threads are not interacting with - // the underlying file. - let _lock = self.semaphore.lock().unwrap(); - - Ok(self - .raw_file - .seek(SeekFrom::End(0)) - .map_err(DiskFileError::Size)? as u64) + disk_size(&mut self.raw_file, &mut self.semaphore) } fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult> { @@ -74,32 +65,15 @@ impl AsyncIo for RawFileSync { iovecs: Vec, user_data: u64, ) -> 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 = { - // Take the semaphore to ensure other threads are not interacting - // with the underlying file. - let _lock = self.semaphore.lock().unwrap(); - - // Move the cursor to the right offset - self.raw_file - .seek(SeekFrom::Start(offset as u64)) - .map_err(AsyncIoError::ReadVectored)?; - - // Read vectored - self.raw_file - .read_vectored(slices.as_mut_slice()) - .map_err(AsyncIoError::ReadVectored)? - }; - - self.completion_list.push((user_data, result as i32)); - self.eventfd.write(1).unwrap(); - - Ok(()) + read_vectored_sync( + offset, + iovecs, + user_data, + &mut self.raw_file, + &self.eventfd, + &mut self.completion_list, + &mut self.semaphore, + ) } fn write_vectored( @@ -108,52 +82,25 @@ impl AsyncIo for RawFileSync { iovecs: Vec, user_data: u64, ) -> 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 = { - // Take the semaphore to ensure other threads are not interacting - // with the underlying file. - let _lock = self.semaphore.lock().unwrap(); - - // Move the cursor to the right offset - self.raw_file - .seek(SeekFrom::Start(offset as u64)) - .map_err(AsyncIoError::WriteVectored)?; - - // Write vectored - self.raw_file - .write_vectored(slices.as_slice()) - .map_err(AsyncIoError::WriteVectored)? - }; - - self.completion_list.push((user_data, result as i32)); - self.eventfd.write(1).unwrap(); - - Ok(()) + write_vectored_sync( + offset, + iovecs, + user_data, + &mut self.raw_file, + &self.eventfd, + &mut self.completion_list, + &mut self.semaphore, + ) } fn fsync(&mut self, user_data: Option) -> AsyncIoResult<()> { - let result: i32 = { - // Take the semaphore to ensure other threads are not interacting - // with the underlying file. - let _lock = self.semaphore.lock().unwrap(); - - // Flush - self.raw_file.flush().map_err(AsyncIoError::Fsync)?; - - 0 - }; - - if let Some(user_data) = user_data { - self.completion_list.push((user_data, result)); - self.eventfd.write(1).unwrap(); - } - - Ok(()) + fsync_sync( + user_data, + &mut self.raw_file, + &self.eventfd, + &mut self.completion_list, + &mut self.semaphore, + ) } fn complete(&mut self) -> Vec<(u64, i32)> {