uos 的庖丁解牛13 招:
这部分有时间总结一下,调试能力确实重要。
环境
[root@localhost ~]# uosinfo
#################################################
Release: UOS Server release 20 (kongzi)Kernel : 5.10.0-46.31.uelc20.x86_64Build : UOS Server 20 (1060a) 20231130 amd64
#################################################
问题现象
在1060u1a版本5.10内核系统上安装虚拟机,安装完成后,重启出现如下现象,虚拟机起不来。
复现方法
按照pms bug单描述的复现方法步骤如下:
1、部署虚拟化环境
2、virt-manager安装虚拟机,具体安装步骤如下:
1)UEFI固件选择如下:
A版本:
3、虚拟机安装完成以后,虚拟机无法启动,具体现象如下:
legacy模式-重启-选择510内核进系统–之后报错如下:
UEFI模式-重启-选择510内核进系统–之后报错如下:
4、虚拟化对比测试如下:
日志分析
从问题现象我们可以看到,内核出现了启动初期阶段,报了panic,如下图:
可以看到基本都是操作寄存器相关操作,我们反汇编看一下具体死在了哪行代码:
可以看到正好是xsetbv指令,我们将xsetbv设置的值打印出来可以看到目前出现问题时,他的值是0x202e7,该指令是将EDX:EAX中的值写入ECX指定的XCR。这时候就需要看看intel手册关于这条指令的详细信息了,这个值是否有异常。
在Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 1的13.3章节描述了关系XSTATE的相关内容:
可以看到,当XCR0的bit18-17是01,10时候会报GP错误,而0x202e7的bit18-17确实是10,到现在报GP问题根因找到了,接下来的问题就是找到为什么EDA:EAX的值低32bit的bit18-17不是00或者11了。
下面我们梳理一下,GUEST、HOST、QEMU交互流程,如下图:
接下来我们需要调试一下②流程:
执行:gdb /usr/libexec/qemu-kvm,进入gdb后执行设置参数,命令如下:
set args -smp 4 -m 4096 -cpu host,migratable=on -machine pc-i440fx-rhel7.6.0 -enable-kvm -kernel /root/bzImage -append
"console=ttyS0,115200 loglevel=8 nokaslr" -nographic -initrd ./myrootfs.cpio.gz
然后打断点到main、kvm_arch_get_supported_cpuid:
bpftrace -e 'kprobe:kvm_arch_vcpu_ioctl {printf("ioctl args: flip %x, ioctl %x, arg %lx\n", arg0, arg1, arg2);}'
开始debug,执行run,观察function,当等于13时候,n单步执行,观察,kvm_ioctl返回结果:
查看此时的host kvm ioctl,没有抓到任何信息,由此可见,是qemu:kvm_ioctl->host出了问题,那接下来需要看一下qemu的kvm_ioctl使用的fd是否合host一致,查看代码发现,qemu中kvm_ioctl使用的fd是open /dev/kvm时候创建的,如下图:
下面我们看一下host内核KVM_GET_DEVICE_ATTR所使用的ioctl是否是/dev/kvm
从代码可以看出,KVM_GET_DEVICE_ATTR属于kvm_vcpu_ioctl的,怎么会这样呢,上游搞错了?于是看了这几行补丁的提交记录,发现是回合anolis的commit,而anolis的这个补丁也是回合上游的补丁,最后发现是anolis回合上游补丁错误导致的。
anolis回合上游补丁部分代码如下:
实际上游补丁部分代码如下:
可以看到KVM_GET_DEVICE_ATTR命令应该加到kvm_arch_dev_ioctl下面,而不是kvm_arch_vcpu_ioctl里,修改代码合入修正补丁,再次测试发现,host dev_ioctl可以抓到qemu发送的KVM_GET_DEVICE_ATTR(0xAEE2)了,如图:
此时虚拟机可以正常启动了。
解决方案
由于anolis在回合上游补丁时候,补丁与上游补丁不一致,导致qemu与kvm交互异常,因此最终解决方案如下:
修复回合上游补丁32eb80465a51 (“KVM: x86: add system attribute to retrieve full set of supported xsave states"的错误,将kvm_dev_ioctl命令KVM_GET_DEVICE_ATTR由kvm_arch_vcpu_ioct()l函数移动到kvm_arch_dev_ioctl()函数里。
参考资料
1、https://gitee.com/anolis/cloud-kernel/pulls/1532
2、A-32 Intel Architecture Software Developer’s Manual Volume.3:System Programming Guide
3、kernel-server 5.10 source code