* [PATCH v7] mm: assert exclusive nid/zonenum bits at the page/folio access sites
@ 2026-06-26 3:20 Hui Zhu
2026-06-26 4:54 ` kernel test robot
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Hui Zhu @ 2026-06-26 3:20 UTC (permalink / raw)
To: Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Kairui Song, Qi Zheng,
Shakeel Butt, Barry Song, Axel Rasmussen, Yuanchu Xie, Wei Xu,
linux-mm, linux-kernel
Cc: Hui Zhu
From: Hui Zhu <zhuhui@kylinos.cn>
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.
Signed-off-by: Hui Zhu <zhuhui@kylinos.cn>
---
Changelog:
v7:
According to the comments of Sashiko, restrict the memdesc_nid() macro
to CONFIG_NUMA, keeping a plain "return 0" static inline stub otherwise,
and re-add a local page pointer in page_to_nid() to avoid evaluating
PF_POISONED_CHECK(page) twice.
v6:
According to the comments of David, turn memdesc_nid() from a static
inline function into a macro so ASSERT_EXCLUSIVE_BITS() can check the
caller's page->flags/folio->flags directly.
v5:
According to the comments of Sashiko, guard the ASSERT_EXCLUSIVE_BITS()
calls with #ifndef NODE_NOT_IN_PAGE_FLAGS (for nid) and #if
ZONES_WIDTH != 0 (for zonenum).
According to the comments of David, avoid calling
PF_POISONED_CHECK(page) twice in page_to_nid().
According to the warning of lkp, switch the CONFIG_NUMA=n
page_to_nid()/folio_nid() stubs from macros to static inline functions.
v4:
According to the comments of Andrew and Sashiko, set
page_to_nid()/folio_nid() as static inline stubs returning 0
under CONFIG_NUMA=n.
v3:
According to the comments of Andrew and Sashiko, move
ASSERT_EXCLUSIVE_BITS out of memdesc_nid()/memdesc_zonenum()
into the page/folio call sites.
v2:
According to the comments of David, remove useless comments and use
ASSERT_EXCLUSIVE_BITS() in memdesc_nid() instead of data_race() in
page_to_nid().
include/linux/mm.h | 25 +++++++++++++++++++++++--
include/linux/mmzone.h | 7 ++++++-
2 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 485df9c2dbdd..63fcf277b675 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2288,21 +2288,42 @@ static inline int page_zone_id(struct page *page)
#ifdef NODE_NOT_IN_PAGE_FLAGS
int memdesc_nid(memdesc_flags_t mdf);
#else
+#ifdef CONFIG_NUMA
+#define memdesc_nid(mdf) \
+({ \
+ ASSERT_EXCLUSIVE_BITS(mdf.f, NODES_MASK << NODES_PGSHIFT); \
+ (int)((mdf.f >> NODES_PGSHIFT) & NODES_MASK); \
+})
+#else
static inline int memdesc_nid(memdesc_flags_t mdf)
{
- return (mdf.f >> NODES_PGSHIFT) & NODES_MASK;
+ return 0;
}
#endif
+#ifdef CONFIG_NUMA
static inline int page_to_nid(const struct page *page)
{
- return memdesc_nid(PF_POISONED_CHECK(page)->flags);
+ const struct page *p = PF_POISONED_CHECK(page);
+
+ return memdesc_nid(p->flags);
}
static inline int folio_nid(const struct folio *folio)
{
return memdesc_nid(folio->flags);
}
+#else
+static inline int page_to_nid(const struct page *page)
+{
+ return 0;
+}
+
+static inline int folio_nid(const struct folio *folio)
+{
+ return 0;
+}
+#endif
#ifdef CONFIG_NUMA_BALANCING
/* page access time bits needs to hold at least 4 seconds */
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index ca2712187147..1b4336098113 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -1274,17 +1274,22 @@ static inline bool zone_is_empty(const struct zone *zone)
static inline enum zone_type memdesc_zonenum(memdesc_flags_t flags)
{
- ASSERT_EXCLUSIVE_BITS(flags.f, ZONES_MASK << ZONES_PGSHIFT);
return (flags.f >> ZONES_PGSHIFT) & ZONES_MASK;
}
static inline enum zone_type page_zonenum(const struct page *page)
{
+#if ZONES_WIDTH != 0
+ ASSERT_EXCLUSIVE_BITS(page->flags, ZONES_MASK << ZONES_PGSHIFT);
+#endif
return memdesc_zonenum(page->flags);
}
static inline enum zone_type folio_zonenum(const struct folio *folio)
{
+#if ZONES_WIDTH != 0
+ ASSERT_EXCLUSIVE_BITS(folio->flags, ZONES_MASK << ZONES_PGSHIFT);
+#endif
return memdesc_zonenum(folio->flags);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v7] mm: assert exclusive nid/zonenum bits at the page/folio access sites
2026-06-26 3:20 [PATCH v7] mm: assert exclusive nid/zonenum bits at the page/folio access sites Hui Zhu
@ 2026-06-26 4:54 ` kernel test robot
2026-06-26 4:54 ` kernel test robot
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: kernel test robot @ 2026-06-26 4:54 UTC (permalink / raw)
To: Hui Zhu, Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Kairui Song, Qi Zheng,
Shakeel Butt, Barry Song, Axel Rasmussen, Yuanchu Xie, Wei Xu,
linux-kernel
Cc: llvm, oe-kbuild-all, Linux Memory Management List, Hui Zhu
Hi Hui,
kernel test robot noticed the following build errors:
[auto build test ERROR on akpm-mm/mm-everything]
url: https://github.com/intel-lab-lkp/linux/commits/Hui-Zhu/mm-assert-exclusive-nid-zonenum-bits-at-the-page-folio-access-sites/20260626-112119
base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything
patch link: https://lore.kernel.org/r/20260626032012.1049667-1-hui.zhu%40linux.dev
patch subject: [PATCH v7] mm: assert exclusive nid/zonenum bits at the page/folio access sites
config: x86_64-allnoconfig (https://download.01.org/0day-ci/archive/20260626/202606261253.X4CwKZZJ-lkp@intel.com/config)
compiler: clang version 22.1.3 (https://github.com/llvm/llvm-project e9846648fd6183ee6d8cbdb4502213fcf902a211)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260626/202606261253.X4CwKZZJ-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202606261253.X4CwKZZJ-lkp@intel.com/
All errors (new ones prefixed by >>):
WARN /zdci/src/lkp/lib/log.sh:131:in `log_warn': /opt/cross/rustc-1.96.0-bindgen-0.72.1 doesn't exist
from /zdci/src/kernel-tests/lib/debug.sh:164: kbuild_log_warn
from /zdci/src/kernel-tests/lib/kbuild.sh:3371: export_rust_path
from /zdci/src/kernel-tests/lib/kbuild.sh:3361: export_compiler_path
from /zdci/src/kernel-tests/lib/kbuild.sh:3840: invoke_make
from /zdci/src/kernel-tests/lib/kbuild.sh:4022: make
from /zdci/src/kernel-tests/common.sh:202: redirect_error_to_screen
from /zdci/src/kernel-tests/common.sh:210: redirect_command_errors
from /zdci/src/kernel-tests/lib/kbuild.sh:5680: make_prepare
from /zdci/src/kernel-tests/lib/kbuild.sh:5909: test_kernel_build
from /zdci/src/kernel-tests/lib/builder/base.sh:442: builder_execute_build
from /zdci/src/kernel-tests/lib/kbuild.sh:6419: compile_one_config
from /zdci/src/kernel-tests/lib/builder/base.sh:88: builder_compile
from /zdci/src/kernel-tests/bisect-test-build-error.sh:102: main
In file included from arch/x86/kernel/asm-offsets.c:14:
In file included from include/linux/suspend.h:5:
In file included from include/linux/swap.h:9:
In file included from include/linux/memcontrol.h:21:
>> include/linux/mm.h:2:2: error: unterminated conditional directive
2 | #ifndef _LINUX_MM_H
| ^
In file included from arch/x86/kernel/asm-offsets.c:14:
In file included from include/linux/suspend.h:5:
In file included from include/linux/swap.h:9:
In file included from include/linux/memcontrol.h:23:
In file included from include/linux/writeback.h:13:
In file included from include/linux/blk_types.h:10:
In file included from include/linux/bvec.h:10:
In file included from include/linux/highmem.h:8:
In file included from include/linux/cacheflush.h:5:
In file included from arch/x86/include/asm/cacheflush.h:5:
>> include/linux/mm.h:2:2: error: unterminated conditional directive
2 | #ifndef _LINUX_MM_H
| ^
In file included from arch/x86/kernel/asm-offsets.c:14:
In file included from include/linux/suspend.h:5:
In file included from include/linux/swap.h:9:
In file included from include/linux/memcontrol.h:23:
In file included from include/linux/writeback.h:13:
In file included from include/linux/blk_types.h:10:
In file included from include/linux/bvec.h:10:
In file included from include/linux/highmem.h:10:
>> include/linux/mm.h:2:2: error: unterminated conditional directive
2 | #ifndef _LINUX_MM_H
| ^
In file included from arch/x86/kernel/asm-offsets.c:14:
In file included from include/linux/suspend.h:5:
In file included from include/linux/swap.h:13:
In file included from include/linux/pagemap.h:8:
>> include/linux/mm.h:2:2: error: unterminated conditional directive
2 | #ifndef _LINUX_MM_H
| ^
In file included from arch/x86/kernel/asm-offsets.c:14:
In file included from include/linux/suspend.h:5:
In file included from include/linux/swap.h:13:
In file included from include/linux/pagemap.h:17:
In file included from include/linux/hugetlb_inline.h:5:
>> include/linux/mm.h:2:2: error: unterminated conditional directive
2 | #ifndef _LINUX_MM_H
| ^
In file included from arch/x86/kernel/asm-offsets.c:14:
In file included from include/linux/suspend.h:9:
>> include/linux/mm.h:2:2: error: unterminated conditional directive
2 | #ifndef _LINUX_MM_H
| ^
6 errors generated.
make[3]: *** [scripts/Makefile.build:184: arch/x86/kernel/asm-offsets.s] Error 1
make[3]: Target 'prepare' not remade because of errors.
make[2]: *** [Makefile:1390: prepare0] Error 2
make[2]: Target 'prepare' not remade because of errors.
make[1]: *** [Makefile:248: __sub-make] Error 2
make[1]: Target 'prepare' not remade because of errors.
make: *** [Makefile:248: __sub-make] Error 2
make: Target 'prepare' not remade because of errors.
vim +2 include/linux/mm.h
^1da177e4c3f41 Linus Torvalds 2005-04-16 @2 #ifndef _LINUX_MM_H
^1da177e4c3f41 Linus Torvalds 2005-04-16 3 #define _LINUX_MM_H
^1da177e4c3f41 Linus Torvalds 2005-04-16 4
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v7] mm: assert exclusive nid/zonenum bits at the page/folio access sites
2026-06-26 3:20 [PATCH v7] mm: assert exclusive nid/zonenum bits at the page/folio access sites Hui Zhu
2026-06-26 4:54 ` kernel test robot
@ 2026-06-26 4:54 ` kernel test robot
2026-06-26 5:04 ` Leon Hwang
2026-06-26 6:05 ` kernel test robot
3 siblings, 0 replies; 6+ messages in thread
From: kernel test robot @ 2026-06-26 4:54 UTC (permalink / raw)
To: Hui Zhu, Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Kairui Song, Qi Zheng,
Shakeel Butt, Barry Song, Axel Rasmussen, Yuanchu Xie, Wei Xu,
linux-kernel
Cc: oe-kbuild-all, Linux Memory Management List, Hui Zhu
Hi Hui,
kernel test robot noticed the following build errors:
[auto build test ERROR on akpm-mm/mm-everything]
url: https://github.com/intel-lab-lkp/linux/commits/Hui-Zhu/mm-assert-exclusive-nid-zonenum-bits-at-the-page-folio-access-sites/20260626-112119
base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything
patch link: https://lore.kernel.org/r/20260626032012.1049667-1-hui.zhu%40linux.dev
patch subject: [PATCH v7] mm: assert exclusive nid/zonenum bits at the page/folio access sites
config: nios2-allnoconfig (https://download.01.org/0day-ci/archive/20260626/202606261257.rnknH3QK-lkp@intel.com/config)
compiler: nios2-linux-gcc (GCC) 11.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260626/202606261257.rnknH3QK-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202606261257.rnknH3QK-lkp@intel.com/
All errors (new ones prefixed by >>):
In file included from include/linux/pid_namespace.h:7,
from include/linux/ptrace.h:10,
from arch/nios2/kernel/asm-offsets.c:10:
>> include/linux/mm.h:2: error: unterminated #ifndef
2 | #ifndef _LINUX_MM_H
|
make[3]: *** [scripts/Makefile.build:184: arch/nios2/kernel/asm-offsets.s] Error 1
make[3]: Target 'prepare' not remade because of errors.
make[2]: *** [Makefile:1390: prepare0] Error 2
make[2]: Target 'prepare' not remade because of errors.
make[1]: *** [Makefile:248: __sub-make] Error 2
make[1]: Target 'prepare' not remade because of errors.
make: *** [Makefile:248: __sub-make] Error 2
make: Target 'prepare' not remade because of errors.
vim +2 include/linux/mm.h
^1da177e4c3f41 Linus Torvalds 2005-04-16 @2 #ifndef _LINUX_MM_H
^1da177e4c3f41 Linus Torvalds 2005-04-16 3 #define _LINUX_MM_H
^1da177e4c3f41 Linus Torvalds 2005-04-16 4
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v7] mm: assert exclusive nid/zonenum bits at the page/folio access sites
2026-06-26 3:20 [PATCH v7] mm: assert exclusive nid/zonenum bits at the page/folio access sites Hui Zhu
2026-06-26 4:54 ` kernel test robot
2026-06-26 4:54 ` kernel test robot
@ 2026-06-26 5:04 ` Leon Hwang
2026-06-26 9:09 ` David Hildenbrand (Arm)
2026-06-26 6:05 ` kernel test robot
3 siblings, 1 reply; 6+ messages in thread
From: Leon Hwang @ 2026-06-26 5:04 UTC (permalink / raw)
To: Hui Zhu, Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Kairui Song, Qi Zheng,
Shakeel Butt, Barry Song, Axel Rasmussen, Yuanchu Xie, Wei Xu,
linux-mm, linux-kernel
Cc: Hui Zhu
On 26/6/26 11:20, Hui Zhu wrote:
> From: Hui Zhu <zhuhui@kylinos.cn>
>
> 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.
>
> Signed-off-by: Hui Zhu <zhuhui@kylinos.cn>
> ---
> Changelog:
> v7:
> According to the comments of Sashiko, restrict the memdesc_nid() macro
> to CONFIG_NUMA, keeping a plain "return 0" static inline stub otherwise,
> and re-add a local page pointer in page_to_nid() to avoid evaluating
> PF_POISONED_CHECK(page) twice.
> v6:
> According to the comments of David, turn memdesc_nid() from a static
> inline function into a macro so ASSERT_EXCLUSIVE_BITS() can check the
> caller's page->flags/folio->flags directly.
> v5:
> According to the comments of Sashiko, guard the ASSERT_EXCLUSIVE_BITS()
> calls with #ifndef NODE_NOT_IN_PAGE_FLAGS (for nid) and #if
> ZONES_WIDTH != 0 (for zonenum).
> According to the comments of David, avoid calling
> PF_POISONED_CHECK(page) twice in page_to_nid().
> According to the warning of lkp, switch the CONFIG_NUMA=n
> page_to_nid()/folio_nid() stubs from macros to static inline functions.
> v4:
> According to the comments of Andrew and Sashiko, set
> page_to_nid()/folio_nid() as static inline stubs returning 0
> under CONFIG_NUMA=n.
> v3:
> According to the comments of Andrew and Sashiko, move
> ASSERT_EXCLUSIVE_BITS out of memdesc_nid()/memdesc_zonenum()
> into the page/folio call sites.
> v2:
> According to the comments of David, remove useless comments and use
> ASSERT_EXCLUSIVE_BITS() in memdesc_nid() instead of data_race() in
> page_to_nid().
>
> include/linux/mm.h | 25 +++++++++++++++++++++++--
> include/linux/mmzone.h | 7 ++++++-
> 2 files changed, 29 insertions(+), 3 deletions(-)
>
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 485df9c2dbdd..63fcf277b675 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -2288,21 +2288,42 @@ static inline int page_zone_id(struct page *page)
> #ifdef NODE_NOT_IN_PAGE_FLAGS
> int memdesc_nid(memdesc_flags_t mdf);
> #else
> +#ifdef CONFIG_NUMA
> +#define memdesc_nid(mdf) \
> +({ \
> + ASSERT_EXCLUSIVE_BITS(mdf.f, NODES_MASK << NODES_PGSHIFT); \
> + (int)((mdf.f >> NODES_PGSHIFT) & NODES_MASK); \
> +})
> +#else
> static inline int memdesc_nid(memdesc_flags_t mdf)
> {
> - return (mdf.f >> NODES_PGSHIFT) & NODES_MASK;
> + return 0;
> }
> #endif
>
> +#ifdef CONFIG_NUMA
> static inline int page_to_nid(const struct page *page)
> {
> - return memdesc_nid(PF_POISONED_CHECK(page)->flags);
> + const struct page *p = PF_POISONED_CHECK(page);
> +
> + return memdesc_nid(p->flags);
> }
>
> static inline int folio_nid(const struct folio *folio)
> {
> return memdesc_nid(folio->flags);
> }
> +#else
> +static inline int page_to_nid(const struct page *page)
> +{
> + return 0;
> +}
> +
> +static inline int folio_nid(const struct folio *folio)
> +{
> + return 0;
> +}
> +#endif
>
> #ifdef CONFIG_NUMA_BALANCING
> /* page access time bits needs to hold at least 4 seconds */
> diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
> index ca2712187147..1b4336098113 100644
> --- a/include/linux/mmzone.h
> +++ b/include/linux/mmzone.h
> @@ -1274,17 +1274,22 @@ static inline bool zone_is_empty(const struct zone *zone)
>
> static inline enum zone_type memdesc_zonenum(memdesc_flags_t flags)
> {
> - ASSERT_EXCLUSIVE_BITS(flags.f, ZONES_MASK << ZONES_PGSHIFT);
> return (flags.f >> ZONES_PGSHIFT) & ZONES_MASK;
> }
>
> static inline enum zone_type page_zonenum(const struct page *page)
> {
> +#if ZONES_WIDTH != 0
> + ASSERT_EXCLUSIVE_BITS(page->flags, ZONES_MASK << ZONES_PGSHIFT);
> +#endif
> return memdesc_zonenum(page->flags);
> }
>
> static inline enum zone_type folio_zonenum(const struct folio *folio)
> {
> +#if ZONES_WIDTH != 0
> + ASSERT_EXCLUSIVE_BITS(folio->flags, ZONES_MASK << ZONES_PGSHIFT);
> +#endif
> return memdesc_zonenum(folio->flags);
> }
>
Better to factor out a common macro alongside a comment for these two '#if'?
Thanks,
Leon
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v7] mm: assert exclusive nid/zonenum bits at the page/folio access sites
2026-06-26 3:20 [PATCH v7] mm: assert exclusive nid/zonenum bits at the page/folio access sites Hui Zhu
` (2 preceding siblings ...)
2026-06-26 5:04 ` Leon Hwang
@ 2026-06-26 6:05 ` kernel test robot
3 siblings, 0 replies; 6+ messages in thread
From: kernel test robot @ 2026-06-26 6:05 UTC (permalink / raw)
To: Hui Zhu, Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Kairui Song, Qi Zheng,
Shakeel Butt, Barry Song, Axel Rasmussen, Yuanchu Xie, Wei Xu,
linux-kernel
Cc: oe-kbuild-all, Linux Memory Management List, Hui Zhu
Hi Hui,
kernel test robot noticed the following build errors:
[auto build test ERROR on akpm-mm/mm-everything]
url: https://github.com/intel-lab-lkp/linux/commits/Hui-Zhu/mm-assert-exclusive-nid-zonenum-bits-at-the-page-folio-access-sites/20260626-112119
base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything
patch link: https://lore.kernel.org/r/20260626032012.1049667-1-hui.zhu%40linux.dev
patch subject: [PATCH v7] mm: assert exclusive nid/zonenum bits at the page/folio access sites
config: x86_64-rhel-9.4-rust (https://download.01.org/0day-ci/archive/20260626/202606260757.WdVU9G1N-lkp@intel.com/config)
compiler: clang version 22.1.8 (https://github.com/llvm/llvm-project ca7933e47d3a3451d81e72ac174dcb5aa28b59d1)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260626/202606260757.WdVU9G1N-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202606260757.WdVU9G1N-lkp@intel.com/
All errors (new ones prefixed by >>):
In file included from arch/x86/kernel/asm-offsets.c:14:
In file included from include/linux/suspend.h:5:
In file included from include/linux/swap.h:9:
In file included from include/linux/memcontrol.h:21:
>> include/linux/mm.h:2:2: error: unterminated conditional directive
2 | #ifndef _LINUX_MM_H
| ^
In file included from arch/x86/kernel/asm-offsets.c:14:
In file included from include/linux/suspend.h:5:
In file included from include/linux/swap.h:9:
In file included from include/linux/memcontrol.h:23:
In file included from include/linux/writeback.h:13:
In file included from include/linux/blk_types.h:10:
In file included from include/linux/bvec.h:10:
In file included from include/linux/highmem.h:8:
In file included from include/linux/cacheflush.h:5:
In file included from arch/x86/include/asm/cacheflush.h:5:
>> include/linux/mm.h:2:2: error: unterminated conditional directive
2 | #ifndef _LINUX_MM_H
| ^
In file included from arch/x86/kernel/asm-offsets.c:14:
In file included from include/linux/suspend.h:5:
In file included from include/linux/swap.h:9:
In file included from include/linux/memcontrol.h:23:
In file included from include/linux/writeback.h:13:
In file included from include/linux/blk_types.h:10:
In file included from include/linux/bvec.h:10:
In file included from include/linux/highmem.h:10:
>> include/linux/mm.h:2:2: error: unterminated conditional directive
2 | #ifndef _LINUX_MM_H
| ^
In file included from arch/x86/kernel/asm-offsets.c:14:
In file included from include/linux/suspend.h:5:
In file included from include/linux/swap.h:13:
In file included from include/linux/pagemap.h:8:
>> include/linux/mm.h:2:2: error: unterminated conditional directive
2 | #ifndef _LINUX_MM_H
| ^
In file included from arch/x86/kernel/asm-offsets.c:14:
In file included from include/linux/suspend.h:5:
In file included from include/linux/swap.h:13:
In file included from include/linux/pagemap.h:17:
In file included from include/linux/hugetlb_inline.h:5:
>> include/linux/mm.h:2:2: error: unterminated conditional directive
2 | #ifndef _LINUX_MM_H
| ^
In file included from arch/x86/kernel/asm-offsets.c:14:
In file included from include/linux/suspend.h:9:
>> include/linux/mm.h:2:2: error: unterminated conditional directive
2 | #ifndef _LINUX_MM_H
| ^
6 errors generated.
vim +2 include/linux/mm.h
^1da177e4c3f415 Linus Torvalds 2005-04-16 @2 #ifndef _LINUX_MM_H
^1da177e4c3f415 Linus Torvalds 2005-04-16 3 #define _LINUX_MM_H
^1da177e4c3f415 Linus Torvalds 2005-04-16 4
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v7] mm: assert exclusive nid/zonenum bits at the page/folio access sites
2026-06-26 5:04 ` Leon Hwang
@ 2026-06-26 9:09 ` David Hildenbrand (Arm)
0 siblings, 0 replies; 6+ messages in thread
From: David Hildenbrand (Arm) @ 2026-06-26 9:09 UTC (permalink / raw)
To: Leon Hwang, Hui Zhu, Andrew Morton, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Kairui Song, Qi Zheng,
Shakeel Butt, Barry Song, Axel Rasmussen, Yuanchu Xie, Wei Xu,
linux-mm, linux-kernel
Cc: Hui Zhu
>>
>> static inline enum zone_type folio_zonenum(const struct folio *folio)
>> {
>> +#if ZONES_WIDTH != 0
>> + ASSERT_EXCLUSIVE_BITS(folio->flags, ZONES_MASK << ZONES_PGSHIFT);
>> +#endif
>> return memdesc_zonenum(folio->flags);
>> }
>>
>
> Better to factor out a common macro alongside a comment for these two '#if'?
Yes.
And while looking at it, doesn't memdesc_section have similar problems? And
there are other callers of memdesc_zonenum we wouldn't handle. So the
macro approach is only partially helpful I thing.
Maybe we should just pass by reference and fixup all callers? Ends up the cleanest.
Untested:
From fb9b4e8c1d0419b960dc0cd4738d19d80d1fe14f Mon Sep 17 00:00:00 2001
From: "David Hildenbrand (Arm)" <david@kernel.org>
Date: Fri, 26 Jun 2026 11:06:39 +0200
Subject: [PATCH] mm: fix KASAN memdec_flags checks for zone/node/section
Signed-off-by: David Hildenbrand (Arm) <david@kernel.org>
---
include/asm-generic/memory_model.h | 2 +-
include/linux/mm.h | 23 +++++++++++++++--------
include/linux/mm_inline.h | 4 ++--
include/linux/mmzone.h | 24 ++++++++++++------------
mm/page_alloc.c | 6 +++---
mm/slab.h | 2 +-
mm/sparse.c | 2 +-
7 files changed, 35 insertions(+), 28 deletions(-)
diff --git a/include/asm-generic/memory_model.h b/include/asm-generic/memory_model.h
index efa6610acbc79..f8404bc7773c2 100644
--- a/include/asm-generic/memory_model.h
+++ b/include/asm-generic/memory_model.h
@@ -53,7 +53,7 @@ static inline int pfn_valid(unsigned long pfn)
*/
#define __page_to_pfn(pg) \
({ const struct page *__pg = (pg); \
- int __sec = memdesc_section(__pg->flags); \
+ int __sec = memdesc_section(&__pg->flags); \
(unsigned long)(__pg - __section_mem_map_addr(__nr_to_section(__sec))); \
})
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 485df9c2dbddb..3111e4a6c9c4c 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2286,22 +2286,28 @@ static inline int page_zone_id(struct page *page)
}
#ifdef NODE_NOT_IN_PAGE_FLAGS
-int memdesc_nid(memdesc_flags_t mdf);
+int memdesc_nid(const memdesc_flags_t *mdf);
+#elif defined(CONFIG_NUMA)
+static inline int memdesc_nid(const memdesc_flags_t *mdf)
+{
+ ASSERT_EXCLUSIVE_BITS(mdf->f, NODES_MASK << NODES_PGSHIFT);
+ return (mdf->f >> NODES_PGSHIFT) & NODES_MASK;
+}
#else
-static inline int memdesc_nid(memdesc_flags_t mdf)
+static inline int memdesc_nid(const memdesc_flags_t *mdf)
{
- return (mdf.f >> NODES_PGSHIFT) & NODES_MASK;
+ return 0;
}
#endif
static inline int page_to_nid(const struct page *page)
{
- return memdesc_nid(PF_POISONED_CHECK(page)->flags);
+ return memdesc_nid(&PF_POISONED_CHECK(page)->flags);
}
static inline int folio_nid(const struct folio *folio)
{
- return memdesc_nid(folio->flags);
+ return memdesc_nid(&folio->flags);
}
#ifdef CONFIG_NUMA_BALANCING
@@ -2541,12 +2547,13 @@ static inline void set_page_section(struct page *page, unsigned long section)
page->flags.f |= (section & SECTIONS_MASK) << SECTIONS_PGSHIFT;
}
-static inline unsigned long memdesc_section(memdesc_flags_t mdf)
+static inline unsigned long memdesc_section(const memdesc_flags_t *mdf)
{
- return (mdf.f >> SECTIONS_PGSHIFT) & SECTIONS_MASK;
+ ASSERT_EXCLUSIVE_BITS(mdf->f, SECTIONS_MASK << SECTIONS_PGSHIFT);
+ return (mdf->f >> SECTIONS_PGSHIFT) & SECTIONS_MASK;
}
#else /* !SECTION_IN_PAGE_FLAGS */
-static inline unsigned long memdesc_section(memdesc_flags_t mdf)
+static inline unsigned long memdesc_section(const memdesc_flags_t *mdf)
{
return 0;
}
diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h
index a8430a7ae0544..efcddb9925add 100644
--- a/include/linux/mm_inline.h
+++ b/include/linux/mm_inline.h
@@ -650,7 +650,7 @@ static inline bool vma_has_recency(const struct vm_area_struct *vma)
static inline size_t num_pages_contiguous(struct page **pages, size_t nr_pages)
{
struct page *cur_page = pages[0];
- unsigned long section = memdesc_section(cur_page->flags);
+ unsigned long section = memdesc_section(&cur_page->flags);
size_t i;
for (i = 1; i < nr_pages; i++) {
@@ -660,7 +660,7 @@ static inline size_t num_pages_contiguous(struct page **pages, size_t nr_pages)
* In unproblematic kernel configs, page_to_section() == 0 and
* the whole check will get optimized out.
*/
- if (memdesc_section(cur_page->flags) != section)
+ if (memdesc_section(&cur_page->flags) != section)
break;
}
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index ca27121871475..19e709d7a13de 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -1272,31 +1272,31 @@ static inline bool zone_is_empty(const struct zone *zone)
#define KASAN_TAG_MASK ((1UL << KASAN_TAG_WIDTH) - 1)
#define ZONEID_MASK ((1UL << ZONEID_SHIFT) - 1)
-static inline enum zone_type memdesc_zonenum(memdesc_flags_t flags)
+static inline enum zone_type memdesc_zonenum(const memdesc_flags_t *flags)
{
- ASSERT_EXCLUSIVE_BITS(flags.f, ZONES_MASK << ZONES_PGSHIFT);
- return (flags.f >> ZONES_PGSHIFT) & ZONES_MASK;
+ ASSERT_EXCLUSIVE_BITS(flags->f, ZONES_MASK << ZONES_PGSHIFT);
+ return (flags->f >> ZONES_PGSHIFT) & ZONES_MASK;
}
static inline enum zone_type page_zonenum(const struct page *page)
{
- return memdesc_zonenum(page->flags);
+ return memdesc_zonenum(&page->flags);
}
static inline enum zone_type folio_zonenum(const struct folio *folio)
{
- return memdesc_zonenum(folio->flags);
+ return memdesc_zonenum(&folio->flags);
}
#ifdef CONFIG_ZONE_DEVICE
-static inline bool memdesc_is_zone_device(memdesc_flags_t mdf)
+static inline bool memdesc_is_zone_device(const memdesc_flags_t *mdf)
{
return memdesc_zonenum(mdf) == ZONE_DEVICE;
}
static inline struct dev_pagemap *page_pgmap(const struct page *page)
{
- VM_WARN_ON_ONCE_PAGE(!memdesc_is_zone_device(page->flags), page);
+ VM_WARN_ON_ONCE_PAGE(!memdesc_is_zone_device(&page->flags), page);
return page_folio(page)->pgmap;
}
@@ -1311,9 +1311,9 @@ static inline struct dev_pagemap *page_pgmap(const struct page *page)
static inline bool zone_device_pages_have_same_pgmap(const struct page *a,
const struct page *b)
{
- if (memdesc_is_zone_device(a->flags) != memdesc_is_zone_device(b->flags))
+ if (memdesc_is_zone_device(&a->flags) != memdesc_is_zone_device(&b->flags))
return false;
- if (!memdesc_is_zone_device(a->flags))
+ if (!memdesc_is_zone_device(&a->flags))
return true;
return page_pgmap(a) == page_pgmap(b);
}
@@ -1321,7 +1321,7 @@ static inline bool zone_device_pages_have_same_pgmap(const struct page *a,
extern void memmap_init_zone_device(struct zone *, unsigned long,
unsigned long, struct dev_pagemap *);
#else
-static inline bool memdesc_is_zone_device(memdesc_flags_t mdf)
+static inline bool memdesc_is_zone_device(const memdesc_flags_t *mdf)
{
return false;
}
@@ -1338,12 +1338,12 @@ static inline struct dev_pagemap *page_pgmap(const struct page *page)
static inline bool is_zone_device_page(const struct page *page)
{
- return memdesc_is_zone_device(page->flags);
+ return memdesc_is_zone_device(&page->flags);
}
static inline bool folio_is_zone_device(const struct folio *folio)
{
- return memdesc_is_zone_device(folio->flags);
+ return memdesc_is_zone_device(&folio->flags);
}
static inline bool is_zone_movable_page(const struct page *page)
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index ee902a468c2f5..020a97ca018e9 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -6904,15 +6904,15 @@ static void __free_contig_range_common(unsigned long pfn, unsigned long nr_pages
continue;
}
- if (start && memdesc_section(page->flags) != start_sec) {
+ if (start && memdesc_section(&page->flags) != start_sec) {
free_prepared_contig_range(start, i - nr_start);
start = page;
nr_start = i;
- start_sec = memdesc_section(page->flags);
+ start_sec = memdesc_section(&page->flags);
} else if (!start) {
start = page;
nr_start = i;
- start_sec = memdesc_section(page->flags);
+ start_sec = memdesc_section(&page->flags);
}
}
diff --git a/mm/slab.h b/mm/slab.h
index bf2f87acf5e3a..1ae8e6084ba32 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -155,7 +155,7 @@ static inline void *slab_address(const struct slab *slab)
static inline int slab_nid(const struct slab *slab)
{
- return memdesc_nid(slab->flags);
+ return memdesc_nid(&slab->flags);
}
static inline pg_data_t *slab_pgdat(const struct slab *slab)
diff --git a/mm/sparse.c b/mm/sparse.c
index 16ac6df3c89fa..8e38477645131 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -43,7 +43,7 @@ static u8 section_to_node_table[NR_MEM_SECTIONS] __cacheline_aligned;
static u16 section_to_node_table[NR_MEM_SECTIONS] __cacheline_aligned;
#endif
-int memdesc_nid(memdesc_flags_t mdf)
+int memdesc_nid(const memdesc_flags_t *mdf)
{
return section_to_node_table[memdesc_section(mdf)];
}
--
2.43.0
--
Cheers,
David
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-06-26 9:10 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-26 3:20 [PATCH v7] mm: assert exclusive nid/zonenum bits at the page/folio access sites Hui Zhu
2026-06-26 4:54 ` kernel test robot
2026-06-26 4:54 ` kernel test robot
2026-06-26 5:04 ` Leon Hwang
2026-06-26 9:09 ` David Hildenbrand (Arm)
2026-06-26 6:05 ` kernel test robot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox