转载: QEMU深入浅出: guest物理内存管理

本文深入探讨了QEMU-kvm虚拟机中guest物理内存的管理机制,包括配置参数、热插拔内存、内存backends、RAM blocks、脏内存追踪及地址空间映射,为理解QEMU源代码提供理论基础。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作  者:Stefan Hajnoczi

领  域:Open source and virtualization

 

适宜读者:对虚拟化有一定了解

背景知识:KVM,Qemu

 

前言:

众所周知,内存是计算机系统的一个关键组成部分。使用Qemu-kvm方式创建虚拟机时,guest物理内存是由几个不同层面共同管理的。本篇基于Qemu2.5的代码对管理guest物理内存的这几个重要层面进行概括性的解释,为读者深究Qemu源代码奠定了理论基础。

 

需要注意的是本篇并未涉及guest虚拟内存方面的内容,后续会对其介绍。毕竟使用KVM虚拟化技术的一个重要前提是支持guest与host之间物理内存的转换,并未涉及Qemu中软件模拟的内存管理(即guest虚拟地址与guest物理地址之间的转换)。

 

一、Guest RAM的配置参数

    Qemu命令行选项“-m [size=]megs[,slots=n,maxmem=size]”分别定义了guest物理内存的初始化值,内存条(如DIMM)的可用插槽数以及可支持的guest物理内存最大值。

 

    有了slot与maxmem这两个参数的定义,在Qemu模拟DIMM热插拔的过程中,guest操作系统像host一样,能够监测到内存块的添加或移除。比如向guest中热插拔一块DIMM内存条,就像是在真实物理机上进行的。再者,guest内存热插拔的操作单位并不是字节,而是插入的DIMM内存条数目。

 

二、可热插拔的guest内存

    Qemu代码中的“pc-dimm”设备(参考Qemu源码hw/mem/pc-dimm.c文件中Typeinfo pc_dimm_info的定义)用来模拟DIMM内存条。代码中“pc-dimm”设备的创建相当于逻辑上热插拔了一块内存(参考代码type_register_static(&pc_dimm_info))。尽管该设备名字包含的“pc”容易让人误解,但ppc和s390机器仍沿用了该名字。

 

    旁注:上文提到的guest的初始化内存是不能用“pc-dimm”设备创建的,也无法将其热移除。

 

在QOM(Qemu Object Model)模型中,“pc-dimm”对象(参考代码include/hw/mem/pc-dimm.h文件中的PCDIMMDevice结构体)中并没有定义表示其对应物理内存的变量,但定义了一个指针用来指向其对应的“memory-backend”对象。

 

三、Memory backends

设备“memory-backend”(参考Qemu源码backends/hostmem.c文件中TypeInfo host_memory_backend_info的定义)描述的是支撑guest物理内存的host上真实的内存资源。这些内存既可以是匿名映射的内存(参考backends/hostmem-ram.c中TypeInfo ram_backend_info的定义),也可以是文件映射的内存(参考backends/hostmem-file.c中TypeInfo file_backend_info的定义)。文件映射这种方式允许Linux在host宿主机上使用大页分配的内存能够映射到guest物理内存,同时实现了共享内存,允许host的其他应用程序访问guest物理内存。

 

“pc-dimm”对象和“memory-backend”对象(参考include/sysemu/hostmem.h文件中的HostMemoryBackend结构体)作为Qemu中用户可见的guest物理内存,可以通过Qemu命令行或者QMP(Qemu Monitor Protocol)对其进行管理。然而这只是冰山一角,下面继续介绍用户不可见的guest物理内存的管理。

 

    图3-01引出下文要介绍的内存管理对象:

image图3-01

四、RAM blocks和ram_addr_t地址空间

