OFFSET偏移
← 文章目录OFFSET / FIELD NOTESNO. 139

KVM 的固件、VFIO、virtiofs 与镜像链

解释高级参数的作用,并为直通、镜像修改和共享目录补齐兼容性与恢复条件。

所在专题KVM 高级能力与平台选择 ↗
约 50 分钟阅读开始阅读

命令与 XML 使用通用示例,需按宿主版本和实际资源调整。网络地址采用文档地址段,实际部署应选择不冲突的私网;镜像修改与设备直通的适用条件见对应章节。

从基础虚拟化到生产级虚拟机,本章涵盖 UEFI/TPM 现代固件支持、VFIO 硬件直通、virtio 半虚拟化驱动优化、virtiofs 文件共享以及磁盘镜像高级操作。


1. UEFI 固件与 TPM —— 现代 OS 支持#

1.1 为什么需要 UEFI

固件选择应按客户机与引导需求决定;SeaBIOS 仍可用于受支持的 legacy 客体,UEFI 提供现代固件接口:

场景 BIOS 限制 UEFI 解决方案
Windows 11 安装 不支持 OVMF + TPM 2.0 + Secure Boot
磁盘 > 2TB MBR 寻址限制与 BIOS 不应混淆;BIOS 可通过合适 bootloader 启动 GPT 磁盘 OVMF 原生支持 GPT
Secure Boot 不支持 OVMF 支持签名验证
启动速度 初始化耗时依实现而变 不保证总启动时间更短
多 OS 引导 多系统可由传统 bootloader 管理,但缺少 UEFI 引导项接口 UEFI 多条目引导管理器

1.2 OVMF (Open Virtual Machine Firmware)

下列文件名与目录是发行版示例,CODE/VARS 的大小、架构和 Secure Boot keys 必须匹配;优先检查 domcapabilities 和固件 metadata。新建域可使用固件自动选择;已有域的 NVRAM 含引导项与密钥,不能为路径迁移随意删除或重建。

OVMF 是 Tianocore EDK2 为 QEMU/KVM 编译的 UEFI 固件实现。

安装:

# Arch Linux
sudo pacman -S edk2-ovmf

# Ubuntu / Debian
sudo apt install ovmf

# Fedora
sudo dnf install edk2-ovmf

固件文件位置:

# Arch / Fedora
ls /usr/share/edk2-ovmf/
# OVMF_CODE.fd        -- 只读固件代码 (UEFI 运行时)
# OVMF_VARS.fd        -- 可变存储模板 (NVRAM, 启动项, 证书)
# OVMF_CODE.secboot.fd -- 带 Secure Boot 的固件代码

# Ubuntu / Debian
ls /usr/share/OVMF/
# OVMF_CODE.fd
# OVMF_CODE_4M.fd       -- 4MB 版本 (推荐用于现代 OS)
# OVMF_VARS.fd
flowchart LR
    A[Host: OVMF_CODE.fd] -->|readonly, shared| B[Guest NVRAM]
    C[Host: OVMF_VARS.fd] -->|copy-on-write| D[Per-VM VARS file]
    D --> E[Boot entries / Keys / Certificates]
    B --> F[UEFI Runtime in Guest]

libvirt XML 配置:

<os firmware='efi'>
  <type arch='x86_64' machine='q35'>hvm</type>
  <firmware>
    <feature enabled='yes' name='enrolled-keys'/>
    <feature enabled='yes' name='secure-boot'/>
  </firmware>
  <!-- 新建域让 libvirt 根据固件元数据选择兼容的 Secure Boot CODE/VARS。 -->
</os>

每台虚拟机需要独立的 NVRAM 文件 OVMF_VARS.fd 是模板文件,libvirt 会在虚拟机创建时 copy 一份到 /var/lib/libvirt/qemu/nvram/。不同 VM 之间不能共享 VARS 文件,否则会互相覆盖启动项和证书。

1.3 Secure Boot

<!-- 启用 Secure Boot -->
<os firmware='efi'>
  <loader readonly='yes' secure='yes' type='pflash'>
    /usr/share/edk2-ovmf/OVMF_CODE.secboot.fd
  </loader>
</os>

Secure Boot 模式下,OVMF 会验证引导加载程序的签名。Linux 发行版通常自带签名引导程序 (shim + GRUB),Windows 也原生支持。

Secure Boot 与某些 GPU ROM 冲突 如果开启了 Secure Boot 同时做 GPU 直通,GPU 的 Video ROM 可能因签名验证失败而无法加载。先确认 firmware、ROM 类型、签名和客体日志,再决定使用经过验证的 ROM 或调整策略;关闭 Secure Boot 不是默认修复,还可能触发磁盘加密恢复。

1.4 TPM 2.0

