Re: [PATCH v5 25/36] mm/memory_hotplug: support N_MEMORY_PRIVATE node hotplug

[email protected] Tue, 21 Jul 2026 18:33:45 +0000
Newsgroups dev.linux.lists.nvdimm,dev.linux.lists.damon,org.kernel.vger.kvm,org.kernel.vger.linux-cxl
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Private node registration and unregistration incorrectly rely on N_MEMORY and N_MEMORY_PRIVATE states, which only track online memory, causing isolation breakage and hijacking of normal memory nodes.
- [High] A TOCTOU race condition exists between memory unplug and private node registration due to lock ordering.
- [Medium] Direct access of __rcu pointer in pgdat_is_private() without using rcu_access_pointer().
--

--- Patch [25]: [PATCH v5 25/36] mm/memory_hotplug: support N_MEMORY_PRIVATE node hotplug ---
commit 976d363a06939b47fdc2d106fc8f3ec46359abd3
Author: Gregory Price <[email protected]>
Subject: mm/memory_hotplug: support N_MEMORY_PRIVATE node hotplug

This commit introduces add_private_memory_driver_managed() to allow
modules to hotplug memory into an N_MEMORY_PRIVATE node. It introduces
logic to register node ownership and opts these private nodes out of
reclaim/compaction by default.

> diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
> index 2b9c0830821e6..be230ac9efe5a 100644
> --- a/mm/memory_hotplug.c
> +++ b/mm/memory_hotplug.c

[ ... ]

> @@ -1204,13 +1204,20 @@ int online_pages(unsigned long pfn, unsigned long nr_pages,
>  	online_pages_range(pfn, nr_pages);
>  	adjust_present_page_count(pfn_to_page(pfn), group, nr_pages);
>  
> +	/*
> +	 * N_MEMORY and N_MEMORY_PRIVATE are mutually exclusive, determine
> +	 * which is correct based on whether the pgdat->private is set.
> +	 */
>  	if (node_arg.nid >= 0)
> -		node_set_state(nid, N_MEMORY);
> +		node_set_state(nid, pgdat_is_private(NODE_DATA(nid)) ?
> +				    N_MEMORY_PRIVATE : N_MEMORY);

[Severity: Medium]
Does pgdat_is_private() directly evaluate the __rcu annotated
pgdat->node_private pointer without using rcu_access_pointer()? A direct
boolean evaluation of an __rcu pointer can result in compiler load tearing.

[ ... ]

> @@ -1688,6 +1702,19 @@ int __add_memory_driver_managed(int nid, u64 start, u64 size,
>  	if (online_type < MMOP_OFFLINE || online_type > MMOP_ONLINE_MOVABLE)
>  		return -EINVAL;
>  
> +	/* Register a private-node owner before adding memory. */
> +	if (np) {
> +		if (mhp_flags & MHP_NID_IS_MGID) {
> +			group = memory_group_find_by_id(nid);
> +			if (!group)
> +				return -EINVAL;
> +			real_nid = group->nid;
> +		}
> +		rc = node_private_register(real_nid, np);
> +		if (rc)
> +			return rc;
> +	}
> +
>  	lock_device_hotplug();

[Severity: High]
Is there a race condition here since node_private_register() is called before
acquiring device_hotplug_lock? 

If Thread A drops the lock in offline_and_remove_memory_ranges() before
calling node_private_unregister(), Thread B could successfully register
the node here. Thread B then blocks on device_hotplug_lock, allowing Thread A
to clear the registration, which might cause Thread B to online its newly
added private memory incorrectly as normal system RAM.

[ ... ]

> @@ -1702,10 +1729,41 @@ int __add_memory_driver_managed(int nid, u64 start, u64 size,
>  
>  out_unlock:
>  	unlock_device_hotplug();
> +	if (rc < 0 && np)
> +		node_private_unregister(real_nid);
>  	return rc;
>  }

[Severity: High]
If this error path is hit, does node_private_unregister() unconditionally
drop the private node registration based only on the online state, ignoring
offline memory blocks on the same node? This could break previously added
offline blocks on this node.

[ ... ]

> @@ -2535,6 +2610,10 @@ int offline_and_remove_memory_ranges(const struct range *ranges,
>  out_unlock:
>  	unlock_device_hotplug();
>  
> +	/* Drop private node registration if they are now memoryless */
> +	for_each_node_mask(nid, nodes)
> +		node_private_unregister(nid);
> +
>  	kfree(online_types);
>  	return rc;
>  }

[Severity: High]
Could node_private_unregister() blindly clear pgdat->node_private here
if it only checks the online N_MEMORY state instead of present memory? 
If remaining memblocks on the node are offline, they might become normal
system RAM when later onlined.

Additionally, because device_hotplug_lock is dropped before unregistering
the private nodes, does this open a race window where a concurrent 
add_private_memory_driver_managed() could have its state wiped out?

-- 
Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=25