Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.15 140 lines 3.3 kB view raw
1/* Inject a hwpoison memory failure on a arbitrary pfn */ 2#include <linux/module.h> 3#include <linux/debugfs.h> 4#include <linux/kernel.h> 5#include <linux/mm.h> 6#include <linux/swap.h> 7#include <linux/pagemap.h> 8#include <linux/hugetlb.h> 9#include "internal.h" 10 11static struct dentry *hwpoison_dir; 12 13static int hwpoison_inject(void *data, u64 val) 14{ 15 unsigned long pfn = val; 16 struct page *p; 17 struct page *hpage; 18 int err; 19 20 if (!capable(CAP_SYS_ADMIN)) 21 return -EPERM; 22 23 if (!pfn_valid(pfn)) 24 return -ENXIO; 25 26 p = pfn_to_page(pfn); 27 hpage = compound_head(p); 28 /* 29 * This implies unable to support free buddy pages. 30 */ 31 if (!get_hwpoison_page(p)) 32 return 0; 33 34 if (!hwpoison_filter_enable) 35 goto inject; 36 37 shake_page(hpage, 0); 38 /* 39 * This implies unable to support non-LRU pages. 40 */ 41 if (!PageLRU(hpage) && !PageHuge(p)) 42 goto put_out; 43 44 /* 45 * do a racy check with elevated page count, to make sure PG_hwpoison 46 * will only be set for the targeted owner (or on a free page). 47 * memory_failure() will redo the check reliably inside page lock. 48 */ 49 err = hwpoison_filter(hpage); 50 if (err) 51 goto put_out; 52 53inject: 54 pr_info("Injecting memory failure at pfn %#lx\n", pfn); 55 return memory_failure(pfn, 18, MF_COUNT_INCREASED); 56put_out: 57 put_hwpoison_page(p); 58 return 0; 59} 60 61static int hwpoison_unpoison(void *data, u64 val) 62{ 63 if (!capable(CAP_SYS_ADMIN)) 64 return -EPERM; 65 66 return unpoison_memory(val); 67} 68 69DEFINE_SIMPLE_ATTRIBUTE(hwpoison_fops, NULL, hwpoison_inject, "%lli\n"); 70DEFINE_SIMPLE_ATTRIBUTE(unpoison_fops, NULL, hwpoison_unpoison, "%lli\n"); 71 72static void pfn_inject_exit(void) 73{ 74 debugfs_remove_recursive(hwpoison_dir); 75} 76 77static int pfn_inject_init(void) 78{ 79 struct dentry *dentry; 80 81 hwpoison_dir = debugfs_create_dir("hwpoison", NULL); 82 if (hwpoison_dir == NULL) 83 return -ENOMEM; 84 85 /* 86 * Note that the below poison/unpoison interfaces do not involve 87 * hardware status change, hence do not require hardware support. 88 * They are mainly for testing hwpoison in software level. 89 */ 90 dentry = debugfs_create_file("corrupt-pfn", 0200, hwpoison_dir, 91 NULL, &hwpoison_fops); 92 if (!dentry) 93 goto fail; 94 95 dentry = debugfs_create_file("unpoison-pfn", 0200, hwpoison_dir, 96 NULL, &unpoison_fops); 97 if (!dentry) 98 goto fail; 99 100 dentry = debugfs_create_u32("corrupt-filter-enable", 0600, 101 hwpoison_dir, &hwpoison_filter_enable); 102 if (!dentry) 103 goto fail; 104 105 dentry = debugfs_create_u32("corrupt-filter-dev-major", 0600, 106 hwpoison_dir, &hwpoison_filter_dev_major); 107 if (!dentry) 108 goto fail; 109 110 dentry = debugfs_create_u32("corrupt-filter-dev-minor", 0600, 111 hwpoison_dir, &hwpoison_filter_dev_minor); 112 if (!dentry) 113 goto fail; 114 115 dentry = debugfs_create_u64("corrupt-filter-flags-mask", 0600, 116 hwpoison_dir, &hwpoison_filter_flags_mask); 117 if (!dentry) 118 goto fail; 119 120 dentry = debugfs_create_u64("corrupt-filter-flags-value", 0600, 121 hwpoison_dir, &hwpoison_filter_flags_value); 122 if (!dentry) 123 goto fail; 124 125#ifdef CONFIG_MEMCG 126 dentry = debugfs_create_u64("corrupt-filter-memcg", 0600, 127 hwpoison_dir, &hwpoison_filter_memcg); 128 if (!dentry) 129 goto fail; 130#endif 131 132 return 0; 133fail: 134 pfn_inject_exit(); 135 return -ENOMEM; 136} 137 138module_init(pfn_inject_init); 139module_exit(pfn_inject_exit); 140MODULE_LICENSE("GPL");