diff --git a/block/src/fixed_vhd.rs b/block/src/fixed_vhd.rs index 49f012cd8..66ef13124 100644 --- a/block/src/fixed_vhd.rs +++ b/block/src/fixed_vhd.rs @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::vhd::VhdFooter; +use crate::BlockBackend; use std::fs::File; use std::io::{Read, Seek, SeekFrom, Write}; use std::os::unix::io::{AsRawFd, RawFd}; @@ -24,10 +25,6 @@ impl FixedVhd { position: 0, }) } - - pub fn size(&self) -> u64 { - self.size - } } impl AsRawFd for FixedVhd { @@ -76,6 +73,12 @@ impl Seek for FixedVhd { } } +impl BlockBackend for FixedVhd { + fn size(&self) -> std::result::Result { + Ok(self.size) + } +} + impl Clone for FixedVhd { fn clone(&self) -> Self { Self { diff --git a/block/src/fixed_vhd_async.rs b/block/src/fixed_vhd_async.rs index ef833a849..d8553afaf 100644 --- a/block/src/fixed_vhd_async.rs +++ b/block/src/fixed_vhd_async.rs @@ -7,6 +7,7 @@ use crate::async_io::{ }; use crate::fixed_vhd::FixedVhd; use crate::raw_async::RawFileAsync; +use crate::BlockBackend; use std::fs::File; use std::os::unix::io::{AsRawFd, RawFd}; use vmm_sys_util::eventfd::EventFd; @@ -21,12 +22,12 @@ impl FixedVhdDiskAsync { impl DiskFile for FixedVhdDiskAsync { fn size(&mut self) -> DiskFileResult { - Ok(self.0.size()) + Ok(self.0.size().unwrap()) } fn new_async_io(&self, ring_depth: u32) -> DiskFileResult> { 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)?, ) as Box) } diff --git a/block/src/fixed_vhd_sync.rs b/block/src/fixed_vhd_sync.rs index 605d22a40..b435bdd38 100644 --- a/block/src/fixed_vhd_sync.rs +++ b/block/src/fixed_vhd_sync.rs @@ -7,6 +7,7 @@ use crate::async_io::{ }; use crate::fixed_vhd::FixedVhd; use crate::raw_sync::RawFileSync; +use crate::BlockBackend; use std::fs::File; use std::os::unix::io::{AsRawFd, RawFd}; use vmm_sys_util::eventfd::EventFd; @@ -21,12 +22,12 @@ impl FixedVhdDiskSync { impl DiskFile for FixedVhdDiskSync { fn size(&mut self) -> DiskFileResult { - Ok(self.0.size()) + Ok(self.0.size().unwrap()) } fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult> { 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)?, ) as Box) } diff --git a/block/src/lib.rs b/block/src/lib.rs index 3348ed804..0787efaec 100644 --- a/block/src/lib.rs +++ b/block/src/lib.rs @@ -30,6 +30,9 @@ pub mod vhdx; pub mod vhdx_sync; 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")] use io_uring::{opcode, IoUring, Probe}; use smallvec::SmallVec; @@ -37,6 +40,7 @@ use std::alloc::{alloc_zeroed, dealloc, Layout}; use std::cmp; use std::collections::VecDeque; use std::convert::TryInto; +use std::fmt::Debug; use std::fs::File; use std::io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; use std::os::linux::fs::MetadataExt; @@ -76,12 +80,22 @@ pub enum Error { DescriptorChainTooShort, #[error("Guest gave us a descriptor that was too short to use")] 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")] GetFileMetadata, #[error("The requested operation would cause a seek beyond disk end")] 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")] TooManyDescriptors, + #[error("Failure in vhdx: {0}")] + VhdxError(VhdxError), } fn build_device_id(disk_path: &Path) -> result::Result { @@ -739,3 +753,26 @@ pub fn detect_image_type(f: &mut File) -> std::io::Result { Ok(image_type) } + +pub trait BlockBackend: Read + Write + Seek + Send + Debug { + fn size(&self) -> Result; +} + +/// 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, 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 + } + ImageType::FixedVhd => { + Box::new(FixedVhd::new(file).map_err(Error::FixedVhdError)?) as Box + } + ImageType::Vhdx => { + Box::new(Vhdx::new(file).map_err(Error::VhdxError)?) as Box + } + ImageType::Raw => Box::new(RawFile::new(file, direct_io)) as Box, + }) +} diff --git a/block/src/qcow/mod.rs b/block/src/qcow/mod.rs index a8b98e687..4449b612d 100644 --- a/block/src/qcow/mod.rs +++ b/block/src/qcow/mod.rs @@ -12,6 +12,7 @@ use crate::qcow::{ refcount::RefCount, vec_cache::{CacheMap, Cacheable, VecCache}, }; +use crate::BlockBackend; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use libc::{EINVAL, ENOSPC, ENOTSUP}; use remain::sorted; @@ -1555,6 +1556,12 @@ impl SeekHole for QcowFile { } } +impl BlockBackend for QcowFile { + fn size(&self) -> std::result::Result { + Ok(self.virtual_size()) + } +} + // 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<()> { if offset & ((0x01 << cluster_bits) - 1) != 0 { diff --git a/block/src/qcow/raw_file.rs b/block/src/qcow/raw_file.rs index 620bad182..fd9c3e3df 100644 --- a/block/src/qcow/raw_file.rs +++ b/block/src/qcow/raw_file.rs @@ -8,6 +8,7 @@ // // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause +use crate::BlockBackend; use libc::c_void; use std::alloc::{alloc_zeroed, dealloc, Layout}; use std::convert::TryInto; @@ -343,6 +344,12 @@ impl SeekHole for RawFile { } } +impl BlockBackend for RawFile { + fn size(&self) -> std::result::Result { + Ok(self.metadata().map_err(crate::Error::RawFileError)?.len()) + } +} + impl Clone for RawFile { fn clone(&self) -> Self { RawFile { diff --git a/block/src/vhdx/mod.rs b/block/src/vhdx/mod.rs index 6d2561d10..ccb05d8b0 100644 --- a/block/src/vhdx/mod.rs +++ b/block/src/vhdx/mod.rs @@ -8,6 +8,7 @@ use crate::vhdx::{ vhdx_io::VhdxIoError, vhdx_metadata::{DiskSpec, VhdxMetadataError}, }; +use crate::BlockBackend; use byteorder::{BigEndian, ByteOrder}; use remain::sorted; use std::collections::btree_map::BTreeMap; @@ -208,6 +209,12 @@ impl Seek for Vhdx { } } +impl BlockBackend for Vhdx { + fn size(&self) -> std::result::Result { + Ok(self.virtual_disk_size()) + } +} + impl Clone for Vhdx { fn clone(&self) -> Self { Vhdx {