Skip to content

Commit f14851a

Browse files
qiuxishitorvalds
qiuxishi
authored andcommitted
memory hotplug: fix section info double registration bug
There may be a bug when registering section info. For example, on my Itanium platform, the pfn range of node0 includes the other nodes, so other nodes' section info will be double registered, and memmap's page count will equal to 3. node0: start_pfn=0x100, spanned_pfn=0x20fb00, present_pfn=0x7f8a3, => 0x000100-0x20fc00 node1: start_pfn=0x80000, spanned_pfn=0x80000, present_pfn=0x80000, => 0x080000-0x100000 node2: start_pfn=0x100000, spanned_pfn=0x80000, present_pfn=0x80000, => 0x100000-0x180000 node3: start_pfn=0x180000, spanned_pfn=0x80000, present_pfn=0x80000, => 0x180000-0x200000 free_all_bootmem_node() register_page_bootmem_info_node() register_page_bootmem_info_section() When hot remove memory, we can't free the memmap's page because page_count() is 2 after put_page_bootmem(). sparse_remove_one_section() free_section_usemap() free_map_bootmem() put_page_bootmem() [akpm@linux-foundation.org: add code comment] Signed-off-by: Xishi Qiu <qiuxishi@huawei.com> Signed-off-by: Jiang Liu <jiang.liu@huawei.com> Acked-by: Mel Gorman <mgorman@suse.de> Cc: "Luck, Tony" <tony.luck@intel.com> Cc: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 0ba8f2d commit f14851a

File tree

1 file changed

+10
-6
lines changed

1 file changed

+10
-6
lines changed

mm/memory_hotplug.c

+10-6
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,6 @@ static void register_page_bootmem_info_section(unsigned long start_pfn)
126126
struct mem_section *ms;
127127
struct page *page, *memmap;
128128

129-
if (!pfn_valid(start_pfn))
130-
return;
131-
132129
section_nr = pfn_to_section_nr(start_pfn);
133130
ms = __nr_to_section(section_nr);
134131

@@ -187,9 +184,16 @@ void register_page_bootmem_info_node(struct pglist_data *pgdat)
187184
end_pfn = pfn + pgdat->node_spanned_pages;
188185

189186
/* register_section info */
190-
for (; pfn < end_pfn; pfn += PAGES_PER_SECTION)
191-
register_page_bootmem_info_section(pfn);
192-
187+
for (; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
188+
/*
189+
* Some platforms can assign the same pfn to multiple nodes - on
190+
* node0 as well as nodeN. To avoid registering a pfn against
191+
* multiple nodes we check that this pfn does not already
192+
* reside in some other node.
193+
*/
194+
if (pfn_valid(pfn) && (pfn_to_nid(pfn) == node))
195+
register_page_bootmem_info_section(pfn);
196+
}
193197
}
194198
#endif /* !CONFIG_SPARSEMEM_VMEMMAP */
195199

0 commit comments

Comments
 (0)