[packages/zfs] - rel 2, upstream fixes for kernel 6.15

baggins baggins at pld-linux.org
Fri Jun 13 11:00:51 CEST 2025


commit 32b58c542f7416ac3535511fab4f05a749fd1519
Author: Jan Rękorajski <baggins at pld-linux.org>
Date:   Fri Jun 13 11:55:52 2025 +0200

    - rel 2, upstream fixes for kernel 6.15

 0001-Linux-6.15-compat-META.patch                  |  29 +
 ...inux-6.15-mkdir-now-returns-struct-dentry.patch | 208 +++++
 0001-Linux-build-silence-objtool-warnings.patch    | 261 ++++++
 ...ly-pass-and-test-creds-on-other-threads-1.patch | 888 +++++++++++++++++++++
 ....15-del_timer_sync-renamed-to-timer_delet.patch | 109 +++
 zfs.spec                                           |  12 +-
 6 files changed, 1506 insertions(+), 1 deletion(-)
---
diff --git a/zfs.spec b/zfs.spec
index 0962827..e1cca23 100644
--- a/zfs.spec
+++ b/zfs.spec
@@ -24,7 +24,7 @@ exit 1
 
 %define		_duplicate_files_terminate_build	0
 
-%define	rel	1
+%define	rel	2
 %define	pname	zfs
 Summary:	Native Linux port of the ZFS filesystem
 Summary(pl.UTF-8):	Natywny linuksowy port systemu plików ZFS
@@ -37,6 +37,11 @@ Source0:	https://github.com/openzfs/zfs/releases/download/zfs-%{version}/%{pname
 # Source0-md5:	eef957a390e9c7641cd829827b0ce183
 Patch0:		initdir.patch
 Patch1:		pld.patch
+Patch2:		0001-Linux-6.15-compat-META.patch
+Patch3:		0001-Linux-6.15-mkdir-now-returns-struct-dentry.patch
+Patch4:		0002-Linux-6.2-6.15-del_timer_sync-renamed-to-timer_delet.patch
+Patch5:		0001-cred-properly-pass-and-test-creds-on-other-threads-1.patch
+Patch6:		0001-Linux-build-silence-objtool-warnings.patch
 URL:		https://zfsonlinux.org/
 BuildRequires:	autoconf >= 2.50
 BuildRequires:	automake
@@ -264,6 +269,11 @@ p=`pwd`\
 %setup -q -n %{pname}-%{version}
 %patch -P 0 -p1
 %patch -P 1 -p1
+%patch -P 2 -p1
+%patch -P 3 -p1
+%patch -P 4 -p1
+%patch -P 5 -p1
+%patch -P 6 -p1
 
 %{__sed} -E -i -e '1s,#!\s*/usr/bin/env\s+python3(\s|$),#!%{__python3}\1,' \
 	cmd/arc_summary
