Commit 8d22ba1b74aa9420b6032d856446564fb21f8090

Authored by Wu Fengguang
Committed by Andi Kleen
1 parent 95d01fc664

HWPOISON: detect free buddy pages explicitly

Most free pages in the buddy system have no PG_buddy set.
Introduce is_free_buddy_page() for detecting them reliably.

CC: Nick Piggin <npiggin@suse.de>
CC: Mel Gorman <mel@linux.vnet.ibm.com>
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>

Showing 3 changed files with 31 additions and 2 deletions Side-by-side Diff

... ... @@ -50,6 +50,9 @@
50 50 */
51 51 extern void __free_pages_bootmem(struct page *page, unsigned int order);
52 52 extern void prep_compound_page(struct page *page, unsigned long order);
  53 +#ifdef CONFIG_MEMORY_FAILURE
  54 +extern bool is_free_buddy_page(struct page *page);
  55 +#endif
53 56  
54 57  
55 58 /*
... ... @@ -807,8 +807,13 @@
807 807 */
808 808 if (!(flags & MF_COUNT_INCREASED) &&
809 809 !get_page_unless_zero(compound_head(p))) {
810   - action_result(pfn, "free or high order kernel", IGNORED);
811   - return PageBuddy(compound_head(p)) ? 0 : -EBUSY;
  810 + if (is_free_buddy_page(p)) {
  811 + action_result(pfn, "free buddy", DELAYED);
  812 + return 0;
  813 + } else {
  814 + action_result(pfn, "high order kernel", IGNORED);
  815 + return -EBUSY;
  816 + }
812 817 }
813 818  
814 819 /*
... ... @@ -5081,4 +5081,25 @@
5081 5081 spin_unlock_irqrestore(&zone->lock, flags);
5082 5082 }
5083 5083 #endif
  5084 +
  5085 +#ifdef CONFIG_MEMORY_FAILURE
  5086 +bool is_free_buddy_page(struct page *page)
  5087 +{
  5088 + struct zone *zone = page_zone(page);
  5089 + unsigned long pfn = page_to_pfn(page);
  5090 + unsigned long flags;
  5091 + int order;
  5092 +
  5093 + spin_lock_irqsave(&zone->lock, flags);
  5094 + for (order = 0; order < MAX_ORDER; order++) {
  5095 + struct page *page_head = page - (pfn & ((1 << order) - 1));
  5096 +
  5097 + if (PageBuddy(page_head) && page_order(page_head) >= order)
  5098 + break;
  5099 + }
  5100 + spin_unlock_irqrestore(&zone->lock, flags);
  5101 +
  5102 + return order < MAX_ORDER;
  5103 +}
  5104 +#endif