Re: [PATCH v4 05/19] selftests/mm: make the swap cases' swapout reliable

"Lorenzo Stoakes (ARM)" <[email protected]>
Newsgroups org.kvack.linux-mm,org.kernel.vger.linux-kernel,org.kernel.vger.linux-kselftest
Message-ID <aoQvTjRbcnQNCAuY@lucifer>
On Sat, Aug 15, 2026 at 02:58:47AM +0100, Kiryl Shutsemau wrote:
> From: "Kiryl Shutsemau (Meta)" <[email protected]>
>
> collapse_swapin_single_pte() and collapse_max_ptes_swap() swap a range out
> and then require smaps to report exactly the count they asked for.  Two
> things keep that count from arriving.
>
> MADV_PAGEOUT is best effort, so the count often turns up a moment late.
>
> And wait_for_scan() leaves MADV_HUGEPAGE behind, so khugepaged is still
> working on the range.  Collapsing a range with up to max_ptes_swap pages
> swapped out means reading them back in, so the daemon empties the swap as
> fast as the case fills it.  On arm64 with 64K pages max_ptes_swap is 1024
> pages, which is 64M a step, and the case loses:
>
>     # Swapout 1024 of 8192 pages... Fail
>     not ok 10 collapse_max_ptes_swap
>
> Ask again for up to two seconds, with the range held out of the daemon's
> reach while asking.  The collapse each case runs next puts MADV_HUGEPAGE
> back, so only the setup is affected.
>
> If the pages still will not go, skip.  A machine with no swap, or swap too
> small, full, capped by a memcg or busy with writeback, is not the kernel
> under test refusing.  An error from madvise() itself still ends the run.
>
> Assisted-by: Claude-Code:claude-opus-5
> Reviewed-by: Muhammad Usama Anjum <[email protected]>
> Tested-by: Muhammad Usama Anjum <[email protected]>
> Signed-off-by: Kiryl Shutsemau (Meta) <[email protected]>
> ---
>  tools/testing/selftests/mm/khugepaged.c | 53 +++++++++++++++++++------
>  1 file changed, 41 insertions(+), 12 deletions(-)
>
> diff --git a/tools/testing/selftests/mm/khugepaged.c b/tools/testing/selftests/mm/khugepaged.c
> index ec5c36a19d92..7eb9db0005a0 100644
> --- a/tools/testing/selftests/mm/khugepaged.c
> +++ b/tools/testing/selftests/mm/khugepaged.c
> @@ -219,6 +219,41 @@ static bool check_swap(void *addr, unsigned long size)
>  	return swap;
>  }
>
> +/*
> + * Page the range out and wait for the swap count to say so.
> + *
> + * Two things get in the way.  MADV_PAGEOUT is best effort:
> + * shrink_folio_list() leaves a folio alone when it cannot reclaim it right
> + * away, and one still under writeback from an earlier pageout is the common
> + * case, so the count the caller asks for arrives a moment later.  And a range
> + * an earlier collapse left MADV_HUGEPAGE is one khugepaged is still working
> + * on: collapsing a range with up to max_ptes_swap pages swapped out means
> + * reading those pages back in, so the daemon undoes the pageout as fast as it
> + * is asked for.  Keep the range out of its reach; the collapse the caller runs
> + * next puts MADV_HUGEPAGE back.
> + *
> + * Failing to get the pages out is the machine's answer, not the kernel's --
> + * swap too small, swap full, a memcg cap, a folio still under writeback -- so
> + * callers skip rather than fail.  An error from madvise() is different, and
> + * ends the run here.
> + */

This is a schloppy comment again. Please trim.

Walls of text are not wanted anywhere.

> +static bool swapout_range(void *p, unsigned long size)
> +{
> +	int i;
> +
> +	if (madvise(p, size, MADV_NOHUGEPAGE))
> +		ksft_exit_fail_perror("madvise(MADV_NOHUGEPAGE)");
> +
> +	for (i = 0; i < 40; i++) {
> +		if (madvise(p, size, MADV_PAGEOUT))
> +			ksft_exit_fail_perror("madvise(MADV_PAGEOUT)");
> +		if (check_swap(p, size))
> +			return true;
> +		usleep(50 * 1000);
> +	}
> +	return false;
> +}
> +
>  static void *alloc_mapping(int nr)
>  {
>  	void *p;
> @@ -827,12 +862,10 @@ static void collapse_swapin_single_pte(struct collapse_context *c, struct mem_op
>  	ops->fault(p, 0, hpage_pmd_size);
>
>  	ksft_print_msg("Swapout one page...");
> -	if (madvise(p, page_size, MADV_PAGEOUT))
> -		ksft_exit_fail_perror("madvise(MADV_PAGEOUT)");
> -	if (check_swap(p, page_size)) {
> +	if (swapout_range(p, page_size)) {
>  		success("OK");
>  	} else {
> -		fail("Fail");
> +		skip("Could not swap out");
>  		goto out;
>  	}
>
> @@ -853,12 +886,10 @@ static void collapse_max_ptes_swap(struct collapse_context *c, struct mem_ops *o
>  	ops->fault(p, 0, hpage_pmd_size);
>
>  	ksft_print_msg("Swapout %d of %d pages...", max_ptes_swap + 1, hpage_pmd_nr);
> -	if (madvise(p, (max_ptes_swap + 1) * page_size, MADV_PAGEOUT))
> -		ksft_exit_fail_perror("madvise(MADV_PAGEOUT)");
> -	if (check_swap(p, (max_ptes_swap + 1) * page_size)) {
> +	if (swapout_range(p, (max_ptes_swap + 1) * page_size)) {
>  		success("OK");
>  	} else {
> -		fail("Fail");
> +		skip("Could not swap out");
>  		goto out;
>  	}
>
> @@ -870,12 +901,10 @@ static void collapse_max_ptes_swap(struct collapse_context *c, struct mem_ops *o
>  		ops->fault(p, 0, hpage_pmd_size);
>  		ksft_print_msg("Swapout %d of %d pages...", max_ptes_swap,
>  		       hpage_pmd_nr);
> -		if (madvise(p, max_ptes_swap * page_size, MADV_PAGEOUT))
> -			ksft_exit_fail_perror("madvise(MADV_PAGEOUT)");
> -		if (check_swap(p, max_ptes_swap * page_size)) {
> +		if (swapout_range(p, max_ptes_swap * page_size)) {
>  			success("OK");
>  		} else {
> -			fail("Fail");
> +			skip("Could not swap out");
>  			goto out;
>  		}
>
> --
> 2.54.0
>

--
Cheers, Lorenzo
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.