/* * Test all pages in the range is free(means isolated) or not. * all pages in [start_pfn...end_pfn) must be in the same zone. * zone->lock must be held before call this. * * Returns the last tested pfn. */ static unsigned long __test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn, bool skip_hwpoisoned_pages) { struct page *page; while (pfn < end_pfn) { if (!pfn_valid_within(pfn)) { pfn++; continue; } page = pfn_to_page(pfn); if (PageBuddy(page)) /* * If the page is on a free list, it has to be on * the correct MIGRATE_ISOLATE freelist. There is no * simple way to verify that as VM_BUG_ON(), though. */ pfn += 1 << page_order(page); else if (skip_hwpoisoned_pages && PageHWPoison(page)) /* A HWPoisoned page cannot be also PageBuddy */ pfn++; else break; } return pfn; }
__test_page_isolated_in_pageblock(struct zone *zone, unsigned long pfn, unsigned long end_pfn, bool skip_hwpoisoned_pages) #endif { struct page *page; while (pfn < end_pfn) { if (!pfn_valid_within(pfn)) { pfn++; continue; } page = pfn_to_page(pfn); #if defined(CONFIG_CMA) && defined(CONFIG_MTK_SVP) // SVP 07 if (page_zone(page) != zone) break; #endif if (PageBuddy(page)) { /* * If race between isolatation and allocation happens, * some free pages could be in MIGRATE_MOVABLE list * although pageblock's migratation type of the page * is MIGRATE_ISOLATE. Catch it and move the page into * MIGRATE_ISOLATE list. */ if (get_freepage_migratetype(page) != MIGRATE_ISOLATE) { struct page *end_page; end_page = page + (1 << page_order(page)) - 1; move_freepages(page_zone(page), page, end_page, MIGRATE_ISOLATE); } pfn += 1 << page_order(page); } else if (page_count(page) == 0 && get_freepage_migratetype(page) == MIGRATE_ISOLATE) pfn += 1; else if (skip_hwpoisoned_pages && PageHWPoison(page)) { /* * The HWPoisoned page may be not in buddy * system, and page_count() is not 0. */ pfn++; continue; } else break; } if (pfn < end_pfn) return 0; return 1; }
static void bad_page(struct page *page) { static unsigned long resume; static unsigned long nr_shown; static unsigned long nr_unshown; /* Don't complain about poisoned pages */ if (PageHWPoison(page)) { __ClearPageBuddy(page); return; } /* * Allow a burst of 60 reports, then keep quiet for that minute; * or allow a steady drip of one report per second. */ if (nr_shown == 60) { if (time_before(jiffies, resume)) { nr_unshown++; goto out; } if (nr_unshown) { printk(KERN_ALERT "BUG: Bad page state: %lu messages suppressed\n", nr_unshown); nr_unshown = 0; } nr_shown = 0; } if (nr_shown++ == 0) resume = jiffies + 60 * HZ; printk(KERN_ALERT "BUG: Bad page state in process pfn:%05lx\n", page_to_pfn(page)); // dump_page(page); dump_stack(); out: /* Leave bad fields for debug, except PageBuddy could make trouble */ __ClearPageBuddy(page); add_taint(TAINT_BAD_PAGE); }