diff options
author | Wu Fengguang <fengguang.wu@intel.com> | 2009-12-16 12:19:59 +0100 |
---|---|---|
committer | Andi Kleen <ak@linux.intel.com> | 2009-12-16 12:19:59 +0100 |
commit | 7c116f2b0dbac4a1dd051c7a5e8cef37701cafd4 (patch) | |
tree | ac7f1e56551df46bc79e400a182a57f4eae5ddaf /mm/memory-failure.c | |
parent | 138ce286eb6ee6d39ca4fb50516e93adaf6b605f (diff) | |
download | op-kernel-dev-7c116f2b0dbac4a1dd051c7a5e8cef37701cafd4.zip op-kernel-dev-7c116f2b0dbac4a1dd051c7a5e8cef37701cafd4.tar.gz |
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 edeaf23..82ac734 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -48,6 +48,50 @@ int sysctl_memory_failure_recovery __read_mostly = 1; atomic_long_t mce_bad_pages __read_mostly = ATOMIC_LONG_INIT(0); +u32 hwpoison_filter_dev_major = ~0U; +u32 hwpoison_filter_dev_minor = ~0U; +EXPORT_SYMBOL_GPL(hwpoison_filter_dev_major); +EXPORT_SYMBOL_GPL(hwpoison_filter_dev_minor); + +static int hwpoison_filter_dev(struct page *p) +{ + struct address_space *mapping; + dev_t dev; + + if (hwpoison_filter_dev_major == ~0U && + hwpoison_filter_dev_minor == ~0U) + return 0; + + /* + * page_mapping() does not accept slab page + */ + if (PageSlab(p)) + return -EINVAL; + + mapping = page_mapping(p); + if (mapping == NULL || mapping->host == NULL) + return -EINVAL; + + dev = mapping->host->i_sb->s_dev; + if (hwpoison_filter_dev_major != ~0U && + hwpoison_filter_dev_major != MAJOR(dev)) + return -EINVAL; + if (hwpoison_filter_dev_minor != ~0U && + hwpoison_filter_dev_minor != MINOR(dev)) + return -EINVAL; + + return 0; +} + +int hwpoison_filter(struct page *p) +{ + if (hwpoison_filter_dev(p)) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL_GPL(hwpoison_filter); + /* * Send all the processes who have the page mapped an ``action optional'' * signal. @@ -843,6 +887,13 @@ int __memory_failure(unsigned long pfn, int trapno, int flags) res = 0; goto out; } + if (hwpoison_filter(p)) { + if (TestClearPageHWPoison(p)) + atomic_long_dec(&mce_bad_pages); + unlock_page(p); + put_page(p); + return 0; + } wait_on_page_writeback(p); |