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
+3 -1
View File
@@ -58,10 +58,12 @@ impl AsRawFd for BorrowedDiskFd<'_> {
pub trait DiskFile: Send { pub trait DiskFile: Send {
/// Returns the logical disk size a guest will see. /// 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 /// that wrap disk images in a container (e.g. QCOW2), this refers to the
/// effective size that the guest will see. /// effective size that the guest will see.
fn logical_size(&mut self) -> DiskFileResult<u64>; 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 new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>>;
fn topology(&mut self) -> DiskTopology { fn topology(&mut self) -> DiskTopology {
DiskTopology::default() DiskTopology::default()
+8
View File
@@ -78,6 +78,14 @@ impl BlockBackend for FixedVhd {
fn logical_size(&self) -> Result<u64, crate::Error> { fn logical_size(&self) -> Result<u64, crate::Error> {
Ok(self.size) 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 { impl Clone for FixedVhd {
+4
View File
@@ -27,6 +27,10 @@ impl DiskFile for FixedVhdDiskAsync {
Ok(self.0.logical_size().unwrap()) 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>> { fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok(Box::new( Ok(Box::new(
FixedVhdAsync::new( FixedVhdAsync::new(
+10
View File
@@ -27,6 +27,16 @@ impl DiskFile for FixedVhdDiskSync {
Ok(self.0.logical_size().unwrap()) 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>> { 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.logical_size().unwrap()) FixedVhdSync::new(self.0.as_raw_fd(), self.0.logical_size().unwrap())
+3 -1
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 { pub trait BlockBackend: Read + Write + Seek + Send + Debug {
/// Returns the logical disk size a guest will see. /// 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 /// that wrap disk images in a container (e.g. QCOW2), this refers to the
/// effective size that the guest will see. /// effective size that the guest will see.
fn logical_size(&self) -> Result<u64, Error>; fn logical_size(&self) -> Result<u64, Error>;
/// Returns the physical size of the underlying file.
fn physical_size(&self) -> Result<u64, Error>;
} }
#[derive(Debug)] #[derive(Debug)]
+6
View File
@@ -1811,6 +1811,12 @@ impl BlockBackend for QcowFile {
fn logical_size(&self) -> std::result::Result<u64, crate::Error> { fn logical_size(&self) -> std::result::Result<u64, crate::Error> {
Ok(self.virtual_size()) 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. // Returns an Error if the given offset doesn't align to a cluster boundary.
+4
View File
@@ -179,6 +179,10 @@ impl QcowRawFile {
self.file.seek(SeekFrom::Start(address))?; self.file.seek(SeekFrom::Start(address))?;
self.file.write_all(&data[0..cluster_size]) 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 { impl Clone for QcowRawFile {
+4
View File
@@ -357,6 +357,10 @@ impl BlockBackend for RawFile {
fn logical_size(&self) -> std::result::Result<u64, crate::Error> { fn logical_size(&self) -> std::result::Result<u64, crate::Error> {
Ok(self.metadata().map_err(crate::Error::RawFileError)?.len()) 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 { impl Clone for RawFile {
+10
View File
@@ -34,6 +34,16 @@ impl DiskFile for QcowDiskSync {
.map_err(DiskFileError::Size) .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>> { 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>) Ok(Box::new(QcowSync::new(self.qcow_file.clone())) as Box<dyn AsyncIo>)
} }
+7
View File
@@ -32,6 +32,13 @@ impl DiskFile for RawFileDisk {
.map_err(DiskFileError::Size) .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>> { fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok(Box::new( Ok(Box::new(
RawFileAsync::new(self.file.as_raw_fd(), ring_depth) RawFileAsync::new(self.file.as_raw_fd(), ring_depth)
+7
View File
@@ -35,6 +35,13 @@ impl DiskFile for RawFileDiskAio {
.map_err(DiskFileError::Size) .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>> { fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok(Box::new( Ok(Box::new(
RawFileAsyncAio::new(self.file.as_raw_fd(), ring_depth) RawFileAsyncAio::new(self.file.as_raw_fd(), ring_depth)
+7
View File
@@ -32,6 +32,13 @@ impl DiskFile for RawFileDiskSync {
.map_err(DiskFileError::Size) .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>> { 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>) Ok(Box::new(RawFileSync::new(self.file.as_raw_fd())) as Box<dyn AsyncIo>)
} }
+7
View File
@@ -205,6 +205,13 @@ impl BlockBackend for Vhdx {
fn logical_size(&self) -> std::result::Result<u64, crate::Error> { fn logical_size(&self) -> std::result::Result<u64, crate::Error> {
Ok(self.virtual_disk_size()) 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 { impl Clone for Vhdx {
+10
View File
@@ -31,6 +31,16 @@ impl DiskFile for VhdxDiskSync {
Ok(self.vhdx_file.virtual_disk_size()) 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>> { fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok( Ok(
Box::new(VhdxSync::new(self.vhdx_file.clone()).map_err(DiskFileError::NewAsyncIo)?) Box::new(VhdxSync::new(self.vhdx_file.clone()).map_err(DiskFileError::NewAsyncIo)?)