xref: /linux/mm/hwpoison-inject.c (revision 7c116f2b0dbac4a1dd051c7a5e8cef37701cafd4)
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