mm/memory_hotplug: factor out node_is_memoryless()

A memoryless node neither spans present pages (populated or ZONE_DEVICE)
nor has an offline-but-added memory block still linked to it in sysfs.

try_offline_node() presently open-codes this memoryless check.

Pull that into a node_is_memoryless() helper and pull the existing
check_no_memblock_for_node_cb() helper ahead of the add/online path so
it's clearer what is happening here.

No functional change.

[akpm@linux-foundation.org: move node_is_memoryless() inside CONFIG_MEMORY_HOTREMOVE]
Link: https://lore.kernel.org/20260902195507.88655-1-gourry@gourry.net
Signed-off-by: Gregory Price <gourry@gourry.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Cc: Oscar Salvador <osalvador@suse.de>
This commit is contained in:
Gregory Price 2026-09-02 15:55:07 -04:00 committed by Andrew Morton
parent 0e3846146f
commit a85a8d0327

View File

@ -1785,6 +1785,37 @@ 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
@ -2214,18 +2245,6 @@ 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
@ -2237,23 +2256,7 @@ static int check_no_memblock_for_node_cb(struct memory_block *mem, void *arg)
*/
void try_offline_node(int 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)
if (!node_is_memoryless(nid))
return;
if (check_cpu_on_node(nid))