summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBaoquan He <bhe@redhat.com>2018-08-17 18:48:49 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-08-17 19:20:31 -0400
commitc98aff649349d9147915a19d378c9c3c1bd85de0 (patch)
tree5af2720e65d8360b66d6b736b3f89a5a58f83589
parent9258631b33374f20d856032c3542b76ad7f5a312 (diff)
mm/sparse: optimize memmap allocation during sparse_init()
In sparse_init(), two temporary pointer arrays, usemap_map and map_map are allocated with the size of NR_MEM_SECTIONS. They are used to store each memory section's usemap and mem map if marked as present. With the help of these two arrays, continuous memory chunk is allocated for usemap and memmap for memory sections on one node. This avoids too many memory fragmentations. Like below diagram, '1' indicates the present memory section, '0' means absent one. The number 'n' could be much smaller than NR_MEM_SECTIONS on most of systems. |1|1|1|1|0|0|0|0|1|1|0|0|...|1|0||1|0|...|1||0|1|...|0| ------------------------------------------------------- 0 1 2 3 4 5 i i+1 n-1 n If we fail to populate the page tables to map one section's memmap, its ->section_mem_map will be cleared finally to indicate that it's not present. After use, these two arrays will be released at the end of sparse_init(). In 4-level paging mode, each array costs 4M which can be ignorable. While in 5-level paging, they costs 256M each, 512M altogether. Kdump kernel Usually only reserves very few memory, e.g 256M. So, even thouth they are temporarily allocated, still not acceptable. In fact, there's no need to allocate them with the size of NR_MEM_SECTIONS. Since the ->section_mem_map clearing has been deferred to the last, the number of present memory sections are kept the same during sparse_init() until we finally clear out the memory section's ->section_mem_map if its usemap or memmap is not correctly handled. Thus in the middle whenever for_each_present_section_nr() loop is taken, the i-th present memory section is always the same one. Here only allocate usemap_map and map_map with the size of 'nr_present_sections'. For the i-th present memory section, install its usemap and memmap to usemap_map[i] and mam_map[i] during allocation. Then in the last for_each_present_section_nr() loop which clears the failed memory section's ->section_mem_map, fetch usemap and memmap from usemap_map[] and map_map[] array and set them into mem_section[] accordingly. [akpm@linux-foundation.org: coding-style fixes] Link: http://lkml.kernel.org/r/20180628062857.29658-5-bhe@redhat.com Signed-off-by: Baoquan He <bhe@redhat.com> Reviewed-by: Pavel Tatashin <pasha.tatashin@oracle.com> Cc: Pasha Tatashin <Pavel.Tatashin@microsoft.com> Cc: Dave Hansen <dave.hansen@intel.com> Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Cc: Oscar Salvador <osalvador@techadventures.net> Cc: Pankaj Gupta <pagupta@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--mm/sparse-vmemmap.c6
-rw-r--r--mm/sparse.c46
2 files changed, 41 insertions, 11 deletions
diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c
index 68bb65b2d34d..95e2c7638a5c 100644
--- a/mm/sparse-vmemmap.c
+++ b/mm/sparse-vmemmap.c
@@ -281,6 +281,7 @@ void __init sparse_mem_maps_populate_node(struct page **map_map,
281 unsigned long pnum; 281 unsigned long pnum;
282 unsigned long size = sizeof(struct page) * PAGES_PER_SECTION; 282 unsigned long size = sizeof(struct page) * PAGES_PER_SECTION;
283 void *vmemmap_buf_start; 283 void *vmemmap_buf_start;
284 int nr_consumed_maps = 0;
284 285
285 size = ALIGN(size, PMD_SIZE); 286 size = ALIGN(size, PMD_SIZE);
286 vmemmap_buf_start = __earlyonly_bootmem_alloc(nodeid, size * map_count, 287 vmemmap_buf_start = __earlyonly_bootmem_alloc(nodeid, size * map_count,
@@ -295,8 +296,9 @@ void __init sparse_mem_maps_populate_node(struct page **map_map,
295 if (!present_section_nr(pnum)) 296 if (!present_section_nr(pnum))
296 continue; 297 continue;
297 298
298 map_map[pnum] = sparse_mem_map_populate(pnum, nodeid, NULL); 299 map_map[nr_consumed_maps] =
299 if (map_map[pnum]) 300 sparse_mem_map_populate(pnum, nodeid, NULL);
301 if (map_map[nr_consumed_maps++])
300 continue; 302 continue;
301 pr_err("%s: sparsemem memory map backing failed some memory will not be available\n", 303 pr_err("%s: sparsemem memory map backing failed some memory will not be available\n",
302 __func__); 304 __func__);
diff --git a/mm/sparse.c b/mm/sparse.c
index eb188eb6b82d..2ea8b3dbd0df 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -381,6 +381,7 @@ static void __init sparse_early_usemaps_alloc_node(void *data,
381 unsigned long pnum; 381 unsigned long pnum;
382 unsigned long **usemap_map = (unsigned long **)data; 382 unsigned long **usemap_map = (unsigned long **)data;
383 int size = usemap_size(); 383 int size = usemap_size();
384 int nr_consumed_maps = 0;
384 385
385 usemap = sparse_early_usemaps_alloc_pgdat_section(NODE_DATA(nodeid), 386 usemap = sparse_early_usemaps_alloc_pgdat_section(NODE_DATA(nodeid),
386 size * usemap_count); 387 size * usemap_count);
@@ -392,9 +393,10 @@ static void __init sparse_early_usemaps_alloc_node(void *data,
392 for (pnum = pnum_begin; pnum < pnum_end; pnum++) { 393 for (pnum = pnum_begin; pnum < pnum_end; pnum++) {
393 if (!present_section_nr(pnum)) 394 if (!present_section_nr(pnum))
394 continue; 395 continue;
395 usemap_map[pnum] = usemap; 396 usemap_map[nr_consumed_maps] = usemap;
396 usemap += size; 397 usemap += size;
397 check_usemap_section_nr(nodeid, usemap_map[pnum]); 398 check_usemap_section_nr(nodeid, usemap_map[nr_consumed_maps]);
399 nr_consumed_maps++;
398 } 400 }
399} 401}
400 402
@@ -419,29 +421,34 @@ void __init sparse_mem_maps_populate_node(struct page **map_map,
419 void *map; 421 void *map;
420 unsigned long pnum; 422 unsigned long pnum;
421 unsigned long size = sizeof(struct page) * PAGES_PER_SECTION; 423 unsigned long size = sizeof(struct page) * PAGES_PER_SECTION;
424 int nr_consumed_maps;
422 425
423 size = PAGE_ALIGN(size); 426 size = PAGE_ALIGN(size);
424 map = memblock_virt_alloc_try_nid_raw(size * map_count, 427 map = memblock_virt_alloc_try_nid_raw(size * map_count,
425 PAGE_SIZE, __pa(MAX_DMA_ADDRESS), 428 PAGE_SIZE, __pa(MAX_DMA_ADDRESS),
426 BOOTMEM_ALLOC_ACCESSIBLE, nodeid); 429 BOOTMEM_ALLOC_ACCESSIBLE, nodeid);
427 if (map) { 430 if (map) {
431 nr_consumed_maps = 0;
428 for (pnum = pnum_begin; pnum < pnum_end; pnum++) { 432 for (pnum = pnum_begin; pnum < pnum_end; pnum++) {
429 if (!present_section_nr(pnum)) 433 if (!present_section_nr(pnum))
430 continue; 434 continue;
431 map_map[pnum] = map; 435 map_map[nr_consumed_maps] = map;
432 map += size; 436 map += size;
437 nr_consumed_maps++;
433 } 438 }
434 return; 439 return;
435 } 440 }
436 441
437 /* fallback */ 442 /* fallback */
443 nr_consumed_maps = 0;
438 for (pnum = pnum_begin; pnum < pnum_end; pnum++) { 444 for (pnum = pnum_begin; pnum < pnum_end; pnum++) {
439 struct mem_section *ms; 445 struct mem_section *ms;
440 446
441 if (!present_section_nr(pnum)) 447 if (!present_section_nr(pnum))
442 continue; 448 continue;
443 map_map[pnum] = sparse_mem_map_populate(pnum, nodeid, NULL); 449 map_map[nr_consumed_maps] =
444 if (map_map[pnum]) 450 sparse_mem_map_populate(pnum, nodeid, NULL);
451 if (map_map[nr_consumed_maps++])
445 continue; 452 continue;
446 ms = __nr_to_section(pnum); 453 ms = __nr_to_section(pnum);
447 pr_err("%s: sparsemem memory map backing failed some memory will not be available\n", 454 pr_err("%s: sparsemem memory map backing failed some memory will not be available\n",
@@ -521,6 +528,7 @@ static void __init alloc_usemap_and_memmap(void (*alloc_func)
521 /* new start, update count etc*/ 528 /* new start, update count etc*/
522 nodeid_begin = nodeid; 529 nodeid_begin = nodeid;
523 pnum_begin = pnum; 530 pnum_begin = pnum;
531 data += map_count * data_unit_size;
524 map_count = 1; 532 map_count = 1;
525 } 533 }
526 /* ok, last chunk */ 534 /* ok, last chunk */
@@ -539,6 +547,7 @@ void __init sparse_init(void)
539 unsigned long *usemap; 547 unsigned long *usemap;
540 unsigned long **usemap_map; 548 unsigned long **usemap_map;
541 int size; 549 int size;
550 int nr_consumed_maps = 0;
542#ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER 551#ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER
543 int size2; 552 int size2;
544 struct page **map_map; 553 struct page **map_map;
@@ -561,7 +570,7 @@ void __init sparse_init(void)
561 * powerpc need to call sparse_init_one_section right after each 570 * powerpc need to call sparse_init_one_section right after each
562 * sparse_early_mem_map_alloc, so allocate usemap_map at first. 571 * sparse_early_mem_map_alloc, so allocate usemap_map at first.
563 */ 572 */
564 size = sizeof(unsigned long *) * NR_MEM_SECTIONS; 573 size = sizeof(unsigned long *) * nr_present_sections;
565 usemap_map = memblock_virt_alloc(size, 0); 574 usemap_map = memblock_virt_alloc(size, 0);
566 if (!usemap_map) 575 if (!usemap_map)
567 panic("can not allocate usemap_map\n"); 576 panic("can not allocate usemap_map\n");
@@ -570,7 +579,7 @@ void __init sparse_init(void)
570 sizeof(usemap_map[0])); 579 sizeof(usemap_map[0]));
571 580
572#ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER 581#ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER
573 size2 = sizeof(struct page *) * NR_MEM_SECTIONS; 582 size2 = sizeof(struct page *) * nr_present_sections;
574 map_map = memblock_virt_alloc(size2, 0); 583 map_map = memblock_virt_alloc(size2, 0);
575 if (!map_map) 584 if (!map_map)
576 panic("can not allocate map_map\n"); 585 panic("can not allocate map_map\n");
@@ -579,27 +588,46 @@ void __init sparse_init(void)
579 sizeof(map_map[0])); 588 sizeof(map_map[0]));
580#endif 589#endif
581 590
591 /*
592 * The number of present sections stored in nr_present_sections
593 * are kept the same since mem sections are marked as present in
594 * memory_present(). In this for loop, we need check which sections
595 * failed to allocate memmap or usemap, then clear its
596 * ->section_mem_map accordingly. During this process, we need
597 * increase 'nr_consumed_maps' whether its allocation of memmap
598 * or usemap failed or not, so that after we handle the i-th
599 * memory section, can get memmap and usemap of (i+1)-th section
600 * correctly.
601 */
582 for_each_present_section_nr(0, pnum) { 602 for_each_present_section_nr(0, pnum) {
583 struct mem_section *ms; 603 struct mem_section *ms;
604
605 if (nr_consumed_maps >= nr_present_sections) {
606 pr_err("nr_consumed_maps goes beyond nr_present_sections\n");
607 break;
608 }
584 ms = __nr_to_section(pnum); 609 ms = __nr_to_section(pnum);
585 usemap = usemap_map[pnum]; 610 usemap = usemap_map[nr_consumed_maps];
586 if (!usemap) { 611 if (!usemap) {
587 ms->section_mem_map = 0; 612 ms->section_mem_map = 0;
613 nr_consumed_maps++;
588 continue; 614 continue;
589 } 615 }
590 616
591#ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER 617#ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER
592 map = map_map[pnum]; 618 map = map_map[nr_consumed_maps];
593#else 619#else
594 map = sparse_early_mem_map_alloc(pnum); 620 map = sparse_early_mem_map_alloc(pnum);
595#endif 621#endif
596 if (!map) { 622 if (!map) {
597 ms->section_mem_map = 0; 623 ms->section_mem_map = 0;
624 nr_consumed_maps++;
598 continue; 625 continue;
599 } 626 }
600 627
601 sparse_init_one_section(__nr_to_section(pnum), pnum, map, 628 sparse_init_one_section(__nr_to_section(pnum), pnum, map,
602 usemap); 629 usemap);
630 nr_consumed_maps++;
603 } 631 }
604 632
605 vmemmap_populate_print_last(); 633 vmemmap_populate_print_last();