|
@@ -295,7 +295,7 @@ static inline int bad_range(struct zone *zone, struct page *page)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
-static void bad_page(struct page *page)
|
|
|
+static void bad_page(struct page *page, char *reason, unsigned long bad_flags)
|
|
|
{
|
|
|
static unsigned long resume;
|
|
|
static unsigned long nr_shown;
|
|
@@ -329,7 +329,7 @@ static void bad_page(struct page *page)
|
|
|
|
|
|
printk(KERN_ALERT "BUG: Bad page state in process %s pfn:%05lx\n",
|
|
|
current->comm, page_to_pfn(page));
|
|
|
- dump_page(page);
|
|
|
+ dump_page_badflags(page, reason, bad_flags);
|
|
|
|
|
|
print_modules();
|
|
|
dump_stack();
|
|
@@ -383,7 +383,7 @@ static int destroy_compound_page(struct page *page, unsigned long order)
|
|
|
int bad = 0;
|
|
|
|
|
|
if (unlikely(compound_order(page) != order)) {
|
|
|
- bad_page(page);
|
|
|
+ bad_page(page, "wrong compound order", 0);
|
|
|
bad++;
|
|
|
}
|
|
|
|
|
@@ -392,8 +392,11 @@ static int destroy_compound_page(struct page *page, unsigned long order)
|
|
|
for (i = 1; i < nr_pages; i++) {
|
|
|
struct page *p = page + i;
|
|
|
|
|
|
- if (unlikely(!PageTail(p) || (p->first_page != page))) {
|
|
|
- bad_page(page);
|
|
|
+ if (unlikely(!PageTail(p))) {
|
|
|
+ bad_page(page, "PageTail not set", 0);
|
|
|
+ bad++;
|
|
|
+ } else if (unlikely(p->first_page != page)) {
|
|
|
+ bad_page(page, "first_page not consistent", 0);
|
|
|
bad++;
|
|
|
}
|
|
|
__ClearPageTail(p);
|
|
@@ -618,12 +621,23 @@ out:
|
|
|
|
|
|
static inline int free_pages_check(struct page *page)
|
|
|
{
|
|
|
- if (unlikely(page_mapcount(page) |
|
|
|
- (page->mapping != NULL) |
|
|
|
- (atomic_read(&page->_count) != 0) |
|
|
|
- (page->flags & PAGE_FLAGS_CHECK_AT_FREE) |
|
|
|
- (mem_cgroup_bad_page_check(page)))) {
|
|
|
- bad_page(page);
|
|
|
+ char *bad_reason = NULL;
|
|
|
+ unsigned long bad_flags = 0;
|
|
|
+
|
|
|
+ if (unlikely(page_mapcount(page)))
|
|
|
+ bad_reason = "nonzero mapcount";
|
|
|
+ if (unlikely(page->mapping != NULL))
|
|
|
+ bad_reason = "non-NULL mapping";
|
|
|
+ if (unlikely(atomic_read(&page->_count) != 0))
|
|
|
+ bad_reason = "nonzero _count";
|
|
|
+ if (unlikely(page->flags & PAGE_FLAGS_CHECK_AT_FREE)) {
|
|
|
+ bad_reason = "PAGE_FLAGS_CHECK_AT_FREE flag(s) set";
|
|
|
+ bad_flags = PAGE_FLAGS_CHECK_AT_FREE;
|
|
|
+ }
|
|
|
+ if (unlikely(mem_cgroup_bad_page_check(page)))
|
|
|
+ bad_reason = "cgroup check failed";
|
|
|
+ if (unlikely(bad_reason)) {
|
|
|
+ bad_page(page, bad_reason, bad_flags);
|
|
|
return 1;
|
|
|
}
|
|
|
page_cpupid_reset_last(page);
|
|
@@ -843,12 +857,23 @@ static inline void expand(struct zone *zone, struct page *page,
|
|
|
*/
|
|
|
static inline int check_new_page(struct page *page)
|
|
|
{
|
|
|
- if (unlikely(page_mapcount(page) |
|
|
|
- (page->mapping != NULL) |
|
|
|
- (atomic_read(&page->_count) != 0) |
|
|
|
- (page->flags & PAGE_FLAGS_CHECK_AT_PREP) |
|
|
|
- (mem_cgroup_bad_page_check(page)))) {
|
|
|
- bad_page(page);
|
|
|
+ char *bad_reason = NULL;
|
|
|
+ unsigned long bad_flags = 0;
|
|
|
+
|
|
|
+ if (unlikely(page_mapcount(page)))
|
|
|
+ bad_reason = "nonzero mapcount";
|
|
|
+ if (unlikely(page->mapping != NULL))
|
|
|
+ bad_reason = "non-NULL mapping";
|
|
|
+ if (unlikely(atomic_read(&page->_count) != 0))
|
|
|
+ bad_reason = "nonzero _count";
|
|
|
+ if (unlikely(page->flags & PAGE_FLAGS_CHECK_AT_PREP)) {
|
|
|
+ bad_reason = "PAGE_FLAGS_CHECK_AT_PREP flag set";
|
|
|
+ bad_flags = PAGE_FLAGS_CHECK_AT_PREP;
|
|
|
+ }
|
|
|
+ if (unlikely(mem_cgroup_bad_page_check(page)))
|
|
|
+ bad_reason = "cgroup check failed";
|
|
|
+ if (unlikely(bad_reason)) {
|
|
|
+ bad_page(page, bad_reason, bad_flags);
|
|
|
return 1;
|
|
|
}
|
|
|
return 0;
|
|
@@ -6494,12 +6519,23 @@ static void dump_page_flags(unsigned long flags)
|
|
|
printk(")\n");
|
|
|
}
|
|
|
|
|
|
-void dump_page(struct page *page)
|
|
|
+void dump_page_badflags(struct page *page, char *reason, unsigned long badflags)
|
|
|
{
|
|
|
printk(KERN_ALERT
|
|
|
"page:%p count:%d mapcount:%d mapping:%p index:%#lx\n",
|
|
|
page, atomic_read(&page->_count), page_mapcount(page),
|
|
|
page->mapping, page->index);
|
|
|
dump_page_flags(page->flags);
|
|
|
+ if (reason)
|
|
|
+ pr_alert("page dumped because: %s\n", reason);
|
|
|
+ if (page->flags & badflags) {
|
|
|
+ pr_alert("bad because of flags:\n");
|
|
|
+ dump_page_flags(page->flags & badflags);
|
|
|
+ }
|
|
|
mem_cgroup_print_bad_page(page);
|
|
|
}
|
|
|
+
|
|
|
+void dump_page(struct page *page, char *reason)
|
|
|
+{
|
|
|
+ dump_page_badflags(page, reason, 0);
|
|
|
+}
|