| @@ -28,6 +28,7 @@ · 27 unmodified lines |
| 28 | 28 | #include <linux/jhash.h> |
| 29 | 29 | #include <linux/numa.h> |
| 30 | 30 | #include <linux/llist.h> |
| 31 | +#include <linux/cma.h> |
| 31 | 32 | |
| 32 | 33 | #include <asm/page.h> |
| 33 | 34 | #include <asm/pgtable.h> |
| @@ -44,6 +45,9 @@ · 10 unmodified lines |
| 44 | 45 | int hugetlb_max_hstate __read_mostly; |
| 45 | 46 | unsigned int default_hstate_idx; |
| 46 | 47 | struct hstate hstates[HUGE_MAX_HSTATE]; |
| 48 | + |
| 49 | +static struct cma *hugetlb_cma[MAX_NUMNODES]; |
| 50 | + |
| 47 | 51 | /* |
| 48 | 52 | * Minimum page order among possible hugepage sizes, set to a proper value |
| 49 | 53 | * at boot time. |
| @@ -1228,6 +1232,14 @@ static void destroy_compound_gigantic_page(struct page *page, · 1178 unmodified lines |
| 1228 | 1232 | |
| 1229 | 1233 | static void free_gigantic_page(struct page *page, unsigned int order) |
| 1230 | 1234 | { |
| 1235 | + /* |
| 1236 | + * If the page isn't allocated using the cma allocator, |
| 1237 | + * cma_release() returns false. |
| 1238 | + */ |
| 1239 | + if (IS_ENABLED(CONFIG_CMA) && |
| 1240 | + cma_release(hugetlb_cma[page_to_nid(page)], page, 1 << order)) |
| 1241 | + return; |
| 1242 | + |
| 1231 | 1243 | free_contig_range(page_to_pfn(page), 1 << order); |
| 1232 | 1244 | } |
| 1233 | 1245 | |
| @@ -1237,6 +1249,21 @@ static struct page *alloc_gigantic_page(struct hstate *h, gfp_t gfp_mask, · 3 unmodified lines |
| 1237 | 1249 | { |
| 1238 | 1250 | unsigned long nr_pages = 1UL << huge_page_order(h); |
| 1239 | 1251 | |
| 1252 | + if (IS_ENABLED(CONFIG_CMA)) { |
| 1253 | + struct page *page; |
| 1254 | + int node; |
| 1255 | + |
| 1256 | + for_each_node_mask(node, *nodemask) { |
| 1257 | + if (!hugetlb_cma[node]) |
| 1258 | + continue; |
| 1259 | + |
| 1260 | + page = cma_alloc(hugetlb_cma[node], nr_pages, |
| 1261 | + huge_page_order(h), true); |
| 1262 | + if (page) |
| 1263 | + return page; |
| 1264 | + } |
| 1265 | + } |
| 1266 | + |
| 1240 | 1267 | return alloc_contig_pages(nr_pages, gfp_mask, nid, nodemask); |
| 1241 | 1268 | } |
| 1242 | 1269 | |
| @@ -1281,8 +1308,14 @@ static void update_and_free_page(struct hstate *h, struct page *page) · 38 unmodified lines |
| 1281 | 1308 | set_compound_page_dtor(page, NULL_COMPOUND_DTOR); |
| 1282 | 1309 | set_page_refcounted(page); |
| 1283 | 1310 | if (hstate_is_gigantic(h)) { |
| 1311 | + /* |
| 1312 | + * Temporarily drop the hugetlb_lock, because |
| 1313 | + * we might block in free_gigantic_page(). |
| 1314 | + */ |
| 1315 | + spin_unlock(&hugetlb_lock); |
| 1284 | 1316 | destroy_compound_gigantic_page(page, huge_page_order(h)); |
| 1285 | 1317 | free_gigantic_page(page, huge_page_order(h)); |
| 1318 | + spin_lock(&hugetlb_lock); |
| 1286 | 1319 | } else { |
| 1287 | 1320 | __free_pages(page, huge_page_order(h)); |
| 1288 | 1321 | } |
| @@ -2539,6 +2572,10 @@ static void __init hugetlb_hstate_alloc_pages(struct hstate *h) · 1250 unmodified lines |
| 2539 | 2572 | |
| 2540 | 2573 | for (i = 0; i < h->max_huge_pages; ++i) { |
| 2541 | 2574 | if (hstate_is_gigantic(h)) { |
| 2575 | + if (IS_ENABLED(CONFIG_CMA) && hugetlb_cma[0]) { |
| 2576 | + pr_warn_once("HugeTLB: hugetlb_cma is enabled, skip boot time allocation\n"); |
| 2577 | + break; |
| 2578 | + } |
| 2542 | 2579 | if (!alloc_bootmem_huge_page(h)) |
| 2543 | 2580 | break; |
| 2544 | 2581 | } else if (!alloc_pool_huge_page(h, |
| @@ -3194,6 +3231,7 @@ static int __init hugetlb_init(void) · 649 unmodified lines |
| 3194 | 3231 | default_hstate.max_huge_pages = default_hstate_max_huge_pages; |
| 3195 | 3232 | } |
| 3196 | 3233 | |
| 3234 | + hugetlb_cma_check(); |
| 3197 | 3235 | hugetlb_init_hstates(); |
| 3198 | 3236 | gather_bootmem_prealloc(); |
| 3199 | 3237 | report_hugepages(); |
| @@ -5506,3 +5544,74 @@ void move_hugetlb_state(struct page *oldpage, struct page *newpage, int reason) · 2306 unmodified lines |
| 5506 | 5544 | spin_unlock(&hugetlb_lock); |
| 5507 | 5545 | } |
| 5508 | 5546 | } |
| 5547 | + |
| 5548 | +#ifdef CONFIG_CMA |
| 5549 | +static unsigned long hugetlb_cma_size __initdata; |
| 5550 | +static bool cma_reserve_called __initdata; |
| 5551 | + |
| 5552 | +static int __init cmdline_parse_hugetlb_cma(char *p) |
| 5553 | +{ |
| 5554 | + hugetlb_cma_size = memparse(p, &p); |
| 5555 | + return 0; |
| 5556 | +} |
| 5557 | + |
| 5558 | +early_param("hugetlb_cma", cmdline_parse_hugetlb_cma); |
| 5559 | + |
| 5560 | +void __init hugetlb_cma_reserve(int order) |
| 5561 | +{ |
| 5562 | + unsigned long size, reserved, per_node; |
| 5563 | + int nid; |
| 5564 | + |
| 5565 | + cma_reserve_called = true; |
| 5566 | + |
| 5567 | + if (!hugetlb_cma_size) |
| 5568 | + return; |
| 5569 | + |
| 5570 | + if (hugetlb_cma_size < (PAGE_SIZE << order)) { |
| 5571 | + pr_warn("hugetlb_cma: cma area should be at least %lu MiB\n", |
| 5572 | + (PAGE_SIZE << order) / SZ_1M); |
| 5573 | + return; |
| 5574 | + } |
| 5575 | + |
| 5576 | + /* |
| 5577 | + * If 3 GB area is requested on a machine with 4 numa nodes, |
| 5578 | + * let's allocate 1 GB on first three nodes and ignore the last one. |
| 5579 | + */ |
| 5580 | + per_node = DIV_ROUND_UP(hugetlb_cma_size, nr_online_nodes); |
| 5581 | + pr_info("hugetlb_cma: reserve %lu MiB, up to %lu MiB per node\n", |
| 5582 | + hugetlb_cma_size / SZ_1M, per_node / SZ_1M); |
| 5583 | + |
| 5584 | + reserved = 0; |
| 5585 | + for_each_node_state(nid, N_ONLINE) { |
| 5586 | + int res; |
| 5587 | + |
| 5588 | + size = min(per_node, hugetlb_cma_size - reserved); |
| 5589 | + size = round_up(size, PAGE_SIZE << order); |
| 5590 | + |
| 5591 | + res = cma_declare_contiguous_nid(0, size, 0, PAGE_SIZE << order, |
| 5592 | + 0, false, "hugetlb", |
| 5593 | + &hugetlb_cma[nid], nid); |
| 5594 | + if (res) { |
| 5595 | + pr_warn("hugetlb_cma: reservation failed: err %d, node %d", |
| 5596 | + res, nid); |
| 5597 | + continue; |
| 5598 | + } |
| 5599 | + |
| 5600 | + reserved += size; |
| 5601 | + pr_info("hugetlb_cma: reserved %lu MiB on node %d\n", |
| 5602 | + size / SZ_1M, nid); |
| 5603 | + |
| 5604 | + if (reserved >= hugetlb_cma_size) |
| 5605 | + break; |
| 5606 | + } |
| 5607 | +} |
| 5608 | + |
| 5609 | +void __init hugetlb_cma_check(void) |
| 5610 | +{ |
| 5611 | + if (!hugetlb_cma_size || cma_reserve_called) |
| 5612 | + return; |
| 5613 | + |
| 5614 | + pr_warn("hugetlb_cma: the option isn't supported by current arch\n"); |
| 5615 | +} |
| 5616 | + |
| 5617 | +#endif /* CONFIG_CMA */ |