summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/vm/hwpoison.txt10
-rw-r--r--mm/Kconfig1
-rw-r--r--mm/hwpoison-inject.c10
-rw-r--r--mm/internal.h2
-rw-r--r--mm/memory-failure.c20
5 files changed, 43 insertions, 0 deletions
diff --git a/Documentation/vm/hwpoison.txt b/Documentation/vm/hwpoison.txt
index 4ef7bb30d15..f454d3cd4d6 100644
--- a/Documentation/vm/hwpoison.txt
+++ b/Documentation/vm/hwpoison.txt
@@ -123,6 +123,16 @@ Only handle memory failures to pages associated with the file system defined
by block device major/minor. -1U is the wildcard value.
This should be only used for testing with artificial injection.
+
+corrupt-filter-flags-mask
+corrupt-filter-flags-value
+
+When specified, only poison pages if ((page_flags & mask) == value).
+This allows stress testing of many kinds of pages. The page_flags
+are the same as in /proc/kpageflags. The flag bits are defined in
+include/linux/kernel-page-flags.h and documented in
+Documentation/vm/pagemap.txt
+
Architecture specific MCE injector
x86 has mce-inject, mce-test
diff --git a/mm/Kconfig b/mm/Kconfig
index 2310984591e..8cea7fde06e 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -253,6 +253,7 @@ config MEMORY_FAILURE
config HWPOISON_INJECT
tristate "Poison pages injector"
depends on MEMORY_FAILURE && DEBUG_KERNEL
+ select PROC_PAGE_MONITOR
config NOMMU_INITIAL_TRIM_EXCESS
int "Turn on mmap() excess space trimming before booting"
diff --git a/mm/hwpoison-inject.c b/mm/hwpoison-inject.c
index 2b6b3200fa6..c4dfd89f654 100644
--- a/mm/hwpoison-inject.c
+++ b/mm/hwpoison-inject.c
@@ -102,6 +102,16 @@ static int pfn_inject_init(void)
if (!dentry)
goto fail;
+ dentry = debugfs_create_u64("corrupt-filter-flags-mask", 0600,
+ hwpoison_dir, &hwpoison_filter_flags_mask);
+ if (!dentry)
+ goto fail;
+
+ dentry = debugfs_create_u64("corrupt-filter-flags-value", 0600,
+ hwpoison_dir, &hwpoison_filter_flags_value);
+ if (!dentry)
+ goto fail;
+
return 0;
fail:
pfn_inject_exit();
diff --git a/mm/internal.h b/mm/internal.h
index 04bbce8b8ba..b2027c73119 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -255,3 +255,5 @@ extern int hwpoison_filter(struct page *p);
extern u32 hwpoison_filter_dev_major;
extern u32 hwpoison_filter_dev_minor;
+extern u64 hwpoison_filter_flags_mask;
+extern u64 hwpoison_filter_flags_value;
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 82ac73436d0..22d2b2028e5 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -34,6 +34,7 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/page-flags.h>
+#include <linux/kernel-page-flags.h>
#include <linux/sched.h>
#include <linux/ksm.h>
#include <linux/rmap.h>
@@ -50,8 +51,12 @@ atomic_long_t mce_bad_pages __read_mostly = ATOMIC_LONG_INIT(0);
u32 hwpoison_filter_dev_major = ~0U;
u32 hwpoison_filter_dev_minor = ~0U;
+u64 hwpoison_filter_flags_mask;
+u64 hwpoison_filter_flags_value;
EXPORT_SYMBOL_GPL(hwpoison_filter_dev_major);
EXPORT_SYMBOL_GPL(hwpoison_filter_dev_minor);
+EXPORT_SYMBOL_GPL(hwpoison_filter_flags_mask);
+EXPORT_SYMBOL_GPL(hwpoison_filter_flags_value);
static int hwpoison_filter_dev(struct page *p)
{
@@ -83,11 +88,26 @@ static int hwpoison_filter_dev(struct page *p)
return 0;
}
+static int hwpoison_filter_flags(struct page *p)
+{
+ if (!hwpoison_filter_flags_mask)
+ return 0;
+
+ if ((stable_page_flags(p) & hwpoison_filter_flags_mask) ==
+ hwpoison_filter_flags_value)
+ return 0;
+ else
+ return -EINVAL;
+}
+
int hwpoison_filter(struct page *p)
{
if (hwpoison_filter_dev(p))
return -EINVAL;
+ if (hwpoison_filter_flags(p))
+ return -EINVAL;
+
return 0;
}
EXPORT_SYMBOL_GPL(hwpoison_filter);