Windows 11 官方要求 TPM 2.0。SWTPM 是常见的模拟实现,也可以采用符合要求的硬件 TPM 后端;还要核对 CPU、内存、存储、UEFI 与 Secure Boot capable 等完整要求。

安装:

# Arch Linux
sudo pacman -S swtpm

# Ubuntu / Debian
sudo apt install swtpm swtpm-tools

# Fedora
sudo dnf install swtpm swtpm-tools

libvirt XML 配置:

<tpm model='tpm-crb'>
  <backend type='emulator' version='2.0'>
    <encryption secret='...'/>
  </backend>
</tpm>

virt-manager 操作:

  1. Add Hardware -> TPM
  2. Model: CRB (推荐,性能优于 TIS)
  3. Backend: Emulated
  4. Version: 2.0

TPM 状态信息持久化 TPM 模拟器的状态存储在 /var/lib/libvirt/swtpm/<vm-uuid>/ 下。如果 BitLocker 等依赖 TPM 的全盘加密开启,备份该目录至关重要——丢失 TPM 状态意味着无法解密磁盘。

1.5 完整 Windows 11 兼容配置

<!-- 演示 UEFI/TPM 相关片段;并非全部 Windows 11 硬件要求 -->
<os firmware='efi'>
  <type arch='x86_64' machine='q35'>hvm</type>
  <firmware>
    <feature enabled='yes' name='secure-boot'/>
  </firmware>
</os>
<tpm model='tpm-crb'>
  <backend type='emulator' version='2.0'/>
</tpm>

2. VFIO / PCI Passthrough —— 硬件直通#

VFIO/IOMMU group 是隔离单位;直通前检查组内所有设备、宿主依赖与恢复控制路径。ID 绑定可能匹配多块同型号设备,黑名单可能禁用宿主全部显卡。ACS override 是部分补丁内核提供的危险软件拆组手段,不会制造硬件 DMA 隔离,也不是默认操作。

VFIO (Virtual Function I/O) 将物理 PCIe 设备直接分配给虚拟机,实现接近裸机的 I/O 性能。典型应用场景:GPU 直通(游戏/渲染/AI 训练)、NVMe 直通(数据库)、USB 控制器直通(外设延迟敏感场景)。

2.1 IOMMU 基础

IOMMU (Input-Output Memory Management Unit) 是 VFIO 的硬件基础,负责将 DMA 地址映射到虚拟机地址空间。

启用 IOMMU:

# /etc/default/grub (GRUB 用户)
GRUB_CMDLINE_LINUX_DEFAULT="... intel_iommu=on iommu=pt"
# Intel: 按内核/固件需要检查 intel_iommu=on;AMD 通常自动初始化,iommu.strict=1 不是启用开关
# iommu=pt: 直通模式下不对 host 设备做 DMA 重映射,减少性能开销

# systemd-boot 用户
# /boot/loader/entries/xxx.conf
options ... intel_iommu=on iommu=pt

# 更新引导配置
sudo grub-mkconfig -o /boot/grub/grub.cfg   # GRUB

验证 IOMMU 启用:

# 检查内核日志
dmesg | grep -i iommu
# Intel 输出示例: DMAR-IR: Enabled IRQ remapping in x2apic mode
# AMD 输出示例: AMD-Vi: Enabling IOMMU

# 检查 DMAR / AMD-Vi 表
dmesg | grep -i -e DMAR -e IOMMU

# 验证 IOMMU 分组
find /sys/kernel/iommu_groups/ -type l | sort -V

2.2 IOMMU 分组与隔离

IOMMU 分组决定了哪些设备可以独立直通。VFIO 需要组内所有相关设备满足安全绑定条件(绑定 VFIO 或从宿主 driver 解绑定等);不等于每个功能都必须暴露给同一客体。不可让仍由宿主使用的同组设备破坏隔离。

# 查看每个分组的设备
#!/bin/bash
for g in $(find /sys/kernel/iommu_groups/ -maxdepth 1 -type d | sort -V); do
    echo "IOMMU Group ${g##*/}:"
    for d in $(find $g/devices/ -type l); do
        echo "  $(basename $d) ($(lspci -nns $(basename $d) | cut -d' ' -f2-))"
    done
done

ACS 补丁的安全风险 如果 GPU 与其他设备(如 USB 控制器、NVMe、网卡)共享 IOMMU 分组,可以使用 pcie_acs_override=downstream,multifunction 内核参数强制拆分组。但这破坏了硬件隔离——同一组内的设备可以通过 DMA 互相访问。不能作为换槽失败后的自动修复;无法获得可靠隔离时应放弃该分配或更换硬件。

