linux/mm/debug-pagealloc.c
<<
>>
Prefs
   1#include <linux/kernel.h>
   2#include <linux/string.h>
   3#include <linux/mm.h>
   4#include <linux/highmem.h>
   5#include <linux/page_ext.h>
   6#include <linux/poison.h>
   7#include <linux/ratelimit.h>
   8
   9static bool page_poisoning_enabled __read_mostly;
  10
  11static bool need_page_poisoning(void)
  12{
  13        if (!debug_pagealloc_enabled())
  14                return false;
  15
  16        return true;
  17}
  18
  19static void init_page_poisoning(void)
  20{
  21        if (!debug_pagealloc_enabled())
  22                return;
  23
  24        page_poisoning_enabled = true;
  25}
  26
  27struct page_ext_operations page_poisoning_ops = {
  28        .need = need_page_poisoning,
  29        .init = init_page_poisoning,
  30};
  31
  32static inline void set_page_poison(struct page *page)
  33{
  34        struct page_ext *page_ext;
  35
  36        page_ext = lookup_page_ext(page);
  37        __set_bit(PAGE_EXT_DEBUG_POISON, &page_ext->flags);
  38}
  39
  40static inline void clear_page_poison(struct page *page)
  41{
  42        struct page_ext *page_ext;
  43
  44        page_ext = lookup_page_ext(page);
  45        __clear_bit(PAGE_EXT_DEBUG_POISON, &page_ext->flags);
  46}
  47
  48static inline bool page_poison(struct page *page)
  49{
  50        struct page_ext *page_ext;
  51
  52        page_ext = lookup_page_ext(page);
  53        return test_bit(PAGE_EXT_DEBUG_POISON, &page_ext->flags);
  54}
  55
  56static void poison_page(struct page *page)
  57{
  58        void *addr = kmap_atomic(page);
  59
  60        set_page_poison(page);
  61        memset(addr, PAGE_POISON, PAGE_SIZE);
  62        kunmap_atomic(addr);
  63}
  64
  65static void poison_pages(struct page *page, int n)
  66{
  67        int i;
  68
  69        for (i = 0; i < n; i++)
  70                poison_page(page + i);
  71}
  72
  73static bool single_bit_flip(unsigned char a, unsigned char b)
  74{
  75        unsigned char error = a ^ b;
  76
  77        return error && !(error & (error - 1));
  78}
  79
  80static void check_poison_mem(unsigned char *mem, size_t bytes)
  81{
  82        static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 10);
  83        unsigned char *start;
  84        unsigned char *end;
  85
  86        start = memchr_inv(mem, PAGE_POISON, bytes);
  87        if (!start)
  88                return;
  89
  90        for (end = mem + bytes - 1; end > start; end--) {
  91                if (*end != PAGE_POISON)
  92                        break;
  93        }
  94
  95        if (!__ratelimit(&ratelimit))
  96                return;
  97        else if (start == end && single_bit_flip(*start, PAGE_POISON))
  98                printk(KERN_ERR "pagealloc: single bit error\n");
  99        else
 100                printk(KERN_ERR "pagealloc: memory corruption\n");
 101
 102        print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 1, start,
 103                        end - start + 1, 1);
 104        dump_stack();
 105}
 106
 107static void unpoison_page(struct page *page)
 108{
 109        void *addr;
 110
 111        if (!page_poison(page))
 112                return;
 113
 114        addr = kmap_atomic(page);
 115        check_poison_mem(addr, PAGE_SIZE);
 116        clear_page_poison(page);
 117        kunmap_atomic(addr);
 118}
 119
 120static void unpoison_pages(struct page *page, int n)
 121{
 122        int i;
 123
 124        for (i = 0; i < n; i++)
 125                unpoison_page(page + i);
 126}
 127
 128void __kernel_map_pages(struct page *page, int numpages, int enable)
 129{
 130        if (!page_poisoning_enabled)
 131                return;
 132
 133        if (enable)
 134                unpoison_pages(page, numpages);
 135        else
 136                poison_pages(page, numpages);
 137}
 138