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);