From: Andrew Morton <akpm@linux-foundation.org>
To: Zi Yan <ziy@nvidia.com>
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 18:47:31 -0700 [thread overview]
Message-ID: <20260325184731.791eda3b81cee4ad3f3ec17e@linux-foundation.org> (raw)
In-Reply-To: <20260323163717.184107-1-ziy@nvidia.com>
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.
Here's how v5 alters mm.git. It's quite a large update.
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;
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);
}
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;
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");
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);
-
- 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);
return 0;
}
_
next prev parent reply other threads:[~2026-03-26 1:47 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-23 16:37 Zi Yan
2026-03-26 0:39 ` Zi Yan
2026-03-26 1:47 ` Andrew Morton [this message]
2026-03-26 1:53 ` Zi Yan
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=20260325184731.791eda3b81cee4ad3f3ec17e@linux-foundation.org \
--to=akpm@linux-foundation.org \
--cc=Liam.Howlett@oracle.com \
--cc=adam.bratschikaye@dfinity.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 \
--cc=ziy@nvidia.com \
/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