From 241dcdb6d5d20949b4289b0fb9459ed6587262b1 Mon Sep 17 00:00:00 2001 From: tao zeng Date: Thu, 26 Oct 2017 11:21:32 +0800 Subject: [PATCH] mm: fix vmemmap pages free bug by pagetrace PD#153090: mm: fix vmemmap pages free bug by pagetrace A page in vmemap will be freed when pagetrace is enabled. This caused page information wrong and may cause unexpected panic issue. Change-Id: I486c62af592a98c22bd1ab071b3a224c3298986d Signed-off-by: tao zeng --- drivers/amlogic/memory_ext/page_trace.c | 30 +++++++++++++++++-------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/amlogic/memory_ext/page_trace.c b/drivers/amlogic/memory_ext/page_trace.c index 4fa3e3cc3a54..0d411c62f088 100644 --- a/drivers/amlogic/memory_ext/page_trace.c +++ b/drivers/amlogic/memory_ext/page_trace.c @@ -167,8 +167,8 @@ static void push_ip(struct page_trace *base, struct page_trace *ip) /* debug check */ check_trace_valid(base); - end = ((unsigned long)trace_buffer + ptrace_size); - WARN_ON(((unsigned long)base) >= end); + end = (((unsigned long)trace_buffer) + ptrace_size); + WARN_ON((unsigned long)(base + trace_step - 1) >= end); base[0] = *ip; } @@ -482,10 +482,12 @@ void set_page_trace(struct page *page, int order, gfp_t gfp_flags) trace.migrate_type = gfpflags_to_migratetype(gfp_flags); trace.order = order; base = find_page_base(page); + #if DEBUG_PAGE_TRACE pr_debug("%s, base:%p, page:%lx, _ip:%x, o:%d, f:%x, ip:%lx\n", __func__, base, page_to_pfn(page), (*((unsigned int *)&trace)), order, gfp_flags, ip); + #endif push_ip(base, &trace); } } @@ -494,12 +496,20 @@ EXPORT_SYMBOL(set_page_trace); void reset_page_trace(struct page *page, int order) { struct page_trace *base; - int i; + int i, cnt; +#if DEBUG_PAGE_TRACE + unsigned long end; +#endif if (page && trace_buffer) { base = find_page_base(page); + cnt = 1 << order; + #if DEBUG_PAGE_TRACE check_trace_valid(base); - for (i = 0; i < (1 << order); i++) { + end = ((unsigned long)trace_buffer + ptrace_size); + WARN_ON((unsigned long)(base + cnt * trace_step - 1) >= end); + #endif + for (i = 0; i < cnt; i++) { base->order = IP_INVALID; base += (trace_step); } @@ -522,23 +532,25 @@ static void __init page_trace_pre_work(struct page *start_page, struct page *page, *last_page; size = PAGE_ALIGN(size); + size >>= PAGE_SHIFT; page = start_page; - last_page = page + (size >> PAGE_SHIFT); - for (i = 0; i < size >> PAGE_SHIFT;) { + last_page = page + size; + for (i = 0; i < size;) { order = page_private(page); pr_debug("page:%p, order:%d\n", page, order); list_del(&page->lru); /* del from buddy */; set_page_private(page, 0); - for (j = 0; j < (1 << order); j++) { - set_init_page_trace(page, 0, GFP_KERNEL); + for (j = 0; j < ((1 << order) - 1); j++) { + if (i < size) + set_init_page_trace(page, 0, GFP_KERNEL); page++; i++; } } /* free tailed pages */ - while (page > last_page) { + while (page >= last_page) { __free_pages(page, 0); page--; tailed++;