flowchart TD
    A[物理 PCIe 设备] --> B{IOMMU 组内仅有目标设备?}
    B -->|是| C[跳过 ACS]
    B -->|否| D{可以更换 PCIe 插槽?}
    D -->|是| E[换插槽后重试]
    D -->|否| F[停止分配并评估硬件隔离]
    F --> G["ACS override 不提供真实硬件隔离"]
    G --> H[⚠️ 安全隔离被破坏,注意风险]
    C --> I[绑定到 vfio-pci]

2.3 GPU 直通完整流程

GPU 直通是 VFIO 最常见的用例。以下以 NVIDIA 显卡为例。

Step 1: 获取 GPU PCI ID

lspci -nn | grep -i nvidia
# 输出示例:
# <PCI_BDF> VGA compatible controller [...] [<VENDOR_DEVICE_ID>]
# <PCI_BDF> Audio device [...] [<VENDOR_DEVICE_ID>]
#
# <VENDOR_DEVICE_ID> = GPU 本体
# <VENDOR_DEVICE_ID> = HDMI Audio 功能
# 检查同组与关联功能、宿主依赖和VFIO绑定条件;需要分配的功能明确列出

Step 2: 配置 vfio-pci 早绑定

阻止宿主机驱动在启动时抢占 GPU:

# /etc/modprobe.d/vfio.conf
# 用你的 GPU PCI ID 替换
options vfio-pci ids=<VENDOR_DEVICE_ID>,<VENDOR_DEVICE_ID>

# 同时黑名单宿主机显卡驱动
# /etc/modprobe.d/blacklist.conf
blacklist nouveau
blacklist nvidia
blacklist nvidiafb
# /etc/mkinitcpio.conf (Arch Linux)
MODULES=(... vfio_pci vfio vfio_iommu_type1 ...)
# 旧内核可能有 vfio_virqfd;Linux 6.2 起功能并入 VFIO,勿盲目加载不存在的模块。
# 然后 sudo mkinitcpio -P

# /etc/initramfs-tools/modules (Debian/Ubuntu)
vfio
vfio_iommu_type1
vfio_pci

# 然后 sudo update-initramfs -u -k all

内核命令行添加:

vfio-pci.ids=<VENDOR_DEVICE_ID>,<VENDOR_DEVICE_ID>

验证绑定:

lspci -k -s "<PCI_BDF>"
# Kernel driver in use: vfio-pci  <-- 成功

Step 3: libvirt XML 配置

<hostdev mode='subsystem' type='pci' managed='yes'>
  <source>
    <address domain='<PCI_DOMAIN>' bus='<GPU_BUS>' slot='<GPU_SLOT>' function='<GPU_FUNCTION>'/>
  </source>
  <rom bar='on'/>
  <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/>
</hostdev>
<hostdev mode='subsystem' type='pci' managed='yes'>
  <source>
    <address domain='<PCI_DOMAIN>' bus='<GPU_BUS>' slot='<GPU_SLOT>' function='<GPU_AUDIO_FUNCTION>'/>
  </source>
  <address type='pci' domain='0x0000' bus='0x07' slot='0x00' function='0x0'/>
</hostdev>

NVIDIA Error 43 问题 历史部分 NVIDIA 驱动存在虚拟化检测限制,现代驱动不能一概如此判断;Error 43 也可能由 ROM、reset、固件或驱动不匹配引起。下面隐藏 KVM/vendor_id 是历史兼容性片段,不是所有 GPU 默认需要的设置,先诊断实际版本与日志:

<features>
  <hyperv>
    <vendor_id state='on' value='KVM Hv'/>
  </hyperv>
  <kvm>
    <hidden state='on'/>
  </kvm>
</features>

同时在 <cpu> 块中添加:<feature policy='disable' name='hypervisor'/>

2.4 单 GPU 直通(无第二块显卡)

如果你只有一张显卡,直通后宿主机将失去图形输出。需要以下额外配置:

  1. 宿主机改为 headless:SSH 远程管理
  2. 引导阶段不要抢占 GPU:video=efifb:off 内核参数
  3. GPU ROM 提取:某些 GPU 需要提供 ROM file
    echo 1 > /sys/bus/pci/devices/<PCI_BDF>/rom
    cat /sys/bus/pci/devices/<PCI_BDF>/rom > gpu.rom
    echo 0 > /sys/bus/pci/devices/<PCI_BDF>/rom
  4. 关闭时归还 GPU:libvirt hook 脚本在 VM 停止时解绑 vfio-pci

2.5 USB 控制器直通

相比逐个透传 USB 设备,直通整个 USB 控制器的优势:

透传方式 热插拔 延迟 兼容性
USB 重定向 (Spice) 需手动选择 较高 依赖 guest 工具
单个 USB 设备 不支持 低 仅透传已选设备
整个 USB 控制器 原生支持 原生延迟 所有 USB 设备均可用
# 找到独立的 USB 控制器
lspci | grep USB
# 示例: <USB_CONTROLLER_BDF> USB controller: Intel Corp. ...

