[RFC PATCH 5/8] mm, compaction: factor out checking if page can be isolated for migration

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The following patch will introduce pre-scanning in migration scanner, which
will check for pages that can be isolated, without actually isolating them. To
prepare for this, move the checking into a new function. No functional change.

Signed-off-by: Vlastimil Babka <vbabka@xxxxxxx>
---
 mm/compaction.c | 150 +++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 88 insertions(+), 62 deletions(-)

diff --git a/mm/compaction.c b/mm/compaction.c
index 4f93a7307fb5..1ef090aa96e6 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -669,6 +669,80 @@ static bool too_many_isolated(struct zone *zone)
 	return isolated > (inactive + active) / 2;
 }
 
+enum candidate_status {
+	CANDIDATE_FAIL,
+	CANDIDATE_FREE,
+	CANDIDATE_LRU,
+	CANDIDATE_OK = CANDIDATE_LRU,
+	CANDIDATE_MOVABLE
+};
+
+static enum candidate_status
+check_isolate_candidate(struct page *page, unsigned long *pfn,
+						struct compact_control *cc)
+{
+	/*
+	 * Skip free pages. We read page order here without zone lock which is
+	 * generally unsafe, but the race window is small and the worst thing
+	 * that can happen is that we skip some potential isolation targets.
+	 */
+	if (PageBuddy(page)) {
+		unsigned long freepage_order = page_order_unsafe(page);
+
+		/*
+		 * Without lock, we cannot be sure that what we got is a valid
+		 * page order. Consider only values in the valid order range to
+		 * prevent _pfn overflow.
+		 */
+		if (freepage_order > 0 && freepage_order < MAX_ORDER)
+			*pfn += (1UL << freepage_order) - 1;
+		return CANDIDATE_FREE;
+	}
+
+	/*
+	 * Regardless of being on LRU, compound pages such as THP and hugetlbfs
+	 * are not to be compacted. We can potentially save a lot of iterations
+	 * if we skip them at once. The check is racy, but we can consider only
+	 * valid values and the only danger is skipping too much.
+	 */
+	if (PageCompound(page)) {
+		const unsigned int order = compound_order(page);
+
+		if (likely(order < MAX_ORDER))
+			*pfn += (1UL << order) - 1;
+		return CANDIDATE_FAIL;
+	}
+
+	/*
+	 * Check may be lockless but that's ok as we recheck later.  It's
+	 * possible to migrate LRU and non-lru movable pages.  Skip any other
+	 * type of page
+	 */
+	if (!PageLRU(page)) {
+		if (unlikely(__PageMovable(page)) && !PageIsolated(page))
+			return CANDIDATE_MOVABLE;
+
+		return CANDIDATE_FAIL;
+	}
+
+	/*
+	 * Migration will fail if an anonymous page is pinned in memory, so
+	 * avoid taking lru_lock and isolating it unnecessarily in an admittedly
+	 * racy check.
+	 */
+	if (!page_mapping(page) && page_count(page) > page_mapcount(page))
+		return CANDIDATE_FAIL;
+
+	/*
+	 * Only allow to migrate anonymous pages in GFP_NOFS context because
+	 * those do not depend on fs locks.
+	 */
+	if (!(cc->gfp_mask & __GFP_FS) && page_mapping(page))
+		return CANDIDATE_FAIL;
+
+	return CANDIDATE_LRU;
+}
+
 /**
  * isolate_migratepages_block() - isolate all migrate-able pages within
  *				  a single pageblock
@@ -736,6 +810,8 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
 	/* Time to isolate some pages for migration */
 	for (; low_pfn < end_pfn; low_pfn++) {
 
+		enum candidate_status status;
+
 		if (skip_on_failure && low_pfn >= next_skip_pfn) {
 			/*
 			 * We have isolated all migration candidates in the
@@ -777,82 +853,32 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
 		if (!valid_page)
 			valid_page = page;
 
-		/*
-		 * Skip if free. We read page order here without zone lock
-		 * which is generally unsafe, but the race window is small and
-		 * the worst thing that can happen is that we skip some
-		 * potential isolation targets.
-		 */
-		if (PageBuddy(page)) {
-			unsigned long freepage_order = page_order_unsafe(page);
+		status = check_isolate_candidate(page, &low_pfn, cc);
 
-			/*
-			 * Without lock, we cannot be sure that what we got is
-			 * a valid page order. Consider only values in the
-			 * valid order range to prevent low_pfn overflow.
-			 */
-			if (freepage_order > 0 && freepage_order < MAX_ORDER)
-				low_pfn += (1UL << freepage_order) - 1;
+		if (status == CANDIDATE_FREE)
 			continue;
-		}
-
-		/*
-		 * Regardless of being on LRU, compound pages such as THP and
-		 * hugetlbfs are not to be compacted. We can potentially save
-		 * a lot of iterations if we skip them at once. The check is
-		 * racy, but we can consider only valid values and the only
-		 * danger is skipping too much.
-		 */
-		if (PageCompound(page)) {
-			const unsigned int order = compound_order(page);
-
-			if (likely(order < MAX_ORDER))
-				low_pfn += (1UL << order) - 1;
+		else if (status == CANDIDATE_FAIL)
 			goto isolate_fail;
-		}
 
-		/*
-		 * Check may be lockless but that's ok as we recheck later.
-		 * It's possible to migrate LRU and non-lru movable pages.
-		 * Skip any other type of page
-		 */
-		if (!PageLRU(page)) {
+		if (unlikely(status == CANDIDATE_MOVABLE)) {
 			/*
 			 * __PageMovable can return false positive so we need
 			 * to verify it under page_lock.
 			 */
-			if (unlikely(__PageMovable(page)) &&
-					!PageIsolated(page)) {
-				if (locked) {
-					spin_unlock_irqrestore(zone_lru_lock(zone),
-									flags);
-					locked = false;
-				}
-
-				if (!isolate_movable_page(page, isolate_mode))
-					goto isolate_success;
+			if (locked) {
+				spin_unlock_irqrestore(zone_lru_lock(zone),
+								flags);
+				locked = false;
 			}
 
-			goto isolate_fail;
+			if (!isolate_movable_page(page, isolate_mode))
+				goto isolate_success;
 		}
 
 		/*
-		 * Migration will fail if an anonymous page is pinned in memory,
-		 * so avoid taking lru_lock and isolating it unnecessarily in an
-		 * admittedly racy check.
+		 * The remaining case is CANDIDATE_LRU. If we already hold the
+		 * lock, we can skip some rechecking
 		 */
-		if (!page_mapping(page) &&
-		    page_count(page) > page_mapcount(page))
-			goto isolate_fail;
-
-		/*
-		 * Only allow to migrate anonymous pages in GFP_NOFS context
-		 * because those do not depend on fs locks.
-		 */
-		if (!(cc->gfp_mask & __GFP_FS) && page_mapping(page))
-			goto isolate_fail;
-
-		/* If we already hold the lock, we can skip some rechecking */
 		if (!locked) {
 			locked = compact_trylock_irqsave(zone_lru_lock(zone),
 								&flags, cc);
-- 
2.15.1

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@xxxxxxxxx.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@xxxxxxxxx";> email@xxxxxxxxx </a>



[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]
  Powered by Linux