https://wiki.deepin.org/?title=Linux_kernel_panic
简介
内核错误就像名字所暗示的那样,它表示Linux kernel走到了一个不知道该怎么走下一步的状况,一旦到这个情况,kernel就尽可能把它此时能获取的全部信息都打印出来,至于能打印出多少信息,那就看是那种情况导致它panic了。
有两种主要类型kernel panic:
- .hard panic(也就是Aieee信息输出)
- soft panic (也就是Oops信息输出)
什么能导致kernel panic
只有加载到内核空间的驱动模块才能直接导致kernel panic,你可以在系统正常的情况下,使用lsmod查看当前系统加载了哪些模块。 除此之外,内建在内核里的组件(比如memory map等)也能导致panic。
因为hard panic和soft panic本质上不同,因此我们分别讨论。
一般出现下面的情况,就认为是发生了kernel panic:
- 机器彻底被锁定,不能使用
- 数字键(Num Lock),大写锁定键(Caps Lock),滚动锁定键(Scroll Lock)不停闪烁。
- 如果在终端下,应该可以看到内核dump出来的信息(包括一段”Aieee”信息或者”Oops”信息)
- 和Windows蓝屏相似
Linux kernel panic
内核错误(Kernel panic)是指操作系统在监测到内部的致命错误,并无法安全处理此错误时采取的动作。这个概念主要被限定在Unix以及类Unix系统中;对于Microsoft Windows系统,等同的概念通常被称为蓝屏死机。
操作系统内核中处理Kernel panic的子程序(在AT&T派生类以及BSD类Unix中,通常称为panic())通常被设计用来向控制台输出错误信息,向磁盘保存一份内核内存的转储,以便事后的调试,然后等待系统被手动重新引导,或自动重新引导。该程序提供的技术性信息通常是用来帮助系统管理员或者软件开发者诊断问题的。
操作系统试图读写无效或不允许的内存地址是导致内核错误的一个常见原因。内核错误也有可能在遇到硬件错误或操作系统BUG时发生。在许同情况中,操作系统可以在内存访问违例发生时继续运行。然而,系统处于不稳定状态时,操作系统通常会停止工作以避免造成破坏安全和数据损坏的风险,并提供错误的诊断信息。
内核错误在早期的Unix系统中被引入,显示了在Unix与Multics在设计哲学上的主要差异之一。Multics的开发者Tom van Vleck曾引述了一段在这个问题上与Unix开发者Dennis Ritchie的讨论:
我提醒Dennis说,我在Multics中写的近半数代码都是错误恢复代码。 他说:“我们不需要这些。我们有称为panic的子程序,如果发生了错误就可以调用这个函数,使得系统崩溃, 然后你可以在大厅里面大叫:‘嘿,重启机器’。”
原始的panic()函数从UNIX第五版开始到基于VAX的UNIX 32V期间几乎没有变化,只是输出一条错误信息,然后就使系统进入NOP的死循环中。当改进UNIX的基础代码的时候,panic()函数也有所改进,可以向控制台输出多种格式的调试信息。
Linux kernel oops
在Linux上,oops即Linux内核的行为不正确,并产生了一份相关的错误日志。许多类型的oops会导致内核错误,即令系统立即停止工作,但部分oops也允许继续操作,作为与稳定性的妥协。这个概念只代表一个简单的错误。
当内核检测到问题时,它会打印一个oops信息然后终止全部相关进程。oops信息可以帮助Linux内核工程师调试,检测oops出现的条件,并修复导致oops的程序错误。
Linux官方内核文档中提到的oops信息被放在内核源代码Documentation/oops-tracing.txt中。通常klogd是用来将oops信息从内核缓存中提取出来的,然而,在某些系统上,例如最近的Debian发行版中,rsyslogd代替了klogd,因此,缺少klogd进程并不能说明log文件中缺少oops信息的原因。
若系统遇到了oops,一些内部资源可能不再可用。即使系统看起来工作正常,非预期的副作用可能导致活动进程被终止。内核oops常常导致内核错误,若系统试图使用被禁用的资源。
Kernelloops提到了一种用于收集和提交oops到 http://www.kerneloops.org/ 的软件 。Kerneloops.org同时也提供oops的统计信息。
简单处理
- 系统死机:系统死机的处理。
分析
kernel panic表现
kernel panic错误表现kernel panic 主要有以下几个出错提示:
Kernel panic-not syncing fatal exception in interrupt kernel panic - not syncing: Attempted to kill the idle task! kernel panic - not syncing: killing interrupt handler! Kernel Panic - not syncing:Attempted to kill init !
kernel错误分析
查看了一下 linux的源码文件,找到相关位置
kernel/panic.c NORET_TYPE void panic(const char * fmt, ...) { static char buf[1024]; va_list args; bust_spinlocks(1); va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); printk(KERN_EMERG "Kernel panic - not syncing: %s/n",buf); bust_spinlocks(0); kernel/exit.c if (unlikely(in_interrupt())) panic("Aiee, killing interrupt handler!"); #中断处理 if (unlikely(!tsk->pid)) panic("Attempted to kill the idle task!"); #空任务 if (unlikely(tsk->pid == 1)) panic("Attempted to kill init!"); #初始化
从其他源文件和相关文档看到应该有几种原因:
1、硬件问题
使用了 SCSI-device 并且使用了未知命令
#WDIOS_TEMPPANIC Kernel panic on temperature trip # # The SETOPTIONS call can be used to enable and disable the card # and to ask the driver to call panic if the system overheats. # # If one uses a SCSI-device of unsupported type/commands, one # immediately runs into a kernel-panic caused by Command Error. To better # understand which SCSI-command caused the problem, I extended this # specific panic-message slightly. # #read/write causes a command error from # the subsystem and this causes kernel-panic
2、系统过热
如果系统过热会调用panci,系统挂起
#WDIOS_TEMPPANIC Kernel panic on temperature trip # # The SETOPTIONS call can be used to enable and disable the card # and to ask the driver to call panic if the system overheats.
3、文件系统引起
#A variety of panics and hangs with /tmp on a reiserfs filesystem #Any other panic, hang, or strange behavior # # It turns out that there's a limit of six environment variables on the # kernel command line. When that limit is reached or exceeded, argument # processing stops, which means that the 'root=' argument that UML # usually adds is not seen. So, the filesystem has no idea what the # root device is, so it panics. # The fix is to put less stuff on the command line. Glomming all your # setup variables into one is probably the best way to go.
Linux内核命令行有6个环境变量。如果即将达到或者已经超过了的话 root= 参数会没有传进去启动时会引发panics错误。
vi grub.conf ##################### title Red Hat Enterprise Linux AS (2.6.9-67.0.15.ELsmp) root (hd0,0) kernel /boot/vmlinuz-2.6.9-67.0.15.ELsmp ro root=LABEL=/ initrd /boot/initrd-2.6.9-67.0.15.ELsmp.img title Red Hat Enterprise Linux AS-up (2.6.9-67.EL) root (hd0,0) kernel /boot/vmlinuz-2.6.9-67.EL ro root=LABEL=/ initrd /boot/initrd-2.6.9-67.EL.img
应该是 其中的 root=LABEL=/ 没有起作用。
4、内核更新
网上相关文档多半是因为升级内核引起的,建议使用官方标准版、稳定版另外还有使用磁盘的lvm 逻辑卷,添加CPU和内存。可在BIOS中禁掉声卡驱动等不必要的设备。
也有报是ext3文件系统的问题。解决: 手工编译内核,把 ext3相关的模块都编译进去,
5、处理panic后的系统自动重启
panic.c源文件有个方法,当panic挂起后,指定超时时间,可以重新启动机器
if (panic_timeout > 0) { int i; /* * Delay timeout seconds before rebooting the machine. * We can't use the "normal" timers since we just panicked.. */ printk(KERN_EMERG "Rebooting in %d seconds..",panic_timeout); for (i = 0; i < panic_timeout; i++) { touch_nmi_watchdog(); mdelay(1000); }
修改方法:/etc/sysctl.conf文件中加入
kernel.panic = 30 #panic错误中自动重启,等待时间为30秒 kernel.sysrq=1 #激活Magic SysRq! 否则,键盘鼠标没有响应
Linux Kernel Panic之后的招数
Linux的稳定性勿容置疑,但是有些时候一些Kernel的致命错误还是会发生(有些时候甚至是因为硬件的原因或驱动故障),Kernel Panic会导致系统crash,并且默认的系统会一直hung在那里,直到你去把它重新启动!不过你可以在/etc/sysctl.conf文件中加入
kernel.panic = 20
来告诉系统从Panic错误中自动重启,等待时间为20秒!这个由管理员自己设定!另外一个讨厌的事情是系统hung住之后,键盘鼠标没有响应,这个可以通过设置Magic SysRq来试着解决,也是在/etc/sysctl.conf中,
kernel.sysrq=1
来激活Magic SysRq!这样在挂住的时候至少还有一招可以使,按住 [ALT]+[SysRq]+[COMMAND], 这里SysRq是Print SCR键,而COMMAND按以下来解释!b - 立即重启
- e - 发送SIGTERM给init之外的系统进程
- o - 关机
- s - sync同步所有的文件系统
- u - 试图重新挂载文件系统
当然,谁也不希望经常用到这些招数!:O,有备无患而已
Kernel panic问题如何调试Linux kernel panic是很难定位和排查的重大故障,一旦系统发生了kernel panic,相关的日志信息非常少,而一种常见的排查方法—重现法–又很难实现,因此遇到kernel panic的问题,一般比较头疼。
没有一个万能和完美的方法来解决所有的kernel panic问题,这篇文章仅仅只是给出一些思路,一来如何解决kernel panic的问题,二来可以尽可能减少发生kernel panic的机会。
Kernel panic问题如何调试
Linux kernel panic是很难定位和排查的重大故障,一旦系统发生了kernel panic,相关的日志信息非常少,而一种常见的排查方法—重现法–又很难实现,因此遇到kernel panic的问题,一般比较头疼。
没有一个万能和完美的方法来解决所有的kernel panic问题,这篇文章仅仅只是给出一些思路,一来如何解决kernel panic的问题,二来可以尽可能减少发生kernel panic的机会。
原因
对于hard panic而言,最大的可能性是驱动模块的中断处理(interrupt handler)导致的,一般是因为驱动模块在中断处理程序中访问一个空指针(null pointre)。一旦发生这种情况,驱动模块就无法处理新的中断请求,最终导致系统崩溃。
信息收集
根据panic的状态不同,内核将记录所有在系统锁定之前的信息。因为kenrel panic是一种很严重的错误,不能确定系统能记录多少信息,下面是一些需要收集的关键信息,他们非常重要,因此尽可能收集全,当然如果系统启动的时候就kernel panic,那就无法只知道能收集到多少有用的信息了。
- /var/log/messages: 幸运的时候,整个kernel panic栈跟踪信息都能记录在这里。
- 应用程序/库 日志: 可能可以从这些日志信息里能看到发生panic之前发生了什么。
- 其他发生panic之前的信息,或者知道如何重现panic那一刻的状态
- 终端屏幕dump信息,一般OS被锁定后,复制,粘贴肯定是没戏了,因此这类信息,你可以需要借助数码相机或者原始的纸笔工具了。
如果kernel dump信息既没有在/var/log/message里,也没有在屏幕上,那么尝试下面的方法来获取(当然是在还没有死机的情况下):
- 如果在图形界面,切换到终端界面,dump信息是不会出现在图形界面的,甚至都不会在图形模式下的虚拟终端里。
- 确保屏幕不黑屏,可以使用下面的几个方法:
setterm -blank 0 setterm -powerdown 0 setvesablank off
- 从终端,拷贝屏幕信息(方法见上)
完整栈跟踪信息的排查方法
栈跟踪信息(stack trace)是排查kernel panic最重要的信息,该信息如果在/var/log/messages日志里当然最好,因为可以看到全部的信息,如果仅仅只是在屏幕上,那么最上面的信息可能因为滚屏消失了,只剩下栈跟踪信息的一部分。如果你有一个完整栈跟踪信息的话,那么就可能根据这些充分的信息来定位panic的根本原因。要确认是否有一个足够的栈跟踪信息,你只要查找包含”EIP”的一行,它显示了是什么函数和模块调用时导致panic。大概就像下面这个例子一样:
EIP is at _dlgn_setevmask [streams-dlgnDriver] 0xe hard panic的一个完整跟踪信息例子: Unable to handle kernel NULL pointer dereference at virtual address 0000000c printing eip: f89e568a *pde = 32859001 *pte = 00000000 Oops: 0000 Kernel 2.4.9-31enterprise CPU: 1 EIP: 0010:[<f89e568a>] Tainted: PF EFLAGS: 00010096 EIP is at _dlgn_setevmask [streams-dlgnDriver] 0xe eax: 00000000 ebx: f65f5410 ecx: f5e16710 edx: f65f5410 esi: 00001ea0 edi: f5e23c30 ebp: f65f5410 esp: f1cf7e78 ds: 0018 es: 0018 ss: 0018 Process pwcallmgr (pid: 10334, stackpage=f1cf7000) Stack: 00000000 c01067fa 00000086 f1cf7ec0 00001ea0 f5e23c30 f65f5410 f89e53ec f89fcd60 f5e16710 f65f5410 f65f5410 f8a54420 f1cf7ec0 f8a4d73a 0000139e f5e16710 f89fcd60 00000086 f5e16710 f5e16754 f65f5410 0000034a f894e648 Call Trace: [setup_sigcontext+218/288] setup_sigcontext [kernel] 0xda Call Trace: [<c01067fa>] setup_sigcontext [kernel] 0xda [<f89e53ec>] dlgnwput [streams-dlgnDriver] 0xe8 [<f89fcd60>] Sm_Handle [streams-dlgnDriver] 0×1ea0 [<f8a54420>] intdrv_lock [streams-dlgnDriver] 0×0 [<f8a4d73a>] Gn_Maxpm [streams-dlgnDriver] 0×8ba [<f89fcd60>] Sm_Handle [streams-dlgnDriver] 0×1ea0 [<f894e648>] lis_safe_putnext [streams] 0×168 [<f8a7b098>] __insmod_streams-dvbmDriver_S.bss_L117376 [streams-dvbmDriver] 0xab8 [<f8a78821>] dvbmwput [streams-dvbmDriver] 0×6f5 [<f8a79f98>] dvwinit [streams-dvbmDriver] 0×2c0 [<f894e648>] lis_safe_putnext [streams] 0×168 [<f893e6d8>] lis_strputpmsg [streams] 0×54c [<f895482e>] __insmod_streams_S.rodata_L35552 [streams] 0×182e [<f8951227>] sys_putpmsg [streams] 0×6f [system_call+51/56] system_call [kernel] 0×33 [<c010719b>] system_call [kernel] 0×33 Nov 28 12:17:58 talus kernel: Nov 28 12:17:58 talus kernel: Code: 8b 70 0c 8b 06 83 f8 20 8b 54 24 20 8b 6c 24 24 76 1c 89 5c
完整栈信息无效的排查方法
如果只有部分跟踪信息,要快速定位问题的根本原因就变得很难,因为没有明显的信息来告诉我们是哪个模块或者函数的调用导致了内核panic,你可能只能看到kernel最后的一些指令。这种情况下,要尽可能多的收集信息,包括程序日志,库的跟踪信息,故障重现的步骤等。
Hard panic 部分跟踪信息例子(没有EIP信息):
[<c01e42e7>] ip_rcv [kernel] 0×357 [<f8a179d5>] sramintr [streams_dlgnDriver] 0×32d [<f89a3999>] lis_spin_lock_irqsave_fcn [streams] 0×7d [<f8a82fdc>] inthw_lock [streams_dlgnDriver] 0×1c [<f8a7bad8>] pwswtbl [streams_dlgnDriver] 0×0 [<f8a15442>] dlgnintr [streams_dlgnDriver] 0×4b [<f8a7c30a>] Gn_Maxpm [streams_dlgnDriver] 0×7ae [<c0123bc1>] __run_timers [kernel] 0xd1 [<c0108a6e>] handle_IRQ_event [kernel] 0×5e [<c0108c74>] do_IRQ [kernel] 0xa4 [<c0105410>] default_idle [kernel] 0×0 [<c0105410>] default_idle [kernel] 0×0 [<c022fab0>] call_do_IRQ [kernel] 0×5 [<c0105410>] default_idle [kernel] 0×0 [<c0105410>] default_idle [kernel] 0×0 [<c010543d>] default_idle [kernel] 0×2d [<c01054c2>] cpu_idle [kernel] 0×2d [<c011bb86>] __call_console_drivers [kernel] 0×4b [<c011bcfb>] call_console_drivers [kernel] 0xeb Code: 8b 50 0c 85 d2 74 31 f6 42 0a 02 74 04 89 44 24 08 31 f6 0f <0> Kernel panic: Aiee, killing interrupt handler! In interrupt handler – not syncing
使用内核调试工具(kenrel debugger ,aka KDB)
如果跟踪信息只有一部分且不足以用来定位问题的根本原因时,kernel debugger(KDB)就需要请出来了。KDB编译到内核里,panic发生时,他将内核引导到一个shell环境而不是锁定。这样,我们就可以收集一些与panic相关的信息了,这对我们定位问题的根本原因有很大的帮助。
使用KDB需要注意,内核必须是基本核心版本,比如是2.4.18,而不是2.4.18-5这样子的,因为KDB仅对基本核心有效。
如何排查soft panic症状:
- 没有hard panic严重
- 通常导致段错误(segmentation fault)
- 可以看到一个oops信息,/var/log/messages里可以搜索到’Oops’
- 机器稍微还能用(但是收集信息后,应该重启系统)
原因:凡是非中断处理引发的模块崩溃都将导致soft panic。在这种情况下,驱动本身会崩溃,但是还不至于让系统出现致命性失败,因为它没有锁定中断处理例程。导致hard panic的原因同样对soft panic也有用(比如在运行时访问一个空指针)
信息收集
当soft panic发生时,内核将产生一个包含内核符号(kernel symbols)信息的dump数据,这个将记录在/var/log/messages里。为了开始排查故障,可以使用ksymoops工具来把内核符号信息转成有意义的数据。
为了生成ksymoops文件,需要:
- 从/var/log/messages里找到的堆栈跟踪文本信息保存为一个新文件。确保删除了时间戳(timestamp),否则ksymoops会失败。
- 运行ksymoops程序(如果没有,请安装)
- 详细的ksymoops执行用法,可以参考ksymoops(8)手册。
下面是一个soft panic的oopsg跟踪例子:
Code: 8b 70 0c 50 e8 69 f9 f8 ff 83 c4 10 83 f8 08 74 35 66 c7 47 EIP; f89ba71e <[streams-dlgnDriver]_dlgn_setidlestate+1e/8c> Trace; f8951bd6 <[streams]lis_wakeup_close+86/110> Trace; f8a2705c <[streams-dlgnDriver]__module_parm_r4_feature+280/1453> Trace; f8a27040 <[streams-dlgnDriver]__module_parm_r4_feature+264/1453> Trace; f89b9198 <[streams-dlgnDriver]dlgnwput+e8/204>
案例分析
Kernel Panic -- not syncing: attempted to kill idle task
出现这种错误是进入不了操作系统的,kernel panic的成因有多种多样,但这种情况是比较奇特的一种,因为它很可能不是软件的问题,而是硬件的问题。几年前我用带奔三的旧主板时遇到过,当时不知道如何解决,只知道它偶尔出现,放一放也会自行消失,所以当初没有重视。现在,当我重新用上旧主板,这种情况又出现了,而且这一次比较顽固,无论怎样重启,总是这条错误,不但硬盘上现有的两个操作系统都进不去,而且连光驱里的LiveCD也进不去了,这显然不是硬盘的问题,也不是内核的问题。以前我就明白应该是主板的问题,可能是主板太旧,电路信号不太通畅的原因,但不知道怎么办,害得我一天一宿没上网。今天早上去网吧,查了点资料,大体上有几种说法:
- 一种是在grub作内核引导时添加idle参数,这一种是国内网常见的一种说法;
- 第二个方法是注意一下bios中显示的CPU或者内存条的温度;
- 第三种是重新作initrd,即mkinitrd;
- 第四种是在grub中启动memtest86来测试内存,
这几个是外国人的论坛上说的。我回到家以后,先试了第一种,加了idle的各种参数后,毫无效果,关于第二种方法,我在bios中看到似乎硬件的温度不是可以调节的,但我从这个思路出发,考虑到,如果与内存有关,不妨把三个内存条互换一下位置,也许有效,于是,我把我的三个SD内存换了位置,然后开机,一切正常了。
Kernel Panic -- not syncing: attempted to kill init
这一种情况的表现是系统的极不稳定。或者进入不了系统,syslog停止于kernel panic;或者重启后可以进入系统,但不久就死机,键盘上的Caps-Lock与Scroll-Lock两个灯在闪。这种错误与上面那个有相同的成因,解决方法也相同。