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
prev parent 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