aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Tatashin <pasha.tatashin@oracle.com>2018-08-17 18:49:33 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-08-17 19:20:32 -0400
commit85c77f79139062901727cc3bd87a65212c8c0a32 (patch)
tree4c8431fb94fe6b48094856a0a7229573e7f38454
parentafda57bc13410459fc957e93341ade7bebca36e2 (diff)
mm/sparse: add new sparse_init_nid() and sparse_init()
sparse_init() requires to temporary allocate two large buffers: usemap_map and map_map. Baoquan He has identified that these buffers are so large that Linux is not bootable on small memory machines, such as a kdump boot. The buffers are especially large when CONFIG_X86_5LEVEL is set, as they are scaled to the maximum physical memory size. Baoquan provided a fix, which reduces these sizes of these buffers, but it is much better to get rid of them entirely. Add a new way to initialize sparse memory: sparse_init_nid(), which only operates within one memory node, and thus allocates memory either in large contiguous block or allocates section by section. This eliminates the need for use of temporary buffers. For simplified bisecting and review temporarly call sparse_init() new_sparse_init(), the new interface is going to be enabled as well as old code removed in the next patch. Link: http://lkml.kernel.org/r/20180712203730.8703-5-pasha.tatashin@oracle.com Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com> Reviewed-by: Oscar Salvador <osalvador@suse.de> Tested-by: Oscar Salvador <osalvador@suse.de> Tested-by: Michael Ellerman <mpe@ellerman.id.au> [powerpc] Cc: Pasha Tatashin <Pavel.Tatashin@microsoft.com> Cc: Abdul Haleem <abdhalee@linux.vnet.ibm.com> Cc: Baoquan He <bhe@redhat.com> Cc: Daniel Jordan <daniel.m.jordan@oracle.com> Cc: Dan Williams <dan.j.williams@intel.com> Cc: Dave Hansen <dave.hansen@intel.com> Cc: David Rientjes <rientjes@google.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Ingo Molnar <mingo@kernel.org> Cc: Jan Kara <jack@suse.cz> Cc: Jérôme Glisse <jglisse@redhat.com> Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> Cc: Michal Hocko <mhocko@kernel.org> Cc: Souptick Joarder <jrdr.linux@gmail.com> Cc: Steven Sistare <steven.sistare@oracle.com> Cc: Vlastimil Babka <vbabka@suse.cz> Cc: Wei Yang <richard.weiyang@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--mm/sparse.c85
1 files changed, 85 insertions, 0 deletions
diff --git a/mm/sparse.c b/mm/sparse.c
index 20ca292d8f11..248d5d7bbf55 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -200,6 +200,11 @@ static inline int next_present_section_nr(int section_nr)
200 (section_nr <= __highest_present_section_nr)); \ 200 (section_nr <= __highest_present_section_nr)); \
201 section_nr = next_present_section_nr(section_nr)) 201 section_nr = next_present_section_nr(section_nr))
202 202
203static inline unsigned long first_present_section_nr(void)
204{
205 return next_present_section_nr(-1);
206}
207
203/* 208/*
204 * Record how many memory sections are marked as present 209 * Record how many memory sections are marked as present
205 * during system bootup. 210 * during system bootup.
@@ -668,6 +673,86 @@ void __init sparse_init(void)
668 memblock_free_early(__pa(usemap_map), size); 673 memblock_free_early(__pa(usemap_map), size);
669} 674}
670 675
676/*
677 * Initialize sparse on a specific node. The node spans [pnum_begin, pnum_end)
678 * And number of present sections in this node is map_count.
679 */
680static void __init sparse_init_nid(int nid, unsigned long pnum_begin,
681 unsigned long pnum_end,
682 unsigned long map_count)
683{
684 unsigned long pnum, usemap_longs, *usemap;
685 struct page *map;
686
687 usemap_longs = BITS_TO_LONGS(SECTION_BLOCKFLAGS_BITS);
688 usemap = sparse_early_usemaps_alloc_pgdat_section(NODE_DATA(nid),
689 usemap_size() *
690 map_count);
691 if (!usemap) {
692 pr_err("%s: node[%d] usemap allocation failed", __func__, nid);
693 goto failed;
694 }
695 sparse_buffer_init(map_count * section_map_size(), nid);
696 for_each_present_section_nr(pnum_begin, pnum) {
697 if (pnum >= pnum_end)
698 break;
699
700 map = sparse_mem_map_populate(pnum, nid, NULL);
701 if (!map) {
702 pr_err("%s: node[%d] memory map backing failed. Some memory will not be available.",
703 __func__, nid);
704 pnum_begin = pnum;
705 goto failed;
706 }
707 check_usemap_section_nr(nid, usemap);
708 sparse_init_one_section(__nr_to_section(pnum), pnum, map, usemap);
709 usemap += usemap_longs;
710 }
711 sparse_buffer_fini();
712 return;
713failed:
714 /* We failed to allocate, mark all the following pnums as not present */
715 for_each_present_section_nr(pnum_begin, pnum) {
716 struct mem_section *ms;
717
718 if (pnum >= pnum_end)
719 break;
720 ms = __nr_to_section(pnum);
721 ms->section_mem_map = 0;
722 }
723}
724
725/*
726 * Allocate the accumulated non-linear sections, allocate a mem_map
727 * for each and record the physical to section mapping.
728 */
729void __init new_sparse_init(void)
730{
731 unsigned long pnum_begin = first_present_section_nr();
732 int nid_begin = sparse_early_nid(__nr_to_section(pnum_begin));
733 unsigned long pnum_end, map_count = 1;
734
735 /* Setup pageblock_order for HUGETLB_PAGE_SIZE_VARIABLE */
736 set_pageblock_order();
737
738 for_each_present_section_nr(pnum_begin + 1, pnum_end) {
739 int nid = sparse_early_nid(__nr_to_section(pnum_end));
740
741 if (nid == nid_begin) {
742 map_count++;
743 continue;
744 }
745 /* Init node with sections in range [pnum_begin, pnum_end) */
746 sparse_init_nid(nid_begin, pnum_begin, pnum_end, map_count);
747 nid_begin = nid;
748 pnum_begin = pnum_end;
749 map_count = 1;
750 }
751 /* cover the last node */
752 sparse_init_nid(nid_begin, pnum_begin, pnum_end, map_count);
753 vmemmap_populate_print_last();
754}
755
671#ifdef CONFIG_MEMORY_HOTPLUG 756#ifdef CONFIG_MEMORY_HOTPLUG
672 757
673/* Mark all memory sections within the pfn range as online */ 758/* Mark all memory sections within the pfn range as online */