aboutsummaryrefslogtreecommitdiffstats
path: root/mm/memory_hotplug.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/memory_hotplug.c')
-rw-r--r--mm/memory_hotplug.c81
1 files changed, 11 insertions, 70 deletions
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 1ad92b46753e..081b4d654ed6 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1621,6 +1621,7 @@ int offline_pages(unsigned long start_pfn, unsigned long nr_pages)
1621{ 1621{
1622 return __offline_pages(start_pfn, start_pfn + nr_pages, 120 * HZ); 1622 return __offline_pages(start_pfn, start_pfn + nr_pages, 120 * HZ);
1623} 1623}
1624#endif /* CONFIG_MEMORY_HOTREMOVE */
1624 1625
1625/** 1626/**
1626 * walk_memory_range - walks through all mem sections in [start_pfn, end_pfn) 1627 * walk_memory_range - walks through all mem sections in [start_pfn, end_pfn)
@@ -1634,7 +1635,7 @@ int offline_pages(unsigned long start_pfn, unsigned long nr_pages)
1634 * 1635 *
1635 * Returns the return value of func. 1636 * Returns the return value of func.
1636 */ 1637 */
1637static int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn, 1638int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn,
1638 void *arg, int (*func)(struct memory_block *, void *)) 1639 void *arg, int (*func)(struct memory_block *, void *))
1639{ 1640{
1640 struct memory_block *mem = NULL; 1641 struct memory_block *mem = NULL;
@@ -1671,24 +1672,7 @@ static int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn,
1671 return 0; 1672 return 0;
1672} 1673}
1673 1674
1674/** 1675#ifdef CONFIG_MEMORY_HOTREMOVE
1675 * offline_memory_block_cb - callback function for offlining memory block
1676 * @mem: the memory block to be offlined
1677 * @arg: buffer to hold error msg
1678 *
1679 * Always return 0, and put the error msg in arg if any.
1680 */
1681static int offline_memory_block_cb(struct memory_block *mem, void *arg)
1682{
1683 int *ret = arg;
1684 int error = offline_memory_block(mem);
1685
1686 if (error != 0 && *ret == 0)
1687 *ret = error;
1688
1689 return 0;
1690}
1691
1692static int is_memblock_offlined_cb(struct memory_block *mem, void *arg) 1676static int is_memblock_offlined_cb(struct memory_block *mem, void *arg)
1693{ 1677{
1694 int ret = !is_memblock_offlined(mem); 1678 int ret = !is_memblock_offlined(mem);
@@ -1814,54 +1798,22 @@ void try_offline_node(int nid)
1814} 1798}
1815EXPORT_SYMBOL(try_offline_node); 1799EXPORT_SYMBOL(try_offline_node);
1816 1800
1817int __ref remove_memory(int nid, u64 start, u64 size) 1801void __ref remove_memory(int nid, u64 start, u64 size)
1818{ 1802{
1819 unsigned long start_pfn, end_pfn; 1803 int ret;
1820 int ret = 0;
1821 int retry = 1;
1822
1823 start_pfn = PFN_DOWN(start);
1824 end_pfn = PFN_UP(start + size - 1);
1825
1826 /*
1827 * When CONFIG_MEMCG is on, one memory block may be used by other
1828 * blocks to store page cgroup when onlining pages. But we don't know
1829 * in what order pages are onlined. So we iterate twice to offline
1830 * memory:
1831 * 1st iterate: offline every non primary memory block.
1832 * 2nd iterate: offline primary (i.e. first added) memory block.
1833 */
1834repeat:
1835 walk_memory_range(start_pfn, end_pfn, &ret,
1836 offline_memory_block_cb);
1837 if (ret) {
1838 if (!retry)
1839 return ret;
1840
1841 retry = 0;
1842 ret = 0;
1843 goto repeat;
1844 }
1845 1804
1846 lock_memory_hotplug(); 1805 lock_memory_hotplug();
1847 1806
1848 /* 1807 /*
1849 * we have offlined all memory blocks like this: 1808 * All memory blocks must be offlined before removing memory. Check
1850 * 1. lock memory hotplug 1809 * whether all memory blocks in question are offline and trigger a BUG()
1851 * 2. offline a memory block 1810 * if this is not the case.
1852 * 3. unlock memory hotplug
1853 *
1854 * repeat step1-3 to offline the memory block. All memory blocks
1855 * must be offlined before removing memory. But we don't hold the
1856 * lock in the whole operation. So we should check whether all
1857 * memory blocks are offlined.
1858 */ 1811 */
1859 1812 ret = walk_memory_range(PFN_DOWN(start), PFN_UP(start + size - 1), NULL,
1860 ret = walk_memory_range(start_pfn, end_pfn, NULL,
1861 is_memblock_offlined_cb); 1813 is_memblock_offlined_cb);
1862 if (ret) { 1814 if (ret) {
1863 unlock_memory_hotplug(); 1815 unlock_memory_hotplug();
1864 return ret; 1816 BUG();
1865 } 1817 }
1866 1818
1867 /* remove memmap entry */ 1819 /* remove memmap entry */
@@ -1872,17 +1824,6 @@ repeat:
1872 try_offline_node(nid); 1824 try_offline_node(nid);
1873 1825
1874 unlock_memory_hotplug(); 1826 unlock_memory_hotplug();
1875
1876 return 0;
1877} 1827}
1878#else
1879int offline_pages(unsigned long start_pfn, unsigned long nr_pages)
1880{
1881 return -EINVAL;
1882}
1883int remove_memory(int nid, u64 start, u64 size)
1884{
1885 return -EINVAL;
1886}
1887#endif /* CONFIG_MEMORY_HOTREMOVE */
1888EXPORT_SYMBOL_GPL(remove_memory); 1828EXPORT_SYMBOL_GPL(remove_memory);
1829#endif /* CONFIG_MEMORY_HOTREMOVE */