From 0d5bde2181d65a684ddd08e4085339cc29882a7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Bombo?= Date: Fri, 1 May 2026 15:10:04 -0500 Subject: [PATCH 1/2] runtime-rs: virtio-fs: plumb virtio_fs_queue_size to qemu/CH MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The shared filesystem device builder in `prepare_virtiofs` was hardcoding `queue_size = 0` and `queue_num = 0` on the `ShareFsConfig` it hands to the hypervisor, ignoring `SharedFsInfo.virtio_fs_queue_size` parsed from `configuration.toml` entirely. For qemu, this is silently broken: the cmdline generator's `DeviceVhostUserFs::set_queue_size` treats 0 as "not set" and skips the `queue-size=` argument when emitting the `vhost-user-fs-pci` device, so QEMU falls back to its built-in default of 128, regardless of what the user configured. For Cloud Hypervisor it happens to work in practice today, but only because `ch::handle_share_fs_device` and `TryFrom for FsConfig` substitute a hardcoded 1024 when the incoming `queue_num`/`queue_size` are zero. That fallback masks the real bug; the toml value still never reaches the VMM. Add a `get_shared_fs_info` accessor on `DeviceManager` mirroring the existing `get_block_device_info` helper, and use it in `prepare_virtiofs` to populate `ShareFsConfig.queue_size` from `SharedFsInfo.virtio_fs_queue_size`. Use a single virtqueue (`queue_num = 1`), matching what runtime-go hardcodes for both qemu (govmm `QemuFSParams` does not emit `num-queues=`) and CH (`numQueues := int32(1)` in `clh.go`). The CH-side fallback and the CH config template are addressed in a follow-up commit. Signed-off-by: Aurélien Bombo --- .../crates/hypervisor/src/device/device_manager.rs | 10 +++++++++- .../crates/resource/src/share_fs/share_virtio_fs.rs | 10 +++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/runtime-rs/crates/hypervisor/src/device/device_manager.rs b/src/runtime-rs/crates/hypervisor/src/device/device_manager.rs index 864494f2e4..78c5a02166 100644 --- a/src/runtime-rs/crates/hypervisor/src/device/device_manager.rs +++ b/src/runtime-rs/crates/hypervisor/src/device/device_manager.rs @@ -12,7 +12,7 @@ use std::{ use anyhow::{anyhow, Context, Result}; use kata_sys_util::rand::RandomBytes; -use kata_types::config::hypervisor::{BlockDeviceInfo, TopologyConfigInfo, VIRTIO_SCSI}; +use kata_types::config::hypervisor::{BlockDeviceInfo, SharedFsInfo, TopologyConfigInfo, VIRTIO_SCSI}; use tokio::sync::{Mutex, RwLock}; use crate::{ @@ -126,6 +126,10 @@ impl DeviceManager { self.hypervisor.hypervisor_config().await.blockdev_info } + async fn get_shared_fs_info(&self) -> SharedFsInfo { + self.hypervisor.hypervisor_config().await.shared_fs + } + async fn try_add_device(&mut self, device_id: &str) -> Result<()> { // find the device let device = self @@ -714,6 +718,10 @@ pub async fn get_block_device_info(d: &RwLock) -> BlockDeviceInfo d.read().await.get_block_device_info().await } +pub async fn get_shared_fs_info(d: &RwLock) -> SharedFsInfo { + d.read().await.get_shared_fs_info().await +} + #[cfg(test)] mod tests { use super::DeviceManager; diff --git a/src/runtime-rs/crates/resource/src/share_fs/share_virtio_fs.rs b/src/runtime-rs/crates/resource/src/share_fs/share_virtio_fs.rs index 8328355ed5..b665846028 100644 --- a/src/runtime-rs/crates/resource/src/share_fs/share_virtio_fs.rs +++ b/src/runtime-rs/crates/resource/src/share_fs/share_virtio_fs.rs @@ -12,7 +12,7 @@ use tokio::sync::RwLock; use hypervisor::{ device::{ - device_manager::{do_handle_device, do_update_device, DeviceManager}, + device_manager::{do_handle_device, do_update_device, get_shared_fs_info, DeviceManager}, driver::{ShareFsMountConfig, ShareFsMountOperation, ShareFsMountType}, DeviceConfig, }, @@ -54,8 +54,12 @@ pub(crate) async fn prepare_virtiofs( sock_path: generate_sock_path(root), mount_tag: String::from(MOUNT_GUEST_TAG), fs_type: fs_type.to_string(), - queue_size: 0, - queue_num: 0, + // Pull virtio-fs queue size from the hypervisor config so the value + // configured via `virtio_fs_queue_size` in the toml actually reaches + // the VMM device line. There is currently no toml knob for the number + // of virtqueues, so we use a single queue (matching the prior default). + queue_size: get_shared_fs_info(d).await.virtio_fs_queue_size as u64, + queue_num: 1, options: vec![], mount_config: None, }; From e2240b694a648019f6c44637f049e63200074b24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Bombo?= Date: Fri, 1 May 2026 15:11:42 -0500 Subject: [PATCH 2/2] runtime-rs: ch: source virtio-fs queue size from toml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that `prepare_virtiofs` populates `ShareFsConfig` from `SharedFsInfo.virtio_fs_queue_size`, the CH-side fallback that substitutes `DEFAULT_FS_QUEUE_SIZE` (1024) when the incoming `queue_num`/`queue_size` are zero is no longer needed. Drop it from both `handle_share_fs_device` and `TryFrom for FsConfig` and use the values straight from the config. Drop the now unused `DEFAULT_FS_QUEUES` and `DEFAULT_FS_QUEUE_SIZE` constants. This also removes a latent bug in both call sites: the previous code gated `queue_size` on `queue_num > 0`, so a user setting only the queue size and not the (currently unconfigurable) queue count would have had their `queue_size` silently overwritten by the default. The CH config template (`configuration-clh-runtime-rs.toml.in`) did not ship the `virtio_fs_queue_size` key (unlike the qemu-runtime-rs templates), so without an explicit override the field would have deserialized to 0 and the fallback would have been the only thing keeping CH working. Add the key to the template, defaulted to `@DEFVIRTIOFSQUEUESIZE@` (1024), matching the qemu-runtime-rs templates. Signed-off-by: Aurélien Bombo --- .../configuration-clh-runtime-rs.toml.in | 3 ++ .../crates/hypervisor/src/ch/inner_device.rs | 29 +++---------------- 2 files changed, 7 insertions(+), 25 deletions(-) diff --git a/src/runtime-rs/config/configuration-clh-runtime-rs.toml.in b/src/runtime-rs/config/configuration-clh-runtime-rs.toml.in index 49fbd1bb71..928130ea37 100644 --- a/src/runtime-rs/config/configuration-clh-runtime-rs.toml.in +++ b/src/runtime-rs/config/configuration-clh-runtime-rs.toml.in @@ -97,6 +97,9 @@ virtio_fs_daemon = "@DEFVIRTIOFSDAEMON@" # Default size of DAX cache in MiB virtio_fs_cache_size = @DEFVIRTIOFSCACHESIZE@ +# Default size of virtqueues +virtio_fs_queue_size = @DEFVIRTIOFSQUEUESIZE@ + # Extra args for virtiofsd daemon # # Format example: diff --git a/src/runtime-rs/crates/hypervisor/src/ch/inner_device.rs b/src/runtime-rs/crates/hypervisor/src/ch/inner_device.rs index c0c621d886..2337d50ebe 100644 --- a/src/runtime-rs/crates/hypervisor/src/ch/inner_device.rs +++ b/src/runtime-rs/crates/hypervisor/src/ch/inner_device.rs @@ -45,9 +45,6 @@ use std::path::PathBuf; const VIRTIO_FS: &str = "virtio-fs"; -pub const DEFAULT_FS_QUEUES: usize = 1; -const DEFAULT_FS_QUEUE_SIZE: u16 = 1024; - impl CloudHypervisorInner { pub(crate) async fn add_device(&mut self, device: DeviceType) -> Result { if self.state != VmmState::VmRunning { @@ -143,17 +140,8 @@ impl CloudHypervisorInner { )); } - let num_queues: usize = if device.config.queue_num > 0 { - device.config.queue_num as usize - } else { - DEFAULT_FS_QUEUES - }; - - let queue_size: u16 = if device.config.queue_num > 0 { - u16::try_from(device.config.queue_size)? - } else { - DEFAULT_FS_QUEUE_SIZE - }; + let num_queues = device.config.queue_num as usize; + let queue_size = u16::try_from(device.config.queue_size)?; let socket_path = if device.config.sock_path.starts_with('/') { PathBuf::from(device.config.sock_path) @@ -545,17 +533,8 @@ impl TryFrom for FsConfig { let cfg = settings.cfg; let vm_path = settings.vm_path; - let num_queues: usize = if cfg.queue_num > 0 { - cfg.queue_num as usize - } else { - DEFAULT_FS_QUEUES - }; - - let queue_size: u16 = if cfg.queue_num > 0 { - u16::try_from(cfg.queue_size)? - } else { - DEFAULT_FS_QUEUE_SIZE - }; + let num_queues = cfg.queue_num as usize; + let queue_size = u16::try_from(cfg.queue_size)?; let socket_path = if cfg.sock_path.starts_with('/') { PathBuf::from(cfg.sock_path)