All of lore.kernel.org
 help / color / mirror / Atom feed
diff for duplicates of <4FD02A66.6030705@kernel.org>

diff --git a/a/2.txt b/N1/2.txt
index 8b13789..7766224 100644
--- a/a/2.txt
+++ b/N1/2.txt
@@ -1 +1,437 @@
+>From ad4f07fe0da971fe8ef841aa4a2a5bc107fa8548 Mon Sep 17 00:00:00 2001
+From: Minchan Kim <minchan@kernel.org>
+Date: Thu, 7 Jun 2012 13:12:14 +0900
+Subject: [PATCH] 1
 
+Signed-off-by: Minchan Kim <minchan@kernel.org>
+---
+ include/linux/compaction.h |   19 +++++
+ mm/compaction.c            |  170 ++++++++++++++++++++++++++++++++++++++------
+ mm/internal.h              |    9 ++-
+ mm/page_alloc.c            |    8 +--
+ 4 files changed, 178 insertions(+), 28 deletions(-)
+
+diff --git a/include/linux/compaction.h b/include/linux/compaction.h
+index 51a90b7..e988037 100644
+--- a/include/linux/compaction.h
++++ b/include/linux/compaction.h
+@@ -1,6 +1,8 @@
+ #ifndef _LINUX_COMPACTION_H
+ #define _LINUX_COMPACTION_H
+ 
++#include <linux/node.h>
++
+ /* Return values for compact_zone() and try_to_compact_pages() */
+ /* compaction didn't start as it was not possible or direct reclaim was more suitable */
+ #define COMPACT_SKIPPED		0
+@@ -11,6 +13,23 @@
+ /* The full zone was compacted */
+ #define COMPACT_COMPLETE	3
+ 
++/*
++ * compaction supports three modes
++ *
++ * COMPACT_ASYNC_MOVABLE uses asynchronous migration and only scans
++ *    MIGRATE_MOVABLE pageblocks as migration sources and targets.
++ * COMPACT_ASYNC_UNMOVABLE uses asynchronous migration and only scans
++ *    MIGRATE_MOVABLE pageblocks as migration sources.
++ *    MIGRATE_UNMOVABLE pageblocks are scanned as potential migration
++ *    targets and convers them to MIGRATE_MOVABLE if possible
++ * COMPACT_SYNC uses synchronous migration and scans all pageblocks
++ */
++enum compact_mode {
++	COMPACT_ASYNC_MOVABLE,
++	COMPACT_ASYNC_UNMOVABLE,
++	COMPACT_SYNC,
++};
++
+ #ifdef CONFIG_COMPACTION
+ extern int sysctl_compact_memory;
+ extern int sysctl_compaction_handler(struct ctl_table *table, int write,
+diff --git a/mm/compaction.c b/mm/compaction.c
+index 7ea259d..a5c9141 100644
+--- a/mm/compaction.c
++++ b/mm/compaction.c
+@@ -236,7 +236,7 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
+ 	 */
+ 	while (unlikely(too_many_isolated(zone))) {
+ 		/* async migration should just abort */
+-		if (!cc->sync)
++		if (cc->mode != COMPACT_SYNC)
+ 			return 0;
+ 
+ 		congestion_wait(BLK_RW_ASYNC, HZ/10);
+@@ -304,7 +304,8 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
+ 		 * satisfies the allocation
+ 		 */
+ 		pageblock_nr = low_pfn >> pageblock_order;
+-		if (!cc->sync && last_pageblock_nr != pageblock_nr &&
++		if (cc->mode != COMPACT_SYNC &&
++		    last_pageblock_nr != pageblock_nr &&
+ 		    !migrate_async_suitable(get_pageblock_migratetype(page))) {
+ 			low_pfn += pageblock_nr_pages;
+ 			low_pfn = ALIGN(low_pfn, pageblock_nr_pages) - 1;
+@@ -325,7 +326,7 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
+ 			continue;
+ 		}
+ 
+-		if (!cc->sync)
++		if (cc->mode != COMPACT_SYNC)
+ 			mode |= ISOLATE_ASYNC_MIGRATE;
+ 
+ 		lruvec = mem_cgroup_page_lruvec(page, zone);
+@@ -360,27 +361,116 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
+ 
+ #endif /* CONFIG_COMPACTION || CONFIG_CMA */
+ #ifdef CONFIG_COMPACTION
++/*
++ * Returns true if MIGRATE_UNMOVABLE pageblock can be successfully
++ * converted to MIGRATE_MOVABLE type, false otherwise.
++ */
++static bool can_rescue_unmovable_pageblock(struct page *page)
++{
++	struct zone *zone;
++	unsigned long pfn, start_pfn, end_pfn;
++	struct page *start_page, *end_page, *cursor_page;
++
++	zone = page_zone(page);
++	pfn = page_to_pfn(page);
++	start_pfn = pfn & ~(pageblock_nr_pages - 1);
++	end_pfn = start_pfn + pageblock_nr_pages - 1;
++
++	start_page = pfn_to_page(start_pfn);
++	end_page = pfn_to_page(end_pfn);
++
++	for (cursor_page = start_page, pfn = start_pfn; cursor_page <= end_page;
++		pfn++, cursor_page++) {
++
++		if (!pfn_valid_within(pfn))
++			continue;
++
++		/* Do not deal with pageblocks that overlap zones */
++		if (page_zone(cursor_page) != zone)
++			return false;
++
++		/*
++		 * Race with page allocator/reclaimer can happen so that
++		 * it can deceive unmovable block to migratable type
++		 * on this pageblock. It could regress on anti-fragmentation
++		 * but it's rare and not critical.
++		 */
++		if (PageBuddy(cursor_page)) {
++			unsigned long order = page_order(cursor_page);
++
++			pfn += (1 << order) - 1;
++			cursor_page += (1 << order) - 1;
++			continue;
++		} else if (PageLRU(cursor_page)) {
++			continue;
++		/*
++		 * We can't use page_count which does compound_head
++		 * as we don't have a pin a page.
++		 */
++		} else if (!atomic_read(&cursor_page->_count)) {
++			continue;
++		}
++
++		return false;
++	}
++
++	return true;
++}
++
++static void rescue_unmovable_pageblock(struct page *page)
++{
++	set_pageblock_migratetype(page, MIGRATE_MOVABLE);
++	move_freepages_block(page_zone(page), page, MIGRATE_MOVABLE);
++}
++
++/*
++ * MIGRATE_TARGET : good for migration target
++ * RESCUE_UNMOVABLE_TARTET : good only if we can rescue the unmovable pageblock.
++ * UNMOVABLE_TARGET : can't migrate because it's a page in unmovable pageblock.
++ * SKIP_TARGET : can't migrate by another reasons.
++ */
++enum smt_result {
++	MIGRATE_TARGET,
++	RESCUE_UNMOVABLE_TARGET,
++	UNMOVABLE_TARGET,
++	SKIP_TARGET,
++};
+ 
+-/* Returns true if the page is within a block suitable for migration to */
+-static bool suitable_migration_target(struct page *page)
++/*
++ * Returns MIGRATE_TARGET if the page is within a block
++ * suitable for migration to, UNMOVABLE_TARGET if the page
++ * is within a MIGRATE_UNMOVABLE block, SKIP_TARGET otherwise.
++ */
++static enum smt_result suitable_migration_target(struct page *page,
++			      struct compact_control *cc)
+ {
+ 
+ 	int migratetype = get_pageblock_migratetype(page);
+ 
+ 	/* Don't interfere with memory hot-remove or the min_free_kbytes blocks */
+ 	if (migratetype == MIGRATE_ISOLATE || migratetype == MIGRATE_RESERVE)
+-		return false;
++		return SKIP_TARGET;
+ 
+ 	/* If the page is a large free page, then allow migration */
+ 	if (PageBuddy(page) && page_order(page) >= pageblock_order)
+-		return true;
++		return MIGRATE_TARGET;
+ 
+ 	/* If the block is MIGRATE_MOVABLE or MIGRATE_CMA, allow migration */
+-	if (migrate_async_suitable(migratetype))
+-		return true;
++	if (cc->mode != COMPACT_ASYNC_UNMOVABLE &&
++	    migrate_async_suitable(migratetype))
++		return MIGRATE_TARGET;
++
++	if (cc->mode == COMPACT_ASYNC_MOVABLE &&
++	    migratetype == MIGRATE_UNMOVABLE)
++		return UNMOVABLE_TARGET;
++
++	if (cc->mode != COMPACT_ASYNC_MOVABLE &&
++	    migratetype == MIGRATE_UNMOVABLE &&
++	    can_rescue_unmovable_pageblock(page))
++		return RESCUE_UNMOVABLE_TARGET;
+ 
+ 	/* Otherwise skip the block */
+-	return false;
++	return SKIP_TARGET;
+ }
+ 
+ /*
+@@ -414,6 +504,13 @@ static void isolate_freepages(struct zone *zone,
+ 	zone_end_pfn = zone->zone_start_pfn + zone->spanned_pages;
+ 
+ 	/*
++	 * isolate_freepages() may be called more than once during
++	 * compact_zone_order() run and we want only the most recent
++	 * count.
++	 */
++	cc->nr_unmovable_pageblock = 0;
++
++	/*
+ 	 * Isolate free pages until enough are available to migrate the
+ 	 * pages on cc->migratepages. We stop searching if the migrate
+ 	 * and free page scanners meet or enough free pages are isolated.
+@@ -421,6 +518,7 @@ static void isolate_freepages(struct zone *zone,
+ 	for (; pfn > low_pfn && cc->nr_migratepages > nr_freepages;
+ 					pfn -= pageblock_nr_pages) {
+ 		unsigned long isolated;
++		enum smt_result ret;
+ 
+ 		if (!pfn_valid(pfn))
+ 			continue;
+@@ -437,9 +535,12 @@ static void isolate_freepages(struct zone *zone,
+ 			continue;
+ 
+ 		/* Check the block is suitable for migration */
+-		if (!suitable_migration_target(page))
++		ret = suitable_migration_target(page, cc);
++		if (ret != MIGRATE_TARGET && ret != RESCUE_UNMOVABLE_TARGET) {
++			if (ret == UNMOVABLE_TARGET)
++				cc->nr_unmovable_pageblock++;
+ 			continue;
+-
++		}
+ 		/*
+ 		 * Found a block suitable for isolating free pages from. Now
+ 		 * we disabled interrupts, double check things are ok and
+@@ -448,12 +549,16 @@ static void isolate_freepages(struct zone *zone,
+ 		 */
+ 		isolated = 0;
+ 		spin_lock_irqsave(&zone->lock, flags);
+-		if (suitable_migration_target(page)) {
++		ret = suitable_migration_target(page, cc);
++		if (ret == MIGRATE_TARGET || ret == RESCUE_UNMOVABLE_TARGET) {
++			if (ret == RESCUE_UNMOVABLE_TARGET)
++				rescue_unmovable_pageblock(page);
+ 			end_pfn = min(pfn + pageblock_nr_pages, zone_end_pfn);
+ 			isolated = isolate_freepages_block(pfn, end_pfn,
+ 							   freelist, false);
+ 			nr_freepages += isolated;
+-		}
++		} else if (ret == UNMOVABLE_TARGET)
++			cc->nr_unmovable_pageblock++;
+ 		spin_unlock_irqrestore(&zone->lock, flags);
+ 
+ 		/*
+@@ -685,8 +790,9 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
+ 
+ 		nr_migrate = cc->nr_migratepages;
+ 		err = migrate_pages(&cc->migratepages, compaction_alloc,
+-				(unsigned long)cc, false,
+-				cc->sync ? MIGRATE_SYNC_LIGHT : MIGRATE_ASYNC);
++			(unsigned long)&cc->freepages, false,
++			(cc->mode == COMPACT_SYNC) ? MIGRATE_SYNC_LIGHT
++						      : MIGRATE_ASYNC);
+ 		update_nr_listpages(cc);
+ 		nr_remaining = cc->nr_migratepages;
+ 
+@@ -715,7 +821,8 @@ out:
+ 
+ static unsigned long compact_zone_order(struct zone *zone,
+ 				 int order, gfp_t gfp_mask,
+-				 bool sync)
++				 enum compact_mode mode,
++				 unsigned long *nr_pageblocks_skipped)
+ {
+ 	struct compact_control cc = {
+ 		.nr_freepages = 0,
+@@ -723,12 +830,17 @@ static unsigned long compact_zone_order(struct zone *zone,
+ 		.order = order,
+ 		.migratetype = allocflags_to_migratetype(gfp_mask),
+ 		.zone = zone,
+-		.sync = sync,
++		.mode = mode,
+ 	};
++	unsigned long rc;
++
+ 	INIT_LIST_HEAD(&cc.freepages);
+ 	INIT_LIST_HEAD(&cc.migratepages);
+ 
+-	return compact_zone(zone, &cc);
++	rc = compact_zone(zone, &cc);
++	*nr_pageblocks_skipped = cc.nr_unmovable_pageblock;
++
++	return rc;
+ }
+ 
+ int sysctl_extfrag_threshold = 500;
+@@ -753,6 +865,8 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist,
+ 	struct zoneref *z;
+ 	struct zone *zone;
+ 	int rc = COMPACT_SKIPPED;
++	unsigned long nr_pageblocks_skipped;
++	enum compact_mode mode;
+ 
+ 	/*
+ 	 * Check whether it is worth even starting compaction. The order check is
+@@ -769,12 +883,22 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist,
+ 								nodemask) {
+ 		int status;
+ 
+-		status = compact_zone_order(zone, order, gfp_mask, sync);
++		mode = sync ? COMPACT_SYNC : COMPACT_ASYNC_MOVABLE;
++retry:
++		status = compact_zone_order(zone, order, gfp_mask, mode,
++						&nr_pageblocks_skipped);
+ 		rc = max(status, rc);
+ 
+ 		/* If a normal allocation would succeed, stop compacting */
+ 		if (zone_watermark_ok(zone, order, low_wmark_pages(zone), 0, 0))
+ 			break;
++
++		if (rc == COMPACT_COMPLETE && mode == COMPACT_ASYNC_MOVABLE) {
++			if (nr_pageblocks_skipped) {
++				mode = COMPACT_ASYNC_UNMOVABLE;
++				goto retry;
++			}
++		}
+ 	}
+ 
+ 	return rc;
+@@ -808,7 +932,7 @@ static int __compact_pgdat(pg_data_t *pgdat, struct compact_control *cc)
+ 			if (ok && cc->order > zone->compact_order_failed)
+ 				zone->compact_order_failed = cc->order + 1;
+ 			/* Currently async compaction is never deferred. */
+-			else if (!ok && cc->sync)
++			else if (!ok && cc->mode == COMPACT_SYNC)
+ 				defer_compaction(zone, cc->order);
+ 		}
+ 
+@@ -823,7 +947,7 @@ int compact_pgdat(pg_data_t *pgdat, int order)
+ {
+ 	struct compact_control cc = {
+ 		.order = order,
+-		.sync = false,
++		.mode = COMPACT_ASYNC_MOVABLE,
+ 	};
+ 
+ 	return __compact_pgdat(pgdat, &cc);
+@@ -833,7 +957,7 @@ static int compact_node(int nid)
+ {
+ 	struct compact_control cc = {
+ 		.order = -1,
+-		.sync = true,
++		.mode = COMPACT_SYNC,
+ 	};
+ 
+ 	return __compact_pgdat(NODE_DATA(nid), &cc);
+diff --git a/mm/internal.h b/mm/internal.h
+index 2ba87fb..061fde7 100644
+--- a/mm/internal.h
++++ b/mm/internal.h
+@@ -94,6 +94,9 @@ extern void putback_lru_page(struct page *page);
+ /*
+  * in mm/page_alloc.c
+  */
++extern void set_pageblock_migratetype(struct page *page, int migratetype);
++extern int move_freepages_block(struct zone *zone, struct page *page,
++				int migratetype);
+ 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
+@@ -101,6 +104,7 @@ extern bool is_free_buddy_page(struct page *page);
+ #endif
+ 
+ #if defined CONFIG_COMPACTION || defined CONFIG_CMA
++#include <linux/compaction.h>
+ 
+ /*
+  * in mm/compaction.c
+@@ -119,11 +123,14 @@ struct compact_control {
+ 	unsigned long nr_migratepages;	/* Number of pages to migrate */
+ 	unsigned long free_pfn;		/* isolate_freepages search base */
+ 	unsigned long migrate_pfn;	/* isolate_migratepages search base */
+-	bool sync;			/* Synchronous migration */
++	enum compact_mode mode;		/* Compaction mode */
+ 
+ 	int order;			/* order a direct compactor needs */
+ 	int migratetype;		/* MOVABLE, RECLAIMABLE etc */
+ 	struct zone *zone;
++
++	/* Number of UNMOVABLE destination pageblocks skipped during scan */
++	unsigned long nr_unmovable_pageblock;
+ };
+ 
+ unsigned long
+diff --git a/mm/page_alloc.c b/mm/page_alloc.c
+index 476ae3e..d40e4c7 100644
+--- a/mm/page_alloc.c
++++ b/mm/page_alloc.c
+@@ -219,7 +219,7 @@ EXPORT_SYMBOL(nr_online_nodes);
+ 
+ int page_group_by_mobility_disabled __read_mostly;
+ 
+-static void set_pageblock_migratetype(struct page *page, int migratetype)
++void set_pageblock_migratetype(struct page *page, int migratetype)
+ {
+ 
+ 	if (unlikely(page_group_by_mobility_disabled))
+@@ -954,8 +954,8 @@ static int move_freepages(struct zone *zone,
+ 	return pages_moved;
+ }
+ 
+-static int move_freepages_block(struct zone *zone, struct page *page,
+-				int migratetype)
++int move_freepages_block(struct zone *zone, struct page *page,
++			 int migratetype)
+ {
+ 	unsigned long start_pfn, end_pfn;
+ 	struct page *start_page, *end_page;
+@@ -5651,7 +5651,7 @@ static int __alloc_contig_migrate_range(unsigned long start, unsigned long end)
+ 		.nr_migratepages = 0,
+ 		.order = -1,
+ 		.zone = page_zone(pfn_to_page(start)),
+-		.sync = true,
++		.mode = COMPACT_SYNC,
+ 	};
+ 	INIT_LIST_HEAD(&cc.migratepages);
+ 
+-- 
+1.7.9.5
diff --git a/a/content_digest b/N1/content_digest
index bdaade1..f6a317f 100644
--- a/a/content_digest
+++ b/N1/content_digest
@@ -215,5 +215,442 @@
  "\01:2\0"
  "fn\00001-1.patch\0"
  "b\0"
+ ">From ad4f07fe0da971fe8ef841aa4a2a5bc107fa8548 Mon Sep 17 00:00:00 2001\n"
+ "From: Minchan Kim <minchan@kernel.org>\n"
+ "Date: Thu, 7 Jun 2012 13:12:14 +0900\n"
+ "Subject: [PATCH] 1\n"
+ "\n"
+ "Signed-off-by: Minchan Kim <minchan@kernel.org>\n"
+ "---\n"
+ " include/linux/compaction.h |   19 +++++\n"
+ " mm/compaction.c            |  170 ++++++++++++++++++++++++++++++++++++++------\n"
+ " mm/internal.h              |    9 ++-\n"
+ " mm/page_alloc.c            |    8 +--\n"
+ " 4 files changed, 178 insertions(+), 28 deletions(-)\n"
+ "\n"
+ "diff --git a/include/linux/compaction.h b/include/linux/compaction.h\n"
+ "index 51a90b7..e988037 100644\n"
+ "--- a/include/linux/compaction.h\n"
+ "+++ b/include/linux/compaction.h\n"
+ "@@ -1,6 +1,8 @@\n"
+ " #ifndef _LINUX_COMPACTION_H\n"
+ " #define _LINUX_COMPACTION_H\n"
+ " \n"
+ "+#include <linux/node.h>\n"
+ "+\n"
+ " /* Return values for compact_zone() and try_to_compact_pages() */\n"
+ " /* compaction didn't start as it was not possible or direct reclaim was more suitable */\n"
+ " #define COMPACT_SKIPPED\t\t0\n"
+ "@@ -11,6 +13,23 @@\n"
+ " /* The full zone was compacted */\n"
+ " #define COMPACT_COMPLETE\t3\n"
+ " \n"
+ "+/*\n"
+ "+ * compaction supports three modes\n"
+ "+ *\n"
+ "+ * COMPACT_ASYNC_MOVABLE uses asynchronous migration and only scans\n"
+ "+ *    MIGRATE_MOVABLE pageblocks as migration sources and targets.\n"
+ "+ * COMPACT_ASYNC_UNMOVABLE uses asynchronous migration and only scans\n"
+ "+ *    MIGRATE_MOVABLE pageblocks as migration sources.\n"
+ "+ *    MIGRATE_UNMOVABLE pageblocks are scanned as potential migration\n"
+ "+ *    targets and convers them to MIGRATE_MOVABLE if possible\n"
+ "+ * COMPACT_SYNC uses synchronous migration and scans all pageblocks\n"
+ "+ */\n"
+ "+enum compact_mode {\n"
+ "+\tCOMPACT_ASYNC_MOVABLE,\n"
+ "+\tCOMPACT_ASYNC_UNMOVABLE,\n"
+ "+\tCOMPACT_SYNC,\n"
+ "+};\n"
+ "+\n"
+ " #ifdef CONFIG_COMPACTION\n"
+ " extern int sysctl_compact_memory;\n"
+ " extern int sysctl_compaction_handler(struct ctl_table *table, int write,\n"
+ "diff --git a/mm/compaction.c b/mm/compaction.c\n"
+ "index 7ea259d..a5c9141 100644\n"
+ "--- a/mm/compaction.c\n"
+ "+++ b/mm/compaction.c\n"
+ "@@ -236,7 +236,7 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,\n"
+ " \t */\n"
+ " \twhile (unlikely(too_many_isolated(zone))) {\n"
+ " \t\t/* async migration should just abort */\n"
+ "-\t\tif (!cc->sync)\n"
+ "+\t\tif (cc->mode != COMPACT_SYNC)\n"
+ " \t\t\treturn 0;\n"
+ " \n"
+ " \t\tcongestion_wait(BLK_RW_ASYNC, HZ/10);\n"
+ "@@ -304,7 +304,8 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,\n"
+ " \t\t * satisfies the allocation\n"
+ " \t\t */\n"
+ " \t\tpageblock_nr = low_pfn >> pageblock_order;\n"
+ "-\t\tif (!cc->sync && last_pageblock_nr != pageblock_nr &&\n"
+ "+\t\tif (cc->mode != COMPACT_SYNC &&\n"
+ "+\t\t    last_pageblock_nr != pageblock_nr &&\n"
+ " \t\t    !migrate_async_suitable(get_pageblock_migratetype(page))) {\n"
+ " \t\t\tlow_pfn += pageblock_nr_pages;\n"
+ " \t\t\tlow_pfn = ALIGN(low_pfn, pageblock_nr_pages) - 1;\n"
+ "@@ -325,7 +326,7 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,\n"
+ " \t\t\tcontinue;\n"
+ " \t\t}\n"
+ " \n"
+ "-\t\tif (!cc->sync)\n"
+ "+\t\tif (cc->mode != COMPACT_SYNC)\n"
+ " \t\t\tmode |= ISOLATE_ASYNC_MIGRATE;\n"
+ " \n"
+ " \t\tlruvec = mem_cgroup_page_lruvec(page, zone);\n"
+ "@@ -360,27 +361,116 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,\n"
+ " \n"
+ " #endif /* CONFIG_COMPACTION || CONFIG_CMA */\n"
+ " #ifdef CONFIG_COMPACTION\n"
+ "+/*\n"
+ "+ * Returns true if MIGRATE_UNMOVABLE pageblock can be successfully\n"
+ "+ * converted to MIGRATE_MOVABLE type, false otherwise.\n"
+ "+ */\n"
+ "+static bool can_rescue_unmovable_pageblock(struct page *page)\n"
+ "+{\n"
+ "+\tstruct zone *zone;\n"
+ "+\tunsigned long pfn, start_pfn, end_pfn;\n"
+ "+\tstruct page *start_page, *end_page, *cursor_page;\n"
+ "+\n"
+ "+\tzone = page_zone(page);\n"
+ "+\tpfn = page_to_pfn(page);\n"
+ "+\tstart_pfn = pfn & ~(pageblock_nr_pages - 1);\n"
+ "+\tend_pfn = start_pfn + pageblock_nr_pages - 1;\n"
+ "+\n"
+ "+\tstart_page = pfn_to_page(start_pfn);\n"
+ "+\tend_page = pfn_to_page(end_pfn);\n"
+ "+\n"
+ "+\tfor (cursor_page = start_page, pfn = start_pfn; cursor_page <= end_page;\n"
+ "+\t\tpfn++, cursor_page++) {\n"
+ "+\n"
+ "+\t\tif (!pfn_valid_within(pfn))\n"
+ "+\t\t\tcontinue;\n"
+ "+\n"
+ "+\t\t/* Do not deal with pageblocks that overlap zones */\n"
+ "+\t\tif (page_zone(cursor_page) != zone)\n"
+ "+\t\t\treturn false;\n"
+ "+\n"
+ "+\t\t/*\n"
+ "+\t\t * Race with page allocator/reclaimer can happen so that\n"
+ "+\t\t * it can deceive unmovable block to migratable type\n"
+ "+\t\t * on this pageblock. It could regress on anti-fragmentation\n"
+ "+\t\t * but it's rare and not critical.\n"
+ "+\t\t */\n"
+ "+\t\tif (PageBuddy(cursor_page)) {\n"
+ "+\t\t\tunsigned long order = page_order(cursor_page);\n"
+ "+\n"
+ "+\t\t\tpfn += (1 << order) - 1;\n"
+ "+\t\t\tcursor_page += (1 << order) - 1;\n"
+ "+\t\t\tcontinue;\n"
+ "+\t\t} else if (PageLRU(cursor_page)) {\n"
+ "+\t\t\tcontinue;\n"
+ "+\t\t/*\n"
+ "+\t\t * We can't use page_count which does compound_head\n"
+ "+\t\t * as we don't have a pin a page.\n"
+ "+\t\t */\n"
+ "+\t\t} else if (!atomic_read(&cursor_page->_count)) {\n"
+ "+\t\t\tcontinue;\n"
+ "+\t\t}\n"
+ "+\n"
+ "+\t\treturn false;\n"
+ "+\t}\n"
+ "+\n"
+ "+\treturn true;\n"
+ "+}\n"
+ "+\n"
+ "+static void rescue_unmovable_pageblock(struct page *page)\n"
+ "+{\n"
+ "+\tset_pageblock_migratetype(page, MIGRATE_MOVABLE);\n"
+ "+\tmove_freepages_block(page_zone(page), page, MIGRATE_MOVABLE);\n"
+ "+}\n"
+ "+\n"
+ "+/*\n"
+ "+ * MIGRATE_TARGET : good for migration target\n"
+ "+ * RESCUE_UNMOVABLE_TARTET : good only if we can rescue the unmovable pageblock.\n"
+ "+ * UNMOVABLE_TARGET : can't migrate because it's a page in unmovable pageblock.\n"
+ "+ * SKIP_TARGET : can't migrate by another reasons.\n"
+ "+ */\n"
+ "+enum smt_result {\n"
+ "+\tMIGRATE_TARGET,\n"
+ "+\tRESCUE_UNMOVABLE_TARGET,\n"
+ "+\tUNMOVABLE_TARGET,\n"
+ "+\tSKIP_TARGET,\n"
+ "+};\n"
+ " \n"
+ "-/* Returns true if the page is within a block suitable for migration to */\n"
+ "-static bool suitable_migration_target(struct page *page)\n"
+ "+/*\n"
+ "+ * Returns MIGRATE_TARGET if the page is within a block\n"
+ "+ * suitable for migration to, UNMOVABLE_TARGET if the page\n"
+ "+ * is within a MIGRATE_UNMOVABLE block, SKIP_TARGET otherwise.\n"
+ "+ */\n"
+ "+static enum smt_result suitable_migration_target(struct page *page,\n"
+ "+\t\t\t      struct compact_control *cc)\n"
+ " {\n"
+ " \n"
+ " \tint migratetype = get_pageblock_migratetype(page);\n"
+ " \n"
+ " \t/* Don't interfere with memory hot-remove or the min_free_kbytes blocks */\n"
+ " \tif (migratetype == MIGRATE_ISOLATE || migratetype == MIGRATE_RESERVE)\n"
+ "-\t\treturn false;\n"
+ "+\t\treturn SKIP_TARGET;\n"
+ " \n"
+ " \t/* If the page is a large free page, then allow migration */\n"
+ " \tif (PageBuddy(page) && page_order(page) >= pageblock_order)\n"
+ "-\t\treturn true;\n"
+ "+\t\treturn MIGRATE_TARGET;\n"
+ " \n"
+ " \t/* If the block is MIGRATE_MOVABLE or MIGRATE_CMA, allow migration */\n"
+ "-\tif (migrate_async_suitable(migratetype))\n"
+ "-\t\treturn true;\n"
+ "+\tif (cc->mode != COMPACT_ASYNC_UNMOVABLE &&\n"
+ "+\t    migrate_async_suitable(migratetype))\n"
+ "+\t\treturn MIGRATE_TARGET;\n"
+ "+\n"
+ "+\tif (cc->mode == COMPACT_ASYNC_MOVABLE &&\n"
+ "+\t    migratetype == MIGRATE_UNMOVABLE)\n"
+ "+\t\treturn UNMOVABLE_TARGET;\n"
+ "+\n"
+ "+\tif (cc->mode != COMPACT_ASYNC_MOVABLE &&\n"
+ "+\t    migratetype == MIGRATE_UNMOVABLE &&\n"
+ "+\t    can_rescue_unmovable_pageblock(page))\n"
+ "+\t\treturn RESCUE_UNMOVABLE_TARGET;\n"
+ " \n"
+ " \t/* Otherwise skip the block */\n"
+ "-\treturn false;\n"
+ "+\treturn SKIP_TARGET;\n"
+ " }\n"
+ " \n"
+ " /*\n"
+ "@@ -414,6 +504,13 @@ static void isolate_freepages(struct zone *zone,\n"
+ " \tzone_end_pfn = zone->zone_start_pfn + zone->spanned_pages;\n"
+ " \n"
+ " \t/*\n"
+ "+\t * isolate_freepages() may be called more than once during\n"
+ "+\t * compact_zone_order() run and we want only the most recent\n"
+ "+\t * count.\n"
+ "+\t */\n"
+ "+\tcc->nr_unmovable_pageblock = 0;\n"
+ "+\n"
+ "+\t/*\n"
+ " \t * Isolate free pages until enough are available to migrate the\n"
+ " \t * pages on cc->migratepages. We stop searching if the migrate\n"
+ " \t * and free page scanners meet or enough free pages are isolated.\n"
+ "@@ -421,6 +518,7 @@ static void isolate_freepages(struct zone *zone,\n"
+ " \tfor (; pfn > low_pfn && cc->nr_migratepages > nr_freepages;\n"
+ " \t\t\t\t\tpfn -= pageblock_nr_pages) {\n"
+ " \t\tunsigned long isolated;\n"
+ "+\t\tenum smt_result ret;\n"
+ " \n"
+ " \t\tif (!pfn_valid(pfn))\n"
+ " \t\t\tcontinue;\n"
+ "@@ -437,9 +535,12 @@ static void isolate_freepages(struct zone *zone,\n"
+ " \t\t\tcontinue;\n"
+ " \n"
+ " \t\t/* Check the block is suitable for migration */\n"
+ "-\t\tif (!suitable_migration_target(page))\n"
+ "+\t\tret = suitable_migration_target(page, cc);\n"
+ "+\t\tif (ret != MIGRATE_TARGET && ret != RESCUE_UNMOVABLE_TARGET) {\n"
+ "+\t\t\tif (ret == UNMOVABLE_TARGET)\n"
+ "+\t\t\t\tcc->nr_unmovable_pageblock++;\n"
+ " \t\t\tcontinue;\n"
+ "-\n"
+ "+\t\t}\n"
+ " \t\t/*\n"
+ " \t\t * Found a block suitable for isolating free pages from. Now\n"
+ " \t\t * we disabled interrupts, double check things are ok and\n"
+ "@@ -448,12 +549,16 @@ static void isolate_freepages(struct zone *zone,\n"
+ " \t\t */\n"
+ " \t\tisolated = 0;\n"
+ " \t\tspin_lock_irqsave(&zone->lock, flags);\n"
+ "-\t\tif (suitable_migration_target(page)) {\n"
+ "+\t\tret = suitable_migration_target(page, cc);\n"
+ "+\t\tif (ret == MIGRATE_TARGET || ret == RESCUE_UNMOVABLE_TARGET) {\n"
+ "+\t\t\tif (ret == RESCUE_UNMOVABLE_TARGET)\n"
+ "+\t\t\t\trescue_unmovable_pageblock(page);\n"
+ " \t\t\tend_pfn = min(pfn + pageblock_nr_pages, zone_end_pfn);\n"
+ " \t\t\tisolated = isolate_freepages_block(pfn, end_pfn,\n"
+ " \t\t\t\t\t\t\t   freelist, false);\n"
+ " \t\t\tnr_freepages += isolated;\n"
+ "-\t\t}\n"
+ "+\t\t} else if (ret == UNMOVABLE_TARGET)\n"
+ "+\t\t\tcc->nr_unmovable_pageblock++;\n"
+ " \t\tspin_unlock_irqrestore(&zone->lock, flags);\n"
+ " \n"
+ " \t\t/*\n"
+ "@@ -685,8 +790,9 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)\n"
+ " \n"
+ " \t\tnr_migrate = cc->nr_migratepages;\n"
+ " \t\terr = migrate_pages(&cc->migratepages, compaction_alloc,\n"
+ "-\t\t\t\t(unsigned long)cc, false,\n"
+ "-\t\t\t\tcc->sync ? MIGRATE_SYNC_LIGHT : MIGRATE_ASYNC);\n"
+ "+\t\t\t(unsigned long)&cc->freepages, false,\n"
+ "+\t\t\t(cc->mode == COMPACT_SYNC) ? MIGRATE_SYNC_LIGHT\n"
+ "+\t\t\t\t\t\t      : MIGRATE_ASYNC);\n"
+ " \t\tupdate_nr_listpages(cc);\n"
+ " \t\tnr_remaining = cc->nr_migratepages;\n"
+ " \n"
+ "@@ -715,7 +821,8 @@ out:\n"
+ " \n"
+ " static unsigned long compact_zone_order(struct zone *zone,\n"
+ " \t\t\t\t int order, gfp_t gfp_mask,\n"
+ "-\t\t\t\t bool sync)\n"
+ "+\t\t\t\t enum compact_mode mode,\n"
+ "+\t\t\t\t unsigned long *nr_pageblocks_skipped)\n"
+ " {\n"
+ " \tstruct compact_control cc = {\n"
+ " \t\t.nr_freepages = 0,\n"
+ "@@ -723,12 +830,17 @@ static unsigned long compact_zone_order(struct zone *zone,\n"
+ " \t\t.order = order,\n"
+ " \t\t.migratetype = allocflags_to_migratetype(gfp_mask),\n"
+ " \t\t.zone = zone,\n"
+ "-\t\t.sync = sync,\n"
+ "+\t\t.mode = mode,\n"
+ " \t};\n"
+ "+\tunsigned long rc;\n"
+ "+\n"
+ " \tINIT_LIST_HEAD(&cc.freepages);\n"
+ " \tINIT_LIST_HEAD(&cc.migratepages);\n"
+ " \n"
+ "-\treturn compact_zone(zone, &cc);\n"
+ "+\trc = compact_zone(zone, &cc);\n"
+ "+\t*nr_pageblocks_skipped = cc.nr_unmovable_pageblock;\n"
+ "+\n"
+ "+\treturn rc;\n"
+ " }\n"
+ " \n"
+ " int sysctl_extfrag_threshold = 500;\n"
+ "@@ -753,6 +865,8 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist,\n"
+ " \tstruct zoneref *z;\n"
+ " \tstruct zone *zone;\n"
+ " \tint rc = COMPACT_SKIPPED;\n"
+ "+\tunsigned long nr_pageblocks_skipped;\n"
+ "+\tenum compact_mode mode;\n"
+ " \n"
+ " \t/*\n"
+ " \t * Check whether it is worth even starting compaction. The order check is\n"
+ "@@ -769,12 +883,22 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist,\n"
+ " \t\t\t\t\t\t\t\tnodemask) {\n"
+ " \t\tint status;\n"
+ " \n"
+ "-\t\tstatus = compact_zone_order(zone, order, gfp_mask, sync);\n"
+ "+\t\tmode = sync ? COMPACT_SYNC : COMPACT_ASYNC_MOVABLE;\n"
+ "+retry:\n"
+ "+\t\tstatus = compact_zone_order(zone, order, gfp_mask, mode,\n"
+ "+\t\t\t\t\t\t&nr_pageblocks_skipped);\n"
+ " \t\trc = max(status, rc);\n"
+ " \n"
+ " \t\t/* If a normal allocation would succeed, stop compacting */\n"
+ " \t\tif (zone_watermark_ok(zone, order, low_wmark_pages(zone), 0, 0))\n"
+ " \t\t\tbreak;\n"
+ "+\n"
+ "+\t\tif (rc == COMPACT_COMPLETE && mode == COMPACT_ASYNC_MOVABLE) {\n"
+ "+\t\t\tif (nr_pageblocks_skipped) {\n"
+ "+\t\t\t\tmode = COMPACT_ASYNC_UNMOVABLE;\n"
+ "+\t\t\t\tgoto retry;\n"
+ "+\t\t\t}\n"
+ "+\t\t}\n"
+ " \t}\n"
+ " \n"
+ " \treturn rc;\n"
+ "@@ -808,7 +932,7 @@ static int __compact_pgdat(pg_data_t *pgdat, struct compact_control *cc)\n"
+ " \t\t\tif (ok && cc->order > zone->compact_order_failed)\n"
+ " \t\t\t\tzone->compact_order_failed = cc->order + 1;\n"
+ " \t\t\t/* Currently async compaction is never deferred. */\n"
+ "-\t\t\telse if (!ok && cc->sync)\n"
+ "+\t\t\telse if (!ok && cc->mode == COMPACT_SYNC)\n"
+ " \t\t\t\tdefer_compaction(zone, cc->order);\n"
+ " \t\t}\n"
+ " \n"
+ "@@ -823,7 +947,7 @@ int compact_pgdat(pg_data_t *pgdat, int order)\n"
+ " {\n"
+ " \tstruct compact_control cc = {\n"
+ " \t\t.order = order,\n"
+ "-\t\t.sync = false,\n"
+ "+\t\t.mode = COMPACT_ASYNC_MOVABLE,\n"
+ " \t};\n"
+ " \n"
+ " \treturn __compact_pgdat(pgdat, &cc);\n"
+ "@@ -833,7 +957,7 @@ static int compact_node(int nid)\n"
+ " {\n"
+ " \tstruct compact_control cc = {\n"
+ " \t\t.order = -1,\n"
+ "-\t\t.sync = true,\n"
+ "+\t\t.mode = COMPACT_SYNC,\n"
+ " \t};\n"
+ " \n"
+ " \treturn __compact_pgdat(NODE_DATA(nid), &cc);\n"
+ "diff --git a/mm/internal.h b/mm/internal.h\n"
+ "index 2ba87fb..061fde7 100644\n"
+ "--- a/mm/internal.h\n"
+ "+++ b/mm/internal.h\n"
+ "@@ -94,6 +94,9 @@ extern void putback_lru_page(struct page *page);\n"
+ " /*\n"
+ "  * in mm/page_alloc.c\n"
+ "  */\n"
+ "+extern void set_pageblock_migratetype(struct page *page, int migratetype);\n"
+ "+extern int move_freepages_block(struct zone *zone, struct page *page,\n"
+ "+\t\t\t\tint migratetype);\n"
+ " extern void __free_pages_bootmem(struct page *page, unsigned int order);\n"
+ " extern void prep_compound_page(struct page *page, unsigned long order);\n"
+ " #ifdef CONFIG_MEMORY_FAILURE\n"
+ "@@ -101,6 +104,7 @@ extern bool is_free_buddy_page(struct page *page);\n"
+ " #endif\n"
+ " \n"
+ " #if defined CONFIG_COMPACTION || defined CONFIG_CMA\n"
+ "+#include <linux/compaction.h>\n"
+ " \n"
+ " /*\n"
+ "  * in mm/compaction.c\n"
+ "@@ -119,11 +123,14 @@ struct compact_control {\n"
+ " \tunsigned long nr_migratepages;\t/* Number of pages to migrate */\n"
+ " \tunsigned long free_pfn;\t\t/* isolate_freepages search base */\n"
+ " \tunsigned long migrate_pfn;\t/* isolate_migratepages search base */\n"
+ "-\tbool sync;\t\t\t/* Synchronous migration */\n"
+ "+\tenum compact_mode mode;\t\t/* Compaction mode */\n"
+ " \n"
+ " \tint order;\t\t\t/* order a direct compactor needs */\n"
+ " \tint migratetype;\t\t/* MOVABLE, RECLAIMABLE etc */\n"
+ " \tstruct zone *zone;\n"
+ "+\n"
+ "+\t/* Number of UNMOVABLE destination pageblocks skipped during scan */\n"
+ "+\tunsigned long nr_unmovable_pageblock;\n"
+ " };\n"
+ " \n"
+ " unsigned long\n"
+ "diff --git a/mm/page_alloc.c b/mm/page_alloc.c\n"
+ "index 476ae3e..d40e4c7 100644\n"
+ "--- a/mm/page_alloc.c\n"
+ "+++ b/mm/page_alloc.c\n"
+ "@@ -219,7 +219,7 @@ EXPORT_SYMBOL(nr_online_nodes);\n"
+ " \n"
+ " int page_group_by_mobility_disabled __read_mostly;\n"
+ " \n"
+ "-static void set_pageblock_migratetype(struct page *page, int migratetype)\n"
+ "+void set_pageblock_migratetype(struct page *page, int migratetype)\n"
+ " {\n"
+ " \n"
+ " \tif (unlikely(page_group_by_mobility_disabled))\n"
+ "@@ -954,8 +954,8 @@ static int move_freepages(struct zone *zone,\n"
+ " \treturn pages_moved;\n"
+ " }\n"
+ " \n"
+ "-static int move_freepages_block(struct zone *zone, struct page *page,\n"
+ "-\t\t\t\tint migratetype)\n"
+ "+int move_freepages_block(struct zone *zone, struct page *page,\n"
+ "+\t\t\t int migratetype)\n"
+ " {\n"
+ " \tunsigned long start_pfn, end_pfn;\n"
+ " \tstruct page *start_page, *end_page;\n"
+ "@@ -5651,7 +5651,7 @@ static int __alloc_contig_migrate_range(unsigned long start, unsigned long end)\n"
+ " \t\t.nr_migratepages = 0,\n"
+ " \t\t.order = -1,\n"
+ " \t\t.zone = page_zone(pfn_to_page(start)),\n"
+ "-\t\t.sync = true,\n"
+ "+\t\t.mode = COMPACT_SYNC,\n"
+ " \t};\n"
+ " \tINIT_LIST_HEAD(&cc.migratepages);\n"
+ " \n"
+ "-- \n"
+ 1.7.9.5
 
-d089f517d5da624d3c993804d5edb310a52b7edf15c5565d37abaa31c61711da
+bb06e5d2de09960c85a6deb0d35a4dad882a049a1c86e1cf41721ae08f3842a7

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.