aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
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;