# 在 virt-manager 中: Add Hardware → PCI Host Device → 选择 USB 控制器

游戏虚拟机最佳实践 对于游戏虚拟机,建议直通一个独立的 USB 3.0 PCIe 扩展卡。这样可以物理切换键盘/鼠标/耳机等外设。


3. virtio 驱动与性能优化#

3.1 virtio 架构原理

virtio 是一套半虚拟化 (paravirtualized) I/O 框架。Guest 知道自己运行在虚拟机中,通过 virtio 驱动直接与 QEMU 的 virtio 后端通信,绕过完整设备模拟的中间层。

flowchart LR
    subgraph Guest
        A[Guest Application]
        B[virtio Frontend Driver]
    end
    subgraph Hypervisor
        C[QEMU virtio Backend]
        D["vhost (kernel)"]
        E["vhost-user (userspace)"]
    end
    subgraph Host Hardware
        F[Physical I/O Device]
    end

    A --> B
    B -->|virtqueue / shared memory| C
    C --> D
    C --> E
    D --> F
    E --> F

3.2 virtio 设备类型对比

设备类型 存储/网络设备 性能特点 推荐场景
virtio-blk 块设备 支持多队列,实际 IOPS 依后端与配置 一般存储
virtio-scsi SCSI 控制器 多 LUN,支持 SCSI 命令 需要 SCSI 功能的场景
virtio-net 网卡 多队列,vhost 加速 所有网络场景
virtio-gpu 显卡 virgl 3D 加速(Linux guest) 需要 3D 的 Linux VM
virtio-serial 串口 VM-guest 通信通道 guest-agent 通信
virtio-rng 随机数 从 host 获取熵 加密密集型应用
virtio-balloon 内存 动态调整 guest 内存 内存超分配
virtio-fs 文件系统 host-guest 目录共享 共享文件目录
virtio-input 输入设备 低延迟鼠标/键盘 替代 USB 重定向
virtio-mem 内存热插拔 运行时增减内存 灵活内存管理

3.3 Windows Guest virtio 驱动安装

Windows 不内置 virtio 驱动,需要从 Fedora 项目下载:

# 下载 virtio-win ISO
wget https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso

# 挂载到虚拟机,然后在 Windows 中浏览安装

安装顺序:

  1. 安装阶段:Windows 安装程序选择磁盘时,"加载驱动程序" -> 浏览 virtio ISO -> 选择对应 Windows 版本的 viostor 目录
  2. 安装后:运行 virtio-win-guest-tools.exe 或逐个安装:
    • NetKVM — 网络驱动
    • viostor — 磁盘驱动
    • vioinput — 鼠标/键盘输入
    • qxldod — QXL 显示驱动
    • vioserial — 串口驱动(用于 guest-agent)
  3. guest-agent:安装 qemu-ga-x64.msi

Linux Guest:

# virtio 驱动内置于内核主线,只需安装 guest-agent
sudo apt install qemu-guest-agent        # Debian/Ubuntu
sudo pacman -S qemu-guest-agent           # Arch
sudo dnf install qemu-guest-agent         # Fedora

# 启用并启动服务
sudo systemctl enable --now qemu-guest-agent

3.4 CPU 与内存性能调优

CPU Pinning(CPU 绑定):

将 vCPU 绑定到固定的物理 CPU 核心,避免调度抖动,对延迟敏感的工作负载至关重要。

<cputune>
  <vcpupin vcpu='0' cpuset='2'/>
  <vcpupin vcpu='1' cpuset='8'/>
  <vcpupin vcpu='2' cpuset='3'/>
  <vcpupin vcpu='3' cpuset='9'/>
  <emulatorpin cpuset='0-1'/>
  <iothreadpin iothread='1' cpuset='10-11'/>
</cputune>

SMT / Hyper-Threading 注意事项 cpuset 数字是示意逻辑 CPU ID,不保证 2 与 8 为 SMT 兄弟。先用 lscpu -e 和 thread_siblings_list 查实际拓扑,留出 housekeeping CPU,再按共享缓存/延迟目标测量绑定效果。iothreadpin 还要求域实际定义相应 iothread。

CPU 隔离 (isolcpus):

# 内核命令行添加,防止宿主机使用指定核心
isolcpus=2-9,10-17
# isolcpus 的 domain 隔离标志被标为 deprecated,其他标志语义不同;优先评估可动态管理的 cpuset,并保留 housekeeping CPU

vCPU 拓扑:

