最近发现环境中 KVM 虚拟机磁盘利用率查不准,使用 virsh 命令查看磁盘使用情况得到如下结果:
显然是有问题的,正常的数值三个应该不通,进入系统查看磁盘使用率也仅有 2% 左右,因此试图通过检查源码的方式查看是否正确。
- libvirt: 5.6.0
- os: Centos
跟踪记录
首先找到 libvirtd 的 PID:
使用 GDB 开始跟踪他:
首先在源码中全局搜索 domblkinfo 关键字,找到该命令的执行函数: tools/virsh-domain-monitor.c→cmdDomblkinfo 。
分析源码找到获取信息的函数 src/libvirt-domain.c -> virDomainGetBlockInfo :
这其中的 info 包含了所需信息,看一下填充该字段的 virDomainGetBlockInfo 函数实现,用 GDB 跟一下它吧.
跟踪 src/libvirt-domain.c -> virDomainGetBlockInfo
先打个断点:
再打开一个终端,执行一下命令:
此时会发现终端卡住了,看一下 GDB 已经将程序中断,单步调试看一下:
发现在 6112 行跳到了另一个函数,继续跟踪它.
跟踪 src/qemu/qemu_driver.c -> qemuDomainGetBlockInfo
至此,我们知道了 info -> allocation 的值来自 entry->wr_highest_offset ,接下来查看源码, entry->wr_highest_offset 的值应该是在这里被赋予的:
下面将断点打在 qemuDomainBlocksStatsGather 看一下其中的 entry->wr_highest_offset 是在哪里被赋值.
跟踪 src/qemu/qemu_driver.c -> qemuDomainBlocksStatsGather
将之前的断点删除,打上新的断点
之后在 GDB continue ,之后一直按回车,直到程序正常运行了,再执行一下获取磁盘信息的命令,继续跟踪。
分析这一调用过程,发现我们跟踪的 restats 变量来自 stats,而该值在这一行被填充:
值来自哈希表查询结果,从 blockstats 中查询 entryname ,而该哈希表在这两行被赋值:
之后就可以跟踪源码了,经过一番探索,发现他们最终都调用了同一个函数来从 QEMU 获取设备信息,即 src/qemu/qemu_monitor_json.c -> qemuMonitorJSONQueryBlock ,看一下它的函数实现:
继续探索会发现 libvirt 在这里调用了 QEMU 提供的 QMP 协议,其中的查询关键词为 query-block ,返回的结果中含有 wr_highest_offset 字段。
最终得到一张 libvirt 查询磁盘使用情况的调用栈示意图:

https://imagehost-cdn.frytea.com/images/2021/09/02/domblkinfoac4ecdcf5caa1926.png
如果继续探索,可能就需要去跟踪 QEMU 源码了,下篇文章见。
参考文献
- 使用gdb debug libvirt 心得
- GDB常用命令
- GDB禁用和删除断点
- qmp—QEMU Machine Protocol介绍_北方南方-程序员宅基地
- QMP ( qemu monitor protocol ) and Different ways of accessing it
- Unix Socket - Server Examples
- About QEMU