什么是OOPS
Oops是美国人比较常有的口语。就是有点意外,吃惊,或突然的意思。“oops”并不是很严重.对于linux内核来说,Oops就意外着内核出了异常,此时会将产生异常时出错原因,CPU的状态,出错的指令地址、数据地址及其他寄存器,函数调用的顺序甚至是栈里面的内容都打印出来,然后根据异常的严重程度来决定下一步的操作:杀死导致异常的进程或者挂起系统。
最典型的异常是在内核态引用了一个非法地址,通常是未初始化的野指针Null,这将导致页表异常,最终引发Oops。
Linux系统足够健壮,能够正常的反应各种异常。异常通常导致当前进程的死亡,而系统依然能够继续运转,但是这种运转都处在一种不稳定的状态,随时可能出问题。对于中断上下文的异常及系统关键资源的破坏,通常会导致内核挂起,不再响应任何事件。
内核的异常级别
内核的异常主要有三个级别,按照严重程度加深,可以分为BUG级->Oops级->Panic级。
BUG级:
Bug是指那些不符合内核的正常设计,但内核能够检测出来并且对系统运行不会产生影响的问题,比如在原子上下文中休眠,再内核中用BUG标识。
Oops
程序在内核态时,进入一种异常情况,比如引用非法指针导致的数据异常,数组越界导致的取指异常,此时异常处理机制能够捕获此异常,并将系统关键信息打印到串口上,正常情况下Oops消息会被记录到系统日志中去,可以通过journalctl -k命令查看.
Oops发生时,进程处在内核态,很可能正在访问系统关键资源,并且获取了一些锁,当进程由于Oops异常退出时,无法释放已经获取的资源,导致其他需要获取此资源的进程挂起,对系统的正常运行造成影响。通常这种情况,系统处在不稳定的状态,很可能崩溃。
Panic
当Oops发生在中断上下文中或者在进程0和1中,系统将彻底挂起,因为中断服务程序异常后,将无法恢复,这种情况即称为内核panic。另外当系统设置了panic标志时,无论Oops发生在中断上下文还是进程上下文,都将导致内核Panic。由于在中断复位程序中panic后,系统将不再进行调度,rsyslogd将不会再运行,因此这种情况下,Oops的消息仅仅打印到串口上,不会被记录在系统日志中。
oops要不要panic依据几个体哦见,分别是:
在中断中oops.
通过设置/proc/sys/kernel/panic_on_oops将panic_on_oops置位。
进程为0号或者1号进程.
kexec_should_crash(current)会判断进程是否为0号或者1号进程,如果是的话,oops会转变为panic.
panic的执行逻辑
流程中的细节要点:
代码尽其所能避免复杂性和可能的死锁
KERN_EMERG 内核打印信息 “Kernel panic - not syncing”
panic_print_sys_info();确定并显示更多系统信息–例如所有任务信息、内存、计时器、锁、ftrace信息和所有内核打印。具体取决于panic_print的bitmask
函数所做的最后一件事就是在单个启用的处理器核上无限循环;在循环中,它重置非屏蔽中断(NMI),然后定期调用一个名为架构依赖的panic_blink函数;在x86上,该事件会引起键盘LED会闪烁.
由于在函数入口处关闭了调度,所以控制台不会在有反应,系统卡死,只能冷上电。
oops要不要转成panic
前面说到,内核文件系统有一个节点/proc/sys/kernel/panic_on_oops,可以控制在oops执行结束前,要不要执行panic.
代码中的逻辑如下:
当检测到设置了panic_on_oops时,执行panic
打开/proc/sys/kernel/panic_on_oops测试,触发越界访问的oops导致的panic.PC直接挂死,电脑无反应。
panic_timeout
panic_timeout通过 /proc/sys/kernel/panic 节点去设置,代表panic后等待几秒系统重启,默认情况为0代表不会重启,一直等待。
重启调用接口emergency_restart。
其它panic控制变量还包括如下例表中的项:
-rw-r--r-- 1 root root 0 2月 1 19:26 /proc/sys/kernel/panic
-rw-r--r-- 1 root root 0 2月 1 19:26 /proc/sys/kernel/panic_on_io_nmi
-rw-r--r-- 1 root root 0 2月 1 19:26 /proc/sys/kernel/panic_on_oops
-rw-r--r-- 1 root root 0 2月 1 19:26 /proc/sys/kernel/panic_on_rcu_stall
-rw-r--r-- 1 root root 0 2月 1 19:26 /proc/sys/kernel/panic_on_unrecovered_nmi
-rw-r--r-- 1 root root 0 2月 1 19:26 /proc/sys/kernel/panic_on_warn
-rw-r--r-- 1 root root 0 2月 1 19:26 /proc/sys/kernel/panic_print
这些参数不但可以通过sysctl建立的procfs去设置,还可以通过启动命令行控制。
以qemu为例,启动参数命令行中传入panic=88
qemu-system-arm -M vexpress-a9 -m 1024M -kernel arch/arm/boot/zImage -append "rdinit=/linuxrc console=ttyAMA0 loglevel=8 panic=88" -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb -nographic
panic_timeout can also be set from config macro.int panic_timeout = CONFIG_PANIC_TIMEOUT;