From dc585960e0c70142b189f215f8da3aca5218def1 Mon Sep 17 00:00:00 2001 From: tiehexue Date: Thu, 28 May 2026 01:07:55 +0800 Subject: [PATCH] Linux 5.6 compat: fix fs_parse API mismatch Added m4 macro to check fs_parse API signature and wrappers. Before 5.6, fs_parse() took a struct fs_parameter_description which wraps the parameter specs with name and enum pointers. From 5.6, the description struct was removed and fs_parse() accepts the fs_parameter_spec directly. Reviewed-by: Rob Norris Reviewed-by: Brian Behlendorf Signed-off-by: tiehexue Closes #18585 --- config/kernel-fs-parse.m4 | 34 +++++++++++++++++++++++++++++++++ config/kernel.m4 | 2 ++ module/os/linux/zfs/zpl_super.c | 25 ++++++++++++++++++++++-- 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 config/kernel-fs-parse.m4 diff --git a/config/kernel-fs-parse.m4 b/config/kernel-fs-parse.m4 new file mode 100644 index 00000000000..7a6ffa77238 --- /dev/null +++ b/config/kernel-fs-parse.m4 @@ -0,0 +1,34 @@ +dnl # SPDX-License-Identifier: CDDL-1.0 +dnl # +dnl # 5.6 API change +dnl # Before 5.6, fs_parse() took a struct fs_parameter_description +dnl # which wraps the parameter specs with name and enum pointers. From 5.6, +dnl # the description struct was removed and fs_parse() accepts the +dnl # fs_parameter_spec directly. +dnl # +AC_DEFUN([ZFS_AC_KERNEL_SRC_FS_PARSE], [ + ZFS_LINUX_TEST_SRC([fs_parse], [ + #include + #include + ],[ + static const struct fs_parameter_spec specs[] = { + {} + }; + int test __attribute__ ((unused)); + struct fs_context *fc __attribute__ ((unused)) = NULL; + struct fs_parameter param __attribute__ ((unused)); + struct fs_parse_result result __attribute__ ((unused)); + test = fs_parse(fc, specs, ¶m, &result); + ]) +]) + +AC_DEFUN([ZFS_AC_KERNEL_FS_PARSE], [ + AC_MSG_CHECKING([whether fs_parse() takes fs_parameter_spec directly]) + ZFS_LINUX_TEST_RESULT([fs_parse], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_FS_PARSE_TAKES_SPEC, 1, + [fs_parse() takes fs_parameter_spec directly]) + ],[ + AC_MSG_RESULT(no) + ]) +]) diff --git a/config/kernel.m4 b/config/kernel.m4 index 7225591b86d..55f40767567 100644 --- a/config/kernel.m4 +++ b/config/kernel.m4 @@ -78,6 +78,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [ ZFS_AC_KERNEL_SRC_TRUNCATE_SETSIZE ZFS_AC_KERNEL_SRC_SECURITY_INODE ZFS_AC_KERNEL_SRC_FS_CONTEXT + ZFS_AC_KERNEL_SRC_FS_PARSE ZFS_AC_KERNEL_SRC_SB_DYING ZFS_AC_KERNEL_SRC_SET_NLINK ZFS_AC_KERNEL_SRC_SGET @@ -201,6 +202,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [ ZFS_AC_KERNEL_TRUNCATE_SETSIZE ZFS_AC_KERNEL_SECURITY_INODE ZFS_AC_KERNEL_FS_CONTEXT + ZFS_AC_KERNEL_FS_PARSE ZFS_AC_KERNEL_SB_DYING ZFS_AC_KERNEL_SET_NLINK ZFS_AC_KERNEL_SGET diff --git a/module/os/linux/zfs/zpl_super.c b/module/os/linux/zfs/zpl_super.c index e1fa0f8e88e..d7194e4f1f7 100644 --- a/module/os/linux/zfs/zpl_super.c +++ b/module/os/linux/zfs/zpl_super.c @@ -613,13 +613,34 @@ static const struct fs_parameter_spec zpl_param_spec[] = { {} }; +/* + * Before 5.6, fs_parse() took a struct fs_parameter_description + * which wraps the parameter specs with name and enum pointers. From 5.6, + * the description struct was removed and fs_parse() accepts the + * fs_parameter_spec directly. + */ +static int +zpl_fs_parse(struct fs_context *fc, struct fs_parameter *param, + struct fs_parse_result *result) +{ +#ifdef HAVE_FS_PARSE_TAKES_SPEC + return (fs_parse(fc, zpl_param_spec, param, result)); +#else + static const struct fs_parameter_description zpl_param_desc = { + .name = "zfs", + .specs = zpl_param_spec, + }; + return (fs_parse(fc, &zpl_param_desc, param, result)); +#endif +} + static int zpl_parse_param(struct fs_context *fc, struct fs_parameter *param) { vfs_t *vfs = fc->fs_private; struct fs_parse_result result; - int opt = fs_parse(fc, zpl_param_spec, param, &result); + int opt = zpl_fs_parse(fc, param, &result); if (opt == -ENOPARAM) { /* * Convert unknowns to warnings, to work around the whole @@ -803,7 +824,7 @@ zpl_parse_monolithic(struct fs_context *fc, void *data) /* Check if this is one of our options. */ struct fs_parse_result result; - int opt = fs_parse(fc, zpl_param_spec, ¶m, &result); + int opt = zpl_fs_parse(fc, ¶m, &result); if (opt >= 0) { /* * We already know this one of our options, so a