public inbox for linux-mm@kvack.org
 help / color / mirror / Atom feed
From: Zi Yan <ziy@nvidia.com>
To: Andrew Morton <akpm@linux-foundation.org>
Cc: David Hildenbrand <david@kernel.org>,
	Lorenzo Stoakes <lorenzo.stoakes@oracle.com>,
	Hugh Dickins <hughd@google.com>,
	Baolin Wang <baolin.wang@linux.alibaba.com>,
	"Liam R. Howlett" <Liam.Howlett@oracle.com>,
	Nico Pache <npache@redhat.com>,
	Ryan Roberts <ryan.roberts@arm.com>, Dev Jain <dev.jain@arm.com>,
	Barry Song <baohua@kernel.org>, Lance Yang <lance.yang@linux.dev>,
	Matthew Wilcox <willy@infradead.org>,
	Bas van Dijk <bas@dfinity.org>,
	Eero Kelly <eero.kelly@dfinity.org>,
	Andrew Battat <andrew.battat@dfinity.org>,
	Adam Bratschi-Kaye <adam.bratschikaye@dfinity.org>,
	linux-mm@kvack.org, linux-kernel@vger.kernel.org,
	linux-fsdevel@vger.kernel.org
Subject: Re: [PATCH v5] selftests/mm: add folio_split() and filemap_get_entry() race test
Date: Wed, 25 Mar 2026 21:53:22 -0400	[thread overview]
Message-ID: <B1437C8C-8827-4588-B42C-147392251983@nvidia.com> (raw)
In-Reply-To: <20260325184731.791eda3b81cee4ad3f3ec17e@linux-foundation.org>

On 25 Mar 2026, at 21:47, Andrew Morton wrote:

> On Mon, 23 Mar 2026 12:37:17 -0400 Zi Yan <ziy@nvidia.com> wrote:
>
>> The added folio_split_race_test is a modified C port of the race condition
>> test from [1]. The test creates shmem huge pages, where the main thread
>> punches holes in the shmem to cause folio_split() in the kernel and
>> a set of 16 threads reads the shmem to cause filemap_get_entry() in the
>> kernel. filemap_get_entry() reads the folio and xarray split by
>> folio_split() locklessly. The original test[2] is written in rust and uses
>> memfd (shmem backed). This C port uses shmem directly and use a single
>> process.
>>
>> Note: the initial rust to C conversion is done by Cursor.
>
> Thanks for the poke, I did indeed miss this.
>
> I'll toss the previous version and its three -fixes.  {lease check that
> those -fixes were incorporated here.
>
Thanks.

> Here's how v5 alters mm.git.  It's quite a large update.

Explanations are below.

