Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/mm/hwpoison-inject.c
26131 views
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 "internal.h"
11
12
static struct dentry *hwpoison_dir;
13
14
static int hwpoison_inject(void *data, u64 val)
15
{
16
unsigned long pfn = val;
17
struct page *p;
18
struct folio *folio;
19
int err;
20
21
if (!capable(CAP_SYS_ADMIN))
22
return -EPERM;
23
24
if (!pfn_valid(pfn))
25
return -ENXIO;
26
27
p = pfn_to_page(pfn);
28
folio = page_folio(p);
29
30
if (!hwpoison_filter_enable)
31
goto inject;
32
33
shake_folio(folio);
34
/*
35
* This implies unable to support non-LRU pages except free page.
36
*/
37
if (!folio_test_lru(folio) && !folio_test_hugetlb(folio) &&
38
!is_free_buddy_page(p))
39
return 0;
40
41
/*
42
* do a racy check to make sure PG_hwpoison will only be set for
43
* the targeted owner (or on a free page).
44
* memory_failure() will redo the check reliably inside page lock.
45
*/
46
err = hwpoison_filter(&folio->page);
47
if (err)
48
return 0;
49
50
inject:
51
pr_info("Injecting memory failure at pfn %#lx\n", pfn);
52
err = memory_failure(pfn, MF_SW_SIMULATED);
53
return (err == -EOPNOTSUPP) ? 0 : err;
54
}
55
56
static int hwpoison_unpoison(void *data, u64 val)
57
{
58
if (!capable(CAP_SYS_ADMIN))
59
return -EPERM;
60
61
return unpoison_memory(val);
62
}
63
64
DEFINE_DEBUGFS_ATTRIBUTE(hwpoison_fops, NULL, hwpoison_inject, "%lli\n");
65
DEFINE_DEBUGFS_ATTRIBUTE(unpoison_fops, NULL, hwpoison_unpoison, "%lli\n");
66
67
static void __exit pfn_inject_exit(void)
68
{
69
hwpoison_filter_enable = 0;
70
debugfs_remove_recursive(hwpoison_dir);
71
}
72
73
static int __init pfn_inject_init(void)
74
{
75
hwpoison_dir = debugfs_create_dir("hwpoison", NULL);
76
77
/*
78
* Note that the below poison/unpoison interfaces do not involve
79
* hardware status change, hence do not require hardware support.
80
* They are mainly for testing hwpoison in software level.
81
*/
82
debugfs_create_file("corrupt-pfn", 0200, hwpoison_dir, NULL,
83
&hwpoison_fops);
84
85
debugfs_create_file("unpoison-pfn", 0200, hwpoison_dir, NULL,
86
&unpoison_fops);
87
88
debugfs_create_u32("corrupt-filter-enable", 0600, hwpoison_dir,
89
&hwpoison_filter_enable);
90
91
debugfs_create_u32("corrupt-filter-dev-major", 0600, hwpoison_dir,
92
&hwpoison_filter_dev_major);
93
94
debugfs_create_u32("corrupt-filter-dev-minor", 0600, hwpoison_dir,
95
&hwpoison_filter_dev_minor);
96
97
debugfs_create_u64("corrupt-filter-flags-mask", 0600, hwpoison_dir,
98
&hwpoison_filter_flags_mask);
99
100
debugfs_create_u64("corrupt-filter-flags-value", 0600, hwpoison_dir,
101
&hwpoison_filter_flags_value);
102
103
#ifdef CONFIG_MEMCG
104
debugfs_create_u64("corrupt-filter-memcg", 0600, hwpoison_dir,
105
&hwpoison_filter_memcg);
106
#endif
107
108
return 0;
109
}
110
111
module_init(pfn_inject_init);
112
module_exit(pfn_inject_exit);
113
MODULE_DESCRIPTION("HWPoison pages injector");
114
MODULE_LICENSE("GPL");
115
116