machine_check_poll() 函数在kernel-3.18前,这个函数基本只是起一个记录的作用(调用mce_log()),在kernel-3.18后,加入的patch,可以使得该函数处理UCNA类型的错误。其他部差异不大,仅仅是扫描记录而已。而且在mce-severity.c中特定写入了UCNA类型的错误表。这个错误正是Intel manual中所规定的。
enum severity_level { MCE_NO_SEVERITY, MCE_DEFERRED_SEVERITY, MCE_UCNA_SEVERITY = MCE_DEFERRED_SEVERITY, MCE_KEEP_SEVERITY, MCE_SOME_SEVERITY, MCE_AO_SEVERITY, MCE_UC_SEVERITY, MCE_AR_SEVERITY, MCE_PANIC_SEVERITY, };
这里为了兼容之前的MCE_KEEP_SEVERITY,加入了MCE_DEFERRED_SEVERITY 和 MCE_UCNA_SEVERITY 两个标志,并在machine_check_poll()中使用。
这里我们要注意的一点是:machine_check_poll工作在中断上下文,在调用mce_schedule_work()后,实际是通过调用工作队列中的mce_process_work() ,而这个函数会读取ring buffer中的错误数据。
@@ -630,6 +662,20 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b) if (!(flags & MCP_TIMESTAMP)) m.tsc = 0; + + severity = mce_severity(&m, mca_cfg.tolerant, NULL, false); + + /* + * In the cases where we don't have a valid address after all, + * do not add it into the ring buffer. + */ + if (severity == MCE_DEFERRED_SEVERITY && memory_error(&m)) { + if (m.status & MCI_STATUS_ADDRV) { + mce_ring_add(m.addr >> PAGE_SHIFT); + mce_schedule_work(); + } + } +
这个时候我们看到memory_failure()已经工作在进程上下文,如果我们要对错误进行过滤的话,可以考虑在memory_failure()函数开头设置hook函数。
static void mce_process_work(struct work_struct *dummy) { unsigned long pfn; while (mce_ring_get(&pfn)) memory_failure(pfn , MCE_VECTOR , 0); }
参考:
[1] Intel Manual