>
>
>  tools/testing/selftests/mm/folio_split_race_test.c |   95 +++++------
>  1 file changed, 44 insertions(+), 51 deletions(-)
>
> --- a/tools/testing/selftests/mm/folio_split_race_test.c~a
> +++ a/tools/testing/selftests/mm/folio_split_race_test.c
> @@ -44,8 +44,8 @@ uint64_t pmd_pagesize;
>  /* Shared control block: control reading threads and record stats */
>  struct shared_ctl {
>  	atomic_uint_fast32_t stop;
> -	atomic_size_t reader_failures;
> -	atomic_size_t reader_verified;
> +	atomic_uint_fast64_t reader_failures;
> +	atomic_uint_fast64_t reader_verified;

I changed all size_t to uint64_t to match the existing uint64_t. This
atomic type change matches size_t to uint64_t.

>  	pthread_barrier_t barrier;
>  };
>
> @@ -59,7 +59,7 @@ static void fill_page(unsigned char *bas
>  }
>
>  /* Returns true if valid, false if corrupted. */
> -static bool check_page(unsigned char *base, size_t page_idx)
> +static bool check_page(unsigned char *base, uint64_t page_idx)
>  {
>  	unsigned char *page_ptr = base + page_idx * page_size;
>  	uint64_t expected_idx = (uint64_t)page_idx;
> @@ -68,7 +68,7 @@ static bool check_page(unsigned char *ba
>  	memcpy(&got_idx, page_ptr, 8);
>
>  	if (got_idx != expected_idx) {
> -		size_t off;
> +		uint64_t off;
>  		int all_zero = 1;
>
>  		for (off = 0; off < page_size; off++) {
> @@ -78,15 +78,19 @@ static bool check_page(unsigned char *ba
>  			}
>  		}
>  		if (all_zero) {
> -			ksft_print_msg(
> -				"CORRUPTED: page %zu (huge page %" PRIu64 ") is ALL ZEROS\n",
> -				page_idx,
> -				(page_idx * page_size) / pmd_pagesize);
> +			ksft_print_msg("CORRUPTED: page %" PRIu64
> +				       " (huge page %" PRIu64
> +				       ") is ALL ZEROS\n",
> +				       page_idx,
> +				       (page_idx * page_size) / pmd_pagesize);
>  		} else {
> -			ksft_print_msg(
> -				"CORRUPTED: page %zu (huge page %" PRIu64 "): expected idx %zu, got %" PRIu64 "\n",
> -				page_idx, (page_idx * page_size) / pmd_pagesize,
> -				page_idx, got_idx);
> +			ksft_print_msg("CORRUPTED: page %" PRIu64
> +				       " (huge page %" PRIu64
> +				       "): expected idx %" PRIu64
> +				       ", got %" PRIu64 "\n",
> +				       page_idx,
> +				       (page_idx * page_size) / pmd_pagesize,
> +				       page_idx, got_idx);

The above two are printf format change from %zu to PRIu64 for size_t -> uint64_t
change. Code is reformatted as well.

>  		}
>  		return false;
>  	}
> @@ -97,8 +101,8 @@ struct reader_arg {
>  	unsigned char *base;
>  	struct shared_ctl *ctl;
>  	int tid;
> -	atomic_size_t *failures;
> -	atomic_size_t *verified;
> +	atomic_uint_fast64_t *failures;
> +	atomic_uint_fast64_t *verified;
>  };
>
>  static void *reader_thread(void *arg)
> @@ -107,9 +111,9 @@ static void *reader_thread(void *arg)
>  	unsigned char *base = ra->base;
>  	struct shared_ctl *ctl = ra->ctl;
>  	int tid = ra->tid;
> -	atomic_size_t *failures = ra->failures;
> -	atomic_size_t *verified = ra->verified;
> -	size_t page_idx;
> +	atomic_uint_fast64_t *failures = ra->failures;
> +	atomic_uint_fast64_t *verified = ra->verified;
> +	uint64_t page_idx;
>
>  	pthread_barrier_wait(&ctl->barrier);
>
> @@ -154,14 +158,14 @@ static void create_readers(pthread_t *th
>  }
>
>  /* Run a single iteration. Returns total number of corrupted pages. */
> -static size_t run_iteration(void)
> +static uint64_t run_iteration(void)
>  {
> -	size_t reader_failures, reader_verified;
> +	uint64_t reader_failures, reader_verified;
>  	struct reader_arg args[NUM_READER_THREADS];
>  	pthread_t threads[NUM_READER_THREADS];
>  	unsigned char *mmap_base;
>  	struct shared_ctl ctl;
> -	size_t i;
> +	uint64_t i;
>
>  	memset(&ctl, 0, sizeof(struct shared_ctl));
>
> @@ -195,7 +199,7 @@ static size_t run_iteration(void)
>  		if (madvise(mmap_base + i * page_size,
>  			    PUNCH_SIZE_FACTOR * page_size, MADV_REMOVE) != 0) {
>  			ksft_exit_fail_msg(
> -				"madvise(MADV_REMOVE) failed on page %zu: %d\n",
> +				"madvise(MADV_REMOVE) failed on page %" PRIu64 ": %d\n",
>  				i, errno);
>  		}
>
> @@ -214,7 +218,7 @@ static size_t run_iteration(void)
>  	reader_verified = atomic_load_explicit(&ctl.reader_verified,
>  					       memory_order_acquire);
>  	if (reader_failures)
> -		ksft_print_msg("Child: %zu pages verified, %zu failures\n",
> +		ksft_print_msg("Child: %" PRIu64 " pages verified, %" PRIu64 " failures\n",
>  			       reader_verified, reader_failures);
>
>  	munmap(mmap_base, FILE_SIZE);
> @@ -242,13 +246,15 @@ static void thp_settings_cleanup(void)
>  int main(void)
>  {
>  	struct thp_settings current_settings;
> -	bool failed = false;
> -	size_t failures;
> -	size_t iter;
> +	uint64_t corrupted_pages;
> +	uint64_t iter;

The above changes are all about size_t to uint64_t change and related
printf format change.

>
>  	ksft_print_header();
>
> -	if (!thp_is_enabled())
> +	page_size = getpagesize();
> +	pmd_pagesize = read_pmd_pagesize();
> +
> +	if (!thp_available() || !pmd_pagesize)
>  		ksft_exit_skip("Transparent Hugepages not available\n");

This addresses David's comment on thp_is_enable() vs thp_available()
and pmd_pagesize can be zero when THP is not available.

>
>  	if (geteuid() != 0)
> @@ -268,37 +274,24 @@ int main(void)
>
>  	ksft_set_plan(1);
>
> -	page_size = getpagesize();
> -	pmd_pagesize = read_pmd_pagesize();
> -
>  	ksft_print_msg("folio split race test\n");
> -	ksft_print_msg("===================================================\n");
> -	ksft_print_msg("Shmem size:       %" PRIu64 " MiB\n", FILE_SIZE / 1024 / 1024);
> -	ksft_print_msg("Total pages:     %" PRIu64 "\n", TOTAL_PAGES);
> -	ksft_print_msg("Child readers:   %d\n", NUM_READER_THREADS);
> -	ksft_print_msg("Punching every %dth to %dth page\n", PUNCH_INTERVAL,
> -		       PUNCH_INTERVAL + PUNCH_SIZE_FACTOR);
> -	ksft_print_msg("Iterations:      %d\n", NUM_ITERATIONS);

Removed based on David's feedback.

> -
> -	for (iter = 1; iter <= NUM_ITERATIONS; iter++) {
> -		failures = run_iteration();
> -		if (failures > 0) {
> -			failed = true;
> -			ksft_print_msg(
> -				"FAILED on iteration %zu: %zu pages corrupted by MADV_REMOVE!\n",
> -				iter, failures);
> +
> +	for (iter = 0; iter < NUM_ITERATIONS; iter++) {
> +		corrupted_pages = run_iteration();
> +		if (corrupted_pages > 0)
>  			break;
> -		}
>  	}
>
> -	if (failed) {
> -		ksft_test_result_fail("Test failed\n");
> -		ksft_exit_fail();
> -	} else {
> +	if (iter < NUM_ITERATIONS)
> +		ksft_test_result_fail("FAILED on iteration %" PRIu64
> +				      ": %" PRIu64
> +				      " pages corrupted by MADV_REMOVE!\n",
> +				      iter, corrupted_pages);
> +	else
>  		ksft_test_result_pass("All %d iterations passed\n",
>  				      NUM_ITERATIONS);
> -		ksft_exit_pass();
> -	}
> +
> +	ksft_exit(iter == NUM_ITERATIONS);

Simplification based on David's feedback. No function change.

>
>  	return 0;
>  }
> _


--
Best Regards,
Yan, Zi


      reply	other threads:[~2026-03-26  1:53 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-23 16:37 [PATCH v5] selftests/mm: add folio_split() and filemap_get_entry() race test Zi Yan
2026-03-26  0:39 ` Zi Yan
2026-03-26  1:47 ` Andrew Morton
2026-03-26  1:53   ` Zi Yan [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=B1437C8C-8827-4588-B42C-147392251983@nvidia.com \
    --to=ziy@nvidia.com \
    --cc=Liam.Howlett@oracle.com \
    --cc=adam.bratschikaye@dfinity.org \
    --cc=akpm@linux-foundation.org \
    --cc=andrew.battat@dfinity.org \
    --cc=baohua@kernel.org \
    --cc=baolin.wang@linux.alibaba.com \
    --cc=bas@dfinity.org \
    --cc=david@kernel.org \
    --cc=dev.jain@arm.com \
    --cc=eero.kelly@dfinity.org \
    --cc=hughd@google.com \
    --cc=lance.yang@linux.dev \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=lorenzo.stoakes@oracle.com \
    --cc=npache@redhat.com \
    --cc=ryan.roberts@arm.com \
    --cc=willy@infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox