系统hung故障一般认为是系统出现了异常,但是内核并没有死掉,出现这种情况,一般都是系统中的关键进程处于D状态,也就是不可中断的睡眠状态(也叫Disk Sleep)。
那么什么情况下系统会处于D状态?
我觉得可以分为两种情况:
1.第一种为可恢复的D状态,表现为系统的卡顿,一般进程的D状态都是在获取系统资源时避免被外界异步信号打断而进入的,并且该状态正常情况下是维持时间很短的,如果是进入了D状态维持了很长的时间,那么可以认为该进程是无法获取到对应的资源下面举两个例子说明:
(1)比如访问一个网络文件系统,如果断网后进程会长时间处于D状态,其他的场景也是基本和I/O资源无法得到满足有关。
(2)再比如当系统中存在有大量写操作,一旦脏页累计到一定程度,继续写都会使进程D住,以等待脏页写入到对应磁盘中。
像这种情况,我们就需要把系统所需要的I/O资源给予满足,或者优化系统参数,尽量避免该情况继续出现,属于系统优化的领域。
2.第二种为不可恢复的D状态,一般是由于代码上的bug,比如线程之间发生了死锁情况,那么后续将无法恢复正常以继续运行了。常见的一种情况就是rw_semaphore和mutex的死锁,比如当两个进程处于AB-BA死锁状态,那么可能引发连锁反应,导致多个其他系统进程也进入D状态,因为进程之间是存在交互的,一个进程死锁,所有等待它的进程都进过进入的D状态,这样就引发了整个系统的瘫痪。
站在内核的角度来看,会是什么样子呢?
参考前面Linux内核故障分类和排查 这篇文章,在内核的角度来看,一般进程是持有了rw_semaphore和mutex并且长时间不释放导致进程一直处于D状态。
对于系统hung住的故障,场景也基本符合上面的分析,如果是单个进程hung住,实际上并不会影响到系统的其他功能,如果整个系统都hung住了,必然是遇到了大量进程进入D状态,导致多个模块无法正常工作,对于手机平台来说,比如屏幕不亮,按键无响应等等都可能发生。
如何进行debug
内核是可以通过打印hung task信息来进行问题的定位,打开如下的内核特性,使能HUNG TASK调试功能:
CONFIG_DETECT_HUNG_TASK=y
CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y
CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=1
如果内核条件不允许我们重新编译运行,那么可以在故障现场手动触发一个dump,收集ramdump信息,然后利用crash工具进行分析:
crash> ps -u | grep UN
一般这种可以过滤掉内核线程进行查看,因为一般系统hung住都是和应用层的服务相关,然后针对性的选择主要的服务进程进行查看。特别提到的是watchdog线程,如果存在该进程,也是重点查看对象。
用户进程处于D状态时,肯定是陷入了内核态,我们进一步通过查看对应进程的内核调用堆栈来分析问题,找到最终持锁的线程:
crash> bt <pid>
参考文章:
https://www.cnblogs.com/embedded-linux/p/7043569.html
https://blog.csdn.net/juS3Ve/article/details/79428049