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.