Re: [PATCH v6] mm: assert exclusive nid/zonenum bits at the page/folio access sites
From: David Hildenbrand (Arm)
Date: Mon Jun 29 2026 - 02:39:33 EST
On 6/28/26 06:30, Andrew Morton wrote:
> On Fri, 26 Jun 2026 10:06:29 +0800 Hui Zhu <hui.zhu@xxxxxxxxx> wrote:
>
>> From: Hui Zhu <zhuhui@xxxxxxxxxx>
>>
>> KCSAN reports a data race between page_to_nid()/folio_pgdat() reading
>> page->flags and folio_trylock()/folio_lock() concurrently doing
>> test_and_set_bit_lock(PG_locked, ...) on the same word, e.g.:
>>
>> BUG: KCSAN: data-race in __lruvec_stat_mod_folio / shmem_get_folio_gfp
>>
>> The node id and zone id occupy fixed bit-ranges of page->flags that
>> are set once at page init and never modified afterwards, so they can
>> never overlap with the low PG_locked/PG_waiters bits touched by the
>> folio lock path.
>>
>> ASSERT_EXCLUSIVE_BITS(mdf.f, ...) inside memdesc_nid()/memdesc_zonenum()
>> used to check a by-value copy of the flags word, not the actual shared
>> page->flags/folio->flags being modified concurrently, so it didn't
>> reliably assert anything about the real race.
>>
>> For zonenum, move the assertion out of memdesc_zonenum() into
>> page_zonenum() and folio_zonenum(), where flags is dereferenced
>> directly from the page/folio.
>>
>> For nid, turn memdesc_nid() into a macro instead, so the mdf argument
>> is expanded as the caller's own flags expression
>> (PF_POISONED_CHECK(page)->flags or folio->flags) rather than copied
>> into a function parameter, letting ASSERT_EXCLUSIVE_BITS() check the
>> real page->flags/folio->flags directly.
>>
>> On CONFIG_NUMA=n, NODES_MASK is 0 and the old memdesc_nid() body
>> folded to a constant, so page->flags/folio->flags was never actually
>> read. ASSERT_EXCLUSIVE_BITS() is a real runtime check that can't be
>> folded away, so doing it unconditionally would add a pointless read
>> of page->flags/folio->flags and a check that can never fire. Keep
>> page_to_nid()/folio_nid() as plain "return 0" static inline stubs
>> under CONFIG_NUMA=n instead.
>>
>
> Thanks for persisting with this.
>
> ASSERT_EXCLUSIVE_BITS is defined in kcsan-checks.h and I'm not
> immediately seeing a reliable route by which mm.h and mmzone.h get to
> include that file. I don't think kasan.h gives that to us,
> surprisingly.
>
> Unless I've missed it, we're presently getting kcsan-checks.h thanks to
> good luck. Let's not rely upon good luck ;)
>
>
> Also, Sashiko is saying stuff again. Does it look legitimate?
> https://sashiko.dev/#/patchset/20260626020629.1042041-1-hui.zhu@xxxxxxxxx
>
Let's see whether pass-by-reference as suggested in reply to v7 sorts this out.
--
Cheers,
David