From patchwork Mon Aug 24 04:04:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anshuman Khandual X-Patchwork-Id: 11732161 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id ECFA313A4 for ; Mon, 24 Aug 2020 04:08:14 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B7C5E20768 for ; Mon, 24 Aug 2020 04:08:14 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="Ap4ZL3hU" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B7C5E20768 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=arm.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:MIME-Version:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References:List-Owner; bh=RCi/bX7LYFuajTBQ4NInatd0zE+gXww+FPqTtSVd7Rs=; b=Ap4ZL3hU4aryveD/0fn2AjUqMr QA2NAZqguy6T5OmQYDClSNXY1GSY96j/QDny/b79pLMhlV3iVLdFUkXn1yK5OSzZRBnUd6Dc7ga+L uwEepFp7K44vbAQ3RI89uHyBWOPadZf36QjfhcxVuUCqbuWxjG5xyPf+aYbfQszIua8jCb95Qv/Pl 6nIC8HQzpaehz+66jz8gPngbgU1ZW7236a3P6hwhJoT/xKF3J5s6cZwn/LNyT2CQh3ID6Eqb/RJSF b18H43B8g1UH3llMGCvWeI+dSxszjjiRLXiHjufPhmwqOPzsH/o2t2C3H8CrudpLEMGcnxmj5tws+ ItRWYBPw==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kA3jg-0003Ya-0B; Mon, 24 Aug 2020 04:05:32 +0000 Received: from foss.arm.com ([217.140.110.172]) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kA3jd-0003Y9-3a for linux-arm-kernel@lists.infradead.org; Mon, 24 Aug 2020 04:05:30 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 64F111063; Sun, 23 Aug 2020 21:05:18 -0700 (PDT) Received: from p8cg001049571a15.arm.com (unknown [10.163.67.29]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 6BBF53F66B; Sun, 23 Aug 2020 21:05:15 -0700 (PDT) From: Anshuman Khandual To: linux-arm-kernel@lists.infradead.org Subject: [PATCH V2] arm64/hotplug: Improve memory offline event notifier Date: Mon, 24 Aug 2020 09:34:29 +0530 Message-Id: <1598241869-28416-1-git-send-email-anshuman.khandual@arm.com> X-Mailer: git-send-email 2.7.4 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200824_000529_315588_0E0FB57B X-CRM114-Status: GOOD ( 27.53 ) X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at https://www.dnswl.org/, medium trust [217.140.110.172 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Will Deacon , Steve Capper , Catalin Marinas , Anshuman Khandual , linux-kernel@vger.kernel.org, Mark Brown , Marc Zyngier MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org This brings about three different changes to the sole memory event notifier for arm64 platform and improves it's robustness while also enhancing debug capabilities during potential memory offlining error conditions. This moves the memory notifier registration bit earlier in the boot process from device_initcall() to setup_arch() which will help in guarding against potential early boot memory offline requests. This enables MEM_OFFLINE memory event handling. It will help intercept any possible error condition such as if boot memory some how still got offlined even after an expilicit notifier failure, potentially by a future change in generic hotplug framework. This would help detect such scenarious and help debug further. It also adds a validation function which scans entire boot memory and makes sure that early memory sections are online. This check is essential for the memory notifier to work properly as it cannot prevent boot memory offlining if they are not online to begin with. But this additional sanity check is enabled only with DEBUG_VM. Cc: Catalin Marinas Cc: Will Deacon Cc: Mark Rutland Cc: Marc Zyngier Cc: Steve Capper Cc: Mark Brown Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Anshuman Khandual --- This applies on 5.9-rc2 Changes in V2: - Dropped all generic changes wrt MEM_CANCEL_OFFLINE reasons enumeration - Dropped all related (processing MEM_CANCEL_OFFLINE reasons) changes on arm64 - Added validate_boot_mem_online_state() that gets called with early_initcall() - Added CONFIG_MEMORY_HOTREMOVE check before registering memory notifier - Moved notifier registration i.e memory_hotremove_notifier into setup_arch() Changes in V1: (https://patchwork.kernel.org/project/linux-mm/list/?series=271237) arch/arm64/include/asm/mmu.h | 8 +++ arch/arm64/kernel/setup.c | 8 +++ arch/arm64/mm/mmu.c | 108 ++++++++++++++++++++++++++++++++--- 3 files changed, 116 insertions(+), 8 deletions(-) diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index a7a5ecaa2e83..b7e99b528766 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h @@ -73,6 +73,14 @@ static inline struct bp_hardening_data *arm64_get_bp_hardening_data(void) static inline void arm64_apply_bp_hardening(void) { } #endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */ +#ifdef CONFIG_MEMORY_HOTPLUG +extern void memory_hotremove_notifier(void); +#else +static inline void memory_hotremove_notifier(void) +{ +} +#endif /* CONFIG_MEMORY_HOTPLUG */ + extern void arm64_memblock_init(void); extern void paging_init(void); extern void bootmem_init(void); diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 77c4c9bad1b8..44406c9f8d83 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -376,6 +376,14 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p) "This indicates a broken bootloader or old kernel\n", boot_args[1], boot_args[2], boot_args[3]); } + + /* + * Register the memory notifier which will prevent boot + * memory offlining requests - early enough. But there + * should not be any actual offlinig request till memory + * block devices are initialized with memory_dev_init(). + */ + memory_hotremove_notifier(); } static inline bool cpu_can_disable(unsigned int cpu) diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 75df62fea1b6..8cdb0b02089f 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -1482,13 +1482,40 @@ static int prevent_bootmem_remove_notifier(struct notifier_block *nb, unsigned long end_pfn = arg->start_pfn + arg->nr_pages; unsigned long pfn = arg->start_pfn; - if (action != MEM_GOING_OFFLINE) + if ((action != MEM_GOING_OFFLINE) && (action != MEM_OFFLINE)) return NOTIFY_OK; - for (; pfn < end_pfn; pfn += PAGES_PER_SECTION) { - ms = __pfn_to_section(pfn); - if (early_section(ms)) - return NOTIFY_BAD; + if (action == MEM_GOING_OFFLINE) { + for (; pfn < end_pfn; pfn += PAGES_PER_SECTION) { + ms = __pfn_to_section(pfn); + if (early_section(ms)) { + pr_warn("Boot memory offlining attempted\n"); + return NOTIFY_BAD; + } + } + } else if (action == MEM_OFFLINE) { + for (; pfn < end_pfn; pfn += PAGES_PER_SECTION) { + ms = __pfn_to_section(pfn); + if (early_section(ms)) { + + /* + * This should have never happened. Boot memory + * offlining should have been prevented by this + * very notifier. Probably some memory removal + * procedure might have changed which would then + * require further debug. + */ + pr_err("Boot memory offlined\n"); + + /* + * Core memory hotplug does not process a return + * code from the notifier for MEM_OFFLINE event. + * Error condition has been reported. Report as + * ignored. + */ + return NOTIFY_DONE; + } + } } return NOTIFY_OK; } @@ -1497,9 +1524,74 @@ static struct notifier_block prevent_bootmem_remove_nb = { .notifier_call = prevent_bootmem_remove_notifier, }; -static int __init prevent_bootmem_remove_init(void) +void memory_hotremove_notifier(void) { - return register_memory_notifier(&prevent_bootmem_remove_nb); + int rc; + + if (!IS_ENABLED(CONFIG_MEMORY_HOTREMOVE)) + return; + + rc = register_memory_notifier(&prevent_bootmem_remove_nb); + if (!rc) + return; + + pr_err("Notifier registration failed - boot memory can be removed\n"); +} + +/* + * This ensures that boot memory sections on the plaltform are online + * during early boot. They could not be prevented from being offlined + * if for some reason they are not brought online to begin with. This + * help validate the basic assumption on which the above memory event + * notifier works to prevent boot memory offlining and it's possible + * removal. + */ +static int __init validate_bootmem_online_state(void) +{ + struct memblock_region *mblk; + struct mem_section *ms; + unsigned long pfn, end_pfn, start, end; + + /* + * Scanning across all memblock might be expensive + * on some big memory systems. Hence enable this + * validation only with DEBUG_VM. + */ + if (!IS_ENABLED(CONFIG_MEMORY_HOTREMOVE) || + !IS_ENABLED(CONFIG_DEBUG_VM)) + return 0; + + for_each_memblock(memory, mblk) { + pfn = PHYS_PFN(mblk->base); + end_pfn = PHYS_PFN(mblk->base + mblk->size); + + for (; pfn < end_pfn; pfn += PAGES_PER_SECTION) { + ms = __pfn_to_section(pfn); + + /* + * All memory ranges in the system at this point + * should have been marked early sections. + */ + WARN_ON(!early_section(ms)); + + /* + * Memory notifier mechanism here to prevent boot + * memory offlining depends on the fact that each + * early section memory on the system is intially + * online. Otherwise a given memory section which + * is already offline will be overlooked and can + * be removed completely. Call out such sections. + */ + if (!online_section(ms)) { + start = PFN_PHYS(pfn); + end = start + (1UL << PA_SECTION_SHIFT); + + pr_err("Memory range [%lx %lx] is offline\n", start, end); + pr_err("Memory range [%lx %lx] can be removed\n", start, end); + } + } + } + return 0; } -device_initcall(prevent_bootmem_remove_init); +early_initcall(validate_bootmem_online_state); #endif