diff options
author | Tang Chen <tangchen@cn.fujitsu.com> | 2013-02-22 19:33:14 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-23 20:50:13 -0500 |
commit | 60a5a19e7419ba0bc22ed01b3285e8940b42944c (patch) | |
tree | ab50aec968bd3386c53c8611f9e0215910daa6bd | |
parent | 815121d2b5cd56f1757d4468dc3abadd06a0ed6b (diff) |
memory-hotplug: remove sysfs file of node
Introduce a new function try_offline_node() to remove sysfs file of node
when all memory sections of this node are removed. If some memory
sections of this node are not removed, this function does nothing.
Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
Signed-off-by: Tang Chen <tangchen@cn.fujitsu.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Jiang Liu <jiang.liu@huawei.com>
Cc: Jianguo Wu <wujianguo@huawei.com>
Cc: Kamezawa Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Lai Jiangshan <laijs@cn.fujitsu.com>
Cc: Wu Jianguo <wujianguo@huawei.com>
Cc: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/acpi/acpi_memhotplug.c | 8 | ||||
-rw-r--r-- | include/linux/memory_hotplug.h | 2 | ||||
-rw-r--r-- | mm/memory_hotplug.c | 58 |
3 files changed, 63 insertions, 5 deletions
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index 034d3e72aa92..da1f82b445e0 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c | |||
@@ -280,9 +280,11 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) | |||
280 | 280 | ||
281 | static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device) | 281 | static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device) |
282 | { | 282 | { |
283 | int result = 0; | 283 | int result = 0, nid; |
284 | struct acpi_memory_info *info, *n; | 284 | struct acpi_memory_info *info, *n; |
285 | 285 | ||
286 | nid = acpi_get_node(mem_device->device->handle); | ||
287 | |||
286 | list_for_each_entry_safe(info, n, &mem_device->res_list, list) { | 288 | list_for_each_entry_safe(info, n, &mem_device->res_list, list) { |
287 | if (info->failed) | 289 | if (info->failed) |
288 | /* The kernel does not use this memory block */ | 290 | /* The kernel does not use this memory block */ |
@@ -295,7 +297,9 @@ static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device) | |||
295 | */ | 297 | */ |
296 | return -EBUSY; | 298 | return -EBUSY; |
297 | 299 | ||
298 | result = remove_memory(info->start_addr, info->length); | 300 | if (nid < 0) |
301 | nid = memory_add_physaddr_to_nid(info->start_addr); | ||
302 | result = remove_memory(nid, info->start_addr, info->length); | ||
299 | if (result) | 303 | if (result) |
300 | return result; | 304 | return result; |
301 | 305 | ||
diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h index 4d523fe75ba1..69903ccf549e 100644 --- a/include/linux/memory_hotplug.h +++ b/include/linux/memory_hotplug.h | |||
@@ -248,7 +248,7 @@ extern int arch_add_memory(int nid, u64 start, u64 size); | |||
248 | extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages); | 248 | extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages); |
249 | extern int offline_memory_block(struct memory_block *mem); | 249 | extern int offline_memory_block(struct memory_block *mem); |
250 | extern bool is_memblock_offlined(struct memory_block *mem); | 250 | extern bool is_memblock_offlined(struct memory_block *mem); |
251 | extern int remove_memory(u64 start, u64 size); | 251 | extern int remove_memory(int nid, u64 start, u64 size); |
252 | extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn, | 252 | extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn, |
253 | int nr_pages); | 253 | int nr_pages); |
254 | extern void sparse_remove_one_section(struct zone *zone, struct mem_section *ms); | 254 | extern void sparse_remove_one_section(struct zone *zone, struct mem_section *ms); |
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 3f792375f326..aea6374f435a 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/suspend.h> | 29 | #include <linux/suspend.h> |
30 | #include <linux/mm_inline.h> | 30 | #include <linux/mm_inline.h> |
31 | #include <linux/firmware-map.h> | 31 | #include <linux/firmware-map.h> |
32 | #include <linux/stop_machine.h> | ||
32 | 33 | ||
33 | #include <asm/tlbflush.h> | 34 | #include <asm/tlbflush.h> |
34 | 35 | ||
@@ -1679,7 +1680,58 @@ static int is_memblock_offlined_cb(struct memory_block *mem, void *arg) | |||
1679 | return ret; | 1680 | return ret; |
1680 | } | 1681 | } |
1681 | 1682 | ||
1682 | int __ref remove_memory(u64 start, u64 size) | 1683 | static int check_cpu_on_node(void *data) |
1684 | { | ||
1685 | struct pglist_data *pgdat = data; | ||
1686 | int cpu; | ||
1687 | |||
1688 | for_each_present_cpu(cpu) { | ||
1689 | if (cpu_to_node(cpu) == pgdat->node_id) | ||
1690 | /* | ||
1691 | * the cpu on this node isn't removed, and we can't | ||
1692 | * offline this node. | ||
1693 | */ | ||
1694 | return -EBUSY; | ||
1695 | } | ||
1696 | |||
1697 | return 0; | ||
1698 | } | ||
1699 | |||
1700 | /* offline the node if all memory sections of this node are removed */ | ||
1701 | static void try_offline_node(int nid) | ||
1702 | { | ||
1703 | unsigned long start_pfn = NODE_DATA(nid)->node_start_pfn; | ||
1704 | unsigned long end_pfn = start_pfn + NODE_DATA(nid)->node_spanned_pages; | ||
1705 | unsigned long pfn; | ||
1706 | |||
1707 | for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { | ||
1708 | unsigned long section_nr = pfn_to_section_nr(pfn); | ||
1709 | |||
1710 | if (!present_section_nr(section_nr)) | ||
1711 | continue; | ||
1712 | |||
1713 | if (pfn_to_nid(pfn) != nid) | ||
1714 | continue; | ||
1715 | |||
1716 | /* | ||
1717 | * some memory sections of this node are not removed, and we | ||
1718 | * can't offline node now. | ||
1719 | */ | ||
1720 | return; | ||
1721 | } | ||
1722 | |||
1723 | if (stop_machine(check_cpu_on_node, NODE_DATA(nid), NULL)) | ||
1724 | return; | ||
1725 | |||
1726 | /* | ||
1727 | * all memory/cpu of this node are removed, we can offline this | ||
1728 | * node now. | ||
1729 | */ | ||
1730 | node_set_offline(nid); | ||
1731 | unregister_one_node(nid); | ||
1732 | } | ||
1733 | |||
1734 | int __ref remove_memory(int nid, u64 start, u64 size) | ||
1683 | { | 1735 | { |
1684 | unsigned long start_pfn, end_pfn; | 1736 | unsigned long start_pfn, end_pfn; |
1685 | int ret = 0; | 1737 | int ret = 0; |
@@ -1734,6 +1786,8 @@ repeat: | |||
1734 | 1786 | ||
1735 | arch_remove_memory(start, size); | 1787 | arch_remove_memory(start, size); |
1736 | 1788 | ||
1789 | try_offline_node(nid); | ||
1790 | |||
1737 | unlock_memory_hotplug(); | 1791 | unlock_memory_hotplug(); |
1738 | 1792 | ||
1739 | return 0; | 1793 | return 0; |
@@ -1743,7 +1797,7 @@ int offline_pages(unsigned long start_pfn, unsigned long nr_pages) | |||
1743 | { | 1797 | { |
1744 | return -EINVAL; | 1798 | return -EINVAL; |
1745 | } | 1799 | } |
1746 | int remove_memory(u64 start, u64 size) | 1800 | int remove_memory(int nid, u64 start, u64 size) |
1747 | { | 1801 | { |
1748 | return -EINVAL; | 1802 | return -EINVAL; |
1749 | } | 1803 | } |