1cae681fcSAndi Kleen /* Inject a hwpoison memory failure on a arbitary pfn */ 2cae681fcSAndi Kleen #include <linux/module.h> 3cae681fcSAndi Kleen #include <linux/debugfs.h> 4cae681fcSAndi Kleen #include <linux/kernel.h> 5cae681fcSAndi Kleen #include <linux/mm.h> 6*7c116f2bSWu Fengguang #include "internal.h" 7cae681fcSAndi Kleen 8847ce401SWu Fengguang static struct dentry *hwpoison_dir; 9cae681fcSAndi Kleen 10cae681fcSAndi Kleen static int hwpoison_inject(void *data, u64 val) 11cae681fcSAndi Kleen { 12cae681fcSAndi Kleen if (!capable(CAP_SYS_ADMIN)) 13cae681fcSAndi Kleen return -EPERM; 14cae681fcSAndi Kleen printk(KERN_INFO "Injecting memory failure at pfn %Lx\n", val); 15cae681fcSAndi Kleen return __memory_failure(val, 18, 0); 16cae681fcSAndi Kleen } 17cae681fcSAndi Kleen 18847ce401SWu Fengguang static int hwpoison_unpoison(void *data, u64 val) 19847ce401SWu Fengguang { 20847ce401SWu Fengguang if (!capable(CAP_SYS_ADMIN)) 21847ce401SWu Fengguang return -EPERM; 22847ce401SWu Fengguang 23847ce401SWu Fengguang return unpoison_memory(val); 24847ce401SWu Fengguang } 25847ce401SWu Fengguang 26cae681fcSAndi Kleen DEFINE_SIMPLE_ATTRIBUTE(hwpoison_fops, NULL, hwpoison_inject, "%lli\n"); 27847ce401SWu Fengguang DEFINE_SIMPLE_ATTRIBUTE(unpoison_fops, NULL, hwpoison_unpoison, "%lli\n"); 28cae681fcSAndi Kleen 29cae681fcSAndi Kleen static void pfn_inject_exit(void) 30cae681fcSAndi Kleen { 31cae681fcSAndi Kleen if (hwpoison_dir) 32cae681fcSAndi Kleen debugfs_remove_recursive(hwpoison_dir); 33cae681fcSAndi Kleen } 34cae681fcSAndi Kleen 35cae681fcSAndi Kleen static int pfn_inject_init(void) 36cae681fcSAndi Kleen { 37847ce401SWu Fengguang struct dentry *dentry; 38847ce401SWu Fengguang 39cae681fcSAndi Kleen hwpoison_dir = debugfs_create_dir("hwpoison", NULL); 40cae681fcSAndi Kleen if (hwpoison_dir == NULL) 41cae681fcSAndi Kleen return -ENOMEM; 42847ce401SWu Fengguang 43847ce401SWu Fengguang /* 44847ce401SWu Fengguang * Note that the below poison/unpoison interfaces do not involve 45847ce401SWu Fengguang * hardware status change, hence do not require hardware support. 46847ce401SWu Fengguang * They are mainly for testing hwpoison in software level. 47847ce401SWu Fengguang */ 48847ce401SWu Fengguang dentry = debugfs_create_file("corrupt-pfn", 0600, hwpoison_dir, 49cae681fcSAndi Kleen NULL, &hwpoison_fops); 50847ce401SWu Fengguang if (!dentry) 51847ce401SWu Fengguang goto fail; 52847ce401SWu Fengguang 53847ce401SWu Fengguang dentry = debugfs_create_file("unpoison-pfn", 0600, hwpoison_dir, 54847ce401SWu Fengguang NULL, &unpoison_fops); 55847ce401SWu Fengguang if (!dentry) 56847ce401SWu Fengguang goto fail; 57847ce401SWu Fengguang 58*7c116f2bSWu Fengguang dentry = debugfs_create_u32("corrupt-filter-dev-major", 0600, 59*7c116f2bSWu Fengguang hwpoison_dir, &hwpoison_filter_dev_major); 60*7c116f2bSWu Fengguang if (!dentry) 61*7c116f2bSWu Fengguang goto fail; 62*7c116f2bSWu Fengguang 63*7c116f2bSWu Fengguang dentry = debugfs_create_u32("corrupt-filter-dev-minor", 0600, 64*7c116f2bSWu Fengguang hwpoison_dir, &hwpoison_filter_dev_minor); 65*7c116f2bSWu Fengguang if (!dentry) 66*7c116f2bSWu Fengguang goto fail; 67*7c116f2bSWu Fengguang 68847ce401SWu Fengguang return 0; 69847ce401SWu Fengguang fail: 70cae681fcSAndi Kleen pfn_inject_exit(); 71cae681fcSAndi Kleen return -ENOMEM; 72cae681fcSAndi Kleen } 73cae681fcSAndi Kleen 74cae681fcSAndi Kleen module_init(pfn_inject_init); 75cae681fcSAndi Kleen module_exit(pfn_inject_exit); 76cae681fcSAndi Kleen MODULE_LICENSE("GPL"); 77