diff --git a/0001-Linux-6.15-compat-META.patch b/0001-Linux-6.15-compat-META.patch
new file mode 100644
index 0000000..94e5110
--- /dev/null
+++ b/0001-Linux-6.15-compat-META.patch
@@ -0,0 +1,29 @@
+From 906ced88df211bdeef9287f72a87661b0192e440 Mon Sep 17 00:00:00 2001
+From: Tony Hutter <hutter2 at llnl.gov>
+Date: Wed, 28 May 2025 16:28:02 -0700
+Subject: [PATCH] Linux 6.15 compat: META
+
+Update the META file to reflect compatibility with the 6.15
+kernel.
+
+Reviewed-by: Brian Behlendorf <behlendorf1 at llnl.gov>
+Signed-off-by: Tony Hutter <hutter2 at llnl.gov>
+Closes #17393
+---
+ META | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/META b/META
+index 6249d5ec2..47f0795bf 100644
+--- a/META
++++ b/META
+@@ -6,5 +6,5 @@ Release:       1
+ Release-Tags:  relext
+ License:       CDDL
+ Author:        OpenZFS
+-Linux-Maximum: 6.14
++Linux-Maximum: 6.15
+ Linux-Minimum: 4.18
+-- 
+2.49.0
+
diff --git a/0001-Linux-6.15-mkdir-now-returns-struct-dentry.patch b/0001-Linux-6.15-mkdir-now-returns-struct-dentry.patch
new file mode 100644
index 0000000..854040a
--- /dev/null
+++ b/0001-Linux-6.15-mkdir-now-returns-struct-dentry.patch
@@ -0,0 +1,208 @@
+From e64d4718a7723bbbe1c367444156b8139ccbfdaf Mon Sep 17 00:00:00 2001
+From: Rob Norris <robn at despairlabs.com>
+Date: Fri, 4 Apr 2025 16:59:15 +1100
+Subject: [PATCH 1/2] Linux 6.15: mkdir now returns struct dentry *
+
+The intent is that the filesystem may have a reference to an "old"
+version of the new directory, eg if it was keeping it alive because a
+remote NFS client still had it open.
+
+We don't need anything like that, so this really just changes things so
+we return error codes encoded in pointers.
+
+Sponsored-by: https://despairlabs.com/sponsor/
+Reviewed-by: Brian Behlendorf <behlendorf1 at llnl.gov>
+Reviewed-by: Tony Hutter <hutter2 at llnl.gov>
+Reviewed-by: Pavel Snajdr <snajpa at snajpa.net>
+Signed-off-by: Rob Norris <robn at despairlabs.com>
+Closes #17229
+(cherry picked from commit bb740d66de2b03a24bd7bfc9cef1844ad3e22a74)
+---
+ config/kernel-mkdir.m4           | 57 +++++++++++++++++++++++---------
+ module/os/linux/zfs/zpl_ctldir.c | 12 ++++++-
+ module/os/linux/zfs/zpl_inode.c  | 21 +++++++++---
+ 3 files changed, 70 insertions(+), 20 deletions(-)
+
+diff --git a/config/kernel-mkdir.m4 b/config/kernel-mkdir.m4
+index 8e084443c..c1aebc387 100644
+--- a/config/kernel-mkdir.m4
++++ b/config/kernel-mkdir.m4
+@@ -2,6 +2,22 @@ dnl #
+ dnl # Supported mkdir() interfaces checked newest to oldest.
+ dnl #
+ AC_DEFUN([ZFS_AC_KERNEL_SRC_MKDIR], [
++	dnl #
++	dnl # 6.15 API change
++	dnl # mkdir() returns struct dentry *
++	dnl #
++	ZFS_LINUX_TEST_SRC([mkdir_return_dentry], [
++		#include <linux/fs.h>
++
++		static struct dentry *mkdir(struct mnt_idmap *idmap,
++			struct inode *inode, struct dentry *dentry,
++			umode_t umode) { return dentry; }
++		static const struct inode_operations
++		    iops __attribute__ ((unused)) = {
++			.mkdir = mkdir,
++		};
++	],[])
++
+ 	dnl #
+ 	dnl # 6.3 API change
+ 	dnl # mkdir() takes struct mnt_idmap * as the first arg
+@@ -59,29 +75,40 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_MKDIR], [
+ 
+ AC_DEFUN([ZFS_AC_KERNEL_MKDIR], [
+ 	dnl #
+-	dnl # 6.3 API change
+-	dnl # mkdir() takes struct mnt_idmap * as the first arg
++	dnl # 6.15 API change
++	dnl # mkdir() returns struct dentry *
+ 	dnl #
+-	AC_MSG_CHECKING([whether iops->mkdir() takes struct mnt_idmap*])
+-	ZFS_LINUX_TEST_RESULT([mkdir_mnt_idmap], [
++	AC_MSG_CHECKING([whether iops->mkdir() returns struct dentry*])
++	ZFS_LINUX_TEST_RESULT([mkdir_return_dentry], [
+ 		AC_MSG_RESULT(yes)
+-		AC_DEFINE(HAVE_IOPS_MKDIR_IDMAP, 1,
+-		    [iops->mkdir() takes struct mnt_idmap*])
++		AC_DEFINE(HAVE_IOPS_MKDIR_DENTRY, 1,
++		    [iops->mkdir() returns struct dentry*])
+ 	],[
+-		AC_MSG_RESULT(no)
+-
+ 		dnl #
+-		dnl # 5.12 API change
+-		dnl # The struct user_namespace arg was added as the first argument to
+-		dnl # mkdir() of the iops structure.
++		dnl # 6.3 API change
++		dnl # mkdir() takes struct mnt_idmap * as the first arg
+ 		dnl #
+-		AC_MSG_CHECKING([whether iops->mkdir() takes struct user_namespace*])
+-		ZFS_LINUX_TEST_RESULT([mkdir_user_namespace], [
++		AC_MSG_CHECKING([whether iops->mkdir() takes struct mnt_idmap*])
++		ZFS_LINUX_TEST_RESULT([mkdir_mnt_idmap], [
+ 			AC_MSG_RESULT(yes)
+-			AC_DEFINE(HAVE_IOPS_MKDIR_USERNS, 1,
+-			    [iops->mkdir() takes struct user_namespace*])
++			AC_DEFINE(HAVE_IOPS_MKDIR_IDMAP, 1,
++			    [iops->mkdir() takes struct mnt_idmap*])
+ 		],[
+ 			AC_MSG_RESULT(no)
++
++			dnl #
++			dnl # 5.12 API change
++			dnl # The struct user_namespace arg was added as the first argument to
++			dnl # mkdir() of the iops structure.
++			dnl #
++			AC_MSG_CHECKING([whether iops->mkdir() takes struct user_namespace*])
++			ZFS_LINUX_TEST_RESULT([mkdir_user_namespace], [
++				AC_MSG_RESULT(yes)
++				AC_DEFINE(HAVE_IOPS_MKDIR_USERNS, 1,
++				    [iops->mkdir() takes struct user_namespace*])
++			],[
++				AC_MSG_RESULT(no)
++			])
+ 		])
+ 	])
+ ])
+diff --git a/module/os/linux/zfs/zpl_ctldir.c b/module/os/linux/zfs/zpl_ctldir.c
+index 0b04ec686..48dae79a2 100644
+--- a/module/os/linux/zfs/zpl_ctldir.c
++++ b/module/os/linux/zfs/zpl_ctldir.c
+@@ -341,14 +341,20 @@ zpl_snapdir_rmdir(struct inode *dip, struct dentry *dentry)
+ 	return (error);
+ }
+ 
++#if defined(HAVE_IOPS_MKDIR_USERNS)
+ static int
+-#ifdef HAVE_IOPS_MKDIR_USERNS
+ zpl_snapdir_mkdir(struct user_namespace *user_ns, struct inode *dip,
+     struct dentry *dentry, umode_t mode)
+ #elif defined(HAVE_IOPS_MKDIR_IDMAP)
++static int
++zpl_snapdir_mkdir(struct mnt_idmap *user_ns, struct inode *dip,
++    struct dentry *dentry, umode_t mode)
++#elif defined(HAVE_IOPS_MKDIR_DENTRY)
++static struct dentry *
+ zpl_snapdir_mkdir(struct mnt_idmap *user_ns, struct inode *dip,
+     struct dentry *dentry, umode_t mode)
+ #else
++static int
+ zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode)
+ #endif
+ {
+@@ -376,7 +382,11 @@ zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode)
+ 	ASSERT3S(error, <=, 0);
+ 	crfree(cr);
+ 
++#if defined(HAVE_IOPS_MKDIR_DENTRY)
++	return (ERR_PTR(error));
++#else
+ 	return (error);
++#endif
+ }
+ 
+ /*
+diff --git a/module/os/linux/zfs/zpl_inode.c b/module/os/linux/zfs/zpl_inode.c
+index 85df9b9ac..f9f6406f8 100644
+--- a/module/os/linux/zfs/zpl_inode.c
++++ b/module/os/linux/zfs/zpl_inode.c
+@@ -374,14 +374,20 @@ zpl_unlink(struct inode *dir, struct dentry *dentry)
+ 	return (error);
+ }
+ 
++#if defined(HAVE_IOPS_MKDIR_USERNS)
+ static int
+-#ifdef HAVE_IOPS_MKDIR_USERNS
+ zpl_mkdir(struct user_namespace *user_ns, struct inode *dir,
+     struct dentry *dentry, umode_t mode)
+ #elif defined(HAVE_IOPS_MKDIR_IDMAP)
++static int
++zpl_mkdir(struct mnt_idmap *user_ns, struct inode *dir,
++    struct dentry *dentry, umode_t mode)
++#elif defined(HAVE_IOPS_MKDIR_DENTRY)
++static struct dentry *
+ zpl_mkdir(struct mnt_idmap *user_ns, struct inode *dir,
+     struct dentry *dentry, umode_t mode)
+ #else
++static int
+ zpl_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+ #endif
+ {
+@@ -390,12 +396,14 @@ zpl_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+ 	znode_t *zp;
+ 	int error;
+ 	fstrans_cookie_t cookie;
+-#if !(defined(HAVE_IOPS_MKDIR_USERNS) || defined(HAVE_IOPS_MKDIR_IDMAP))
++#if !(defined(HAVE_IOPS_MKDIR_USERNS) || \
++	defined(HAVE_IOPS_MKDIR_IDMAP) || defined(HAVE_IOPS_MKDIR_DENTRY))
+ 	zidmap_t *user_ns = kcred->user_ns;
+ #endif
+ 
+ 	if (is_nametoolong(dentry)) {
+-		return (-ENAMETOOLONG);
++		error = -ENAMETOOLONG;
++		goto err;
+ 	}
+ 
+ 	crhold(cr);
+@@ -422,9 +430,14 @@ zpl_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+ 	spl_fstrans_unmark(cookie);
+ 	kmem_free(vap, sizeof (vattr_t));
+ 	crfree(cr);
+-	ASSERT3S(error, <=, 0);
+ 
++err:
++	ASSERT3S(error, <=, 0);
++#if defined(HAVE_IOPS_MKDIR_DENTRY)
++	return (error != 0 ? ERR_PTR(error) : NULL);
++#else
+ 	return (error);
++#endif
+ }
+ 
+ static int
+-- 
+2.49.0
+
diff --git a/0001-Linux-build-silence-objtool-warnings.patch b/0001-Linux-build-silence-objtool-warnings.patch
new file mode 100644
index 0000000..630fc76
--- /dev/null
+++ b/0001-Linux-build-silence-objtool-warnings.patch
@@ -0,0 +1,261 @@
+From b96f1a4b1f6fdcb683c7f0e9d773c4f41f25fc18 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Attila=20F=C3=BCl=C3=B6p?= <attila at fueloep.org>
+Date: Thu, 5 Jun 2025 02:40:09 +0200
+Subject: [PATCH] Linux build: silence objtool warnings
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+After #17401 the Linux build produces some stack related warnings.
+
+Silence them with the `STACK_FRAME_NON_STANDARD` macro.
+
+Reviewed-by: Brian Behlendorf <behlendorf1 at llnl.gov>
+Reviewed-by: Tino Reichardt <milky-zfs at mcmilk.de>
+Signed-off-by: Attila Fülöp <attila at fueloep.org>
+Co-authored-by: Brian Behlendorf <behlendorf1 at llnl.gov>
+Closes #17410
+---
+ config/kernel-objtool.m4                      | 19 +++++++++++++++++++
+ include/sys/frame.h                           |  8 ++++++++
+ .../icp/asm-x86_64/modes/aesni-gcm-x86_64.S   | 17 +++++++++++++++++
+ module/icp/asm-x86_64/sha2/sha256-x86_64.S    | 17 +++++++++++++++++
+ module/icp/asm-x86_64/sha2/sha512-x86_64.S    | 13 +++++++++++++
+ 5 files changed, 74 insertions(+)
+
+diff --git a/config/kernel-objtool.m4 b/config/kernel-objtool.m4
+index f9f9d657d..e616ccebc 100644
+--- a/config/kernel-objtool.m4
++++ b/config/kernel-objtool.m4
+@@ -11,10 +11,12 @@ AC_DEFUN([ZFS_AC_KERNEL_OBJTOOL_HEADER], [
+ 		#include <linux/objtool.h>
+ 	],[
+ 	],[
++		objtool_header=$LINUX/include/linux/objtool.h
+ 		AC_DEFINE(HAVE_KERNEL_OBJTOOL_HEADER, 1,
+ 		    [kernel has linux/objtool.h])
+ 		AC_MSG_RESULT(linux/objtool.h)
+ 	],[
++		objtool_header=$LINUX/include/linux/frame.h
+ 		AC_MSG_RESULT(linux/frame.h)
+ 	])
+ ])
+@@ -62,6 +64,23 @@ AC_DEFUN([ZFS_AC_KERNEL_OBJTOOL], [
+ 			AC_MSG_RESULT(yes)
+ 			AC_DEFINE(HAVE_STACK_FRAME_NON_STANDARD, 1,
+ 			   [STACK_FRAME_NON_STANDARD is defined])
++
++			dnl # Needed for kernels missing the asm macro. We grep
++			dnl # for it in the header file since there is currently
++			dnl # no test to check the result of assembling a file.
++			AC_MSG_CHECKING(
++			    [whether STACK_FRAME_NON_STANDARD asm macro is defined])
++			dnl # Escape square brackets.
++			sp='@<:@@<:@:space:@:>@@:>@'
++			dotmacro='@<:@.@:>@macro'
++			regexp="^$sp*$dotmacro$sp+STACK_FRAME_NON_STANDARD$sp"
++			AS_IF([$EGREP -s -q "$regexp" $objtool_header],[
++				AC_MSG_RESULT(yes)
++				AC_DEFINE(HAVE_STACK_FRAME_NON_STANDARD_ASM, 1,
++				   [STACK_FRAME_NON_STANDARD asm macro is defined])
++			],[
++				AC_MSG_RESULT(no)
++			])
+ 		],[
+ 			AC_MSG_RESULT(no)
+ 		])
+diff --git a/include/sys/frame.h b/include/sys/frame.h
+index dbcf1087b..fe1db28b7 100644
+--- a/include/sys/frame.h
++++ b/include/sys/frame.h
+@@ -31,8 +31,16 @@ extern "C" {
+ #else
+ #include <linux/frame.h>
+ #endif
++#if defined(_ASM) && ! defined(HAVE_STACK_FRAME_NON_STANDARD_ASM)
++.macro STACK_FRAME_NON_STANDARD func:req
++.endm
++#endif
+ #else
+ #define	STACK_FRAME_NON_STANDARD(func)
++#if defined(_ASM)
++.macro STACK_FRAME_NON_STANDARD func:req
++.endm
++#endif
+ #endif
+ 
+ #ifdef	__cplusplus
+diff --git a/module/icp/asm-x86_64/modes/aesni-gcm-x86_64.S b/module/icp/asm-x86_64/modes/aesni-gcm-x86_64.S
+index 6ff3490d3..49671f1fc 100644
+--- a/module/icp/asm-x86_64/modes/aesni-gcm-x86_64.S
++++ b/module/icp/asm-x86_64/modes/aesni-gcm-x86_64.S
+@@ -50,6 +50,7 @@
+ 
+ #define _ASM
+ #include <sys/asm_linkage.h>
++#include <sys/frame.h>
+ 
+ /* Windows userland links with OpenSSL */
+ #if !defined (_WIN32) || defined (_KERNEL)
+@@ -378,6 +379,7 @@ FUNCTION(_aesni_ctr32_ghash_6x)
+ 	RET
+ .cfi_endproc
+ SET_SIZE(_aesni_ctr32_ghash_6x)
++STACK_FRAME_NON_STANDARD _aesni_ctr32_ghash_6x
+ #endif /* ifdef HAVE_MOVBE */
+ 
+ .balign 32
+@@ -706,6 +708,7 @@ FUNCTION(_aesni_ctr32_ghash_no_movbe_6x)
+ 	RET
+ .cfi_endproc
+ SET_SIZE(_aesni_ctr32_ghash_no_movbe_6x)
++STACK_FRAME_NON_STANDARD _aesni_ctr32_ghash_no_movbe_6x
+ 
+ ENTRY_ALIGN(aesni_gcm_decrypt, 32)
+ .cfi_startproc
+@@ -823,6 +826,7 @@ ENTRY_ALIGN(aesni_gcm_decrypt, 32)
+ 	RET
+ .cfi_endproc
+ SET_SIZE(aesni_gcm_decrypt)
++STACK_FRAME_NON_STANDARD aesni_gcm_decrypt
+ 
+ .balign 32
+ FUNCTION(_aesni_ctr32_6x)
+@@ -1198,6 +1202,7 @@ ENTRY_ALIGN(aesni_gcm_encrypt, 32)
+ 	RET
+ .cfi_endproc
+ SET_SIZE(aesni_gcm_encrypt)
++STACK_FRAME_NON_STANDARD aesni_gcm_encrypt
+ 
+ #endif /* !_WIN32 || _KERNEL */
+ 
+@@ -1257,6 +1262,18 @@ SECTION_STATIC
+ .byte	65,69,83,45,78,73,32,71,67,77,32,109,111,100,117,108,101,32,102,111,114,32,120,56,54,95,54,52,44,32,67,82,89,80,84,79,71,65,77,83,32,98,121,32,60,97,112,112,114,111,64,111,112,101,110,115,115,108,46,111,114,103,62,0
+ .balign	64
+ 
++/* Workaround for missing asm macro in RHEL 8. */
++#if defined(__linux__) && defined(HAVE_STACK_FRAME_NON_STANDARD) && \
++    ! defined(HAVE_STACK_FRAME_NON_STANDARD_ASM)
++.section .discard.func_stack_frame_non_standard, "aw"
++#ifdef HAVE_MOVBE
++	.long _aesni_ctr32_ghash_6x  - .
++#endif
++	.long _aesni_ctr32_ghash_no_movbe_6x - .
++	.long aesni_gcm_decrypt - .
++	.long aesni_gcm_encrypt - .
++#endif
++
+ /* Mark the stack non-executable. */
+ #if defined(__linux__) && defined(__ELF__)
+ .section .note.GNU-stack,"",%progbits
+diff --git a/module/icp/asm-x86_64/sha2/sha256-x86_64.S b/module/icp/asm-x86_64/sha2/sha256-x86_64.S
+index f19f7b471..5976f7acf 100644
+--- a/module/icp/asm-x86_64/sha2/sha256-x86_64.S
++++ b/module/icp/asm-x86_64/sha2/sha256-x86_64.S
+@@ -24,6 +24,7 @@
+ 
+ #define _ASM
+ #include <sys/asm_linkage.h>
++#include <sys/frame.h>
+ 
+ SECTION_STATIC
+ 
+@@ -1420,6 +1421,7 @@ ENTRY_ALIGN(zfs_sha256_transform_x64, 16)
+ 	RET
+ .cfi_endproc
+ SET_SIZE(zfs_sha256_transform_x64)
++STACK_FRAME_NON_STANDARD zfs_sha256_transform_x64
+ 
+ ENTRY_ALIGN(zfs_sha256_transform_shani, 64)
+ .cfi_startproc
+@@ -1628,6 +1630,7 @@ ENTRY_ALIGN(zfs_sha256_transform_shani, 64)
+ 	RET
+ .cfi_endproc
+ SET_SIZE(zfs_sha256_transform_shani)
++STACK_FRAME_NON_STANDARD zfs_sha256_transform_shani
+ 
+ ENTRY_ALIGN(zfs_sha256_transform_ssse3, 64)
+ .cfi_startproc
+@@ -2739,6 +2742,7 @@ ENTRY_ALIGN(zfs_sha256_transform_ssse3, 64)
+ 	RET
+ .cfi_endproc
+ SET_SIZE(zfs_sha256_transform_ssse3)
++STACK_FRAME_NON_STANDARD zfs_sha256_transform_ssse3
+ 
+ ENTRY_ALIGN(zfs_sha256_transform_avx, 64)
+ .cfi_startproc
+@@ -3813,6 +3817,7 @@ ENTRY_ALIGN(zfs_sha256_transform_avx, 64)
+ 	RET
+ .cfi_endproc
+ SET_SIZE(zfs_sha256_transform_avx)
++STACK_FRAME_NON_STANDARD zfs_sha256_transform_avx
+ 
+ ENTRY_ALIGN(zfs_sha256_transform_avx2, 64)
+ .cfi_startproc
+@@ -5098,6 +5103,18 @@ ENTRY_ALIGN(zfs_sha256_transform_avx2, 64)
+ 	RET
+ .cfi_endproc
+ SET_SIZE(zfs_sha256_transform_avx2)
++STACK_FRAME_NON_STANDARD zfs_sha256_transform_avx2
++
++/* Workaround for missing asm macro in RHEL 8. */
++#if defined(__linux__) && defined(HAVE_STACK_FRAME_NON_STANDARD) && \
++    ! defined(HAVE_STACK_FRAME_NON_STANDARD_ASM)
++.section .discard.func_stack_frame_non_standard, "aw"
++	.long zfs_sha256_transform_x64 - .
++	.long zfs_sha256_transform_shani - .
++	.long zfs_sha256_transform_ssse3 - .
++	.long zfs_sha256_transform_avx - .
++	.long zfs_sha256_transform_avx2 - .
++#endif
+ 
+ #if defined(__ELF__)
+ 	.section .note.GNU-stack,"",%progbits
+diff --git a/module/icp/asm-x86_64/sha2/sha512-x86_64.S b/module/icp/asm-x86_64/sha2/sha512-x86_64.S
+index a5111d501..9ed50ddc7 100644
+--- a/module/icp/asm-x86_64/sha2/sha512-x86_64.S
++++ b/module/icp/asm-x86_64/sha2/sha512-x86_64.S
+@@ -24,6 +24,7 @@
+ 
+ #define _ASM
+ #include <sys/asm_linkage.h>
++#include <sys/frame.h>
+ 
+ SECTION_STATIC
+ 
+@@ -1463,6 +1464,7 @@ ENTRY_ALIGN(zfs_sha512_transform_x64, 16)
+ 	RET
+ .cfi_endproc
+ SET_SIZE(zfs_sha512_transform_x64)
++STACK_FRAME_NON_STANDARD zfs_sha512_transform_x64
+ 
+ ENTRY_ALIGN(zfs_sha512_transform_avx, 64)
+ .cfi_startproc
+@@ -2627,6 +2629,7 @@ ENTRY_ALIGN(zfs_sha512_transform_avx, 64)
+ 	RET
+ .cfi_endproc
+ SET_SIZE(zfs_sha512_transform_avx)
++STACK_FRAME_NON_STANDARD zfs_sha512_transform_avx
+ 
+ ENTRY_ALIGN(zfs_sha512_transform_avx2, 64)
+ .cfi_startproc
+@@ -4005,6 +4008,16 @@ ENTRY_ALIGN(zfs_sha512_transform_avx2, 64)
+ 	RET
+ .cfi_endproc
+ SET_SIZE(zfs_sha512_transform_avx2)
++STACK_FRAME_NON_STANDARD zfs_sha512_transform_avx2
++
++/* Workaround for missing asm macro in RHEL 8. */
++#if defined(__linux__) && defined(HAVE_STACK_FRAME_NON_STANDARD) && \
++    ! defined(HAVE_STACK_FRAME_NON_STANDARD_ASM)
++.section .discard.func_stack_frame_non_standard, "aw"
++	.long zfs_sha512_transform_x64 - .
++	.long zfs_sha512_transform_avx - .
++	.long zfs_sha512_transform_avx2 - .
++#endif
+ 
+ #if defined(__ELF__)
+ 	.section .note.GNU-stack,"",%progbits
+-- 
+2.49.0
+
diff --git a/0001-cred-properly-pass-and-test-creds-on-other-threads-1.patch b/0001-cred-properly-pass-and-test-creds-on-other-threads-1.patch
new file mode 100644
index 0000000..102a759
--- /dev/null
+++ b/0001-cred-properly-pass-and-test-creds-on-other-threads-1.patch
@@ -0,0 +1,888 @@
+From c85f2fd53105f59c9ac8ee1e3dec3bb9145e15e5 Mon Sep 17 00:00:00 2001
+From: Rob Norris <robn at despairlabs.com>
+Date: Wed, 30 Apr 2025 09:27:48 +1000
+Subject: [PATCH] cred: properly pass and test creds on other threads (#17273)
+
+### Background
+
+Various admin operations will be invoked by some userspace task, but the
+work will be done on a separate kernel thread at a later time. Snapshots
+are an example, which are triggered through zfs_ioc_snapshot() ->
+dsl_dataset_snapshot(), but the actual work is from a task dispatched to
+dp_sync_taskq.
+
+Many such tasks end up in dsl_enforce_ds_ss_limits(), where various
+limits and permissions are enforced. Among other things, it is necessary
+to ensure that the invoking task (that is, the user) has permission to
+do things. We can't simply check if the running task has permission; it
+is a privileged kernel thread, which can do anything.
+
+However, in the general case it's not safe to simply query the task for
+its permissions at the check time, as the task may not exist any more,
+or its permissions may have changed since it was first invoked. So
+instead, we capture the permissions by saving CRED() in the user task,
+and then using it for the check through the secpolicy_* functions.
+
+### Current implementation
+
+The current code calls CRED() to get the credential, which gets a
+pointer to the cred_t inside the current task and passes it to the
+worker task. However, it doesn't take a reference to the cred_t, and so
+expects that it won't change, and that the task continues to exist. In
+practice that is always the case, because we don't let the calling task
+return from the kernel until the work is done.
+
+For Linux, we also take a reference to the current task, because the
+Linux credential APIs for the most part do not check an arbitrary
+credential, but rather, query what a task can do. See
+secpolicy_zfs_proc(). Again, we don't take a reference on the task, just
+a pointer to it.
+
+### Changes
+
+We change to calling crhold() on the task credential, and crfree() when
+we're done with it. This ensures it stays alive and unchanged for the
+duration of the call.
+
+On the Linux side, we change the main policy checking function
+priv_policy_ns() to use override_creds()/revert_creds() if necessary to
+make the provided credential active in the current task, allowing the
+standard task-permission APIs to do the needed check. Since the task
+pointer is no longer required, this lets us entirely remove
+secpolicy_zfs_proc() and the need to carry a task pointer around as
+well.
+
+Sponsored-by: https://despairlabs.com/sponsor/
+
+Signed-off-by: Rob Norris <robn at despairlabs.com>
+Reviewed-by: Pavel Snajdr <snajpa at snajpa.net>
+Reviewed-by: Alexander Motin <mav at FreeBSD.org>
+Reviewed-by: Kyle Evans <kevans at FreeBSD.org>
+Reviewed-by: Tony Hutter <hutter2 at llnl.gov>
+(cherry picked from commit c8fa39b46c133cd094aebb46064da0592b9a553b)
+---
+ include/os/freebsd/spl/sys/policy.h |  1 -
+ include/os/linux/zfs/sys/policy.h   |  1 -
+ include/sys/dmu_recv.h              |  1 -
+ include/sys/dsl_dataset.h           |  4 +--
+ include/sys/dsl_dir.h               |  4 +--
+ include/sys/zcp.h                   |  1 -
+ include/sys/zfs_context.h           |  4 ++-
+ lib/libzpool/kernel.c               |  7 -----
+ module/os/freebsd/spl/spl_policy.c  |  7 -----
+ module/os/linux/zfs/policy.c        | 44 +++++++++++---------------
+ module/zfs/dmu_objset.c             | 25 ++++++++++-----
+ module/zfs/dmu_recv.c               | 48 +++++++++++++++++++----------
+ module/zfs/dsl_dataset.c            | 29 +++++++++++------
+ module/zfs/dsl_dir.c                | 42 ++++++++++++-------------
+ module/zfs/zcp.c                    |  8 +++--
+ module/zfs/zcp_synctask.c           |  2 --
+ 16 files changed, 116 insertions(+), 112 deletions(-)
+
+diff --git a/include/os/freebsd/spl/sys/policy.h b/include/os/freebsd/spl/sys/policy.h
+index 639ade831..48bc4f3d5 100644
+--- a/include/os/freebsd/spl/sys/policy.h
++++ b/include/os/freebsd/spl/sys/policy.h
+@@ -39,7 +39,6 @@ struct znode;
+ 
+ int	secpolicy_nfs(cred_t *cr);
+ int	secpolicy_zfs(cred_t *crd);
+-int	secpolicy_zfs_proc(cred_t *cr, proc_t *proc);
+ int	secpolicy_sys_config(cred_t *cr, int checkonly);
+ int	secpolicy_zinject(cred_t *cr);
+ int	secpolicy_fs_unmount(cred_t *cr, struct mount *vfsp);
+diff --git a/include/os/linux/zfs/sys/policy.h b/include/os/linux/zfs/sys/policy.h
+index 77d0cdef5..8fa6ab01d 100644
+--- a/include/os/linux/zfs/sys/policy.h
++++ b/include/os/linux/zfs/sys/policy.h
+@@ -52,7 +52,6 @@ int secpolicy_vnode_setids_setgids(const cred_t *, gid_t, zidmap_t *,
+     struct user_namespace *);
+ int secpolicy_zinject(const cred_t *);
+ int secpolicy_zfs(const cred_t *);
+-int secpolicy_zfs_proc(const cred_t *, proc_t *);
+ void secpolicy_setid_clear(vattr_t *, cred_t *);
+ int secpolicy_setid_setsticky_clear(struct inode *, vattr_t *,
+     const vattr_t *, cred_t *, zidmap_t *, struct user_namespace *);
+diff --git a/include/sys/dmu_recv.h b/include/sys/dmu_recv.h
+index cd292d924..ffb2b602d 100644
+--- a/include/sys/dmu_recv.h
++++ b/include/sys/dmu_recv.h
+@@ -60,7 +60,6 @@ typedef struct dmu_recv_cookie {
+ 	uint64_t drc_ivset_guid;
+ 	void *drc_owner;
+ 	cred_t *drc_cred;
+-	proc_t *drc_proc;
+ 	nvlist_t *drc_begin_nvl;
+ 
+ 	objset_t *drc_os;
+diff --git a/include/sys/dsl_dataset.h b/include/sys/dsl_dataset.h
+index 624f3ddde..681294593 100644
+--- a/include/sys/dsl_dataset.h
++++ b/include/sys/dsl_dataset.h
+@@ -284,7 +284,6 @@ typedef struct dsl_dataset_promote_arg {
+ 	uint64_t used, comp, uncomp, unique, cloneusedsnap, originusedsnap;
+ 	nvlist_t *err_ds;
+ 	cred_t *cr;
+-	proc_t *proc;
+ } dsl_dataset_promote_arg_t;
+ 
+ typedef struct dsl_dataset_rollback_arg {
+@@ -299,7 +298,6 @@ typedef struct dsl_dataset_snapshot_arg {
+ 	nvlist_t *ddsa_props;
+ 	nvlist_t *ddsa_errors;
+ 	cred_t *ddsa_cr;
+-	proc_t *ddsa_proc;
+ } dsl_dataset_snapshot_arg_t;
+ 
+ typedef struct dsl_dataset_rename_snapshot_arg {
+@@ -459,7 +457,7 @@ int dsl_dataset_clone_swap_check_impl(dsl_dataset_t *clone,
+ void dsl_dataset_clone_swap_sync_impl(dsl_dataset_t *clone,
+     dsl_dataset_t *origin_head, dmu_tx_t *tx);
+ int dsl_dataset_snapshot_check_impl(dsl_dataset_t *ds, const char *snapname,
+-    dmu_tx_t *tx, boolean_t recv, uint64_t cnt, cred_t *cr, proc_t *proc);
++    dmu_tx_t *tx, boolean_t recv, uint64_t cnt, cred_t *cr);
+ void dsl_dataset_snapshot_sync_impl(dsl_dataset_t *ds, const char *snapname,
+     dmu_tx_t *tx);
+ 
+diff --git a/include/sys/dsl_dir.h b/include/sys/dsl_dir.h
+index 6135835fc..d2e9e2282 100644
+--- a/include/sys/dsl_dir.h
++++ b/include/sys/dsl_dir.h
+@@ -185,11 +185,11 @@ int dsl_dir_set_reservation(const char *ddname, zprop_source_t source,
+     uint64_t reservation);
+ int dsl_dir_activate_fs_ss_limit(const char *);
+ int dsl_fs_ss_limit_check(dsl_dir_t *, uint64_t, zfs_prop_t, dsl_dir_t *,
+-    cred_t *, proc_t *);
++    cred_t *);
+ void dsl_fs_ss_count_adjust(dsl_dir_t *, int64_t, const char *, dmu_tx_t *);
+ int dsl_dir_rename(const char *oldname, const char *newname);
+ int dsl_dir_transfer_possible(dsl_dir_t *sdd, dsl_dir_t *tdd,
+-    uint64_t fs_cnt, uint64_t ss_cnt, uint64_t space, cred_t *, proc_t *);
++    uint64_t fs_cnt, uint64_t ss_cnt, uint64_t space, cred_t *);
+ boolean_t dsl_dir_is_clone(dsl_dir_t *dd);
+ void dsl_dir_new_refreservation(dsl_dir_t *dd, struct dsl_dataset *ds,
+     uint64_t reservation, cred_t *cr, dmu_tx_t *tx);
+diff --git a/include/sys/zcp.h b/include/sys/zcp.h
+index 96279deae..5fcfb6219 100644
+--- a/include/sys/zcp.h
++++ b/include/sys/zcp.h
+@@ -76,7 +76,6 @@ typedef struct zcp_run_info {
+ 	 * rather than the 'current' thread's.
+ 	 */
+ 	cred_t		*zri_cred;
+-	proc_t		*zri_proc;
+ 
+ 	/*
+ 	 * The tx in which this channel program is running.
+diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h
+index 549f54c09..b3d48e257 100644
+--- a/include/sys/zfs_context.h
++++ b/include/sys/zfs_context.h
+@@ -632,6 +632,9 @@ extern void delay(clock_t ticks);
+ #define	kcred		NULL
+ #define	CRED()		NULL
+ 
++#define	crhold(cr)	((void)cr)
++#define	crfree(cr)	((void)cr)
++
+ #define	ptob(x)		((x) * PAGESIZE)
+ 
+ #define	NN_DIVISOR_1000	(1U << 0)
+@@ -744,7 +747,6 @@ extern int zfs_secpolicy_rename_perms(const char *from, const char *to,
+     cred_t *cr);
+ extern int zfs_secpolicy_destroy_perms(const char *name, cred_t *cr);
+ extern int secpolicy_zfs(const cred_t *cr);
+-extern int secpolicy_zfs_proc(const cred_t *cr, proc_t *proc);
+ extern zoneid_t getzoneid(void);
+ 
+ /* SID stuff */
+diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c
+index 653380149..e397fc851 100644
+--- a/lib/libzpool/kernel.c
++++ b/lib/libzpool/kernel.c
+@@ -918,13 +918,6 @@ secpolicy_zfs(const cred_t *cr)
+ 	return (0);
+ }
+ 
+-int
+-secpolicy_zfs_proc(const cred_t *cr, proc_t *proc)
+-{
+-	(void) cr, (void) proc;
+-	return (0);
+-}
+-
+ ksiddomain_t *
+ ksid_lookupdomain(const char *dom)
+ {
+diff --git a/module/os/freebsd/spl/spl_policy.c b/module/os/freebsd/spl/spl_policy.c
+index aad3ef2fa..7fc93648c 100644
+--- a/module/os/freebsd/spl/spl_policy.c
++++ b/module/os/freebsd/spl/spl_policy.c
+@@ -52,13 +52,6 @@ secpolicy_zfs(cred_t *cr)
+ 	return (priv_check_cred(cr, PRIV_VFS_MOUNT));
+ }
+ 
+-int
+-secpolicy_zfs_proc(cred_t *cr, proc_t *proc)
+-{
+-
+-	return (priv_check_cred(cr, PRIV_VFS_MOUNT));
+-}
+-
+ int
+ secpolicy_sys_config(cred_t *cr, int checkonly __unused)
+ {
+diff --git a/module/os/linux/zfs/policy.c b/module/os/linux/zfs/policy.c
+index c50ffcfe6..4396a5d9e 100644
+--- a/module/os/linux/zfs/policy.c
++++ b/module/os/linux/zfs/policy.c
+@@ -24,6 +24,7 @@
+  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+  * Copyright 2013, Joyent, Inc. All rights reserved.
+  * Copyright (C) 2016 Lawrence Livermore National Security, LLC.
++ * Copyright (c) 2025, Rob Norris <robn at despairlabs.com>
+  *
+  * For Linux the vast majority of this enforcement is already handled via
+  * the standard Linux VFS permission checks.  However certain administrative
+@@ -35,28 +36,32 @@
+ #include <linux/security.h>
+ #include <linux/vfs_compat.h>
+ 
+-/*
+- * The passed credentials cannot be directly verified because Linux only
+- * provides and interface to check the *current* process credentials.  In
+- * order to handle this the capable() test is only run when the passed
+- * credentials match the current process credentials or the kcred.  In
+- * all other cases this function must fail and return the passed err.
+- */
+ static int
+ priv_policy_ns(const cred_t *cr, int capability, int err,
+     struct user_namespace *ns)
+ {
+-	if (cr != CRED() && (cr != kcred))
+-		return (err);
++	/*
++	 * The passed credentials cannot be directly verified because Linux
++	 * only provides an interface to check the *current* process
++	 * credentials.  In order to handle this we check if the passed in
++	 * creds match the current process credentials or the kcred.  If not,
++	 * we swap the passed credentials into the current task, perform the
++	 * check, and then revert it before returning.
++	 */
++	const cred_t *old =
++	    (cr != CRED() && cr != kcred) ? override_creds(cr) : NULL;
+ 
+ #if defined(CONFIG_USER_NS)
+-	if (!(ns ? ns_capable(ns, capability) : capable(capability)))
++	if (ns ? ns_capable(ns, capability) : capable(capability))
+ #else
+-	if (!capable(capability))
++	if (capable(capability))
+ #endif
+-		return (err);
++		err = 0;
+ 
+-	return (0);
++	if (old)
++		revert_creds(old);
++
++	return (err);
+ }
+ 
+ static int
+@@ -249,19 +254,6 @@ secpolicy_zfs(const cred_t *cr)
+ 	return (priv_policy(cr, CAP_SYS_ADMIN, EACCES));
+ }
+ 
+-/*
+- * Equivalent to secpolicy_zfs(), but works even if the cred_t is not that of
+- * the current process.  Takes both cred_t and proc_t so that this can work
+- * easily on all platforms.
+- */
+-int
+-secpolicy_zfs_proc(const cred_t *cr, proc_t *proc)
+-{
+-	if (!has_capability(proc, CAP_SYS_ADMIN))
+-		return (EACCES);
+-	return (0);
+-}
+-
+ void
+ secpolicy_setid_clear(vattr_t *vap, cred_t *cr)
+ {
+diff --git a/module/zfs/dmu_objset.c b/module/zfs/dmu_objset.c
+index f22a236a6..6ab4304fa 100644
+--- a/module/zfs/dmu_objset.c
++++ b/module/zfs/dmu_objset.c
+@@ -34,6 +34,7 @@
+  * Copyright (c) 2019, Klara Inc.
+  * Copyright (c) 2019, Allan Jude
+  * Copyright (c) 2022 Hewlett Packard Enterprise Development LP.
++ * Copyright (c) 2025, Rob Norris <robn at despairlabs.com>
+  */
+ 
+ /* Portions Copyright 2010 Robert Milkowski */
+@@ -68,6 +69,7 @@
+ #include <sys/vdev_impl.h>
+ #include <sys/arc.h>
+ #include <cityhash.h>
++#include <sys/cred.h>
+ 
+ /*
+  * Needed to close a window in dnode_move() that allows the objset to be freed
+@@ -1179,7 +1181,6 @@ dmu_objset_create_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
+ typedef struct dmu_objset_create_arg {
+ 	const char *doca_name;
+ 	cred_t *doca_cred;
+-	proc_t *doca_proc;
+ 	void (*doca_userfunc)(objset_t *os, void *arg,
+ 	    cred_t *cr, dmu_tx_t *tx);
+ 	void *doca_userarg;
+@@ -1223,7 +1224,7 @@ dmu_objset_create_check(void *arg, dmu_tx_t *tx)
+ 	}
+ 
+ 	error = dsl_fs_ss_limit_check(pdd, 1, ZFS_PROP_FILESYSTEM_LIMIT, NULL,
+-	    doca->doca_cred, doca->doca_proc);
++	    doca->doca_cred);
+ 	if (error != 0) {
+ 		dsl_dir_rele(pdd, FTAG);
+ 		return (error);
+@@ -1350,9 +1351,11 @@ dmu_objset_create(const char *name, dmu_objset_type_t type, uint64_t flags,
+ 	dmu_objset_create_arg_t doca;
+ 	dsl_crypto_params_t tmp_dcp = { 0 };
+ 
++	cred_t *cr = CRED();
++	crhold(cr);
++
+ 	doca.doca_name = name;
+-	doca.doca_cred = CRED();
+-	doca.doca_proc = curproc;
++	doca.doca_cred = cr;
+ 	doca.doca_flags = flags;
+ 	doca.doca_userfunc = func;
+ 	doca.doca_userarg = arg;
+@@ -1374,6 +1377,9 @@ dmu_objset_create(const char *name, dmu_objset_type_t type, uint64_t flags,
+ 
+ 	if (rv == 0)
+ 		zvol_create_minor(name);
++
++	crfree(cr);
++
+ 	return (rv);
+ }
+ 
+@@ -1381,7 +1387,6 @@ typedef struct dmu_objset_clone_arg {
+ 	const char *doca_clone;
+ 	const char *doca_origin;
+ 	cred_t *doca_cred;
+-	proc_t *doca_proc;
+ } dmu_objset_clone_arg_t;
+ 
+ static int
+@@ -1409,7 +1414,7 @@ dmu_objset_clone_check(void *arg, dmu_tx_t *tx)
+ 	}
+ 
+ 	error = dsl_fs_ss_limit_check(pdd, 1, ZFS_PROP_FILESYSTEM_LIMIT, NULL,
+-	    doca->doca_cred, doca->doca_proc);
++	    doca->doca_cred);
+ 	if (error != 0) {
+ 		dsl_dir_rele(pdd, FTAG);
+ 		return (SET_ERROR(EDQUOT));
+@@ -1465,10 +1470,12 @@ dmu_objset_clone(const char *clone, const char *origin)
+ {
+ 	dmu_objset_clone_arg_t doca;
+ 
++	cred_t *cr = CRED();
++	crhold(cr);
++
+ 	doca.doca_clone = clone;
+ 	doca.doca_origin = origin;
+-	doca.doca_cred = CRED();
+-	doca.doca_proc = curproc;
++	doca.doca_cred = cr;
+ 
+ 	int rv = dsl_sync_task(clone,
+ 	    dmu_objset_clone_check, dmu_objset_clone_sync, &doca,
+@@ -1477,6 +1484,8 @@ dmu_objset_clone(const char *clone, const char *origin)
+ 	if (rv == 0)
+ 		zvol_create_minor(clone);
+ 
++	crfree(cr);
++
+ 	return (rv);
+ }
+ 
+diff --git a/module/zfs/dmu_recv.c b/module/zfs/dmu_recv.c
+index 91e3ca1cf..1a10ac156 100644
+--- a/module/zfs/dmu_recv.c
++++ b/module/zfs/dmu_recv.c
+@@ -30,6 +30,7 @@
+  * Copyright (c) 2019, Allan Jude
+  * Copyright (c) 2019 Datto Inc.
+  * Copyright (c) 2022 Axcient.
++ * Copyright (c) 2025, Rob Norris <robn at despairlabs.com>
+  */
+ 
+ #include <sys/arc.h>
+@@ -68,6 +69,7 @@
+ #include <sys/zfs_vfsops.h>
+ #endif
+ #include <sys/zfs_file.h>
++#include <sys/cred.h>
+ 
+ static uint_t zfs_recv_queue_length = SPA_MAXBLOCKSIZE;
+ static uint_t zfs_recv_queue_ff = 20;
+@@ -145,7 +147,6 @@ typedef struct dmu_recv_begin_arg {
+ 	const char *drba_origin;
+ 	dmu_recv_cookie_t *drba_cookie;
+ 	cred_t *drba_cred;
+-	proc_t *drba_proc;
+ 	dsl_crypto_params_t *drba_dcp;
+ } dmu_recv_begin_arg_t;
+ 
+@@ -411,7 +412,7 @@ recv_begin_check_existing_impl(dmu_recv_begin_arg_t *drba, dsl_dataset_t *ds,
+ 	 * against that limit.
+ 	 */
+ 	error = dsl_fs_ss_limit_check(ds->ds_dir, 1, ZFS_PROP_SNAPSHOT_LIMIT,
+-	    NULL, drba->drba_cred, drba->drba_proc);
++	    NULL, drba->drba_cred);
+ 	if (error != 0)
+ 		return (error);
+ 
+@@ -750,16 +751,14 @@ dmu_recv_begin_check(void *arg, dmu_tx_t *tx)
+ 		 * filesystems and increment those counts during begin_sync).
+ 		 */
+ 		error = dsl_fs_ss_limit_check(ds->ds_dir, 1,
+-		    ZFS_PROP_FILESYSTEM_LIMIT, NULL,
+-		    drba->drba_cred, drba->drba_proc);
++		    ZFS_PROP_FILESYSTEM_LIMIT, NULL, drba->drba_cred);
+ 		if (error != 0) {
+ 			dsl_dataset_rele(ds, FTAG);
+ 			return (error);
+ 		}
+ 
+ 		error = dsl_fs_ss_limit_check(ds->ds_dir, 1,
+-		    ZFS_PROP_SNAPSHOT_LIMIT, NULL,
+-		    drba->drba_cred, drba->drba_proc);
++		    ZFS_PROP_SNAPSHOT_LIMIT, NULL, drba->drba_cred);
+ 		if (error != 0) {
+ 			dsl_dataset_rele(ds, FTAG);
+ 			return (error);
+@@ -1265,6 +1264,9 @@ dmu_recv_begin(const char *tofs, const char *tosnap,
+ 	dmu_recv_begin_arg_t drba = { 0 };
+ 	int err = 0;
+ 
++	cred_t *cr = CRED();
++	crhold(cr);
++
+ 	memset(drc, 0, sizeof (dmu_recv_cookie_t));
+ 	drc->drc_drr_begin = drr_begin;
+ 	drc->drc_drrb = &drr_begin->drr_u.drr_begin;
+@@ -1273,8 +1275,7 @@ dmu_recv_begin(const char *tofs, const char *tosnap,
+ 	drc->drc_force = force;
+ 	drc->drc_heal = heal;
+ 	drc->drc_resumable = resumable;
+-	drc->drc_cred = CRED();
+-	drc->drc_proc = curproc;
++	drc->drc_cred = cr;
+ 	drc->drc_clone = (origin != NULL);
+ 
+ 	if (drc->drc_drrb->drr_magic == BSWAP_64(DMU_BACKUP_MAGIC)) {
+@@ -1286,6 +1287,8 @@ dmu_recv_begin(const char *tofs, const char *tosnap,
+ 		(void) fletcher_4_incremental_native(drr_begin,
+ 		    sizeof (dmu_replay_record_t), &drc->drc_cksum);
+ 	} else {
++		crfree(cr);
++		drc->drc_cred = NULL;
+ 		return (SET_ERROR(EINVAL));
+ 	}
+ 
+@@ -1302,9 +1305,11 @@ dmu_recv_begin(const char *tofs, const char *tosnap,
+ 	 * upper limit. Systems with less than 1GB of RAM will see a lower
+ 	 * limit from `arc_all_memory() / 4`.
+ 	 */
+-	if (payloadlen > (MIN((1U << 28), arc_all_memory() / 4)))
+-		return (E2BIG);
+-
++	if (payloadlen > (MIN((1U << 28), arc_all_memory() / 4))) {
++		crfree(cr);
++		drc->drc_cred = NULL;
++		return (SET_ERROR(E2BIG));
++	}
+ 
+ 	if (payloadlen != 0) {
+ 		void *payload = vmem_alloc(payloadlen, KM_SLEEP);
+@@ -1320,6 +1325,8 @@ dmu_recv_begin(const char *tofs, const char *tosnap,
+ 		    payload);
+ 		if (err != 0) {
+ 			vmem_free(payload, payloadlen);
++			crfree(cr);
++			drc->drc_cred = NULL;
+ 			return (err);
+ 		}
+ 		err = nvlist_unpack(payload, payloadlen, &drc->drc_begin_nvl,
+@@ -1328,6 +1335,8 @@ dmu_recv_begin(const char *tofs, const char *tosnap,
+ 		if (err != 0) {
+ 			kmem_free(drc->drc_next_rrd,
+ 			    sizeof (*drc->drc_next_rrd));
++			crfree(cr);
++			drc->drc_cred = NULL;
+ 			return (err);
+ 		}
+ 	}
+@@ -1337,8 +1346,7 @@ dmu_recv_begin(const char *tofs, const char *tosnap,
+ 
+ 	drba.drba_origin = origin;
+ 	drba.drba_cookie = drc;
+-	drba.drba_cred = CRED();
+-	drba.drba_proc = curproc;
++	drba.drba_cred = drc->drc_cred;
+ 
+ 	if (drc->drc_featureflags & DMU_BACKUP_FEATURE_RESUMING) {
+ 		err = dsl_sync_task(tofs,
+@@ -1373,6 +1381,8 @@ dmu_recv_begin(const char *tofs, const char *tosnap,
+ 	if (err != 0) {
+ 		kmem_free(drc->drc_next_rrd, sizeof (*drc->drc_next_rrd));
+ 		nvlist_free(drc->drc_begin_nvl);
++		crfree(cr);
++		drc->drc_cred = NULL;
+ 	}
+ 	return (err);
+ }
+@@ -3524,6 +3534,8 @@ out:
+ 		 */
+ 		dmu_recv_cleanup_ds(drc);
+ 		nvlist_free(drc->drc_keynvl);
++		crfree(drc->drc_cred);
++		drc->drc_cred = NULL;
+ 	}
+ 
+ 	objlist_destroy(drc->drc_ignore_objlist);
+@@ -3598,8 +3610,7 @@ dmu_recv_end_check(void *arg, dmu_tx_t *tx)
+ 			return (error);
+ 		}
+ 		error = dsl_dataset_snapshot_check_impl(origin_head,
+-		    drc->drc_tosnap, tx, B_TRUE, 1,
+-		    drc->drc_cred, drc->drc_proc);
++		    drc->drc_tosnap, tx, B_TRUE, 1, drc->drc_cred);
+ 		dsl_dataset_rele(origin_head, FTAG);
+ 		if (error != 0)
+ 			return (error);
+@@ -3607,8 +3618,7 @@ dmu_recv_end_check(void *arg, dmu_tx_t *tx)
+ 		error = dsl_destroy_head_check_impl(drc->drc_ds, 1);
+ 	} else {
+ 		error = dsl_dataset_snapshot_check_impl(drc->drc_ds,
+-		    drc->drc_tosnap, tx, B_TRUE, 1,
+-		    drc->drc_cred, drc->drc_proc);
++		    drc->drc_tosnap, tx, B_TRUE, 1, drc->drc_cred);
+ 	}
+ 	return (error);
+ }
+@@ -3820,6 +3830,10 @@ dmu_recv_end(dmu_recv_cookie_t *drc, void *owner)
+ 		zvol_create_minor(snapname);
+ 		kmem_strfree(snapname);
+ 	}
++
++	crfree(drc->drc_cred);
++	drc->drc_cred = NULL;
++
+ 	return (error);
+ }
+ 
+diff --git a/module/zfs/dsl_dataset.c b/module/zfs/dsl_dataset.c
+index 6f467fc0d..e4113c604 100644
+--- a/module/zfs/dsl_dataset.c
++++ b/module/zfs/dsl_dataset.c
+@@ -32,6 +32,7 @@
+  * Copyright (c) 2019, Klara Inc.
+  * Copyright (c) 2019, Allan Jude
+  * Copyright (c) 2020 The FreeBSD Foundation [1]
++ * Copyright (c) 2025, Rob Norris <robn at despairlabs.com>
+  *
+  * [1] Portions of this software were developed by Allan Jude
+  *     under sponsorship from the FreeBSD Foundation.
+@@ -1518,7 +1519,7 @@ dsl_dataset_snapshot_reserve_space(dsl_dataset_t *ds, dmu_tx_t *tx)
+ 
+ int
+ dsl_dataset_snapshot_check_impl(dsl_dataset_t *ds, const char *snapname,
+-    dmu_tx_t *tx, boolean_t recv, uint64_t cnt, cred_t *cr, proc_t *proc)
++    dmu_tx_t *tx, boolean_t recv, uint64_t cnt, cred_t *cr)
+ {
+ 	int error;
+ 	uint64_t value;
+@@ -1563,7 +1564,7 @@ dsl_dataset_snapshot_check_impl(dsl_dataset_t *ds, const char *snapname,
+ 	 */
+ 	if (cnt != 0 && cr != NULL) {
+ 		error = dsl_fs_ss_limit_check(ds->ds_dir, cnt,
+-		    ZFS_PROP_SNAPSHOT_LIMIT, NULL, cr, proc);
++		    ZFS_PROP_SNAPSHOT_LIMIT, NULL, cr);
+ 		if (error != 0)
+ 			return (error);
+ 	}
+@@ -1664,7 +1665,7 @@ dsl_dataset_snapshot_check(void *arg, dmu_tx_t *tx)
+ 			if (error == 0) {
+ 				error = dsl_fs_ss_limit_check(ds->ds_dir, cnt,
+ 				    ZFS_PROP_SNAPSHOT_LIMIT, NULL,
+-				    ddsa->ddsa_cr, ddsa->ddsa_proc);
++				    ddsa->ddsa_cr);
+ 				dsl_dataset_rele(ds, FTAG);
+ 			}
+ 
+@@ -1702,7 +1703,7 @@ dsl_dataset_snapshot_check(void *arg, dmu_tx_t *tx)
+ 		if (error == 0) {
+ 			/* passing 0/NULL skips dsl_fs_ss_limit_check */
+ 			error = dsl_dataset_snapshot_check_impl(ds,
+-			    atp + 1, tx, B_FALSE, 0, NULL, NULL);
++			    atp + 1, tx, B_FALSE, 0, NULL);
+ 			dsl_dataset_rele(ds, FTAG);
+ 		}
+ 
+@@ -1976,11 +1977,13 @@ dsl_dataset_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t *errors)
+ 		}
+ 	}
+ 
++	cred_t *cr = CRED();
++	crhold(cr);
++
+ 	ddsa.ddsa_snaps = snaps;
+ 	ddsa.ddsa_props = props;
+ 	ddsa.ddsa_errors = errors;
+-	ddsa.ddsa_cr = CRED();
+-	ddsa.ddsa_proc = curproc;
++	ddsa.ddsa_cr = cr;
+ 
+ 	if (error == 0) {
+ 		error = dsl_sync_task(firstname, dsl_dataset_snapshot_check,
+@@ -1988,6 +1991,8 @@ dsl_dataset_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t *errors)
+ 		    fnvlist_num_pairs(snaps) * 3, ZFS_SPACE_CHECK_NORMAL);
+ 	}
+ 
++	crfree(cr);
++
+ 	if (suspended != NULL) {
+ 		for (pair = nvlist_next_nvpair(suspended, NULL); pair != NULL;
+ 		    pair = nvlist_next_nvpair(suspended, pair)) {
+@@ -2028,7 +2033,7 @@ dsl_dataset_snapshot_tmp_check(void *arg, dmu_tx_t *tx)
+ 
+ 	/* NULL cred means no limit check for tmp snapshot */
+ 	error = dsl_dataset_snapshot_check_impl(ds, ddsta->ddsta_snapname,
+-	    tx, B_FALSE, 0, NULL, NULL);
++	    tx, B_FALSE, 0, NULL);
+ 	if (error != 0) {
+ 		dsl_dataset_rele(ds, FTAG);
+ 		return (error);
+@@ -3496,7 +3501,7 @@ dsl_dataset_promote_check(void *arg, dmu_tx_t *tx)
+ 
+ 	/* Check that there is enough space and limit headroom here */
+ 	err = dsl_dir_transfer_possible(origin_ds->ds_dir, hds->ds_dir,
+-	    0, ss_mv_cnt, ddpa->used, ddpa->cr, ddpa->proc);
++	    0, ss_mv_cnt, ddpa->used, ddpa->cr);
+ 	if (err != 0)
+ 		goto out;
+ 
+@@ -3932,15 +3937,19 @@ dsl_dataset_promote(const char *name, char *conflsnap)
+ 	if (error != 0)
+ 		return (error);
+ 
++	cred_t *cr = CRED();
++	crhold(cr);
++
+ 	ddpa.ddpa_clonename = name;
+ 	ddpa.err_ds = fnvlist_alloc();
+-	ddpa.cr = CRED();
+-	ddpa.proc = curproc;
++	ddpa.cr = cr;
+ 
+ 	error = dsl_sync_task(name, dsl_dataset_promote_check,
+ 	    dsl_dataset_promote_sync, &ddpa,
+ 	    2 + numsnaps, ZFS_SPACE_CHECK_RESERVED);
+ 
++	crfree(cr);
++
+ 	/*
+ 	 * Return the first conflicting snapshot found.
+ 	 */
+diff --git a/module/zfs/dsl_dir.c b/module/zfs/dsl_dir.c
+index a23486008..8c59fbf60 100644
+--- a/module/zfs/dsl_dir.c
++++ b/module/zfs/dsl_dir.c
+@@ -28,6 +28,7 @@
+  * Copyright (c) 2016 Actifio, Inc. All rights reserved.
+  * Copyright (c) 2018, loli10K <ezomori.nozomu at gmail.com>. All rights reserved.
+  * Copyright (c) 2023 Hewlett Packard Enterprise Development LP.
++ * Copyright (c) 2025, Rob Norris <robn at despairlabs.com>
+  */
+ 
+ #include <sys/dmu.h>
+@@ -759,7 +760,7 @@ typedef enum {
+ 
+ static enforce_res_t
+ dsl_enforce_ds_ss_limits(dsl_dir_t *dd, zfs_prop_t prop,
+-    cred_t *cr, proc_t *proc)
++    cred_t *cr)
+ {
+ 	enforce_res_t enforce = ENFORCE_ALWAYS;
+ 	uint64_t obj;
+@@ -774,16 +775,8 @@ dsl_enforce_ds_ss_limits(dsl_dir_t *dd, zfs_prop_t prop,
+ 	if (crgetzoneid(cr) != GLOBAL_ZONEID)
+ 		return (ENFORCE_ALWAYS);
+ 
+-	/*
+-	 * We are checking the saved credentials of the user process, which is
+-	 * not the current process.  Note that we can't use secpolicy_zfs(),
+-	 * because it only works if the cred is that of the current process (on
+-	 * Linux).
+-	 */
+-	if (secpolicy_zfs_proc(cr, proc) == 0)
++	if (secpolicy_zfs(cr) == 0)
+ 		return (ENFORCE_NEVER);
+-#else
+-	(void) proc;
+ #endif
+ 
+ 	if ((obj = dsl_dir_phys(dd)->dd_head_dataset_obj) == 0)
+@@ -817,7 +810,7 @@ dsl_enforce_ds_ss_limits(dsl_dir_t *dd, zfs_prop_t prop,
+  */
+ int
+ dsl_fs_ss_limit_check(dsl_dir_t *dd, uint64_t delta, zfs_prop_t prop,
+-    dsl_dir_t *ancestor, cred_t *cr, proc_t *proc)
++    dsl_dir_t *ancestor, cred_t *cr)
+ {
+ 	objset_t *os = dd->dd_pool->dp_meta_objset;
+ 	uint64_t limit, count;
+@@ -849,7 +842,7 @@ dsl_fs_ss_limit_check(dsl_dir_t *dd, uint64_t delta, zfs_prop_t prop,
+ 	 * are allowed to change the limit on the current dataset, but there
+ 	 * is another limit in the tree above.
+ 	 */
+-	enforce = dsl_enforce_ds_ss_limits(dd, prop, cr, proc);
++	enforce = dsl_enforce_ds_ss_limits(dd, prop, cr);
+ 	if (enforce == ENFORCE_NEVER)
+ 		return (0);
+ 
+@@ -893,7 +886,7 @@ dsl_fs_ss_limit_check(dsl_dir_t *dd, uint64_t delta, zfs_prop_t prop,
+ 
+ 	if (dd->dd_parent != NULL)
+ 		err = dsl_fs_ss_limit_check(dd->dd_parent, delta, prop,
+-		    ancestor, cr, proc);
++		    ancestor, cr);
+ 
+ 	return (err);
+ }
+@@ -1916,7 +1909,6 @@ typedef struct dsl_dir_rename_arg {
+ 	const char *ddra_oldname;
+ 	const char *ddra_newname;
+ 	cred_t *ddra_cred;
+-	proc_t *ddra_proc;
+ } dsl_dir_rename_arg_t;
+ 
+ typedef struct dsl_valid_rename_arg {
+@@ -2095,8 +2087,7 @@ dsl_dir_rename_check(void *arg, dmu_tx_t *tx)
+ 		}
+ 
+ 		error = dsl_dir_transfer_possible(dd->dd_parent,
+-		    newparent, fs_cnt, ss_cnt, myspace,
+-		    ddra->ddra_cred, ddra->ddra_proc);
++		    newparent, fs_cnt, ss_cnt, myspace, ddra->ddra_cred);
+ 		if (error != 0) {
+ 			dsl_dir_rele(newparent, FTAG);
+ 			dsl_dir_rele(dd, FTAG);
+@@ -2213,22 +2204,27 @@ dsl_dir_rename_sync(void *arg, dmu_tx_t *tx)
+ int
+ dsl_dir_rename(const char *oldname, const char *newname)
+ {
++	cred_t *cr = CRED();
++	crhold(cr);
++
+ 	dsl_dir_rename_arg_t ddra;
+ 
+ 	ddra.ddra_oldname = oldname;
+ 	ddra.ddra_newname = newname;
+-	ddra.ddra_cred = CRED();
+-	ddra.ddra_proc = curproc;
++	ddra.ddra_cred = cr;
+ 
+-	return (dsl_sync_task(oldname,
++	int err = dsl_sync_task(oldname,
+ 	    dsl_dir_rename_check, dsl_dir_rename_sync, &ddra,
+-	    3, ZFS_SPACE_CHECK_RESERVED));
++	    3, ZFS_SPACE_CHECK_RESERVED);
++
++	crfree(cr);
++	return (err);
+ }
+ 
+ int
+ dsl_dir_transfer_possible(dsl_dir_t *sdd, dsl_dir_t *tdd,
+     uint64_t fs_cnt, uint64_t ss_cnt, uint64_t space,
+-    cred_t *cr, proc_t *proc)
++    cred_t *cr)
+ {
+ 	dsl_dir_t *ancestor;
+ 	int64_t adelta;
+@@ -2242,11 +2238,11 @@ dsl_dir_transfer_possible(dsl_dir_t *sdd, dsl_dir_t *tdd,
+ 		return (SET_ERROR(ENOSPC));
+ 
+ 	err = dsl_fs_ss_limit_check(tdd, fs_cnt, ZFS_PROP_FILESYSTEM_LIMIT,
+-	    ancestor, cr, proc);
++	    ancestor, cr);
+ 	if (err != 0)
+ 		return (err);
+ 	err = dsl_fs_ss_limit_check(tdd, ss_cnt, ZFS_PROP_SNAPSHOT_LIMIT,
+-	    ancestor, cr, proc);
++	    ancestor, cr);
+ 	if (err != 0)
+ 		return (err);
+ 
+diff --git a/module/zfs/zcp.c b/module/zfs/zcp.c
+index 4cc3be6dd..c0f395d3c 100644
+--- a/module/zfs/zcp.c
++++ b/module/zfs/zcp.c
+@@ -1141,12 +1141,14 @@ zcp_eval(const char *poolname, const char *program, boolean_t sync,
+ 	}
+ 	VERIFY3U(3, ==, lua_gettop(state));
+ 
++	cred_t *cr = CRED();
++	crhold(cr);
++
+ 	runinfo.zri_state = state;
+ 	runinfo.zri_allocargs = &allocargs;
+ 	runinfo.zri_outnvl = outnvl;
+ 	runinfo.zri_result = 0;
+-	runinfo.zri_cred = CRED();
+-	runinfo.zri_proc = curproc;
++	runinfo.zri_cred = cr;
+ 	runinfo.zri_timed_out = B_FALSE;
+ 	runinfo.zri_canceled = B_FALSE;
+ 	runinfo.zri_sync = sync;
+@@ -1165,6 +1167,8 @@ zcp_eval(const char *poolname, const char *program, boolean_t sync,
+ 	}
+ 	lua_close(state);
+ 
++	crfree(cr);
++
+ 	/*
+ 	 * Create device minor nodes for any new zvols.
+ 	 */
+diff --git a/module/zfs/zcp_synctask.c b/module/zfs/zcp_synctask.c
+index b9a42ffba..28f734abf 100644
+--- a/module/zfs/zcp_synctask.c
++++ b/module/zfs/zcp_synctask.c
+@@ -193,7 +193,6 @@ zcp_synctask_promote(lua_State *state, boolean_t sync, nvlist_t *err_details)
+ 	ddpa.ddpa_clonename = dsname;
+ 	ddpa.err_ds = err_details;
+ 	ddpa.cr = ri->zri_cred;
+-	ddpa.proc = ri->zri_proc;
+ 
+ 	/*
+ 	 * If there was a snapshot name conflict, then err_ds will be filled
+@@ -277,7 +276,6 @@ zcp_synctask_snapshot(lua_State *state, boolean_t sync, nvlist_t *err_details)
+ 	ddsa.ddsa_errors = NULL;
+ 	ddsa.ddsa_props = NULL;
+ 	ddsa.ddsa_cr = ri->zri_cred;
+-	ddsa.ddsa_proc = ri->zri_proc;
+ 	ddsa.ddsa_snaps = fnvlist_alloc();
+ 	fnvlist_add_boolean(ddsa.ddsa_snaps, dsname);
+ 
+-- 
+2.49.0
+
diff --git a/0002-Linux-6.2-6.15-del_timer_sync-renamed-to-timer_delet.patch b/0002-Linux-6.2-6.15-del_timer_sync-renamed-to-timer_delet.patch
new file mode 100644
index 0000000..d8963ce
--- /dev/null
+++ b/0002-Linux-6.2-6.15-del_timer_sync-renamed-to-timer_delet.patch
@@ -0,0 +1,109 @@
+From 8c0f7619b23f8756afe3c9cb75c261f4362205bf Mon Sep 17 00:00:00 2001
+From: Rob Norris <robn at despairlabs.com>
+Date: Tue, 8 Apr 2025 20:47:43 +1000
+Subject: [PATCH 2/2] Linux 6.2/6.15: del_timer_sync() renamed to
+ timer_delete_sync()
+
+Renamed in 6.2, and the compat wrapper removed in 6.15. No signature or
+functional change apart from that, so a very minimal update for us.
+
+Sponsored-by: https://despairlabs.com/sponsor/
+Reviewed-by: Brian Behlendorf <behlendorf1 at llnl.gov>
+Reviewed-by: Tony Hutter <hutter2 at llnl.gov>
+Reviewed-by: Pavel Snajdr <snajpa at snajpa.net>
+Signed-off-by: Rob Norris <robn at despairlabs.com>
+Closes #17229
+(cherry picked from commit 841be1d0495224a47d3dbfd8647c7fcbf58b205c)
+---
+ config/kernel-timer.m4          | 32 ++++++++++++++++++++++++++++++++
+ config/kernel.m4                |  2 ++
+ module/os/linux/spl/spl-taskq.c |  7 ++++++-
+ 3 files changed, 40 insertions(+), 1 deletion(-)
+ create mode 100644 config/kernel-timer.m4
+
+diff --git a/config/kernel-timer.m4 b/config/kernel-timer.m4
+new file mode 100644
+index 000000000..c89ea204e
+--- /dev/null
++++ b/config/kernel-timer.m4
+@@ -0,0 +1,32 @@
++dnl #
++dnl # 6.2: timer_delete_sync introduced, del_timer_sync deprecated and made
++dnl #      into a simple wrapper
++dnl # 6.15: del_timer_sync removed
++dnl #
++AC_DEFUN([ZFS_AC_KERNEL_SRC_TIMER_DELETE_SYNC], [
++	ZFS_LINUX_TEST_SRC([timer_delete_sync], [
++		#include <linux/timer.h>
++	],[
++		struct timer_list *timer __attribute__((unused)) = NULL;
++		timer_delete_sync(timer);
++	])
++])
++
++AC_DEFUN([ZFS_AC_KERNEL_TIMER_DELETE_SYNC], [
++	AC_MSG_CHECKING([whether timer_delete_sync() is available])
++	ZFS_LINUX_TEST_RESULT([timer_delete_sync], [
++		AC_MSG_RESULT(yes)
++		AC_DEFINE(HAVE_TIMER_DELETE_SYNC, 1,
++		    [timer_delete_sync is available])
++	],[
++		AC_MSG_RESULT(no)
++	])
++])
++
++AC_DEFUN([ZFS_AC_KERNEL_SRC_TIMER], [
++	ZFS_AC_KERNEL_SRC_TIMER_DELETE_SYNC
++])
++
++AC_DEFUN([ZFS_AC_KERNEL_TIMER], [
++	ZFS_AC_KERNEL_TIMER_DELETE_SYNC
++])
+diff --git a/config/kernel.m4 b/config/kernel.m4
+index 29bf58868..b933475e9 100644
+--- a/config/kernel.m4
++++ b/config/kernel.m4
+@@ -130,6 +130,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
+ 	ZFS_AC_KERNEL_SRC_MM_PAGE_MAPPING
+ 	ZFS_AC_KERNEL_SRC_FILE
+ 	ZFS_AC_KERNEL_SRC_PIN_USER_PAGES
++	ZFS_AC_KERNEL_SRC_TIMER
+ 	case "$host_cpu" in
+ 		powerpc*)
+ 			ZFS_AC_KERNEL_SRC_CPU_HAS_FEATURE
+@@ -244,6 +245,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
+ 	ZFS_AC_KERNEL_1ARG_ASSIGN_STR
+ 	ZFS_AC_KERNEL_FILE
+ 	ZFS_AC_KERNEL_PIN_USER_PAGES
++	ZFS_AC_KERNEL_TIMER
+ 	case "$host_cpu" in
+ 		powerpc*)
+ 			ZFS_AC_KERNEL_CPU_HAS_FEATURE
+diff --git a/module/os/linux/spl/spl-taskq.c b/module/os/linux/spl/spl-taskq.c
+index d5b42fdfa..700ec1c7f 100644
+--- a/module/os/linux/spl/spl-taskq.c
++++ b/module/os/linux/spl/spl-taskq.c
+@@ -38,6 +38,11 @@
+ #include <sys/kstat.h>
+ #include <linux/cpuhotplug.h>
+ 
++/* Linux 6.2 renamed timer_delete_sync(); point it at its old name for those. */
++#ifndef HAVE_TIMER_DELETE_SYNC
++#define	timer_delete_sync(t)	del_timer_sync(t)
++#endif
++
+ typedef struct taskq_kstats {
+ 	/* static values, for completeness */
+ 	kstat_named_t tqks_threads_max;
+@@ -633,7 +638,7 @@ taskq_cancel_id(taskq_t *tq, taskqid_t id)
+ 		 */
+ 		if (timer_pending(&t->tqent_timer)) {
+ 			spin_unlock_irqrestore(&tq->tq_lock, flags);
+-			del_timer_sync(&t->tqent_timer);
++			timer_delete_sync(&t->tqent_timer);
+ 			spin_lock_irqsave_nested(&tq->tq_lock, flags,
+ 			    tq->tq_lock_class);
+ 		}
+-- 
+2.49.0
+
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/zfs.git/commitdiff/32b58c542f7416ac3535511fab4f05a749fd1519



More information about the pld-cvs-commit mailing list