Root/mm/debug-pagealloc.c

1#include <linux/kernel.h>
2#include <linux/mm.h>
3#include <linux/page-debug-flags.h>
4#include <linux/poison.h>
5
6static inline void set_page_poison(struct page *page)
7{
8    __set_bit(PAGE_DEBUG_FLAG_POISON, &page->debug_flags);
9}
10
11static inline void clear_page_poison(struct page *page)
12{
13    __clear_bit(PAGE_DEBUG_FLAG_POISON, &page->debug_flags);
14}
15
16static inline bool page_poison(struct page *page)
17{
18    return test_bit(PAGE_DEBUG_FLAG_POISON, &page->debug_flags);
19}
20
21static void poison_highpage(struct page *page)
22{
23    /*
24     * Page poisoning for highmem pages is not implemented.
25     *
26     * This can be called from interrupt contexts.
27     * So we need to create a new kmap_atomic slot for this
28     * application and it will need interrupt protection.
29     */
30}
31
32static void poison_page(struct page *page)
33{
34    void *addr;
35
36    if (PageHighMem(page)) {
37        poison_highpage(page);
38        return;
39    }
40    set_page_poison(page);
41    addr = page_address(page);
42    memset(addr, PAGE_POISON, PAGE_SIZE);
43}
44
45static void poison_pages(struct page *page, int n)
46{
47    int i;
48
49    for (i = 0; i < n; i++)
50        poison_page(page + i);
51}
52
53static bool single_bit_flip(unsigned char a, unsigned char b)
54{
55    unsigned char error = a ^ b;
56
57    return error && !(error & (error - 1));
58}
59
60static void check_poison_mem(unsigned char *mem, size_t bytes)
61{
62    unsigned char *start;
63    unsigned char *end;
64
65    for (start = mem; start < mem + bytes; start++) {
66        if (*start != PAGE_POISON)
67            break;
68    }
69    if (start == mem + bytes)
70        return;
71
72    for (end = mem + bytes - 1; end > start; end--) {
73        if (*end != PAGE_POISON)
74            break;
75    }
76
77    if (!printk_ratelimit())
78        return;
79    else if (start == end && single_bit_flip(*start, PAGE_POISON))
80        printk(KERN_ERR "pagealloc: single bit error\n");
81    else
82        printk(KERN_ERR "pagealloc: memory corruption\n");
83
84    print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 1, start,
85            end - start + 1, 1);
86    dump_stack();
87}
88
89static void unpoison_highpage(struct page *page)
90{
91    /*
92     * See comment in poison_highpage().
93     * Highmem pages should not be poisoned for now
94     */
95    BUG_ON(page_poison(page));
96}
97
98static void unpoison_page(struct page *page)
99{
100    if (PageHighMem(page)) {
101        unpoison_highpage(page);
102        return;
103    }
104    if (page_poison(page)) {
105        void *addr = page_address(page);
106
107        check_poison_mem(addr, PAGE_SIZE);
108        clear_page_poison(page);
109    }
110}
111
112static void unpoison_pages(struct page *page, int n)
113{
114    int i;
115
116    for (i = 0; i < n; i++)
117        unpoison_page(page + i);
118}
119
120void kernel_map_pages(struct page *page, int numpages, int enable)
121{
122    if (!debug_pagealloc_enabled)
123        return;
124
125    if (enable)
126        unpoison_pages(page, numpages);
127    else
128        poison_pages(page, numpages);
129}
130

Archive Download this file



interactive