更多内核安全、eBPF分析和实践文章,请关注博客和公众号:
CSDN博客:内核功守道
公众号: 内核功守道
背景
接上篇文章:请记住内核中这个勤劳的监测卫士—Watchdog(Soft lockup篇),本篇详细分析Hard lockup流程和原理,并给出此类问题分析经验,供大家参考。
我们知道,hardware watchdog是Soc内的一个内部外设,是一个硬件模块,常说的watchdog driver指的就是该硬件。Hard lockup比soft lockup更加严重,CPU不仅无法调度其它进程,而且不能响应中断。在开启soft lockup时,已经给每个CPU启动了一个hrtimer定时器,在定时器中断处理函数watchdog_timer_fn中更新hrtimer_interrupts变量。
检测hard lockup的原理是:
- 在CPU0的watchdog_timer_fn函数中检测CPU1的hrtimer_interrupts变量是否更新过;
- 若没更新,意味着CPU1不能响应中断,出现了hard lockup(CPU1检测CPU2、CPU2检测CPU3、CPU3检测CPU0);
- 在驱动中加入以下代码可触发hard lockup
static spinlock_t spinlock;
unsigned long flags;
spin_lock_init(&spinlock);
spin_lock_irqsave(&spinlock, flags);
while (1);
- 在上述代码中,本地抢占和本地中断被关闭,该CPU的普通中断无法被响应(包括hrtimer定时器中断),线程也无法调度。在这种情况下,[watchdog/x]线程无法工作,hrtimer中断也无法被响应,就会出现hard lockup。
Hard lockup源码分析
1、hrtimer中断处理函数
watchdog_timer_fn()
{
/* hrtimer_interrupts++ */
watchdog_interrupt_count();
/* test for hardlockups on the next cpu */
watchdog_check_hardlockup_other_cpu();
}
2、Hard lockup检测函数
void watchdog_check_hardlockup_other_cpu(void)
{
unsigned int next_cpu;
/* hrtimer的中断4s触发一次,“%3”表示经过3个周期*,即每隔12s检测一下是否 */
/* hard lockup*/
if (__this_cpu_read(hrtimer_interrupts) % 3 != 0)
return;
/* 得到下一颗CPU */
next_cpu = watchdog_next_cpu(smp_processor_id());
if (is_hardlockup_other_cpu(next_cpu)) {
if (hardlockup_panic)//是否panic
panic("Watchdog detected hard LOCKUP on cpu %u", next_cpu);
else
WARN(1, "Watchdog detected hard LOCKUP on cpu %u", next_cpu);
per_cpu(hard_watchdog_warn, next_cpu) = true;
} else {
per_cpu(hard_watchdog_warn, next_cpu) = false;
}
}
3、Hard lockup判断函数
static int is_hardlockup_other_cpu(unsigned int cpu)
{
unsigned long hrint = per_cpu(hrtimer_interrupts, cpu);
/* 如果相等,说明hrtimer中断函数没有执行,出现hard lockup */
if (per_cpu(hrtimer_interrupts_saved, cpu) == hrint)
return 1;
/* 保存最新的hrtimer_interrupts变量值 */
per_cpu(hrtimer_interrupts_saved, cpu) = hrint;
return 0;
}
内核配置
- 开启hard lockup(默认为y)
HARDLOCKUP_DETECTOR_OTHER_CPU
- 是否需要panic(默认为n)
CONFIG_BOOTPARAM_HARDLOCKUP_PANIC
- 在应用层做以下设置也可以触发:
echo 1 > /proc/sys/kernel/hardlockup_panic
问题分析思路
Soft lockup用于检测CPU调度是否正常,而Hard lockup主要用于检测CPU中断响应是否正常。内核调度以及中断响应的正常与否,和死锁有很深入的关系,也可以是说是检测系统死锁的一种机制。
- 某个中断服务函数长时间运行;
- 关中断时间过长,譬如使用spin_lock_irqsave()函数关闭中断之后,太久没释放;
遇到此类问题,最有效的方法就是使用Trace32或者ARM DS5这类的在线调试器,查看出现异常卡死的位置或者哪个模块最近一次关了中断没有释放,进一步分析可疑点。
总结
以上两篇详细分析了Soft lockup和Hard lockup流程,并介绍了问题解决思路。可以看到不管是Soft lockup还是Hard lockup,都是从内核态的角度来分析死锁的情况,这也是很多内核工程师经常会遇到的问题。
尽管内核watchdog能检测softlockup 和 hardlockup 并采取相应的措施,但并非所有的系统宕机都是因为内核线程lockup引起的。用户线程/进程一样有可能引发系统宕机的情况。比如,用户程序有可能占着临界资源无法释放或系统太忙(疲于响应各种中断),导致无法调度其他用户进程(此时watchdog内核线程不受影响),这也可能导致系统无法正常使用。
后续会详细分析Android场景下的用户态Watchdog以及具体案例,敬请期待。