block: qcow: Add QcowTempDisk helper

A common pattern in the test code is to create a temporary file, format
it as QCOW2 and then open it as a QcowDisk. Create a helper struct that
can be used in those tests. This is marked as #[cfg(test)] as initially
it will only be used by the test suite.

Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Rob Bradford <rbradford@meta.com>
This commit is contained in:
Rob Bradford
2026-06-05 15:29:04 +01:00
parent b3cf8a84cd
commit 31ee5e99e4

View File

@@ -12,17 +12,21 @@ pub mod internal;
pub mod worker;
use std::fs::File;
#[cfg(test)]
use std::io::Seek;
use std::os::unix::io::AsRawFd;
use std::sync::Arc;
use std::{fmt, io};
#[cfg(test)]
use vmm_sys_util::tempfile::TempFile;
use self::internal::backing::shared_backing_from;
use self::internal::metadata::{BackingRead, QcowMetadata};
use self::internal::qcow_raw_file::QcowRawFile;
use self::internal::{
BackingFileConfig, Error as QcowError, MAX_NESTING_DEPTH, QcowHeader, RawFile, parse_qcow,
};
#[cfg(test)]
use self::internal::{BackingFileConfig, Error as QcowError, QcowHeader};
use self::internal::{MAX_NESTING_DEPTH, RawFile, parse_qcow};
#[cfg(feature = "io_uring")]
use self::worker::async_uring::QcowAsync;
use self::worker::sync::QcowSync;
@@ -101,7 +105,7 @@ impl QcowDisk {
}
/// Writes a fresh qcow2 layout into `file`
#[expect(dead_code)]
#[cfg(test)]
pub(crate) fn create_image(
file: &File,
virtual_size: u64,
@@ -131,6 +135,58 @@ pub(crate) fn create_image(
Ok(())
}
/// Helper struct to create a new qcow2 image in a temporary file.
#[cfg(test)]
pub struct QcowTempDisk {
tmp: TempFile,
disk: QcowDisk,
}
#[cfg(test)]
impl QcowTempDisk {
/// Creates a new qcow2 image in a temporary file with optional
/// backing file. Flags are passed to QcowDisk::new.
pub fn new(
virtual_size: u64,
backing_config: Option<&BackingFileConfig>,
direct_io: bool,
sparse: bool,
use_io_uring: bool,
) -> BlockResult<Self> {
let tmp = TempFile::new().map_err(io::Error::from)?;
create_image(tmp.as_file(), virtual_size, backing_config)?;
let file = tmp
.as_file()
.try_clone()
.map_err(|e| BlockError::new(BlockErrorKind::Io, DiskFileError::Clone(e)))?;
let disk = QcowDisk::new(
file,
direct_io,
backing_config.is_some(),
sparse,
use_io_uring,
)?;
Ok(Self { tmp, disk })
}
pub fn path(&self) -> &std::path::Path {
self.tmp.as_path()
}
pub fn as_file(&self) -> &File {
self.tmp.as_file()
}
pub fn disk(&self) -> &QcowDisk {
&self.disk
}
/// Drops the disk handle and returns the underlying TempFile.
pub fn into_tempfile(self) -> TempFile {
self.tmp
}
}
impl Drop for QcowDisk {
fn drop(&mut self) {
self.metadata.shutdown();