Commit 8d22ba1b74aa9420b6032d856446564fb21f8090
Committed by
Andi Kleen
1 parent
95d01fc664
Exists in
master
and in
4 other branches
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
mm/internal.h
... | ... | @@ -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 | /* |
mm/memory-failure.c
... | ... | @@ -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 | /* |
mm/page_alloc.c
... | ... | @@ -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 |