From patchwork Thu Aug 3 21:23:43 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Tatashin X-Patchwork-Id: 9879895 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id EC2D16088A for ; Thu, 3 Aug 2017 21:43:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E63A02896C for ; Thu, 3 Aug 2017 21:43:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DAC5E28973; Thu, 3 Aug 2017 21:43:30 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-1.4 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,RCVD_IN_SORBS_SPAM,UNPARSEABLE_RELAY autolearn=no version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id DFB522896C for ; Thu, 3 Aug 2017 21:43:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:List-Subscribe:List-Help: List-Post:List-Archive:List-Unsubscribe:List-Id:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Cc:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=Y21YeneiwDMCTEf6gMD6Z7iO6PSjWNHnUBpuxcv74/c=; b=daAxHd/LR2EYu2 y6WZ0982SPfdhoy6iuaZuN0fhoAJbn0RuObCtzaEPEWw76c/vfs+HW/Ub+XCCoewSKL9WZ/Gd8Ub4 mqPK/NnfsG10EIRBmnN/buR7Z/l56xgIvbt3ymaa7WFfqbmt7rnbGJciiz2/v/FuKuWzoBRbehmKK WhzgIQfwTEFdzQ42rTVOz9DcfhrKmqWKcohO0w1/BgM+cPPeR/FBqiv9NPUQIXpCC2oN31XflboLh 9PK3IDM5tCxi+ICKsbzZ3wFoVJblI7x20KPhV6PRB9NFlE5TeEEb+aPJ0Sge4ZhpYUxr4LFso1OQF Y7K0LrKSTErfkBW/wwuQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1ddNto-0000yt-5S; Thu, 03 Aug 2017 21:43:20 +0000 Received: from casper.infradead.org ([85.118.1.10]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1ddNcV-0005Pr-9R for linux-arm-kernel@bombadil.infradead.org; Thu, 03 Aug 2017 21:25:27 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=References:In-Reply-To:Message-Id:Date: Subject:To:From:Sender:Reply-To:Cc:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id: List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=V/qpaMCIFQxd9g0iPwp5wWPP8TisLV3zwficQ3m2kOo=; b=V8qzVPU3lt4qqLv8q5YloPUyK GRDxGJ+ZT0yUZ5NYih5bgQd1UXJgRTx/XWX0meR6tjU/YGQNhtoZYDgjXEaxblpIIBr0thC+nym2j HqnQI1jJnDUQr/WsBKBscS7OaFg+oOxQihWEN8JMFYv3mmWNJEZNi7aUZDOz/kDFrrwXNbrlb/wVv RxxHIadn2HYr3dTU7afvHNvvLlDgCkX9S94tj7YHC/FCWm71wqYcJeOLn4e9UlKCeJkgnkD8Fdw68 +XysDU9sxFxZ8NxiI+/LHKGvvkIenuU4YneJjEmZPlrqqIKUdUrVviNGqMhyv+vNNE7KlZKAUMKxb eqo0jmt+A==; Received: from aserp1040.oracle.com ([141.146.126.69]) by casper.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1ddNcP-0007N1-Rn for linux-arm-kernel@lists.infradead.org; Thu, 03 Aug 2017 21:25:26 +0000 Received: from aserv0021.oracle.com (aserv0021.oracle.com [141.146.126.233]) by aserp1040.oracle.com (Sentrion-MTA-4.3.2/Sentrion-MTA-4.3.2) with ESMTP id v73LO8IE002418 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 3 Aug 2017 21:24:09 GMT Received: from userv0122.oracle.com (userv0122.oracle.com [156.151.31.75]) by aserv0021.oracle.com (8.14.4/8.14.4) with ESMTP id v73LO8GI011814 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 3 Aug 2017 21:24:08 GMT Received: from abhmp0004.oracle.com (abhmp0004.oracle.com [141.146.116.10]) by userv0122.oracle.com (8.14.4/8.14.4) with ESMTP id v73LO7mG010374; Thu, 3 Aug 2017 21:24:07 GMT Received: from ca-ldom-ol-build-1.us.oracle.com (/10.129.68.23) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Thu, 03 Aug 2017 14:24:06 -0700 From: Pavel Tatashin To: linux-kernel@vger.kernel.org, sparclinux@vger.kernel.org, linux-mm@kvack.org, linuxppc-dev@lists.ozlabs.org, linux-s390@vger.kernel.org, linux-arm-kernel@lists.infradead.org, x86@kernel.org, kasan-dev@googlegroups.com, borntraeger@de.ibm.com, heiko.carstens@de.ibm.com, davem@davemloft.net, willy@infradead.org, mhocko@kernel.org Subject: [v5 05/15] mm: don't accessed uninitialized struct pages Date: Thu, 3 Aug 2017 17:23:43 -0400 Message-Id: <1501795433-982645-6-git-send-email-pasha.tatashin@oracle.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1501795433-982645-1-git-send-email-pasha.tatashin@oracle.com> References: <1501795433-982645-1-git-send-email-pasha.tatashin@oracle.com> X-Source-IP: aserv0021.oracle.com [141.146.126.233] X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20170803_222522_343795_22C4933D X-CRM114-Status: GOOD ( 21.80 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP In deferred_init_memmap() where all deferred struct pages are initialized we have a check like this: if (page->flags) { VM_BUG_ON(page_zone(page) != zone); goto free_range; } This way we are checking if the current deferred page has already been initialized. It works, because memory for struct pages has been zeroed, and the only way flags are not zero if it went through __init_single_page() before. But, once we change the current behavior and won't zero the memory in memblock allocator, we cannot trust anything inside "struct page"es until they are initialized. This patch fixes this. This patch defines a new accessor memblock_get_reserved_pfn_range() which returns successive ranges of reserved PFNs. deferred_init_memmap() calls it to determine if a PFN and its struct page has already been initialized. Signed-off-by: Pavel Tatashin Reviewed-by: Steven Sistare Reviewed-by: Daniel Jordan Reviewed-by: Bob Picco --- include/linux/memblock.h | 3 +++ mm/memblock.c | 54 ++++++++++++++++++++++++++++++++++++++++++------ mm/page_alloc.c | 11 +++++++++- 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/include/linux/memblock.h b/include/linux/memblock.h index bae11c7e7bf3..b6a2a610f5e1 100644 --- a/include/linux/memblock.h +++ b/include/linux/memblock.h @@ -320,6 +320,9 @@ int memblock_is_map_memory(phys_addr_t addr); int memblock_is_region_memory(phys_addr_t base, phys_addr_t size); bool memblock_is_reserved(phys_addr_t addr); bool memblock_is_region_reserved(phys_addr_t base, phys_addr_t size); +void memblock_get_reserved_pfn_range(unsigned long pfn, + unsigned long *pfn_start, + unsigned long *pfn_end); extern void __memblock_dump_all(void); diff --git a/mm/memblock.c b/mm/memblock.c index 3a2707914064..e6df054e3180 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -1580,7 +1580,13 @@ void __init memblock_mem_limit_remove_map(phys_addr_t limit) memblock_cap_memory_range(0, max_addr); } -static int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr) +/** + * Return index in regions array if addr is within the region. Otherwise + * return -1. If -1 is returned and *next_idx is not %NULL, sets it to the + * next region index or -1 if there is none. + */ +static int __init_memblock memblock_search(struct memblock_type *type, + phys_addr_t addr, int *next_idx) { unsigned int left = 0, right = type->cnt; @@ -1595,22 +1601,26 @@ static int __init_memblock memblock_search(struct memblock_type *type, phys_addr else return mid; } while (left < right); + + if (next_idx) + *next_idx = (right == type->cnt) ? -1 : right; + return -1; } bool __init memblock_is_reserved(phys_addr_t addr) { - return memblock_search(&memblock.reserved, addr) != -1; + return memblock_search(&memblock.reserved, addr, NULL) != -1; } bool __init_memblock memblock_is_memory(phys_addr_t addr) { - return memblock_search(&memblock.memory, addr) != -1; + return memblock_search(&memblock.memory, addr, NULL) != -1; } int __init_memblock memblock_is_map_memory(phys_addr_t addr) { - int i = memblock_search(&memblock.memory, addr); + int i = memblock_search(&memblock.memory, addr, NULL); if (i == -1) return false; @@ -1622,7 +1632,7 @@ int __init_memblock memblock_search_pfn_nid(unsigned long pfn, unsigned long *start_pfn, unsigned long *end_pfn) { struct memblock_type *type = &memblock.memory; - int mid = memblock_search(type, PFN_PHYS(pfn)); + int mid = memblock_search(type, PFN_PHYS(pfn), NULL); if (mid == -1) return -1; @@ -1646,7 +1656,7 @@ int __init_memblock memblock_search_pfn_nid(unsigned long pfn, */ int __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size) { - int idx = memblock_search(&memblock.memory, base); + int idx = memblock_search(&memblock.memory, base, NULL); phys_addr_t end = base + memblock_cap_size(base, &size); if (idx == -1) @@ -1656,6 +1666,38 @@ int __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size } /** + * memblock_get_reserved_pfn_range - search for the next reserved region + * + * @pfn: start searching from this pfn. + * + * RETURNS: + * [start_pfn, end_pfn), where start_pfn >= pfn. If none is found + * start_pfn, and end_pfn are both set to ULONG_MAX. + */ +void __init_memblock memblock_get_reserved_pfn_range(unsigned long pfn, + unsigned long *start_pfn, + unsigned long *end_pfn) +{ + struct memblock_type *type = &memblock.reserved; + int next_idx, idx; + + idx = memblock_search(type, PFN_PHYS(pfn), &next_idx); + if (idx == -1 && next_idx == -1) { + *start_pfn = ULONG_MAX; + *end_pfn = ULONG_MAX; + return; + } + + if (idx == -1) { + idx = next_idx; + *start_pfn = PFN_DOWN(type->regions[idx].base); + } else { + *start_pfn = pfn; + } + *end_pfn = PFN_DOWN(type->regions[idx].base + type->regions[idx].size); +} + +/** * memblock_is_region_reserved - check if a region intersects reserved memory * @base: base of region to check * @size: size of region to check diff --git a/mm/page_alloc.c b/mm/page_alloc.c index f1e84d8f1e37..05110ae50aca 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1447,6 +1447,7 @@ static int __init deferred_init_memmap(void *data) pg_data_t *pgdat = data; int nid = pgdat->node_id; struct mminit_pfnnid_cache nid_init_state = { }; + unsigned long resv_start_pfn = 0, resv_end_pfn = 0; unsigned long start = jiffies; unsigned long nr_pages = 0; unsigned long walk_start, walk_end; @@ -1491,6 +1492,10 @@ static int __init deferred_init_memmap(void *data) pfn = zone->zone_start_pfn; for (; pfn < end_pfn; pfn++) { + if (pfn >= resv_end_pfn) + memblock_get_reserved_pfn_range(pfn, + &resv_start_pfn, + &resv_end_pfn); if (!pfn_valid_within(pfn)) goto free_range; @@ -1524,7 +1529,11 @@ static int __init deferred_init_memmap(void *data) cond_resched(); } - if (page->flags) { + /* + * Check if this page has already been initialized due + * to being reserved during boot in memblock. + */ + if (pfn >= resv_start_pfn) { VM_BUG_ON(page_zone(page) != zone); goto free_range; }