Linux Audio

Check our new training course

Loading...
v3.1
  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}
v3.15
  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}