1#include <linux/kernel.h> 2#include <linux/string.h> 3#include <linux/mm.h> 4#include <linux/highmem.h> 5#include <linux/page-debug-flags.h> 6#include <linux/poison.h> 7#include <linux/ratelimit.h> 8 9static inline void set_page_poison(struct page *page) 10{ 11 __set_bit(PAGE_DEBUG_FLAG_POISON, &page->debug_flags); 12} 13 14static inline void clear_page_poison(struct page *page) 15{ 16 __clear_bit(PAGE_DEBUG_FLAG_POISON, &page->debug_flags); 17} 18 19static inline bool page_poison(struct page *page) 20{ 21 return test_bit(PAGE_DEBUG_FLAG_POISON, &page->debug_flags); 22} 23 24static void poison_page(struct page *page) 25{ 26 void *addr = kmap_atomic(page); 27 28 set_page_poison(page); 29 memset(addr, PAGE_POISON, PAGE_SIZE); 30 kunmap_atomic(addr); 31} 32 33static void poison_pages(struct page *page, int n) 34{ 35 int i; 36 37 for (i = 0; i < n; i++) 38 poison_page(page + i); 39} 40 41static bool single_bit_flip(unsigned char a, unsigned char b) 42{ 43 unsigned char error = a ^ b; 44 45 return error && !(error & (error - 1)); 46} 47 48static void check_poison_mem(unsigned char *mem, size_t bytes) 49{ 50 static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 10); 51 unsigned char *start; 52 unsigned char *end; 53 54 start = memchr_inv(mem, PAGE_POISON, bytes); 55 if (!start) 56 return; 57 58 for (end = mem + bytes - 1; end > start; end--) { 59 if (*end != PAGE_POISON) 60 break; 61 } 62 63 if (!__ratelimit(&ratelimit)) 64 return; 65 else if (start == end && single_bit_flip(*start, PAGE_POISON)) 66 printk(KERN_ERR "pagealloc: single bit error\n"); 67 else 68 printk(KERN_ERR "pagealloc: memory corruption\n"); 69 70 print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 1, start, 71 end - start + 1, 1); 72 dump_stack(); 73} 74 75static void unpoison_page(struct page *page) 76{ 77 void *addr; 78 79 if (!page_poison(page)) 80 return; 81 82 addr = kmap_atomic(page); 83 check_poison_mem(addr, PAGE_SIZE); 84 clear_page_poison(page); 85 kunmap_atomic(addr); 86} 87 88static void unpoison_pages(struct page *page, int n) 89{ 90 int i; 91 92 for (i = 0; i < n; i++) 93 unpoison_page(page + i); 94} 95 96void kernel_map_pages(struct page *page, int numpages, int enable) 97{ 98 if (enable) 99 unpoison_pages(page, numpages); 100 else 101 poison_pages(page, numpages); 102} 103