首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

高级平台错误接口在 Linux 平台上的应用(6)

高级平台错误接口在 Linux 平台上的应用(6)

清单 13. NMI 类型错误的处理过程:第三部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
       list_for_each_entry_rcu(ghes, &ghes_nmi, list) {
#ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
               u32 len, node_len;
               struct ghes_estatus_node *estatus_node;
               struct acpi_hest_generic_status *estatus;
#endif
               if (!(ghes->flags & GHES_TO_CLEAR))
                       continue;
#ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
               if (ghes_estatus_cached(ghes->estatus))
                       goto next;
               /* Save estatus for further processing in IRQ context */
               len = apei_estatus_len(ghes->estatus);
               node_len = GHES_ESTATUS_NODE_LEN(len);
               estatus_node = (void *)gen_pool_alloc(ghes_estatus_pool,
                                                     node_len);
               if (estatus_node) {
                       estatus_node->generic = ghes->generic;
                       estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
                       memcpy(estatus, ghes->estatus, len);
                       llist_add(&estatus_node->llnode, &ghes_estatus_llist);
               }
next:
#endif
               ghes_clear_estatus(ghes);
       }
#ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
       irq_work_queue(&ghes_proc_irq_work);
#endif

out:
       raw_spin_unlock(&ghes_nmi_lock);
       return ret;
}




这是最后一部分代码。如果这个错误还不足以引起系统重启,那么可以尝试进行错误恢复。正如上文提到的,NMI context 是一个非常受限制的环境,因此所有的处理应该尽可能的简单快速。这里的核心思想就是采用推迟处理。首先将 GHES 错误源中获取的信息复制到安全地方,然后将其依次挂载到特定的链表上,最后将整个处理推迟到 IRQ context 中进行处理。CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG 宏的作用用来判断当前体系结构能否支持可靠的无锁处理(具体可参见 )。而 irq_work_queue 的作用则是唤醒放在 IRQ_WORK 上的与 GHES 有关的工作队列(这里就是 ghes_proc_irq_work,对应的处理函数为 ghes_proc_in_irq),以便在 NMI 结束并返回到 IRQ context 时继续完成未决的处理工作。
什么是 IRQ_WORKIRQ_WORK 在“硬”中断上下文中执行。它向 NMI handler 提供了一种可以推后执行的机制,以便于完成某些不能在 NMI context 中执行的代码。相关代码请参考 kernel/irq_work.c 以及 commit e360adbe2

由于在 ghes_proc_in_irq 函数执行时,系统已经从 NMI context 退出进入 IRQ context,因此相应的限制也少了很多,譬如调用 printk 进行打印就是安全的。ghes_proc_in_irq 的作用就是遍历之前保存但尚未处理的所有 GHES 错误项,调用 ghes_do_proc 进行最终的处理。
清单 14. NMI 类型错误的细化处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
在 drivers/acpi/apei/ghes.c 中
static void ghes_do_proc(const struct acpi_hest_generic_status *estatus)
{
        int sev, sec_sev;
        struct acpi_hest_generic_data *gdata;

        sev = ghes_severity(estatus->error_severity);
        apei_estatus_for_each_section(estatus, gdata) {
                sec_sev = ghes_severity(gdata->error_severity);
                if (!uuid_le_cmp(*(uuid_le *)gdata->section_type,
                                 CPER_SEC_PLATFORM_MEM)) {
                        struct cper_sec_mem_err *mem_err;
                        mem_err = (struct cper_sec_mem_err *)(gdata+1);
#ifdef CONFIG_X86_MCE
                        apei_mce_report_mem_error(sev == GHES_SEV_CORRECTED,
                                                  mem_err);
#endif
#ifdef CONFIG_ACPI_APEI_MEMORY_FAILURE
                        if (sev == GHES_SEV_RECOVERABLE &&
                            sec_sev == GHES_SEV_RECOVERABLE &&
                            mem_err->validation_bits &
                                     CPER_MEM_VALID_PHYSICAL_ADDRESS) {
                                unsigned long pfn;
                                pfn = mem_err->physical_addr >> PAGE_SHIFT;
                                memory_failure_queue(pfn, 0, 0);
                        }
#endif
                }
        }
}




在 ghes_do_proc 函数中,需要根据错误的不同进行分类处理。首先需要判断错误类型,是内存错误(错误类型为 CPER_SEC_PLATFORM_MEM),还是 PCI-E 错误(错误类型为 CPER_SEC_PCIE)。如果是内存错误,还需要根据错误的严重程度进行分别处理。如果是 CE 类型的错误,需要通过 APEI 和 MCE 之间的接口将错误信息转储到内核的 MCE 日志缓冲区中,供之后用户层的 daemon,如 mcelog 读取用;如果是 UC 类型的错误,则需要交给 HWPOISON(参见参考资料中 一文)进行后继处理。由于 HWPOISON 需要工作在 process context,因此不能直接在 IRQ context 调用 HWPOISON 相关的函数,而是和之前 IRQ WORK 的执行类似,不过这里唤醒的是普通的工作队列罢了。
结论APEI 作为一个非常新的接口规范,在很多平台中尚未实现,只有少部分最新的 XEON 服务器中提供了部分支持,随着新的 XEON 服务器平台的发布,APEI 的支持也会逐渐完善起来。除了 APEI,底层原生的 UEFI BIOS 也在尝试着在硬件错误处理,错误报告方面做更多的工作;在硬件平台这个层面上,随着 CPU 集成了越来越多的外设和控制器,作为整个平台核心的 CPU,也在不断加强这方面的功能,APEI 将以怎样一种方式将自身整合到更高一级的架构组成中,我们拭目以待。
返回列表