diff options
Diffstat (limited to 'mm/memory_hotplug.c')
| -rw-r--r-- | mm/memory_hotplug.c | 67 |
1 files changed, 31 insertions, 36 deletions
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index d7a59167bec4..226ab9cb078a 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -43,7 +43,6 @@ #include "mm_init.h" #include "page_alloc.h" #include "shuffle.h" -#include "sparse.h" enum { MEMMAP_ON_MEMORY_DISABLE = 0, @@ -555,9 +554,8 @@ void remove_pfn_range_from_zone(struct zone *zone, /* Select all remaining pages up to the next section boundary */ cur_nr_pages = min(end_pfn - pfn, SECTION_ALIGN_UP(pfn + 1) - pfn); - if (!section_vmemmap_optimizable(__pfn_to_section(pfn))) - page_init_poison(pfn_to_page(pfn), - sizeof(struct page) * cur_nr_pages); + page_init_poison(pfn_to_page(pfn), + sizeof(struct page) * cur_nr_pages); } /* @@ -1787,37 +1785,6 @@ bool mhp_range_allowed(u64 start, u64 size, bool need_mapping) } #ifdef CONFIG_MEMORY_HOTREMOVE - -static int check_no_memblock_for_node_cb(struct memory_block *mem, void *arg) -{ - int nid = *(int *)arg; - - /* - * If a memory block belongs to multiple nodes, the stored nid is not - * reliable. However, such blocks are always online (e.g., cannot get - * offlined) and, therefore, are still spanned by the node. - */ - return mem->nid == nid ? -EEXIST : 0; -} - -/* Caller must hold the memory hotplug lock for this check. */ -static bool node_is_memoryless(int nid) -{ - /* - * A node still spanning pages (especially ZONE_DEVICE) is not - * memoryless. A node spans memory after move_pfn_range_to_zone(), - * e.g. once a memory block has been onlined. - */ - if (node_spanned_pages(nid)) - return false; - /* - * Offline memory blocks may not be spanned by the node yet, but they - * link to it in sysfs and can be onlined later, so the node is not - * memoryless while any remain. - */ - return !for_each_memory_block(&nid, check_no_memblock_for_node_cb); -} - /* * Scan pfn range [start,end) to find movable/migratable pages (LRU and * hugetlb folio, movable_ops pages). Will skip over most unmovable @@ -2247,6 +2214,18 @@ static int check_cpu_on_node(int nid) return 0; } +static int check_no_memblock_for_node_cb(struct memory_block *mem, void *arg) +{ + int nid = *(int *)arg; + + /* + * If a memory block belongs to multiple nodes, the stored nid is not + * reliable. However, such blocks are always online (e.g., cannot get + * offlined) and, therefore, are still spanned by the node. + */ + return mem->nid == nid ? -EEXIST : 0; +} + /** * try_offline_node * @nid: the node ID @@ -2258,7 +2237,23 @@ static int check_cpu_on_node(int nid) */ void try_offline_node(int nid) { - if (!node_is_memoryless(nid)) + int rc; + + /* + * If the node still spans pages (especially ZONE_DEVICE), don't + * offline it. A node spans memory after move_pfn_range_to_zone(), + * e.g., after the memory block was onlined. + */ + if (node_spanned_pages(nid)) + return; + + /* + * Especially offline memory blocks might not be spanned by the + * node. They will get spanned by the node once they get onlined. + * However, they link to the node in sysfs and can get onlined later. + */ + rc = for_each_memory_block(&nid, check_no_memblock_for_node_cb); + if (rc) return; if (check_cpu_on_node(nid)) |