<cpu mode='host-passthrough' check='none'>
  <topology sockets='1' dies='1' cores='4' threads='2'/>
  <cache mode='passthrough'/>
  <feature policy='require' name='topoext'/>
</cpu>
  • host-passthrough:将宿主机 CPU 特性完整暴露给 guest,最大性能
  • check='none':跳过 QEMU 的 CPU 模型验证
  • sockets='1' cores='4' threads='2':模拟 1 socket x 4 核 x 2 线程 = 8 vCPU

HugePages(大页内存):

# 宿主机配置 2MB 大页
# /etc/default/grub 或内核命令行
hugepagesz=2M hugepages=4096
# 4096 × 2MB = 8GB 大页池

# 运行时配置
sudo sysctl vm.nr_hugepages=4096

# 查看大页状态
cat /proc/meminfo | grep Huge
<!-- libvirt XML -->
<memoryBacking>
  <hugepages/>
  <locked/>
</memoryBacking>

什么时候用 HugePages? 对于内存 > 8GB 且需要稳定性能的虚拟机(游戏、数据库、AI 推理),大页可以显著减少 TLB miss。但对于轻量级 VM,THP (Transparent Huge Pages) 已足够。

性能优化速查表:

技术 效果 应用场景 复杂度
CPU Pinning 消除 vCPU 调度抖动 延迟敏感(游戏/实时) 中
isolcpus / cgroup 防止宿主机抢占核心 与 CPU Pinning 配合 中
HugePages 减少 TLB miss 大内存 VM 中
host-passthrough 最大化 CPU 特性暴露 适用于不需要异构迁移的场景;仍需测量 低
IOThreads 独立磁盘 I/O 线程 高 IOPS 场景 低
Multi-queue NIC 网络并行处理 多 vCPU + 高吞吐 低

3.5 网络优化

Multi-queue virtio-net:

<interface type='network'>
  <model type='virtio'/>
  <driver name='vhost' queues='8'/>
</interface>

queues 数量建议等于 vCPU 数量。

# Guest 内设置队列数
sudo ethtool -L eth0 combined 8

# 验证
ethtool -l eth0

vhost-net vs vhost-user:

后端 位置 延迟 功能
QEMU 用户态 QEMU 进程 高 兼容性最好
vhost-net 内核 低 标准选择
vhost-user DPDK/SPDK 用户态进程 极低 需要额外配置

3.6 磁盘 I/O 优化

<!-- iothreads 在 domain 顶层,disk driver 引用对应 ID;本片段须放入正确位置。 -->
<iothreads>1</iothreads>
<!-- devices 内: -->
<disk type='file' device='disk'>
  <driver name='qemu' type='qcow2' cache='none' io='native' discard='unmap' iothread='1'/>
  <source file='/var/lib/libvirt/images/vm.qcow2'/>
  <target dev='vda' bus='virtio'/>
</disk>
参数 选项 含义
cache none 绕过宿主机页缓存,直接 O_DIRECT
cache writeback 使用宿主机页缓存;正确性取决于 flush 和存储,性能需实测
cache writethrough 同步确认;不保证所有设备故障下的安全,延迟需实测
cache directsync O_DIRECT + 同步确认;仍需底层存储持久性保证
io native 使用 Linux AIO;通常配合 cache=none/directsync,性能需测量;io_uring 支持依版本
discard unmap 支持 TRIM/DISCARD,释放磁盘空间

4. virtiofs —— 主机与虚拟机文件共享#

virtiofs 是 QEMU 5.0+ 引入的半虚拟化文件系统,替代老旧的 virtio-9p,提供 host-guest 间的高性能文件共享。

4.1 与替代方案对比

方案 吞吐量 POSIX 语义 配置复杂度 推荐度
virtiofs 极高 完整 中 首选
virtio-9p 低 不完整 低 遗留兼容
NFS 中-高 较完整 中 多 VM 共享
Samba/CIFS 低-中 不完整 低 Windows guest
VirtFS (9p) 低 部分 低 废弃

4.2 环境要求

  • Linux Guest kernel >= 5.4(virtiofs 驱动;Host 还需对应软件支持)
  • QEMU >= 5.0(推荐 >= 8.0)
  • libvirt >= 6.2
  • virtiofsd 守护进程(现代常为独立 Rust 包;路径与选项按版本核对)
# 确认 virtiofsd 可用
which virtiofsd
# 通常位于 /usr/lib/qemu/virtiofsd 或 /usr/libexec/virtiofsd

4.3 完整配置

Step 1: 宿主机创建共享目录

mkdir -p ~/vm-shared
chmod 755 ~/vm-shared

Step 2: libvirt 内存后备配置

virtiofs 需要用共享内存 (memfd) 作为通信通道:

<domain type='kvm'>
  <!-- ... -->
  <memoryBacking>
    <source type='memfd'/>
    <access mode='shared'/>
  </memoryBacking>
  <!-- ... -->
</domain>

Step 3: 添加 filesystem 设备

<filesystem type='mount' accessmode='passthrough'>
  <driver type='virtiofs'/>
  <source dir='/home/user/vm-shared'/>
  <target dir='share_tag'/>
  <binary path='/usr/libexec/virtiofsd' xattr='on'>
    <cache mode='always'/>
    <sandbox mode='chroot'/>
  </binary>
</filesystem>
参数 说明
accessmode='passthrough' 按 passthrough 语义处理权限/所有者;实际 UID/GID 映射与 daemon 权限需检查
source dir Host 端目录路径
target dir Guest 端挂载标签(非实际路径,是标识名)
cache mode='always' 更积极缓存;与宿主并发修改时需核对一致性语义
cache mode='auto' 默认,根据访问模式自动选择
xattr='on' 启用扩展属性支持 (SELinux)

Step 4: Guest 内挂载

# 手动挂载
sudo mount -t virtiofs share_tag /mnt/shared

# 验证挂载
mount | grep virtiofs
df -h /mnt/shared

# 自动挂载 (/etc/fstab)
share_tag  /mnt/shared  virtiofs  defaults  0  0

fstab 挂载顺序 virtiofs 是本地虚拟设备,不必视为网络文件系统。可按客体 systemd/启动依赖选择 nofail,x-systemd.automount,并验证设备就绪与挂载结果;_netdev 只改变挂载顺序语义:

share_tag  /mnt/shared  virtiofs  defaults,nofail,x-systemd.automount  0  0

virt-manager 操作路径:

  1. Add Hardware -> Filesystem
  2. Type: mount, Driver: virtiofs
  3. Source path: /home/user/vm-shared
  4. Target path: share_tag (自定义标签)

4.4 DAX (Direct Access) 窗口配置

本节是 DAX 设计示意,不代表下面 memfd/cache 片段就启用了 DAX window。DAX 必须有匹配的 QEMU、virtiofsd、客体内核及实际窗口配置;当前实现是否支持需查对应版本,不能仅加 mount -o dax 保证生效。

DAX 的设计允许 guest 映射 host 文件页,减少部分缓存路径;收益和支持条件需要按完整软件栈验证:

<memoryBacking>
  <source type='memfd'/>
  <access mode='shared'/>
</memoryBacking>
<!-- ... -->
<filesystem type='mount' accessmode='passthrough'>
  <driver type='virtiofs'/>
  <source dir='/home/user/vm-shared'/>
  <target dir='share_tag'/>
  <binary path='/usr/libexec/virtiofsd'>
    <cache mode='always'/>
  </binary>
</filesystem>

使用 DAX 挂载:

sudo mount -t virtiofs -o dax share_tag /mnt/shared

5. 磁盘镜像高级操作#

qemu-img 面向离线磁盘。任何修改、转换、修复、快照、resize、commit 或 rebase 前都必须停止所有使用者并备份;在线查询也可能看到不一致的元数据。check -r all 可能丢失数据,先复制原件。qemu-img 的磁盘内部快照不保存 guest RAM、UEFI NVRAM 或 TPM 状态。

5.1 qemu-img 命令大全

# ========== 创建镜像 ==========

# 创建 qcow2 格式(精简配置,按需增长)
qemu-img create -f qcow2 disk.qcow2 40G

# 创建预分配 qcow2(避免碎片)
qemu-img create -f qcow2 -o preallocation=full disk.qcow2 40G

# 创建 raw 格式(通常是稀疏文件;完整预分配可显式选择 preallocation=full)
qemu-img create -f raw disk.raw 40G

# 创建 qcow2 带集群大小(默认 64K)
qemu-img create -f qcow2 -o cluster_size=2M disk.qcow2 100G

# ========== 转换镜像 ==========

# raw -> qcow2(最常用:回收空间)
qemu-img convert -f raw -O qcow2 old.img new.qcow2

# qcow2 -> raw(性能优化)
qemu-img convert -f qcow2 -O raw old.qcow2 new.raw

# 压缩转换(-c 压缩目标镜像)
qemu-img convert -c -f raw -O qcow2 old.img compressed.qcow2

# 离线转换:-W 允许目标乱序写,不提供在线一致性;仅在合适的预分配目标上考虑
qemu-img convert -f raw -O qcow2 source.img target.qcow2
# 进阶示意:预分配 raw 目标;仍要求源离线
qemu-img convert -W -f raw -O raw -o preallocation=full source.img target.raw

# ========== 查看信息 ==========

# 查看镜像元数据
qemu-img info disk.qcow2
# virtual size: 40 GiB
# disk size: 2.3 GiB
# cluster_size: 65536
# backing file: base.qcow2

# 查看详细 JSON 输出
qemu-img info --output=json disk.qcow2

# 一致性检查
qemu-img check disk.qcow2

# 修复发现的错误(慎用)
qemu-img check -r all disk.qcow2

# ========== 快照操作 ==========

# 创建快照
qemu-img snapshot -c snap1_before_update disk.qcow2

# 列出所有快照
qemu-img snapshot -l disk.qcow2

# 应用/回滚到某快照
qemu-img snapshot -a snap1_before_update disk.qcow2

# 删除快照
qemu-img snapshot -d snap1_before_update disk.qcow2

# ========== 调整大小 ==========

# 扩容(仅扩大虚拟磁盘,分区/文件系统需在 guest 内扩展)
qemu-img resize disk.qcow2 +20G

# 缩容(先在客体/离线工具中安全缩文件系统与分区;新边界必须容纳全部结构与数据,XFS 等不支持常规缩容)
qemu-img resize disk.qcow2 -10G --shrink

# 显式截短该镜像的虚拟大小(不是重新计算链;满足全部缩容前提才可操作)
qemu-img resize --shrink disk.qcow2 20G

5.2 Backing Chain(增量镜像链)

qcow2 支持基于 backing file 的增量叠加,类似 overlay 文件系统:

# 创建基础镜像
qemu-img create -f qcow2 base.qcow2 40G

# 基于基础镜像创建 overlay(记录差异)
qemu-img create -f qcow2 -b base.qcow2 -F qcow2 overlay.qcow2

# 查看 backing chain
qemu-img info --backing-chain overlay.qcow2
flowchart TD
    A["base.qcow2 / OS 安装 + 基础软件 / 40GB virtual, 15GB actual"]
    B["overlay1.qcow2 / backing: base.qcow2 / Application 1 改变 / diff: 2GB"]
    C["overlay2.qcow2 / backing: overlay1.qcow2 / Application 2 改变 / diff: 500MB"]
    A -->|backing file| B
    B -->|backing file| C

Backing Chain 操作:

# 合并 overlay 到 base(commit)
qemu-img commit overlay.qcow2

# 重构 backing chain(rebase)
qemu-img rebase -b new_base.qcow2 -F qcow2 overlay.qcow2

# 拍平 backing chain(合并所有 overlay 生成独立镜像)
qemu-img convert -f qcow2 -O qcow2 overlay2.qcow2 standalone.qcow2

Backing chain 的危险操作 base 中未被 overlay 覆盖的扇区仍会被读取,因此改写共享 base 会改变所有依赖它的客体数据视图;不应把这解释成“扇区偏移必然失效”。正常运行中 base 应保持不可变。

  1. 修改前列出所有依赖链并停止写入者,备份完整链。
  2. commit 会写入 backing file,可能影响其他 overlay;不能作为修改共享 base 前的通用安全步骤。
  3. 安全模式 rebase 会读取旧/新 base 并保留客体视图;-u 只改元数据,错误使用会破坏视图。格式、路径与底层数据均需核对。
  4. 需要独立副本时优先将离线链 convert 拍平,并验证副本;不对在线镜像运行这些工具。

5.3 存储池管理

定义 LVM/disk 池前核对设备稳定 ID、容量、现有分区及使用者;定义与 build/格式化是不同操作,后者可能毁掉现有数据。物理块设备不是“空白镜像”,不能凭 /dev/sdX 名称操作。后端是否支持该功能依当前 libvirt 编译与版本。

libvirt 存储池类型:

类型 适用场景 特点
Directory 通用 最简单,宿主机文件系统
LVM 高性能块存储 快照、精简分配
ZFS 高级存储 快照、克隆、send/recv、压缩、去重
NFS 集中存储/迁移 远程访问、多宿主机共享
iSCSI SAN 高可用、企业级
GlusterFS 分布式 横向扩展
RBD (Ceph) 云规模 极大规模、副本、自动修复

创建存储池:

# Directory 类型 (最常用)
virsh pool-define-as --name images --type dir --target /var/lib/libvirt/images
virsh pool-start images
virsh pool-autostart images

# LVM 类型
virsh pool-define-as --name lvm_pool --type logical \
  --source-device "/dev/disk/by-id/<LVM_SOURCE_DISK_ID>" --target /dev/vg_kvm

存储池管理命令:

virsh pool-list --all              # 列出所有存储池
virsh pool-info images             # 存储池详情
virsh pool-refresh images          # 刷新(重新扫描卷)
virsh vol-list images              # 列出池中所有卷
virsh vol-info disk.qcow2 --pool images  # 卷信息
virsh vol-create-as images new_disk.qcow2 40G --format qcow2
virsh vol-delete disk.qcow2 --pool images

