runtime-rs: every CH raw disk is preallocated to its full size since #13292
Description of problem
Since #13292 (a886f99a0), TryFrom<BlockConfigModern> for DiskConfig in src/runtime-rs/crates/hypervisor/src/ch/inner_device.rs sets sparse: blkcfg.discard_unmap. discard_unmap defaults to false and is only set by the block-plain emptyDir volume, so every other block device reaches Cloud Hypervisor as sparse=false. Cloud Hypervisor v51.0 (cloud-hypervisor/cloud-hypervisor@49a30cbbaf) preallocates a raw disk file with fallocate() when sparse=false, and Kata pins v51.1.
On a host with the runtime-rs shim and the Cloud Hypervisor config, as root:
# A sparse 4 GiB raw image. Only the ext4 metadata is allocated, about 33M.
truncate -s 4G /var/tmp/vol.img && mkfs.ext4 -q /var/tmp/vol.img
du -h /var/tmp/vol.img
# Register it as a direct volume behind the path /var/tmp/vol.
mkdir -p /var/tmp/vol
kata-ctl direct-volume add /var/tmp/vol '{"volume-type":"directvol","device":"/var/tmp/vol.img","fstype":"ext4","metadata":{},"options":[]}'
# Start a container that bind-mounts that path. The runtime attaches the image as a
# hot-plugged disk instead of sharing the directory.
ctr image pull docker.io/library/busybox:latest
ctr run --rm --runtime io.containerd.kata.v2 \
--mount type=bind,src=/var/tmp/vol,dst=/mnt,options=rbind \
docker.io/library/busybox:latest vol-test sh -c 'df -h /mnt'
# The allocation after the VMM opened the disk.
du -h /var/tmp/vol.img
filefrag -v /var/tmp/vol.img | head -5Expected result
The second du reports about the same as the first, and the host disk loses only what the guest writes.
Actual result
The second du reports the full 4.0G, and filefrag -v shows one large unwritten extent, which only fallocate() produces. strace -f -e trace=fallocate -p $(pidof containerd) during the start shows the call:
fallocate(129, 0, 0, 4294967296) = 0Measured today on a 4 GiB and an 8 GiB image attached to one pod: du went from 33M each to 4.1G and 8.1G. A 40 GiB host filled after three pods.
Further information
- Kata 4.1.0 static tarball, runtime-rs shim,
[hypervisor.clh],shared_fs = "none",block_device_driver = "virtio-blk-pci",rootless = true - Cloud Hypervisor v51.1 (the bundled binary), containerd 2.2.2, Ubuntu 26.04 arm64 guest under Lima on an Apple Silicon host
- The shim here is the 4.1.0 source rebuilt with one unrelated patch to
MemoryConfig.shared; thesparseline is the same as in the tarball's shim. - The Go runtime does not preallocate:
NewDiskConfig()in the generated Cloud Hypervisor client setsSparse = trueandclh.gonever overrides it. That is also Cloud Hypervisor's own default and the default inch-config. Cloud Hypervisor has one flag for both "advertise DISCARD" and "do not preallocate", so the only way to stopdiscard_unmap=falsedisks from preallocating is to stop mapping it ontosparse(#13865).
Source: kata-containers/kata-containers