machine_check_poll() 函数分析
machine_check_poll() 函数分析
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