mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: Add option to control backing files
Backing files (e.g. for QCOW2) interact badly with landlock since they are not obvious from the initial VM configuration. Only enable their use with an explicit option. Signed-off-by: Rob Bradford <rbradford@meta.com>
This commit is contained in:
@@ -788,6 +788,7 @@ pub trait AsyncAdaptor {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub enum ImageType {
|
||||
FixedVhd,
|
||||
Qcow2,
|
||||
|
||||
@@ -29,10 +29,19 @@ pub struct QcowDiskSync {
|
||||
}
|
||||
|
||||
impl QcowDiskSync {
|
||||
pub fn new(file: File, direct_io: bool) -> QcowResult<Self> {
|
||||
Ok(QcowDiskSync {
|
||||
qcow_file: Arc::new(Mutex::new(QcowFile::from(RawFile::new(file, direct_io))?)),
|
||||
})
|
||||
pub fn new(file: File, direct_io: bool, backing_files: bool) -> QcowResult<Self> {
|
||||
if backing_files {
|
||||
Ok(QcowDiskSync {
|
||||
qcow_file: Arc::new(Mutex::new(QcowFile::from(RawFile::new(file, direct_io))?)),
|
||||
})
|
||||
} else {
|
||||
Ok(QcowDiskSync {
|
||||
qcow_file: Arc::new(Mutex::new(QcowFile::from_with_nesting_depth(
|
||||
RawFile::new(file, direct_io),
|
||||
0,
|
||||
)?)),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3422,6 +3422,7 @@ mod common_parallel {
|
||||
disable_io_uring: bool,
|
||||
disable_aio: bool,
|
||||
verify_os_disk: bool,
|
||||
backing_files: bool,
|
||||
) {
|
||||
let disk_config = UbuntuDiskConfig::new(image_name.to_string());
|
||||
let guest = Guest::new(Box::new(disk_config));
|
||||
@@ -3448,8 +3449,9 @@ mod common_parallel {
|
||||
.args([
|
||||
"--disk",
|
||||
format!(
|
||||
"path={}",
|
||||
guest.disk_config.disk(DiskType::OperatingSystem).unwrap()
|
||||
"path={},backing_files={}",
|
||||
guest.disk_config.disk(DiskType::OperatingSystem).unwrap(),
|
||||
if backing_files { "on"} else {"off"}
|
||||
)
|
||||
.as_str(),
|
||||
format!(
|
||||
@@ -3528,17 +3530,17 @@ mod common_parallel {
|
||||
|
||||
#[test]
|
||||
fn test_virtio_block_io_uring() {
|
||||
_test_virtio_block(FOCAL_IMAGE_NAME, false, true, false);
|
||||
_test_virtio_block(FOCAL_IMAGE_NAME, false, true, false, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_virtio_block_aio() {
|
||||
_test_virtio_block(FOCAL_IMAGE_NAME, true, false, false);
|
||||
_test_virtio_block(FOCAL_IMAGE_NAME, true, false, false, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_virtio_block_sync() {
|
||||
_test_virtio_block(FOCAL_IMAGE_NAME, true, true, false);
|
||||
_test_virtio_block(FOCAL_IMAGE_NAME, true, true, false, false);
|
||||
}
|
||||
|
||||
fn run_qemu_img(path: &std::path::Path, args: &[&str]) -> std::process::Output {
|
||||
@@ -3768,22 +3770,28 @@ mod common_parallel {
|
||||
|
||||
#[test]
|
||||
fn test_virtio_block_qcow2() {
|
||||
_test_virtio_block(JAMMY_IMAGE_NAME_QCOW2, false, false, true);
|
||||
_test_virtio_block(JAMMY_IMAGE_NAME_QCOW2, false, false, true, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_virtio_block_qcow2_zlib() {
|
||||
_test_virtio_block(JAMMY_IMAGE_NAME_QCOW2_ZLIB, false, false, true);
|
||||
_test_virtio_block(JAMMY_IMAGE_NAME_QCOW2_ZLIB, false, false, true, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_virtio_block_qcow2_zstd() {
|
||||
_test_virtio_block(JAMMY_IMAGE_NAME_QCOW2_ZSTD, false, false, true);
|
||||
_test_virtio_block(JAMMY_IMAGE_NAME_QCOW2_ZSTD, false, false, true, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_virtio_block_qcow2_backing_zstd_file() {
|
||||
_test_virtio_block(JAMMY_IMAGE_NAME_QCOW2_BACKING_ZSTD_FILE, false, false, true);
|
||||
_test_virtio_block(
|
||||
JAMMY_IMAGE_NAME_QCOW2_BACKING_ZSTD_FILE,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -3793,12 +3801,19 @@ mod common_parallel {
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_virtio_block_qcow2_backing_raw_file() {
|
||||
_test_virtio_block(JAMMY_IMAGE_NAME_QCOW2_BACKING_RAW_FILE, false, false, true);
|
||||
_test_virtio_block(
|
||||
JAMMY_IMAGE_NAME_QCOW2_BACKING_RAW_FILE,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
/// Configuration for QCOW2 multiqueue test image setup
|
||||
@@ -3873,7 +3888,15 @@ mod common_parallel {
|
||||
"path={}",
|
||||
guest.disk_config.disk(DiskType::CloudInit).unwrap()
|
||||
),
|
||||
&format!("path={},num_queues=8", test_image_path.to_str().unwrap()),
|
||||
&format!(
|
||||
"path={},num_queues=8,backing_files={}",
|
||||
test_image_path.to_str().unwrap(),
|
||||
if initial_backing_checksum.is_some() {
|
||||
"on"
|
||||
} else {
|
||||
"off"
|
||||
},
|
||||
),
|
||||
])
|
||||
.default_net()
|
||||
.capture_output()
|
||||
@@ -4491,7 +4514,7 @@ mod common_parallel {
|
||||
.output()
|
||||
.expect("Expect generating VHD image from RAW image");
|
||||
|
||||
_test_virtio_block(FOCAL_IMAGE_NAME_VHD, false, false, false);
|
||||
_test_virtio_block(FOCAL_IMAGE_NAME_VHD, false, false, false, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -4515,7 +4538,7 @@ mod common_parallel {
|
||||
.output()
|
||||
.expect("Expect generating dynamic VHDx image from RAW image");
|
||||
|
||||
_test_virtio_block(FOCAL_IMAGE_NAME_VHDX, false, false, true);
|
||||
_test_virtio_block(FOCAL_IMAGE_NAME_VHDX, false, false, true, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1093,7 +1093,7 @@ impl DiskConfig {
|
||||
ops_size=<io_ops>,ops_one_time_burst=<io_ops>,ops_refill_time=<ms>,\
|
||||
id=<device_id>,pci_segment=<segment_id>,rate_limit_group=<group_id>,\
|
||||
queue_affinity=<list_of_queue_indices_with_their_associated_cpuset>,\
|
||||
serial=<serial_number>";
|
||||
serial=<serial_number>,backing_files=on|off";
|
||||
|
||||
pub fn parse(disk: &str) -> Result<Self> {
|
||||
let mut parser = OptionParser::new();
|
||||
@@ -1118,7 +1118,8 @@ impl DiskConfig {
|
||||
.add("pci_segment")
|
||||
.add("serial")
|
||||
.add("rate_limit_group")
|
||||
.add("queue_affinity");
|
||||
.add("queue_affinity")
|
||||
.add("backing_files");
|
||||
parser.parse(disk).map_err(Error::ParseDisk)?;
|
||||
|
||||
let path = parser.get("path").map(PathBuf::from);
|
||||
@@ -1203,6 +1204,12 @@ impl DiskConfig {
|
||||
})
|
||||
.collect()
|
||||
});
|
||||
let backing_files = parser
|
||||
.convert::<Toggle>("backing_files")
|
||||
.map_err(Error::ParseDisk)?
|
||||
.unwrap_or(Toggle(false))
|
||||
.0;
|
||||
|
||||
let bw_tb_config = if bw_size != 0 && bw_refill_time != 0 {
|
||||
Some(TokenBucketConfig {
|
||||
size: bw_size,
|
||||
@@ -1247,6 +1254,7 @@ impl DiskConfig {
|
||||
pci_segment,
|
||||
serial,
|
||||
queue_affinity,
|
||||
backing_files,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3414,6 +3422,7 @@ mod unit_tests {
|
||||
pci_segment: 0,
|
||||
serial: None,
|
||||
queue_affinity: None,
|
||||
backing_files: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2657,6 +2657,10 @@ impl DeviceManager {
|
||||
let image_type =
|
||||
detect_image_type(&mut file).map_err(DeviceManagerError::DetectImageType)?;
|
||||
|
||||
if image_type != ImageType::Qcow2 && disk_cfg.backing_files {
|
||||
warn!("Enabling backing_files option only applies for QCOW2 files");
|
||||
}
|
||||
|
||||
let image = match image_type {
|
||||
ImageType::FixedVhd => {
|
||||
// Use asynchronous backend relying on io_uring if the
|
||||
@@ -2710,7 +2714,7 @@ impl DeviceManager {
|
||||
ImageType::Qcow2 => {
|
||||
info!("Using synchronous QCOW2 disk file");
|
||||
Box::new(
|
||||
QcowDiskSync::new(file, disk_cfg.direct)
|
||||
QcowDiskSync::new(file, disk_cfg.direct, disk_cfg.backing_files)
|
||||
.map_err(DeviceManagerError::CreateQcowDiskSync)?,
|
||||
) as Box<dyn DiskFile>
|
||||
}
|
||||
|
||||
@@ -284,6 +284,8 @@ pub struct DiskConfig {
|
||||
pub serial: Option<String>,
|
||||
#[serde(default)]
|
||||
pub queue_affinity: Option<Vec<VirtQueueAffinity>>,
|
||||
#[serde(default)]
|
||||
pub backing_files: bool,
|
||||
}
|
||||
|
||||
impl ApplyLandlock for DiskConfig {
|
||||
|
||||
Reference in New Issue
Block a user