Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  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}