本文介绍如何处理在部分高版本内核的ECS实例中热拔virtio设备时出现Oops异常的问题。
问题现象
在部分高版本内核的ECS实例中热拔virtio设备(例如磁盘、网卡)时,操作系统会发生如下Oops异常:
在配置了
kernel.panic_on_oops = 1
的实例中,会发生内核Panic异常。在配置了
kernel.panic_on_oops = 0
的实例中,会出现hung错误。
kernel.panic_on_oops
是一个内核参数,控制内核遇到Oops(内核错误)时的行为。
内核Panic异常:系统会停止运行当前任务,保存调试信息,然后重启或关机,有助于快速响应问题并减少潜在的损害。
内核hung错误:内核可能会尝试继续运行,但在生产环境中不推荐,因为可能会导致数据损坏或其他严重问题。
问题原因
Linux上游社区在内核社区中添加了对virtio设备Admin Virtqueue的支持:commit详情。
在该commit中:
对virtio_pci_device的定义中添加了一个is_avq的函数指针,用于判断是否存在Admin Virtqueue。
在modern virtio设备的初始化函数virtio_pci_modern_probe中赋值了is_avq函数指针。
在热拔virtio设备时,代码会检查当前队列是否为Admin Virtqueue。
但是如果该virtio设备是legacy virtio设备,is_avq函数指针没有被赋值,导致legacy virtio设备中的virtio_pci_device结构体中的函数指针is_avq是一个空指针(NULL Pointer)。此时如果热拔virtio设备,调用if (vp_dev->is_avq(vdev, vq->index))
时,会触发空指针异常,会导致程序崩溃或系统错误。
影响范围
Linux上游社区
上游社区已经针对该问题进行了修复:commit详情。在该commit中,对is_avq函数指针是否为空的情况进行了判断,修复了该问题。
操作系统
Ubuntu 24
其他内核版本在6.8左右的操作系统,且这些操作系统合入了Admin Virtqueue能力(virtio-pci: Introduce admin virtqueue),但未修复is_avq函数指针判断问题(virtio-pci: Check if is_avq is NULL)。
说明您可以通过
uname -r
命令查询内核版本。
virtio设备
实例使用了legacy virtio设备,并在进行热拔操作。
解决方案
方案一:建议更换为modern virtio设备的实例规格族(8代及以上规格),该类实例规格族不受该问题影响。具体操作,请参见修改实例规格。关于实例规格族的更多信息,请参见实例规格族。
方案二:
升级最新内核软件包,并确认最新软件包是否已合入is_avq函数指针判断的补丁包:virtio-pci: Check if is_avq is NULL。
(条件必选)如果最新的内核中没有合入is_avq函数指针判断的补丁包,请自行合入。
附录:名词解释
关于文档中涉及的virtio设备、Admin Virtqueue、virtio_pci_device等名词解释说明如下:
名词 | 说明 |
virtio设备 | virtio是一种标准化的虚拟化设备通信框架,允许虚拟机高效地与宿主机上的虚拟硬件设备交互。virtio设备是在虚拟化环境中模拟出来的硬件设备(如磁盘、网卡),分为传统legacy virtio和现代modern virtio两类,主要区别在于使用的配置接口不同。 |
Admin Virtqueue | 是一个特殊的virtio队列,用于执行设备的管理操作,比如获取设备状态、配置设备等。并非所有virtio设备都支持Admin Virtqueue。 |
virtio_pci_device | 是在内核中表示一个virtio PCI设备的数据结构,包含了指向各种功能函数的指针,其中之一就是新添加的is_avq函数指针,用于判断给定的队列是否为Admin Virtqueue。 |
is_avq | 该函数用于判断给定的virtio队列是否为Admin Virtqueue。 |
virtio_pci_modern_probe | 该函数负责virtio PCI设备的探测和初始化过程。在设备被系统发现后,此函数会被调用来完成设备的设置,包括配置空间的读取、设备特性的检测以及必要的资源分配等。 |
RIP寄存器 | RIP(Instruction Pointer Register)寄存器是x86架构CPU中的一个寄存器,存储了当前执行指令的下一条指令的地址。当程序发生异常,如尝试执行一个空指针所指向的地址时,RIP寄存器会指向引发异常的那条指令的地址。 |