diff options
Diffstat (limited to 'mm/memory_hotplug.c')
-rw-r--r-- | mm/memory_hotplug.c | 64 |
1 files changed, 43 insertions, 21 deletions
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 6166ba5a15f3..4ebe696138e8 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c | |||
@@ -1734,9 +1734,10 @@ static int check_memblock_offlined_cb(struct memory_block *mem, void *arg) | |||
1734 | endpa = PFN_PHYS(section_nr_to_pfn(mem->end_section_nr + 1))-1; | 1734 | endpa = PFN_PHYS(section_nr_to_pfn(mem->end_section_nr + 1))-1; |
1735 | pr_warn("removing memory fails, because memory [%pa-%pa] is onlined\n", | 1735 | pr_warn("removing memory fails, because memory [%pa-%pa] is onlined\n", |
1736 | &beginpa, &endpa); | 1736 | &beginpa, &endpa); |
1737 | } | ||
1738 | 1737 | ||
1739 | return ret; | 1738 | return -EBUSY; |
1739 | } | ||
1740 | return 0; | ||
1740 | } | 1741 | } |
1741 | 1742 | ||
1742 | static int check_cpu_on_node(pg_data_t *pgdat) | 1743 | static int check_cpu_on_node(pg_data_t *pgdat) |
@@ -1819,19 +1820,9 @@ static void __release_memory_resource(resource_size_t start, | |||
1819 | } | 1820 | } |
1820 | } | 1821 | } |
1821 | 1822 | ||
1822 | /** | 1823 | static int __ref try_remove_memory(int nid, u64 start, u64 size) |
1823 | * remove_memory | ||
1824 | * @nid: the node ID | ||
1825 | * @start: physical address of the region to remove | ||
1826 | * @size: size of the region to remove | ||
1827 | * | ||
1828 | * NOTE: The caller must call lock_device_hotplug() to serialize hotplug | ||
1829 | * and online/offline operations before this call, as required by | ||
1830 | * try_offline_node(). | ||
1831 | */ | ||
1832 | void __ref __remove_memory(int nid, u64 start, u64 size) | ||
1833 | { | 1824 | { |
1834 | int ret; | 1825 | int rc = 0; |
1835 | 1826 | ||
1836 | BUG_ON(check_hotplug_memory_range(start, size)); | 1827 | BUG_ON(check_hotplug_memory_range(start, size)); |
1837 | 1828 | ||
@@ -1839,13 +1830,13 @@ void __ref __remove_memory(int nid, u64 start, u64 size) | |||
1839 | 1830 | ||
1840 | /* | 1831 | /* |
1841 | * All memory blocks must be offlined before removing memory. Check | 1832 | * All memory blocks must be offlined before removing memory. Check |
1842 | * whether all memory blocks in question are offline and trigger a BUG() | 1833 | * whether all memory blocks in question are offline and return error |
1843 | * if this is not the case. | 1834 | * if this is not the case. |
1844 | */ | 1835 | */ |
1845 | ret = walk_memory_range(PFN_DOWN(start), PFN_UP(start + size - 1), NULL, | 1836 | rc = walk_memory_range(PFN_DOWN(start), PFN_UP(start + size - 1), NULL, |
1846 | check_memblock_offlined_cb); | 1837 | check_memblock_offlined_cb); |
1847 | if (ret) | 1838 | if (rc) |
1848 | BUG(); | 1839 | goto done; |
1849 | 1840 | ||
1850 | /* remove memmap entry */ | 1841 | /* remove memmap entry */ |
1851 | firmware_map_remove(start, start + size, "System RAM"); | 1842 | firmware_map_remove(start, start + size, "System RAM"); |
@@ -1857,14 +1848,45 @@ void __ref __remove_memory(int nid, u64 start, u64 size) | |||
1857 | 1848 | ||
1858 | try_offline_node(nid); | 1849 | try_offline_node(nid); |
1859 | 1850 | ||
1851 | done: | ||
1860 | mem_hotplug_done(); | 1852 | mem_hotplug_done(); |
1853 | return rc; | ||
1861 | } | 1854 | } |
1862 | 1855 | ||
1863 | void remove_memory(int nid, u64 start, u64 size) | 1856 | /** |
1857 | * remove_memory | ||
1858 | * @nid: the node ID | ||
1859 | * @start: physical address of the region to remove | ||
1860 | * @size: size of the region to remove | ||
1861 | * | ||
1862 | * NOTE: The caller must call lock_device_hotplug() to serialize hotplug | ||
1863 | * and online/offline operations before this call, as required by | ||
1864 | * try_offline_node(). | ||
1865 | */ | ||
1866 | void __remove_memory(int nid, u64 start, u64 size) | ||
1867 | { | ||
1868 | |||
1869 | /* | ||
1870 | * trigger BUG() is some memory is not offlined prior to calling this | ||
1871 | * function | ||
1872 | */ | ||
1873 | if (try_remove_memory(nid, start, size)) | ||
1874 | BUG(); | ||
1875 | } | ||
1876 | |||
1877 | /* | ||
1878 | * Remove memory if every memory block is offline, otherwise return -EBUSY is | ||
1879 | * some memory is not offline | ||
1880 | */ | ||
1881 | int remove_memory(int nid, u64 start, u64 size) | ||
1864 | { | 1882 | { |
1883 | int rc; | ||
1884 | |||
1865 | lock_device_hotplug(); | 1885 | lock_device_hotplug(); |
1866 | __remove_memory(nid, start, size); | 1886 | rc = try_remove_memory(nid, start, size); |
1867 | unlock_device_hotplug(); | 1887 | unlock_device_hotplug(); |
1888 | |||
1889 | return rc; | ||
1868 | } | 1890 | } |
1869 | EXPORT_SYMBOL_GPL(remove_memory); | 1891 | EXPORT_SYMBOL_GPL(remove_memory); |
1870 | #endif /* CONFIG_MEMORY_HOTREMOVE */ | 1892 | #endif /* CONFIG_MEMORY_HOTREMOVE */ |