linux panic 流程
Linux Kernel Panic(内核崩溃)的流程大致如下:
1. 发生严重错误
内核检测到无法继续运行的错误,例如:
- 空指针访问(NULL Pointer Dereference)
- 页错误(Page Fault)
- 栈溢出(Stack Overflow)
- 内核 BUG
- Watchdog 超时
- 内核内存损坏
- 驱动访问非法地址
例如:
int *p = NULL;
*p = 100;
在内核态执行就可能触发 Oops。
2. 进入异常处理
CPU产生异常:
CPU
↓
Exception
↓
IDT
↓
对应异常处理函数
例如:
#PF Page Fault
#GP General Protection
#UD Invalid Opcode
x86:
do_page_fault()
do_general_protection()
ARM:
do_mem_abort()
do_DataAbort()
3. 打印 Oops 信息
内核首先打印:
Unable to handle kernel NULL pointer dereference
然后输出:
PC
LR
SP
Call Trace
寄存器
进程名
CPU号
例如:
BUG: unable to handle kernel NULL pointer dereference
Call Trace:
driver_open()
misc_open()
do_dentry_open()
path_openat()
这一步叫:
Kernel Oops
4. 判断是否继续运行
内核有个参数:
panic_on_oops
查看:
cat /proc/sys/kernel/panic_on_oops
等于0
Oops
↓
杀死当前任务
↓
系统继续运行
很多服务器这样配置。
等于1
Oops
↓
panic()
↓
系统停止
5. 调用 panic()
核心函数:
panic()
源码位置:
kernel/panic.c
大致流程:
panic()
{
禁止抢占
停止其他CPU
输出日志
调用panic notifier
kdump
reboot/halt
}
6. 停止其它CPU
SMP系统:
CPU0
CPU1
CPU2
CPU3
如果CPU1崩溃:
CPU1 panic
↓
IPI
↓
停止CPU0 CPU2 CPU3
调用:
smp_send_stop()
7. 触发 Notifier
注册的模块会收到通知:
panic_notifier_list
例如:
- watchdog
- kdump
- crash logger
- BMC
panic
↓
notifier
↓
保存现场
8. Kdump
企业Linux最重要的一步。
panic
↓
crash kernel
↓
保存 vmcore
流程:
正常Kernel
↓ panic
Crash Kernel
↓
保存内存镜像
↓
vmcore
文件:
/var/crash/vmcore
之后可分析:
crash vmlinux vmcore
9. 输出 Panic 信息
屏幕会看到:
Kernel panic - not syncing:
Fatal exception
例如:
Kernel panic - not syncing:
Attempted to kill init!
或者:
Kernel panic - not syncing:
VFS: Unable to mount root fs
10. 等待重启
参数:
cat /proc/sys/kernel/panic
例如:
10
表示:
panic
↓
等待10秒
↓
自动重启
设置:
echo 5 > /proc/sys/kernel/panic
整体流程图
驱动BUG
↓
CPU异常
↓
Page Fault
↓
do_page_fault()
↓
Oops
↓
panic_on_oops ?
↓
├── 0
│ ↓
│ 杀死进程
│ ↓
│ 系统继续
│
└── 1
↓
panic()
↓
stop_other_cpus()
↓
panic_notifier
↓
kdump
↓
输出日志
↓
reboot/halt
如果你以后做 ONU/OLT、嵌入式 Linux、驱动开发面试,面试官经常会问:
- Oops 和 Panic 的区别?
- panic() 里面做了什么?
- kdump 如何抓取 vmcore?
- ARM Data Abort 如何变成 Kernel Panic?
