mirror of
https://github.com/team-infusion-developers/android_kernel_samsung_msm8976.git
synced 2024-09-21 20:04:01 +00:00
f13a476269
Currently, we just print the pagealloc corruption warnings and proceed. Sometimes, we are getting multiple errors printed down the line. It will be good to get the device state as early as possible when we get the first pagealloc error. Change-Id: I79155ac8a039b30a3a98d5dd1384d3923082712f Signed-off-by: Subbaraman Narayanamurthy <subbaram@codeaurora.org>
103 lines
2.1 KiB
C
103 lines
2.1 KiB
C
#include <linux/kernel.h>
|
|
#include <linux/string.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/highmem.h>
|
|
#include <linux/page-debug-flags.h>
|
|
#include <linux/poison.h>
|
|
#include <linux/ratelimit.h>
|
|
|
|
static inline void set_page_poison(struct page *page)
|
|
{
|
|
__set_bit(PAGE_DEBUG_FLAG_POISON, &page->debug_flags);
|
|
}
|
|
|
|
static inline void clear_page_poison(struct page *page)
|
|
{
|
|
__clear_bit(PAGE_DEBUG_FLAG_POISON, &page->debug_flags);
|
|
}
|
|
|
|
static inline bool page_poison(struct page *page)
|
|
{
|
|
return test_bit(PAGE_DEBUG_FLAG_POISON, &page->debug_flags);
|
|
}
|
|
|
|
static void poison_page(struct page *page)
|
|
{
|
|
void *addr = kmap_atomic(page);
|
|
|
|
set_page_poison(page);
|
|
memset(addr, PAGE_POISON, PAGE_SIZE);
|
|
kunmap_atomic(addr);
|
|
}
|
|
|
|
static void poison_pages(struct page *page, int n)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < n; i++)
|
|
poison_page(page + i);
|
|
}
|
|
|
|
static bool single_bit_flip(unsigned char a, unsigned char b)
|
|
{
|
|
unsigned char error = a ^ b;
|
|
|
|
return error && !(error & (error - 1));
|
|
}
|
|
|
|
static void check_poison_mem(unsigned char *mem, size_t bytes)
|
|
{
|
|
static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 10);
|
|
unsigned char *start;
|
|
unsigned char *end;
|
|
|
|
start = memchr_inv(mem, PAGE_POISON, bytes);
|
|
if (!start)
|
|
return;
|
|
|
|
for (end = mem + bytes - 1; end > start; end--) {
|
|
if (*end != PAGE_POISON)
|
|
break;
|
|
}
|
|
|
|
if (!__ratelimit(&ratelimit))
|
|
return;
|
|
else if (start == end && single_bit_flip(*start, PAGE_POISON))
|
|
printk(KERN_ERR "pagealloc: single bit error\n");
|
|
else
|
|
printk(KERN_ERR "pagealloc: memory corruption\n");
|
|
|
|
print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 1, start,
|
|
end - start + 1, 1);
|
|
BUG_ON(PANIC_CORRUPTION);
|
|
dump_stack();
|
|
}
|
|
|
|
static void unpoison_page(struct page *page)
|
|
{
|
|
void *addr;
|
|
|
|
if (!page_poison(page))
|
|
return;
|
|
|
|
addr = kmap_atomic(page);
|
|
check_poison_mem(addr, PAGE_SIZE);
|
|
clear_page_poison(page);
|
|
kunmap_atomic(addr);
|
|
}
|
|
|
|
static void unpoison_pages(struct page *page, int n)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < n; i++)
|
|
unpoison_page(page + i);
|
|
}
|
|
|
|
void kernel_map_pages(struct page *page, int numpages, int enable)
|
|
{
|
|
if (enable)
|
|
unpoison_pages(page, numpages);
|
|
else
|
|
poison_pages(page, numpages);
|
|
}
|