aboutsummaryrefslogtreecommitdiffstats
path: root/mm/sparse.c
diff options
context:
space:
mode:
authorMichal Hocko <mhocko@suse.com>2017-07-06 18:37:56 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-06 19:24:32 -0400
commit2d070eab2e8270c8a84d480bb91e4f739315f03d (patch)
tree18c8db141506d2a6a505eda7c45ec5dc032aa034 /mm/sparse.c
parent8b0662f245a328df8873be949b0087760420f40c (diff)
mm: consider zone which is not fully populated to have holes
__pageblock_pfn_to_page has two users currently, set_zone_contiguous which checks whether the given zone contains holes and pageblock_pfn_to_page which then carefully returns a first valid page from the given pfn range for the given zone. This doesn't handle zones which are not fully populated though. Memory pageblocks can be offlined or might not have been onlined yet. In such a case the zone should be considered to have holes otherwise pfn walkers can touch and play with offline pages. Current callers of pageblock_pfn_to_page in compaction seem to work properly right now because they only isolate PageBuddy (isolate_freepages_block) or PageLRU resp. __PageMovable (isolate_migratepages_block) which will be always false for these pages. It would be safer to skip these pages altogether, though. In order to do this patch adds a new memory section state (SECTION_IS_ONLINE) which is set in memory_present (during boot time) or in online_pages_range during the memory hotplug. Similarly offline_mem_sections clears the bit and it is called when the memory range is offlined. pfn_to_online_page helper is then added which check the mem section and only returns a page if it is onlined already. Use the new helper in __pageblock_pfn_to_page and skip the whole page block in such a case. [mhocko@suse.com: check valid section number in pfn_to_online_page (Vlastimil), mark sections online after all struct pages are initialized in online_pages_range (Vlastimil)] Link: http://lkml.kernel.org/r/20170518164210.GD18333@dhcp22.suse.cz Link: http://lkml.kernel.org/r/20170515085827.16474-8-mhocko@kernel.org Signed-off-by: Michal Hocko <mhocko@suse.com> Acked-by: Vlastimil Babka <vbabka@suse.cz> Cc: Andi Kleen <ak@linux.intel.com> Cc: Andrea Arcangeli <aarcange@redhat.com> Cc: Balbir Singh <bsingharora@gmail.com> Cc: Dan Williams <dan.j.williams@intel.com> Cc: Daniel Kiper <daniel.kiper@oracle.com> Cc: David Rientjes <rientjes@google.com> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: Igor Mammedov <imammedo@redhat.com> Cc: Jerome Glisse <jglisse@redhat.com> Cc: Joonsoo Kim <js1304@gmail.com> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Mel Gorman <mgorman@suse.de> Cc: Reza Arbab <arbab@linux.vnet.ibm.com> Cc: Tobias Regnery <tobias.regnery@gmail.com> Cc: Toshi Kani <toshi.kani@hpe.com> Cc: Vitaly Kuznetsov <vkuznets@redhat.com> Cc: Xishi Qiu <qiuxishi@huawei.com> Cc: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/sparse.c')
-rw-r--r--mm/sparse.c45
1 files changed, 44 insertions, 1 deletions
diff --git a/mm/sparse.c b/mm/sparse.c
index 5032c9a619de..9d7fd666015e 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -222,7 +222,8 @@ void __init memory_present(int nid, unsigned long start, unsigned long end)
222 222
223 ms = __nr_to_section(section); 223 ms = __nr_to_section(section);
224 if (!ms->section_mem_map) { 224 if (!ms->section_mem_map) {
225 ms->section_mem_map = sparse_encode_early_nid(nid); 225 ms->section_mem_map = sparse_encode_early_nid(nid) |
226 SECTION_IS_ONLINE;
226 section_mark_present(ms); 227 section_mark_present(ms);
227 } 228 }
228 } 229 }
@@ -622,6 +623,48 @@ void __init sparse_init(void)
622} 623}
623 624
624#ifdef CONFIG_MEMORY_HOTPLUG 625#ifdef CONFIG_MEMORY_HOTPLUG
626
627/* Mark all memory sections within the pfn range as online */
628void online_mem_sections(unsigned long start_pfn, unsigned long end_pfn)
629{
630 unsigned long pfn;
631
632 for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
633 unsigned long section_nr = pfn_to_section_nr(start_pfn);
634 struct mem_section *ms;
635
636 /* onlining code should never touch invalid ranges */
637 if (WARN_ON(!valid_section_nr(section_nr)))
638 continue;
639
640 ms = __nr_to_section(section_nr);
641 ms->section_mem_map |= SECTION_IS_ONLINE;
642 }
643}
644
645#ifdef CONFIG_MEMORY_HOTREMOVE
646/* Mark all memory sections within the pfn range as online */
647void offline_mem_sections(unsigned long start_pfn, unsigned long end_pfn)
648{
649 unsigned long pfn;
650
651 for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
652 unsigned long section_nr = pfn_to_section_nr(start_pfn);
653 struct mem_section *ms;
654
655 /*
656 * TODO this needs some double checking. Offlining code makes
657 * sure to check pfn_valid but those checks might be just bogus
658 */
659 if (WARN_ON(!valid_section_nr(section_nr)))
660 continue;
661
662 ms = __nr_to_section(section_nr);
663 ms->section_mem_map &= ~SECTION_IS_ONLINE;
664 }
665}
666#endif
667
625#ifdef CONFIG_SPARSEMEM_VMEMMAP 668#ifdef CONFIG_SPARSEMEM_VMEMMAP
626static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid) 669static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid)
627{ 670{