block: add DiskFile::physical_size()

This is a pre-requisite for the bug fix in the following commit.

Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
On-behalf-of: SAP philipp.schuster@sap.com
This commit is contained in:
Philipp Schuster
2025-12-12 09:07:44 +01:00
committed by Rob Bradford
parent 53092359b4
commit 603b5e862c
14 changed files with 90 additions and 2 deletions

View File

@@ -58,10 +58,12 @@ impl AsRawFd for BorrowedDiskFd<'_> {
pub trait DiskFile: Send {
/// Returns the logical disk size a guest will see.
///
/// For raw formats, this is equal to the physical size. For file formats
/// For raw formats, this is equal to [`Self::physical_size`]. For file formats
/// that wrap disk images in a container (e.g. QCOW2), this refers to the
/// effective size that the guest will see.
fn logical_size(&mut self) -> DiskFileResult<u64>;
/// Returns the physical size of the underlying file.
fn physical_size(&mut self) -> DiskFileResult<u64>;
fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>>;
fn topology(&mut self) -> DiskTopology {
DiskTopology::default()

View File

@@ -78,6 +78,14 @@ impl BlockBackend for FixedVhd {
fn logical_size(&self) -> Result<u64, crate::Error> {
Ok(self.size)
}
/// Returns the physical size of the underlying file.
fn physical_size(&self) -> Result<u64, crate::Error> {
self.file
.metadata()
.map(|m| m.len())
.map_err(crate::Error::GetFileMetadata)
}
}
impl Clone for FixedVhd {

View File

@@ -27,6 +27,10 @@ impl DiskFile for FixedVhdDiskAsync {
Ok(self.0.logical_size().unwrap())
}
fn physical_size(&mut self) -> DiskFileResult<u64> {
Ok(self.0.physical_size().unwrap())
}
fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok(Box::new(
FixedVhdAsync::new(

View File

@@ -27,6 +27,16 @@ impl DiskFile for FixedVhdDiskSync {
Ok(self.0.logical_size().unwrap())
}
fn physical_size(&mut self) -> DiskFileResult<u64> {
self.0.physical_size().map_err(|e| {
let io_inner = match e {
crate::Error::GetFileMetadata(e) => e,
_ => unreachable!(),
};
DiskFileError::Size(io_inner)
})
}
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok(Box::new(
FixedVhdSync::new(self.0.as_raw_fd(), self.0.logical_size().unwrap())

View File

@@ -836,10 +836,12 @@ pub fn detect_image_type(f: &mut File) -> std::io::Result<ImageType> {
pub trait BlockBackend: Read + Write + Seek + Send + Debug {
/// Returns the logical disk size a guest will see.
///
/// For raw formats, this is equal to the physical_size. For file formats
/// For raw formats, this is equal to [`Self::physical_size`]. For file formats
/// that wrap disk images in a container (e.g. QCOW2), this refers to the
/// effective size that the guest will see.
fn logical_size(&self) -> Result<u64, Error>;
/// Returns the physical size of the underlying file.
fn physical_size(&self) -> Result<u64, Error>;
}
#[derive(Debug)]

View File

@@ -1811,6 +1811,12 @@ impl BlockBackend for QcowFile {
fn logical_size(&self) -> std::result::Result<u64, crate::Error> {
Ok(self.virtual_size())
}
fn physical_size(&self) -> std::result::Result<u64, crate::Error> {
self.raw_file
.physical_size()
.map_err(crate::Error::GetFileMetadata)
}
}
// Returns an Error if the given offset doesn't align to a cluster boundary.

View File

@@ -179,6 +179,10 @@ impl QcowRawFile {
self.file.seek(SeekFrom::Start(address))?;
self.file.write_all(&data[0..cluster_size])
}
pub fn physical_size(&self) -> Result<u64, std::io::Error> {
self.file.metadata().map(|m| m.len())
}
}
impl Clone for QcowRawFile {

View File

@@ -357,6 +357,10 @@ impl BlockBackend for RawFile {
fn logical_size(&self) -> std::result::Result<u64, crate::Error> {
Ok(self.metadata().map_err(crate::Error::RawFileError)?.len())
}
fn physical_size(&self) -> std::result::Result<u64, crate::Error> {
Ok(self.metadata().map_err(crate::Error::RawFileError)?.len())
}
}
impl Clone for RawFile {

View File

@@ -34,6 +34,16 @@ impl DiskFile for QcowDiskSync {
.map_err(DiskFileError::Size)
}
fn physical_size(&mut self) -> DiskFileResult<u64> {
self.qcow_file.physical_size().map_err(|e| {
let io_inner = match e {
crate::Error::GetFileMetadata(e) => e,
_ => unreachable!(),
};
DiskFileError::Size(io_inner)
})
}
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok(Box::new(QcowSync::new(self.qcow_file.clone())) as Box<dyn AsyncIo>)
}

View File

@@ -32,6 +32,13 @@ impl DiskFile for RawFileDisk {
.map_err(DiskFileError::Size)
}
fn physical_size(&mut self) -> DiskFileResult<u64> {
self.file
.metadata()
.map(|m| m.len())
.map_err(DiskFileError::Size)
}
fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok(Box::new(
RawFileAsync::new(self.file.as_raw_fd(), ring_depth)

View File

@@ -35,6 +35,13 @@ impl DiskFile for RawFileDiskAio {
.map_err(DiskFileError::Size)
}
fn physical_size(&mut self) -> DiskFileResult<u64> {
self.file
.metadata()
.map(|m| m.len())
.map_err(DiskFileError::Size)
}
fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok(Box::new(
RawFileAsyncAio::new(self.file.as_raw_fd(), ring_depth)

View File

@@ -32,6 +32,13 @@ impl DiskFile for RawFileDiskSync {
.map_err(DiskFileError::Size)
}
fn physical_size(&mut self) -> DiskFileResult<u64> {
self.file
.metadata()
.map(|m| m.len())
.map_err(DiskFileError::Size)
}
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok(Box::new(RawFileSync::new(self.file.as_raw_fd())) as Box<dyn AsyncIo>)
}

View File

@@ -205,6 +205,13 @@ impl BlockBackend for Vhdx {
fn logical_size(&self) -> std::result::Result<u64, crate::Error> {
Ok(self.virtual_disk_size())
}
fn physical_size(&self) -> std::result::Result<u64, crate::Error> {
self.file
.metadata()
.map(|m| m.len())
.map_err(crate::Error::GetFileMetadata)
}
}
impl Clone for Vhdx {

View File

@@ -31,6 +31,16 @@ impl DiskFile for VhdxDiskSync {
Ok(self.vhdx_file.virtual_disk_size())
}
fn physical_size(&mut self) -> DiskFileResult<u64> {
self.vhdx_file.physical_size().map_err(|e| {
let io_inner = match e {
Error::GetFileMetadata(e) => e,
_ => unreachable!(),
};
DiskFileError::Size(io_inner)
})
}
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok(
Box::new(VhdxSync::new(self.vhdx_file.clone()).map_err(DiskFileError::NewAsyncIo)?)