Linux 内核 RAS 框架深度解析:从 EDAC 子系统的错误处理原理到 sysfs 实战
【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux
Linux 内核文档 Documentation/admin-guide/RAS/main.rst 系统阐述了面向服务器的可靠性(Reliability)、可用性(Availability)与可服务性(Serviceability,合称 RAS)在内核中的实现:从硬件错误的分类与 ECC 纠错原理,到内核 EDAC(Error Detection And Correction)子系统如何采集内存 CE/UE 错误、通过 sysfs 上报给管理程序,再到 PCI 总线奇偶校验扫描与 Intel 新架构的错误注入接口。读完本篇,你将能够理解服务器硬件错误的完整检测链路,并掌握在/sys/devices/system/edac下查看计数器、配置模块参数、定位故障 DIMM(最小可更换单元)的全部实操方法。
RAS 概念与改进手段
RAS 是衡量服务器鲁棒性的三个维度:
- Reliability(可靠性):系统产生正确输出的概率,通常以平均故障间隔时间(MTBF)衡量,靠帮助避免、检测并修复硬件故障的特性来增强;
- Availability(可用性):系统在任意给定时刻处于运行状态的概率,通常以一段时间内的停机百分比衡量,常借助运行时检测并纠正硬件故障的机制;
- Serviceability(可服务性/可维护性):系统被修复或维护的简易程度与速度,通常以平均修复时间(MTBR)衡量。
为降低系统停机时间,一个具备良好 RAS 能力的系统应当能够检测硬件错误、尽可能在运行时纠正它们,同时提供硬件劣化侦测机制,在组件造成数据丢失或停机之前提醒管理员更换。文档列出的最常见监控手段包括:
- CPU——检测指令执行及 L1/L2/L3 缓存中的错误;
- 内存——增加 ECC 纠错逻辑以检测和纠正错误;
- I/O——为传输的数据增加 CRC 校验;
- 存储——RAID、日志文件系统、校验和、SMART(Self-Monitoring, Analysis and Reporting Technology)。
通过监控错误发生次数的趋势,可以判断硬件错误概率是否在上升;若如此,就应在这些错误仍属可纠正的阶段进行预防性维护,更换正在劣化的组件。
错误分类:CE、UE、Fatal 与 Non-fatal
现代系统大多采用汉明码(Hamming Code)一类的技术,当一组比特中的错误数低于阈值时可以纠错;超过阈值时则能高置信度地判定“出错了”却无法纠正。另外,错误也可能发生在未被使用的组件上(例如尚未分配的内存)。由此形成四类错误:
- Correctable Error(CE,可纠正错误):检测机制发现并纠正了错误,通常不致命,但某些内核机制允许管理员将其视为致命;
- Uncorrectable Error(UE,不可纠正错误):错误数超过纠错阈值,系统无法自动纠正;
- Fatal Error(致命错误):UE 发生在系统关键组件上(例如内核自身被 UE 破坏),此时唯一可靠的避免数据损坏的方式是挂起或重启机器;
- Non-fatal Error(非致命错误):UE 发生在未使用的组件上(如处于断电状态的 CPU、未使用的内存 bank),系统可能仍能运行,甚至可用热备件替换受影响硬件;若错误发生在用户态进程,也可以杀掉该进程让其重启。
非致命错误的处理机制通常较复杂,可能需要用户态应用配合,以执行管理员期望的策略。
定位故障硬件:指向最小可更换单元(MRU)
仅仅检测到硬件缺陷通常是不够的:系统需要定位到应当更换的最小可更换单元(Minimal Replaceable Unit, MRU),才能让硬件恢复可靠。这要求不仅有错误记录能力,还要能把错误消息翻译成主板丝印或组件标签。
以内存为例,由于现代 CPU 会将不同内存条的数据交叉(interlace)以提升性能,定位非常复杂。DMI BIOS 通常保存有内存模块标签列表,可用dmidecode工具查看。例如某台桌面机器的输出:
Memory Device Total Width: 64 bits Data Width: 64 bits Size: 16384 MB Form Factor: SODIMM Set: None Locator: ChannelA-DIMM0 Bank Locator: BANK 0 Type: DDR4 Type Detail: Synchronous Speed: 2133 MHz Rank: 2 Configured Clock Speed: 2133 MHz上例中这块 DDR4 SO-DIMM 位于bank locator字段标示的 "BANK 0"。注意其total width等于data width,意味着该内存模块没有纠错机制。
而在另一台较老的服务器上,dmidecode输出可能是:
Memory Device Array Handle: 0x1000 Error Information Handle: Not Provided Total Width: 72 bits Data Width: 64 bits Size: 8192 MB Form Factor: DIMM Set: 1 Locator: DIMM_A1 Bank Locator: Not Specified Type: DDR3 Type Detail: Synchronous Registered (Buffered) Speed: 1600 MHz Rank: 2 Configured Clock Speed: 1600 MHz此例中 DDR3 RDIMM 位于locator字段标示的 "DIMM_A1"。该模块data width为 64 位、total width为 72 位,多出的 8 位用于检错/纠错——这类内存即ECC 内存。更麻烦的是,不同丝印标签的主板可能使用完全相同的 BIOS,导致 BIOS 给出的标签与实物不符。
ECC 内存的工作原理
ECC 内存的额外位用于纠错。以上例 64 位数据 + 72 位总宽为例,多出的 8 位用于检错/纠错,称为syndrome(校验子)。
写路径:当 CPU 请求内存控制器写入一个data width宽度的字时,内存控制器实时用汉明码或其他纠错码(如 SECDED+)计算 syndrome,生成total width大小的码字写入内存模块。
读路径:读回total width比特后用相同 ECC 码还原,得到一个data width宽度的字和 syndrome;即使发生错误,数据字也会被送往 CPU。内存控制器同时检查 syndrome 判断是否发生错误、以及 ECC 是否成功纠正:纠正成功即 CE,纠正失败即 UE。
CE/UE 信息保存在内存控制器的特殊寄存器中,可经 BIOS、特定 CPU 或 Linux EDAC 驱动读取;在 x86 64 位 CPU 上,这些错误还能通过 Machine Check Architecture(MCA)获取,详见内核文档 arch/x86/x86_64/machinecheck.rst。
两种值得注意的特殊内存模式(原文脚注):
- Lock-Step(锁步)模式:部分内存控制器可将两个内存模块编组、以 128 位读/写工作,从而提供 16 位纠错能力,显著提升纠错效果;代价是一旦出错无法确定是哪块模块的错,只能同时归咎两块模块;
- Mirror(镜像)模式:同一数据写入两块模块,读时比对一致性。出错时同样无法定位单块模块,只能归咎两块(若同时处于 Lock-step 模式则归咎四块)。
EDAC 子系统:目标与组成
历史背景:该驱动子系统在树外维护时期名为 "bluesmoke"(原网站现已陈旧,仅供历史参考);当它在 2.6.16 内核首次推送上游时,被改名为EDAC。
EDAC 在当前内核源码中位于 drivers/edac 目录,核心由edac_mc内存控制器模块与众多具体的 Memory Controller(MC)驱动组成,例如 amd76x_edac.c、amd64_edac.c、i7core_edac.c、sb_edac.c 等。
内存错误采集(edac_mc)
内存的 CE/UE 是 EDAC 采集的首要错误类型,由edac_mc设备负责。需要强调文档中的重要告诫:CE 事件的采集与上报“可以”但并非必然地预示未来 UE 事件——仅有 CE 时系统可以且会继续正常运行,因为数据尚未损坏。不过,对表现出 CE 的内存模块做预防性维护和主动更换,确实能降低出现 UE 和系统宕机的概率。
其他硬件元素(edac_device)
2.6.23 版本内核引入了新的edac_device设备类(实现见 drivers/edac/edac_device.c)。它让非内存类的 ECC 硬件检测器——如 L1/L2/L3 缓存 ECC 检测器、DMA 引擎、fabric 交换、主数据通路交换、互连等——也能把状态经 sysfs 呈现给用户态。只要硬件有上报,通常就可以构造一个 edac_device 来采集并呈现。
PCI 总线扫描
EDAC 还会扫描 PCI 设备的 Bus Parity 与 SERR 错误,判断数据传输期间是否发生错误。PCI Parity 错误须谨慎看待:PCI 规范要求厂商若不打算产生奇偶校验,应把奇偶状态位系到 0;但有些厂商不这样做,导致奇偶位“浮空”产生假阳性。EDAC 的 PCI 扫描代码会检查 sysfs 中的 PCI 设备属性:
broken_parity_status它位于/sys/devices/pci<XXX>/0000:XX:YY.Z目录下,该属性置位后,对应设备将跳过 PCI 奇偶/错误扫描。当前源码中,奇偶校验检查入口与pci_parity_count计数器的维护逻辑分别位于 drivers/edac/edac_pci.c 与 drivers/edac/edac_pci_sysfs.c。
版本号与模块加载
EDAC 由一个"核心"模块(原文称edac_core.ko,从当前源码树结构看,核心模块由 drivers/edac/edac_mc.c 构建)和若干 MC 驱动模块组成。在给定系统上,核心被加载后只加载一个 MC 驱动;核心与 MC 驱动(或 edac_device 驱动)各有独立版本号,因此报告系统运行版本时须同时报告两者。
若edac静态链接进内核则无需加载;若构建成模块,直接 modprobe 所需部件即可,加载硬件特定模块时依赖会自动带出核心模块。例如:
$ modprobe amd76x_edac该命令会同时加载amd76x_edac.ko内存控制器模块和edac_mc.ko核心模块。
sysfs 接口总览
EDAC 提供位于/sys/devices/system/edac的 sysfs 接口用于控制与上报。该目录下有两个主要组件:
| 组件 | 说明 |
|---|---|
mc | 内存控制器系统 |
pci | PCI 控制与状态系统 |
完整的 sysfs 属性语义(含各文件的用途说明)定义在 ABI 文档 Documentation/ABI/testing/sysfs-devices-edac 中,建议配合阅读。
Memory Controller(mc)模型
每个mc设备控制一组内存模块。模块按Chip-Select Row(csrowX)与Channel 表(chX)布局,可以有多个 csrow 和多个通道。典型系统有 8 个 csrow,但实际数量取决于主板布局、内存控制器与内存模块特性。
双通道允许双数据宽度(如 64 位系统上的 128 位)对 CPU 读写内存;部分新芯片组(如 FB-DIMM 内存控制器)支持更多通道。以 2 通道为例,模块布局如下:
+------------+-----------------------+ | CS Rows | Channels | +------------+-----------+-----------+ | | ch0 | ch1 | +============+===========+===========+ | |**DIMM_A0**|**DIMM_B0**| +------------+-----------+-----------+ | csrow0 | rank0 | rank0 | +------------+-----------+-----------+ | csrow1 | rank1 | rank1 | +------------+-----------+-----------+ | |**DIMM_A1**|**DIMM_B1**| +------------+-----------+-----------+ | csrow2 | rank0 | rank0 | +------------+-----------+-----------+ | csrow3 | rank1 | rank1 | +------------+-----------+-----------+对应主板上 4 个物理 DIMM 槽位:
+---------+---------+ | DIMM_A0 | DIMM_B0 | +---------+---------+ | DIMM_A1 | DIMM_B1 | +---------+---------+槽位标签通常丝印在主板上:A槽是通道 0,B槽是通道 1。注意一个物理 DIMM 可能对应两个 csrow——csrow 的分配基于 DIMM 所插入的槽位,因此每个通道各插 1 条 DIMM 时,csrow 会横跨两条 DIMM。
内存 DIMM 分单 rank 和双 rank,一个 rank 即一个被占用的 csrow。例如两条双 rank DIMM 分别插到 DIMM_A0/DIMM_B0 与 DIMM_A1/DIMM_B1 时,csrow0、csrow1 均被占用;若两条单 rank DIMM 只插在 DIMM_A0/DIMM_B0,则只有 csrow0 被占用,csrow1 为空。另外,有些内存控制器没有任何识别内存模块的逻辑,对应 sysfs 目录见下文rankX。
sysfs 目录树中,/sys/devices/system/edac/mc下每个内存控制器以mcX目录表示(X 为 MC 索引):
..../edac/mc/ | |->mc0 |->mc1 |->mc2 ....术语说明(原文脚注):如今 DIMM(Dual In-line Memory Module)被广泛用来指代内存模块,但还有 SO-DIMM、SIMM 等封装形式。UEFI 规范(2.7 版)在 CPER(Common Platform Error Record)一节将内存模块定义为 SMBIOS Memory Device(Type 17)。本文档与 EDAC 子系统内部统一用 "dimm" 指代所有内存模块,不论其封装形式。
推荐的查看方式:dimmX / rankX 目录
使用 EDAC 子系统的推荐方式是查看dimmX或rankX目录提供的信息。典型 EDAC 系统下/sys/devices/system/edac/的结构如下(其中power目录与subsystem符号链接由 sysfs 子系统自动创建,目前无实际用途):
/sys/devices/system/edac/ ├── mc │ ├── mc0 │ │ ├── ce_count │ │ ├── ce_noinfo_count │ │ ├── dimm0 │ │ │ ├── dimm_ce_count │ │ │ ├── dimm_dev_type │ │ │ ├── dimm_edac_mode │ │ │ ├── dimm_label │ │ │ ├── dimm_location │ │ │ ├── dimm_mem_type │ │ │ ├── dimm_ue_count │ │ │ ├── size │ │ │ └── uevent │ │ ├── max_location │ │ ├── mc_name │ │ ├── reset_counters │ │ ├── seconds_since_reset │ │ ├── size_mb │ │ ├── ue_count │ │ ├── ue_noinfo_count │ │ └── uevent │ ├── mc1 │ │ ├── ce_count │ │ ├── ce_noinfo_count │ │ ├── dimm0 │ │ │ ├── dimm_ce_count │ │ │ ├── dimm_dev_type │ │ │ ├── dimm_edac_mode │ │ │ ├── dimm_label │ │ │ ├── dimm_location │ │ │ ├── dimm_mem_type │ │ │ ├── dimm_ue_count │ │ │ ├── size │ │ │ └── uevent │ │ ├── max_location │ │ ├── mc_name │ │ ├── reset_counters │ │ ├── seconds_since_reset │ │ ├── size_mb │ │ ├── ue_count │ │ ├── ue_noinfo_count │ │ └── uevent │ └── uevent └── ueventdimmX目录包含该内存模块的控制与属性文件:
size——该 csrow 管理的内存总量,以 MB 为单位显示;dimm_ue_count——该 DIMM 上发生的不可纠正错误总计数。若panic_on_ue置位,此计数将没有机会增长,因为 EDAC 会让系统 panic;dimm_ce_count——该 DIMM 上发生的可纠正错误总计数。这是最值得重点关注的字段:CE 是 DIMM 开始失效的早期信号,应监控其非零值并把信息报告给系统管理员;dimm_dev_type——该 DIMM 上使用的 DRAM 器件类型,取值如x1、x2、x4、x8。从源码 drivers/edac/edac_mc_sysfs.c 可见,dev_types表实际覆盖x1至x64;dimm_edac_mode——正在使用的检错/纠错类型。源码 drivers/edac/edac_mc_sysfs.c 中的edac_caps表列出的可能取值包括:None、PARITY、EC、SECDED、S2ECD2ED、S4ECD4ED、S8ECD8ED、S16ECD16ED;dimm_label——内存模块标签控制文件(可写)。为该 DIMM 赋予标签后,错误发生时系统日志中可输出 DIMM 标签,这在 panic 事件中定位 UE 根因至关重要。注意标签须在启动后、用与主板丝印标签一致的信息在用户态分配,因为该信息目前非常依赖主板型号;dimm_location——内存模块位置,最多 3 级,描述内存控制器如何识别模块位置,依内存与控制器类型不同而不同:csrow+channel——内存控制器无法识别单条 DIMM 时使用,对应rankX目录;branch+channel+slot——FB-DIMM 内存控制器常见;channel+slot——Nehalem 及更新 Intel 驱动所用;
dimm_mem_type——该 csrow 上的内存类型,通常为 buffered 或 unbuffered,例如Registered-DDR、Unbuffered-DDR。
关于dimmX与rankX的区别(原文脚注):当内存控制器没有任何识别内存模块的逻辑时,目录名为rankX;在现代 Intel 内存控制器上,控制器能直接识别内存模块,目录名为dimmX。
系统日志消息格式
若启用了 UE/CE 日志,系统日志将包含错误检测信息,例如:
EDAC MC0: CE page 0x283, offset 0xce0, grain 8, syndrome 0x6ec3, row 0, channel 1 "DIMM_B1": amd76x_edac EDAC MC0: CE page 0x1e5, offset 0xfb0, grain 8, syndrome 0xb741, row 0, channel 1 "DIMM_B1": amd76x_edac消息结构如下:
| 内容 | 示例 |
|---|---|
| 内存控制器 | MC0 |
| 错误类型 | CE |
| 内存页 | 0x283 |
| 页内偏移 | 0xce0 |
| 错误的字节粒度/分辨率 | grain 8 |
| 错误 syndrome | 0xb741 |
| 内存行 | row 0 |
| 内存通道 | channel 1 |
| DIMM 标签(若事先设置) | DIMM B1 |
| 可选的驱动特定附加信息 | — |
所有信息缺失(no info)的 UE 与 CE,消息中只保留内存控制器、错误类型、"no info" 提示及可选的驱动特定错误消息。
PCI Bus Parity 检测
对 Header Type 00 的设备,无论奇偶校验是否启用,都会检查主状态寄存器(规范指明某些情况下会生成奇偶);对 Header Type 01 桥,还会检查次级状态寄存器,判断桥另一侧的总线上是否发生了奇偶错误。
在/sys/devices/system/edac/pci下有如下控制与属性文件:
check_pci_parity——启用/禁用 PCI Parity 扫描。写1启用,写0禁用:
# Enable echo "1" >/sys/devices/system/edac/pci/check_pci_parity # Disable echo "0" >/sys/devices/system/edac/pci/check_pci_paritypci_parity_count——显示已检测到的奇偶错误数。当前源码中该计数器在 drivers/edac/edac_pci_sysfs.c 中以原子变量维护,每次扫描发现奇偶错误时自增。
模块参数
EDAC 核心暴露以下模块参数(定义于 drivers/edac/edac_mc_sysfs.c,均可在加载时与运行时调整)。
edac_mc_panic_on_ue —— UE 时 panic
发生不可纠正错误时将引发机器 panic,这通常是期望的行为——UE 之后继续运行是坏主意:无法确定什么数据未被纠正,操作系统上下文可能已严重错乱,继续运行会导致进一步损坏。若内核配置了 MCE,则 EDAC 根本不会"注意到"该 UE(MCE 会先处理)。
- 加载时:
module/kernel parameter: edac_mc_panic_on_ue=[0|1] - 运行时:
echo "1" > /sys/module/edac_mc/parameters/edac_mc_panic_on_ue
edac_mc_log_ue —— UE 日志开关
生成描述不可纠正错误的内核消息(经系统消息日志上报)。即使禁用 UE 日志,UE 统计仍会累积。源码默认值为 1(开启日志)。
- 加载时:
edac_mc_log_ue=[0|1] - 运行时:
echo "1" > /sys/module/edac_mc/parameters/edac_mc_log_ue
edac_mc_log_ce —— CE 日志开关
生成描述可纠正错误的内核消息。同样,即使禁用 CE 日志,CE 统计仍会累积。默认值 1。
- 加载时:
edac_mc_log_ce=[0|1] - 运行时:
echo "1" > /sys/module/edac_mc/parameters/edac_mc_log_ce
edac_mc_poll_msec —— 轮询周期
轮询错误信息的周期,单位毫秒。值太小浪费资源,太大可能延迟必要的错误处理、丢失定位错误所需的信息。当前默认 1000 ms(每秒一次),对带宽要求极苛刻的系统可以适当调大。源码默认值即 1000(见 drivers/edac/edac_mc_sysfs.c),且设置函数edac_set_poll_msec会拒绝小于 1000 的值(drivers/edac/edac_mc_sysfs.c),即最小可配置周期为 1000 ms:
- 加载时:
edac_mc_poll_msec=<毫秒值> - 运行时:
echo "1000" > /sys/module/edac_mc/parameters/edac_mc_poll_msec
edac_panic_on_pci_pe —— PCI 奇偶错误时 panic
检测到奇偶错误时是否 panic:
# module/kernel parameter edac_panic_on_pci_pe=[0|1] # Enable echo "1" > /sys/module/edac_mc/parameters/edac_panic_on_pci_pe # Disable echo "0" > /sys/module/edac_mc/parameters/edac_panic_on_pci_pe说明:原文档将该参数列于
edac_core模块下;从当前源码树看,MC 相关参数集中声明于edac_mc模块中,而 PCI 奇偶相关的属性与计数逻辑位于edac_pci*源文件。实际使用时请以所在系统/sys/module/下真实存在的参数文件为准。
EDAC device 类型:三层树状 sysfs
drivers/edac/edac_pci.h(原文所述头文件)及 edac_device 相关头文件中有一系列edac_device结构与 API。用户态通过 sysfs 访问 edac_device:新设备会出现在/sys/devices/system/edac下,其下是一个三层目录树。
以测试驱动test_device_edac为例,它注册为:
/sys/devices/system/edac/test-instance该目录下有各种控制项、一个符号链接和一个或多个instance目录。标准默认控制项:
| 控制项 | 说明 |
|---|---|
log_ce | 是否记录 CE 事件(布尔) |
log_ue | 是否记录 UE 事件(布尔) |
panic_on_ue | 遇到 UE 时是否 panic(默认 off,可在启动脚本中置 true) |
poll_msec | 事件 POLL 周期 |
test_device_edac还会添加至少一个自定义控制:test_bits——在当前测试驱动中不产生任何实际作用,仅演示如何安装控制/属性;移植驱动可添加一个或多个这样的控制项(例如某些树外驱动在此暴露 ERROR INJECTION 控制,用于向硬件注入寄存器写入错误)。符号链接指向该 edac_device 注册的struct dev。
Instance 层
存在一个或多个 instance 目录,如test-instance0。其中有两个默认计数器属性,为更深层子目录计数之和:
| 属性 | 说明 |
|---|---|
ce_count | 子目录 CE 事件总数 |
ue_count | 子目录 UE 事件总数 |
Block 层
最底层目录是block,每个 instance 可包含 0、1 个或多个 block,如test-block0。默认属性:
| 属性 | 说明 |
|---|---|
ce_count | 该块被监控硬件的 CE 事件计数 |
ue_count | 该块被监控硬件的 UE 事件计数 |
test_device_edac另添加 4 个属性和 1 个控制:
test-block-bits-0——每个 POLL 周期递增一次;test-block-bits-1——每 10 个周期递增一次,同时将 bits-0 清零;test-block-bits-2——每 100 个周期递增一次,同时将 bits-1 清零;test-block-bits-3——每 1000 个周期递增一次,同时将 bits-2 清零;reset-counters——向该控制写任何内容都会重置上述全部计数器。
test_device_edac样例驱动的意义在于:让其他开发者可以仿照它为各自硬件编写独特的 edac_device 驱动。
Intel Nehalem 及更新架构上的 EDAC API 用法
在较老的 Intel 架构上,内存控制器属于 North Bridge 芯片组;从 Nehalem、Sandy Bridge、Ivy Bridge、Haswell、Sky Lake 到更新架构,增强版内存控制器(MC)被集成进 CPU 内部。本节(对应驱动如i7core_edac、sb_edac、sbx_edac,源码分别为 i7core_edac.c、sb_edac.c)描述这些增强 MC 的差异。
注意:Xeon E7 处理器家族使用独立的内存控制器芯片——Intel Scalable Memory Buffer,本节不适用于这些家族。
1) 通道与 DIMM 到 csrow 的映射
每个 Quick Path Interconnect(QPI)对应一个内存控制器;驱动中 "socket" 一词指一个 QPI,关联一个物理 CPU 插座。每个 MC 有 3 个物理读通道、3 个物理写通道和 3 个逻辑通道,驱动当前将其视作 3 个通道,每个通道最多可插 3 条 DIMM。
最小的已知单元是 DIMM,没有任何 csrow 信息;由于 EDAC API 把最小单元映射为 csrow,驱动按序把 channel/DIMM 映射到不同 csrow。例如以下布局:
Ch0 phy rd0, wr0 (0x063f4031): 2 ranks, UDIMMs dimm 0 1024 Mb offset: 0, bank: 8, rank: 1, row: 0x4000, col: 0x400 dimm 1 1024 Mb offset: 4, bank: 8, rank: 1, row: 0x4000, col: 0x400 Ch1 phy rd1, wr1 (0x063f4031): 2 ranks, UDIMMs dimm 0 1024 Mb offset: 0, bank: 8, rank: 1, row: 0x4000, col: 0x400 Ch2 phy rd3, wr3 (0x063f4031): 2 ranks, UDIMMs dimm 0 1024 Mb offset: 0, bank: 8, rank: 1, row: 0x4000, col: 0x400驱动将映射为:
csrow0: channel 0, dimm0 csrow1: channel 0, dimm1 csrow2: channel 1, dimm0 csrow3: channel 2, dimm0即每个 csrow 导出一条 DIMM,且每个 QPI 作为独立内存控制器导出。
2) 错误注入节点
新 MC 具备错误注入能力用于测试驱动。驱动通过/sys/devices/system/edac/mc/mc?/下的一组 sysfs 节点实现(如 i7core_edac.c、amd64_edac.c 中实现的inject_*属性,Kconfig 说明见 drivers/edac/Kconfig):
inject_addrmatch/*:控制错误注入的地址匹配掩码寄存器,可指定多个地址特征以匹配错误:dimm——受影响的 dimm(编号相对通道);rank——内存 rank;channel——将产生错误的通道;bank——受影响的 bank;page——页地址;column(或col)——地址列。
以上每个值均可设为
any以匹配任意合法值;驱动初始化时全部为 any。例如在 dimm 2 的 rank 1 上生成错误(任意通道、bank、页、列):echo 2 >/sys/devices/system/edac/mc/mc0/inject_addrmatch/dimm echo 1 >/sys/devices/system/edac/mc/mc0/inject_addrmatch/rank恢复默认"任意匹配"行为:
echo any >/sys/devices/system/edac/mc/mc0/inject_addrmatch/dimm echo any >/sys/devices/system/edac/mc/mc0/inject_addrmatch/rankinject_eccmask:指定哪些比特将出错;inject_section:指定哪个 ECC cache 段发生错误:3表示两段都、2表示最高段、1表示最低段;inject_type:指定错误类型,为以下位组合——bit 0: repeat、bit 1: ecc、bit 2: parity;inject_enable:写入非 0 值即启动错误生成。
所有 inject 变量均可读;写需要 root 权限。数据手册声明错误仅在向匹配inject_addrmatch的地址执行写操作后生成,但实际观察中读操作也会产生错误。
完整示例——在 socket 0、通道 2 上对任意 DIMM/地址的写访问生成错误:
echo 2 >/sys/devices/system/edac/mc/mc0/inject_addrmatch/channel echo 2 >/sys/devices/system/edac/mc/mc0/inject_type echo 64 >/sys/devices/system/edac/mc/mc0/inject_eccmask echo 3 >/sys/devices/system/edac/mc/mc0/inject_section echo 1 >/sys/devices/system/edac/mc/mc0/inject_enable dd if=/dev/mem of=/dev/null seek=16k bs=4k count=1 >& /dev/null对 socket 1,把上述命令中的mc0替换为mc1。生成的错误消息形如:
EDAC MC0: UE row 0, channel-a= 0 channel-b= 0 labels "-": NON_FATAL (addr = 0x0075b980, socket=0, Dimm=0, Channel=2, syndrome=0x00000040, count=1, Err=8c0000400001009f:4000080482 (read error: read ECC error))3) Corrected Error 内存寄存器计数器
新 MC 提供若干计数内存错误的寄存器,驱动使用它们为 Registered DIMM 上报 CE。但这些计数器对 Unregistered DIMM(UDIMM)无效;由于芯片组另有一些对 UDIMM 也有效(但粒度不如默认计数器精细)的计数器,驱动为 UDIMM 内存暴露了这些寄存器,通过all_channel_counts/读取:
$ for i in /sys/devices/system/edac/mc/mc0/all_channel_counts/*; do echo $i; cat $i; done /sys/devices/system/edac/mc/mc0/all_channel_counts/udimm0 0 /sys/devices/system/edac/mc/mc0/all_channel_counts/udimm1 0 /sys/devices/system/edac/mc/mc0/all_channel_counts/udimm2 0其工作方式是:不同 csrow 但相同 dimm 编号上的错误会递增同一个计数器。在上文的内存映射(csrow0: channel 0 dimm0;csrow1: channel 0 dimm1;csrow2: channel 1 dimm0;csrow3: channel 2 dimm0)下:csrow0/csrow2/csrow3 上第一条 dimm 的错误都会递增udimm0,第二条 dimm 递增udimm1,第三条递增udimm2。
4) 标准错误计数器
标准错误计数器在驱动收到 mcelog 错误时生成。由于 UDIMM 情形下这是由软件计数的,可能丢失部分错误;RDIMM 情形下则直接显示寄存器内容。
amd64_edac 的参考文档
amd64_edac模块(源码 drivers/edac/amd64_edac.c)基于 AMD 官方 BKDG(BIOS and Kernel Developer's Guide)文档,原文档列出的参考包括(可通过 AMD 技术支持站点检索,此处不附外部链接):
- BIOS and Kernel Developer's Guide for AMD Athlon 64 and AMD Opteron Processors(AMD 出版物 26094,Rev 3.26);
- BIOS and Kernel Developer's Guide for AMD NPT Family 0Fh Processors(出版物 32559,Rev 3.00,2006 年 5 月);
- BKDG For AMD Family 10h Processors(出版物 31116,Rev 3.00,2007 年 9 月 7 日);
- BKDG for AMD Family 15h Models 30h-3Fh Processors(出版物 49125,Rev 3.06,2015 年 2 月 12 日);
- BKDG for AMD Family 15h Models 60h-6Fh Processors(出版物 50742,Rev 3.01,2015 年 7 月 23 日);
- BKDG for AMD Family 16h Models 00h-0Fh Processors(出版物 48751,Rev 3.03,2015 年 2 月 23 日)。
实操速查与小结
| 场景 | 操作 |
|---|---|
| 查看某 DIMM 的 CE 计数(早期失效信号) | cat /sys/devices/system/edac/mc/mc0/dimm0/dimm_ce_count |
| 为 DIMM 写丝印标签以便 panic 定位 | 向dimm_label写入与主板丝印一致的标签 |
| 重置 mc 计数器 | 写reset_counters |
| 调整错误轮询周期(≥1000 ms) | echo 2000 > /sys/module/edac_mc/parameters/edac_mc_poll_msec |
| UE 时立即 panic | echo 1 > /sys/module/edac_mc/parameters/edac_mc_panic_on_ue |
| 开启/关闭 PCI 奇偶扫描 | 向/sys/devices/system/edac/pci/check_pci_parity写1/0 |
| 排除坏奇偶状态设备 | 确认该设备broken_parity_status属性 |
| Intel 新架构注入测试错误 | 配置mc?/inject_*节点后触发匹配地址访问 |
RAS 与 EDAC 的完整脉络可总结为:硬件(ECC/MCA/PCI 奇偶)产生错误信号 → 内核 EDAC 核心(edac_mc/edac_pci/edac_device)经 MC 驱动采集 → 通过/sys/devices/system/edac下的计数器与日志消息上报 → 用户态监控 CE 趋势、写入 DIMM 标签、调整 panic/日志/轮询策略,最终定位 MRU 完成预防性维护。相关文档入口为 Documentation/admin-guide/RAS/index.rst(含本主题及错误解码、地址翻译等子文档),属性语义权威定义见 Documentation/ABI/testing/sysfs-devices-edac,x86 平台的 MCA 细节见 arch/x86/x86_64/machinecheck.rst。
(原文档作者:Doug Thompson;Nehalem 接口部分由 Mauro Carvalho Chehab 增补并完成 ReST 转换;EDAC 作者/维护者还包括 Dave Jiang、Dave Peterson、Borislav Petkov,原始作者为 Thayne Harbaugh。)
【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考