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