Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8d22ba1b authored by Wu Fengguang's avatar Wu Fengguang Committed by Andi Kleen
Browse files

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: default avatarWu Fengguang <fengguang.wu@intel.com>
Signed-off-by: default avatarAndi Kleen <ak@linux.intel.com>
parent 95d01fc6
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -50,6 +50,9 @@ extern void putback_lru_page(struct page *page);
 */
extern void __free_pages_bootmem(struct page *page, unsigned int order);
extern void prep_compound_page(struct page *page, unsigned long order);
#ifdef CONFIG_MEMORY_FAILURE
extern bool is_free_buddy_page(struct page *page);
#endif


/*
+7 −2
Original line number Diff line number Diff line
@@ -807,8 +807,13 @@ int __memory_failure(unsigned long pfn, int trapno, int flags)
	 */
	if (!(flags & MF_COUNT_INCREASED) &&
		!get_page_unless_zero(compound_head(p))) {
		action_result(pfn, "free or high order kernel", IGNORED);
		return PageBuddy(compound_head(p)) ? 0 : -EBUSY;
		if (is_free_buddy_page(p)) {
			action_result(pfn, "free buddy", DELAYED);
			return 0;
		} else {
			action_result(pfn, "high order kernel", IGNORED);
			return -EBUSY;
		}
	}

	/*
+21 −0
Original line number Diff line number Diff line
@@ -5081,3 +5081,24 @@ __offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn)
	spin_unlock_irqrestore(&zone->lock, flags);
}
#endif

#ifdef CONFIG_MEMORY_FAILURE
bool is_free_buddy_page(struct page *page)
{
	struct zone *zone = page_zone(page);
	unsigned long pfn = page_to_pfn(page);
	unsigned long flags;
	int order;

	spin_lock_irqsave(&zone->lock, flags);
	for (order = 0; order < MAX_ORDER; order++) {
		struct page *page_head = page - (pfn & ((1 << order) - 1));

		if (PageBuddy(page_head) && page_order(page_head) >= order)
			break;
	}
	spin_unlock_irqrestore(&zone->lock, flags);

	return order < MAX_ORDER;
}
#endif