nmi_watchdog原理(用于检测关中断死锁)
nmi_watchdog用于检测内核中关中断死锁(也称硬死锁)的情况,是调测内核死机或死锁问题的一大利器。内核中,如果代码编写不好可能会出现关中断死锁的情况,即进入内核态后,关中断,然后在内核态中死锁,或长时间运行,导致该CPU无法响应中断(因为中断已关),也无法得到调度(对于没有启用内核抢占的内核来说),外在表现可能为系统挂死、无法ping通、没有响应。而nmi_watchdog正是针对这种情况而设计的。
其基本原理为:注册nmi中断(3号中断),为不可屏蔽中断,由硬件定期触发(通过性能计数器)。在时钟中断中更新相关计数器,在nmi中断处理中,判断相关计数器是否更新,如果超过5s(默认情况下)没有更新,则触发nmi_watchdog,默认情况下,最终会进入panic流程。
2.6.11代码流程如下:
本地时钟中断处理函数:
-
fastcall void smp_apic_timer_interrupt(struct pt_regs *regs)
-
{
-
/**
-
* 获得CPU逻辑号
-
*/
-
int cpu = smp_processor_id();
-
-
/*
-
* the NMI deadlock-detector uses this.
-
*/
-
/*增加apic_timer_irqs计数,此计数用于nmi_watchdog,其会在do_nmi中检测这个值的更新状态 */
-
irq_stat[cpu].apic_timer_irqs++;
-
...
-
}
nmi中断的处理函数:do_nmi->default_do_nmi()
-
static void default_do_nmi(struct pt_regs * regs)
-
{
-
...
-
if (nmi_watchdog) {
-
nmi_watchdog_tick(regs);
-
return;
-
...
-
}
nmi_watchdog检测函数:nmi_watchdog_tick()
-
void nmi_watchdog_tick (struct pt_regs * regs)
-
{
-
int sum, cpu = smp_processor_id();
-
-
sum = irq_stat[cpu].apic_timer_irqs;
-
//检测irq计数是否更新,如果没更新,则表示可能发生关中断死锁了。
-
if (last_irq_sums[cpu] == sum) {
-
/*
-
* Ayiee, looks like this CPU is stuck ...
-
* wait a few IRQs (5 seconds) before doing the oops ...
-
*/
-
alert_counter[cpu]++;
-
//如果5s内,计数都没有更新,那就触发die_nmi(),最终会走panic流程。
-
if (alert_counter[cpu] == 5*nmi_hz)
-
die_nmi(regs, "NMI Watchdog detected LOCKUP");
-
} else {
-
last_irq_sums[cpu] = sum;
-
alert_counter[cpu] = 0;
-
}
-
...
-
}
阅读(10741) | 评论(0) | 转发(0) |