From bdce007aacd447b8cd5bca6bbadda63078d59191 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Thu, 26 Mar 2026 21:08:14 +0100 Subject: [PATCH] performance-metrics: Add QCOW2 overlay tempfile helper Add qcow_overlay_tempfile() which creates a raw backing file with pre-populated data and a QCOW2 overlay on top with no allocated clusters. The overlay is opened with backing file support via QcowDiskSync so reads fall through to the backing file. To be used by backing file read and copy-on-write write benchmarks. Signed-off-by: Anatol Belski --- performance-metrics/src/util.rs | 41 ++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/performance-metrics/src/util.rs b/performance-metrics/src/util.rs index 09d6ad7e6..3ba9a9eee 100644 --- a/performance-metrics/src/util.rs +++ b/performance-metrics/src/util.rs @@ -5,11 +5,12 @@ //! Shared benchmark helpers. use std::io::{ErrorKind, Seek, SeekFrom, Write}; +use std::os::unix::fs::FileExt; use std::thread; use std::time::Duration; use block::async_io::AsyncIo; -use block::qcow::{QcowFile, RawFile}; +use block::qcow::{BackingFileConfig, ImageType, QcowFile, RawFile}; use block::qcow_async::QcowDiskAsync; use block::qcow_sync::QcowDiskSync; use vmm_sys_util::eventfd::EventFd; @@ -143,6 +144,44 @@ pub fn empty_qcow_tempfile(num_clusters: usize) -> (TempFile, QcowDiskSync) { (tmp, disk) } +/// Create a QCOW2 overlay backed by a raw file with `num_clusters` +/// pre-populated clusters. Returns (backing_tempfile, overlay_tempfile). +fn create_overlay_tempfiles(num_clusters: usize) -> (TempFile, TempFile) { + let virtual_size = QCOW_CLUSTER_SIZE * num_clusters as u64; + + let backing = TempFile::new().expect("failed to create backing tempfile"); + { + let f = backing.as_file(); + f.set_len(virtual_size).expect("set_len failed"); + let buf = vec![0xA5u8; QCOW_CLUSTER_SIZE as usize]; + for i in 0..num_clusters { + f.write_at(&buf, i as u64 * QCOW_CLUSTER_SIZE) + .expect("write_at failed"); + } + } + + let overlay = TempFile::new().expect("failed to create overlay tempfile"); + { + let raw = RawFile::new(overlay.as_file().try_clone().unwrap(), false); + let backing_config = BackingFileConfig { + path: backing.as_path().to_str().unwrap().to_string(), + format: Some(ImageType::Raw), + }; + QcowFile::new_from_backing(raw, 3, virtual_size, &backing_config, true) + .expect("failed to create overlay qcow2"); + } + + (backing, overlay) +} + +/// QCOW2 overlay with raw backing opened via QcowDiskSync. +pub fn qcow_overlay_tempfile(num_clusters: usize) -> (TempFile, TempFile, QcowDiskSync) { + let (backing, overlay) = create_overlay_tempfiles(num_clusters); + let disk = QcowDiskSync::new(overlay.as_file().try_clone().unwrap(), false, true, true) + .expect("failed to open overlay qcow2 via QcowDiskSync"); + (backing, overlay, disk) +} + /// Spin and wait until the given eventfd becomes readable. pub fn wait_for_eventfd(notifier: &EventFd) { loop {