From 7e33476a7c838eefafe4a8a6ecd1da5220cfacfa Mon Sep 17 00:00:00 2001 From: Erik Larsson Date: Tue, 3 Feb 2026 00:16:10 +0200 Subject: [PATCH] Fix build for Linux 6.18 with PowerPC/RISC-V kernels. (#18145) The macro 'flush_dcache_page(...)' modifies the page flags, but in Linux 6.18 the type of the page flags changed from 'unsigned long' to the struct type 'memdesc_flags_t' with a single member 'f' which is the page flags field. Signed-off-by: Erik Larsson Reviewed-by: Brian Behlendorf Reviewed-by: Tino Reichardt Reviewed-by: Tony Hutter --- config/kernel-mm-page-flags.m4 | 27 +++++++++++++++++++ include/os/linux/kernel/linux/dcache_compat.h | 19 ++++++++++--- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/config/kernel-mm-page-flags.m4 b/config/kernel-mm-page-flags.m4 index 0bcac0b5c..1c7397d19 100644 --- a/config/kernel-mm-page-flags.m4 +++ b/config/kernel-mm-page-flags.m4 @@ -17,9 +17,36 @@ AC_DEFUN([ZFS_AC_KERNEL_MM_PAGE_FLAG_ERROR], [ ]) ]) +dnl # +dnl # Linux 6.18+ uses a struct typedef (memdesc_flags_t) instead of an +dnl # 'unsigned long' for the 'flags' field in 'struct page'. +dnl # +AC_DEFUN([ZFS_AC_KERNEL_SRC_MM_PAGE_FLAGS_STRUCT], [ + ZFS_LINUX_TEST_SRC([mm_page_flags_struct], [ + #include + + static const struct page p __attribute__ ((unused)) = { + .flags = { .f = 0 } + }; + ],[]) +]) + +AC_DEFUN([ZFS_AC_KERNEL_MM_PAGE_FLAGS_STRUCT], [ + AC_MSG_CHECKING([whether 'flags' in 'struct page' is a struct]) + ZFS_LINUX_TEST_RESULT([mm_page_flags_struct], [ + AC_MSG_RESULT([yes]) + AC_DEFINE(HAVE_MM_PAGE_FLAGS_STRUCT, 1, + ['flags' in 'struct page' is a struct]) + ],[ + AC_MSG_RESULT([no]) + ]) +]) + AC_DEFUN([ZFS_AC_KERNEL_SRC_MM_PAGE_FLAGS], [ ZFS_AC_KERNEL_SRC_MM_PAGE_FLAG_ERROR + ZFS_AC_KERNEL_SRC_MM_PAGE_FLAGS_STRUCT ]) AC_DEFUN([ZFS_AC_KERNEL_MM_PAGE_FLAGS], [ ZFS_AC_KERNEL_MM_PAGE_FLAG_ERROR + ZFS_AC_KERNEL_MM_PAGE_FLAGS_STRUCT ]) diff --git a/include/os/linux/kernel/linux/dcache_compat.h b/include/os/linux/kernel/linux/dcache_compat.h index 152e5a606..f94dcda61 100644 --- a/include/os/linux/kernel/linux/dcache_compat.h +++ b/include/os/linux/kernel/linux/dcache_compat.h @@ -34,6 +34,17 @@ #define d_alias d_u.d_alias +#ifdef HAVE_MM_PAGE_FLAGS_STRUCT +/* + * Starting from Linux 6.18, the 'flags' field in 'struct page' is defined + * to a struct ('memdesc_flags_t' typedef) instead of an unsigned long for + * improved typesafety. + */ +#define page_flags flags.f +#else +#define page_flags flags +#endif + /* * Starting from Linux 5.13, flush_dcache_page() becomes an inline function * and under some configurations, may indirectly referencing GPL-only @@ -44,8 +55,8 @@ #include #define flush_dcache_page(page) do { \ if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE) && \ - test_bit(PG_dcache_clean, &(page)->flags)) \ - clear_bit(PG_dcache_clean, &(page)->flags); \ + test_bit(PG_dcache_clean, &(page)->page_flags)) \ + clear_bit(PG_dcache_clean, &(page)->page_flags);\ } while (0) #endif /* @@ -55,8 +66,8 @@ */ #if defined __riscv && defined HAVE_FLUSH_DCACHE_PAGE_GPL_ONLY #define flush_dcache_page(page) do { \ - if (test_bit(PG_dcache_clean, &(page)->flags)) \ - clear_bit(PG_dcache_clean, &(page)->flags); \ + if (test_bit(PG_dcache_clean, &(page)->page_flags)) \ + clear_bit(PG_dcache_clean, &(page)->page_flags);\ } while (0) #endif