hwpoison

什么是 hwpoison?

即将推出的 Intel CPU 支持从某些内存错误中恢复 (MCA recovery)。这需要操作系统声明一个页面为“中毒”,杀死与之关联的进程,并避免将来使用它。

此补丁集在 VM 中实现必要的基础架构。

引用概述注释

High level machine check handler. Handles pages reported by the
hardware as being corrupted usually due to a 2bit ECC memory or cache
failure.

This focusses on pages detected as corrupted in the background.
When the current CPU tries to consume corruption the currently
running process can just be killed directly instead. This implies
that if the error cannot be handled for some reason it's safe to
just ignore it because no corruption has been consumed yet. Instead
when that happens another machine check will happen.

Handles page cache pages in various states. The tricky part
here is that we can access any page asynchronous to other VM
users, because memory failures could happen anytime and anywhere,
possibly violating some of their assumptions. This is why this code
has to be extremely careful. Generally it tries to use normal locking
rules, as in get the standard locks, even if that means the
error handling takes potentially a long time.

Some of the operations here are somewhat inefficient and have non
linear algorithmic complexity, because the data structures have not
been optimized for this case. This is in particular the case
for the mapping from a vma to a process. Since this case is expected
to be rare we hope we can get away with this.

代码由 mm/memory-failure.c 中的高级处理程序、一个新的页面中毒位以及 VM 中用于处理中毒页面的各种检查组成。

目前的主要目标是 KVM 虚拟机,但它适用于各种应用程序。KVM 支持需要最近的 qemu-kvm 版本。

对于 KVM 使用,需要一个新的信号类型,以便 KVM 可以将机器检查以正确的地址注入到虚拟机中。理论上,这也允许其他应用程序处理内存故障。预期大多数应用程序不会这样做,但一些非常专业的应用程序可能会这样做。

故障恢复模式

内存故障恢复有两种(实际上是三种)模式

vm.memory_failure_recovery sysctl 设置为零

所有内存故障都会导致恐慌。不要尝试恢复。

早期终止

(可以全局和按进程控制)一旦检测到错误,立即向应用程序发送 SIGBUS。这允许能够以温和的方式处理内存错误的应用程序(例如,删除受影响的对象)。这是 KVM qemu 使用的模式。

后期终止

当应用程序遇到损坏的页面时发送 SIGBUS。这最适合不了解内存错误的应用程序,也是默认模式。请注意,有些页面始终被视为后期终止。

用户控制

vm.memory_failure_recovery

请参阅 sysctl.txt

vm.memory_failure_early_kill

全局启用早期终止模式

PR_MCE_KILL

设置早期/后期终止模式/恢复为系统默认值

arg1: PR_MCE_KILL_CLEAR

恢复为系统默认值

arg1: PR_MCE_KILL_SET

arg2 定义线程特定模式

PR_MCE_KILL_EARLY

早期终止

PR_MCE_KILL_LATE

后期终止

PR_MCE_KILL_DEFAULT

使用系统全局默认值

请注意,如果您希望拥有一个专门的线程代表进程处理 SIGBUS(BUS_MCEERR_AO),则应在指定的线程上调用 prctl(PR_MCE_KILL_EARLY)。否则,SIGBUS 将发送到主线程。

PR_MCE_KILL_GET

返回当前模式

测试

  • madvise(MADV_HWPOISON, ....) (以 root 身份) - 在进程中中毒一个页面以进行测试

  • 通过 debugfs 的 hwpoison-inject 模块 /sys/kernel/debug/hwpoison/

    corrupt-pfn

    在回显到此文件中的 PFN 处注入 hwpoison 故障。这会进行一些早期过滤,以避免在测试套件中损坏意外的页面。

    unpoison-pfn

    在回显到此文件中的 PFN 处进行软件取消中毒页面。这样可以再次重用页面。这仅适用于 Linux 注入的故障,不适用于真实的内存故障。一旦发生任何硬件内存故障,此功能将被禁用。

    请注意,这些注入接口不稳定,并且可能在内核版本之间发生变化

    corrupt-filter-dev-major, corrupt-filter-dev-minor

    仅处理与由块设备主/次设备号定义的文件系统关联的页面的内存故障。-1U 是通配符值。这应仅用于使用人工注入进行测试。

    corrupt-filter-memcg

    将注入限制为 memgroup 拥有的页面。由 memcg 的 inode 号指定。

    示例

    mkdir /sys/fs/cgroup/mem/hwpoison
    
    usemem -m 100 -s 1000 &
    echo `jobs -p` > /sys/fs/cgroup/mem/hwpoison/tasks
    
    memcg_ino=$(ls -id /sys/fs/cgroup/mem/hwpoison | cut -f1 -d' ')
    echo $memcg_ino > /debug/hwpoison/corrupt-filter-memcg
    
    page-types -p `pidof init`   --hwpoison  # shall do nothing
    page-types -p `pidof usemem` --hwpoison  # poison its pages
    
    corrupt-filter-flags-mask, corrupt-filter-flags-value

    指定后,仅当 ((page_flags & mask) == value) 时才中毒页面。这允许对多种页面进行压力测试。page_flags 与 /proc/kpageflags 中的相同。标志位定义在 include/linux/kernel-page-flags.h 中,并在检查进程页表中进行了文档说明

  • 特定于架构的 MCE 注入器

    x86 有 mce-inject, mce-test

    mce-test 中有一些可移植的 hwpoison 测试程序,请参见下文。

参考

http://halobates.de/mce-lc09-2.pdf

来自 LinuxCon 09 的概述演示文稿

git://git.kernel.org/pub/scm/utils/cpu/mce/mce-test.git

测试套件(tsrc 中特定于 hwpoison 的可移植测试)

git://git.kernel.org/pub/scm/utils/cpu/mce/mce-inject.git

特定于 x86 的注入器

限制

  • 并非所有页面类型都受支持,而且永远不会。大多数内核内部对象无法恢复,目前只有 LRU 页面。

--- Andi Kleen,2009 年 10 月