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 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 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; 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 80 static int hwpoison_filter_task(struct page *p) { return 0; } 81 #endif 82 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 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 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 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 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