内核常见异常信息说明

本文主要介绍内核常见异常以及定位方法。

内核死循环监控

示例:

1
BUG: soft lockup - CPU#0 stuck for 9s![stpd:233]

解释:
soft lockup: 关键词,表明监测到死循环
CPU#0: this cpu,监测到死循环所在的cpu核
9s:监测到死循环的时长,一般比设置的死循环监控门限大1
[stpd:233]:监测到死循环发生时的任务名和任务id

注意:任务名和任务id说明的只是在该任务的上下文,不一定是当前任务发生了死循环,中断或者软中断过多,处理时间过长也会导致

定位思路:
1、死循环:进程或线程可能陷入了一个无限的循环中,导致无法退出。
2、资源竞争:可能存在资源竞争的情况,导致CPU#0 无法顺利释放并处理其他任务。
3、锁问题:可能存在锁的问题,如死锁或无法正确释放锁。
4、大量的中断:导致CPU#0 被卡住并无法处理其他任务
通过dmesg信息查看调用栈信息分析当前流程是否可能发生死循环。或者当前环境是否会导致大量的中断和软中断处理。

核间监测

每隔1s,core(n)会对core(n+1)的软中断处理个数和中断处理个数与上一秒进行比较,若中断(软中断)个数不发生变化的时间超过门限值,会触发狗叫。

注:核间检测是否配置,通过查看/porc/cmdline中是否有ccd_threshold=28参数。28表示的是门限值,单位为s,可修改

示例:

1
2
3
4
cpu 0 [hard cpu 0] disable softirq long times.
0:NMI[#1]:
...
Call Trace:

解释:
cpu 0:0核上被检测到,关中断/软中断时间过长
softirq:表示关软中断时间过长,若为irq,则关中断时间过长
0:NMI[#1]:0核上触发的狗叫异常
Call Trace:处理狗叫异常时会打印调用栈
CPU 0被禁用了软件中断(softirq)较长的一段时间。硬件中断(hardirq)通常优先于软件中断进行处理,但如果软件中断需要处理的任务太耗时,就会导致CPU 0无法及时进行硬件中断的处理。

定位思路:
1、通过查看Call Trace中的函数调用栈,找到导致CPU 0长时间禁用软件中断的函数。
2、通过/proc/softirqs和/proc/interrupts两个文件,查看软中断和硬中断的统计数据。可以提供有关中断处理程序正在处理以及哪些软件中断正在被禁用。
3、借助中断检测工具来查看谁最后关闭了中断或软中断。

死锁

内核中的某个线程或进程持有一个锁并等待该锁被释放,而其他进程或线程无法获取该锁而无法继续执行。这种情况下,所有进程或线程都会停止响应,系统会陷入死循环或死锁状态。
示例:

1
2
3
4
5
6
BUG: spinlock lockup on CPU#1, swapper/0, 83bb3fc0
lock:83bb3fc, lock owner: swapper/0, lock owner_cpu: CPU#3
Call Trace:
...
owner's Stack:
Call Trace:

解释:
swapper/0:获取锁的任务名和pid
83bb3fc0:锁所在的地址,标识了一个锁
lock owner:当前锁的持有者
lock owner_cpu:当前持有者所在的cpu
Call Trace:尝试获取锁的任务的调用栈
owner’s Stack:持有锁的任务栈
Call Trace:锁持有者的调用栈

定位思路:
1、分析Call Trace和owner’s Stack调用栈
2、在CPU3上,通过bta打印出的获取者、持有者的信息以及调用栈信息,分析相应流程是否存在死锁的情况。
3、锁所在的内存被踩或访问野指针也可能会导致死锁。

原子上下文调用可能睡眠的函数

示例:

1
2
3
4
5
6
7
8
9
10
11
BUG: sleeping function called from invalid context at down_read:21
in atomic():0,irqs_disabled():1
INFO:lockdep is truned off.
irq event stamp: 0
hardirqs last enabled at (0): [<0000000000000000>] 0x0
hardirqs last disabled at (0): [<ffffffff80245404>] copy_process+0x2d4/0x12e0
softirqs last enabled at (0): [<ffffffff80245404>] copy_process+0x2d4/0x12e0
softirqs last disabled at (0): [<0000000000000000>] 0x0
Call Trace:
.....
might_sleep: 内核中有的会睡眠的函数会在入口处用might_sleep检测当前上下文是否位于原子上下文

解释:
down_read:21:调用might_sleep所在的文件及行号
in_atomic():1表示在原子上下文
irqs_disabled():1表示在中断上下文
hardirqs last enabled at (0):最后一次开中断的位置
hardirqs last disabled at (0):最后一次关中断的位置
softirqs last enabled at (0):最后一次开软中断的位置
softirqs last disabled at (0):最后一次关软中断的位置

定位思路:
1、中断上下文:排查中断处理流程中调用可能睡眠函数
2、原子上下文:排查流程中是否在获取锁后调用可能睡眠函数

注意:当前linux中允许睡眠的锁是信号量(semaphore)、互斥锁(mutex)、条件变量(condition variable)

原子上下文进行任务切换

在锁住某个内核资源时,尝试调用会导致进程睡眠的操作,从而违反了内核的同步约束(如不允许睡眠锁等)引起的。
示例:

1
2
BUG: scheduling while atomic: swapper/0/0x00000100
Call Trace:

定位思路: 根据调用栈排查代码;尝试开启内核debugging级别的错误信息,例如Enable CONFIG_DEBUG_ATOMIC_SLEEP 打印信息,帮忙检查问题。

内存耗尽

示例:

1
2
3
4
5
lldpd invoked oom-killer: gfp_mask=0xd0, order=0, oomkilladj=0
Call Trace:
[<80123a28>]dump_stack+0x8/0x40
[<801a2564>]oom_kill_process+0xd4/0x280
[<801a2bc4>]out_of_memory+0xf4/0x180

解释:
oom-killer:内存耗尽杀手(Out Of-Memory Killer)
gfp_mask=0xd0:表示该进程申请内存时,使用了GFP_COMP和GFP_ZERO标志
order=0:表示该进程申请的是一块大小为4KB的物理内存页
dump_stack:记录内核堆栈跟踪信息
oom_kill_process:系统通过调用oom_kill_process函数杀死进程lldpd,以释放内存资源
out_of_memory:表示系统因为内存不足,而调用了out_of_memory函数来释放被占用的内存。

定位思路:
1、在进入OOM异常前肯定打印了内存告警信息,分析内存告警中用户态内存使用和内核态各内存池分配情况,找出异常情况。
2、内存门限告警信息若没有打印出,去flash或cf卡上找diag日志。

-------------本文结束感谢您的阅读-------------

本文标题:内核常见异常信息说明

文章作者:

发布时间:2025年02月20日 - 02:02

最后更新:2023年07月23日 - 18:07

原始链接:http://wangzaifa.com/2025/02/20/%E5%86%85%E6%A0%B8%E5%B8%B8%E8%A7%81%E5%BC%82%E5%B8%B8%E4%BF%A1%E6%81%AF%E8%AF%B4%E6%98%8E/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

坚持原创技术分享,您的支持将鼓励我继续创作!
0%