From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754038AbbLIJjG (ORCPT ); Wed, 9 Dec 2015 04:39:06 -0500 Received: from youngberry.canonical.com ([91.189.89.112]:45033 "EHLO youngberry.canonical.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751973AbbLIJjA (ORCPT ); Wed, 9 Dec 2015 04:39:00 -0500 From: Luis Henriques To: linux-kernel@vger.kernel.org, stable@vger.kernel.org, kernel-team@lists.ubuntu.com Cc: Yinghai Lu , Greg Kroah-Hartman , Luis Henriques Subject: [PATCH 3.16.y-ckt 021/126] mm: Check if section present during memory block (un)registering Date: Wed, 9 Dec 2015 09:36:31 +0000 Message-Id: <1449653896-5236-22-git-send-email-luis.henriques@canonical.com> In-Reply-To: <1449653896-5236-1-git-send-email-luis.henriques@canonical.com> References: <1449653896-5236-1-git-send-email-luis.henriques@canonical.com> X-Extended-Stable: 3.16 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 3.16.7-ckt21 -stable review patch. If anyone has any objections, please let me know. ------------------ From: Yinghai Lu commit 7568fb63f57ac8672f8bf2018171255441238882 upstream. Tony found on his setup, if memory block size 512M will cause crash during booting. BUG: unable to handle kernel paging request at ffffea0074000020 IP: [] get_nid_for_pfn+0x17/0x40 PGD 128ffcb067 PUD 128ffc9067 PMD 0 Oops: 0000 [#1] SMP Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.2.0-rc8 #1 ... Call Trace: [] ? register_mem_sect_under_node+0x66/0xe0 [] register_one_node+0x17b/0x240 [] ? pci_iommu_alloc+0x6e/0x6e [] topology_init+0x3c/0x95 [] do_one_initcall+0xcd/0x1f0 The system has non continuous RAM address: BIOS-e820: [mem 0x0000001300000000-0x0000001cffffffff] usable BIOS-e820: [mem 0x0000001d70000000-0x0000001ec7ffefff] usable BIOS-e820: [mem 0x0000001f00000000-0x0000002bffffffff] usable BIOS-e820: [mem 0x0000002c18000000-0x0000002d6fffefff] usable BIOS-e820: [mem 0x0000002e00000000-0x00000039ffffffff] usable So there are start sections in memory block not present. For example: memory block : [0x2c18000000, 0x2c20000000) 512M first three sections are not present. Current register_mem_sect_under_node() assume first section is present, but memory block section number range [start_section_nr, end_section_nr] would include not present section. For arch that support vmemmap, we don't setup memmap for struct page area within not present sections area. So skip the pfn range that belong to absent section. Also fixes unregister_mem_sect_under_nodes() that assume one section per memory block. Reported-by: Tony Luck Tested-by: Tony Luck Fixes: bdee237c0343 ("x86: mm: Use 2GB memory block size on large memory x86-64 systems") Fixes: 982792c782ef ("x86, mm: probe memory block size for generic x86 64bit") Signed-off-by: Yinghai Lu Signed-off-by: Greg Kroah-Hartman Signed-off-by: Luis Henriques --- drivers/base/node.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/drivers/base/node.c b/drivers/base/node.c index 5777d10d1e25..7334e47996bc 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -397,7 +397,18 @@ int register_mem_sect_under_node(struct memory_block *mem_blk, int nid) sect_end_pfn = section_nr_to_pfn(mem_blk->end_section_nr); sect_end_pfn += PAGES_PER_SECTION - 1; for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) { - int page_nid; + int page_nid, scn_nr; + + /* + * memory block could have several absent sections from start. + * skip pfn range from absent section + */ + scn_nr = pfn_to_section_nr(pfn); + if (!present_section_nr(scn_nr)) { + pfn = round_down(pfn + PAGES_PER_SECTION, + PAGES_PER_SECTION) - 1; + continue; + } /* * memory block could have several absent sections from start. @@ -443,10 +454,22 @@ int unregister_mem_sect_under_nodes(struct memory_block *mem_blk, return -ENOMEM; nodes_clear(*unlinked_nodes); - sect_start_pfn = section_nr_to_pfn(phys_index); - sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1; + sect_start_pfn = section_nr_to_pfn(mem_blk->start_section_nr); + sect_end_pfn = section_nr_to_pfn(mem_blk->end_section_nr); + sect_end_pfn += PAGES_PER_SECTION - 1; for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) { - int nid; + int nid, scn_nr; + + /* + * memory block could have several absent sections from start. + * skip pfn range from absent section + */ + scn_nr = pfn_to_section_nr(pfn); + if (!present_section_nr(scn_nr)) { + pfn = round_down(pfn + PAGES_PER_SECTION, + PAGES_PER_SECTION) - 1; + continue; + } nid = get_nid_for_pfn(pfn); if (nid < 0)