oops 和warning和panic类似的地方是,他们都是因内核发现了不一致而主动报告的异常. 但oops和warning导致的问题严重程度要比panic轻很多,以致于内核处理该问题时不需要使系统挂起. 产生oops和warning, 内核通常已经在dmesg中记录了相当的信息,特别是oops, 至少会打印出现故障的地方的call trace. Oops也可转换成panic/kdump来进行offline-debugging, 只要将/proc/sys/kernel下的panic_on_oops变量设置为1就行了.
产生oops和warning的直接原因有很多,如内核中的segment fault, 或内核发现的某数据结构的counter值不对, 而segment fault 和counter值的变化还有更深层次的原因,通常并不能从内核dmesg的信息中看出来,解决这种问题的是要用SystemTap进行probe, 如发现某counter的值不对,就用SystemTap做一个probe来记录所有代码对该counter的访问, 然后再进行分析.
定位oops和warning会比定��应用程序的内存访问故障困难很多,因为在内核并不能象用valgrind去trace应用程序一样跟踪数据结构的分配和使用情况.
2. 其他(硬件相关)故障
机器自动重启是一种常见的故障情形,一般是由硬件如物理内存故障引起的,软件的故障只会导致死锁或panic, 内核中几乎没有代码在发现问题的情况下去reboot机器. 在/proc/sys/kernel目录下有个参数“panic”, 其值如果设置为非0,则在panic发生若干秒后,内核会重启机器. 现在高端的PC服务器,都在努力用软件来处理物理内存故障,如MCA的 “HWPoison”方法会将故障的物理页隔离起来,Kill掉故障页所在的进程就可以了,RHEL6现在已经支持 “HWPoison”. 那些不具备MCA能力的机器,物理内存故障时,不会产生MCE异常,直接由硬件机制reboot机器
3. RHEL6 上的Debugging技术介绍
A) Kdump故障收集和crash分析
kdump就是用来在内核panic的情况下收集系统内存信息的, 用户也可在online情况下用sysrq的'c'键触发. Kdump 采用没有污染的内核来执行dump工作,所以其比以前的diskdump, lkcd方法更可靠. 使用kdump,用户可选择将数据dump到本地盘或网络上,也可通过定义makedumpfile的参数过滤要收集的内存信息,已减少kdump所需要的停机时间
Crash就是对kdump的信息进行分析的工具.其实际就是gdb的一个wrapper. 使用crash时,最好安装kernel-debuginfo包,这样能解析kdump收集的内核数据的符号信息. 用crash来定位问题的能力,完全取决于用户对内核代码的理解和分析能力
参考 “#>man kdump.conf”, “#>man crash”, “#>man makedumpfile”学习怎样使用kdump和crash. 访问 RedHat.com可下载debuginfo文件
B) 用systemTap定位bug
systemtap 属于probe类的定位工具,它能对内核或用户代码的指定位置进行probe, 当执行到指定位置或访问指定位置的数据时,用户定义的probe函数自动执行,可打印出该位置的调用堆栈,参数值,变量值等信息. systemtap选择进行probe的位置很灵活,这是systemtap的强大功能所在. Systemtap的probe点可包括如下几个方面:
l 内核中全部系统调用,内核及模块中全部函数的入口或出口点
l 自定义的定时器probe点
l 内核中任意指定的代码或数据访问位置
l 特定用户进程中任意制定的代码或数据访问位置
l 各个功能子系统预先设置的若干probe点,如tcp,udp,nfs,signal各子系统都预先设置了很多探测点
systemTap的脚本用stap脚本语言来编写,脚本代码中调用stap提供的API进行统计,打印数据等工作,关于stap语言提供的API函数,参考 “#> man stapfuncs”. 关于systemTap的功能和使用可参考 “#> man stap”, “#> man stapprobes”
C) ftrace
ftrace 是linux内核中利用tracepoints基础设施实现的事件追踪机制,它的作用在于能比较清楚的给出在一定时间内系统或进程所执行的活动,如函数调用路径,进程切换流等. Ftrace可用于观察系统各部分的latency,以便进行实时应用的优化;它也可以通过记录一段时间内的内核活动来帮助定位故障. 如用以下方法可trace某个进程在一端时间的函数调用情况
#> echo “function” > /sys/kernel/debug/tracing/current_tracer
#> echo “xxx” > /sys/kernel/debug/tracing/set_ftrace_pid
#> echo 1 > /sys/kernel/debug/tracing/tracing_enabled