aboutsummaryrefslogtreecommitdiffstats
path: root/mm/page_alloc.c
diff options
context:
space:
mode:
authorVlastimil Babka <vbabka@suse.cz>2014-06-04 19:07:22 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-06-04 19:54:00 -0400
commit5bcc9f86ef09a933255ee66bd899d4601785dad5 (patch)
treea451b94983b961c29e1d697a731ff68799144425 /mm/page_alloc.c
parent9b857d26d08f00971997cd21aa491e27e0c84ce3 (diff)
mm/page_alloc: prevent MIGRATE_RESERVE pages from being misplaced
For the MIGRATE_RESERVE pages, it is useful when they do not get misplaced on free_list of other migratetype, otherwise they might get allocated prematurely and e.g. fragment the MIGRATE_RESEVE pageblocks. While this cannot be avoided completely when allocating new MIGRATE_RESERVE pageblocks in min_free_kbytes sysctl handler, we should prevent the misplacement where possible. Currently, it is possible for the misplacement to happen when a MIGRATE_RESERVE page is allocated on pcplist through rmqueue_bulk() as a fallback for other desired migratetype, and then later freed back through free_pcppages_bulk() without being actually used. This happens because free_pcppages_bulk() uses get_freepage_migratetype() to choose the free_list, and rmqueue_bulk() calls set_freepage_migratetype() with the *desired* migratetype and not the page's original MIGRATE_RESERVE migratetype. This patch fixes the problem by moving the call to set_freepage_migratetype() from rmqueue_bulk() down to __rmqueue_smallest() and __rmqueue_fallback() where the actual page's migratetype (e.g. from which free_list the page is taken from) is used. Note that this migratetype might be different from the pageblock's migratetype due to freepage stealing decisions. This is OK, as page stealing never uses MIGRATE_RESERVE as a fallback, and also takes care to leave all MIGRATE_CMA pages on the correct freelist. Therefore, as an additional benefit, the call to get_pageblock_migratetype() from rmqueue_bulk() when CMA is enabled, can be removed completely. This relies on the fact that MIGRATE_CMA pageblocks are created only during system init, and the above. The related is_migrate_isolate() check is also unnecessary, as memory isolation has other ways to move pages between freelists, and drain pcp lists containing pages that should be isolated. The buffered_rmqueue() can also benefit from calling get_freepage_migratetype() instead of get_pageblock_migratetype(). Signed-off-by: Vlastimil Babka <vbabka@suse.cz> Reported-by: Yong-Taek Lee <ytk.lee@samsung.com> Reported-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> Suggested-by: Joonsoo Kim <iamjoonsoo.kim@lge.com> Acked-by: Joonsoo Kim <iamjoonsoo.kim@lge.com> Suggested-by: Mel Gorman <mgorman@suse.de> Acked-by: Minchan Kim <minchan@kernel.org> Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Cc: Hugh Dickins <hughd@google.com> Cc: Rik van Riel <riel@redhat.com> Cc: Michal Nazarewicz <mina86@mina86.com> Cc: "Wang, Yalin" <Yalin.Wang@sonymobile.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/page_alloc.c')
-rw-r--r--mm/page_alloc.c23
1 files changed, 13 insertions, 10 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 9f13bcfb6762..ab46f7945098 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -931,6 +931,7 @@ struct page *__rmqueue_smallest(struct zone *zone, unsigned int order,
931 rmv_page_order(page); 931 rmv_page_order(page);
932 area->nr_free--; 932 area->nr_free--;
933 expand(zone, page, order, current_order, area, migratetype); 933 expand(zone, page, order, current_order, area, migratetype);
934 set_freepage_migratetype(page, migratetype);
934 return page; 935 return page;
935 } 936 }
936 937
@@ -1057,7 +1058,9 @@ static int try_to_steal_freepages(struct zone *zone, struct page *page,
1057 1058
1058 /* 1059 /*
1059 * When borrowing from MIGRATE_CMA, we need to release the excess 1060 * When borrowing from MIGRATE_CMA, we need to release the excess
1060 * buddy pages to CMA itself. 1061 * buddy pages to CMA itself. We also ensure the freepage_migratetype
1062 * is set to CMA so it is returned to the correct freelist in case
1063 * the page ends up being not actually allocated from the pcp lists.
1061 */ 1064 */
1062 if (is_migrate_cma(fallback_type)) 1065 if (is_migrate_cma(fallback_type))
1063 return fallback_type; 1066 return fallback_type;
@@ -1125,6 +1128,12 @@ __rmqueue_fallback(struct zone *zone, int order, int start_migratetype)
1125 1128
1126 expand(zone, page, order, current_order, area, 1129 expand(zone, page, order, current_order, area,
1127 new_type); 1130 new_type);
1131 /* The freepage_migratetype may differ from pageblock's
1132 * migratetype depending on the decisions in
1133 * try_to_steal_freepages. This is OK as long as it does
1134 * not differ for MIGRATE_CMA type.
1135 */
1136 set_freepage_migratetype(page, new_type);
1128 1137
1129 trace_mm_page_alloc_extfrag(page, order, current_order, 1138 trace_mm_page_alloc_extfrag(page, order, current_order,
1130 start_migratetype, migratetype, new_type); 1139 start_migratetype, migratetype, new_type);
@@ -1175,7 +1184,7 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order,
1175 unsigned long count, struct list_head *list, 1184 unsigned long count, struct list_head *list,
1176 int migratetype, int cold) 1185 int migratetype, int cold)
1177{ 1186{
1178 int mt = migratetype, i; 1187 int i;
1179 1188
1180 spin_lock(&zone->lock); 1189 spin_lock(&zone->lock);
1181 for (i = 0; i < count; ++i) { 1190 for (i = 0; i < count; ++i) {
@@ -1196,14 +1205,8 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order,
1196 list_add(&page->lru, list); 1205 list_add(&page->lru, list);
1197 else 1206 else
1198 list_add_tail(&page->lru, list); 1207 list_add_tail(&page->lru, list);
1199 if (IS_ENABLED(CONFIG_CMA)) {
1200 mt = get_pageblock_migratetype(page);
1201 if (!is_migrate_cma(mt) && !is_migrate_isolate(mt))
1202 mt = migratetype;
1203 }
1204 set_freepage_migratetype(page, mt);
1205 list = &page->lru; 1208 list = &page->lru;
1206 if (is_migrate_cma(mt)) 1209 if (is_migrate_cma(get_freepage_migratetype(page)))
1207 __mod_zone_page_state(zone, NR_FREE_CMA_PAGES, 1210 __mod_zone_page_state(zone, NR_FREE_CMA_PAGES,
1208 -(1 << order)); 1211 -(1 << order));
1209 } 1212 }
@@ -1572,7 +1575,7 @@ again:
1572 if (!page) 1575 if (!page)
1573 goto failed; 1576 goto failed;
1574 __mod_zone_freepage_state(zone, -(1 << order), 1577 __mod_zone_freepage_state(zone, -(1 << order),
1575 get_pageblock_migratetype(page)); 1578 get_freepage_migratetype(page));
1576 } 1579 }
1577 1580
1578 __mod_zone_page_state(zone, NR_ALLOC_BATCH, -(1 << order)); 1581 __mod_zone_page_state(zone, NR_ALLOC_BATCH, -(1 << order));