Commit 4cd64dcede969cf30f47a6e6ba8e378e74d0790d

Authored by Vlastimil Babka
Committed by Jiri Slaby
1 parent 2ce666c175

mm/page_alloc: prevent MIGRATE_RESERVE pages from being misplaced

commit 5bcc9f86ef09a933255ee66bd899d4601785dad5 upstream.

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>
Signed-off-by: Mel Gorman <mgorman@suse.de>
Signed-off-by: Jiri Slaby <jslaby@suse.cz>

Showing 1 changed file with 13 additions and 10 deletions Side-by-side Diff

... ... @@ -918,6 +918,7 @@
918 918 rmv_page_order(page);
919 919 area->nr_free--;
920 920 expand(zone, page, order, current_order, area, migratetype);
  921 + set_freepage_migratetype(page, migratetype);
921 922 return page;
922 923 }
923 924  
... ... @@ -1044,7 +1045,9 @@
1044 1045  
1045 1046 /*
1046 1047 * When borrowing from MIGRATE_CMA, we need to release the excess
1047   - * buddy pages to CMA itself.
  1048 + * buddy pages to CMA itself. We also ensure the freepage_migratetype
  1049 + * is set to CMA so it is returned to the correct freelist in case
  1050 + * the page ends up being not actually allocated from the pcp lists.
1048 1051 */
1049 1052 if (is_migrate_cma(fallback_type))
1050 1053 return fallback_type;
... ... @@ -1112,6 +1115,12 @@
1112 1115  
1113 1116 expand(zone, page, order, current_order, area,
1114 1117 new_type);
  1118 + /* The freepage_migratetype may differ from pageblock's
  1119 + * migratetype depending on the decisions in
  1120 + * try_to_steal_freepages. This is OK as long as it does
  1121 + * not differ for MIGRATE_CMA type.
  1122 + */
  1123 + set_freepage_migratetype(page, new_type);
1115 1124  
1116 1125 trace_mm_page_alloc_extfrag(page, order, current_order,
1117 1126 start_migratetype, migratetype, new_type);
... ... @@ -1162,7 +1171,7 @@
1162 1171 unsigned long count, struct list_head *list,
1163 1172 int migratetype, int cold)
1164 1173 {
1165   - int mt = migratetype, i;
  1174 + int i;
1166 1175  
1167 1176 spin_lock(&zone->lock);
1168 1177 for (i = 0; i < count; ++i) {
1169 1178  
... ... @@ -1183,14 +1192,8 @@
1183 1192 list_add(&page->lru, list);
1184 1193 else
1185 1194 list_add_tail(&page->lru, list);
1186   - if (IS_ENABLED(CONFIG_CMA)) {
1187   - mt = get_pageblock_migratetype(page);
1188   - if (!is_migrate_cma(mt) && !is_migrate_isolate(mt))
1189   - mt = migratetype;
1190   - }
1191   - set_freepage_migratetype(page, mt);
1192 1195 list = &page->lru;
1193   - if (is_migrate_cma(mt))
  1196 + if (is_migrate_cma(get_freepage_migratetype(page)))
1194 1197 __mod_zone_page_state(zone, NR_FREE_CMA_PAGES,
1195 1198 -(1 << order));
1196 1199 }
... ... @@ -1559,7 +1562,7 @@
1559 1562 if (!page)
1560 1563 goto failed;
1561 1564 __mod_zone_freepage_state(zone, -(1 << order),
1562   - get_pageblock_migratetype(page));
  1565 + get_freepage_migratetype(page));
1563 1566 }
1564 1567  
1565 1568 __mod_zone_page_state(zone, NR_ALLOC_BATCH, -(1 << order));