Commit 478c5ffc0b50527bd2390f2daa46cc16276b8413

Authored by Wu Fengguang
Committed by Andi Kleen
1 parent 1a9b5b7fe0

HWPOISON: add page flags filter

When specified, only poison pages if ((page_flags & mask) == value).

-       corrupt-filter-flags-mask
-       corrupt-filter-flags-value

This allows stress testing of many kinds of pages.

Strictly speaking, the buddy pages requires taking zone lock, to avoid
setting PG_hwpoison on a "was buddy but now allocated to someone" page.
However we can just do nothing because we set PG_locked in the beginning,
this prevents the page allocator from allocating it to someone. (It will
BUG() on the unexpected PG_locked, which is fine for hwpoison testing.)

[AK: Add select PROC_PAGE_MONITOR to satisfy dependency]

CC: Nick Piggin <npiggin@suse.de>
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>

Showing 5 changed files with 43 additions and 0 deletions Side-by-side Diff

Documentation/vm/hwpoison.txt
... ... @@ -123,6 +123,16 @@
123 123 by block device major/minor. -1U is the wildcard value.
124 124 This should be only used for testing with artificial injection.
125 125  
  126 +
  127 +corrupt-filter-flags-mask
  128 +corrupt-filter-flags-value
  129 +
  130 +When specified, only poison pages if ((page_flags & mask) == value).
  131 +This allows stress testing of many kinds of pages. The page_flags
  132 +are the same as in /proc/kpageflags. The flag bits are defined in
  133 +include/linux/kernel-page-flags.h and documented in
  134 +Documentation/vm/pagemap.txt
  135 +
126 136 Architecture specific MCE injector
127 137  
128 138 x86 has mce-inject, mce-test
... ... @@ -253,6 +253,7 @@
253 253 config HWPOISON_INJECT
254 254 tristate "Poison pages injector"
255 255 depends on MEMORY_FAILURE && DEBUG_KERNEL
  256 + select PROC_PAGE_MONITOR
256 257  
257 258 config NOMMU_INITIAL_TRIM_EXCESS
258 259 int "Turn on mmap() excess space trimming before booting"
mm/hwpoison-inject.c
... ... @@ -102,6 +102,16 @@
102 102 if (!dentry)
103 103 goto fail;
104 104  
  105 + dentry = debugfs_create_u64("corrupt-filter-flags-mask", 0600,
  106 + hwpoison_dir, &hwpoison_filter_flags_mask);
  107 + if (!dentry)
  108 + goto fail;
  109 +
  110 + dentry = debugfs_create_u64("corrupt-filter-flags-value", 0600,
  111 + hwpoison_dir, &hwpoison_filter_flags_value);
  112 + if (!dentry)
  113 + goto fail;
  114 +
105 115 return 0;
106 116 fail:
107 117 pfn_inject_exit();
... ... @@ -255,4 +255,6 @@
255 255  
256 256 extern u32 hwpoison_filter_dev_major;
257 257 extern u32 hwpoison_filter_dev_minor;
  258 +extern u64 hwpoison_filter_flags_mask;
  259 +extern u64 hwpoison_filter_flags_value;
... ... @@ -34,6 +34,7 @@
34 34 #include <linux/kernel.h>
35 35 #include <linux/mm.h>
36 36 #include <linux/page-flags.h>
  37 +#include <linux/kernel-page-flags.h>
37 38 #include <linux/sched.h>
38 39 #include <linux/ksm.h>
39 40 #include <linux/rmap.h>
40 41  
... ... @@ -50,8 +51,12 @@
50 51  
51 52 u32 hwpoison_filter_dev_major = ~0U;
52 53 u32 hwpoison_filter_dev_minor = ~0U;
  54 +u64 hwpoison_filter_flags_mask;
  55 +u64 hwpoison_filter_flags_value;
53 56 EXPORT_SYMBOL_GPL(hwpoison_filter_dev_major);
54 57 EXPORT_SYMBOL_GPL(hwpoison_filter_dev_minor);
  58 +EXPORT_SYMBOL_GPL(hwpoison_filter_flags_mask);
  59 +EXPORT_SYMBOL_GPL(hwpoison_filter_flags_value);
55 60  
56 61 static int hwpoison_filter_dev(struct page *p)
57 62 {
58 63  
... ... @@ -83,9 +88,24 @@
83 88 return 0;
84 89 }
85 90  
  91 +static int hwpoison_filter_flags(struct page *p)
  92 +{
  93 + if (!hwpoison_filter_flags_mask)
  94 + return 0;
  95 +
  96 + if ((stable_page_flags(p) & hwpoison_filter_flags_mask) ==
  97 + hwpoison_filter_flags_value)
  98 + return 0;
  99 + else
  100 + return -EINVAL;
  101 +}
  102 +
86 103 int hwpoison_filter(struct page *p)
87 104 {
88 105 if (hwpoison_filter_dev(p))
  106 + return -EINVAL;
  107 +
  108 + if (hwpoison_filter_flags(p))
89 109 return -EINVAL;
90 110  
91 111 return 0;