Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm: mmzone: MIGRATE_CMA migration type added

The MIGRATE_CMA migration type has two main characteristics:
(i) only movable pages can be allocated from MIGRATE_CMA
pageblocks and (ii) page allocator will never change migration
type of MIGRATE_CMA pageblocks.

This guarantees (to some degree) that page in a MIGRATE_CMA page
block can always be migrated somewhere else (unless there's no
memory left in the system).

It is designed to be used for allocating big chunks (eg. 10MiB)
of physically contiguous memory. Once driver requests
contiguous memory, pages from MIGRATE_CMA pageblocks may be
migrated away to create a contiguous block.

To minimise number of migrations, MIGRATE_CMA migration type
is the last type tried when page allocator falls back to other
migration types when requested.

Signed-off-by: Michal Nazarewicz <mina86@mina86.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Acked-by: Mel Gorman <mel@csn.ul.ie>
Reviewed-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Tested-by: Rob Clark <rob.clark@linaro.org>
Tested-by: Ohad Ben-Cohen <ohad@wizery.com>
Tested-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Tested-by: Robert Nelson <robertcnelson@gmail.com>
Tested-by: Barry Song <Baohua.Song@csr.com>

authored by

Michal Nazarewicz and committed by
Marek Szyprowski
47118af0 6d4a4916

