block: Add supports_zero_flag trait method

Add supports_zero_flag() to DiskFile trait to indicate whether a disk
format can mark clusters/blocks as reading zeros without deallocating
storage.

QCOW2 supports this via the zero flag in L2 entries. VHDX also has
PAYLOAD_BLOCK_ZERO state for this, though it's not yet implemented in
cloud-hypervisor.

This enables DISCARD to be advertised even with sparse=false for formats
with zero-flag support, since they can mark regions as zeros (keeps
storage allocated) instead of requiring full deallocation.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
This commit is contained in:
Anatol Belski 2026-02-02 00:04:20 +01:00 committed by Rob Bradford
parent 7dfcbff309
commit 46e6ecddfe
3 changed files with 21 additions and 4 deletions

View file

@ -84,6 +84,12 @@ pub trait DiskFile: Send {
false
}
/// Indicates support for zero flag optimization in WRITE_ZEROES. Override
/// to return true when supported.
fn supports_zero_flag(&self) -> bool {
false
}
/// Returns the file descriptor of the underlying disk image file.
///
/// The file descriptor is supposed to be used for `fcntl()` calls but no

View file

@ -80,6 +80,10 @@ impl DiskFile for QcowDiskSync {
true
}
fn supports_zero_flag(&self) -> bool {
true
}
fn fd(&mut self) -> BorrowedDiskFd<'_> {
BorrowedDiskFd::new(self.qcow_file.lock().unwrap().as_raw_fd())
}

View file

@ -672,7 +672,7 @@ impl Block {
exit_evt: EventFd,
state: Option<BlockState>,
queue_affinity: BTreeMap<u16, Vec<usize>>,
_sparse: bool,
sparse: bool,
) -> io::Result<Self> {
let (disk_nsectors, avail_features, acked_features, config, paused) =
if let Some(state) = state {
@ -704,10 +704,17 @@ impl Block {
| (1u64 << VIRTIO_RING_F_EVENT_IDX)
| (1u64 << VIRTIO_RING_F_INDIRECT_DESC);
// Only advertise discard/write zeroes if the backend supports sparse operations
// When backend supports sparse operations:
// - Always advertise WRITE_ZEROES
// - Advertise DISCARD only if sparse=true OR format supports marking
// clusters as zero without deallocating
if disk_image.supports_sparse_operations() {
avail_features |=
(1u64 << VIRTIO_BLK_F_DISCARD) | (1u64 << VIRTIO_BLK_F_WRITE_ZEROES);
avail_features |= 1u64 << VIRTIO_BLK_F_WRITE_ZEROES;
if sparse || disk_image.supports_zero_flag() {
avail_features |= 1u64 << VIRTIO_BLK_F_DISCARD;
}
} else if sparse {
warn!("sparse=on requested but backend does not support sparse operations");
}
if iommu {