mm: introduce dump_page() and print symbolic flag names

- introduce dump_page() to print the page info for debugging some error
  condition.

- convert three mm users: bad_page(), print_bad_pte() and memory offline
  failure.

- print an extra field: the symbolic names of page->flags

Example dump_page() output:

[  157.521694] page:ffffea0000a7cba8 count:2 mapcount:1 mapping:ffff88001c901791 index:0x147
[  157.525570] page flags: 0x100000000100068(uptodate|lru|active|swapbacked)

Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Alex Chiang <achiang@hp.com>
Cc: Rik van Riel <riel@redhat.com>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Mel Gorman <mel@linux.vnet.ibm.com>
Cc: Christoph Lameter <cl@linux-foundation.org>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Wu Fengguang 2010-03-10 15:20:43 -08:00 committed by Linus Torvalds
parent 9b3a6549b2
commit 718a38211b
4 changed files with 86 additions and 13 deletions

View File

@ -1465,5 +1465,7 @@ extern void shake_page(struct page *p, int access);
extern atomic_long_t mce_bad_pages; extern atomic_long_t mce_bad_pages;
extern int soft_offline_page(struct page *page, int flags); extern int soft_offline_page(struct page *page, int flags);
extern void dump_page(struct page *page);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _LINUX_MM_H */ #endif /* _LINUX_MM_H */

View File

@ -509,12 +509,8 @@ static void print_bad_pte(struct vm_area_struct *vma, unsigned long addr,
"BUG: Bad page map in process %s pte:%08llx pmd:%08llx\n", "BUG: Bad page map in process %s pte:%08llx pmd:%08llx\n",
current->comm, current->comm,
(long long)pte_val(pte), (long long)pmd_val(*pmd)); (long long)pte_val(pte), (long long)pmd_val(*pmd));
if (page) { if (page)
printk(KERN_ALERT dump_page(page);
"page:%p flags:%p count:%d mapcount:%d mapping:%p index:%lx\n",
page, (void *)page->flags, page_count(page),
page_mapcount(page), page->mapping, page->index);
}
printk(KERN_ALERT printk(KERN_ALERT
"addr:%p vm_flags:%08lx anon_vma:%p mapping:%p index:%lx\n", "addr:%p vm_flags:%08lx anon_vma:%p mapping:%p index:%lx\n",
(void *)addr, vma->vm_flags, vma->anon_vma, mapping, index); (void *)addr, vma->vm_flags, vma->anon_vma, mapping, index);

View File

@ -688,9 +688,9 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
if (page_count(page)) if (page_count(page))
not_managed++; not_managed++;
#ifdef CONFIG_DEBUG_VM #ifdef CONFIG_DEBUG_VM
printk(KERN_INFO "removing from LRU failed" printk(KERN_ALERT "removing pfn %lx from LRU failed\n",
" %lx/%d/%lx\n", pfn);
pfn, page_count(page), page->flags); dump_page(page);
#endif #endif
} }
} }

View File

@ -50,6 +50,7 @@
#include <linux/kmemleak.h> #include <linux/kmemleak.h>
#include <linux/memory.h> #include <linux/memory.h>
#include <trace/events/kmem.h> #include <trace/events/kmem.h>
#include <linux/ftrace_event.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/div64.h> #include <asm/div64.h>
@ -288,10 +289,7 @@ static void bad_page(struct page *page)
printk(KERN_ALERT "BUG: Bad page state in process %s pfn:%05lx\n", printk(KERN_ALERT "BUG: Bad page state in process %s pfn:%05lx\n",
current->comm, page_to_pfn(page)); current->comm, page_to_pfn(page));
printk(KERN_ALERT dump_page(page);
"page:%p flags:%p count:%d mapcount:%d mapping:%p index:%lx\n",
page, (void *)page->flags, page_count(page),
page_mapcount(page), page->mapping, page->index);
dump_stack(); dump_stack();
out: out:
@ -5183,3 +5181,80 @@ bool is_free_buddy_page(struct page *page)
return order < MAX_ORDER; return order < MAX_ORDER;
} }
#endif #endif
static struct trace_print_flags pageflag_names[] = {
{1UL << PG_locked, "locked" },
{1UL << PG_error, "error" },
{1UL << PG_referenced, "referenced" },
{1UL << PG_uptodate, "uptodate" },
{1UL << PG_dirty, "dirty" },
{1UL << PG_lru, "lru" },
{1UL << PG_active, "active" },
{1UL << PG_slab, "slab" },
{1UL << PG_owner_priv_1, "owner_priv_1" },
{1UL << PG_arch_1, "arch_1" },
{1UL << PG_reserved, "reserved" },
{1UL << PG_private, "private" },
{1UL << PG_private_2, "private_2" },
{1UL << PG_writeback, "writeback" },
#ifdef CONFIG_PAGEFLAGS_EXTENDED
{1UL << PG_head, "head" },
{1UL << PG_tail, "tail" },
#else
{1UL << PG_compound, "compound" },
#endif
{1UL << PG_swapcache, "swapcache" },
{1UL << PG_mappedtodisk, "mappedtodisk" },
{1UL << PG_reclaim, "reclaim" },
{1UL << PG_buddy, "buddy" },
{1UL << PG_swapbacked, "swapbacked" },
{1UL << PG_unevictable, "unevictable" },
#ifdef CONFIG_MMU
{1UL << PG_mlocked, "mlocked" },
#endif
#ifdef CONFIG_ARCH_USES_PG_UNCACHED
{1UL << PG_uncached, "uncached" },
#endif
#ifdef CONFIG_MEMORY_FAILURE
{1UL << PG_hwpoison, "hwpoison" },
#endif
{-1UL, NULL },
};
static void dump_page_flags(unsigned long flags)
{
const char *delim = "";
unsigned long mask;
int i;
printk(KERN_ALERT "page flags: %#lx(", flags);
/* remove zone id */
flags &= (1UL << NR_PAGEFLAGS) - 1;
for (i = 0; pageflag_names[i].name && flags; i++) {
mask = pageflag_names[i].mask;
if ((flags & mask) != mask)
continue;
flags &= ~mask;
printk("%s%s", delim, pageflag_names[i].name);
delim = "|";
}
/* check for left over flags */
if (flags)
printk("%s%#lx", delim, flags);
printk(")\n");
}
void dump_page(struct page *page)
{
printk(KERN_ALERT
"page:%p count:%d mapcount:%d mapping:%p index:%#lx\n",
page, page_count(page), page_mapcount(page),
page->mapping, page->index);
dump_page_flags(page->flags);
}