From 7dfcbff309887507022219cabbd711478fa27e0c Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Fri, 30 Jan 2026 16:18:29 +0100 Subject: [PATCH] vmm: config: Add sparse flag to control disk space allocation Add sparse boolean configuration option to DiskConfig with a default value of true to control disk space allocation behavior. When sparse is true, the disk uses sparse allocation where deallocated blocks are returned to the filesystem, and the DISCARD feature is advertised to the guest. When sparse is false, disk space is kept fully allocated and DISCARD is not advertised. WRITE_ZEROES is always advertised when the backend supports it, regardless of the sparse setting. Signed-off-by: Anatol Belski --- fuzz/fuzz_targets/block.rs | 1 + virtio-devices/src/block.rs | 1 + vmm/src/config.rs | 12 ++++++++++-- vmm/src/device_manager.rs | 1 + vmm/src/vm_config.rs | 6 ++++++ 5 files changed, 19 insertions(+), 2 deletions(-) diff --git a/fuzz/fuzz_targets/block.rs b/fuzz/fuzz_targets/block.rs index c06f0dea2..be461d7a7 100644 --- a/fuzz/fuzz_targets/block.rs +++ b/fuzz/fuzz_targets/block.rs @@ -67,6 +67,7 @@ fuzz_target!(|bytes: &[u8]| -> Corpus { EventFd::new(EFD_NONBLOCK).unwrap(), None, queue_affinity, + true, ) .unwrap(); diff --git a/virtio-devices/src/block.rs b/virtio-devices/src/block.rs index 7de45bc1b..e05900b5a 100644 --- a/virtio-devices/src/block.rs +++ b/virtio-devices/src/block.rs @@ -672,6 +672,7 @@ impl Block { exit_evt: EventFd, state: Option, queue_affinity: BTreeMap>, + _sparse: bool, ) -> io::Result { let (disk_nsectors, avail_features, acked_features, config, paused) = if let Some(state) = state { diff --git a/vmm/src/config.rs b/vmm/src/config.rs index abadbb936..8a8d637fd 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -1096,7 +1096,7 @@ impl DiskConfig { ops_size=,ops_one_time_burst=,ops_refill_time=,\ id=,pci_segment=,rate_limit_group=,\ queue_affinity=,\ - serial=,backing_files=on|off"; + serial=,backing_files=on|off,sparse=on|off"; pub fn parse(disk: &str) -> Result { let mut parser = OptionParser::new(); @@ -1122,7 +1122,8 @@ impl DiskConfig { .add("serial") .add("rate_limit_group") .add("queue_affinity") - .add("backing_files"); + .add("backing_files") + .add("sparse"); parser.parse(disk).map_err(Error::ParseDisk)?; let path = parser.get("path").map(PathBuf::from); @@ -1239,6 +1240,11 @@ impl DiskConfig { } else { None }; + let sparse = parser + .convert::("sparse") + .map_err(Error::ParseDisk)? + .unwrap_or_else(|| Toggle(default_diskconfig_sparse())) + .0; Ok(DiskConfig { path, @@ -1258,6 +1264,7 @@ impl DiskConfig { serial, queue_affinity, backing_files, + sparse, }) } @@ -3508,6 +3515,7 @@ mod unit_tests { serial: None, queue_affinity: None, backing_files: false, + sparse: true, } } diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 0a88b4400..a78e2ab2f 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -2799,6 +2799,7 @@ impl DeviceManager { state_from_id(self.snapshot.as_ref(), id.as_str()) .map_err(DeviceManagerError::RestoreGetState)?, queue_affinity, + disk_cfg.sparse, ) .map_err(DeviceManagerError::CreateVirtioBlock)?; diff --git a/vmm/src/vm_config.rs b/vmm/src/vm_config.rs index e0e74cb4a..407d4e491 100644 --- a/vmm/src/vm_config.rs +++ b/vmm/src/vm_config.rs @@ -286,6 +286,8 @@ pub struct DiskConfig { pub queue_affinity: Option>, #[serde(default)] pub backing_files: bool, + #[serde(default = "default_diskconfig_sparse")] + pub sparse: bool, } impl ApplyLandlock for DiskConfig { @@ -309,6 +311,10 @@ pub fn default_diskconfig_queue_size() -> u16 { DEFAULT_DISK_QUEUE_SIZE } +pub fn default_diskconfig_sparse() -> bool { + true +} + #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] pub struct NetConfig { #[serde(default = "default_netconfig_tap")]