aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorWu Fengguang <fengguang.wu@intel.com>2009-12-16 06:19:59 -0500
committerAndi Kleen <ak@linux.intel.com>2009-12-16 06:19:59 -0500
commit31d3d3484f9bd263925ecaa341500ac2df3a5d9b (patch)
tree38f331f27f3b4bc537303fc90490b88d53e43710 /mm
parent7c116f2b0dbac4a1dd051c7a5e8cef37701cafd4 (diff)
HWPOISON: limit hwpoison injector to known page types
__memory_failure()'s workflow is set PG_hwpoison //... unset PG_hwpoison if didn't pass hwpoison filter That could kill unrelated process if it happens to page fault on the page with the (temporary) PG_hwpoison. The race should be big enough to appear in stress tests. Fix it by grabbing the page and checking filter at inject time. This also avoids the very noisy "Injecting memory failure..." messages. - we don't touch madvise() based injection, because the filters are generally not necessary for it. - if we want to apply the filters to h/w aided injection, we'd better to rearrange the logic in __memory_failure() instead of this patch. AK: fix documentation, use drain all, cleanups CC: Haicheng Li <haicheng.li@intel.com> Signed-off-by: Wu Fengguang <fengguang.wu@intel.com> Signed-off-by: Andi Kleen <ak@linux.intel.com>
Diffstat (limited to 'mm')
-rw-r--r--mm/hwpoison-inject.c41
-rw-r--r--mm/internal.h2
2 files changed, 41 insertions, 2 deletions
diff --git a/mm/hwpoison-inject.c b/mm/hwpoison-inject.c
index ac692a9b766c..2b6b3200fa65 100644
--- a/mm/hwpoison-inject.c
+++ b/mm/hwpoison-inject.c
@@ -3,16 +3,53 @@
3#include <linux/debugfs.h> 3#include <linux/debugfs.h>
4#include <linux/kernel.h> 4#include <linux/kernel.h>
5#include <linux/mm.h> 5#include <linux/mm.h>
6#include <linux/swap.h>
7#include <linux/pagemap.h>
6#include "internal.h" 8#include "internal.h"
7 9
8static struct dentry *hwpoison_dir; 10static struct dentry *hwpoison_dir;
9 11
10static int hwpoison_inject(void *data, u64 val) 12static int hwpoison_inject(void *data, u64 val)
11{ 13{
14 unsigned long pfn = val;
15 struct page *p;
16 int err;
17
12 if (!capable(CAP_SYS_ADMIN)) 18 if (!capable(CAP_SYS_ADMIN))
13 return -EPERM; 19 return -EPERM;
14 printk(KERN_INFO "Injecting memory failure at pfn %Lx\n", val); 20
15 return __memory_failure(val, 18, 0); 21 if (!pfn_valid(pfn))
22 return -ENXIO;
23
24 p = pfn_to_page(pfn);
25 /*
26 * This implies unable to support free buddy pages.
27 */
28 if (!get_page_unless_zero(p))
29 return 0;
30
31 if (!PageLRU(p))
32 shake_page(p);
33 /*
34 * This implies unable to support non-LRU pages.
35 */
36 if (!PageLRU(p))
37 return 0;
38
39 /*
40 * do a racy check with elevated page count, to make sure PG_hwpoison
41 * will only be set for the targeted owner (or on a free page).
42 * We temporarily take page lock for try_get_mem_cgroup_from_page().
43 * __memory_failure() will redo the check reliably inside page lock.
44 */
45 lock_page(p);
46 err = hwpoison_filter(p);
47 unlock_page(p);
48 if (err)
49 return 0;
50
51 printk(KERN_INFO "Injecting memory failure at pfn %lx\n", pfn);
52 return __memory_failure(pfn, 18, MF_COUNT_INCREASED);
16} 53}
17 54
18static int hwpoison_unpoison(void *data, u64 val) 55static int hwpoison_unpoison(void *data, u64 val)
diff --git a/mm/internal.h b/mm/internal.h
index 814da335f050..04bbce8b8ba6 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -251,5 +251,7 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
251#define ZONE_RECLAIM_SUCCESS 1 251#define ZONE_RECLAIM_SUCCESS 1
252#endif 252#endif
253 253
254extern int hwpoison_filter(struct page *p);
255
254extern u32 hwpoison_filter_dev_major; 256extern u32 hwpoison_filter_dev_major;
255extern u32 hwpoison_filter_dev_minor; 257extern u32 hwpoison_filter_dev_minor;