Re: [PATCH v5 32/36] mm/khugepaged: base private node collapse eligiblity on actor/cap bits

Richard Cheng <[email protected]>
Newsgroups dev.linux.lists.damon,dev.linux.lists.driver-core,dev.linux.lists.nvdimm,org.kernel.vger.cgroups,org.kernel.vger.kvm,org.kernel.vger.linux-cxl,org.kernel.vger.linux-debuggers,org.kernel.vger.linux-doc,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-kselftest,org.kvack.linux-mm
Message-ID <amDEEnTv0QumcDJn@MWDK4CY14F>
On Mon, Jul 20, 2026 at 03:34:26PM +0800, Gregory Price wrote:
> Collapse can move base pages across nodes.  The khugepaged daemon does
> this transparently, while MADV_COLLAPSE is a userland construct.
> 
> Isolate private nodes from khugepaged exactly like ZONE_DEVICE.
> Never collapse private node folios silently (the owner may not
> support migration).
> 
> MADV_COLLAPSE is user-initiated, so it is allowed on a private node
> opted into CAP_USER_NUMA, consistent with other userspace interfaces.
> 
> folio_allows_collapse() encodes this: false for khugepaged on a private
> node, CAP_USER_NUMA for MADV_COLLAPSE.
> 
> Signed-off-by: Gregory Price <[email protected]>
> ---
>  mm/internal.h   | 26 ++++++++++++++++++++++++++
>  mm/khugepaged.c | 16 +++++++++++++---
>  2 files changed, 39 insertions(+), 3 deletions(-)
> 
> diff --git a/mm/internal.h b/mm/internal.h
> index 9621eb127c28c..9dbc5752cd3fe 100644
> --- a/mm/internal.h
> +++ b/mm/internal.h
> @@ -136,6 +136,32 @@ static inline bool folio_allows_numa_balance(struct folio *folio)
>  	       node_allows_numa_balancing(folio_nid(folio));
>  }
>  
> +/*
> + * folio_allows_collapse() - may collapse fold this folio into a THP?
> + * @is_khugepaged: true for the khugepaged, false for MADV_COLLAPSE.
> + *
> + * Collapse is a residency operation gated by the actor calling it:
> + *   - khugepaged never operates on private-node folios (like ZONE_DEVICE)
> + *   - MADV_COLLAPSE is gated by CAP_USER_NUMA
> + *
> + * Never true for ZONE_DEVICE.
> + */
> +static inline bool folio_allows_collapse(struct folio *folio, bool is_khugepaged)
> +{
> +	int nid = folio_nid(folio);
> +
> +	if (folio_is_zone_device(folio))
> +		return false;
> +	if (is_khugepaged)
> +		return !node_is_private(nid);
> +	return node_allows_user_numa(nid);
> +}
> +
> +static inline bool page_allows_collapse(struct page *page, bool is_khugepaged)
> +{
> +	return folio_allows_collapse(page_folio(page), is_khugepaged);
> +}
> +
>  /*
>   * folio_allows_longterm_pin() - may this folio be long-term GUP-pinned?
>   *
> diff --git a/mm/khugepaged.c b/mm/khugepaged.c
> index fb4378cc17b10..5f20839857738 100644
> --- a/mm/khugepaged.c
> +++ b/mm/khugepaged.c
> @@ -700,7 +700,8 @@ static enum scan_result __collapse_huge_page_isolate(struct vm_area_struct *vma,
>  			goto out;
>  		}
>  		page = vm_normal_page(vma, addr, pteval);
> -		if (unlikely(!page) || unlikely(page_is_private_managed(page))) {
> +		if (unlikely(!page) ||
> +		    unlikely(!page_allows_collapse(page, cc->is_khugepaged))) {
>  			result = SCAN_PAGE_NULL;
>  			goto out;
>  		}
> @@ -1241,9 +1242,17 @@ static enum scan_result alloc_charge_folio(struct folio **foliop, struct mm_stru
>  	gfp_t gfp = (cc->is_khugepaged ? alloc_hugepage_khugepaged_gfpmask() :
>  		     GFP_TRANSHUGE);
>  	int node = collapse_find_target_node(cc);
> +	unsigned int aflags;
>  	struct folio *folio;
> +	bool allow;
>  
> -	folio = __folio_alloc(gfp, order, node, &cc->alloc_nmask, ALLOC_DEFAULT);
> +	/* Private node access: khugepaged never, madvise with CAP_USER_NUMA */
> +	allow = cc->is_khugepaged ? !node_is_private(node)
> +				  : node_allows_user_numa(node);
> +	aflags = (allow && node_is_private(node)) ?
> +		ALLOC_ZONELIST_PRIVATE : ALLOC_DEFAULT;
> +
> +	folio = __folio_alloc(gfp, order, node, &cc->alloc_nmask, aflags);
>  	if (!folio) {
>  		*foliop = NULL;
>  		if (is_pmd_order(order))
> @@ -1687,7 +1696,8 @@ static enum scan_result collapse_scan_pmd(struct mm_struct *mm,
>  		}
>  
>  		page = vm_normal_page(vma, addr, pteval);
> -		if (unlikely(!page) || unlikely(page_is_private_managed(page))) {
> +		if (unlikely(!page) ||
> +		    unlikely(!page_allows_collapse(page, cc->is_khugepaged))) {

I think collapse_scan_file() need something like folio_allows_collapse() check as well.

--Richard

>  			result = SCAN_PAGE_NULL;
>  			goto out_unmap;
>  		}
> -- 
> 2.53.0-Meta
> 
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.