aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWen Congyang <wency@cn.fujitsu.com>2012-10-08 19:34:01 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-09 03:23:02 -0400
commite90bdb7f52f94204c78fb40b0804645defdebd71 (patch)
tree4acb09ecd1f98fd98408f18e816d075601585d2a
parenta16cee10c7ab994546ed98d9abfd4de74050124a (diff)
memory-hotplug: update memory block's state and notify userspace
remove_memory() will be called when hot removing a memory device. But even if offlining memory, we cannot notice it. So the patch updates the memory block's state and sends notification to userspace. Additionally, 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. Thus remove_memory() also check each memory block's state. So there is no need to check the memory block's state before calling remove_memory(). Signed-off-by: Wen Congyang <wency@cn.fujitsu.com> Signed-off-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com> Cc: David Rientjes <rientjes@google.com> Cc: Jiang Liu <liuj97@gmail.com> Cc: Len Brown <len.brown@intel.com> Cc: Christoph Lameter <cl@linux.com> Cc: Minchan Kim <minchan.kim@gmail.com> Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/base/memory.c31
-rw-r--r--include/linux/memory_hotplug.h2
-rw-r--r--mm/memory_hotplug.c33
3 files changed, 61 insertions, 5 deletions
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 44e7de6ce69..86c88216a50 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)
275 return ret; 275 return ret;
276} 276}
277 277
278static int memory_block_change_state(struct memory_block *mem, 278static int __memory_block_change_state(struct memory_block *mem,
279 unsigned long to_state, unsigned long from_state_req) 279 unsigned long to_state, unsigned long from_state_req)
280{ 280{
281 int ret = 0; 281 int ret = 0;
282 282
283 mutex_lock(&mem->state_mutex);
284
285 if (mem->state != from_state_req) { 283 if (mem->state != from_state_req) {
286 ret = -EINVAL; 284 ret = -EINVAL;
287 goto out; 285 goto out;
@@ -309,10 +307,20 @@ static int memory_block_change_state(struct memory_block *mem,
309 break; 307 break;
310 } 308 }
311out: 309out:
312 mutex_unlock(&mem->state_mutex);
313 return ret; 310 return ret;
314} 311}
315 312
313static int memory_block_change_state(struct memory_block *mem,
314 unsigned long to_state, unsigned long from_state_req)
315{
316 int ret;
317
318 mutex_lock(&mem->state_mutex);
319 ret = __memory_block_change_state(mem, to_state, from_state_req);
320 mutex_unlock(&mem->state_mutex);
321
322 return ret;
323}
316static ssize_t 324static ssize_t
317store_mem_state(struct device *dev, 325store_mem_state(struct device *dev,
318 struct device_attribute *attr, const char *buf, size_t count) 326 struct device_attribute *attr, const char *buf, size_t count)
@@ -653,6 +661,21 @@ int unregister_memory_section(struct mem_section *section)
653} 661}
654 662
655/* 663/*
664 * offline one memory block. If the memory block has been offlined, do nothing.
665 */
666int offline_memory_block(struct memory_block *mem)
667{
668 int ret = 0;
669
670 mutex_lock(&mem->state_mutex);
671 if (mem->state != MEM_OFFLINE)
672 ret = __memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE);
673 mutex_unlock(&mem->state_mutex);
674
675 return ret;
676}
677
678/*
656 * Initialize the sysfs support for memory devices... 679 * Initialize the sysfs support for memory devices...
657 */ 680 */
658int __init memory_dev_init(void) 681int __init memory_dev_init(void)
diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
index e64fe80eba9..95573ec4ee6 100644
--- a/include/linux/memory_hotplug.h
+++ b/include/linux/memory_hotplug.h
@@ -10,6 +10,7 @@ struct page;
10struct zone; 10struct zone;
11struct pglist_data; 11struct pglist_data;
12struct mem_section; 12struct mem_section;
13struct memory_block;
13 14
14#ifdef CONFIG_MEMORY_HOTPLUG 15#ifdef CONFIG_MEMORY_HOTPLUG
15 16
@@ -234,6 +235,7 @@ extern int mem_online_node(int nid);
234extern int add_memory(int nid, u64 start, u64 size); 235extern int add_memory(int nid, u64 start, u64 size);
235extern int arch_add_memory(int nid, u64 start, u64 size); 236extern int arch_add_memory(int nid, u64 start, u64 size);
236extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages); 237extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages);
238extern int offline_memory_block(struct memory_block *mem);
237extern int remove_memory(u64 start, u64 size); 239extern int remove_memory(u64 start, u64 size);
238extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn, 240extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn,
239 int nr_pages); 241 int nr_pages);
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index dfc0a6134c7..7d0797475a4 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1014,11 +1014,42 @@ int offline_pages(unsigned long start_pfn, unsigned long nr_pages)
1014 1014
1015int remove_memory(u64 start, u64 size) 1015int remove_memory(u64 start, u64 size)
1016{ 1016{
1017 struct memory_block *mem = NULL;
1018 struct mem_section *section;
1017 unsigned long start_pfn, end_pfn; 1019 unsigned long start_pfn, end_pfn;
1020 unsigned long pfn, section_nr;
1021 int ret;
1018 1022
1019 start_pfn = PFN_DOWN(start); 1023 start_pfn = PFN_DOWN(start);
1020 end_pfn = start_pfn + PFN_DOWN(size); 1024 end_pfn = start_pfn + PFN_DOWN(size);
1021 return __offline_pages(start_pfn, end_pfn, 120 * HZ); 1025
1026 for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
1027 section_nr = pfn_to_section_nr(pfn);
1028 if (!present_section_nr(section_nr))
1029 continue;
1030
1031 section = __nr_to_section(section_nr);
1032 /* same memblock? */
1033 if (mem)
1034 if ((section_nr >= mem->start_section_nr) &&
1035 (section_nr <= mem->end_section_nr))
1036 continue;
1037
1038 mem = find_memory_block_hinted(section, mem);
1039 if (!mem)
1040 continue;
1041
1042 ret = offline_memory_block(mem);
1043 if (ret) {
1044 kobject_put(&mem->dev.kobj);
1045 return ret;
1046 }
1047 }
1048
1049 if (mem)
1050 kobject_put(&mem->dev.kobj);
1051
1052 return 0;
1022} 1053}
1023#else 1054#else
1024int offline_pages(unsigned long start_pfn, unsigned long nr_pages) 1055int offline_pages(unsigned long start_pfn, unsigned long nr_pages)