Blame view

mm/hwpoison-inject.c 3.33 KB
25985edce   Lucas De Marchi   Fix common misspe...
1
  /* Inject a hwpoison memory failure on a arbitrary pfn */
cae681fc1   Andi Kleen   HWPOISON: Add sim...
2
3
4
5
  #include <linux/module.h>
  #include <linux/debugfs.h>
  #include <linux/kernel.h>
  #include <linux/mm.h>
31d3d3484   Wu Fengguang   HWPOISON: limit h...
6
7
  #include <linux/swap.h>
  #include <linux/pagemap.h>
43131e141   Naoya Horiguchi   HWPOISON, hugetlb...
8
  #include <linux/hugetlb.h>
7c116f2b0   Wu Fengguang   HWPOISON: add fs/...
9
  #include "internal.h"
cae681fc1   Andi Kleen   HWPOISON: Add sim...
10

847ce401d   Wu Fengguang   HWPOISON: Add unp...
11
  static struct dentry *hwpoison_dir;
cae681fc1   Andi Kleen   HWPOISON: Add sim...
12
13
14
  
  static int hwpoison_inject(void *data, u64 val)
  {
31d3d3484   Wu Fengguang   HWPOISON: limit h...
15
16
  	unsigned long pfn = val;
  	struct page *p;
43131e141   Naoya Horiguchi   HWPOISON, hugetlb...
17
  	struct page *hpage;
31d3d3484   Wu Fengguang   HWPOISON: limit h...
18
  	int err;
cae681fc1   Andi Kleen   HWPOISON: Add sim...
19
20
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
31d3d3484   Wu Fengguang   HWPOISON: limit h...
21

0d57eb8df   Andi Kleen   HWPOISON: Don't d...
22
23
  	if (!hwpoison_filter_enable)
  		goto inject;
31d3d3484   Wu Fengguang   HWPOISON: limit h...
24
25
26
27
  	if (!pfn_valid(pfn))
  		return -ENXIO;
  
  	p = pfn_to_page(pfn);
43131e141   Naoya Horiguchi   HWPOISON, hugetlb...
28
  	hpage = compound_head(p);
31d3d3484   Wu Fengguang   HWPOISON: limit h...
29
30
31
  	/*
  	 * This implies unable to support free buddy pages.
  	 */
43131e141   Naoya Horiguchi   HWPOISON, hugetlb...
32
  	if (!get_page_unless_zero(hpage))
31d3d3484   Wu Fengguang   HWPOISON: limit h...
33
  		return 0;
43131e141   Naoya Horiguchi   HWPOISON, hugetlb...
34
  	if (!PageLRU(p) && !PageHuge(p))
facb6011f   Andi Kleen   HWPOISON: Add sof...
35
  		shake_page(p, 0);
31d3d3484   Wu Fengguang   HWPOISON: limit h...
36
37
38
  	/*
  	 * This implies unable to support non-LRU pages.
  	 */
43131e141   Naoya Horiguchi   HWPOISON, hugetlb...
39
  	if (!PageLRU(p) && !PageHuge(p))
31d3d3484   Wu Fengguang   HWPOISON: limit h...
40
41
42
43
44
45
46
47
  		return 0;
  
  	/*
  	 * do a racy check with elevated page count, to make sure PG_hwpoison
  	 * will only be set for the targeted owner (or on a free page).
  	 * We temporarily take page lock for try_get_mem_cgroup_from_page().
  	 * __memory_failure() will redo the check reliably inside page lock.
  	 */
43131e141   Naoya Horiguchi   HWPOISON, hugetlb...
48
49
50
  	lock_page(hpage);
  	err = hwpoison_filter(hpage);
  	unlock_page(hpage);
31d3d3484   Wu Fengguang   HWPOISON: limit h...
51
52
  	if (err)
  		return 0;
0d57eb8df   Andi Kleen   HWPOISON: Don't d...
53
  inject:
31d3d3484   Wu Fengguang   HWPOISON: limit h...
54
55
56
  	printk(KERN_INFO "Injecting memory failure at pfn %lx
  ", pfn);
  	return __memory_failure(pfn, 18, MF_COUNT_INCREASED);
cae681fc1   Andi Kleen   HWPOISON: Add sim...
57
  }
847ce401d   Wu Fengguang   HWPOISON: Add unp...
58
59
60
61
62
63
64
  static int hwpoison_unpoison(void *data, u64 val)
  {
  	if (!capable(CAP_SYS_ADMIN))
  		return -EPERM;
  
  	return unpoison_memory(val);
  }
cae681fc1   Andi Kleen   HWPOISON: Add sim...
65
66
  DEFINE_SIMPLE_ATTRIBUTE(hwpoison_fops, NULL, hwpoison_inject, "%lli
  ");
847ce401d   Wu Fengguang   HWPOISON: Add unp...
67
68
  DEFINE_SIMPLE_ATTRIBUTE(unpoison_fops, NULL, hwpoison_unpoison, "%lli
  ");
cae681fc1   Andi Kleen   HWPOISON: Add sim...
69
70
71
72
73
74
75
76
77
  
  static void pfn_inject_exit(void)
  {
  	if (hwpoison_dir)
  		debugfs_remove_recursive(hwpoison_dir);
  }
  
  static int pfn_inject_init(void)
  {
847ce401d   Wu Fengguang   HWPOISON: Add unp...
78
  	struct dentry *dentry;
cae681fc1   Andi Kleen   HWPOISON: Add sim...
79
80
81
  	hwpoison_dir = debugfs_create_dir("hwpoison", NULL);
  	if (hwpoison_dir == NULL)
  		return -ENOMEM;
847ce401d   Wu Fengguang   HWPOISON: Add unp...
82
83
84
85
86
87
88
  
  	/*
  	 * Note that the below poison/unpoison interfaces do not involve
  	 * hardware status change, hence do not require hardware support.
  	 * They are mainly for testing hwpoison in software level.
  	 */
  	dentry = debugfs_create_file("corrupt-pfn", 0600, hwpoison_dir,
cae681fc1   Andi Kleen   HWPOISON: Add sim...
89
  					  NULL, &hwpoison_fops);
847ce401d   Wu Fengguang   HWPOISON: Add unp...
90
91
92
93
94
95
96
  	if (!dentry)
  		goto fail;
  
  	dentry = debugfs_create_file("unpoison-pfn", 0600, hwpoison_dir,
  				     NULL, &unpoison_fops);
  	if (!dentry)
  		goto fail;
1bfe5febe   Haicheng Li   HWPOISON: add an ...
97
98
99
100
  	dentry = debugfs_create_u32("corrupt-filter-enable", 0600,
  				    hwpoison_dir, &hwpoison_filter_enable);
  	if (!dentry)
  		goto fail;
7c116f2b0   Wu Fengguang   HWPOISON: add fs/...
101
102
103
104
105
106
107
108
109
  	dentry = debugfs_create_u32("corrupt-filter-dev-major", 0600,
  				    hwpoison_dir, &hwpoison_filter_dev_major);
  	if (!dentry)
  		goto fail;
  
  	dentry = debugfs_create_u32("corrupt-filter-dev-minor", 0600,
  				    hwpoison_dir, &hwpoison_filter_dev_minor);
  	if (!dentry)
  		goto fail;
478c5ffc0   Wu Fengguang   HWPOISON: add pag...
110
111
112
113
114
115
116
117
118
  	dentry = debugfs_create_u64("corrupt-filter-flags-mask", 0600,
  				    hwpoison_dir, &hwpoison_filter_flags_mask);
  	if (!dentry)
  		goto fail;
  
  	dentry = debugfs_create_u64("corrupt-filter-flags-value", 0600,
  				    hwpoison_dir, &hwpoison_filter_flags_value);
  	if (!dentry)
  		goto fail;
4fd466eb4   Andi Kleen   HWPOISON: add mem...
119
120
121
122
123
124
  #ifdef	CONFIG_CGROUP_MEM_RES_CTLR_SWAP
  	dentry = debugfs_create_u64("corrupt-filter-memcg", 0600,
  				    hwpoison_dir, &hwpoison_filter_memcg);
  	if (!dentry)
  		goto fail;
  #endif
cae681fc1   Andi Kleen   HWPOISON: Add sim...
125
  	return 0;
847ce401d   Wu Fengguang   HWPOISON: Add unp...
126
127
128
  fail:
  	pfn_inject_exit();
  	return -ENOMEM;
cae681fc1   Andi Kleen   HWPOISON: Add sim...
129
130
131
132
133
  }
  
  module_init(pfn_inject_init);
  module_exit(pfn_inject_exit);
  MODULE_LICENSE("GPL");