5.4 磁盘性能对比

格式 精简分配 快照 压缩 性能 推荐场景
raw 文件可稀疏/后端可精简 无 qcow2 内部快照,后端可快照 无原生压缩 依后端与负载 简单文件或块设备镜像
qcow2 是 是 是 高(约 95% raw) 通用推荐
vmdk 是 是 部分 中 VMware 兼容
vdi 是 是 部分 中 VirtualBox 兼容

5.5 Guest 内分区扩展

qemu-img resize 只扩大了虚拟磁盘,还需要在 guest 内扩展分区和文件系统:

# === Guest 内操作 ===

# 1. 查看当前分区表
lsblk
sudo fdisk -l /dev/vda

# 2. 扩展分区(以 GPT + systemd-growfs 为例)
sudo growpart /dev/vda 1          # 扩展第 1 个分区

# 3. 扩展文件系统
# ext4
sudo resize2fs /dev/vda1
# XFS
sudo xfs_growfs /
# Btrfs
sudo btrfs filesystem resize max /

# 4. 验证
df -h /

virt-resize 离线扩容 如果 guest 分区布局复杂,可以在 guest 关机后使用 libguestfs 工具:

先离线备份并检查客体分区;预先创建足够大的目标文件(如 `qemu-img create -f qcow2 new.qcow2 <LARGER_SIZE>`),再执行:
`virt-resize --expand /dev/sda1 old.qcow2 new.qcow2`。这里 /dev/sda1 指镜像内的客体分区,不是宿主磁盘;支持的文件系统与扩展结果需核对。

6. 高级网络配置#

NAT、isolated、bridge 和 macvtap 的安全与性能由规则、拓扑和负载决定,表中的高低仅表示原笔记概览,不是测量结果。NAT/isolated 不阻断客体对宿主桥与同网段客体;bridge/macvtap 需外部网络授权,macvtap 不是 PCI 直通。普通 Wi-Fi client 常不能透明桥接多个 MAC。变更宿主 IP/路由前准备本地或带外恢复。

6.1 网络模式对比

模式 NAT 隔离性 外部可访问 性能 使用场景
NAT (default) 是 高 否(需端口转发) 中 桌面虚拟化
Bridged 否 低 是(同网段 IP) 高 服务器虚拟化
macvtap (VEPA) 否 中 是 极高 高性能场景
macvtap (Bridge) 否 低 是 极高 单机高性能
PCI Passthrough (SR-IOV) 否 无 是 接近裸机 极致性能

6.2 桥接网络配置

# /etc/network/interfaces (Debian/Ubuntu) 或使用 NetworkManager / systemd-networkd

# 使用 nmcli (NetworkManager)
nmcli connection add type bridge ifname br0
nmcli connection add type ethernet slave-type bridge con-name bridge-br0 ifname eth0 master br0
nmcli connection up br0
<!-- libvirt XML -->
<interface type='bridge'>
  <!-- 未指定 MAC,由 libvirt 生成;迁移现有 VM 应保留其地址。 -->
  <source bridge='br0'/>
  <model type='virtio'/>
</interface>

6.3 macvtap 高性能直通

macvtap 将客体虚拟网卡关联到宿主物理接口,无需传统 bridge;它仍经过宿主网络路径,并非 PCI/VFIO 网卡直通:

<interface type='direct'>
  <source dev='eth0' mode='bridge'/>
  <model type='virtio'/>
</interface>

macvtap 模式:

模式 行为 适用场景
VEPA VM 间流量经外部交换机转发 企业环境
Bridge 宿主机上的 VM 间可直接通信 单机多 VM
Private VM 间完全隔离 安全隔离
Passthrough 一个 VM 独占网卡 单 VM 高性能

macvtap 的局限 macvtap bridge 模式下,宿主机自身无法与 VM 通信(即使是同一物理网卡)。这是 Linux macvlan 的设计限制。如需宿主机与 VM 通信,在宿主机的 macvtap 接口上额外配置一个 macvlan 或者改用传统 bridge。



参考与延伸

  1. VFIO 与 IOMMU group ↗
  2. libvirt virtiofs ↗
  3. QEMU qemu-img ↗
  4. Domain XML ↗
  5. Linux kernel parameters ↗

根据技术笔记重新整理,示例使用通用名称。

沿专题继续阅读

KVM 高级能力与平台选择

  1. 01KVM 的固件、VFIO、virtiofs 与镜像链
  2. 02在 NixOS 声明 KVM 宿主能力
  3. 03KVM 管理工具与自动化入口选型
CONTINUE READING / 下一篇在 NixOS 声明 KVM 宿主能力

通过固定版本的模块接口配置 libvirt,同时管理网络、固件和 VM 外部运行状态。