-
随着内存容量的增大以及内存密度的增大,内存发生失败 的可能性以及内存的错误率都会增加。hwpoison是用来标 记发生错误的内存以及从内存错误中恢复的一个补丁。这 个补丁是由Andi Kleen和Wu Fengguang开发的,它提供了 Linux内核更强的承受内存错误的能力。
内存错误可以分为两类:软错误(暂时性的错误)和硬错 误(永久性的错误)。软错误可能是宇宙射线以及随机的 错误造成的内存中某一位的翻转。硬错误是物理硬件上的 失败(即使重启后仍然存在)。而由硬件提供的ECC(Error Correct Code)机制可以被用来自动纠正内存中单个位发 生翻转的情况,而对于多个位的翻转却无能为力。多个位 的翻转通常会导致MCE异常。
然而不论对于不可纠正的软错误还是硬错误都直接crash内 核就有点防卫过度了,人们更希望当错误没有影响到当前 正在运行的软件时,能够忽略这个错误或者将其进行隔离。 内存poison(memory poisoninng)就提供了一种这样的能 力,它可以将错误延迟处理并且可以隔离错误。然而内存 poison技术需要硬件和软件共同的支持。
HWPOISON补丁来得非常及时,出现在Intel刚刚推出支持内 存poison的Xeon处理器(Nehalem-EX)时。在Nehalem-EX 中包括了MCA架构(Machine Check Abort),并且该架构 支持内存poison,以及其他的硬件错误恢复机制。
关于内存poison的几个通用的概念:首先,硬件会在数据 由内存传递到系统缓存,或者在系统总线上检测到不可纠 正的错误。或者也可能是由内存“清洗”检测到的内存错误, 即有一个后台进程会在一个或者多个页上启动ECC检测。但 是上面两种检测到错误的情况都不会立即产生MCE,而是先 将这些数据标记为poison状态,然后当这些数据真正被读 (消费)时才会产生MCE。因此只要没有用到错误的数据, 就不会产生MCE。所以,有可能一个被修改的缓存行中包含 错误的数据,只要这个错误的数据没有被使用,就可以写 回内存。所以MCE可能发生在检测到错误数据很长时间以后。
HWPOISON是一个poison的处理函数,它由底层的MCE代码调 用。通常人们会认为HWPOISON的实现应将重点放在与错误数 据相关的进程和内存地址上,然而这是有难度的。因为在 数据错误被消费和调用poison处理函数之间存在着延迟,因 而不能决定受影响的究竟是哪一个进程。这种延迟是由硬件 报告错误的延迟以及poison处理函数使用工作队列执行造成 的,因而当poison处理函数开始执行的时候,当前系统中运 行的进程可能已经不是受影响的进程了。另外,poison处理 函数需要在内核真正能够管理内存的级别上来隔离内存,因 此处理使用的的是以页为单位的。
HWPOISON找到包含发生错误的数据所在的页,然后尝试将这 个页进行隔离,以防止以后被使用。对于受影响的进程可以 遍历系统中所有的进程检测哪个进程映射了这个页。HWPOISON 执行一些列的操作,这依赖于发生错误的页的类型和内核配 置参数。
HWPOISON必须在内和中配置MEMORY_FAILURE时才能使用,并 且还是需要硬件支持。
HWPOISON使用page结构体中flag成员的一个位用来标记poison 状态。
HWPOISON对于以下四种情况忽略处理:1)已经被标记为poison 状态的页;2)内核保留的页;3)使用者计数为0的页(例 如:空闲页或者内核的高端页);4)超出内核控制的页( 例如非法的页框)。
除了忽略错误以外,HWPOISON采取的措施还包括:恢复(recovery), 延迟(delay)和失败(failure)。忽略,延迟和失败的 共同点就是它们都没有隔离页框。延迟就是对错误不做任 何处理,等到受影响的内存被引用时再做处理,因为这种 错误可能是暂时的或者不相关的,等到再次使用的时候错 误可能已经不存在了。例如发生在slab和伙伴系统分配器 中的页和空闲页中的错误都被延迟。在hugepage的处理上 会失败,因为hugepage不支持由逆向映射找到使用它的进 程。
对于存在于页高速缓存(page cache)和swap中的干净的 页,可以通过失效(invalidate)缓存来进行恢复,因为 在磁盘上存在和缓存中一样的备份数据。对于脏页,页高 速缓存可以通过失效缓存来进行恢复,并且会将这个页标 记为页错误,之后用户空间系统调用访问与这个页相关的 文件时就会返回一个IO错误。另外,对于swap中的脏页采 取延迟处理的策略,发生错误的页中的脏标记被清除,并 且缓存项仍保存在swap中,之后访问swap中页的进程会通 过page fault被杀掉。
对于用户空间进程映射的内存,HWPOISON会首先找到所有 映射这个页的进程,如果这个页是干净的,那么HWPOISON 不需要做任何的恢复操作;如果这个也是脏的,HWPOISON 会解除与这个页相关的所有进程的映射,之后这些进程会 被杀死。与杀死进程相关的有用户空间的两个接口,这两 个接口分别是: /proc/sys/vm/memory_failure_early_kill /proc/sys/vm/memory_failure_recovery 前者置位会造成内核会立刻向受影响的进程发送SIGBUS 信号,这个SIGBUS信号是可以捕获的,并且带有额外信 息BUS_MCEERR_AO,因此进程可以决定如何处理被标记 为poison的数据。而后者置位延迟了杀死进程,仅仅是 解除了映射,当被接触映射的页之后真正被访问到时, 才会发送SIGBUS信号。
可以使用mm/hwpoison-inject.c提供的工具向内存中任 何一个页中注入错误。[1]
-
概述
-
高层次的机器检测处理函数,用来处理包含错误的页, 这些错误通常是由硬件报告的两位的ECC内存或者cache 错误。
-
该机制主要关心由后台程序检查到的内存错误,而当 CPU准备消费某个内存错误时,当前的进程直接被杀死。 这就意味着如果该错误不能由HWPOISON来处理时,可 以直接忽略掉,因为它并没有影响到当前CPU的执行, 当之后CPU在执行过程中遇到这个错误时再进行处理。
-
处理页高速缓存中不同状态的页。可以与VM的其他使用 者异步的访问任何页,因为内存错误在任何时候,任何 地方都可能发生。这可能违反了其他使用者的假设,因 而这部分代码格外小心。使用内核中通常的锁规则,尽 管这意味着错误处理程序可能会运行很长的时间。
-
在这部分实现中部分代码是效率低下的,因为没有对数 据结构进行优化,尤其是在有vma映射进程的时候,因为 这种场景的确很少见。
-
ref
1. https://lwn.net/Articles/348886/
2. http://www.linuxprogrammingblog.com/all-about-linux-signals?page=4
3. https://www.kernel.org/doc/Documentation/vm/hwpoison.txt
1.SIGBUS?
SIGBUS信号一般在访问映射内存时,与映射的内存相关的 文件不存在时产生,这种情况一般是由于一个进程已经截 断了映射的文件。对于SIGBUS的默认处理就是终止进程。 当然SIGBUS信号是可以捕获的,可以在该信号处理函数中 进行恢复,需要用到longjmp函数跳转到程序中未访问映 射内存的其他地方。[2]
2.swap?