+106 -27
+3
include/linux/gfp.h
··· 397 397 extern int alloc_contig_range(unsigned long start, unsigned long end); 398 398 extern void free_contig_range(unsigned long pfn, unsigned nr_pages); 399 399 400 + /* CMA stuff */ 401 + extern void init_cma_reserved_pageblock(struct page *page); 402 + 400 403 #endif 401 404 402 405 #endif /* __LINUX_GFP_H */
+31 -7
include/linux/mmzone.h
··· 35 35 */ 36 36 #define PAGE_ALLOC_COSTLY_ORDER 3 37 37 38 - #define MIGRATE_UNMOVABLE 0 39 - #define MIGRATE_RECLAIMABLE 1 40 - #define MIGRATE_MOVABLE 2 41 - #define MIGRATE_PCPTYPES 3 /* the number of types on the pcp lists */ 42 - #define MIGRATE_RESERVE 3 43 - #define MIGRATE_ISOLATE 4 /* can't allocate from here */ 44 - #define MIGRATE_TYPES 5 38 + enum { 39 + MIGRATE_UNMOVABLE, 40 + MIGRATE_RECLAIMABLE, 41 + MIGRATE_MOVABLE, 42 + MIGRATE_PCPTYPES, /* the number of types on the pcp lists */ 43 + MIGRATE_RESERVE = MIGRATE_PCPTYPES, 44 + #ifdef CONFIG_CMA 45 + /* 46 + * MIGRATE_CMA migration type is designed to mimic the way 47 + * ZONE_MOVABLE works. Only movable pages can be allocated 48 + * from MIGRATE_CMA pageblocks and page allocator never 49 + * implicitly change migration type of MIGRATE_CMA pageblock. 50 + * 51 + * The way to use it is to change migratetype of a range of 52 + * pageblocks to MIGRATE_CMA which can be done by 53 + * __free_pageblock_cma() function. What is important though 54 + * is that a range of pageblocks must be aligned to 55 + * MAX_ORDER_NR_PAGES should biggest page be bigger then 56 + * a single pageblock. 57 + */ 58 + MIGRATE_CMA, 59 + #endif 60 + MIGRATE_ISOLATE, /* can't allocate from here */ 61 + MIGRATE_TYPES 62 + }; 63 + 64 + #ifdef CONFIG_CMA 65 + # define is_migrate_cma(migratetype) unlikely((migratetype) == MIGRATE_CMA) 66 + #else 67 + # define is_migrate_cma(migratetype) false 68 + #endif 45 69 46 70 #define for_each_migratetype_order(order, type) \ 47 71 for (order = 0; order < MAX_ORDER; order++) \
+1 -1
mm/Kconfig
··· 198 198 config MIGRATION 199 199 bool "Page migration" 200 200 def_bool y 201 - depends on NUMA || ARCH_ENABLE_MEMORY_HOTREMOVE || COMPACTION 201 + depends on NUMA || ARCH_ENABLE_MEMORY_HOTREMOVE || COMPACTION || CMA 202 202 help 203 203 Allows the migration of the physical location of pages of processes 204 204 while the virtual addresses are not changed. This is useful in
+8 -3
mm/compaction.c
··· 45 45 } 46 46 } 47 47 48 + static inline bool migrate_async_suitable(int migratetype) 49 + { 50 + return is_migrate_cma(migratetype) || migratetype == MIGRATE_MOVABLE; 51 + } 52 + 48 53 /* 49 54 * Isolate free pages onto a private freelist. Caller must hold zone->lock. 50 55 * If @strict is true, will abort returning 0 on any invalid PFNs or non-free ··· 304 299 */ 305 300 pageblock_nr = low_pfn >> pageblock_order; 306 301 if (!cc->sync && last_pageblock_nr != pageblock_nr && 307 - get_pageblock_migratetype(page) != MIGRATE_MOVABLE) { 302 + !migrate_async_suitable(get_pageblock_migratetype(page))) { 308 303 low_pfn += pageblock_nr_pages; 309 304 low_pfn = ALIGN(low_pfn, pageblock_nr_pages) - 1; 310 305 last_pageblock_nr = pageblock_nr; ··· 372 367 if (PageBuddy(page) && page_order(page) >= pageblock_order) 373 368 return true; 374 369 375 - /* If the block is MIGRATE_MOVABLE, allow migration */ 376 - if (migratetype == MIGRATE_MOVABLE) 370 + /* If the block is MIGRATE_MOVABLE or MIGRATE_CMA, allow migration */ 371 + if (migrate_async_suitable(migratetype)) 377 372 return true; 378 373 379 374 /* Otherwise skip the block */
+60 -16
mm/page_alloc.c
··· 750 750 __free_pages(page, order); 751 751 } 752 752 753 + #ifdef CONFIG_CMA 754 + /* Free whole pageblock and set it's migration type to MIGRATE_CMA. */ 755 + void __init init_cma_reserved_pageblock(struct page *page) 756 + { 757 + unsigned i = pageblock_nr_pages; 758 + struct page *p = page; 759 + 760 + do { 761 + __ClearPageReserved(p); 762 + set_page_count(p, 0); 763 + } while (++p, --i); 764 + 765 + set_page_refcounted(page); 766 + set_pageblock_migratetype(page, MIGRATE_CMA); 767 + __free_pages(page, pageblock_order); 768 + totalram_pages += pageblock_nr_pages; 769 + } 770 + #endif 753 771 754 772 /* 755 773 * The order of subdivision here is critical for the IO subsystem. ··· 893 875 * This array describes the order lists are fallen back to when 894 876 * the free lists for the desirable migrate type are depleted 895 877 */ 896 - static int fallbacks[MIGRATE_TYPES][3] = { 897 - [MIGRATE_UNMOVABLE] = { MIGRATE_RECLAIMABLE, MIGRATE_MOVABLE, MIGRATE_RESERVE }, 898 - [MIGRATE_RECLAIMABLE] = { MIGRATE_UNMOVABLE, MIGRATE_MOVABLE, MIGRATE_RESERVE }, 899 - [MIGRATE_MOVABLE] = { MIGRATE_RECLAIMABLE, MIGRATE_UNMOVABLE, MIGRATE_RESERVE }, 878 + static int fallbacks[MIGRATE_TYPES][4] = { 879 + [MIGRATE_UNMOVABLE] = { MIGRATE_RECLAIMABLE, MIGRATE_MOVABLE, MIGRATE_RESERVE }, 880 + [MIGRATE_RECLAIMABLE] = { MIGRATE_UNMOVABLE, MIGRATE_MOVABLE, MIGRATE_RESERVE }, 881 + #ifdef CONFIG_CMA 882 + [MIGRATE_MOVABLE] = { MIGRATE_CMA, MIGRATE_RECLAIMABLE, MIGRATE_UNMOVABLE, MIGRATE_RESERVE }, 883 + [MIGRATE_CMA] = { MIGRATE_RESERVE }, /* Never used */ 884 + #else 885 + [MIGRATE_MOVABLE] = { MIGRATE_RECLAIMABLE, MIGRATE_UNMOVABLE, MIGRATE_RESERVE }, 886 + #endif 900 887 [MIGRATE_RESERVE] = { MIGRATE_RESERVE }, /* Never used */ 901 888 [MIGRATE_ISOLATE] = { MIGRATE_RESERVE }, /* Never used */ 902 889 }; ··· 1018 995 * pages to the preferred allocation list. If falling 1019 996 * back for a reclaimable kernel allocation, be more 1020 997 * aggressive about taking ownership of free pages 998 + * 999 + * On the other hand, never change migration 1000 + * type of MIGRATE_CMA pageblocks nor move CMA 1001 + * pages on different free lists. We don't 1002 + * want unmovable pages to be allocated from 1003 + * MIGRATE_CMA areas. 1021 1004 */ 1022 - if (unlikely(current_order >= (pageblock_order >> 1)) || 1023 - start_migratetype == MIGRATE_RECLAIMABLE || 1024 - page_group_by_mobility_disabled) { 1025 - unsigned long pages; 1005 + if (!is_migrate_cma(migratetype) && 1006 + (unlikely(current_order >= pageblock_order / 2) || 1007 + start_migratetype == MIGRATE_RECLAIMABLE || 1008 + page_group_by_mobility_disabled)) { 1009 + int pages; 1026 1010 pages = move_freepages_block(zone, page, 1027 1011 start_migratetype); 1028 1012 ··· 1047 1017 rmv_page_order(page); 1048 1018 1049 1019 /* Take ownership for orders >= pageblock_order */ 1050 - if (current_order >= pageblock_order) 1020 + if (current_order >= pageblock_order && 1021 + !is_migrate_cma(migratetype)) 1051 1022 change_pageblock_range(page, current_order, 1052 1023 start_migratetype); 1053 1024 1054 - expand(zone, page, order, current_order, area, migratetype); 1025 + expand(zone, page, order, current_order, area, 1026 + is_migrate_cma(migratetype) 1027 + ? migratetype : start_migratetype); 1055 1028 1056 1029 trace_mm_page_alloc_extfrag(page, order, current_order, 1057 1030 start_migratetype, migratetype); ··· 1105 1072 unsigned long count, struct list_head *list, 1106 1073 int migratetype, int cold) 1107 1074 { 1108 - int i; 1075 + int mt = migratetype, i; 1109 1076 1110 1077 spin_lock(&zone->lock); 1111 1078 for (i = 0; i < count; ++i) { ··· 1126 1093 list_add(&page->lru, list); 1127 1094 else 1128 1095 list_add_tail(&page->lru, list); 1129 - set_page_private(page, migratetype); 1096 + if (IS_ENABLED(CONFIG_CMA)) { 1097 + mt = get_pageblock_migratetype(page); 1098 + if (!is_migrate_cma(mt) && mt != MIGRATE_ISOLATE) 1099 + mt = migratetype; 1100 + } 1101 + set_page_private(page, mt); 1130 1102 list = &page->lru; 1131 1103 } 1132 1104 __mod_zone_page_state(zone, NR_FREE_PAGES, -(i << order)); ··· 1411 1373 1412 1374 if (order >= pageblock_order - 1) { 1413 1375 struct page *endpage = page + (1 << order) - 1; 1414 - for (; page < endpage; page += pageblock_nr_pages) 1415 - set_pageblock_migratetype(page, MIGRATE_MOVABLE); 1376 + for (; page < endpage; page += pageblock_nr_pages) { 1377 + int mt = get_pageblock_migratetype(page); 1378 + if (mt != MIGRATE_ISOLATE && !is_migrate_cma(mt)) 1379 + set_pageblock_migratetype(page, 1380 + MIGRATE_MOVABLE); 1381 + } 1416 1382 } 1417 1383 1418 1384 return 1 << order; ··· 5456 5414 __count_immobile_pages(struct zone *zone, struct page *page, int count) 5457 5415 { 5458 5416 unsigned long pfn, iter, found; 5417 + int mt; 5418 + 5459 5419 /* 5460 5420 * For avoiding noise data, lru_add_drain_all() should be called 5461 5421 * If ZONE_MOVABLE, the zone never contains immobile pages 5462 5422 */ 5463 5423 if (zone_idx(zone) == ZONE_MOVABLE) 5464 5424 return true; 5465 - 5466 - if (get_pageblock_migratetype(page) == MIGRATE_MOVABLE) 5425 + mt = get_pageblock_migratetype(page); 5426 + if (mt == MIGRATE_MOVABLE || is_migrate_cma(mt)) 5467 5427 return true; 5468 5428 5469 5429 pfn = page_to_pfn(page);
+3
mm/vmstat.c
··· 613 613 "Reclaimable", 614 614 "Movable", 615 615 "Reserve", 616 + #ifdef CONFIG_CMA 617 + "CMA", 618 + #endif 616 619 "Isolate", 617 620 }; 618 621