疑难问题定位案例复盘(四)

        最近碰到多起内核soft lockup问题,通过分析、解决该问题学习了解内核soft lockup问题的常规定位思路。

问题现象

  1. 更换设备硬件或升级版本后串口打印出内核soft lockup相关栈回溯信息,然后进入kdb。
  2. 出现的多起问题现象打印的内核栈回溯都不一致。
  3. 同一台设备出现soft lockup一段时间后,看门狗超时重启。重启后仍然出现内核soft lockup问题,而且每次出现soft lockup时打印的栈回溯也都不一致,出现超时的进程也不一致。具体超时的进程有各种各样的,包括用户态进程、内核线程,甚至ps等命令进程。
  4. 对设备进行下电处理后再上电,问题依然存在,持续打印内核soft lockup问题。

问题分析

        由于是第一次碰到内核soft lockup问题,所以得先了解一下内核soft lockup机制。内核soft lockup是为了解决内核中某些线程长期霸占CPU的问题,特别是关闭抢占时间过长。其实还有另一外一个叫hard lockup的机制,它是为了解决内核中长时间关闭中断的问题。soft lockup和hard lockup机制放在了一起实现,其中涉及3个模块:内核看门狗线程watchdog、高精度时钟定时器、基于PMU硬件的perf event的NMI中断。

  • 内核看门狗线程watchdog

        内核针对每个CPU创建了一个看门狗线程[watchdog/x],该线程是一个优先级最高的实时线程,采取的调度策略是SCHED_FIFO,它的主要作用就是定时被时钟中断唤醒,对CPU进行喂狗、更新时间戳。

  • 高精度时钟定时器

        为了完成内核监控任务(毕竟CPU被长时间霸占时普通线程都无法得到调度),内核使用了一个高精度的定时器hrtimer。该定时器定时产生中断(默认4s),产生中断后调用中断处理函数watchdog_timer_fn。在中断处理函数watchdog_timer_fn中主要做以下3件事:

  1. 更新hard lockup的计数变量hrtimer_interrupts。
  2. 唤醒内核看门狗线程[watchdog/x],使其更新时间戳。
  3. 调用is_softlockup判断是否出现了soft lockup问题(默认20s超时)。
  • 基于PMU硬件的perf event的NMI中断

        根据上面的介绍,hard lockup是为了定位解决长时间关闭中断的问题。如果中断长时间被关闭,进程和普通的中断都无法执行了,此时只有NMI(不可屏蔽中断)能得到执行。因此为了完成内核监控长时间关闭中断问题,内核引入了NMI中断进行检测。具体操作如下:

  1. 基于PMU硬件的perf event,每隔一定时间(默认20s)触发一次NMI中断。
  2. 在NMI中断中会比较当前的高精度定时器中断数hrtimer_interrupts和上次的高精度定时器中断数hrtimer_interrupts_saved是否相等。若相等,则说明两次NMI中断间未触发高精度时钟中断,即中断被长时间关闭,则触发hard lockup问题;否则说明高精度时钟中断正常触发,中断正常,则更新hrtimer_interrupts_saved值为hrtimer_interrupts。

通过上面的介绍,我们已经了解了内核soft lockup的原理,即某个线程长时间霸占CPU,导致进程无法得到有效调度,出现看门狗超时的现象。而什么情况下会出现某个线程长时间霸占CPU的情况呢?针对常见的可能情形一一分析验证。

内核代码死循环

        当我们在内核中实现了一个死循环代码时,若刚好内核又关闭了内核抢占功能,就有可能导致该内核线程持续执行,无法调度其他进程。注意,若我们开启了内核抢占功能,即使执行了上述的死循环代码,由于时间片中断进行抢占式调度,这样也能调度其他的线程,不会出现内核soft lockup问题。

        可以想象,如果是由于内核死循环导致的soft lockup问题,则串口下打印的栈回溯肯定相同,每次都指向同一个位置。而我们每次复现soft lockup时打印的栈回溯都不相同,而且进程也不相同,因此排除了这种可能。

内核自旋锁死锁

        如果我们在某个CPU上使用了自旋锁,并且出现了死锁,则这也会导致该内核线程一直执行,其他线程无法得到调度,从而出现内核超时的soft lockup问题。

        如果是由于自旋锁导致的soft lockup,则每次打印的栈回溯会相同,始终都指向对该自旋锁的获取。而我们每次出现soft lockup时打印的栈回溯都不相同,因此排除了这种可能。

中断数过多

        当我们在短时间内产生大量的中断,内核将持续忙于处理中断处理流程,导致其他线程得不到调度,从而出现内核超时的soft lockup问题。

        为了验证这种可能,我们在系统启动的早期拉起一个脚本,在脚本中主要做两件事:

  1. 利用top -b -d 3每隔3s定时采样数据并输出到串口/dev/ttyS4,这样查看出现问题时系统的使用率情况,特别是哪些进程更多的使用了CPU。另外也查看io使用率是否正常,因为中断往往需要使用io访问外部硬件设备。
  2. 循环执行cat /proc/interrupts命令查看系统的中断情况。查看是否有中断产生过多。

更新上述临时版本进行复现。发现在产生soft lockup时,CPU的使用率持续为100%,而且io使用率高达几十,甚至接近一半。同时,打印的/proc/interrupts显示i2c bus 15在短时间内产生了高达几千次中断。因此,初步判断是由于i2c bus 15产生了大量的中断导致内核持续忙于处理中断流程,从而出现了内核soft lockup问题。

        当我们屏蔽了i2c bus 15的中断上报时,问题不复现,这进一步验证了i2c bus 15持续上报过多的中断导致了内核soft lockup问题。针对i2c bus 15上报过多中断问题,经和相关硬件开发责任人确认,其是由于i2c bus 15的SDA引脚被异常短接接地,导致SDA被持续拉低,从而上报大量的中断。至此,完成了问题根因的定位。

问题总结

        通过上述例子,我们了解了内核soft lockup的原理以及常规定位思路。当我们碰到了该问题时,可以尝试针对以下几种情形进行一一验证判断,从而定位根因。

  • 内核代码死循环
  • 内核自旋锁死锁
  • 短时间内中断数过多

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值