在云计算中,虚机使用云盘,后端连接ceph的存储集群的场景中,在测试中经常出现了虚机里面有飞行io的情况,出现这种情况之后就需要查看在存储链路上是哪一级出现了io没回复的问题。
问题现象:
在一次内部测试中一个虚拟机出现了飞行io的情况,但是查看后端并没有出现io没回的情况:

在host驱动内存里面的used idx值和avail idx值也相等:

这说明硬件是取走了所有io,并且也回写了io数据到内存中,那现在基本可以确定问题出在虚拟机内部,可能是驱动没有上送这个io,也可能是存储协议栈没有上送这个io,需要进一步定位。
crash分析过程:
首先用virsh命令产生虚机的vmcore:
# virsh qemu-monitor-command --hmp 8c459758-ad37-9b79-c625-6fb5c3fef286 "dump-guest-memory -z 8c459758-ad37-9b79-c625-6fb5c3fef286.img"
然后准备crash分析环境:
# rpm -qa | grep kernel-debug kernel-debuginfo-5.10.0-136.12.0.88.2.ctl3.x86_64
kernel-debuginfo-5.10.0-136.12.0.88.2.ctl3.x86_64
#yum search kernel-debug
#yum search kernel-debug --showduplicates
#dnf install kernel-debuginfo-5.10.0-136.12.0.88.2.ctl3.x86_64
执行crash命令分析:
# cp /lib/modules/5.10.0-136.12.0.88.2.ctl3.x86_64/kernel/drivers/block/virtio_blk.ko.xz ./
# xz -d ./virtio_blk.ko.xz
# pwd
/usr/src/linux-5.10.0-136.12.0.88.2.ctl3.x86_64/work
# find /usr/ -name vmlinux /usr/lib/debug/usr/lib/modules/5.10.0-136.12.0.88.2.ctl3.x86_64/vmlinux
#crash ./069b4dfb-bc6e-7467-5003-0a0e2623ecbf.img /usr/lib/debug/usr/lib/modules/5.10.0-136.12.0.88.2.ctl3.x86_64/vmlinux
crash> mod -s virtio_blk /usr/lib/debug/lib/modules/5.10.0-136.12.0.88.2.ctl3.x86_64/kernel/drivers/block/virtio_blk.ko-5.10.0-136.12.0.88.2.ctl3.x86_64.debug
通过数据结构找到blk驱动相关的数据:

virtio_blk和gendisk的关联:

打印所有硬盘的blk信息,并找到对应的virt queue:

可以看到在这个磁盘对应的一个queue上面

可以看到avail_idx_shadow和last_used_idx不一致,并且avail_idx_shadow比last_used_idx多了一个io,飞行io也是一个,问题能对应上。avail_idx_shadow表示驱动avail ring的当前提交索引,这个值通过写入硬件的avail->idx并notify来通知硬件处理,last_used_idx表示used vring的最后处理索引,设备处理完请求后写入used ring并更新used->idx然后中断来通知驱动取数据,驱动通过比较last_used_idx和used->idx来确定哪些请求已完成并上送 ,进一步需要看硬件的avail vring 和used vring

这个两个值一致,说明硬件接收到了通知并且处理了这个io,也完成了这个io,但存在last_used_idx和used->idx差1的情况,并且没恢复,说明是驱动不知道硬件设备完成了一个io,说明这里是少了一个硬件通知,即少了一个中断。
解决方案:
通过补硬件中断解决这个驱动一直收不上io的问题,这里是通过软件vdpa来补这样一个中断。