linux/mm/debug-pagealloc.c
<<
>>
Prefs
   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