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 (!hwpoison_filter_enable)
24        goto inject;
25    if (!pfn_valid(pfn))
26        return -ENXIO;
27
28    p = pfn_to_page(pfn);
29    hpage = compound_head(p);
30    /*
31     * This implies unable to support free buddy pages.
32     */
33    if (!get_page_unless_zero(hpage))
34        return 0;
35
36    if (!PageLRU(p) && !PageHuge(p))
37        shake_page(p, 0);
38    /*
39     * This implies unable to support non-LRU pages.
40     */
41    if (!PageLRU(p) && !PageHuge(p))
42        return 0;
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     * We temporarily take page lock for try_get_mem_cgroup_from_page().
48     * memory_failure() will redo the check reliably inside page lock.
49     */
50    lock_page(hpage);
51    err = hwpoison_filter(hpage);
52    unlock_page(hpage);
53    if (err)
54        return 0;
55
56inject:
57    printk(KERN_INFO "Injecting memory failure at pfn %lx\n", pfn);
58    return memory_failure(pfn, 18, MF_COUNT_INCREASED);
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    if (hwpoison_dir)
75        debugfs_remove_recursive(hwpoison_dir);
76}
77
78static int pfn_inject_init(void)
79{
80    struct dentry *dentry;
81
82    hwpoison_dir = debugfs_create_dir("hwpoison", NULL);
83    if (hwpoison_dir == NULL)
84        return -ENOMEM;
85
86    /*
87     * Note that the below poison/unpoison interfaces do not involve
88     * hardware status change, hence do not require hardware support.
89     * They are mainly for testing hwpoison in software level.
90     */
91    dentry = debugfs_create_file("corrupt-pfn", 0600, hwpoison_dir,
92                      NULL, &hwpoison_fops);
93    if (!dentry)
94        goto fail;
95
96    dentry = debugfs_create_file("unpoison-pfn", 0600, hwpoison_dir,
97                     NULL, &unpoison_fops);
98    if (!dentry)
99        goto fail;
100
101    dentry = debugfs_create_u32("corrupt-filter-enable", 0600,
102                    hwpoison_dir, &hwpoison_filter_enable);
103    if (!dentry)
104        goto fail;
105
106    dentry = debugfs_create_u32("corrupt-filter-dev-major", 0600,
107                    hwpoison_dir, &hwpoison_filter_dev_major);
108    if (!dentry)
109        goto fail;
110
111    dentry = debugfs_create_u32("corrupt-filter-dev-minor", 0600,
112                    hwpoison_dir, &hwpoison_filter_dev_minor);
113    if (!dentry)
114        goto fail;
115
116    dentry = debugfs_create_u64("corrupt-filter-flags-mask", 0600,
117                    hwpoison_dir, &hwpoison_filter_flags_mask);
118    if (!dentry)
119        goto fail;
120
121    dentry = debugfs_create_u64("corrupt-filter-flags-value", 0600,
122                    hwpoison_dir, &hwpoison_filter_flags_value);
123    if (!dentry)
124        goto fail;
125
126#ifdef CONFIG_MEMCG_SWAP
127    dentry = debugfs_create_u64("corrupt-filter-memcg", 0600,
128                    hwpoison_dir, &hwpoison_filter_memcg);
129    if (!dentry)
130        goto fail;
131#endif
132
133    return 0;
134fail:
135    pfn_inject_exit();
136    return -ENOMEM;
137}
138
139module_init(pfn_inject_init);
140module_exit(pfn_inject_exit);
141MODULE_LICENSE("GPL");
142

Archive Download this file



interactive