1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Inject a hwpoison memory failure on a arbitrary pfn */
3 #include <linux/module.h>
4 #include <linux/debugfs.h>
5 #include <linux/kernel.h>
6 #include <linux/mm.h>
7 #include <linux/swap.h>
8 #include <linux/pagemap.h>
9 #include <linux/hugetlb.h>
10 #include <linux/page-flags.h>
11 #include <linux/memcontrol.h>
12 #include "internal.h"
13
14 static u32 hwpoison_filter_enable;
15 static u32 hwpoison_filter_dev_major = ~0U;
16 static u32 hwpoison_filter_dev_minor = ~0U;
17 static u64 hwpoison_filter_flags_mask;
18 static u64 hwpoison_filter_flags_value;
19
hwpoison_filter_dev(struct page * p)20 static int hwpoison_filter_dev(struct page *p)
21 {
22 struct folio *folio = page_folio(p);
23 struct address_space *mapping;
24 dev_t dev;
25
26 if (hwpoison_filter_dev_major == ~0U &&
27 hwpoison_filter_dev_minor == ~0U)
28 return 0;
29
30 mapping = folio_mapping(folio);
31 if (mapping == NULL || mapping->host == NULL)
32 return -EINVAL;
33
34 dev = mapping->host->i_sb->s_dev;
35 if (hwpoison_filter_dev_major != ~0U &&
36 hwpoison_filter_dev_major != MAJOR(dev))
37 return -EINVAL;
38 if (hwpoison_filter_dev_minor != ~0U &&
39 hwpoison_filter_dev_minor != MINOR(dev))
40 return -EINVAL;
41
42 return 0;
43 }
44
hwpoison_filter_flags(struct page * p)45 static int hwpoison_filter_flags(struct page *p)
46 {
47 if (!hwpoison_filter_flags_mask)
48 return 0;
49
50 if ((stable_page_flags(p) & hwpoison_filter_flags_mask) ==
51 hwpoison_filter_flags_value)
52 return 0;
53 else
54 return -EINVAL;
55 }
56
57 /*
58 * This allows stress tests to limit test scope to a collection of tasks
59 * by putting them under some memcg. This prevents killing unrelated/important
60 * processes such as /sbin/init. Note that the target task may share clean
61 * pages with init (eg. libc text), which is harmless. If the target task
62 * share _dirty_ pages with another task B, the test scheme must make sure B
63 * is also included in the memcg. At last, due to race conditions this filter
64 * can only guarantee that the page either belongs to the memcg tasks, or is
65 * a freed page.
66 */
67 #ifdef CONFIG_MEMCG
68 static u64 hwpoison_filter_memcg;
hwpoison_filter_task(struct page * p)69 static int hwpoison_filter_task(struct page *p)
70 {
71 if (!hwpoison_filter_memcg)
72 return 0;
73
74 if (page_cgroup_ino(p) != hwpoison_filter_memcg)
75 return -EINVAL;
76
77 return 0;
78 }
79 #else
hwpoison_filter_task(struct page * p)80 static int hwpoison_filter_task(struct page *p) { return 0; }
81 #endif
82
hwpoison_filter(struct page * p)83 static int hwpoison_filter(struct page *p)
84 {
85 if (!hwpoison_filter_enable)
86 return 0;
87
88 if (hwpoison_filter_dev(p))
89 return -EINVAL;
90
91 if (hwpoison_filter_flags(p))
92 return -EINVAL;
93
94 if (hwpoison_filter_task(p))
95 return -EINVAL;
96
97 return 0;
98 }
99
100 static struct dentry *hwpoison_dir;
101
hwpoison_inject(void * data,u64 val)102 static int hwpoison_inject(void *data, u64 val)
103 {
104 unsigned long pfn = val;
105 struct page *p;
106 struct folio *folio;
107 int err;
108
109 if (!capable(CAP_SYS_ADMIN))
110 return -EPERM;
111
112 if (!pfn_valid(pfn))
113 return -ENXIO;
114
115 p = pfn_to_page(pfn);
116 folio = page_folio(p);
117
118 if (!hwpoison_filter_enable)
119 goto inject;
120
121 shake_folio(folio);
122 /*
123 * This implies unable to support non-LRU pages except free page.
124 */
125 if (!folio_test_lru(folio) && !folio_test_hugetlb(folio) &&
126 !is_free_buddy_page(p))
127 return 0;
128
129 /*
130 * do a racy check to make sure PG_hwpoison will only be set for
131 * the targeted owner (or on a free page).
132 * memory_failure() will redo the check reliably inside page lock.
133 */
134 err = hwpoison_filter(&folio->page);
135 if (err)
136 return 0;
137
138 inject:
139 pr_info("Injecting memory failure at pfn %#lx\n", pfn);
140 err = memory_failure(pfn, MF_SW_SIMULATED);
141 return (err == -EOPNOTSUPP) ? 0 : err;
142 }
143
hwpoison_unpoison(void * data,u64 val)144 static int hwpoison_unpoison(void *data, u64 val)
145 {
146 if (!capable(CAP_SYS_ADMIN))
147 return -EPERM;
148
149 return unpoison_memory(val);
150 }
151
152 DEFINE_DEBUGFS_ATTRIBUTE(hwpoison_fops, NULL, hwpoison_inject, "%lli\n");
153 DEFINE_DEBUGFS_ATTRIBUTE(unpoison_fops, NULL, hwpoison_unpoison, "%lli\n");
154
pfn_inject_exit(void)155 static void __exit pfn_inject_exit(void)
156 {
157 hwpoison_filter_enable = 0;
158 hwpoison_filter_unregister();
159 debugfs_remove_recursive(hwpoison_dir);
160 }
161
pfn_inject_init(void)162 static int __init pfn_inject_init(void)
163 {
164 hwpoison_dir = debugfs_create_dir("hwpoison", NULL);
165
166 /*
167 * Note that the below poison/unpoison interfaces do not involve
168 * hardware status change, hence do not require hardware support.
169 * They are mainly for testing hwpoison in software level.
170 */
171 debugfs_create_file("corrupt-pfn", 0200, hwpoison_dir, NULL,
172 &hwpoison_fops);
173
174 debugfs_create_file("unpoison-pfn", 0200, hwpoison_dir, NULL,
175 &unpoison_fops);
176
177 debugfs_create_u32("corrupt-filter-enable", 0600, hwpoison_dir,
178 &hwpoison_filter_enable);
179
180 debugfs_create_u32("corrupt-filter-dev-major", 0600, hwpoison_dir,
181 &hwpoison_filter_dev_major);
182
183 debugfs_create_u32("corrupt-filter-dev-minor", 0600, hwpoison_dir,
184 &hwpoison_filter_dev_minor);
185
186 debugfs_create_u64("corrupt-filter-flags-mask", 0600, hwpoison_dir,
187 &hwpoison_filter_flags_mask);
188
189 debugfs_create_u64("corrupt-filter-flags-value", 0600, hwpoison_dir,
190 &hwpoison_filter_flags_value);
191
192 #ifdef CONFIG_MEMCG
193 debugfs_create_u64("corrupt-filter-memcg", 0600, hwpoison_dir,
194 &hwpoison_filter_memcg);
195 #endif
196
197 hwpoison_filter_register(hwpoison_filter);
198
199 return 0;
200 }
201
202 module_init(pfn_inject_init);
203 module_exit(pfn_inject_exit);
204 MODULE_DESCRIPTION("HWPoison pages injector");
205 MODULE_LICENSE("GPL");
206