From 89509fd3ea193d8d7a1f4fa457223baf675cfbc2 Mon Sep 17 00:00:00 2001 From: Alex Lyn Date: Mon, 13 Jul 2026 11:14:40 +0800 Subject: [PATCH] runtime-rs: Gate block emptyDir discard by hypervisor capability Only enable discard for block-plain emptyDir volumes when the hypervisor reports block device discard support. The resource manager now queries hypervisor capabilities once and passes block discard support through VolumeContext. Block emptyDir volume setup uses that capability to decide whether to add the discard mount option and related mount metadata, avoiding unsupported discard mounts on hypervisors that cannot expose discard/unmap to the guest. It will correctly adjust the related codes with the new support. Signed-off-by: Alex Lyn --- .../crates/resource/src/manager_inner.rs | 8 ++--- .../src/volume/block_emptydir_volume.rs | 34 +++++++++++++++---- .../crates/resource/src/volume/mod.rs | 13 +++++-- 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/src/runtime-rs/crates/resource/src/manager_inner.rs b/src/runtime-rs/crates/resource/src/manager_inner.rs index d1b063060d..8551aab78e 100644 --- a/src/runtime-rs/crates/resource/src/manager_inner.rs +++ b/src/runtime-rs/crates/resource/src/manager_inner.rs @@ -492,17 +492,15 @@ impl ResourceManagerInner { cid: &str, spec: &oci::Spec, ) -> Result>> { + let capabilities = self.hypervisor.capabilities().await?; let ctx = crate::volume::VolumeContext { share_fs: &self.share_fs, d: self.device_manager.as_ref(), sid: &self.sid, agent: self.agent.clone(), emptydir_mode: &self.toml_config.runtime.emptydir_mode, - fs_sharing_supported: self - .hypervisor - .capabilities() - .await? - .is_fs_sharing_supported(), + fs_sharing_supported: capabilities.is_fs_sharing_supported(), + block_device_discard_supported: capabilities.is_block_device_discard_supported(), }; self.volume_resource.handler_volumes(&ctx, cid, spec).await } diff --git a/src/runtime-rs/crates/resource/src/volume/block_emptydir_volume.rs b/src/runtime-rs/crates/resource/src/volume/block_emptydir_volume.rs index a4b74d77b8..da7b9ffbd1 100644 --- a/src/runtime-rs/crates/resource/src/volume/block_emptydir_volume.rs +++ b/src/runtime-rs/crates/resource/src/volume/block_emptydir_volume.rs @@ -60,9 +60,11 @@ impl BlockEmptyDirVolume { m: &oci::Mount, sid: &str, emptydir_mode: &str, + block_device_discard_supported: bool, ) -> Result { let encrypted = emptydir_mode == EMPTYDIR_MODE_BLOCK_ENCRYPTED; - let discard_unmap = emptydir_mode == EMPTYDIR_MODE_BLOCK_PLAIN; + let discard_unmap = + emptydir_mode == EMPTYDIR_MODE_BLOCK_PLAIN && block_device_discard_supported; let source = m .source() .as_ref() @@ -127,7 +129,7 @@ impl BlockEmptyDirVolume { mount.set_typ(Some("bind".to_string())); let mut storage = storage; - configure_block_emptydir_storage(&mut storage, encrypted); + configure_block_emptydir_storage(&mut storage, encrypted, discard_unmap); // Mirror the Go runtime's handleBlkOCIMounts: the agent mounts the // block device at $(spath)/$(b64_device_id) which genpolicy expands to @@ -188,7 +190,11 @@ fn block_emptydir_mount_options(discard_unmap: bool) -> Vec { } } -fn configure_block_emptydir_storage(storage: &mut agent::Storage, encrypted: bool) { +fn configure_block_emptydir_storage( + storage: &mut agent::Storage, + encrypted: bool, + discard_unmap: bool, +) { if encrypted { storage.driver_options.push(format!( "{}={}", @@ -198,7 +204,7 @@ fn configure_block_emptydir_storage(storage: &mut agent::Storage, encrypted: boo storage .driver_options .push(KATA_BLOCK_VOLUME_CREATE_FS.to_string()); - if !encrypted { + if discard_unmap { storage.options.push(DISCARD_MOUNT_OPTION.to_string()); } storage.shared = true; @@ -283,7 +289,7 @@ mod tests { let mut storage = agent::Storage::default(); - configure_block_emptydir_storage(&mut storage, false); + configure_block_emptydir_storage(&mut storage, false, true); assert_eq!( storage.driver_options, @@ -293,6 +299,22 @@ mod tests { assert!(storage.shared); } + #[test] + fn block_plain_emptydir_skips_discard_when_hypervisor_cannot_expose_it() { + assert!(block_emptydir_mount_options(false).is_empty()); + + let mut storage = agent::Storage::default(); + + configure_block_emptydir_storage(&mut storage, false, false); + + assert_eq!( + storage.driver_options, + vec![KATA_BLOCK_VOLUME_CREATE_FS.to_string()] + ); + assert!(storage.options.is_empty()); + assert!(storage.shared); + } + #[test] fn block_encrypted_emptydir_requests_encryption_and_filesystem_creation() { let metadata = block_emptydir_metadata(true, 0); @@ -310,7 +332,7 @@ mod tests { let mut storage = agent::Storage::default(); - configure_block_emptydir_storage(&mut storage, true); + configure_block_emptydir_storage(&mut storage, true, false); assert_eq!( storage.driver_options, diff --git a/src/runtime-rs/crates/resource/src/volume/mod.rs b/src/runtime-rs/crates/resource/src/volume/mod.rs index b2cfc258a0..c8a8c03bb5 100644 --- a/src/runtime-rs/crates/resource/src/volume/mod.rs +++ b/src/runtime-rs/crates/resource/src/volume/mod.rs @@ -39,6 +39,7 @@ pub struct VolumeContext<'a> { pub agent: Arc, pub emptydir_mode: &'a str, pub fs_sharing_supported: bool, + pub block_device_discard_supported: bool, } #[async_trait] @@ -101,9 +102,15 @@ impl VolumeResource { .with_context(|| format!("new ephemeral volume {m:?}"))?, ) } else if block_emptydir_volume::is_block_emptydir_volume(m, emptydir_mode) { - let vol = block_emptydir_volume::BlockEmptyDirVolume::new(d, m, sid, emptydir_mode) - .await - .with_context(|| format!("new block emptydir volume {m:?}"))?; + let vol = block_emptydir_volume::BlockEmptyDirVolume::new( + d, + m, + sid, + emptydir_mode, + ctx.block_device_discard_supported, + ) + .await + .with_context(|| format!("new block emptydir volume {m:?}"))?; let vol_arc: Arc = Arc::new(vol.clone()); let mut inner = self.inner.write().await; inner.ephemeral_disks.push(vol.disk_info);