Root/mm/hwpoison-inject.c

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_page_unless_zero(hpage))
32        return 0;
33
34    if (!hwpoison_filter_enable)
35        goto inject;
36
37    if (!PageLRU(p) && !PageHuge(p))
38        shake_page(p, 0);
39    /*
40     * This implies unable to support non-LRU pages.
41     */
42    if (!PageLRU(p) && !PageHuge(p))
43        return 0;
44
45    /*
46     * do a racy check with elevated page count, to make sure PG_hwpoison
47     * will only be set for the targeted owner (or on a free page).
48     * We temporarily take page lock for try_get_mem_cgroup_from_page().
49     * memory_failure() will redo the check reliably inside page lock.
50     */
51    lock_page(hpage);
52    err = hwpoison_filter(hpage);
53    unlock_page(hpage);
54    if (err)
55        return 0;
56
57inject:
58    pr_info("Injecting memory failure at pfn %#lx\n", pfn);
59    return memory_failure(pfn, 18, MF_COUNT_INCREASED);
60}
61
62static int hwpoison_unpoison(void *data, u64 val)
63{
64    if (!capable(CAP_SYS_ADMIN))
65        return -EPERM;
66
67    return unpoison_memory(val);
68}
69
70DEFINE_SIMPLE_ATTRIBUTE(hwpoison_fops, NULL, hwpoison_inject, "%lli\n");
71DEFINE_SIMPLE_ATTRIBUTE(unpoison_fops, NULL, hwpoison_unpoison, "%lli\n");
72
73static void pfn_inject_exit(void)
74{
75    if (hwpoison_dir)
76        debugfs_remove_recursive(hwpoison_dir);
77}
78
79static int pfn_inject_init(void)
80{
81    struct dentry *dentry;
82
83    hwpoison_dir = debugfs_create_dir("hwpoison", NULL);
84    if (hwpoison_dir == NULL)
85        return -ENOMEM;
86
87    /*
88     * Note that the below poison/unpoison interfaces do not involve
89     * hardware status change, hence do not require hardware support.
90     * They are mainly for testing hwpoison in software level.
91     */
92    dentry = debugfs_create_file("corrupt-pfn", 0200, hwpoison_dir,
93                      NULL, &hwpoison_fops);
94    if (!dentry)
95        goto fail;
96
97    dentry = debugfs_create_file("unpoison-pfn", 0200, hwpoison_dir,
98                     NULL, &unpoison_fops);
99    if (!dentry)
100        goto fail;
101
102    dentry = debugfs_create_u32("corrupt-filter-enable", 0600,
103                    hwpoison_dir, &hwpoison_filter_enable);
104    if (!dentry)
105        goto fail;
106
107    dentry = debugfs_create_u32("corrupt-filter-dev-major", 0600,
108                    hwpoison_dir, &hwpoison_filter_dev_major);
109    if (!dentry)
110        goto fail;
111
112    dentry = debugfs_create_u32("corrupt-filter-dev-minor", 0600,
113                    hwpoison_dir, &hwpoison_filter_dev_minor);
114    if (!dentry)
115        goto fail;
116
117    dentry = debugfs_create_u64("corrupt-filter-flags-mask", 0600,
118                    hwpoison_dir, &hwpoison_filter_flags_mask);
119    if (!dentry)
120        goto fail;
121
122    dentry = debugfs_create_u64("corrupt-filter-flags-value", 0600,
123                    hwpoison_dir, &hwpoison_filter_flags_value);
124    if (!dentry)
125        goto fail;
126
127#ifdef CONFIG_MEMCG_SWAP
128    dentry = debugfs_create_u64("corrupt-filter-memcg", 0600,
129                    hwpoison_dir, &hwpoison_filter_memcg);
130    if (!dentry)
131        goto fail;
132#endif
133
134    return 0;
135fail:
136    pfn_inject_exit();
137    return -ENOMEM;
138}
139
140module_init(pfn_inject_init);
141module_exit(pfn_inject_exit);
142MODULE_LICENSE("GPL");
143

Archive Download this file



interactive