diff options
Diffstat (limited to 'mm/hwpoison-inject.c')
-rw-r--r-- | mm/hwpoison-inject.c | 41 |
1 files changed, 39 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 | ||
8 | static struct dentry *hwpoison_dir; | 10 | static struct dentry *hwpoison_dir; |
9 | 11 | ||
10 | static int hwpoison_inject(void *data, u64 val) | 12 | static 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 | ||
18 | static int hwpoison_unpoison(void *data, u64 val) | 55 | static int hwpoison_unpoison(void *data, u64 val) |