“memory-backend”表示的host上真实内存资源由RAMBlock调用exec.c文件中的qemu_ram_alloc()函数,最终通过mmap映射到host上的一块虚拟内存。RAMBlock结构体中的uint8_t *host指向host上虚拟内存的起始值,ram_addr_t offset表示当前RAMBlock相对于RAMList(描述host虚拟内存的全局链表)的偏移量。也就是说ram_addr_t offset位于一个全局命名空间中,可以通过此offset偏移量定位某个RAMBlock。

 

    然而ram_addr_t命名空间并不等同于guest物理内存空间,它仅表示所有RAMBlock集合构成的一个地址空间。举个例子,guest物理地址0x100001000可能并不对应于ram_addr_t命名空间中的0x100001000地址,因为ram_addr_t命名空间不包含guest物理内存区域中用于预留和I/O内存映射的这些部分。此外ram_addr_t offset的值取决于RAMBlock被创建的顺序,而在guest物理内存空间中每块内存都有其固定的地址。

 

    所有的RAMBlock以链表节点的形式存放在全局链表RAMList(参考include/exec/ram_addr.h文件中的struct RAMList)中,即ram_list。结构体ram_list中记录了所有RAMBlock以及“脏”内存bitmap的信息。

 

五、“脏”内存页面的追踪

    当guest CPU或通过设备DMA向guest RAM中存储数据时,需要通知以下特性:

  1. 动态迁移特性会一直跟踪“脏”内存页,在迁移过程中一旦发现这些内存页发生变化就会重新向目的主机发送这些“脏”页面。
  2. Qemu中的动态翻译器TCG(Tiny Code Generator)会一直追踪自调整的代码,当上游指令发生变化时对其重新编译。
  3. 显卡仿真会一直追踪视频相关的“脏”内存,并重新绘制扫描线。

 

以上每种特性在结构体ram_list的成员变量DirtyMemoryBlocks *dirty_memory[DIRTY_MEMORY_NUM]中都有其对应的bitmap,为以上特性独立的开启或关闭“脏”页面跟踪机制。

 

六、Address spaces地址空间

    所有CPU体系架构都有其内存空间,有一些架构还有单独的I/O地址空间。I/O地址空间由AddressSpace结构体描述,一个AddressSpace对应一棵MemoryRegion树(其对应关系在include/exec/memory.h文件的AddressSpace结构体中定义:mr = as->root)。

 

    结构体MemoryRegion是联系guest物理地址空间和描述真实内存的RAMBlocks之间的桥梁。每个MemoryRegion结构体中定义了ram_addr_t offset成员指向其对应RAMBlock中的offset成员变量[1],而在RAMBlock结构体中则定义了struct MemoryRegion *mr指向对应的MemoryRegion。

 

要注意MemoryRegion不仅用来描述RAM,还可以用来描述I/O内存,在访问I/O内存时调用read/write回调函数。如guest CPU在访问硬件设备寄存器时通过查找其对应MemoryRegion结构体中的信息去访问指定的模拟设备。

 

函数address_space_rw()访问MemoryRegion并对该MR描述的内存执行load/store操作。RAM类型的MemoryRegion描述的内存可通过访问RAMBlock中的guest物理内存来获取。Guest物理内存空间定义了一个全局变量AddressSpace address_space_memory,用来表示跟RAM相关的内存。

 

七、总结

Guest物理内存的管理是由几个不同层面共同作用的:“pc-dimm”和“memory-backend”描述了用户可见的guest物理内存(分别代表DIMM内存条与host真实的内存资源);RAMBlock描述了通过mmap映射的host虚拟内存块;AddressSpace和MemoryRegion则记录了guest物理内存与host虚拟内存之间的映射。

 

注释[1]:在Qemu2.6的最新代码中,去除了ram_addr_t offset成员的定义,改为定义RAMBlock *ram_block成员,指向其对应的RAMBlock。

 

参考资料:

http://blog.vmsplice.net/2016/01/qemu-internals-how-guest-physical-ram.html

