KDMP真实案例之主机 I/O 请求没有正常结束导致系统重启

目录

查看kdump文件

导致系统崩溃的寄存器指向的内存地址

导致重启的汇编指令

导致重启的源码

block/blk-core.c文件简介

导致重启的blk_finish_request函数源码

函数源码解读

系统重启原因

处理意见


查看kdump文件

各字段意思说明
KERNEL:显示内核文件的路径。
DUMPFILE:显示崩溃转储文件的路径和类型(部分转储)。
CPUS:显示系统中的 CPU 数量。
DATE:显示系统崩溃的日期和时间。
UPTIME:显示系统崩溃前的正常运行时间。
LOAD AVERAGE:显示系统在崩溃前的负载情况。
TASKS:显示系统中运行的任务数。
NODENAME:显示主机名。
RELEASE:显示系统的内核版本号。
VERSION:显示系统内核的详细版本信息。
MACHINE:显示系统所在的机器架构。
MEMORY:显示系统可用内存大小。
PANIC:显示导致系统崩溃的错误信息。
PID:显示导致系统崩溃的进程 ID。
COMMAND:显示导致系统崩溃的命令。
TASK:显示与崩溃相关的进程信息。
CPU:显示导致系统崩溃的 CPU 核心编号。
STATE:显示导致系统崩溃的进程状态。在以上截图中,进程处于 TASK_RUNNING(运行状态),并且系统崩溃了。

根据日志中的信息,系统崩溃的原因是一个内核 BUG,具体位置在 block/blk-core.c 文件的第 2500 行。

导致系统崩溃的寄存器指向的内存地址

通过log命令找到RIP寄存器存储的地址

各类寄存器说明

RIP:指令指针寄存器,记录了下一条将要执行的指令在内存中的地址。
RSP:栈指针寄存器,记录了当前栈顶的地址。
EFLAGS:标志寄存器,记录了 CPU 的运行状态和控制信息,如进位标志、零标志、中断使能标志等。
RAX、RBX、RCX、RDX、RSI、RDI、RBP、R8-R15:通用寄存器,用于存储计算过程中的数据和地址等信息。
FS、GS:段寄存器,用于存储指向各自段的基址。在这里,FS 存储了一个用户空间的地址,而 GS 存储了一个内核空间的地址。
CR0-CR4:控制寄存器,用于控制 CPU 的运行模式和特性。
CR2、CR3:页表寄存器,用于存储页表的基地址。
DR0-DR7:调试寄存器,用于存储调试信息,如断点地址、访问权限等。

导致重启的汇编指令

以上是Linux内核版本3.10.0-123.8.1.el7中blk-core.c文件中的blk_finish_request()函数的汇编代码,代码采用x86_64体系结构。以下是代码的简要说明:

  1. 使用cmpl指令将rbx寄存器的值加上偏移量0x50得到的内存地址中的值与0x1进行比较。
  2. 如果比较结果不相等,则跳转到blk_finish_request()函数的第51行。否则,将从rbx寄存器的值加上偏移量0x38得到的内存地址中的值移动到rax寄存器中。然后通过将0x190添加到rax中得到内存地址,并将其存储在rdi寄存器中。最后,使用callq指令调用位于0xffffffff8114d460内存地址的函数laptop_io_completion()。
  3. 跳转到blk_finish_request()函数的第51行
  4. 这一行包含指令“ud2”。这是一个未定义的指令,用于向操作系统发出异常信号。通常情况下,它代表程序遇到错误并且无法继续执行。

导致重启的源码

block/blk-core.c文件简介

block/blk-core.c是Linux内核源代码中的一个文件,它实现了内核I/O子系统中的核心块层功能。块层提供了一个接口,让其他内核子系统和用户空间程序能够在块设备上执行I/O操作,例如硬盘驱动器和固态硬盘;blk-core.c文件包含管理块设备和处理这些设备的I/O请求的函数和数据结构。它实现了关键功能,例如请求合并、I/O调度和I/O限制,以提高性能并确保在竞争I/O请求之间公平分配资源。

导致重启的blk_finish_request函数源码

函数源码解读

这段代码是 Linux 内核中块设备层的代码,用于完成块 I/O 请求。该函数接受两个参数:一个是指向request结构体的指针,另一个是错误码。代码的主要作用是完成 I/O 请求,释放相关的资源,并通知请求的发起者该操作已完成。具体来说,它执行以下几个操作:

  1. 如果请求已经被标记,就调用 blk_queue_end_tag() 函数结束标记。
  2. 检查请求是否仍在等待处理,如果是,就使用 BUG_ON() 抛出 BUG 错误。
  3. 如果 laptop_mode 开启且请求的类型是文件系统请求,就调用 laptop_io_completion() 函数来通知系统已完成请求。
  4. 删除定时器,以便释放相关资源。
  5. 如果请求没有被标记为不需要准备,就调用 blk_unprep_request() 函数。
  6. 帐户 I/O 完成,以便更新块设备的统计信息。
  7. 如果请求有回调函数(end_io),就调用它来通知请求已经完成,否则,如果请求是双向请求,则将其下一个请求放回队列中;否则,将请求放回队列中。

系统重启原因

云主机 I/O 请求没有正常结束导致系统重启

处理意见

选用高版本内核观察测试

注:

任何内核版本都有异常重启风险

猜你喜欢

转载自blog.csdn.net/zyqash/article/details/130077361
今日推荐