From patchwork Mon Aug 20 09:35:25 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wen Congyang X-Patchwork-Id: 178720 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from ozlabs.org (localhost [IPv6:::1]) by ozlabs.org (Postfix) with ESMTP id 569372C0339 for ; Mon, 20 Aug 2012 19:33:23 +1000 (EST) Received: from song.cn.fujitsu.com (unknown [222.73.24.84]) by ozlabs.org (Postfix) with ESMTP id C2DD72C00BB for ; Mon, 20 Aug 2012 19:30:50 +1000 (EST) X-IronPort-AV: E=Sophos;i="4.77,796,1336320000"; d="scan'208";a="5672997" Received: from unknown (HELO tang.cn.fujitsu.com) ([10.167.250.3]) by song.cn.fujitsu.com with ESMTP; 20 Aug 2012 17:29:37 +0800 Received: from fnstmail02.fnst.cn.fujitsu.com (tang.cn.fujitsu.com [127.0.0.1]) by tang.cn.fujitsu.com (8.14.3/8.13.1) with ESMTP id q7K9UdnX021547; Mon, 20 Aug 2012 17:30:40 +0800 Received: from ghost.fnst.cn.fujitsu.com ([10.167.225.226]) by fnstmail02.fnst.cn.fujitsu.com (Lotus Domino Release 8.5.3) with ESMTP id 2012082017304192-378314 ; Mon, 20 Aug 2012 17:30:41 +0800 From: wency@cn.fujitsu.com To: linux-mm@kvack.org, linux-kernel@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, linux-acpi@vger.kernel.org, linux-s390@vger.kernel.org, linux-sh@vger.kernel.org, linux-ia64@vger.kernel.org, cmetcalf@tilera.com Subject: [RFC V7 PATCH 02/19] memory-hotplug: implement offline_memory() Date: Mon, 20 Aug 2012 17:35:25 +0800 Message-Id: <1345455342-27752-3-git-send-email-wency@cn.fujitsu.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1345455342-27752-1-git-send-email-wency@cn.fujitsu.com> References: <1345455342-27752-1-git-send-email-wency@cn.fujitsu.com> X-MIMETrack: Itemize by SMTP Server on mailserver/fnst(Release 8.5.3|September 15, 2011) at 2012/08/20 17:30:41, Serialize by Router on mailserver/fnst(Release 8.5.3|September 15, 2011) at 2012/08/20 17:30:46, Serialize complete at 2012/08/20 17:30:46 Cc: len.brown@intel.com, Wen Congyang , Vasilis Liaskovitis , isimatu.yasuaki@jp.fujitsu.com, paulus@samba.org, minchan.kim@gmail.com, kosaki.motohiro@jp.fujitsu.com, rientjes@google.com, cl@linux.com, akpm@linux-foundation.org, liuj97@gmail.com X-BeenThere: linuxppc-dev@lists.ozlabs.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org Sender: "Linuxppc-dev" From: Wen Congyang The function offline_memory() will be called when hot removing a memory device. The memory device may contain more than one memory block. If the memory block has been offlined, __offline_pages() will fail. So we should try to offline one memory block at a time. If the memory block is offlined in offline_memory(), we also update it's state, and notify the userspace that its state is changed. The function offline_memory() also check each memory block's state. So there is no need to check the memory block's state before calling offline_memory(). CC: David Rientjes CC: Jiang Liu CC: Len Brown CC: Benjamin Herrenschmidt CC: Paul Mackerras CC: Christoph Lameter Cc: Minchan Kim CC: Andrew Morton CC: KOSAKI Motohiro CC: Yasuaki Ishimatsu CC: Vasilis Liaskovitis Signed-off-by: Wen Congyang --- drivers/base/memory.c | 31 +++++++++++++++++++++++++++---- include/linux/memory_hotplug.h | 2 ++ mm/memory_hotplug.c | 37 ++++++++++++++++++++++++++++++++++++- 3 files changed, 65 insertions(+), 5 deletions(-) diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 44e7de6..86c8821 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -275,13 +275,11 @@ memory_block_action(unsigned long phys_index, unsigned long action) return ret; } -static int memory_block_change_state(struct memory_block *mem, +static int __memory_block_change_state(struct memory_block *mem, unsigned long to_state, unsigned long from_state_req) { int ret = 0; - mutex_lock(&mem->state_mutex); - if (mem->state != from_state_req) { ret = -EINVAL; goto out; @@ -309,10 +307,20 @@ static int memory_block_change_state(struct memory_block *mem, break; } out: - mutex_unlock(&mem->state_mutex); return ret; } +static int memory_block_change_state(struct memory_block *mem, + unsigned long to_state, unsigned long from_state_req) +{ + int ret; + + mutex_lock(&mem->state_mutex); + ret = __memory_block_change_state(mem, to_state, from_state_req); + mutex_unlock(&mem->state_mutex); + + return ret; +} static ssize_t store_mem_state(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -653,6 +661,21 @@ int unregister_memory_section(struct mem_section *section) } /* + * offline one memory block. If the memory block has been offlined, do nothing. + */ +int offline_memory_block(struct memory_block *mem) +{ + int ret = 0; + + mutex_lock(&mem->state_mutex); + if (mem->state != MEM_OFFLINE) + ret = __memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE); + mutex_unlock(&mem->state_mutex); + + return ret; +} + +/* * Initialize the sysfs support for memory devices... */ int __init memory_dev_init(void) diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h index c183f39..0b040bb 100644 --- a/include/linux/memory_hotplug.h +++ b/include/linux/memory_hotplug.h @@ -10,6 +10,7 @@ struct page; struct zone; struct pglist_data; struct mem_section; +struct memory_block; #ifdef CONFIG_MEMORY_HOTPLUG @@ -234,6 +235,7 @@ extern int mem_online_node(int nid); extern int add_memory(int nid, u64 start, u64 size); extern int arch_add_memory(int nid, u64 start, u64 size); extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages); +extern int offline_memory_block(struct memory_block *mem); extern int offline_memory(u64 start, u64 size); extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn, int nr_pages); diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index c182c76..3113cd4 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -1001,7 +1001,42 @@ int offline_pages(unsigned long start_pfn, unsigned long nr_pages) int offline_memory(u64 start, u64 size) { - return -EINVAL; + struct memory_block *mem = NULL; + struct mem_section *section; + unsigned long start_pfn, end_pfn; + unsigned long pfn, section_nr; + int ret; + + start_pfn = PFN_DOWN(start); + end_pfn = start_pfn + PFN_DOWN(size); + + for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { + section_nr = pfn_to_section_nr(pfn); + if (!present_section_nr(section_nr)) + continue; + + section = __nr_to_section(section_nr); + /* same memblock? */ + if (mem) + if ((section_nr >= mem->start_section_nr) && + (section_nr <= mem->end_section_nr)) + continue; + + mem = find_memory_block_hinted(section, mem); + if (!mem) + continue; + + ret = offline_memory_block(mem); + if (ret) { + kobject_put(&mem->dev.kobj); + return ret; + } + } + + if (mem) + kobject_put(&mem->dev.kobj); + + return 0; } #else int offline_pages(u64 start, u64 size)