[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