From patchwork Fri Jan 17 10:57:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Hildenbrand X-Patchwork-Id: 1224744 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47zdPB1r6dz9sRK for ; Fri, 17 Jan 2020 21:59:42 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=M1Oh/bIj; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 47zdPB12CxzDqht for ; Fri, 17 Jan 2020 21:59:42 +1100 (AEDT) X-Original-To: linuxppc-dev@lists.ozlabs.org Delivered-To: linuxppc-dev@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=redhat.com (client-ip=207.211.31.81; helo=us-smtp-delivery-1.mimecast.com; envelope-from=david@redhat.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: lists.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=M1Oh/bIj; dkim-atps=neutral Received: from us-smtp-delivery-1.mimecast.com (us-smtp-2.mimecast.com [207.211.31.81]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 47zdMc2pMwzDqYM for ; Fri, 17 Jan 2020 21:58:19 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1579258696; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=pfb7ZqQ08slR2j6b3nkPpigirqDHm9QWjl/R0SsgtyU=; b=M1Oh/bIjH1exRu4qFdu1Olk8/8F4Un5bylx4YXTM83PqU/QvHI082Nwk/ubMVVBy/RNujO +PPg76vrBm9iglK5uL9TKcUkn2h2sb+ejx5rRD52fJzKn4Rrj+p+/p6h7ddTZXqi//pVLP bX8LXn1l+t/wCwACghMqqKiJvL6zq3o= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-221-Y1B2syKMNCWezWBqhccdsA-1; Fri, 17 Jan 2020 05:58:12 -0500 X-MC-Unique: Y1B2syKMNCWezWBqhccdsA-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id CB8D118C43E5; Fri, 17 Jan 2020 10:58:08 +0000 (UTC) Received: from t480s.redhat.com (ovpn-116-244.ams2.redhat.com [10.36.116.244]) by smtp.corp.redhat.com (Postfix) with ESMTP id D7254845D2; Fri, 17 Jan 2020 10:57:59 +0000 (UTC) From: David Hildenbrand To: linux-kernel@vger.kernel.org Subject: [PATCH RFC v1] mm: is_mem_section_removable() overhaul Date: Fri, 17 Jan 2020 11:57:59 +0100 Message-Id: <20200117105759.27905-1-david@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-BeenThere: linuxppc-dev@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Nathan Lynch , Stephen Rothwell , Michal Hocko , Thomas Gleixner , Anshuman Khandual , David Hildenbrand , Greg Kroah-Hartman , "Rafael J. Wysocki" , Dan Williams , linux-mm@kvack.org, Paul Mackerras , Leonardo Bras , Andrew Morton , linuxppc-dev@lists.ozlabs.org, Nathan Fontenot , Allison Randal , lantianyu1986@gmail.com Errors-To: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org Sender: "Linuxppc-dev" Let's refactor that code. We want to check if we can offline memory blocks. Add a new function is_mem_section_offlineable() for that and make it call is_mem_section_offlineable() for each contained section. Within is_mem_section_offlineable(), add some more sanity checks and directly bail out if the section contains holes or if it spans multiple zones. The old code was inherently racy with concurrent offlining/memory unplug. Let's avoid that and grab the device_hotplug_lock. Luckily we are already holding it when calling from powerpc code. Note1: If somebody wants to export this function for use in driver code, we need a variant that takes the device_hotplug_lock() Note2: If we could have a zombie device (not clear yet), the present section checks would properly bail out early. Note3: I'd prefer the mem_hotplug_lock in read, but as we are about to change the locking on the removal path (IOW, don't hold it when removing memory block devices), I do not want to go down that path. Note4: For now we would have returned "removable" although we would block offlining due to memory holes, multiple zones, or missing sections. Tested with DIMMs on x86-64. Compile-tested on Power. Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Michael Ellerman Cc: Greg Kroah-Hartman Cc: "Rafael J. Wysocki" Cc: Andrew Morton Cc: Leonardo Bras Cc: Nathan Lynch Cc: Allison Randal Cc: Nathan Fontenot Cc: Thomas Gleixner Cc: Michal Hocko Cc: Dan Williams Cc: Stephen Rothwell Cc: Anshuman Khandual Cc: lantianyu1986@gmail.com Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: David Hildenbrand --- .../platforms/pseries/hotplug-memory.c | 24 ++----- drivers/base/memory.c | 37 ++++++---- include/linux/memory.h | 1 + include/linux/memory_hotplug.h | 5 +- mm/memory_hotplug.c | 68 +++++++++---------- 5 files changed, 67 insertions(+), 68 deletions(-) diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index c126b94d1943..8d80159465e4 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -337,34 +337,24 @@ static int pseries_remove_mem_node(struct device_node *np) static bool lmb_is_removable(struct drmem_lmb *lmb) { - int i, scns_per_block; - bool rc = true; - unsigned long pfn, block_sz; - u64 phys_addr; + struct memory_block *mem; + bool rc = false; if (!(lmb->flags & DRCONF_MEM_ASSIGNED)) return false; - block_sz = memory_block_size_bytes(); - scns_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE; - phys_addr = lmb->base_addr; - #ifdef CONFIG_FA_DUMP /* * Don't hot-remove memory that falls in fadump boot memory area * and memory that is reserved for capturing old kernel memory. */ - if (is_fadump_memory_area(phys_addr, block_sz)) + if (is_fadump_memory_area(lmb->base_addr, memory_block_size_bytes())) return false; #endif - - for (i = 0; i < scns_per_block; i++) { - pfn = PFN_DOWN(phys_addr); - if (!pfn_present(pfn)) - continue; - - rc = rc && is_mem_section_removable(pfn, PAGES_PER_SECTION); - phys_addr += MIN_MEMORY_BLOCK_SIZE; + mem = lmb_to_memblock(lmb); + if (mem) { + rc = is_memory_block_offlineable(mem); + put_device(&mem->dev); } return rc; diff --git a/drivers/base/memory.c b/drivers/base/memory.c index c6d288fad493..f744250c34d0 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -104,6 +104,25 @@ static ssize_t phys_index_show(struct device *dev, return sprintf(buf, "%08lx\n", phys_index); } +/* + * Test if a memory block is likely to be offlineable. Returns true if + * the block is already offline. + * + * Called under device_hotplug_lock. + */ +bool is_memory_block_offlineable(struct memory_block *mem) +{ + int i; + + if (mem->state != MEM_ONLINE) + return true; + + for (i = 0; i < sections_per_block; i++) + if (!is_mem_section_offlineable(mem->start_section_nr + i)) + return false; + return true; +} + /* * Show whether the memory block is likely to be offlineable (or is already * offline). Once offline, the memory block could be removed. The return @@ -114,20 +133,14 @@ static ssize_t removable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct memory_block *mem = to_memory_block(dev); - unsigned long pfn; - int ret = 1, i; - - if (mem->state != MEM_ONLINE) - goto out; + int ret; - for (i = 0; i < sections_per_block; i++) { - if (!present_section_nr(mem->start_section_nr + i)) - continue; - pfn = section_nr_to_pfn(mem->start_section_nr + i); - ret &= is_mem_section_removable(pfn, PAGES_PER_SECTION); - } + ret = lock_device_hotplug_sysfs(); + if (ret) + return ret; + ret = is_memory_block_offlineable(mem); + unlock_device_hotplug(); -out: return sprintf(buf, "%d\n", ret); } diff --git a/include/linux/memory.h b/include/linux/memory.h index 0b8d791b6669..faf03eb64ecc 100644 --- a/include/linux/memory.h +++ b/include/linux/memory.h @@ -91,6 +91,7 @@ typedef int (*walk_memory_blocks_func_t)(struct memory_block *, void *); extern int walk_memory_blocks(unsigned long start, unsigned long size, void *arg, walk_memory_blocks_func_t func); extern int for_each_memory_block(void *arg, walk_memory_blocks_func_t func); +extern bool is_memory_block_offlineable(struct memory_block *mem); #define CONFIG_MEM_BLOCK_SIZE (PAGES_PER_SECTION<