aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-05-27 06:58:46 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-06-01 15:37:10 -0400
commit242831eb15a06fa4414eaa705fdc6dd432ab98d1 (patch)
tree65b57b16800e27b0354ef72a4fe1aecbf8b6d89a
parent303bfdb1a14d0460feb859cd008ff81da36b517c (diff)
Memory hotplug / ACPI: Simplify memory removal
Now that the memory offlining should be taken care of by the companion device offlining code in acpi_scan_hot_remove(), the ACPI memory hotplug driver doesn't need to offline it in remove_memory() any more. Moreover, since the return value of remove_memory() is not used, it's better to make it be a void function and trigger a BUG() if the memory scheduled for removal is not offline. Change the code in accordance with the above observations. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Toshi Kani <toshi.kani@hp.com>
-rw-r--r--drivers/acpi/acpi_memhotplug.c13
-rw-r--r--include/linux/memory_hotplug.h2
-rw-r--r--mm/memory_hotplug.c71
3 files changed, 12 insertions, 74 deletions
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index 5590db12028e..c711d1144044 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -271,13 +271,11 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
271 return 0; 271 return 0;
272} 272}
273 273
274static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device) 274static void acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
275{ 275{
276 acpi_handle handle = mem_device->device->handle; 276 acpi_handle handle = mem_device->device->handle;
277 int result = 0, nid;
278 struct acpi_memory_info *info, *n; 277 struct acpi_memory_info *info, *n;
279 278 int nid = acpi_get_node(handle);
280 nid = acpi_get_node(handle);
281 279
282 list_for_each_entry_safe(info, n, &mem_device->res_list, list) { 280 list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
283 if (!info->enabled) 281 if (!info->enabled)
@@ -287,15 +285,10 @@ static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
287 nid = memory_add_physaddr_to_nid(info->start_addr); 285 nid = memory_add_physaddr_to_nid(info->start_addr);
288 286
289 acpi_unbind_memory_blocks(info, handle); 287 acpi_unbind_memory_blocks(info, handle);
290 result = remove_memory(nid, info->start_addr, info->length); 288 remove_memory(nid, info->start_addr, info->length);
291 if (result)
292 return result;
293
294 list_del(&info->list); 289 list_del(&info->list);
295 kfree(info); 290 kfree(info);
296 } 291 }
297
298 return result;
299} 292}
300 293
301static void acpi_memory_device_free(struct acpi_memory_device *mem_device) 294static void acpi_memory_device_free(struct acpi_memory_device *mem_device)
diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
index ae5480a00963..00569fb4ed6a 100644
--- a/include/linux/memory_hotplug.h
+++ b/include/linux/memory_hotplug.h
@@ -252,7 +252,7 @@ extern int add_memory(int nid, u64 start, u64 size);
252extern int arch_add_memory(int nid, u64 start, u64 size); 252extern int arch_add_memory(int nid, u64 start, u64 size);
253extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages); 253extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages);
254extern bool is_memblock_offlined(struct memory_block *mem); 254extern bool is_memblock_offlined(struct memory_block *mem);
255extern int remove_memory(int nid, u64 start, u64 size); 255extern void remove_memory(int nid, u64 start, u64 size);
256extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn, 256extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn,
257 int nr_pages); 257 int nr_pages);
258extern void sparse_remove_one_section(struct zone *zone, struct mem_section *ms); 258extern 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 a39841d240e8..7026fbc42aaa 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1670,24 +1670,6 @@ int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn,
1670} 1670}
1671 1671
1672#ifdef CONFIG_MEMORY_HOTREMOVE 1672#ifdef CONFIG_MEMORY_HOTREMOVE
1673/**
1674 * offline_memory_block_cb - callback function for offlining memory block
1675 * @mem: the memory block to be offlined
1676 * @arg: buffer to hold error msg
1677 *
1678 * Always return 0, and put the error msg in arg if any.
1679 */
1680static int offline_memory_block_cb(struct memory_block *mem, void *arg)
1681{
1682 int *ret = arg;
1683 int error = device_offline(&mem->dev);
1684
1685 if (error != 0 && *ret == 0)
1686 *ret = error;
1687
1688 return 0;
1689}
1690
1691static int is_memblock_offlined_cb(struct memory_block *mem, void *arg) 1673static int is_memblock_offlined_cb(struct memory_block *mem, void *arg)
1692{ 1674{
1693 int ret = !is_memblock_offlined(mem); 1675 int ret = !is_memblock_offlined(mem);
@@ -1813,54 +1795,22 @@ void try_offline_node(int nid)
1813} 1795}
1814EXPORT_SYMBOL(try_offline_node); 1796EXPORT_SYMBOL(try_offline_node);
1815 1797
1816int __ref remove_memory(int nid, u64 start, u64 size) 1798void __ref remove_memory(int nid, u64 start, u64 size)
1817{ 1799{
1818 unsigned long start_pfn, end_pfn; 1800 int ret;
1819 int ret = 0;
1820 int retry = 1;
1821
1822 start_pfn = PFN_DOWN(start);
1823 end_pfn = PFN_UP(start + size - 1);
1824
1825 /*
1826 * When CONFIG_MEMCG is on, one memory block may be used by other
1827 * blocks to store page cgroup when onlining pages. But we don't know
1828 * in what order pages are onlined. So we iterate twice to offline
1829 * memory:
1830 * 1st iterate: offline every non primary memory block.
1831 * 2nd iterate: offline primary (i.e. first added) memory block.
1832 */
1833repeat:
1834 walk_memory_range(start_pfn, end_pfn, &ret,
1835 offline_memory_block_cb);
1836 if (ret) {
1837 if (!retry)
1838 return ret;
1839
1840 retry = 0;
1841 ret = 0;
1842 goto repeat;
1843 }
1844 1801
1845 lock_memory_hotplug(); 1802 lock_memory_hotplug();
1846 1803
1847 /* 1804 /*
1848 * we have offlined all memory blocks like this: 1805 * All memory blocks must be offlined before removing memory. Check
1849 * 1. lock memory hotplug 1806 * whether all memory blocks in question are offline and trigger a BUG()
1850 * 2. offline a memory block 1807 * if this is not the case.
1851 * 3. unlock memory hotplug
1852 *
1853 * repeat step1-3 to offline the memory block. All memory blocks
1854 * must be offlined before removing memory. But we don't hold the
1855 * lock in the whole operation. So we should check whether all
1856 * memory blocks are offlined.
1857 */ 1808 */
1858 1809 ret = walk_memory_range(PFN_DOWN(start), PFN_UP(start + size - 1), NULL,
1859 ret = walk_memory_range(start_pfn, end_pfn, NULL,
1860 is_memblock_offlined_cb); 1810 is_memblock_offlined_cb);
1861 if (ret) { 1811 if (ret) {
1862 unlock_memory_hotplug(); 1812 unlock_memory_hotplug();
1863 return ret; 1813 BUG();
1864 } 1814 }
1865 1815
1866 /* remove memmap entry */ 1816 /* remove memmap entry */
@@ -1871,17 +1821,12 @@ repeat:
1871 try_offline_node(nid); 1821 try_offline_node(nid);
1872 1822
1873 unlock_memory_hotplug(); 1823 unlock_memory_hotplug();
1874
1875 return 0;
1876} 1824}
1877#else 1825#else
1878int offline_pages(unsigned long start_pfn, unsigned long nr_pages) 1826int offline_pages(unsigned long start_pfn, unsigned long nr_pages)
1879{ 1827{
1880 return -EINVAL; 1828 return -EINVAL;
1881} 1829}
1882int remove_memory(int nid, u64 start, u64 size) 1830void remove_memory(int nid, u64 start, u64 size) {}
1883{
1884 return -EINVAL;
1885}
1886#endif /* CONFIG_MEMORY_HOTREMOVE */ 1831#endif /* CONFIG_MEMORY_HOTREMOVE */
1887EXPORT_SYMBOL_GPL(remove_memory); 1832EXPORT_SYMBOL_GPL(remove_memory);