<think>好的,用户现在遇到了错误信息:“error: Guest agent is not responding: QEMU guest agent is not connected”。我需要帮他解决这个问题。首先,我得回想一下之前他问过关于OpenStack重置Windows虚拟机密码的问题,现在这个错误可能是在执行相关操作时出现的,比如通过命令行或者Horizon控制台操作时触发的。 首先,我需要确定这个错误的具体原因。QEMU Guest Agent(QGA)是虚拟机内部运行的一个服务,用于宿主机和虚拟机之间的通信。如果QGA没有安装或者没有运行,宿主机就无法和虚拟机通信,导致这个错误。用户可能在使用某些需要QGA支持的功能时遇到了问题,比如调整磁盘大小、安全关闭虚拟机或者获取虚拟机信息等。 接下来,我应该分步骤分析可能的原因。首先检查虚拟机内部是否安装了QEMU Guest Agent。对于Windows虚拟机,可能需要安装virtio驱动中的Guest Agent。如果是Linux系统,通常使用qemu-guest-agent包。如果未安装,用户需要安装对应的软件。 然后,检查QGA服务是否在虚拟机内运行。在Windows中,服务可能被禁用或者没有启动;在Linux中,可能需要启动服务并确保它正在运行。此外,虚拟机的配置是否正确也很重要,比如在OpenStack的实例配置中是否添加了相应的属性,告诉Nova需要启用QGA。 另外,用户使用的镜像可能没有正确配置支持QGA,或者创建实例时没有包含必要的配置参数。例如,在创建实例时可能需要指定`hw_qemu_guest_agent=yes`的属性。如果用户是从现有镜像创建的实例,可能需要更新镜像的元数据。 还有可能,虚拟机启动时QGA的套接字没有正确附加。需要检查虚拟机的XML定义(如果是使用Libvirt的话)或者OpenStack的实例配置,确保QGA的通道已经正确配置。 此外,防火墙设置也可能阻止QGA的通信,尤其是在虚拟机内部防火墙(如Windows防火墙)可能拦截了相关通信。需要确保相应的端口或服务被允许。 用户可能是在尝试执行某些操作时遇到这个错误,比如调整虚拟机规格,创建快照,或者执行其他需要与QGA通信的操作。需要根据用户的具体操作场景,提供针对性的解决方案。 最后,还要考虑日志信息的重要性。查看OpenStack的Nova日志或者虚拟机的日志,可能会提供更详细的错误原因,帮助更快定位问题。 总结一下,解决步骤可能包括: 1. 确认QEMU Guest Agent是否安装。 2. 检查QGA服务是否运行。 3. 验证虚拟机配置是否正确启用了QGA。 4. 检查防火墙设置。 5. 查看相关日志以获取更多信息。 需要将这些步骤以用户容易理解的方式呈现,分点说明,并给出具体的命令或操作指导,特别是针对Windows和Linux的不同情况。同时,提醒用户在修改配置后需要重启实例或服务,并确认问题是否解决。如果用户不熟悉某些操作,比如编辑Libvirt的XML配置,可能需要更详细的指导或建议使用OpenStack的命令行工具进行调整。</think> OpenStack 或基于 QEMU/KVM 的虚拟化环境中,遇到 **`Guest agent is not responding: QEMU guest agent is not connected`** 错误,通常表示虚拟机内部的 **QEMU Guest Agent (QGA)** 未正确运行或未配置。以下是问题的原因及解决方法: --- ### **原因分析** 1. **QEMU Guest Agent 未安装** - Windows 虚拟机未安装 `QEMU Guest Agent`(通常集成在 VirtIO 驱动中)。 - Linux 虚拟机未安装 `qemu-guest-agent` 包。 2. **QEMU Guest Agent 未启动** - 服务未运行(Windows 中未启动服务,Linux 中未启用 systemd 服务)。 3. **虚拟机配置未启用 QGA 通道** - OpenStack Nova 或 Libvirt 未配置 QGA 的通信通道。 4. **防火墙或权限问题** - 虚拟机内部防火墙(如 Windows Defender、iptables)阻止了 QGA 的通信。 --- ### **解决方法** #### **1. 安装并启动 QEMU Guest Agent** 根据虚拟机操作系统操作: - **Windows 虚拟机** - 安装 VirtIO 驱动中的 QEMU Guest Agent: 1. 从 [Fedora VirtIO 驱动下载页](https://fedoraproject.org/wiki/Windows_Virtio_Drivers) 下载最新的 VirtIO ISO。 2. 挂载 ISO 到虚拟机,安装 `guest-agent` 组件(通常位于 `virtio-win-guest-tools` 目录)。 3. 启动服务: - 按 `Win + R`,输入 `services.msc`,找到 **`QEMU Guest Agent`** 服务并启动。 - 设置服务为 **自动启动**。 ![Windows 服务启动 QGA](https://example.com/qga- **Linux 虚拟机** ```bash # Debian/Ubuntu sudo apt-get install qemu-guest-agent # RHEL/CentOS sudo yum install qemu-guest-agent # 启动服务 sudo systemctl start qemu-guest-agent sudo systemctl enable qemu-guest-agent ``` -- #### **2. 配置虚拟机启用 QGA 通道** 在 OpenStack 中,需确保虚拟机配置启用了 QGA 支持: - **通过 OpenStack CLI 创建实例时指定 QGA** ```bash openstack server create \ --image <image_name> \ --flavor <flavor_name> \ --network <network> \ --property hw_qemu_guest_agent=yes \ # 关键配置 <instance_name> ``` - **对已有实例更新配置** 1. 关闭虚拟机: ```bash openstack server stop <instance_name_or_id> ``` 2. 更新实例元数据: ```bash openstack server set --property hw_qemu_guest_agent=yes <instance_name_or_id> ``` 3. 重新启动虚拟机: ```bash openstack server start <instance_name_or_id> ``` --- #### **3. 验证 Libvirt XML 配置(底层检查)** 如果是私有 KVM 环境,检查 Libvirt 的虚拟机 XML 配置是否包含 QGA 通道: ```xml <channel type='unix'> <source mode='bind'/> <target type='virtio' name='org.qemu.guest_agent.0'/> </channel> ``` 若缺失,需添加后重启虚拟机。 -- #### **4. 检查虚拟机内部防火墙** - **Windows** - 允许 `QEMU Guest Agent` 通过防火墙(默认端口为 TCP 334)。 - 或临时关闭防火墙测试: ```powershell netsh advfirewall set allprofiles state off ``` - **Linux** ```bash # 放行 QGA 通信 sudo iptables -p tcp --dport 334 -j ACCEPT ``` -- #### **5. 查看日志定位问题** - **OpenStack Nova 日志** ```bash # 查看 Nova 计算节点日志 tail -f /var/log/nova/nova-compute.log ``` - **虚拟机内部 QGA 日志** - Windows:事件查看器 → Windows 日志 → 系统。 - Linux: ```bash journalctl -u qemu-guest-agent ``` --- ### **故障现象示例** | **场景** | **报错信息** | **解决方案** | |--| | 调整虚拟机磁盘大小 | `Guest agent is not responding` | 安装并启动 QGA | | 执行 `openstack server rescue` | `QEMU guest agent is not connected` | 配置 `hw_qemu_guest_agent=yes` | | 安全关闭虚拟机 | 超时并提示 QGA 未响应 | 检查防火墙或服务状态 | --- ### **总结** 1. **优先安装并启动 QEMU Guest Agent**,确保服务在虚拟机内部运行。 2. **配置 OpenStack 实例启用 QGA 支持**(通过元数据 `hw_qemu_guest_agent=yes`)。 3. 若问题持续,检查防火墙、日志及底层 Libvirt/KVM 配置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值