diff options
author | Wu Fengguang <fengguang.wu@intel.com> | 2009-12-16 06:19:59 -0500 |
---|---|---|
committer | Andi Kleen <ak@linux.intel.com> | 2009-12-16 06:19:59 -0500 |
commit | 7c116f2b0dbac4a1dd051c7a5e8cef37701cafd4 (patch) | |
tree | ac7f1e56551df46bc79e400a182a57f4eae5ddaf /mm/memory-failure.c | |
parent | 138ce286eb6ee6d39ca4fb50516e93adaf6b605f (diff) |
HWPOISON: add fs/device filters
Filesystem data/metadata present the most tricky-to-isolate pages.
It requires careful code review and stress testing to get them right.
The fs/device filter helps to target the stress tests to some specific
filesystem pages. The filter condition is block device's major/minor
numbers:
- corrupt-filter-dev-major
- corrupt-filter-dev-minor
When specified (non -1), only page cache pages that belong to that
device will be poisoned.
The filters are checked reliably on the locked and refcounted page.
Haicheng: clear PG_hwpoison and drop bad page count if filter not OK
AK: Add documentation
CC: Haicheng Li <haicheng.li@intel.com>
CC: Nick Piggin <npiggin@suse.de>
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Diffstat (limited to 'mm/memory-failure.c')
-rw-r--r-- | mm/memory-failure.c | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/mm/memory-failure.c b/mm/memory-failure.c index edeaf2319e74..82ac73436d0e 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c | |||
@@ -48,6 +48,50 @@ int sysctl_memory_failure_recovery __read_mostly = 1; | |||
48 | 48 | ||
49 | atomic_long_t mce_bad_pages __read_mostly = ATOMIC_LONG_INIT(0); | 49 | atomic_long_t mce_bad_pages __read_mostly = ATOMIC_LONG_INIT(0); |
50 | 50 | ||
51 | u32 hwpoison_filter_dev_major = ~0U; | ||
52 | u32 hwpoison_filter_dev_minor = ~0U; | ||
53 | EXPORT_SYMBOL_GPL(hwpoison_filter_dev_major); | ||
54 | EXPORT_SYMBOL_GPL(hwpoison_filter_dev_minor); | ||
55 | |||
56 | static int hwpoison_filter_dev(struct page *p) | ||
57 | { | ||
58 | struct address_space *mapping; | ||
59 | dev_t dev; | ||
60 | |||
61 | if (hwpoison_filter_dev_major == ~0U && | ||
62 | hwpoison_filter_dev_minor == ~0U) | ||
63 | return 0; | ||
64 | |||
65 | /* | ||
66 | * page_mapping() does not accept slab page | ||
67 | */ | ||
68 | if (PageSlab(p)) | ||
69 | return -EINVAL; | ||
70 | |||
71 | mapping = page_mapping(p); | ||
72 | if (mapping == NULL || mapping->host == NULL) | ||
73 | return -EINVAL; | ||
74 | |||
75 | dev = mapping->host->i_sb->s_dev; | ||
76 | if (hwpoison_filter_dev_major != ~0U && | ||
77 | hwpoison_filter_dev_major != MAJOR(dev)) | ||
78 | return -EINVAL; | ||
79 | if (hwpoison_filter_dev_minor != ~0U && | ||
80 | hwpoison_filter_dev_minor != MINOR(dev)) | ||
81 | return -EINVAL; | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | int hwpoison_filter(struct page *p) | ||
87 | { | ||
88 | if (hwpoison_filter_dev(p)) | ||
89 | return -EINVAL; | ||
90 | |||
91 | return 0; | ||
92 | } | ||
93 | EXPORT_SYMBOL_GPL(hwpoison_filter); | ||
94 | |||
51 | /* | 95 | /* |
52 | * Send all the processes who have the page mapped an ``action optional'' | 96 | * Send all the processes who have the page mapped an ``action optional'' |
53 | * signal. | 97 | * signal. |
@@ -843,6 +887,13 @@ int __memory_failure(unsigned long pfn, int trapno, int flags) | |||
843 | res = 0; | 887 | res = 0; |
844 | goto out; | 888 | goto out; |
845 | } | 889 | } |
890 | if (hwpoison_filter(p)) { | ||
891 | if (TestClearPageHWPoison(p)) | ||
892 | atomic_long_dec(&mce_bad_pages); | ||
893 | unlock_page(p); | ||
894 | put_page(p); | ||
895 | return 0; | ||
896 | } | ||
846 | 897 | ||
847 | wait_on_page_writeback(p); | 898 | wait_on_page_writeback(p); |
848 | 899 | ||