Commit 60a5a19e7419ba0bc22ed01b3285e8940b42944c
Committed by
Linus Torvalds
1 parent
815121d2b5
Exists in
master
and in
20 other branches
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>
Showing 3 changed files with 63 additions and 5 deletions Side-by-side Diff
drivers/acpi/acpi_memhotplug.c
... | ... | @@ -280,9 +280,11 @@ |
280 | 280 | |
281 | 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 | 284 | struct acpi_memory_info *info, *n; |
285 | 285 | |
286 | + nid = acpi_get_node(mem_device->device->handle); | |
287 | + | |
286 | 288 | list_for_each_entry_safe(info, n, &mem_device->res_list, list) { |
287 | 289 | if (info->failed) |
288 | 290 | /* The kernel does not use this memory block */ |
... | ... | @@ -295,7 +297,9 @@ |
295 | 297 | */ |
296 | 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 | 303 | if (result) |
300 | 304 | return result; |
301 | 305 |
include/linux/memory_hotplug.h
... | ... | @@ -248,7 +248,7 @@ |
248 | 248 | extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages); |
249 | 249 | extern int offline_memory_block(struct memory_block *mem); |
250 | 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 | 252 | extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn, |
253 | 253 | int nr_pages); |
254 | 254 | extern void sparse_remove_one_section(struct zone *zone, struct mem_section *ms); |
mm/memory_hotplug.c
... | ... | @@ -29,6 +29,7 @@ |
29 | 29 | #include <linux/suspend.h> |
30 | 30 | #include <linux/mm_inline.h> |
31 | 31 | #include <linux/firmware-map.h> |
32 | +#include <linux/stop_machine.h> | |
32 | 33 | |
33 | 34 | #include <asm/tlbflush.h> |
34 | 35 | |
35 | 36 | |
... | ... | @@ -1679,8 +1680,59 @@ |
1679 | 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) | |
1683 | 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) | |
1735 | +{ | |
1684 | 1736 | unsigned long start_pfn, end_pfn; |
1685 | 1737 | int ret = 0; |
1686 | 1738 | int retry = 1; |
... | ... | @@ -1734,6 +1786,8 @@ |
1734 | 1786 | |
1735 | 1787 | arch_remove_memory(start, size); |
1736 | 1788 | |
1789 | + try_offline_node(nid); | |
1790 | + | |
1737 | 1791 | unlock_memory_hotplug(); |
1738 | 1792 | |
1739 | 1793 | return 0; |
... | ... | @@ -1743,7 +1797,7 @@ |
1743 | 1797 | { |
1744 | 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 | 1802 | return -EINVAL; |
1749 | 1803 | } |