block: introduce trait BlockBackend for block types

This commit introduces the trait `BlockBackend` with generic ops
including read, write and seek, which can be used for common I/O
interfaces for the block types without using `DiskFile` and `AsyncIo`.

Signed-off-by: Yu Li <liyu.yukiteru@bytedance.com>
This commit is contained in:
Yu Li 2023-07-12 10:27:45 +08:00 committed by Rob Bradford
parent 447cad3861
commit 741d640330
7 changed files with 71 additions and 8 deletions

View File

@ -3,6 +3,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::vhd::VhdFooter; use crate::vhd::VhdFooter;
use crate::BlockBackend;
use std::fs::File; use std::fs::File;
use std::io::{Read, Seek, SeekFrom, Write}; use std::io::{Read, Seek, SeekFrom, Write};
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};
@ -24,10 +25,6 @@ impl FixedVhd {
position: 0, position: 0,
}) })
} }
pub fn size(&self) -> u64 {
self.size
}
} }
impl AsRawFd for FixedVhd { impl AsRawFd for FixedVhd {
@ -76,6 +73,12 @@ impl Seek for FixedVhd {
} }
} }
impl BlockBackend for FixedVhd {
fn size(&self) -> std::result::Result<u64, crate::Error> {
Ok(self.size)
}
}
impl Clone for FixedVhd { impl Clone for FixedVhd {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {

View File

@ -7,6 +7,7 @@ use crate::async_io::{
}; };
use crate::fixed_vhd::FixedVhd; use crate::fixed_vhd::FixedVhd;
use crate::raw_async::RawFileAsync; use crate::raw_async::RawFileAsync;
use crate::BlockBackend;
use std::fs::File; use std::fs::File;
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
@ -21,12 +22,12 @@ impl FixedVhdDiskAsync {
impl DiskFile for FixedVhdDiskAsync { impl DiskFile for FixedVhdDiskAsync {
fn size(&mut self) -> DiskFileResult<u64> { fn size(&mut self) -> DiskFileResult<u64> {
Ok(self.0.size()) Ok(self.0.size().unwrap())
} }
fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> { fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok(Box::new( Ok(Box::new(
FixedVhdAsync::new(self.0.as_raw_fd(), ring_depth, self.0.size()) FixedVhdAsync::new(self.0.as_raw_fd(), ring_depth, self.0.size().unwrap())
.map_err(DiskFileError::NewAsyncIo)?, .map_err(DiskFileError::NewAsyncIo)?,
) as Box<dyn AsyncIo>) ) as Box<dyn AsyncIo>)
} }

View File

@ -7,6 +7,7 @@ use crate::async_io::{
}; };
use crate::fixed_vhd::FixedVhd; use crate::fixed_vhd::FixedVhd;
use crate::raw_sync::RawFileSync; use crate::raw_sync::RawFileSync;
use crate::BlockBackend;
use std::fs::File; use std::fs::File;
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
@ -21,12 +22,12 @@ impl FixedVhdDiskSync {
impl DiskFile for FixedVhdDiskSync { impl DiskFile for FixedVhdDiskSync {
fn size(&mut self) -> DiskFileResult<u64> { fn size(&mut self) -> DiskFileResult<u64> {
Ok(self.0.size()) Ok(self.0.size().unwrap())
} }
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> { fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok(Box::new( Ok(Box::new(
FixedVhdSync::new(self.0.as_raw_fd(), self.0.size()) FixedVhdSync::new(self.0.as_raw_fd(), self.0.size().unwrap())
.map_err(DiskFileError::NewAsyncIo)?, .map_err(DiskFileError::NewAsyncIo)?,
) as Box<dyn AsyncIo>) ) as Box<dyn AsyncIo>)
} }

View File

@ -30,6 +30,9 @@ pub mod vhdx;
pub mod vhdx_sync; pub mod vhdx_sync;
use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult}; use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult};
use crate::fixed_vhd::FixedVhd;
use crate::qcow::{QcowFile, RawFile};
use crate::vhdx::{Vhdx, VhdxError};
#[cfg(feature = "io_uring")] #[cfg(feature = "io_uring")]
use io_uring::{opcode, IoUring, Probe}; use io_uring::{opcode, IoUring, Probe};
use smallvec::SmallVec; use smallvec::SmallVec;
@ -37,6 +40,7 @@ use std::alloc::{alloc_zeroed, dealloc, Layout};
use std::cmp; use std::cmp;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::convert::TryInto; use std::convert::TryInto;
use std::fmt::Debug;
use std::fs::File; use std::fs::File;
use std::io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; use std::io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
use std::os::linux::fs::MetadataExt; use std::os::linux::fs::MetadataExt;
@ -76,12 +80,22 @@ pub enum Error {
DescriptorChainTooShort, DescriptorChainTooShort,
#[error("Guest gave us a descriptor that was too short to use")] #[error("Guest gave us a descriptor that was too short to use")]
DescriptorLengthTooSmall, DescriptorLengthTooSmall,
#[error("Failed to detect image type: {0}")]
DetectImageType(std::io::Error),
#[error("Failure in fixed vhd: {0}")]
FixedVhdError(std::io::Error),
#[error("Getting a block's metadata fails for any reason")] #[error("Getting a block's metadata fails for any reason")]
GetFileMetadata, GetFileMetadata,
#[error("The requested operation would cause a seek beyond disk end")] #[error("The requested operation would cause a seek beyond disk end")]
InvalidOffset, InvalidOffset,
#[error("Failure in qcow: {0}")]
QcowError(qcow::Error),
#[error("Failure in raw file: {0}")]
RawFileError(std::io::Error),
#[error("The requested operation does not support multiple descriptors")] #[error("The requested operation does not support multiple descriptors")]
TooManyDescriptors, TooManyDescriptors,
#[error("Failure in vhdx: {0}")]
VhdxError(VhdxError),
} }
fn build_device_id(disk_path: &Path) -> result::Result<String, Error> { fn build_device_id(disk_path: &Path) -> result::Result<String, Error> {
@ -739,3 +753,26 @@ pub fn detect_image_type(f: &mut File) -> std::io::Result<ImageType> {
Ok(image_type) Ok(image_type)
} }
pub trait BlockBackend: Read + Write + Seek + Send + Debug {
fn size(&self) -> Result<u64, Error>;
}
/// Inspect the image file type and create an appropriate disk file to match it.
pub fn create_disk_file(mut file: File, direct_io: bool) -> Result<Box<dyn BlockBackend>, Error> {
let image_type = detect_image_type(&mut file).map_err(Error::DetectImageType)?;
Ok(match image_type {
ImageType::Qcow2 => {
Box::new(QcowFile::from(RawFile::new(file, direct_io)).map_err(Error::QcowError)?)
as Box<dyn BlockBackend>
}
ImageType::FixedVhd => {
Box::new(FixedVhd::new(file).map_err(Error::FixedVhdError)?) as Box<dyn BlockBackend>
}
ImageType::Vhdx => {
Box::new(Vhdx::new(file).map_err(Error::VhdxError)?) as Box<dyn BlockBackend>
}
ImageType::Raw => Box::new(RawFile::new(file, direct_io)) as Box<dyn BlockBackend>,
})
}

View File

@ -12,6 +12,7 @@ use crate::qcow::{
refcount::RefCount, refcount::RefCount,
vec_cache::{CacheMap, Cacheable, VecCache}, vec_cache::{CacheMap, Cacheable, VecCache},
}; };
use crate::BlockBackend;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use libc::{EINVAL, ENOSPC, ENOTSUP}; use libc::{EINVAL, ENOSPC, ENOTSUP};
use remain::sorted; use remain::sorted;
@ -1555,6 +1556,12 @@ impl SeekHole for QcowFile {
} }
} }
impl BlockBackend for QcowFile {
fn size(&self) -> std::result::Result<u64, crate::Error> {
Ok(self.virtual_size())
}
}
// Returns an Error if the given offset doesn't align to a cluster boundary. // Returns an Error if the given offset doesn't align to a cluster boundary.
fn offset_is_cluster_boundary(offset: u64, cluster_bits: u32) -> Result<()> { fn offset_is_cluster_boundary(offset: u64, cluster_bits: u32) -> Result<()> {
if offset & ((0x01 << cluster_bits) - 1) != 0 { if offset & ((0x01 << cluster_bits) - 1) != 0 {

View File

@ -8,6 +8,7 @@
// //
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
use crate::BlockBackend;
use libc::c_void; use libc::c_void;
use std::alloc::{alloc_zeroed, dealloc, Layout}; use std::alloc::{alloc_zeroed, dealloc, Layout};
use std::convert::TryInto; use std::convert::TryInto;
@ -343,6 +344,12 @@ impl SeekHole for RawFile {
} }
} }
impl BlockBackend for RawFile {
fn size(&self) -> std::result::Result<u64, crate::Error> {
Ok(self.metadata().map_err(crate::Error::RawFileError)?.len())
}
}
impl Clone for RawFile { impl Clone for RawFile {
fn clone(&self) -> Self { fn clone(&self) -> Self {
RawFile { RawFile {

View File

@ -8,6 +8,7 @@ use crate::vhdx::{
vhdx_io::VhdxIoError, vhdx_io::VhdxIoError,
vhdx_metadata::{DiskSpec, VhdxMetadataError}, vhdx_metadata::{DiskSpec, VhdxMetadataError},
}; };
use crate::BlockBackend;
use byteorder::{BigEndian, ByteOrder}; use byteorder::{BigEndian, ByteOrder};
use remain::sorted; use remain::sorted;
use std::collections::btree_map::BTreeMap; use std::collections::btree_map::BTreeMap;
@ -208,6 +209,12 @@ impl Seek for Vhdx {
} }
} }
impl BlockBackend for Vhdx {
fn size(&self) -> std::result::Result<u64, crate::Error> {
Ok(self.virtual_disk_size())
}
}
impl Clone for Vhdx { impl Clone for Vhdx {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Vhdx { Vhdx {