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 <anbelski@linux.microsoft.com>
This commit is contained in:
Anatol Belski 2026-01-30 16:18:29 +01:00 committed by Rob Bradford
parent 7f4b56b217
commit 7dfcbff309
5 changed files with 19 additions and 2 deletions

View file

@ -67,6 +67,7 @@ fuzz_target!(|bytes: &[u8]| -> Corpus {
EventFd::new(EFD_NONBLOCK).unwrap(),
None,
queue_affinity,
true,
)
.unwrap();

View file

@ -672,6 +672,7 @@ impl Block {
exit_evt: EventFd,
state: Option<BlockState>,
queue_affinity: BTreeMap<u16, Vec<usize>>,
_sparse: bool,
) -> io::Result<Self> {
let (disk_nsectors, avail_features, acked_features, config, paused) =
if let Some(state) = state {

View file

@ -1096,7 +1096,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>,backing_files=on|off";
serial=<serial_number>,backing_files=on|off,sparse=on|off";
pub fn parse(disk: &str) -> Result<Self> {
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::<Toggle>("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,
}
}

View file

@ -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)?;

View file

@ -286,6 +286,8 @@ pub struct DiskConfig {
pub queue_affinity: Option<Vec<VirtQueueAffinity>>,
#[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")]