Cloud Hypervisor 使用 virtio-fs 实现宿主机与虚拟机目录共享:从 virtiofsd 配置到内核挂载全指南
【免费下载链接】cloud-hypervisorA Virtual Machine Monitor for modern Cloud workloads. Features include CPU, memory and device hotplug, support for running Windows and Linux guests, device offload with vhost-user and a minimal compact footprint. Written in Rust with a strong focus on security.项目地址: https://gitcode.com/GitHub_Trending/cl/cloud-hypervisor
导读
本文介绍如何在 Cloud Hypervisor 中通过 virtio-fs(即 vhost-user-fs)将宿主机目录共享给虚拟机使用。virtio-fs 是由 VIRTIO 规范定义的虚拟设备,它借助 vhost-user 协议把文件系统后端模拟卸载到宿主机上的独立守护进程 virtiofsd 中运行。读完本文,你将掌握 virtiofsd 的构建与运行参数(cache 模式、线程池大小)、Cloud Hypervisor--fs命令行配置(tag、socket、队列参数)、虚拟机内mount -t virtiofs的挂载流程,以及 DAX 特性的可用性边界,并能结合源码理解每个参数背后的校验逻辑与默认值。
virtio-fs 是什么
在虚拟化场景中,宿主机与客户机之间的目录共享一直是高频需求——无论是开发调试、日志收集,还是容器编排中的持久化存储,都需要一种安全、高效、低开销的共享方案。virtio-fs(也称vhost-user-fs)正是为此设计的 VIRTIO 虚拟设备,它允许任意 VMM(虚拟机监视器)提供文件系统共享能力。
它的核心设计在于"前端/后端分离":设备的前端(virtio 队列与 PCI 设备)由 VMM 侧实现,而后端(真实文件系统的 I/O 模拟)则通过vhost-user协议委托给宿主机上一个专用守护进程执行。这种 offload 架构让文件系统实现与 VMM 解耦,也便于复用成熟的 FUSE/文件系统栈。在 Cloud Hypervisor 仓库中,前端设备实现位于 virtio-devices/src/vhost_user/fs.rs,设备类型注册为VirtioDeviceType::Fs,并通过 vmm/src/device_manager.rs 的make_virtio_fs_device()在 VM 启动时实例化。
前置条件
守护进程 virtiofsd
virtio-fs 依赖 vhost-user 协议,即设备模拟(后端)由宿主机上一个专用进程承担,这个进程就是virtiofsd。在启动 Cloud Hypervisor 之前,必须先确保 virtiofsd 已构建并运行在宿主机上。
构建 virtiofsd
git clone https://gitlab.com/virtio-fs/virtiofsd pushd virtiofsd cargo build --release sudo setcap cap_sys_admin+epi target/release/virtiofsd说明:
setcap cap_sys_admin+epi为 virtiofsd 授予必要的CAP_SYS_ADMIN能力,使其能够在宿主机上完成与 VMM 共享内存相关的操作。
创建共享目录
mkdir /tmp/shared_dir运行 virtiofsd
./virtiofsd \ --log-level debug \ --socket-path=/tmp/virtiofs \ --shared-dir=/tmp/shared_dir \ --cache=never \ --thread-pool-size=$N几个关键参数说明:
--socket-path:vhost-user 的 unix socket 路径,Cloud Hypervisor 侧--fs socket=必须与之一致;--shared-dir:宿主机上要共享出去的目录,例如/tmp/shared_dir;--cache:控制宿主页面缓存(page cache)的使用策略;--thread-pool-size:virtiofsd 内部 I/O 线程池大小。
关于--cache模式
cache=never是与 Cloud Hypervisor 配合时的默认(推荐)选项。它禁止使用宿主页面缓存,从而降低对宿主机内存的占用,减少"单台宿主机可承载的虚拟机密度"被缓存拖累的风险——这正是"尽可能小 footprint"的体现,有助于在一台宿主机上启动更多虚拟机。cache=always允许使用宿主页面缓存,guest 的工作负载可能获得更好的性能,但代价是宿主机内存 footprint 上升。
关于--thread-pool-size
该参数控制 virtiofsd 派生多少个 I/O 线程。对于 NVMe 这类非常快速的存储,线程数不足会成为瓶颈,只有派生足够的工作线程,才能获得接近原生文件系统的性能。
内核支持
virtio-fs 需要 guest 内核提供virtiofs文件系统驱动。现代 Linux 内核(至少 v5.10)已原生支持 virtio-fs;带额外补丁的旧内核不受支持。同时,Cloud Hypervisor 侧要求 guest 镜像内包含足够新的内核,无论采用直接内核引导(direct kernel boot)还是 EFI 固件引导,都可以配合 virtio-fs 使用。
用 Cloud Hypervisor 共享目录
启动虚拟机
virtiofsd 运行后,在 Cloud Hypervisor 命令行使用--fs选项即可为虚拟机挂载该共享设备。
这里有一个硬性前提:--fs正常工作要求--memory开启shared=on,以便在 virtiofsd(后端进程)与 VMM 之间进行跨进程内存共享。
假设宿主机上已有focal-server-cloudimg-amd64.raw磁盘镜像和vmlinux内核,一个可运行的 Cloud Hypervisor 命令如下:
./cloud-hypervisor \ --cpus boot=1 \ --memory size=1G,shared=on \ --disk path=focal-server-cloudimg-amd64.raw,image_type=raw \ --kernel vmlinux \ --cmdline "console=hvc0 root=/dev/vda1 rw" \ --fs tag=myfs,socket=/tmp/virtiofs,num_queues=1,queue_size=512其中--fs的参数完整语法(定义于 vmm/src/config.rs 的FsConfig::SYNTAX)为:
tag=<tag_name>,socket=<socket_path>,num_queues=<number_of_queues>,queue_size=<size_of_each_queue>,id=<device_id>,pci_segment=<segment_id>,pci_device_id=<pci_slot>各参数解析与校验逻辑均可从源码得到印证(vmm/src/config.rsFsConfig::parse/validate):
| 参数 | 含义 | 默认值与约束 |
|---|---|---|
tag | 共享文件系统的标签,guest 挂载时使用;必填 | 长度不能超过VIRTIO_FS_TAG_LEN(36 字节),超长报ParseFsTagTooLong;该常量定义于 virtio-devices/src/vhost_user/fs.rs |
socket | vhost-user socket 路径;必填 | 必须与 virtiofsd--socket-path一致;Landlock 沙箱模式下会为它授予rw访问规则(见 vmm/src/vm_config.rsApplyLandlock for FsConfig) |
num_queues | 请求队列数量 | 默认1;不能超过--cpus boot=指定的 vCPU 数,否则报TooManyQueues |
queue_size | 每个 virtio 队列的项数 | 默认1024;必须是 2 的幂(validate_queue_size),否则报InvalidQueueSize |
id | 设备 ID(可选) | 缺省时由make_virtio_fs_device()自动生成(前缀见FS_DEVICE_NAME_PREFIX) |
pci_segment/pci_device_id | PCI 段与槽位(可选) | 用于多 PCI 段拓扑中的设备定位 |
iommu | 不支持 | 若开启会返回IommuNotSupported校验错误 |
默认值定义于 vmm/src/vm_config.rs(default_fsconfig_num_queues() -> 1、default_fsconfig_queue_size() -> 1024),并在 vmm/src/config.rs 的parse中通过unwrap_or_else兜底。
队列数量背后的实现细节
从源码看(virtio-devices/src/vhost_user/fs.rsFs::new),实际生效的 virtio 队列数为:
实际队列数 = NUM_QUEUE_OFFSET(1) + num_queues即除了--fs num_queues=指定的请求队列外,virtio-fs 规范还要求一个额外的队列(通常承载高优先级请求/通知)。同时,设备在协商阶段会通告MQ(多队列)、CONFIGURE_MEM_SLOTS、REPLY_ACK、INFLIGHT_SHMFD、LOG_SHMFD、DEVICE_STATE等 vhost-user 协议特性,并会查询后端(virtiofsd)支持的最大队列数;如果请求的队列数超过后端能力,会返回BadQueueNum错误并打印日志vhost-user-fs requested too many queues。
另外需要留意:--fs设备默认不开启 vhost-user 直通内存之外的访问平台特性,force_access_platform仅在全局强制时才会置位VIRTIO_F_ACCESS_PLATFORM。
在 guest 内挂载共享目录
最后一步是在客户机内部使用virtiofs文件系统类型挂载共享目录:
mkdir mount_dir mount -t virtiofs myfs mount_dir/其中的tag(此处为myfs)必须与 Cloud Hypervisor 命令行--fs tag=提供的一致,两者对不上将无法正确找到设备。
DAX 特性
virtio-fs 的 DAX(直接访问,将宿主页面缓存以 mmap 方式暴露给 guest,从而让 guest 直接访问文件数据页)特性由于在 virtiofsd 一侧尚未稳定,因此Cloud Hypervisor 中不可用。在 virtio-devices/src/vhost_user/fs.rs 的设备实现中也没有为 DAX 预留共享内存区域——cache字段与get_shm_regions()/userspace_mappings()相关的共享内存能力均围绕通用 vhost-user 机制设计,而非 DAX 缓存窗口。选择cache=never也能进一步降低 host 内存占用,从侧面弱化了在 Cloud Hypervisor 场景下对 DAX 的需求。
更多资源
- 以 virtio-fs 作为根文件系统启动 guest 的完整示例,可参考 docs/virtiofs-root.md;
- 若需要了解 Cloud Hypervisor 中其他 vhost-user 后端(块、网络等)的通用协议处理,可阅读 virtio-devices/src/vhost_user/vu_common_ctrl.rs;
FsConfig的解析单测(含缺失tag/socket报错、多队列参数解析、非法配置拒绝等场景)位于 vmm/src/config.rs 的fs_fixture及附近测试代码中,可作为排查命令行参数问题的参考。
【免费下载链接】cloud-hypervisorA Virtual Machine Monitor for modern Cloud workloads. Features include CPU, memory and device hotplug, support for running Windows and Linux guests, device offload with vhost-user and a minimal compact footprint. Written in Rust with a strong focus on security.项目地址: https://gitcode.com/GitHub_Trending/cl/cloud-hypervisor
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考