memory_hotplug.c (f991fae5c6d42dfc5029150b05a78cf3f6c18cc9) | memory_hotplug.c (aa47228a18e6d49369df877463095b899aff495f) |
---|---|
1/* 2 * linux/mm/memory_hotplug.c 3 * 4 * Copyright (C) 5 */ 6 7#include <linux/stddef.h> 8#include <linux/mm.h> --- 904 unchanged lines hidden (view full) --- 913 node_set_state(node, N_HIGH_MEMORY); 914 915 node_set_state(node, N_MEMORY); 916} 917 918 919int __ref online_pages(unsigned long pfn, unsigned long nr_pages, int online_type) 920{ | 1/* 2 * linux/mm/memory_hotplug.c 3 * 4 * Copyright (C) 5 */ 6 7#include <linux/stddef.h> 8#include <linux/mm.h> --- 904 unchanged lines hidden (view full) --- 913 node_set_state(node, N_HIGH_MEMORY); 914 915 node_set_state(node, N_MEMORY); 916} 917 918 919int __ref online_pages(unsigned long pfn, unsigned long nr_pages, int online_type) 920{ |
921 unsigned long flags; |
|
921 unsigned long onlined_pages = 0; 922 struct zone *zone; 923 int need_zonelists_rebuild = 0; 924 int nid; 925 int ret; 926 struct memory_notify arg; 927 928 lock_memory_hotplug(); --- 62 unchanged lines hidden (view full) --- 991 << PAGE_SHIFT) - 1); 992 memory_notify(MEM_CANCEL_ONLINE, &arg); 993 unlock_memory_hotplug(); 994 return ret; 995 } 996 997 zone->managed_pages += onlined_pages; 998 zone->present_pages += onlined_pages; | 922 unsigned long onlined_pages = 0; 923 struct zone *zone; 924 int need_zonelists_rebuild = 0; 925 int nid; 926 int ret; 927 struct memory_notify arg; 928 929 lock_memory_hotplug(); --- 62 unchanged lines hidden (view full) --- 992 << PAGE_SHIFT) - 1); 993 memory_notify(MEM_CANCEL_ONLINE, &arg); 994 unlock_memory_hotplug(); 995 return ret; 996 } 997 998 zone->managed_pages += onlined_pages; 999 zone->present_pages += onlined_pages; |
1000 1001 pgdat_resize_lock(zone->zone_pgdat, &flags); |
|
999 zone->zone_pgdat->node_present_pages += onlined_pages; | 1002 zone->zone_pgdat->node_present_pages += onlined_pages; |
1003 pgdat_resize_unlock(zone->zone_pgdat, &flags); 1004 |
|
1000 if (onlined_pages) { 1001 node_states_set_node(zone_to_nid(zone), &arg); 1002 if (need_zonelists_rebuild) 1003 build_all_zonelists(NULL, NULL); 1004 else 1005 zone_pcp_update(zone); 1006 } 1007 --- 608 unchanged lines hidden (view full) --- 1616 unlock_memory_hotplug(); 1617 return ret; 1618} 1619 1620int offline_pages(unsigned long start_pfn, unsigned long nr_pages) 1621{ 1622 return __offline_pages(start_pfn, start_pfn + nr_pages, 120 * HZ); 1623} | 1005 if (onlined_pages) { 1006 node_states_set_node(zone_to_nid(zone), &arg); 1007 if (need_zonelists_rebuild) 1008 build_all_zonelists(NULL, NULL); 1009 else 1010 zone_pcp_update(zone); 1011 } 1012 --- 608 unchanged lines hidden (view full) --- 1621 unlock_memory_hotplug(); 1622 return ret; 1623} 1624 1625int offline_pages(unsigned long start_pfn, unsigned long nr_pages) 1626{ 1627 return __offline_pages(start_pfn, start_pfn + nr_pages, 120 * HZ); 1628} |
1624#endif /* CONFIG_MEMORY_HOTREMOVE */ | |
1625 1626/** 1627 * walk_memory_range - walks through all mem sections in [start_pfn, end_pfn) 1628 * @start_pfn: start pfn of the memory range 1629 * @end_pfn: end pfn of the memory range 1630 * @arg: argument passed to func 1631 * @func: callback for each memory section walked 1632 * 1633 * This function walks through all present mem sections in range 1634 * [start_pfn, end_pfn) and call func on each mem section. 1635 * 1636 * Returns the return value of func. 1637 */ | 1629 1630/** 1631 * walk_memory_range - walks through all mem sections in [start_pfn, end_pfn) 1632 * @start_pfn: start pfn of the memory range 1633 * @end_pfn: end pfn of the memory range 1634 * @arg: argument passed to func 1635 * @func: callback for each memory section walked 1636 * 1637 * This function walks through all present mem sections in range 1638 * [start_pfn, end_pfn) and call func on each mem section. 1639 * 1640 * Returns the return value of func. 1641 */ |
1638int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn, | 1642static int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn, |
1639 void *arg, int (*func)(struct memory_block *, void *)) 1640{ 1641 struct memory_block *mem = NULL; 1642 struct mem_section *section; 1643 unsigned long pfn, section_nr; 1644 int ret; 1645 1646 for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { --- 20 unchanged lines hidden (view full) --- 1667 } 1668 1669 if (mem) 1670 kobject_put(&mem->dev.kobj); 1671 1672 return 0; 1673} 1674 | 1643 void *arg, int (*func)(struct memory_block *, void *)) 1644{ 1645 struct memory_block *mem = NULL; 1646 struct mem_section *section; 1647 unsigned long pfn, section_nr; 1648 int ret; 1649 1650 for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { --- 20 unchanged lines hidden (view full) --- 1671 } 1672 1673 if (mem) 1674 kobject_put(&mem->dev.kobj); 1675 1676 return 0; 1677} 1678 |
1675#ifdef CONFIG_MEMORY_HOTREMOVE | 1679/** 1680 * offline_memory_block_cb - callback function for offlining memory block 1681 * @mem: the memory block to be offlined 1682 * @arg: buffer to hold error msg 1683 * 1684 * Always return 0, and put the error msg in arg if any. 1685 */ 1686static int offline_memory_block_cb(struct memory_block *mem, void *arg) 1687{ 1688 int *ret = arg; 1689 int error = offline_memory_block(mem); 1690 1691 if (error != 0 && *ret == 0) 1692 *ret = error; 1693 1694 return 0; 1695} 1696 |
1676static int is_memblock_offlined_cb(struct memory_block *mem, void *arg) 1677{ 1678 int ret = !is_memblock_offlined(mem); 1679 1680 if (unlikely(ret)) { 1681 phys_addr_t beginpa, endpa; 1682 1683 beginpa = PFN_PHYS(section_nr_to_pfn(mem->start_section_nr)); --- 109 unchanged lines hidden (view full) --- 1793 * without reference counting or other symchronizing method, do not 1794 * reset node_data and free pgdat here. Just reset it to 0 and reuse 1795 * the memory when the node is online again. 1796 */ 1797 memset(pgdat, 0, sizeof(*pgdat)); 1798} 1799EXPORT_SYMBOL(try_offline_node); 1800 | 1697static int is_memblock_offlined_cb(struct memory_block *mem, void *arg) 1698{ 1699 int ret = !is_memblock_offlined(mem); 1700 1701 if (unlikely(ret)) { 1702 phys_addr_t beginpa, endpa; 1703 1704 beginpa = PFN_PHYS(section_nr_to_pfn(mem->start_section_nr)); --- 109 unchanged lines hidden (view full) --- 1814 * without reference counting or other symchronizing method, do not 1815 * reset node_data and free pgdat here. Just reset it to 0 and reuse 1816 * the memory when the node is online again. 1817 */ 1818 memset(pgdat, 0, sizeof(*pgdat)); 1819} 1820EXPORT_SYMBOL(try_offline_node); 1821 |
1801void __ref remove_memory(int nid, u64 start, u64 size) | 1822int __ref remove_memory(int nid, u64 start, u64 size) |
1802{ | 1823{ |
1803 int ret; | 1824 unsigned long start_pfn, end_pfn; 1825 int ret = 0; 1826 int retry = 1; |
1804 | 1827 |
1828 start_pfn = PFN_DOWN(start); 1829 end_pfn = PFN_UP(start + size - 1); 1830 1831 /* 1832 * When CONFIG_MEMCG is on, one memory block may be used by other 1833 * blocks to store page cgroup when onlining pages. But we don't know 1834 * in what order pages are onlined. So we iterate twice to offline 1835 * memory: 1836 * 1st iterate: offline every non primary memory block. 1837 * 2nd iterate: offline primary (i.e. first added) memory block. 1838 */ 1839repeat: 1840 walk_memory_range(start_pfn, end_pfn, &ret, 1841 offline_memory_block_cb); 1842 if (ret) { 1843 if (!retry) 1844 return ret; 1845 1846 retry = 0; 1847 ret = 0; 1848 goto repeat; 1849 } 1850 |
|
1805 lock_memory_hotplug(); 1806 1807 /* | 1851 lock_memory_hotplug(); 1852 1853 /* |
1808 * All memory blocks must be offlined before removing memory. Check 1809 * whether all memory blocks in question are offline and trigger a BUG() 1810 * if this is not the case. | 1854 * we have offlined all memory blocks like this: 1855 * 1. lock memory hotplug 1856 * 2. offline a memory block 1857 * 3. unlock memory hotplug 1858 * 1859 * repeat step1-3 to offline the memory block. All memory blocks 1860 * must be offlined before removing memory. But we don't hold the 1861 * lock in the whole operation. So we should check whether all 1862 * memory blocks are offlined. |
1811 */ | 1863 */ |
1812 ret = walk_memory_range(PFN_DOWN(start), PFN_UP(start + size - 1), NULL, | 1864 1865 ret = walk_memory_range(start_pfn, end_pfn, NULL, |
1813 is_memblock_offlined_cb); 1814 if (ret) { 1815 unlock_memory_hotplug(); | 1866 is_memblock_offlined_cb); 1867 if (ret) { 1868 unlock_memory_hotplug(); |
1816 BUG(); | 1869 return ret; |
1817 } 1818 1819 /* remove memmap entry */ 1820 firmware_map_remove(start, start + size, "System RAM"); 1821 1822 arch_remove_memory(start, size); 1823 1824 try_offline_node(nid); 1825 1826 unlock_memory_hotplug(); | 1870 } 1871 1872 /* remove memmap entry */ 1873 firmware_map_remove(start, start + size, "System RAM"); 1874 1875 arch_remove_memory(start, size); 1876 1877 try_offline_node(nid); 1878 1879 unlock_memory_hotplug(); |
1880 1881 return 0; |
|
1827} | 1882} |
1828EXPORT_SYMBOL_GPL(remove_memory); | 1883#else 1884int offline_pages(unsigned long start_pfn, unsigned long nr_pages) 1885{ 1886 return -EINVAL; 1887} 1888int remove_memory(int nid, u64 start, u64 size) 1889{ 1890 return -EINVAL; 1891} |
1829#endif /* CONFIG_MEMORY_HOTREMOVE */ | 1892#endif /* CONFIG_MEMORY_HOTREMOVE */ |
1893EXPORT_SYMBOL_GPL(remove_memory); |
|