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 */ |
