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