[packages/zfs] - up to 2.2.0-rc3

baggins baggins at pld-linux.org
Thu Sep 7 15:19:57 CEST 2023


commit 757b8d9475f8bdc5710df221acbd0c6dfcc9fca7
Author: Jan Rękorajski <baggins at pld-linux.org>
Date:   Thu Sep 7 14:33:52 2023 +0200

    - up to 2.2.0-rc3

 am.patch         |   33 -
 kernel-6.5.patch |  934 +++++++++
 no-Werror.patch  |   11 -
 staging.patch    | 5955 ------------------------------------------------------
 zfs.spec         |   59 +-
 5 files changed, 957 insertions(+), 6035 deletions(-)
---
diff --git a/zfs.spec b/zfs.spec
index 9167d7a..a415511 100644
--- a/zfs.spec
+++ b/zfs.spec
@@ -24,21 +24,20 @@ exit 1
 
 %define		_duplicate_files_terminate_build	0
 
-%define	rel	1
+%define	pre	rc3
+%define	rel	0.%{pre}.1
 %define	pname	zfs
 Summary:	Native Linux port of the ZFS filesystem
 Summary(pl.UTF-8):	Natywny linuksowy port systemu plików ZFS
 Name:		%{pname}%{?_pld_builder:%{?with_kernel:-kernel}}%{_alt_kernel}
-Version:	2.1.11
+Version:	2.2.0
 Release:	%{rel}%{?_pld_builder:%{?with_kernel:@%{_kernel_ver_str}}}
 License:	CDDL
 Group:		Applications/System
-Source0:	https://github.com/openzfs/zfs/releases/download/zfs-%{version}/%{pname}-%{version}.tar.gz
-# Source0-md5:	2a7b9d2a487a02d373404c48719488ed
+Source0:	https://github.com/openzfs/zfs/releases/download/zfs-%{version}-%{pre}/%{pname}-%{version}-%{pre}.tar.gz
+# Source0-md5:	75fd8dc40d9601db40029b357c824f3f
 Patch0:		initdir.patch
-Patch1:		am.patch
-Patch2:		no-Werror.patch
-Patch3:		staging.patch
+Patch3:		kernel-6.5.patch
 URL:		https://zfsonlinux.org/
 BuildRequires:	autoconf >= 2.50
 BuildRequires:	automake
@@ -238,24 +237,8 @@ pakietu kernel%{_alt_kernel} w wersji %{_kernel_ver}.\
 \
 %files -n kernel%{_alt_kernel}-zfs\
 %defattr(644,root,root,755)\
-%dir /lib/modules/%{_kernel_ver}/misc/lua\
-/lib/modules/%{_kernel_ver}/misc/lua/zlua.ko*\
-%dir /lib/modules/%{_kernel_ver}/misc/avl\
-/lib/modules/%{_kernel_ver}/misc/avl/zavl.ko*\
-%dir /lib/modules/%{_kernel_ver}/misc/icp\
-/lib/modules/%{_kernel_ver}/misc/icp/icp.ko*\
-%dir /lib/modules/%{_kernel_ver}/misc/nvpair\
-/lib/modules/%{_kernel_ver}/misc/nvpair/znvpair.ko*\
-%dir /lib/modules/%{_kernel_ver}/misc/spl\
-/lib/modules/%{_kernel_ver}/misc/spl/spl.ko*\
-%dir /lib/modules/%{_kernel_ver}/misc/unicode\
-/lib/modules/%{_kernel_ver}/misc/unicode/zunicode.ko*\
-%dir /lib/modules/%{_kernel_ver}/misc/zcommon\
-/lib/modules/%{_kernel_ver}/misc/zcommon/zcommon.ko*\
-%dir /lib/modules/%{_kernel_ver}/misc/zfs\
-/lib/modules/%{_kernel_ver}/misc/zfs/zfs.ko*\
-%dir /lib/modules/%{_kernel_ver}/misc/zstd\
-/lib/modules/%{_kernel_ver}/misc/zstd/zzstd.ko*\
+/lib/modules/%{_kernel_ver}/misc/spl.ko*\
+/lib/modules/%{_kernel_ver}/misc/zfs.ko*\
 \
 %files -n kernel%{_alt_kernel}-zfs-devel\
 %defattr(644,root,root,755)\
@@ -284,18 +267,17 @@ p=`pwd`\
 %{?with_kernel:%{expand:%create_kernel_packages}}
 
 %prep
-%setup -q -n %{pname}-%{version}
+%setup -q -n %{pname}-%{version}-%{pre}
 %patch0 -p1
-%patch1 -p1
-%patch2 -p1
 %patch3 -p1
 
 %{__sed} -E -i -e '1s,#!\s*/usr/bin/env\s+python3(\s|$),#!%{__python3}\1,' \
-      cmd/arc_summary/arc_summary3
+      cmd/arc_summary
 
 %{__sed} -E -i -e '1s,#!\s*/usr/bin/env\s+ at PYTHON_SHEBANG@(\s|$),#!%{__python3}\1,' \
-      cmd/arcstat/arcstat.in \
-      cmd/dbufstat/dbufstat.in
+      cmd/arcstat.in \
+      cmd/dbufstat.in \
+      cmd/zilstat.in
 
 %{__sed} -E -i -e '1s,#!\s*/usr/bin/env\s+bash(\s|$),#!/bin/bash\1,' \
       contrib/dracut/02zfsexpandknowledge/module-setup.sh.in \
@@ -347,8 +329,6 @@ rm -rf $RPM_BUILD_ROOT
 %if %{with kernel}
 install -d $RPM_BUILD_ROOT
 cp -a installed/* $RPM_BUILD_ROOT
-# Drop unneeded spl compat links
-%{__rm} -r $RPM_BUILD_ROOT/usr/src/spl-%{version}
 %endif
 
 %if %{with userspace}
@@ -403,6 +383,7 @@ rm -rf $RPM_BUILD_ROOT
 %attr(755,root,root) %{_bindir}/arc_summary
 %attr(755,root,root) %{_bindir}/arcstat
 %attr(755,root,root) %{_bindir}/dbufstat
+%attr(755,root,root) %{_bindir}/zilstat
 %attr(755,root,root) %{_bindir}/zvol_wait
 %attr(755,root,root) %{_sbindir}/fsck.zfs
 %attr(755,root,root) %{_sbindir}/zdb
@@ -447,6 +428,9 @@ rm -rf $RPM_BUILD_ROOT
 %{systemdunitdir}/zfs-scrub-monthly at .timer
 %{systemdunitdir}/zfs-scrub-weekly at .timer
 %{systemdunitdir}/zfs-share.service
+%{systemdunitdir}/zfs-trim-monthly at .timer
+%{systemdunitdir}/zfs-trim-weekly at .timer
+%{systemdunitdir}/zfs-trim at .service
 %{systemdunitdir}/zfs-volume-wait.service
 %{systemdunitdir}/zfs-volumes.target
 %{systemdunitdir}/zfs-zed.service
@@ -471,6 +455,7 @@ rm -rf $RPM_BUILD_ROOT
 %{_mandir}/man4/spl.4*
 %{_mandir}/man4/zfs.4*
 %{_mandir}/man5/vdev_id.conf.5*
+%{_mandir}/man7/vdevprops.7*
 %{_mandir}/man7/zfsconcepts.7*
 %{_mandir}/man7/zfsprops.7*
 %{_mandir}/man7/zpool-features.7*
@@ -515,10 +500,12 @@ rm -rf $RPM_BUILD_ROOT
 %{_mandir}/man8/zfs-unallow.8*
 %{_mandir}/man8/zfs-unjail.8*
 %{_mandir}/man8/zfs-unload-key.8*
+%{_mandir}/man8/zfs-unzone.8*
 %{_mandir}/man8/zfs-unmount.8*
 %{_mandir}/man8/zfs-upgrade.8*
 %{_mandir}/man8/zfs-userspace.8*
 %{_mandir}/man8/zfs-wait.8*
+%{_mandir}/man8/zfs-zone.8*
 %{_mandir}/man8/zfs_ids_to_path.8*
 %{_mandir}/man8/zgenhostid.8*
 %{_mandir}/man8/zinject.8*
@@ -604,7 +591,7 @@ rm -rf $RPM_BUILD_ROOT
 
 %files -n dracut-zfs
 %defattr(644,root,root,755)
-%doc contrib/dracut/README.dracut.markdown
+%doc contrib/dracut/README.md
 %dir %{dracutlibdir}/modules.d/02zfsexpandknowledge
 %attr(755,root,root) %{dracutlibdir}/modules.d/02zfsexpandknowledge/module-setup.sh
 %dir %{dracutlibdir}/modules.d/90zfs
@@ -649,6 +636,6 @@ rm -rf $RPM_BUILD_ROOT
 %defattr(644,root,root,755)
 %dir /usr/src/zfs-%{version}
 /usr/src/zfs-%{version}/include
-/usr/src/zfs-%{version}/zfs.release
-/usr/src/zfs-%{version}/zfs_config.h
+/usr/src/zfs-%{version}/zfs.release.in
+/usr/src/zfs-%{version}/zfs_config.h.in
 %endif
diff --git a/am.patch b/am.patch
deleted file mode 100644
index ca31132..0000000
--- a/am.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-diff --git a/Makefile.am b/Makefile.am
-index 55cae89fa..8ce1af3b8 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -9,14 +9,14 @@ if CONFIG_USER
- endif
- endif
- if CONFIG_KERNEL
--SUBDIRS += module
-+SUBDIRS += scripts module
- 
- extradir = $(prefix)/src/zfs-$(VERSION)
--extra_HEADERS = zfs.release.in zfs_config.h.in
-+extra_HEADERS = zfs.release zfs_config.h
- 
- if BUILD_LINUX
- kerneldir = $(prefix)/src/zfs-$(VERSION)/$(LINUX_VERSION)
--nodist_kernel_HEADERS = zfs.release zfs_config.h module/$(LINUX_SYMBOLS)
-+nodist_kernel_HEADERS = zfs.release.in zfs_config.h.in module/$(LINUX_SYMBOLS)
- endif
- endif
- 
-@@ -54,8 +54,8 @@ install-data-hook:
- 	cd $(DESTDIR)$(prefix)/src/spl-$(VERSION) && \
- 	ln -s ../zfs-$(VERSION)/include/spl include && \
- 	ln -s ../zfs-$(VERSION)/$(LINUX_VERSION) $(LINUX_VERSION) && \
--	ln -s ../zfs-$(VERSION)/zfs_config.h.in spl_config.h.in && \
--	ln -s ../zfs-$(VERSION)/zfs.release.in spl.release.in && \
-+	ln -s ../zfs-$(VERSION)/zfs_config.h spl_config.h && \
-+	ln -s ../zfs-$(VERSION)/zfs.release spl.release && \
- 	cd $(DESTDIR)$(prefix)/src/zfs-$(VERSION)/$(LINUX_VERSION) && \
- 	ln -fs zfs_config.h spl_config.h && \
- 	ln -fs zfs.release spl.release
diff --git a/kernel-6.5.patch b/kernel-6.5.patch
new file mode 100644
index 0000000..6c4a55f
--- /dev/null
+++ b/kernel-6.5.patch
@@ -0,0 +1,934 @@
+From 3b8e318b7737fa40daf6abbc06ba31cd6ae8d572 Mon Sep 17 00:00:00 2001
+From: Coleman Kane <ckane at colemankane.org>
+Date: Tue, 1 Aug 2023 11:32:38 -0400
+Subject: [PATCH] Linux 6.5 compat: use disk_check_media_change when it exists
+
+When disk_check_media_change() exists, then define
+zfs_check_media_change() to simply call disk_check_media_change() on
+the bd_disk member of its argument. Since disk_check_media_change()
+is newer than when revalidate_disk was present in bops, we should
+be able to safely do this via a macro, instead of recreating a new
+implementation of the inline function that forces revalidation.
+
+Reviewed-by: Brian Behlendorf <behlendorf1 at llnl.gov>
+Reviewed-by: Brian Atkinson <batkinson at lanl.gov>
+Signed-off-by: Coleman Kane <ckane at colemankane.org>
+Closes #15101
+---
+ include/os/linux/kernel/linux/blkdev_compat.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/include/os/linux/kernel/linux/blkdev_compat.h b/include/os/linux/kernel/linux/blkdev_compat.h
+index e0f20ba32008..1641dd92a918 100644
+--- a/include/os/linux/kernel/linux/blkdev_compat.h
++++ b/include/os/linux/kernel/linux/blkdev_compat.h
+@@ -347,6 +347,7 @@ zfs_check_media_change(struct block_device *bdev)
+ #define	vdev_bdev_reread_part(bdev)	zfs_check_media_change(bdev)
+ #elif defined(HAVE_DISK_CHECK_MEDIA_CHANGE)
+ #define	vdev_bdev_reread_part(bdev)	disk_check_media_change(bdev->bd_disk)
++#define	zfs_check_media_change(bdev)	disk_check_media_change(bdev->bd_disk)
+ #else
+ /*
+  * This is encountered if check_disk_change() and bdev_check_media_change()
+From 43e8f6e37fddc31f23301cb70d466687bd205cd9 Mon Sep 17 00:00:00 2001
+From: Coleman Kane <ckane at colemankane.org>
+Date: Tue, 1 Aug 2023 11:37:20 -0400
+Subject: [PATCH] Linux 6.5 compat: blkdev changes
+
+Multiple changes to the blkdev API were introduced in Linux 6.5. This
+includes passing (void* holder) to blkdev_put, adding a new
+blk_holder_ops* arg to blkdev_get_by_path, adding a new blk_mode_t type
+that replaces uses of fmode_t, and removing an argument from the release
+handler on block_device_operations that we weren't using. The open
+function definition has also changed to take gendisk* and blk_mode_t, so
+update it accordingly, too.
+
+Implement local wrappers for blkdev_get_by_path() and
+vdev_blkdev_put() so that the in-line calls are cleaner, and place the
+conditionally-compiled implementation details inside of both of these
+local wrappers. Both calls are exclusively used within vdev_disk.c, at
+this time.
+
+Add blk_mode_is_open_write() to test FMODE_WRITE / BLK_OPEN_WRITE
+The wrapper function is now used for testing using the appropriate
+method for the kernel, whether the open mode is writable or not.
+
+Emphasize fmode_t arg in zvol_release is not used
+
+Reviewed-by: Brian Behlendorf <behlendorf1 at llnl.gov>
+Signed-off-by: Coleman Kane <ckane at colemankane.org>
+Closes #15099
+---
+ config/kernel-blkdev.m4                       | 84 ++++++++++++++++++-
+ config/kernel-block-device-operations.m4      | 35 +++++++-
+ include/os/linux/kernel/linux/blkdev_compat.h |  6 ++
+ module/os/linux/zfs/vdev_disk.c               | 65 ++++++++++++--
+ module/os/linux/zfs/zfs_vnops_os.c            |  2 +-
+ module/os/linux/zfs/zpl_ctldir.c              |  2 +-
+ module/os/linux/zfs/zvol_os.c                 | 28 ++++++-
+ 7 files changed, 203 insertions(+), 19 deletions(-)
+
+diff --git a/config/kernel-blkdev.m4 b/config/kernel-blkdev.m4
+index 887acee670ba..e04a2bd2c3b6 100644
+--- a/config/kernel-blkdev.m4
++++ b/config/kernel-blkdev.m4
+@@ -16,12 +16,63 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV_GET_BY_PATH], [
+ 	])
+ ])
+ 
++dnl #
++dnl # 6.5.x API change,
++dnl # blkdev_get_by_path() takes 4 args
++dnl #
++AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV_GET_BY_PATH_4ARG], [
++	ZFS_LINUX_TEST_SRC([blkdev_get_by_path_4arg], [
++		#include <linux/fs.h>
++		#include <linux/blkdev.h>
++	], [
++		struct block_device *bdev __attribute__ ((unused)) = NULL;
++		const char *path = "path";
++		fmode_t mode = 0;
++		void *holder = NULL;
++		struct blk_holder_ops h;
++
++		bdev = blkdev_get_by_path(path, mode, holder, &h);
++	])
++])
++
+ AC_DEFUN([ZFS_AC_KERNEL_BLKDEV_GET_BY_PATH], [
+-	AC_MSG_CHECKING([whether blkdev_get_by_path() exists])
++	AC_MSG_CHECKING([whether blkdev_get_by_path() exists and takes 3 args])
+ 	ZFS_LINUX_TEST_RESULT([blkdev_get_by_path], [
+ 		AC_MSG_RESULT(yes)
+ 	], [
+-		ZFS_LINUX_TEST_ERROR([blkdev_get_by_path()])
++		AC_MSG_RESULT(no)
++		AC_MSG_CHECKING([whether blkdev_get_by_path() exists and takes 4 args])
++		ZFS_LINUX_TEST_RESULT([blkdev_get_by_path_4arg], [
++			AC_DEFINE(HAVE_BLKDEV_GET_BY_PATH_4ARG, 1,
++				[blkdev_get_by_path() exists and takes 4 args])
++			AC_MSG_RESULT(yes)
++		], [
++			ZFS_LINUX_TEST_ERROR([blkdev_get_by_path()])
++		])
++	])
++])
++
++dnl #
++dnl # 6.5.x API change
++dnl # blk_mode_t was added as a type to supercede some places where fmode_t
++dnl # is used
++dnl #
++AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV_BLK_MODE_T], [
++	ZFS_LINUX_TEST_SRC([blk_mode_t], [
++		#include <linux/fs.h>
++		#include <linux/blkdev.h>
++	], [
++		blk_mode_t m __attribute((unused)) = (blk_mode_t)0;
++	])
++])
++
++AC_DEFUN([ZFS_AC_KERNEL_BLKDEV_BLK_MODE_T], [
++	AC_MSG_CHECKING([whether blk_mode_t is defined])
++	ZFS_LINUX_TEST_RESULT([blk_mode_t], [
++		AC_MSG_RESULT(yes)
++		AC_DEFINE(HAVE_BLK_MODE_T, 1, [blk_mode_t is defined])
++	], [
++		AC_MSG_RESULT(no)
+ 	])
+ ])
+ 
+@@ -41,12 +92,35 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV_PUT], [
+ 	])
+ ])
+ 
++dnl #
++dnl # 6.5.x API change.
++dnl # blkdev_put() takes (void* holder) as arg 2
++dnl #
++AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV_PUT_HOLDER], [
++	ZFS_LINUX_TEST_SRC([blkdev_put_holder], [
++		#include <linux/fs.h>
++		#include <linux/blkdev.h>
++	], [
++		struct block_device *bdev = NULL;
++		void *holder = NULL;
++
++		blkdev_put(bdev, holder);
++	])
++])
++
+ AC_DEFUN([ZFS_AC_KERNEL_BLKDEV_PUT], [
+ 	AC_MSG_CHECKING([whether blkdev_put() exists])
+ 	ZFS_LINUX_TEST_RESULT([blkdev_put], [
+ 		AC_MSG_RESULT(yes)
+ 	], [
+-		ZFS_LINUX_TEST_ERROR([blkdev_put()])
++		AC_MSG_CHECKING([whether blkdev_put() accepts void* as arg 2])
++		ZFS_LINUX_TEST_RESULT([blkdev_put_holder], [
++			AC_MSG_RESULT(yes)
++			AC_DEFINE(HAVE_BLKDEV_PUT_HOLDER, 1,
++				[blkdev_put() accepts void* as arg 2])
++		], [
++			ZFS_LINUX_TEST_ERROR([blkdev_put()])
++		])
+ 	])
+ ])
+ 
+@@ -495,7 +569,9 @@ AC_DEFUN([ZFS_AC_KERNEL_BLKDEV_BLK_STS_RESV_CONFLICT], [
+ 
+ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV], [
+ 	ZFS_AC_KERNEL_SRC_BLKDEV_GET_BY_PATH
++	ZFS_AC_KERNEL_SRC_BLKDEV_GET_BY_PATH_4ARG
+ 	ZFS_AC_KERNEL_SRC_BLKDEV_PUT
++	ZFS_AC_KERNEL_SRC_BLKDEV_PUT_HOLDER
+ 	ZFS_AC_KERNEL_SRC_BLKDEV_REREAD_PART
+ 	ZFS_AC_KERNEL_SRC_BLKDEV_INVALIDATE_BDEV
+ 	ZFS_AC_KERNEL_SRC_BLKDEV_LOOKUP_BDEV
+@@ -510,6 +586,7 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKDEV], [
+ 	ZFS_AC_KERNEL_SRC_BLKDEV_PART_TO_DEV
+ 	ZFS_AC_KERNEL_SRC_BLKDEV_DISK_CHECK_MEDIA_CHANGE
+ 	ZFS_AC_KERNEL_SRC_BLKDEV_BLK_STS_RESV_CONFLICT
++	ZFS_AC_KERNEL_SRC_BLKDEV_BLK_MODE_T
+ ])
+ 
+ AC_DEFUN([ZFS_AC_KERNEL_BLKDEV], [
+@@ -530,4 +607,5 @@ AC_DEFUN([ZFS_AC_KERNEL_BLKDEV], [
+ 	ZFS_AC_KERNEL_BLKDEV_PART_TO_DEV
+ 	ZFS_AC_KERNEL_BLKDEV_DISK_CHECK_MEDIA_CHANGE
+ 	ZFS_AC_KERNEL_BLKDEV_BLK_STS_RESV_CONFLICT
++	ZFS_AC_KERNEL_BLKDEV_BLK_MODE_T
+ ])
+diff --git a/config/kernel-block-device-operations.m4 b/config/kernel-block-device-operations.m4
+index 84e39dc8a2f6..d13c1337b1fb 100644
+--- a/config/kernel-block-device-operations.m4
++++ b/config/kernel-block-device-operations.m4
+@@ -49,12 +49,42 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID], [
+ 	], [], [])
+ ])
+ 
++dnl #
++dnl # 5.9.x API change
++dnl #
++AC_DEFUN([ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_RELEASE_1ARG], [
++	ZFS_LINUX_TEST_SRC([block_device_operations_release_void_1arg], [
++		#include <linux/blkdev.h>
++
++		void blk_release(struct gendisk *g) {
++			(void) g;
++			return;
++		}
++
++		static const struct block_device_operations
++		    bops __attribute__ ((unused)) = {
++			.open		= NULL,
++			.release	= blk_release,
++			.ioctl		= NULL,
++			.compat_ioctl	= NULL,
++		};
++	], [], [])
++])
++
+ AC_DEFUN([ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID], [
+-	AC_MSG_CHECKING([whether bops->release() is void])
++	AC_MSG_CHECKING([whether bops->release() is void and takes 2 args])
+ 	ZFS_LINUX_TEST_RESULT([block_device_operations_release_void], [
+ 		AC_MSG_RESULT(yes)
+ 	],[
+-		ZFS_LINUX_TEST_ERROR([bops->release()])
++		AC_MSG_RESULT(no)
++		AC_MSG_CHECKING([whether bops->release() is void and takes 1 arg])
++		ZFS_LINUX_TEST_RESULT([block_device_operations_release_void_1arg], [
++			AC_MSG_RESULT(yes)
++			AC_DEFINE([HAVE_BLOCK_DEVICE_OPERATIONS_RELEASE_1ARG], [1],
++				[Define if release() in block_device_operations takes 1 arg])
++		],[
++			ZFS_LINUX_TEST_ERROR([bops->release()])
++		])
+ 	])
+ ])
+ 
+@@ -92,6 +122,7 @@ AC_DEFUN([ZFS_AC_KERNEL_BLOCK_DEVICE_OPERATIONS_REVALIDATE_DISK], [
+ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS], [
+ 	ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_CHECK_EVENTS
+ 	ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_RELEASE_VOID
++	ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_RELEASE_1ARG
+ 	ZFS_AC_KERNEL_SRC_BLOCK_DEVICE_OPERATIONS_REVALIDATE_DISK
+ ])
+ 
+diff --git a/include/os/linux/kernel/linux/blkdev_compat.h b/include/os/linux/kernel/linux/blkdev_compat.h
+index 1641dd92a918..f111e648ccf7 100644
+--- a/include/os/linux/kernel/linux/blkdev_compat.h
++++ b/include/os/linux/kernel/linux/blkdev_compat.h
+@@ -398,6 +398,12 @@ vdev_lookup_bdev(const char *path, dev_t *dev)
+ #endif
+ }
+ 
++#if defined(HAVE_BLK_MODE_T)
++#define	blk_mode_is_open_write(flag)	((flag) & BLK_OPEN_WRITE)
++#else
++#define	blk_mode_is_open_write(flag)	((flag) & FMODE_WRITE)
++#endif
++
+ /*
+  * Kernels without bio_set_op_attrs use bi_rw for the bio flags.
+  */
+diff --git a/module/os/linux/zfs/vdev_disk.c b/module/os/linux/zfs/vdev_disk.c
+index 925ee9d9fe9c..48ac55f07034 100644
+--- a/module/os/linux/zfs/vdev_disk.c
++++ b/module/os/linux/zfs/vdev_disk.c
+@@ -80,9 +80,22 @@ typedef struct dio_request {
+ 
+ static unsigned int zfs_vdev_failfast_mask = 1;
+ 
++#ifdef HAVE_BLK_MODE_T
++static blk_mode_t
++#else
+ static fmode_t
++#endif
+ vdev_bdev_mode(spa_mode_t spa_mode)
+ {
++#ifdef HAVE_BLK_MODE_T
++	blk_mode_t mode = 0;
++
++	if (spa_mode & SPA_MODE_READ)
++		mode |= BLK_OPEN_READ;
++
++	if (spa_mode & SPA_MODE_WRITE)
++		mode |= BLK_OPEN_WRITE;
++#else
+ 	fmode_t mode = 0;
+ 
+ 	if (spa_mode & SPA_MODE_READ)
+@@ -90,6 +103,7 @@ vdev_bdev_mode(spa_mode_t spa_mode)
+ 
+ 	if (spa_mode & SPA_MODE_WRITE)
+ 		mode |= FMODE_WRITE;
++#endif
+ 
+ 	return (mode);
+ }
+@@ -197,12 +211,47 @@ vdev_disk_kobj_evt_post(vdev_t *v)
+ 	}
+ }
+ 
++#if !defined(HAVE_BLKDEV_GET_BY_PATH_4ARG)
++/*
++ * Define a dummy struct blk_holder_ops for kernel versions
++ * prior to 6.5.
++ */
++struct blk_holder_ops {};
++#endif
++
++static struct block_device *
++vdev_blkdev_get_by_path(const char *path, spa_mode_t mode, void *holder,
++    const struct blk_holder_ops *hops)
++{
++#ifdef HAVE_BLKDEV_GET_BY_PATH_4ARG
++	return (blkdev_get_by_path(path,
++	    vdev_bdev_mode(mode) | BLK_OPEN_EXCL, holder, hops));
++#else
++	return (blkdev_get_by_path(path,
++	    vdev_bdev_mode(mode) | FMODE_EXCL, holder));
++#endif
++}
++
++static void
++vdev_blkdev_put(struct block_device *bdev, spa_mode_t mode, void *holder)
++{
++#ifdef HAVE_BLKDEV_PUT_HOLDER
++	return (blkdev_put(bdev, holder));
++#else
++	return (blkdev_put(bdev, vdev_bdev_mode(mode) | FMODE_EXCL));
++#endif
++}
++
+ static int
+ vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *max_psize,
+     uint64_t *logical_ashift, uint64_t *physical_ashift)
+ {
+ 	struct block_device *bdev;
++#ifdef HAVE_BLK_MODE_T
++	blk_mode_t mode = vdev_bdev_mode(spa_mode(v->vdev_spa));
++#else
+ 	fmode_t mode = vdev_bdev_mode(spa_mode(v->vdev_spa));
++#endif
+ 	hrtime_t timeout = MSEC2NSEC(zfs_vdev_open_timeout_ms);
+ 	vdev_disk_t *vd;
+ 
+@@ -252,15 +301,15 @@ vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *max_psize,
+ 					reread_part = B_TRUE;
+ 			}
+ 
+-			blkdev_put(bdev, mode | FMODE_EXCL);
++			vdev_blkdev_put(bdev, mode, zfs_vdev_holder);
+ 		}
+ 
+ 		if (reread_part) {
+-			bdev = blkdev_get_by_path(disk_name, mode | FMODE_EXCL,
+-			    zfs_vdev_holder);
++			bdev = vdev_blkdev_get_by_path(disk_name, mode,
++			    zfs_vdev_holder, NULL);
+ 			if (!IS_ERR(bdev)) {
+ 				int error = vdev_bdev_reread_part(bdev);
+-				blkdev_put(bdev, mode | FMODE_EXCL);
++				vdev_blkdev_put(bdev, mode, zfs_vdev_holder);
+ 				if (error == 0) {
+ 					timeout = MSEC2NSEC(
+ 					    zfs_vdev_open_timeout_ms * 2);
+@@ -305,8 +354,8 @@ vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *max_psize,
+ 	hrtime_t start = gethrtime();
+ 	bdev = ERR_PTR(-ENXIO);
+ 	while (IS_ERR(bdev) && ((gethrtime() - start) < timeout)) {
+-		bdev = blkdev_get_by_path(v->vdev_path, mode | FMODE_EXCL,
+-		    zfs_vdev_holder);
++		bdev = vdev_blkdev_get_by_path(v->vdev_path, mode,
++		    zfs_vdev_holder, NULL);
+ 		if (unlikely(PTR_ERR(bdev) == -ENOENT)) {
+ 			/*
+ 			 * There is no point of waiting since device is removed
+@@ -382,8 +431,8 @@ vdev_disk_close(vdev_t *v)
+ 		return;
+ 
+ 	if (vd->vd_bdev != NULL) {
+-		blkdev_put(vd->vd_bdev,
+-		    vdev_bdev_mode(spa_mode(v->vdev_spa)) | FMODE_EXCL);
++		vdev_blkdev_put(vd->vd_bdev, spa_mode(v->vdev_spa),
++		    zfs_vdev_holder);
+ 	}
+ 
+ 	rw_destroy(&vd->vd_lock);
+diff --git a/module/os/linux/zfs/zfs_vnops_os.c b/module/os/linux/zfs/zfs_vnops_os.c
+index 234c4d5ef0e0..33baac9db06b 100644
+--- a/module/os/linux/zfs/zfs_vnops_os.c
++++ b/module/os/linux/zfs/zfs_vnops_os.c
+@@ -186,7 +186,7 @@ zfs_open(struct inode *ip, int mode, int flag, cred_t *cr)
+ 		return (error);
+ 
+ 	/* Honor ZFS_APPENDONLY file attribute */
+-	if ((mode & FMODE_WRITE) && (zp->z_pflags & ZFS_APPENDONLY) &&
++	if (blk_mode_is_open_write(mode) && (zp->z_pflags & ZFS_APPENDONLY) &&
+ 	    ((flag & O_APPEND) == 0)) {
+ 		zfs_exit(zfsvfs, FTAG);
+ 		return (SET_ERROR(EPERM));
+diff --git a/module/os/linux/zfs/zpl_ctldir.c b/module/os/linux/zfs/zpl_ctldir.c
+index 68a7de78f471..7786444fea35 100644
+--- a/module/os/linux/zfs/zpl_ctldir.c
++++ b/module/os/linux/zfs/zpl_ctldir.c
+@@ -42,7 +42,7 @@
+ static int
+ zpl_common_open(struct inode *ip, struct file *filp)
+ {
+-	if (filp->f_mode & FMODE_WRITE)
++	if (blk_mode_is_open_write(filp->f_mode))
+ 		return (-EACCES);
+ 
+ 	return (generic_file_open(ip, filp));
+diff --git a/module/os/linux/zfs/zvol_os.c b/module/os/linux/zfs/zvol_os.c
+index 38bc8e2c4eeb..7a95b54bdf0d 100644
+--- a/module/os/linux/zfs/zvol_os.c
++++ b/module/os/linux/zfs/zvol_os.c
+@@ -671,7 +671,11 @@ zvol_request(struct request_queue *q, struct bio *bio)
+ }
+ 
+ static int
++#ifdef HAVE_BLK_MODE_T
++zvol_open(struct gendisk *disk, blk_mode_t flag)
++#else
+ zvol_open(struct block_device *bdev, fmode_t flag)
++#endif
+ {
+ 	zvol_state_t *zv;
+ 	int error = 0;
+@@ -686,10 +690,14 @@ zvol_open(struct block_device *bdev, fmode_t flag)
+ 	/*
+ 	 * Obtain a copy of private_data under the zvol_state_lock to make
+ 	 * sure that either the result of zvol free code path setting
+-	 * bdev->bd_disk->private_data to NULL is observed, or zvol_os_free()
++	 * disk->private_data to NULL is observed, or zvol_os_free()
+ 	 * is not called on this zv because of the positive zv_open_count.
+ 	 */
++#ifdef HAVE_BLK_MODE_T
++	zv = disk->private_data;
++#else
+ 	zv = bdev->bd_disk->private_data;
++#endif
+ 	if (zv == NULL) {
+ 		rw_exit(&zvol_state_lock);
+ 		return (SET_ERROR(-ENXIO));
+@@ -769,14 +777,15 @@ zvol_open(struct block_device *bdev, fmode_t flag)
+ 			}
+ 		}
+ 
+-		error = -zvol_first_open(zv, !(flag & FMODE_WRITE));
++		error = -zvol_first_open(zv, !(blk_mode_is_open_write(flag)));
+ 
+ 		if (drop_namespace)
+ 			mutex_exit(&spa_namespace_lock);
+ 	}
+ 
+ 	if (error == 0) {
+-		if ((flag & FMODE_WRITE) && (zv->zv_flags & ZVOL_RDONLY)) {
++		if ((blk_mode_is_open_write(flag)) &&
++		    (zv->zv_flags & ZVOL_RDONLY)) {
+ 			if (zv->zv_open_count == 0)
+ 				zvol_last_close(zv);
+ 
+@@ -791,14 +800,25 @@ zvol_open(struct block_device *bdev, fmode_t flag)
+ 		rw_exit(&zv->zv_suspend_lock);
+ 
+ 	if (error == 0)
++#ifdef HAVE_BLK_MODE_T
++		disk_check_media_change(disk);
++#else
+ 		zfs_check_media_change(bdev);
++#endif
+ 
+ 	return (error);
+ }
+ 
+ static void
+-zvol_release(struct gendisk *disk, fmode_t mode)
++#ifdef HAVE_BLOCK_DEVICE_OPERATIONS_RELEASE_1ARG
++zvol_release(struct gendisk *disk)
++#else
++zvol_release(struct gendisk *disk, fmode_t unused)
++#endif
+ {
++#if !defined(HAVE_BLOCK_DEVICE_OPERATIONS_RELEASE_1ARG)
++	(void) unused;
++#endif
+ 	zvol_state_t *zv;
+ 	boolean_t drop_suspend = B_TRUE;
+ 
+From e47e9bbe86f2e8fe5da0fc7c3a9014e1f8c132a9 Mon Sep 17 00:00:00 2001
+From: Coleman Kane <ckane at colemankane.org>
+Date: Wed, 2 Aug 2023 17:05:46 -0400
+Subject: [PATCH] Linux 6.5 compat: register_sysctl_table removed
+
+Additionally, the .child element of ctl_table has been removed in 6.5.
+This change adds a new test for the pre-6.5 register_sysctl_table()
+function, and uses the old code in that case. If it isn't found, then
+the parentage entries in the tables are removed, and the register_sysctl
+call is provided the paths of "kernel/spl", "kernel/spl/kmem", and
+"kernel/spl/kstat" directly, to populate each subdirectory over three
+calls, as is the new API.
+
+Reviewed-by: Brian Atkinson <batkinson at lanl.gov>
+Reviewed-by: Brian Behlendorf <behlendorf1 at llnl.gov>
+Signed-off-by: Coleman Kane <ckane at colemankane.org>
+Closes #15138
+---
+ config/kernel-register_sysctl_table.m4 | 27 ++++++++++++++++++++++++++
+ config/kernel.m4                       |  2 ++
+ module/os/linux/spl/spl-proc.c         | 26 ++++++++++++++++++++++---
+ 3 files changed, 52 insertions(+), 3 deletions(-)
+ create mode 100644 config/kernel-register_sysctl_table.m4
+
+diff --git a/config/kernel-register_sysctl_table.m4 b/config/kernel-register_sysctl_table.m4
+new file mode 100644
+index 000000000000..a5e934f56d29
+--- /dev/null
++++ b/config/kernel-register_sysctl_table.m4
+@@ -0,0 +1,27 @@
++dnl #
++dnl # Linux 6.5 removes register_sysctl_table
++dnl #
++AC_DEFUN([ZFS_AC_KERNEL_SRC_REGISTER_SYSCTL_TABLE], [
++	ZFS_LINUX_TEST_SRC([has_register_sysctl_table], [
++		#include <linux/sysctl.h>
++
++		static struct ctl_table dummy_table[] = {
++			{}
++		};
++
++    ],[
++		struct ctl_table_header *h
++			__attribute((unused)) = register_sysctl_table(dummy_table);
++    ])
++])
++
++AC_DEFUN([ZFS_AC_KERNEL_REGISTER_SYSCTL_TABLE], [
++	AC_MSG_CHECKING([whether register_sysctl_table exists])
++	ZFS_LINUX_TEST_RESULT([has_register_sysctl_table], [
++		AC_MSG_RESULT([yes])
++		AC_DEFINE(HAVE_REGISTER_SYSCTL_TABLE, 1,
++			[register_sysctl_table exists])
++	],[
++		AC_MSG_RESULT([no])
++	])
++])
+diff --git a/config/kernel.m4 b/config/kernel.m4
+index 1487fa2e7793..28bd361d33ff 100644
+--- a/config/kernel.m4
++++ b/config/kernel.m4
+@@ -160,6 +160,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
+ 	ZFS_AC_KERNEL_SRC_FILEMAP
+ 	ZFS_AC_KERNEL_SRC_WRITEPAGE_T
+ 	ZFS_AC_KERNEL_SRC_RECLAIMED
++	ZFS_AC_KERNEL_SRC_REGISTER_SYSCTL_TABLE
+ 	case "$host_cpu" in
+ 		powerpc*)
+ 			ZFS_AC_KERNEL_SRC_CPU_HAS_FEATURE
+@@ -299,6 +300,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
+ 	ZFS_AC_KERNEL_FILEMAP
+ 	ZFS_AC_KERNEL_WRITEPAGE_T
+ 	ZFS_AC_KERNEL_RECLAIMED
++	ZFS_AC_KERNEL_REGISTER_SYSCTL_TABLE
+ 	case "$host_cpu" in
+ 		powerpc*)
+ 			ZFS_AC_KERNEL_CPU_HAS_FEATURE
+diff --git a/module/os/linux/spl/spl-proc.c b/module/os/linux/spl/spl-proc.c
+index 01f5619e1893..bcc356ae55b6 100644
+--- a/module/os/linux/spl/spl-proc.c
++++ b/module/os/linux/spl/spl-proc.c
+@@ -624,6 +624,7 @@ static struct ctl_table spl_table[] = {
+ 		.mode		= 0644,
+ 		.proc_handler	= &proc_dohostid,
+ 	},
++#ifdef HAVE_REGISTER_SYSCTL_TABLE
+ 	{
+ 		.procname	= "kmem",
+ 		.mode		= 0555,
+@@ -634,9 +635,11 @@ static struct ctl_table spl_table[] = {
+ 		.mode		= 0555,
+ 		.child		= spl_kstat_table,
+ 	},
++#endif
+ 	{},
+ };
+ 
++#ifdef HAVE_REGISTER_SYSCTL_TABLE
+ static struct ctl_table spl_dir[] = {
+ 	{
+ 		.procname	= "spl",
+@@ -648,21 +651,38 @@ static struct ctl_table spl_dir[] = {
+ 
+ static struct ctl_table spl_root[] = {
+ 	{
+-	.procname = "kernel",
+-	.mode = 0555,
+-	.child = spl_dir,
++		.procname	= "kernel",
++		.mode		= 0555,
++		.child		= spl_dir,
+ 	},
+ 	{}
+ };
++#endif
+ 
+ int
+ spl_proc_init(void)
+ {
+ 	int rc = 0;
+ 
++#ifdef HAVE_REGISTER_SYSCTL_TABLE
+ 	spl_header = register_sysctl_table(spl_root);
+ 	if (spl_header == NULL)
+ 		return (-EUNATCH);
++#else
++	spl_header = register_sysctl("kernel/spl", spl_table);
++	if (spl_header == NULL)
++		return (-EUNATCH);
++
++	if (register_sysctl("kernel/spl/kmem", spl_kmem_table) == NULL) {
++		rc = -EUNATCH;
++		goto out;
++	}
++
++	if (register_sysctl("kernel/spl/kstat", spl_kstat_table) == NULL) {
++		rc = -EUNATCH;
++		goto out;
++	}
++#endif
+ 
+ 	proc_spl = proc_mkdir("spl", NULL);
+ 	if (proc_spl == NULL) {
+From 36261c8238df462b214854ccea1df4f060cf0995 Mon Sep 17 00:00:00 2001
+From: Coleman Kane <ckane at colemankane.org>
+Date: Mon, 7 Aug 2023 18:47:46 -0400
+Subject: [PATCH] Linux 6.5 compat: replace generic_file_splice_read with
+ filemap_splice_read
+
+The generic_file_splice_read function was removed in Linux 6.5 in favor
+of filemap_splice_read. Add an autoconf test for filemap_splice_read and
+use it if it is found as the handler for .splice_read in the
+file_operations struct. Additionally, ITER_PIPE was removed in 6.5. This
+change removes the ITER_* macros that OpenZFS doesn't use from being
+tested in config/kernel-vfs-iov_iter.m4. The removal of ITER_PIPE was
+causing the test to fail, which also affected the code responsible for
+setting the .splice_read handler, above. That behavior caused run-time
+panics on Linux 6.5.
+
+Reviewed-by: Brian Atkinson <batkinson at lanl.gov>
+Reviewed-by: Brian Behlendorf <behlendorf1 at llnl.gov>
+Signed-off-by: Coleman Kane <ckane at colemankane.org>
+Closes #15155
+---
+ config/kernel-filemap-splice-read.m4 | 25 +++++++++++++++++++++++++
+ config/kernel-vfs-iov_iter.m4        |  3 +--
+ config/kernel.m4                     |  2 ++
+ module/os/linux/zfs/zpl_file.c       |  4 ++++
+ 4 files changed, 32 insertions(+), 2 deletions(-)
+ create mode 100644 config/kernel-filemap-splice-read.m4
+
+diff --git a/config/kernel-filemap-splice-read.m4 b/config/kernel-filemap-splice-read.m4
+new file mode 100644
+index 000000000000..5199b7373e4d
+--- /dev/null
++++ b/config/kernel-filemap-splice-read.m4
+@@ -0,0 +1,25 @@
++AC_DEFUN([ZFS_AC_KERNEL_SRC_FILEMAP_SPLICE_READ], [
++	dnl #
++	dnl # Kernel 6.5 - generic_file_splice_read was removed in favor
++	dnl # of filemap_splice_read for the .splice_read member of the
++	dnl # file_operations struct.
++	dnl #
++	ZFS_LINUX_TEST_SRC([has_filemap_splice_read], [
++		#include <linux/fs.h>
++
++		struct file_operations fops __attribute__((unused)) = {
++			.splice_read = filemap_splice_read,
++		};
++	],[])
++])
++
++AC_DEFUN([ZFS_AC_KERNEL_FILEMAP_SPLICE_READ], [
++	AC_MSG_CHECKING([whether filemap_splice_read() exists])
++	ZFS_LINUX_TEST_RESULT([has_filemap_splice_read], [
++		AC_MSG_RESULT(yes)
++		AC_DEFINE(HAVE_FILEMAP_SPLICE_READ, 1,
++		    [filemap_splice_read exists])
++	],[
++		AC_MSG_RESULT(no)
++	])
++])
+diff --git a/config/kernel-vfs-iov_iter.m4 b/config/kernel-vfs-iov_iter.m4
+index cc5a7ab0c237..ff560ff3eef0 100644
+--- a/config/kernel-vfs-iov_iter.m4
++++ b/config/kernel-vfs-iov_iter.m4
+@@ -6,8 +6,7 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_VFS_IOV_ITER], [
+ 		#include <linux/fs.h>
+ 		#include <linux/uio.h>
+ 	],[
+-		int type __attribute__ ((unused)) =
+-		    ITER_IOVEC | ITER_KVEC | ITER_BVEC | ITER_PIPE;
++		int type __attribute__ ((unused)) = ITER_KVEC;
+ 	])
+ 
+ 	ZFS_LINUX_TEST_SRC([iov_iter_advance], [
+diff --git a/config/kernel.m4 b/config/kernel.m4
+index 28bd361d33ff..309f1819be48 100644
+--- a/config/kernel.m4
++++ b/config/kernel.m4
+@@ -161,6 +161,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
+ 	ZFS_AC_KERNEL_SRC_WRITEPAGE_T
+ 	ZFS_AC_KERNEL_SRC_RECLAIMED
+ 	ZFS_AC_KERNEL_SRC_REGISTER_SYSCTL_TABLE
++	ZFS_AC_KERNEL_SRC_FILEMAP_SPLICE_READ
+ 	case "$host_cpu" in
+ 		powerpc*)
+ 			ZFS_AC_KERNEL_SRC_CPU_HAS_FEATURE
+@@ -301,6 +302,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
+ 	ZFS_AC_KERNEL_WRITEPAGE_T
+ 	ZFS_AC_KERNEL_RECLAIMED
+ 	ZFS_AC_KERNEL_REGISTER_SYSCTL_TABLE
++	ZFS_AC_KERNEL_FILEMAP_SPLICE_READ
+ 	case "$host_cpu" in
+ 		powerpc*)
+ 			ZFS_AC_KERNEL_CPU_HAS_FEATURE
+diff --git a/module/os/linux/zfs/zpl_file.c b/module/os/linux/zfs/zpl_file.c
+index f6af2ebd1163..24cc1064a8fc 100644
+--- a/module/os/linux/zfs/zpl_file.c
++++ b/module/os/linux/zfs/zpl_file.c
+@@ -1323,7 +1323,11 @@ const struct file_operations zpl_file_operations = {
+ 	.read_iter	= zpl_iter_read,
+ 	.write_iter	= zpl_iter_write,
+ #ifdef HAVE_VFS_IOV_ITER
++#ifdef HAVE_FILEMAP_SPLICE_READ
++	.splice_read	= filemap_splice_read,
++#else
+ 	.splice_read	= generic_file_splice_read,
++#endif
+ 	.splice_write	= iter_file_splice_write,
+ #endif
+ #else
+From 8ce2eba9e6a384feef93d77c397f37d17dc588ce Mon Sep 17 00:00:00 2001
+From: Coleman Kane <ckane at colemankane.org>
+Date: Tue, 8 Aug 2023 18:42:32 -0400
+Subject: [PATCH] Linux 6.5 compat: Use copy_splice_read instead of
+ filemap_splice_read
+
+Using the filemap_splice_read function for the splice_read handler was
+leading to occasional data corruption under certain circumstances. Favor
+using copy_splice_read instead, which does not demonstrate the same
+erroneous behavior under the tested failure cases.
+
+Reviewed-by: Brian Atkinson <batkinson at lanl.gov>
+Reviewed-by: Brian Behlendorf <behlendorf1 at llnl.gov>
+Signed-off-by: Coleman Kane <ckane at colemankane.org>
+Closes #15164
+---
+ config/kernel-filemap-splice-read.m4 | 18 +++++++++---------
+ config/kernel.m4                     |  4 ++--
+ module/os/linux/zfs/zpl_file.c       |  4 ++--
+ 3 files changed, 13 insertions(+), 13 deletions(-)
+
+diff --git a/config/kernel-filemap-splice-read.m4 b/config/kernel-filemap-splice-read.m4
+index 5199b7373e4d..4c83b31d738a 100644
+--- a/config/kernel-filemap-splice-read.m4
++++ b/config/kernel-filemap-splice-read.m4
+@@ -1,24 +1,24 @@
+-AC_DEFUN([ZFS_AC_KERNEL_SRC_FILEMAP_SPLICE_READ], [
++AC_DEFUN([ZFS_AC_KERNEL_SRC_COPY_SPLICE_READ], [
+ 	dnl #
+ 	dnl # Kernel 6.5 - generic_file_splice_read was removed in favor
+-	dnl # of filemap_splice_read for the .splice_read member of the
++	dnl # of copy_splice_read for the .splice_read member of the
+ 	dnl # file_operations struct.
+ 	dnl #
+-	ZFS_LINUX_TEST_SRC([has_filemap_splice_read], [
++	ZFS_LINUX_TEST_SRC([has_copy_splice_read], [
+ 		#include <linux/fs.h>
+ 
+ 		struct file_operations fops __attribute__((unused)) = {
+-			.splice_read = filemap_splice_read,
++			.splice_read = copy_splice_read,
+ 		};
+ 	],[])
+ ])
+ 
+-AC_DEFUN([ZFS_AC_KERNEL_FILEMAP_SPLICE_READ], [
+-	AC_MSG_CHECKING([whether filemap_splice_read() exists])
+-	ZFS_LINUX_TEST_RESULT([has_filemap_splice_read], [
++AC_DEFUN([ZFS_AC_KERNEL_COPY_SPLICE_READ], [
++	AC_MSG_CHECKING([whether copy_splice_read() exists])
++	ZFS_LINUX_TEST_RESULT([has_copy_splice_read], [
+ 		AC_MSG_RESULT(yes)
+-		AC_DEFINE(HAVE_FILEMAP_SPLICE_READ, 1,
+-		    [filemap_splice_read exists])
++		AC_DEFINE(HAVE_COPY_SPLICE_READ, 1,
++		    [copy_splice_read exists])
+ 	],[
+ 		AC_MSG_RESULT(no)
+ 	])
+diff --git a/config/kernel.m4 b/config/kernel.m4
+index 309f1819be48..df194ec72207 100644
+--- a/config/kernel.m4
++++ b/config/kernel.m4
+@@ -161,7 +161,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
+ 	ZFS_AC_KERNEL_SRC_WRITEPAGE_T
+ 	ZFS_AC_KERNEL_SRC_RECLAIMED
+ 	ZFS_AC_KERNEL_SRC_REGISTER_SYSCTL_TABLE
+-	ZFS_AC_KERNEL_SRC_FILEMAP_SPLICE_READ
++	ZFS_AC_KERNEL_SRC_COPY_SPLICE_READ
+ 	case "$host_cpu" in
+ 		powerpc*)
+ 			ZFS_AC_KERNEL_SRC_CPU_HAS_FEATURE
+@@ -302,7 +302,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
+ 	ZFS_AC_KERNEL_WRITEPAGE_T
+ 	ZFS_AC_KERNEL_RECLAIMED
+ 	ZFS_AC_KERNEL_REGISTER_SYSCTL_TABLE
+-	ZFS_AC_KERNEL_FILEMAP_SPLICE_READ
++	ZFS_AC_KERNEL_COPY_SPLICE_READ
+ 	case "$host_cpu" in
+ 		powerpc*)
+ 			ZFS_AC_KERNEL_CPU_HAS_FEATURE
+diff --git a/module/os/linux/zfs/zpl_file.c b/module/os/linux/zfs/zpl_file.c
+index 24cc1064a8fc..3caa0fc6c214 100644
+--- a/module/os/linux/zfs/zpl_file.c
++++ b/module/os/linux/zfs/zpl_file.c
+@@ -1323,8 +1323,8 @@ const struct file_operations zpl_file_operations = {
+ 	.read_iter	= zpl_iter_read,
+ 	.write_iter	= zpl_iter_write,
+ #ifdef HAVE_VFS_IOV_ITER
+-#ifdef HAVE_FILEMAP_SPLICE_READ
+-	.splice_read	= filemap_splice_read,
++#ifdef HAVE_COPY_SPLICE_READ
++	.splice_read	= copy_splice_read,
+ #else
+ 	.splice_read	= generic_file_splice_read,
+ #endif
+From bcb1159c095f57564914b59f5e7e82170261afb0 Mon Sep 17 00:00:00 2001
+From: Andrea Righi <andrea.righi at canonical.com>
+Date: Sat, 2 Sep 2023 02:21:40 +0200
+Subject: [PATCH] Linux 6.5 compat: safe cleanup in spl_proc_fini()
+
+If we fail to create a proc entry in spl_proc_init() we may end up
+calling unregister_sysctl_table() twice: one in the failure path of
+spl_proc_init() and another time during spl_proc_fini().
+
+Avoid the double call to unregister_sysctl_table() and while at it
+refactor the code a bit to reduce code duplication.
+
+This was accidentally introduced when the spl code was
+updated for Linux 6.5 compatibility.
+
+Reviewed-by: Brian Behlendorf <behlendorf1 at llnl.gov>
+Reviewed-by: Ameer Hamza <ahamza at ixsystems.com>
+Signed-off-by: Andrea Righi <andrea.righi at canonical.com>
+Closes #15234
+Closes #15235
+---
+ module/os/linux/spl/spl-proc.c | 36 +++++++++++++++++-----------------
+ 1 file changed, 18 insertions(+), 18 deletions(-)
+
+diff --git a/module/os/linux/spl/spl-proc.c b/module/os/linux/spl/spl-proc.c
+index bcc356ae55b6..5cb5a6dadb05 100644
+--- a/module/os/linux/spl/spl-proc.c
++++ b/module/os/linux/spl/spl-proc.c
+@@ -659,6 +659,21 @@ static struct ctl_table spl_root[] = {
+ };
+ #endif
+ 
++static void spl_proc_cleanup(void)
++{
++	remove_proc_entry("kstat", proc_spl);
++	remove_proc_entry("slab", proc_spl_kmem);
++	remove_proc_entry("kmem", proc_spl);
++	remove_proc_entry("taskq-all", proc_spl);
++	remove_proc_entry("taskq", proc_spl);
++	remove_proc_entry("spl", NULL);
++
++	if (spl_header) {
++		unregister_sysctl_table(spl_header);
++		spl_header = NULL;
++	}
++}
++
+ int
+ spl_proc_init(void)
+ {
+@@ -723,15 +738,8 @@ spl_proc_init(void)
+ 		goto out;
+ 	}
+ out:
+-	if (rc) {
+-		remove_proc_entry("kstat", proc_spl);
+-		remove_proc_entry("slab", proc_spl_kmem);
+-		remove_proc_entry("kmem", proc_spl);
+-		remove_proc_entry("taskq-all", proc_spl);
+-		remove_proc_entry("taskq", proc_spl);
+-		remove_proc_entry("spl", NULL);
+-		unregister_sysctl_table(spl_header);
+-	}
++	if (rc)
++		spl_proc_cleanup();
+ 
+ 	return (rc);
+ }
+@@ -739,13 +747,5 @@ spl_proc_init(void)
+ void
+ spl_proc_fini(void)
+ {
+-	remove_proc_entry("kstat", proc_spl);
+-	remove_proc_entry("slab", proc_spl_kmem);
+-	remove_proc_entry("kmem", proc_spl);
+-	remove_proc_entry("taskq-all", proc_spl);
+-	remove_proc_entry("taskq", proc_spl);
+-	remove_proc_entry("spl", NULL);
+-
+-	ASSERT(spl_header != NULL);
+-	unregister_sysctl_table(spl_header);
++	spl_proc_cleanup();
+ }
diff --git a/no-Werror.patch b/no-Werror.patch
deleted file mode 100644
index 1d0f326..0000000
--- a/no-Werror.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- zfs-2.1.5/config/kernel.m4~	2022-06-22 18:55:53.000000000 +0200
-+++ zfs-2.1.5/config/kernel.m4	2022-09-24 08:10:59.050219049 +0200
-@@ -581,7 +581,7 @@
- # Example command line to manually build source
- # make modules -C $LINUX_OBJ $ARCH_UM M=$PWD/build/$1
- 
--ccflags-y := -Werror $FRAME_LARGER_THAN
-+ccflags-y := $FRAME_LARGER_THAN
- _ACEOF
- 
- 	dnl # Additional custom CFLAGS as requested.
diff --git a/staging.patch b/staging.patch
deleted file mode 100644
index c6131ed..0000000
--- a/staging.patch
+++ /dev/null
@@ -1,5955 +0,0 @@
-diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c
-index f424dd771..bcd520de3 100644
---- a/cmd/zdb/zdb.c
-+++ b/cmd/zdb/zdb.c
-@@ -3102,13 +3102,22 @@ dump_znode_sa_xattr(sa_handle_t *hdl)
- 	(void) printf("\tSA xattrs: %d bytes, %d entries\n\n",
- 	    sa_xattr_size, sa_xattr_entries);
- 	while ((elem = nvlist_next_nvpair(sa_xattr, elem)) != NULL) {
-+		boolean_t can_print = !dump_opt['P'];
- 		uchar_t *value;
- 		uint_t cnt, idx;
- 
- 		(void) printf("\t\t%s = ", nvpair_name(elem));
- 		nvpair_value_byte_array(elem, &value, &cnt);
-+
-+		for (idx = 0; idx < cnt; ++idx) {
-+			if (!isprint(value[idx])) {
-+				can_print = B_FALSE;
-+				break;
-+			}
-+		}
-+
- 		for (idx = 0; idx < cnt; ++idx) {
--			if (isprint(value[idx]))
-+			if (can_print)
- 				(void) putchar(value[idx]);
- 			else
- 				(void) printf("\\%3.3o", value[idx]);
-diff --git a/cmd/zed/agents/zfs_retire.c b/cmd/zed/agents/zfs_retire.c
-index b4794e311..29eaee750 100644
---- a/cmd/zed/agents/zfs_retire.c
-+++ b/cmd/zed/agents/zfs_retire.c
-@@ -444,14 +444,16 @@ zfs_retire_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl,
- 			return;
- 
- 		/* Remove the vdev since device is unplugged */
-+		int remove_status = 0;
- 		if (l2arc || (strcmp(class, "resource.fs.zfs.removed") == 0)) {
--			int status = zpool_vdev_remove_wanted(zhp, devname);
-+			remove_status = zpool_vdev_remove_wanted(zhp, devname);
- 			fmd_hdl_debug(hdl, "zpool_vdev_remove_wanted '%s'"
--			    ", ret:%d", devname, status);
-+			    ", err:%d", devname, libzfs_errno(zhdl));
- 		}
- 
- 		/* Replace the vdev with a spare if its not a l2arc */
--		if (!l2arc && (!fmd_prop_get_int32(hdl, "spare_on_remove") ||
-+		if (!l2arc && !remove_status &&
-+		    (!fmd_prop_get_int32(hdl, "spare_on_remove") ||
- 		    replace_with_spare(hdl, zhp, vdev) == B_FALSE)) {
- 			/* Could not handle with spare */
- 			fmd_hdl_debug(hdl, "no spare for '%s'", devname);
-diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c
-index 2311d4f04..a06af9aec 100644
---- a/cmd/zpool/zpool_main.c
-+++ b/cmd/zpool/zpool_main.c
-@@ -392,7 +392,7 @@ get_usage(zpool_help_t idx)
- 	case HELP_REOPEN:
- 		return (gettext("\treopen [-n] <pool>\n"));
- 	case HELP_INITIALIZE:
--		return (gettext("\tinitialize [-c | -s] [-w] <pool> "
-+		return (gettext("\tinitialize [-c | -s | -u] [-w] <pool> "
- 		    "[<device> ...]\n"));
- 	case HELP_SCRUB:
- 		return (gettext("\tscrub [-s | -p] [-w] <pool> ...\n"));
-@@ -548,12 +548,13 @@ usage(boolean_t requested)
- }
- 
- /*
-- * zpool initialize [-c | -s] [-w] <pool> [<vdev> ...]
-+ * zpool initialize [-c | -s | -u] [-w] <pool> [<vdev> ...]
-  * Initialize all unused blocks in the specified vdevs, or all vdevs in the pool
-  * if none specified.
-  *
-  *	-c	Cancel. Ends active initializing.
-  *	-s	Suspend. Initializing can then be restarted with no flags.
-+ *	-u	Uninitialize. Clears initialization state.
-  *	-w	Wait. Blocks until initializing has completed.
-  */
- int
-@@ -569,12 +570,14 @@ zpool_do_initialize(int argc, char **argv)
- 	struct option long_options[] = {
- 		{"cancel",	no_argument,		NULL, 'c'},
- 		{"suspend",	no_argument,		NULL, 's'},
-+		{"uninit",	no_argument,		NULL, 'u'},
- 		{"wait",	no_argument,		NULL, 'w'},
- 		{0, 0, 0, 0}
- 	};
- 
- 	pool_initialize_func_t cmd_type = POOL_INITIALIZE_START;
--	while ((c = getopt_long(argc, argv, "csw", long_options, NULL)) != -1) {
-+	while ((c = getopt_long(argc, argv, "csuw", long_options,
-+	    NULL)) != -1) {
- 		switch (c) {
- 		case 'c':
- 			if (cmd_type != POOL_INITIALIZE_START &&
-@@ -594,6 +597,15 @@ zpool_do_initialize(int argc, char **argv)
- 			}
- 			cmd_type = POOL_INITIALIZE_SUSPEND;
- 			break;
-+		case 'u':
-+			if (cmd_type != POOL_INITIALIZE_START &&
-+			    cmd_type != POOL_INITIALIZE_UNINIT) {
-+				(void) fprintf(stderr, gettext("-u cannot be "
-+				    "combined with other options\n"));
-+				usage(B_FALSE);
-+			}
-+			cmd_type = POOL_INITIALIZE_UNINIT;
-+			break;
- 		case 'w':
- 			wait = B_TRUE;
- 			break;
-@@ -620,8 +632,8 @@ zpool_do_initialize(int argc, char **argv)
- 	}
- 
- 	if (wait && (cmd_type != POOL_INITIALIZE_START)) {
--		(void) fprintf(stderr, gettext("-w cannot be used with -c or "
--		    "-s\n"));
-+		(void) fprintf(stderr, gettext("-w cannot be used with -c, -s"
-+		    "or -u\n"));
- 		usage(B_FALSE);
- 	}
- 
-@@ -6921,6 +6933,17 @@ zpool_do_online(int argc, char **argv)
- 		return (1);
- 
- 	for (i = 1; i < argc; i++) {
-+		vdev_state_t oldstate;
-+		boolean_t avail_spare, l2cache;
-+		nvlist_t *tgt = zpool_find_vdev(zhp, argv[i], &avail_spare,
-+		    &l2cache, NULL);
-+		if (tgt == NULL) {
-+			ret = 1;
-+			continue;
-+		}
-+		uint_t vsc;
-+		oldstate = ((vdev_stat_t *)fnvlist_lookup_uint64_array(tgt,
-+		    ZPOOL_CONFIG_VDEV_STATS, &vsc))->vs_state;
- 		if (zpool_vdev_online(zhp, argv[i], flags, &newstate) == 0) {
- 			if (newstate != VDEV_STATE_HEALTHY) {
- 				(void) printf(gettext("warning: device '%s' "
-@@ -6934,6 +6957,17 @@ zpool_do_online(int argc, char **argv)
- 					(void) printf(gettext("use 'zpool "
- 					    "replace' to replace devices "
- 					    "that are no longer present\n"));
-+				if ((flags & ZFS_ONLINE_EXPAND)) {
-+					(void) printf(gettext("%s: failed "
-+					    "to expand usable space on "
-+					    "unhealthy device '%s'\n"),
-+					    (oldstate >= VDEV_STATE_DEGRADED ?
-+					    "error" : "warning"), argv[i]);
-+					if (oldstate >= VDEV_STATE_DEGRADED) {
-+						ret = 1;
-+						break;
-+					}
-+				}
- 			}
- 		} else {
- 			ret = 1;
-@@ -7549,19 +7583,20 @@ print_scan_scrub_resilver_status(pool_scan_stat_t *ps)
- 
- 	zfs_nicebytes(ps->pss_processed, processed_buf, sizeof (processed_buf));
- 
--	assert(ps->pss_func == POOL_SCAN_SCRUB ||
--	    ps->pss_func == POOL_SCAN_RESILVER);
-+	int is_resilver = ps->pss_func == POOL_SCAN_RESILVER;
-+	int is_scrub = ps->pss_func == POOL_SCAN_SCRUB;
-+	assert(is_resilver || is_scrub);
- 
- 	/* Scan is finished or canceled. */
- 	if (ps->pss_state == DSS_FINISHED) {
- 		secs_to_dhms(end - start, time_buf);
- 
--		if (ps->pss_func == POOL_SCAN_SCRUB) {
-+		if (is_scrub) {
- 			(void) printf(gettext("scrub repaired %s "
- 			    "in %s with %llu errors on %s"), processed_buf,
- 			    time_buf, (u_longlong_t)ps->pss_errors,
- 			    ctime(&end));
--		} else if (ps->pss_func == POOL_SCAN_RESILVER) {
-+		} else if (is_resilver) {
- 			(void) printf(gettext("resilvered %s "
- 			    "in %s with %llu errors on %s"), processed_buf,
- 			    time_buf, (u_longlong_t)ps->pss_errors,
-@@ -7569,10 +7604,10 @@ print_scan_scrub_resilver_status(pool_scan_stat_t *ps)
- 		}
- 		return;
- 	} else if (ps->pss_state == DSS_CANCELED) {
--		if (ps->pss_func == POOL_SCAN_SCRUB) {
-+		if (is_scrub) {
- 			(void) printf(gettext("scrub canceled on %s"),
- 			    ctime(&end));
--		} else if (ps->pss_func == POOL_SCAN_RESILVER) {
-+		} else if (is_resilver) {
- 			(void) printf(gettext("resilver canceled on %s"),
- 			    ctime(&end));
- 		}
-@@ -7582,7 +7617,7 @@ print_scan_scrub_resilver_status(pool_scan_stat_t *ps)
- 	assert(ps->pss_state == DSS_SCANNING);
- 
- 	/* Scan is in progress. Resilvers can't be paused. */
--	if (ps->pss_func == POOL_SCAN_SCRUB) {
-+	if (is_scrub) {
- 		if (pause == 0) {
- 			(void) printf(gettext("scrub in progress since %s"),
- 			    ctime(&start));
-@@ -7592,7 +7627,7 @@ print_scan_scrub_resilver_status(pool_scan_stat_t *ps)
- 			(void) printf(gettext("\tscrub started on %s"),
- 			    ctime(&start));
- 		}
--	} else if (ps->pss_func == POOL_SCAN_RESILVER) {
-+	} else if (is_resilver) {
- 		(void) printf(gettext("resilver in progress since %s"),
- 		    ctime(&start));
- 	}
-@@ -7634,17 +7669,27 @@ print_scan_scrub_resilver_status(pool_scan_stat_t *ps)
- 		    scanned_buf, issued_buf, total_buf);
- 	}
- 
--	if (ps->pss_func == POOL_SCAN_RESILVER) {
-+	if (is_resilver) {
- 		(void) printf(gettext("\t%s resilvered, %.2f%% done"),
- 		    processed_buf, 100 * fraction_done);
--	} else if (ps->pss_func == POOL_SCAN_SCRUB) {
-+	} else if (is_scrub) {
- 		(void) printf(gettext("\t%s repaired, %.2f%% done"),
- 		    processed_buf, 100 * fraction_done);
- 	}
- 
- 	if (pause == 0) {
-+		/*
-+		 * Only provide an estimate iff:
-+		 * 1) the time remaining is valid, and
-+		 * 2) the issue rate exceeds 10 MB/s, and
-+		 * 3) it's either:
-+		 *    a) a resilver which has started repairs, or
-+		 *    b) a scrub which has entered the issue phase.
-+		 */
- 		if (total_secs_left != UINT64_MAX &&
--		    issue_rate >= 10 * 1024 * 1024) {
-+		    issue_rate >= 10 * 1024 * 1024 &&
-+		    ((is_resilver && ps->pss_processed > 0) ||
-+		    (is_scrub && issued > 0))) {
- 			(void) printf(gettext(", %s to go\n"), time_buf);
- 		} else {
- 			(void) printf(gettext(", no estimated "
-diff --git a/config/always-compiler-options.m4 b/config/always-compiler-options.m4
-index 5046ce0dd..0f66db584 100644
---- a/config/always-compiler-options.m4
-+++ b/config/always-compiler-options.m4
-@@ -221,3 +221,34 @@ AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_CC_NO_IPA_SRA], [
- 	CFLAGS="$saved_flags"
- 	AC_SUBST([NO_IPA_SRA])
- ])
-+
-+dnl #
-+dnl # Check if kernel cc supports -fno-ipa-sra option.
-+dnl #
-+AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_KERNEL_CC_NO_IPA_SRA], [
-+	AC_MSG_CHECKING([whether $KERNEL_CC supports -fno-ipa-sra])
-+
-+	saved_cc="$CC"
-+	saved_flags="$CFLAGS"
-+	CC="gcc"
-+	CFLAGS="$CFLAGS -Werror -fno-ipa-sra"
-+
-+	AS_IF([ test -n "$KERNEL_CC" ], [
-+		CC="$KERNEL_CC"
-+	])
-+	AS_IF([ test -n "$KERNEL_LLVM" ], [
-+		CC="clang"
-+	])
-+
-+	AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [])], [
-+		KERNEL_NO_IPA_SRA=-fno-ipa-sra
-+		AC_MSG_RESULT([yes])
-+	], [
-+		KERNEL_NO_IPA_SRA=
-+		AC_MSG_RESULT([no])
-+	])
-+
-+	CC="$saved_cc"
-+	CFLAGS="$saved_flags"
-+	AC_SUBST([KERNEL_NO_IPA_SRA])
-+])
-diff --git a/config/kernel-acl.m4 b/config/kernel-acl.m4
-index 6e92da97d..be08c3c60 100644
---- a/config/kernel-acl.m4
-+++ b/config/kernel-acl.m4
-@@ -236,7 +236,22 @@ dnl #
- dnl # 6.2 API change,
- dnl # set_acl() second paramter changed to a struct dentry *
- dnl #
-+dnl # 6.3 API change,
-+dnl # set_acl() first parameter changed to struct mnt_idmap *
-+dnl #
- AC_DEFUN([ZFS_AC_KERNEL_SRC_INODE_OPERATIONS_SET_ACL], [
-+	ZFS_LINUX_TEST_SRC([inode_operations_set_acl_mnt_idmap_dentry], [
-+		#include <linux/fs.h>
-+
-+		int set_acl_fn(struct mnt_idmap *idmap,
-+		    struct dentry *dent, struct posix_acl *acl,
-+		    int type) { return 0; }
-+
-+		static const struct inode_operations
-+		    iops __attribute__ ((unused)) = {
-+			.set_acl = set_acl_fn,
-+		};
-+	],[])
- 	ZFS_LINUX_TEST_SRC([inode_operations_set_acl_userns_dentry], [
- 		#include <linux/fs.h>
- 
-@@ -281,17 +296,24 @@ AC_DEFUN([ZFS_AC_KERNEL_INODE_OPERATIONS_SET_ACL], [
- 		AC_DEFINE(HAVE_SET_ACL, 1, [iops->set_acl() exists])
- 		AC_DEFINE(HAVE_SET_ACL_USERNS, 1, [iops->set_acl() takes 4 args])
- 	],[
--		ZFS_LINUX_TEST_RESULT([inode_operations_set_acl_userns_dentry], [
-+		ZFS_LINUX_TEST_RESULT([inode_operations_set_acl_mnt_idmap_dentry], [
- 			AC_MSG_RESULT(yes)
- 			AC_DEFINE(HAVE_SET_ACL, 1, [iops->set_acl() exists])
--			AC_DEFINE(HAVE_SET_ACL_USERNS_DENTRY_ARG2, 1,
--			    [iops->set_acl() takes 4 args, arg2 is struct dentry *])
-+			AC_DEFINE(HAVE_SET_ACL_IDMAP_DENTRY, 1,
-+			    [iops->set_acl() takes 4 args, arg1 is struct mnt_idmap *])
- 		],[
--			ZFS_LINUX_TEST_RESULT([inode_operations_set_acl], [
-+			ZFS_LINUX_TEST_RESULT([inode_operations_set_acl_userns_dentry], [
- 				AC_MSG_RESULT(yes)
--				AC_DEFINE(HAVE_SET_ACL, 1, [iops->set_acl() exists, takes 3 args])
-+				AC_DEFINE(HAVE_SET_ACL, 1, [iops->set_acl() exists])
-+				AC_DEFINE(HAVE_SET_ACL_USERNS_DENTRY_ARG2, 1,
-+				    [iops->set_acl() takes 4 args, arg2 is struct dentry *])
- 			],[
--				ZFS_LINUX_REQUIRE_API([i_op->set_acl()], [3.14])
-+				ZFS_LINUX_TEST_RESULT([inode_operations_set_acl], [
-+					AC_MSG_RESULT(yes)
-+					AC_DEFINE(HAVE_SET_ACL, 1, [iops->set_acl() exists, takes 3 args])
-+				],[
-+					ZFS_LINUX_REQUIRE_API([i_op->set_acl()], [3.14])
-+				])
- 			])
- 		])
- 	])
-diff --git a/config/kernel-cpu_has_feature.m4 b/config/kernel-cpu_has_feature.m4
-new file mode 100644
-index 000000000..608faf0f8
---- /dev/null
-+++ b/config/kernel-cpu_has_feature.m4
-@@ -0,0 +1,29 @@
-+dnl #
-+dnl # cpu_has_feature() may referencing GPL-only cpu_feature_keys on powerpc
-+dnl #
-+
-+dnl #
-+dnl # Checking if cpu_has_feature is exported GPL-only
-+dnl #
-+AC_DEFUN([ZFS_AC_KERNEL_SRC_CPU_HAS_FEATURE], [
-+	ZFS_LINUX_TEST_SRC([cpu_has_feature], [
-+		#include <linux/version.h>
-+		#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
-+		#include <asm/cpu_has_feature.h>
-+		#else
-+		#include <asm/cputable.h>
-+		#endif
-+	], [
-+		return cpu_has_feature(CPU_FTR_ALTIVEC) ? 0 : 1;
-+	], [], [ZFS_META_LICENSE])
-+])
-+AC_DEFUN([ZFS_AC_KERNEL_CPU_HAS_FEATURE], [
-+	AC_MSG_CHECKING([whether cpu_has_feature() is GPL-only])
-+	ZFS_LINUX_TEST_RESULT([cpu_has_feature_license], [
-+		AC_MSG_RESULT(no)
-+	], [
-+		AC_MSG_RESULT(yes)
-+		AC_DEFINE(HAVE_CPU_HAS_FEATURE_GPL_ONLY, 1,
-+		    [cpu_has_feature() is GPL-only])
-+	])
-+])
-diff --git a/config/kernel-filemap.m4 b/config/kernel-filemap.m4
-new file mode 100644
-index 000000000..745928168
---- /dev/null
-+++ b/config/kernel-filemap.m4
-@@ -0,0 +1,26 @@
-+dnl #
-+dnl # filemap_range_has_page was not available till 4.13
-+dnl #
-+AC_DEFUN([ZFS_AC_KERNEL_SRC_FILEMAP], [
-+	ZFS_LINUX_TEST_SRC([filemap_range_has_page], [
-+		#include <linux/fs.h>
-+	],[
-+		struct address_space *mapping = NULL;
-+		loff_t lstart = 0;
-+		loff_t lend = 0;
-+		bool ret __attribute__ ((unused));
-+
-+		ret = filemap_range_has_page(mapping, lstart, lend);
-+	])
-+])
-+
-+AC_DEFUN([ZFS_AC_KERNEL_FILEMAP], [
-+	AC_MSG_CHECKING([whether filemap_range_has_page() is available])
-+	ZFS_LINUX_TEST_RESULT([filemap_range_has_page], [
-+		AC_MSG_RESULT(yes)
-+		AC_DEFINE(HAVE_FILEMAP_RANGE_HAS_PAGE, 1,
-+		[filemap_range_has_page() is available])
-+	],[
-+		AC_MSG_RESULT(no)
-+	])
-+])
-diff --git a/config/kernel-flush_dcache_page.m4 b/config/kernel-flush_dcache_page.m4
-new file mode 100644
-index 000000000..2340c386e
---- /dev/null
-+++ b/config/kernel-flush_dcache_page.m4
-@@ -0,0 +1,26 @@
-+dnl #
-+dnl # Starting from Linux 5.13, flush_dcache_page() becomes an inline
-+dnl # function and may indirectly referencing GPL-only cpu_feature_keys on
-+dnl # powerpc
-+dnl #
-+
-+dnl #
-+dnl # Checking if flush_dcache_page is exported GPL-only
-+dnl #
-+AC_DEFUN([ZFS_AC_KERNEL_SRC_FLUSH_DCACHE_PAGE], [
-+	ZFS_LINUX_TEST_SRC([flush_dcache_page], [
-+		#include <asm/cacheflush.h>
-+	], [
-+		flush_dcache_page(0);
-+	], [], [ZFS_META_LICENSE])
-+])
-+AC_DEFUN([ZFS_AC_KERNEL_FLUSH_DCACHE_PAGE], [
-+	AC_MSG_CHECKING([whether flush_dcache_page() is GPL-only])
-+	ZFS_LINUX_TEST_RESULT([flush_dcache_page_license], [
-+		AC_MSG_RESULT(no)
-+	], [
-+		AC_MSG_RESULT(yes)
-+		AC_DEFINE(HAVE_FLUSH_DCACHE_PAGE_GPL_ONLY, 1,
-+		    [flush_dcache_page() is GPL-only])
-+	])
-+])
-diff --git a/config/kernel-generic_fillattr.m4 b/config/kernel-generic_fillattr.m4
-index 0acd5d531..02dee4d4c 100644
---- a/config/kernel-generic_fillattr.m4
-+++ b/config/kernel-generic_fillattr.m4
-@@ -4,7 +4,10 @@ dnl #
- dnl # generic_fillattr in linux/fs.h now requires a struct user_namespace*
- dnl # as the first arg, to support idmapped mounts.
- dnl #
--AC_DEFUN([ZFS_AC_KERNEL_SRC_GENERIC_FILLATTR_USERNS], [
-+dnl # 6.3 API
-+dnl # generic_fillattr() now takes struct mnt_idmap* as the first argument
-+dnl #
-+AC_DEFUN([ZFS_AC_KERNEL_SRC_GENERIC_FILLATTR], [
- 	ZFS_LINUX_TEST_SRC([generic_fillattr_userns], [
- 		#include <linux/fs.h>
- 	],[
-@@ -13,16 +16,32 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_GENERIC_FILLATTR_USERNS], [
- 		struct kstat *k = NULL;
- 		generic_fillattr(userns, in, k);
- 	])
-+
-+	ZFS_LINUX_TEST_SRC([generic_fillattr_mnt_idmap], [
-+		#include <linux/fs.h>
-+	],[
-+		struct mnt_idmap *idmap = NULL;
-+		struct inode *in = NULL;
-+		struct kstat *k = NULL;
-+		generic_fillattr(idmap, in, k);
-+	])
- ])
- 
--AC_DEFUN([ZFS_AC_KERNEL_GENERIC_FILLATTR_USERNS], [
--	AC_MSG_CHECKING([whether generic_fillattr requires struct user_namespace*])
--	ZFS_LINUX_TEST_RESULT([generic_fillattr_userns], [
-+AC_DEFUN([ZFS_AC_KERNEL_GENERIC_FILLATTR], [
-+	AC_MSG_CHECKING([whether generic_fillattr requires struct mnt_idmap*])
-+	ZFS_LINUX_TEST_RESULT([generic_fillattr_mnt_idmap], [
- 		AC_MSG_RESULT([yes])
--		AC_DEFINE(HAVE_GENERIC_FILLATTR_USERNS, 1,
--		    [generic_fillattr requires struct user_namespace*])
-+		AC_DEFINE(HAVE_GENERIC_FILLATTR_IDMAP, 1,
-+		    [generic_fillattr requires struct mnt_idmap*])
- 	],[
--		AC_MSG_RESULT([no])
-+		AC_MSG_CHECKING([whether generic_fillattr requires struct user_namespace*])
-+		ZFS_LINUX_TEST_RESULT([generic_fillattr_userns], [
-+			AC_MSG_RESULT([yes])
-+			AC_DEFINE(HAVE_GENERIC_FILLATTR_USERNS, 1,
-+			    [generic_fillattr requires struct user_namespace*])
-+		],[
-+			AC_MSG_RESULT([no])
-+		])
- 	])
- ])
- 
-diff --git a/config/kernel-inode-create.m4 b/config/kernel-inode-create.m4
-index a6ea11fb6..9e9e43180 100644
---- a/config/kernel-inode-create.m4
-+++ b/config/kernel-inode-create.m4
-@@ -1,4 +1,22 @@
- AC_DEFUN([ZFS_AC_KERNEL_SRC_CREATE], [
-+	dnl #
-+	dnl # 6.3 API change
-+	dnl # The first arg is changed to struct mnt_idmap *
-+	dnl #
-+	ZFS_LINUX_TEST_SRC([create_mnt_idmap], [
-+		#include <linux/fs.h>
-+		#include <linux/sched.h>
-+
-+		int inode_create(struct mnt_idmap *idmap,
-+		    struct inode *inode ,struct dentry *dentry,
-+		    umode_t umode, bool flag) { return 0; }
-+
-+		static const struct inode_operations
-+			iops __attribute__ ((unused)) = {
-+			.create         = inode_create,
-+		};
-+	],[])
-+
- 	dnl #
- 	dnl # 5.12 API change that added the struct user_namespace* arg
- 	dnl # to the front of this function type's arg list.
-@@ -35,19 +53,28 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_CREATE], [
- ])
- 
- AC_DEFUN([ZFS_AC_KERNEL_CREATE], [
--	AC_MSG_CHECKING([whether iops->create() takes struct user_namespace*])
--	ZFS_LINUX_TEST_RESULT([create_userns], [
-+	AC_MSG_CHECKING([whether iops->create() takes struct mnt_idmap*])
-+	ZFS_LINUX_TEST_RESULT([create_mnt_idmap], [
- 		AC_MSG_RESULT(yes)
--		AC_DEFINE(HAVE_IOPS_CREATE_USERNS, 1,
--		   [iops->create() takes struct user_namespace*])
-+		AC_DEFINE(HAVE_IOPS_CREATE_IDMAP, 1,
-+		   [iops->create() takes struct mnt_idmap*])
- 	],[
- 		AC_MSG_RESULT(no)
- 
--		AC_MSG_CHECKING([whether iops->create() passes flags])
--		ZFS_LINUX_TEST_RESULT([create_flags], [
-+		AC_MSG_CHECKING([whether iops->create() takes struct user_namespace*])
-+		ZFS_LINUX_TEST_RESULT([create_userns], [
- 			AC_MSG_RESULT(yes)
-+			AC_DEFINE(HAVE_IOPS_CREATE_USERNS, 1,
-+			   [iops->create() takes struct user_namespace*])
- 		],[
--			ZFS_LINUX_TEST_ERROR([iops->create()])
-+			AC_MSG_RESULT(no)
-+
-+			AC_MSG_CHECKING([whether iops->create() passes flags])
-+			ZFS_LINUX_TEST_RESULT([create_flags], [
-+				AC_MSG_RESULT(yes)
-+			],[
-+				ZFS_LINUX_TEST_ERROR([iops->create()])
-+			])
- 		])
- 	])
- ])
-diff --git a/config/kernel-inode-getattr.m4 b/config/kernel-inode-getattr.m4
-index f62e82f52..c8bfb0786 100644
---- a/config/kernel-inode-getattr.m4
-+++ b/config/kernel-inode-getattr.m4
-@@ -1,4 +1,24 @@
- AC_DEFUN([ZFS_AC_KERNEL_SRC_INODE_GETATTR], [
-+	dnl #
-+	dnl # Linux 6.3 API
-+	dnl # The first arg of getattr I/O operations handler type
-+	dnl # is changed to struct mnt_idmap*
-+	dnl #
-+	ZFS_LINUX_TEST_SRC([inode_operations_getattr_mnt_idmap], [
-+		#include <linux/fs.h>
-+
-+		int test_getattr(
-+		    struct mnt_idmap *idmap,
-+		    const struct path *p, struct kstat *k,
-+		    u32 request_mask, unsigned int query_flags)
-+		    { return 0; }
-+
-+		static const struct inode_operations
-+		    iops __attribute__ ((unused)) = {
-+			.getattr = test_getattr,
-+		};
-+	],[])
-+
- 	dnl #
- 	dnl # Linux 5.12 API
- 	dnl # The getattr I/O operations handler type was extended to require
-@@ -55,37 +75,48 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_INODE_GETATTR], [
- 
- AC_DEFUN([ZFS_AC_KERNEL_INODE_GETATTR], [
- 	dnl #
--	dnl # Kernel 5.12 test
-+	dnl # Kernel 6.3 test
- 	dnl #
--	AC_MSG_CHECKING([whether iops->getattr() takes user_namespace])
--	ZFS_LINUX_TEST_RESULT([inode_operations_getattr_userns], [
-+	AC_MSG_CHECKING([whether iops->getattr() takes mnt_idmap])
-+	ZFS_LINUX_TEST_RESULT([inode_operations_getattr_mnt_idmap], [
- 		AC_MSG_RESULT(yes)
--		AC_DEFINE(HAVE_USERNS_IOPS_GETATTR, 1,
--		    [iops->getattr() takes struct user_namespace*])
-+		AC_DEFINE(HAVE_IDMAP_IOPS_GETATTR, 1,
-+		    [iops->getattr() takes struct mnt_idmap*])
- 	],[
- 		AC_MSG_RESULT(no)
--
- 		dnl #
--		dnl # Kernel 4.11 test
-+		dnl # Kernel 5.12 test
- 		dnl #
--		AC_MSG_CHECKING([whether iops->getattr() takes a path])
--		ZFS_LINUX_TEST_RESULT([inode_operations_getattr_path], [
-+		AC_MSG_CHECKING([whether iops->getattr() takes user_namespace])
-+		ZFS_LINUX_TEST_RESULT([inode_operations_getattr_userns], [
- 			AC_MSG_RESULT(yes)
--			AC_DEFINE(HAVE_PATH_IOPS_GETATTR, 1,
--				[iops->getattr() takes a path])
-+			AC_DEFINE(HAVE_USERNS_IOPS_GETATTR, 1,
-+			    [iops->getattr() takes struct user_namespace*])
- 		],[
- 			AC_MSG_RESULT(no)
- 
- 			dnl #
--			dnl # Kernel < 4.11 test
-+			dnl # Kernel 4.11 test
- 			dnl #
--			AC_MSG_CHECKING([whether iops->getattr() takes a vfsmount])
--			ZFS_LINUX_TEST_RESULT([inode_operations_getattr_vfsmount], [
-+			AC_MSG_CHECKING([whether iops->getattr() takes a path])
-+			ZFS_LINUX_TEST_RESULT([inode_operations_getattr_path], [
- 				AC_MSG_RESULT(yes)
--				AC_DEFINE(HAVE_VFSMOUNT_IOPS_GETATTR, 1,
--					[iops->getattr() takes a vfsmount])
-+				AC_DEFINE(HAVE_PATH_IOPS_GETATTR, 1,
-+					[iops->getattr() takes a path])
- 			],[
- 				AC_MSG_RESULT(no)
-+
-+				dnl #
-+				dnl # Kernel < 4.11 test
-+				dnl #
-+				AC_MSG_CHECKING([whether iops->getattr() takes a vfsmount])
-+				ZFS_LINUX_TEST_RESULT([inode_operations_getattr_vfsmount], [
-+					AC_MSG_RESULT(yes)
-+					AC_DEFINE(HAVE_VFSMOUNT_IOPS_GETATTR, 1,
-+						[iops->getattr() takes a vfsmount])
-+				],[
-+					AC_MSG_RESULT(no)
-+				])
- 			])
- 		])
- 	])
-diff --git a/config/kernel-inode-setattr.m4 b/config/kernel-inode-setattr.m4
-new file mode 100644
-index 000000000..45755b4eb
---- /dev/null
-+++ b/config/kernel-inode-setattr.m4
-@@ -0,0 +1,87 @@
-+AC_DEFUN([ZFS_AC_KERNEL_SRC_INODE_SETATTR], [
-+	dnl #
-+	dnl # Linux 6.3 API
-+	dnl # The first arg of setattr I/O operations handler type
-+	dnl # is changed to struct mnt_idmap*
-+	dnl #
-+	ZFS_LINUX_TEST_SRC([inode_operations_setattr_mnt_idmap], [
-+		#include <linux/fs.h>
-+
-+		int test_setattr(
-+		    struct mnt_idmap *idmap,
-+		    struct dentry *de, struct iattr *ia)
-+		    { return 0; }
-+
-+		static const struct inode_operations
-+		    iops __attribute__ ((unused)) = {
-+			.setattr = test_setattr,
-+		};
-+	],[])
-+
-+	dnl #
-+	dnl # Linux 5.12 API
-+	dnl # The setattr I/O operations handler type was extended to require
-+	dnl # a struct user_namespace* as its first arg, to support idmapped
-+	dnl # mounts.
-+	dnl #
-+	ZFS_LINUX_TEST_SRC([inode_operations_setattr_userns], [
-+		#include <linux/fs.h>
-+
-+		int test_setattr(
-+		    struct user_namespace *userns,
-+		    struct dentry *de, struct iattr *ia)
-+		    { return 0; }
-+
-+		static const struct inode_operations
-+		    iops __attribute__ ((unused)) = {
-+			.setattr = test_setattr,
-+		};
-+	],[])
-+
-+	ZFS_LINUX_TEST_SRC([inode_operations_setattr], [
-+		#include <linux/fs.h>
-+
-+		int test_setattr(
-+		    struct dentry *de, struct iattr *ia)
-+		    { return 0; }
-+
-+		static const struct inode_operations
-+		    iops __attribute__ ((unused)) = {
-+			.setattr = test_setattr,
-+		};
-+	],[])
-+])
-+
-+AC_DEFUN([ZFS_AC_KERNEL_INODE_SETATTR], [
-+	dnl #
-+	dnl # Kernel 6.3 test
-+	dnl #
-+	AC_MSG_CHECKING([whether iops->setattr() takes mnt_idmap])
-+	ZFS_LINUX_TEST_RESULT([inode_operations_setattr_mnt_idmap], [
-+		AC_MSG_RESULT(yes)
-+		AC_DEFINE(HAVE_IDMAP_IOPS_SETATTR, 1,
-+		    [iops->setattr() takes struct mnt_idmap*])
-+	],[
-+		AC_MSG_RESULT(no)
-+		dnl #
-+		dnl # Kernel 5.12 test
-+		dnl #
-+		AC_MSG_CHECKING([whether iops->setattr() takes user_namespace])
-+		ZFS_LINUX_TEST_RESULT([inode_operations_setattr_userns], [
-+			AC_MSG_RESULT(yes)
-+			AC_DEFINE(HAVE_USERNS_IOPS_SETATTR, 1,
-+			    [iops->setattr() takes struct user_namespace*])
-+		],[
-+			AC_MSG_RESULT(no)
-+
-+			AC_MSG_CHECKING([whether iops->setattr() exists])
-+			ZFS_LINUX_TEST_RESULT([inode_operations_setattr], [
-+				AC_MSG_RESULT(yes)
-+				AC_DEFINE(HAVE_IOPS_SETATTR, 1,
-+					[iops->setattr() exists])
-+			],[
-+				AC_MSG_RESULT(no)
-+			])
-+		])
-+	])
-+])
-diff --git a/config/kernel-is_owner_or_cap.m4 b/config/kernel-is_owner_or_cap.m4
-index a90cf3da6..4e9c002b7 100644
---- a/config/kernel-is_owner_or_cap.m4
-+++ b/config/kernel-is_owner_or_cap.m4
-@@ -16,12 +16,20 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_INODE_OWNER_OR_CAPABLE], [
- 		(void) inode_owner_or_capable(ip);
- 	])
- 
--	ZFS_LINUX_TEST_SRC([inode_owner_or_capable_idmapped], [
-+	ZFS_LINUX_TEST_SRC([inode_owner_or_capable_userns], [
- 		#include <linux/fs.h>
- 	],[
- 		struct inode *ip = NULL;
- 		(void) inode_owner_or_capable(&init_user_ns, ip);
- 	])
-+
-+	ZFS_LINUX_TEST_SRC([inode_owner_or_capable_mnt_idmap], [
-+		#include <linux/fs.h>
-+		#include <linux/mnt_idmapping.h>
-+	],[
-+		struct inode *ip = NULL;
-+		(void) inode_owner_or_capable(&nop_mnt_idmap, ip);
-+	])
- ])
- 
- AC_DEFUN([ZFS_AC_KERNEL_INODE_OWNER_OR_CAPABLE], [
-@@ -35,12 +43,21 @@ AC_DEFUN([ZFS_AC_KERNEL_INODE_OWNER_OR_CAPABLE], [
- 
- 		AC_MSG_CHECKING(
- 		    [whether inode_owner_or_capable() takes user_ns])
--		ZFS_LINUX_TEST_RESULT([inode_owner_or_capable_idmapped], [
-+		ZFS_LINUX_TEST_RESULT([inode_owner_or_capable_userns], [
- 			AC_MSG_RESULT(yes)
--			AC_DEFINE(HAVE_INODE_OWNER_OR_CAPABLE_IDMAPPED, 1,
-+			AC_DEFINE(HAVE_INODE_OWNER_OR_CAPABLE_USERNS, 1,
- 			    [inode_owner_or_capable() takes user_ns])
- 		],[
--			ZFS_LINUX_TEST_ERROR([capability])
-+			AC_MSG_RESULT(no)
-+			AC_MSG_CHECKING(
-+			    [whether inode_owner_or_capable() takes mnt_idmap])
-+			ZFS_LINUX_TEST_RESULT([inode_owner_or_capable_mnt_idmap], [
-+				AC_MSG_RESULT(yes)
-+				AC_DEFINE(HAVE_INODE_OWNER_OR_CAPABLE_IDMAP, 1,
-+				    [inode_owner_or_capable() takes mnt_idmap])
-+			], [
-+				ZFS_LINUX_TEST_ERROR([capability])
-+			])
- 		])
- 	])
- ])
-diff --git a/config/kernel-mkdir.m4 b/config/kernel-mkdir.m4
-index 6667ed04f..7407a791b 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.3 API change
-+	dnl # mkdir() takes struct mnt_idmap * as the first arg
-+	dnl #
-+	ZFS_LINUX_TEST_SRC([mkdir_mnt_idmap], [
-+		#include <linux/fs.h>
-+
-+		int mkdir(struct mnt_idmap *idmap,
-+			struct inode *inode, struct dentry *dentry,
-+			umode_t umode) { return 0; }
-+		static const struct inode_operations
-+		    iops __attribute__ ((unused)) = {
-+			.mkdir = mkdir,
-+		};
-+	],[])
-+
- 	dnl #
- 	dnl # 5.12 API change
- 	dnl # The struct user_namespace arg was added as the first argument to
-@@ -43,25 +59,36 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_MKDIR], [
- 
- AC_DEFUN([ZFS_AC_KERNEL_MKDIR], [
- 	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)
--
--		AC_MSG_CHECKING([whether iops->mkdir() takes umode_t])
--		ZFS_LINUX_TEST_RESULT([inode_operations_mkdir], [
-+		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_MKDIR_UMODE_T, 1,
--			    [iops->mkdir() takes umode_t])
-+			AC_DEFINE(HAVE_IOPS_MKDIR_USERNS, 1,
-+			    [iops->mkdir() takes struct user_namespace*])
- 		],[
--			ZFS_LINUX_TEST_ERROR([mkdir()])
-+			AC_MSG_RESULT(no)
-+
-+			AC_MSG_CHECKING([whether iops->mkdir() takes umode_t])
-+			ZFS_LINUX_TEST_RESULT([inode_operations_mkdir], [
-+				AC_MSG_RESULT(yes)
-+				AC_DEFINE(HAVE_MKDIR_UMODE_T, 1,
-+				    [iops->mkdir() takes umode_t])
-+			],[
-+				ZFS_LINUX_TEST_ERROR([mkdir()])
-+			])
- 		])
- 	])
- ])
-diff --git a/config/kernel-mknod.m4 b/config/kernel-mknod.m4
-index ffe451060..1494ec1ae 100644
---- a/config/kernel-mknod.m4
-+++ b/config/kernel-mknod.m4
-@@ -1,4 +1,22 @@
- AC_DEFUN([ZFS_AC_KERNEL_SRC_MKNOD], [
-+	dnl #
-+	dnl # 6.3 API change
-+	dnl # The first arg is now struct mnt_idmap*
-+	dnl #
-+	ZFS_LINUX_TEST_SRC([mknod_mnt_idmap], [
-+		#include <linux/fs.h>
-+		#include <linux/sched.h>
-+
-+		int tmp_mknod(struct mnt_idmap *idmap,
-+		    struct inode *inode ,struct dentry *dentry,
-+		    umode_t u, dev_t d) { return 0; }
-+
-+		static const struct inode_operations
-+			iops __attribute__ ((unused)) = {
-+			.mknod          = tmp_mknod,
-+		};
-+	],[])
-+
- 	dnl #
- 	dnl # 5.12 API change that added the struct user_namespace* arg
- 	dnl # to the front of this function type's arg list.
-@@ -19,12 +37,20 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_MKNOD], [
- ])
- 
- AC_DEFUN([ZFS_AC_KERNEL_MKNOD], [
--	AC_MSG_CHECKING([whether iops->mknod() takes struct user_namespace*])
--	ZFS_LINUX_TEST_RESULT([mknod_userns], [
-+	AC_MSG_CHECKING([whether iops->mknod() takes struct mnt_idmap*])
-+	ZFS_LINUX_TEST_RESULT([mknod_mnt_idmap], [
- 		AC_MSG_RESULT(yes)
--		AC_DEFINE(HAVE_IOPS_MKNOD_USERNS, 1,
--		    [iops->mknod() takes struct user_namespace*])
-+		AC_DEFINE(HAVE_IOPS_MKNOD_IDMAP, 1,
-+		    [iops->mknod() takes struct mnt_idmap*])
- 	],[
- 		AC_MSG_RESULT(no)
-+		AC_MSG_CHECKING([whether iops->mknod() takes struct user_namespace*])
-+		ZFS_LINUX_TEST_RESULT([mknod_userns], [
-+			AC_MSG_RESULT(yes)
-+			AC_DEFINE(HAVE_IOPS_MKNOD_USERNS, 1,
-+			    [iops->mknod() takes struct user_namespace*])
-+		],[
-+			AC_MSG_RESULT(no)
-+		])
- 	])
- ])
-diff --git a/config/kernel-reclaim_state.m4 b/config/kernel-reclaim_state.m4
-new file mode 100644
-index 000000000..9936b3c10
---- /dev/null
-+++ b/config/kernel-reclaim_state.m4
-@@ -0,0 +1,26 @@
-+AC_DEFUN([ZFS_AC_KERNEL_SRC_RECLAIMED], [
-+	dnl #
-+	dnl # 6.4 API change
-+	dnl # The reclaimed_slab of struct reclaim_state
-+	dnl # is renamed to reclaimed
-+	dnl #
-+	ZFS_LINUX_TEST_SRC([reclaim_state_reclaimed], [
-+		#include <linux/swap.h>
-+		static const struct reclaim_state
-+		    rs  __attribute__ ((unused)) = {
-+		    .reclaimed = 100,
-+		};
-+	],[])
-+])
-+
-+AC_DEFUN([ZFS_AC_KERNEL_RECLAIMED], [
-+	AC_MSG_CHECKING([whether struct reclaim_state has reclaimed field])
-+	ZFS_LINUX_TEST_RESULT([reclaim_state_reclaimed], [
-+		AC_MSG_RESULT(yes)
-+		AC_DEFINE(HAVE_RECLAIM_STATE_RECLAIMED, 1,
-+		   [struct reclaim_state has reclaimed])
-+	],[
-+		AC_MSG_RESULT(no)
-+	])
-+])
-+
-diff --git a/config/kernel-rename.m4 b/config/kernel-rename.m4
-index 302db43f5..b33cd0bfb 100644
---- a/config/kernel-rename.m4
-+++ b/config/kernel-rename.m4
-@@ -33,24 +33,48 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_RENAME], [
- 			.rename = rename_fn,
- 		};
- 	],[])
-+
-+	dnl #
-+	dnl # 6.3 API change - the first arg is now struct mnt_idmap*
-+	dnl #
-+	ZFS_LINUX_TEST_SRC([inode_operations_rename_mnt_idmap], [
-+		#include <linux/fs.h>
-+		int rename_fn(struct mnt_idmap *idmap, struct inode *sip,
-+			struct dentry *sdp, struct inode *tip, struct dentry *tdp,
-+			unsigned int flags) { return 0; }
-+
-+		static const struct inode_operations
-+		    iops __attribute__ ((unused)) = {
-+			.rename = rename_fn,
-+		};
-+	],[])
- ])
- 
- AC_DEFUN([ZFS_AC_KERNEL_RENAME], [
--	AC_MSG_CHECKING([whether iops->rename() takes struct user_namespace*])
--	ZFS_LINUX_TEST_RESULT([inode_operations_rename_userns], [
-+	AC_MSG_CHECKING([whether iops->rename() takes struct mnt_idmap*])
-+	ZFS_LINUX_TEST_RESULT([inode_operations_rename_mnt_idmap], [
- 		AC_MSG_RESULT(yes)
--		AC_DEFINE(HAVE_IOPS_RENAME_USERNS, 1,
--		    [iops->rename() takes struct user_namespace*])
-+		AC_DEFINE(HAVE_IOPS_RENAME_IDMAP, 1,
-+		    [iops->rename() takes struct mnt_idmap*])
- 	],[
- 		AC_MSG_RESULT(no)
- 
--		AC_MSG_CHECKING([whether iop->rename() wants flags])
--		ZFS_LINUX_TEST_RESULT([inode_operations_rename_flags], [
-+		AC_MSG_CHECKING([whether iops->rename() takes struct user_namespace*])
-+		ZFS_LINUX_TEST_RESULT([inode_operations_rename_userns], [
- 			AC_MSG_RESULT(yes)
--			AC_DEFINE(HAVE_RENAME_WANTS_FLAGS, 1,
--				[iops->rename() wants flags])
-+			AC_DEFINE(HAVE_IOPS_RENAME_USERNS, 1,
-+			    [iops->rename() takes struct user_namespace*])
- 		],[
- 			AC_MSG_RESULT(no)
-+
-+			AC_MSG_CHECKING([whether iops->rename() wants flags])
-+			ZFS_LINUX_TEST_RESULT([inode_operations_rename_flags], [
-+				AC_MSG_RESULT(yes)
-+				AC_DEFINE(HAVE_RENAME_WANTS_FLAGS, 1,
-+					[iops->rename() wants flags])
-+			],[
-+				AC_MSG_RESULT(no)
-+			])
- 		])
- 	])
- ])
-diff --git a/config/kernel-setattr-prepare.m4 b/config/kernel-setattr-prepare.m4
-index 24245aa53..e02d6263e 100644
---- a/config/kernel-setattr-prepare.m4
-+++ b/config/kernel-setattr-prepare.m4
-@@ -27,26 +27,48 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_SETATTR_PREPARE], [
- 		int error __attribute__ ((unused)) =
- 			setattr_prepare(userns, dentry, attr);
- 	])
-+
-+	dnl #
-+	dnl # 6.3 API change
-+	dnl # The first arg of setattr_prepare() is changed to struct mnt_idmap*
-+	dnl #
-+	ZFS_LINUX_TEST_SRC([setattr_prepare_mnt_idmap], [
-+		#include <linux/fs.h>
-+	], [
-+		struct dentry *dentry = NULL;
-+		struct iattr *attr = NULL;
-+		struct mnt_idmap *idmap = NULL;
-+		int error __attribute__ ((unused)) =
-+			setattr_prepare(idmap, dentry, attr);
-+	])
- ])
- 
- AC_DEFUN([ZFS_AC_KERNEL_SETATTR_PREPARE], [
--	AC_MSG_CHECKING([whether setattr_prepare() is available and accepts struct user_namespace*])
--	ZFS_LINUX_TEST_RESULT_SYMBOL([setattr_prepare_userns],
-+	AC_MSG_CHECKING([whether setattr_prepare() is available and accepts struct mnt_idmap*])
-+	ZFS_LINUX_TEST_RESULT_SYMBOL([setattr_prepare_mnt_idmap],
- 	    [setattr_prepare], [fs/attr.c], [
- 		AC_MSG_RESULT(yes)
--		AC_DEFINE(HAVE_SETATTR_PREPARE_USERNS, 1,
--		    [setattr_prepare() accepts user_namespace])
-+		AC_DEFINE(HAVE_SETATTR_PREPARE_IDMAP, 1,
-+		    [setattr_prepare() accepts mnt_idmap])
- 	], [
--		AC_MSG_RESULT(no)
--
--		AC_MSG_CHECKING([whether setattr_prepare() is available, doesn't accept user_namespace])
--		ZFS_LINUX_TEST_RESULT_SYMBOL([setattr_prepare],
--			[setattr_prepare], [fs/attr.c], [
-+		AC_MSG_CHECKING([whether setattr_prepare() is available and accepts struct user_namespace*])
-+		ZFS_LINUX_TEST_RESULT_SYMBOL([setattr_prepare_userns],
-+		    [setattr_prepare], [fs/attr.c], [
- 			AC_MSG_RESULT(yes)
--			AC_DEFINE(HAVE_SETATTR_PREPARE_NO_USERNS, 1,
--				[setattr_prepare() is available, doesn't accept user_namespace])
-+			AC_DEFINE(HAVE_SETATTR_PREPARE_USERNS, 1,
-+			    [setattr_prepare() accepts user_namespace])
- 		], [
- 			AC_MSG_RESULT(no)
-+
-+			AC_MSG_CHECKING([whether setattr_prepare() is available, doesn't accept user_namespace])
-+			ZFS_LINUX_TEST_RESULT_SYMBOL([setattr_prepare],
-+				[setattr_prepare], [fs/attr.c], [
-+				AC_MSG_RESULT(yes)
-+				AC_DEFINE(HAVE_SETATTR_PREPARE_NO_USERNS, 1,
-+					[setattr_prepare() is available, doesn't accept user_namespace])
-+			], [
-+				AC_MSG_RESULT(no)
-+			])
- 		])
- 	])
- ])
-diff --git a/config/kernel-symlink.m4 b/config/kernel-symlink.m4
-index d90366d04..a0333ed66 100644
---- a/config/kernel-symlink.m4
-+++ b/config/kernel-symlink.m4
-@@ -1,4 +1,20 @@
- AC_DEFUN([ZFS_AC_KERNEL_SRC_SYMLINK], [
-+	dnl #
-+	dnl # 6.3 API change that changed the first arg
-+	dnl # to struct mnt_idmap*
-+	dnl #
-+	ZFS_LINUX_TEST_SRC([symlink_mnt_idmap], [
-+		#include <linux/fs.h>
-+		#include <linux/sched.h>
-+		int tmp_symlink(struct mnt_idmap *idmap,
-+		    struct inode *inode ,struct dentry *dentry,
-+		    const char *path) { return 0; }
-+
-+		static const struct inode_operations
-+			iops __attribute__ ((unused)) = {
-+			.symlink                = tmp_symlink,
-+		};
-+	],[])
- 	dnl #
- 	dnl # 5.12 API change that added the struct user_namespace* arg
- 	dnl # to the front of this function type's arg list.
-@@ -19,12 +35,19 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_SYMLINK], [
- ])
- 
- AC_DEFUN([ZFS_AC_KERNEL_SYMLINK], [
--	AC_MSG_CHECKING([whether iops->symlink() takes struct user_namespace*])
--	ZFS_LINUX_TEST_RESULT([symlink_userns], [
-+	AC_MSG_CHECKING([whether iops->symlink() takes struct mnt_idmap*])
-+	ZFS_LINUX_TEST_RESULT([symlink_mnt_idmap], [
- 		AC_MSG_RESULT(yes)
--		AC_DEFINE(HAVE_IOPS_SYMLINK_USERNS, 1,
--		    [iops->symlink() takes struct user_namespace*])
-+		AC_DEFINE(HAVE_IOPS_SYMLINK_IDMAP, 1,
-+		    [iops->symlink() takes struct mnt_idmap*])
- 	],[
--		AC_MSG_RESULT(no)
-+		AC_MSG_CHECKING([whether iops->symlink() takes struct user_namespace*])
-+		ZFS_LINUX_TEST_RESULT([symlink_userns], [
-+			AC_MSG_RESULT(yes)
-+			AC_DEFINE(HAVE_IOPS_SYMLINK_USERNS, 1,
-+			    [iops->symlink() takes struct user_namespace*])
-+		],[
-+			AC_MSG_RESULT(no)
-+		])
- 	])
- ])
-diff --git a/config/kernel-tmpfile.m4 b/config/kernel-tmpfile.m4
-index 0e1deb361..cc18b8f65 100644
---- a/config/kernel-tmpfile.m4
-+++ b/config/kernel-tmpfile.m4
-@@ -4,6 +4,19 @@ dnl # Add support for i_op->tmpfile
- dnl #
- AC_DEFUN([ZFS_AC_KERNEL_SRC_TMPFILE], [
- 	dnl #
-+	dnl # 6.3 API change
-+	dnl # The first arg is now struct mnt_idmap * 
-+	dnl #
-+	ZFS_LINUX_TEST_SRC([inode_operations_tmpfile_mnt_idmap], [
-+		#include <linux/fs.h>
-+		int tmpfile(struct mnt_idmap *idmap,
-+		    struct inode *inode, struct file *file,
-+		    umode_t mode) { return 0; }
-+		static struct inode_operations
-+		    iops __attribute__ ((unused)) = {
-+			.tmpfile = tmpfile,
-+		};
-+	],[])
- 	dnl # 6.1 API change
- 	dnl # use struct file instead of struct dentry
- 	dnl #
-@@ -44,23 +57,29 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_TMPFILE], [
- 
- AC_DEFUN([ZFS_AC_KERNEL_TMPFILE], [
- 	AC_MSG_CHECKING([whether i_op->tmpfile() exists])
--	ZFS_LINUX_TEST_RESULT([inode_operations_tmpfile], [
-+	ZFS_LINUX_TEST_RESULT([inode_operations_tmpfile_mnt_idmap], [
- 		AC_MSG_RESULT(yes)
- 		AC_DEFINE(HAVE_TMPFILE, 1, [i_op->tmpfile() exists])
--		AC_DEFINE(HAVE_TMPFILE_USERNS, 1, [i_op->tmpfile() has userns])
--	],[
--		ZFS_LINUX_TEST_RESULT([inode_operations_tmpfile_dentry_userns], [
-+		AC_DEFINE(HAVE_TMPFILE_IDMAP, 1, [i_op->tmpfile() has mnt_idmap])
-+	], [
-+		ZFS_LINUX_TEST_RESULT([inode_operations_tmpfile], [
- 			AC_MSG_RESULT(yes)
- 			AC_DEFINE(HAVE_TMPFILE, 1, [i_op->tmpfile() exists])
- 			AC_DEFINE(HAVE_TMPFILE_USERNS, 1, [i_op->tmpfile() has userns])
--			AC_DEFINE(HAVE_TMPFILE_DENTRY, 1, [i_op->tmpfile() uses old dentry signature])
- 		],[
--			ZFS_LINUX_TEST_RESULT([inode_operations_tmpfile_dentry], [
-+			ZFS_LINUX_TEST_RESULT([inode_operations_tmpfile_dentry_userns], [
- 				AC_MSG_RESULT(yes)
- 				AC_DEFINE(HAVE_TMPFILE, 1, [i_op->tmpfile() exists])
-+				AC_DEFINE(HAVE_TMPFILE_USERNS, 1, [i_op->tmpfile() has userns])
- 				AC_DEFINE(HAVE_TMPFILE_DENTRY, 1, [i_op->tmpfile() uses old dentry signature])
- 			],[
--				ZFS_LINUX_REQUIRE_API([i_op->tmpfile()], [3.11])
-+				ZFS_LINUX_TEST_RESULT([inode_operations_tmpfile_dentry], [
-+					AC_MSG_RESULT(yes)
-+					AC_DEFINE(HAVE_TMPFILE, 1, [i_op->tmpfile() exists])
-+					AC_DEFINE(HAVE_TMPFILE_DENTRY, 1, [i_op->tmpfile() uses old dentry signature])
-+				],[
-+					ZFS_LINUX_REQUIRE_API([i_op->tmpfile()], [3.11])
-+				])
- 			])
- 		])
- 	])
-diff --git a/config/kernel-writepage_t.m4 b/config/kernel-writepage_t.m4
-new file mode 100644
-index 000000000..3a0cffd98
---- /dev/null
-+++ b/config/kernel-writepage_t.m4
-@@ -0,0 +1,26 @@
-+AC_DEFUN([ZFS_AC_KERNEL_SRC_WRITEPAGE_T], [
-+	dnl #
-+	dnl # 6.3 API change
-+	dnl # The writepage_t function type now has its first argument as
-+	dnl # struct folio* instead of struct page*
-+	dnl #
-+	ZFS_LINUX_TEST_SRC([writepage_t_folio], [
-+		#include <linux/writeback.h>
-+		int putpage(struct folio *folio,
-+		    struct writeback_control *wbc, void *data)
-+		{ return 0; }
-+		writepage_t func = putpage;
-+	],[])
-+])
-+
-+AC_DEFUN([ZFS_AC_KERNEL_WRITEPAGE_T], [
-+	AC_MSG_CHECKING([whether int (*writepage_t)() takes struct folio*])
-+	ZFS_LINUX_TEST_RESULT([writepage_t_folio], [
-+		AC_MSG_RESULT(yes)
-+		AC_DEFINE(HAVE_WRITEPAGE_T_FOLIO, 1,
-+		   [int (*writepage_t)() takes struct folio*])
-+	],[
-+		AC_MSG_RESULT(no)
-+	])
-+])
-+
-diff --git a/config/kernel-xattr-handler.m4 b/config/kernel-xattr-handler.m4
-index b6cbfa155..6b8a08dbc 100644
---- a/config/kernel-xattr-handler.m4
-+++ b/config/kernel-xattr-handler.m4
-@@ -179,6 +179,21 @@ dnl #
- dnl # Supported xattr handler set() interfaces checked newest to oldest.
- dnl #
- AC_DEFUN([ZFS_AC_KERNEL_SRC_XATTR_HANDLER_SET], [
-+	ZFS_LINUX_TEST_SRC([xattr_handler_set_mnt_idmap], [
-+		#include <linux/xattr.h>
-+
-+		int set(const struct xattr_handler *handler,
-+			struct mnt_idmap *idmap,
-+			struct dentry *dentry, struct inode *inode,
-+			const char *name, const void *buffer,
-+			size_t size, int flags)
-+			{ return 0; }
-+		static const struct xattr_handler
-+			xops __attribute__ ((unused)) = {
-+			.set = set,
-+		};
-+	],[])
-+
- 	ZFS_LINUX_TEST_SRC([xattr_handler_set_userns], [
- 		#include <linux/xattr.h>
- 
-@@ -240,53 +255,63 @@ AC_DEFUN([ZFS_AC_KERNEL_XATTR_HANDLER_SET], [
- 	dnl # The xattr_handler->set() callback was changed to 8 arguments, and
- 	dnl # struct user_namespace* was inserted as arg #2
- 	dnl #
--	AC_MSG_CHECKING([whether xattr_handler->set() wants dentry, inode, and user_namespace])
--	ZFS_LINUX_TEST_RESULT([xattr_handler_set_userns], [
-+	dnl # 6.3 API change,
-+	dnl # The xattr_handler->set() callback 2nd arg is now struct mnt_idmap *
-+	dnl #
-+	AC_MSG_CHECKING([whether xattr_handler->set() wants dentry, inode, and mnt_idmap])
-+	ZFS_LINUX_TEST_RESULT([xattr_handler_set_mnt_idmap], [
- 		AC_MSG_RESULT(yes)
--		AC_DEFINE(HAVE_XATTR_SET_USERNS, 1,
--		    [xattr_handler->set() takes user_namespace])
--	],[
--		dnl #
--		dnl # 4.7 API change,
--		dnl # The xattr_handler->set() callback was changed to take both
--		dnl # dentry and inode.
--		dnl #
--		AC_MSG_RESULT(no)
--		AC_MSG_CHECKING([whether xattr_handler->set() wants dentry and inode])
--		ZFS_LINUX_TEST_RESULT([xattr_handler_set_dentry_inode], [
-+		AC_DEFINE(HAVE_XATTR_SET_IDMAP, 1,
-+		    [xattr_handler->set() takes mnt_idmap])
-+	], [
-+		AC_MSG_CHECKING([whether xattr_handler->set() wants dentry, inode, and user_namespace])
-+		ZFS_LINUX_TEST_RESULT([xattr_handler_set_userns], [
- 			AC_MSG_RESULT(yes)
--			AC_DEFINE(HAVE_XATTR_SET_DENTRY_INODE, 1,
--			    [xattr_handler->set() wants both dentry and inode])
-+			AC_DEFINE(HAVE_XATTR_SET_USERNS, 1,
-+			    [xattr_handler->set() takes user_namespace])
- 		],[
- 			dnl #
--			dnl # 4.4 API change,
--			dnl # The xattr_handler->set() callback was changed to take a
--			dnl # xattr_handler, and handler_flags argument was removed and
--			dnl # should be accessed by handler->flags.
-+			dnl # 4.7 API change,
-+			dnl # The xattr_handler->set() callback was changed to take both
-+			dnl # dentry and inode.
- 			dnl #
- 			AC_MSG_RESULT(no)
--			AC_MSG_CHECKING(
--			    [whether xattr_handler->set() wants xattr_handler])
--			ZFS_LINUX_TEST_RESULT([xattr_handler_set_xattr_handler], [
-+			AC_MSG_CHECKING([whether xattr_handler->set() wants dentry and inode])
-+			ZFS_LINUX_TEST_RESULT([xattr_handler_set_dentry_inode], [
- 				AC_MSG_RESULT(yes)
--				AC_DEFINE(HAVE_XATTR_SET_HANDLER, 1,
--				    [xattr_handler->set() wants xattr_handler])
-+				AC_DEFINE(HAVE_XATTR_SET_DENTRY_INODE, 1,
-+				    [xattr_handler->set() wants both dentry and inode])
- 			],[
- 				dnl #
--				dnl # 2.6.33 API change,
--				dnl # The xattr_handler->set() callback was changed
--				dnl # to take a dentry instead of an inode, and a
--				dnl # handler_flags argument was added.
-+				dnl # 4.4 API change,
-+				dnl # The xattr_handler->set() callback was changed to take a
-+				dnl # xattr_handler, and handler_flags argument was removed and
-+				dnl # should be accessed by handler->flags.
- 				dnl #
- 				AC_MSG_RESULT(no)
- 				AC_MSG_CHECKING(
--				    [whether xattr_handler->set() wants dentry])
--				ZFS_LINUX_TEST_RESULT([xattr_handler_set_dentry], [
-+				    [whether xattr_handler->set() wants xattr_handler])
-+				ZFS_LINUX_TEST_RESULT([xattr_handler_set_xattr_handler], [
- 					AC_MSG_RESULT(yes)
--					AC_DEFINE(HAVE_XATTR_SET_DENTRY, 1,
--					    [xattr_handler->set() wants dentry])
-+					AC_DEFINE(HAVE_XATTR_SET_HANDLER, 1,
-+					    [xattr_handler->set() wants xattr_handler])
- 				],[
--					ZFS_LINUX_TEST_ERROR([xattr set()])
-+					dnl #
-+					dnl # 2.6.33 API change,
-+					dnl # The xattr_handler->set() callback was changed
-+					dnl # to take a dentry instead of an inode, and a
-+					dnl # handler_flags argument was added.
-+					dnl #
-+					AC_MSG_RESULT(no)
-+					AC_MSG_CHECKING(
-+					    [whether xattr_handler->set() wants dentry])
-+					ZFS_LINUX_TEST_RESULT([xattr_handler_set_dentry], [
-+						AC_MSG_RESULT(yes)
-+						AC_DEFINE(HAVE_XATTR_SET_DENTRY, 1,
-+						    [xattr_handler->set() wants dentry])
-+					],[
-+						ZFS_LINUX_TEST_ERROR([xattr set()])
-+					])
- 				])
- 			])
- 		])
-diff --git a/config/kernel.m4 b/config/kernel.m4
-index 7806da7a8..173c78a2a 100644
---- a/config/kernel.m4
-+++ b/config/kernel.m4
-@@ -69,6 +69,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
- 	ZFS_AC_KERNEL_SRC_INODE_OWNER_OR_CAPABLE
- 	ZFS_AC_KERNEL_SRC_XATTR
- 	ZFS_AC_KERNEL_SRC_ACL
-+	ZFS_AC_KERNEL_SRC_INODE_SETATTR
- 	ZFS_AC_KERNEL_SRC_INODE_GETATTR
- 	ZFS_AC_KERNEL_SRC_INODE_SET_FLAGS
- 	ZFS_AC_KERNEL_SRC_INODE_SET_IVERSION
-@@ -130,7 +131,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
- 	ZFS_AC_KERNEL_SRC_KSTRTOUL
- 	ZFS_AC_KERNEL_SRC_PERCPU
- 	ZFS_AC_KERNEL_SRC_CPU_HOTPLUG
--	ZFS_AC_KERNEL_SRC_GENERIC_FILLATTR_USERNS
-+	ZFS_AC_KERNEL_SRC_GENERIC_FILLATTR
- 	ZFS_AC_KERNEL_SRC_MKNOD
- 	ZFS_AC_KERNEL_SRC_SYMLINK
- 	ZFS_AC_KERNEL_SRC_BIO_MAX_SEGS
-@@ -144,6 +145,15 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
- 	ZFS_AC_KERNEL_SRC_KTHREAD
- 	ZFS_AC_KERNEL_SRC_ZERO_PAGE
- 	ZFS_AC_KERNEL_SRC___COPY_FROM_USER_INATOMIC
-+	ZFS_AC_KERNEL_SRC_FILEMAP
-+	ZFS_AC_KERNEL_SRC_WRITEPAGE_T
-+	ZFS_AC_KERNEL_SRC_RECLAIMED
-+	case "$host_cpu" in
-+		powerpc*)
-+			ZFS_AC_KERNEL_SRC_CPU_HAS_FEATURE
-+			ZFS_AC_KERNEL_SRC_FLUSH_DCACHE_PAGE
-+			;;
-+	esac
- 
- 	AC_MSG_CHECKING([for available kernel interfaces])
- 	ZFS_LINUX_TEST_COMPILE_ALL([kabi])
-@@ -186,6 +196,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
- 	ZFS_AC_KERNEL_INODE_OWNER_OR_CAPABLE
- 	ZFS_AC_KERNEL_XATTR
- 	ZFS_AC_KERNEL_ACL
-+	ZFS_AC_KERNEL_INODE_SETATTR
- 	ZFS_AC_KERNEL_INODE_GETATTR
- 	ZFS_AC_KERNEL_INODE_SET_FLAGS
- 	ZFS_AC_KERNEL_INODE_SET_IVERSION
-@@ -247,7 +258,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
- 	ZFS_AC_KERNEL_KSTRTOUL
- 	ZFS_AC_KERNEL_PERCPU
- 	ZFS_AC_KERNEL_CPU_HOTPLUG
--	ZFS_AC_KERNEL_GENERIC_FILLATTR_USERNS
-+	ZFS_AC_KERNEL_GENERIC_FILLATTR
- 	ZFS_AC_KERNEL_MKNOD
- 	ZFS_AC_KERNEL_SYMLINK
- 	ZFS_AC_KERNEL_BIO_MAX_SEGS
-@@ -261,6 +272,15 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
- 	ZFS_AC_KERNEL_KTHREAD
- 	ZFS_AC_KERNEL_ZERO_PAGE
- 	ZFS_AC_KERNEL___COPY_FROM_USER_INATOMIC
-+	ZFS_AC_KERNEL_FILEMAP
-+	ZFS_AC_KERNEL_WRITEPAGE_T
-+	ZFS_AC_KERNEL_RECLAIMED
-+	case "$host_cpu" in
-+		powerpc*)
-+			ZFS_AC_KERNEL_CPU_HAS_FEATURE
-+			ZFS_AC_KERNEL_FLUSH_DCACHE_PAGE
-+			;;
-+	esac
- ])
- 
- dnl #
-diff --git a/config/zfs-build.m4 b/config/zfs-build.m4
-index 2ab6765c3..9390812cd 100644
---- a/config/zfs-build.m4
-+++ b/config/zfs-build.m4
-@@ -81,7 +81,7 @@ AC_DEFUN([ZFS_AC_DEBUG], [
- AC_DEFUN([ZFS_AC_DEBUGINFO_ENABLE], [
- 	DEBUG_CFLAGS="$DEBUG_CFLAGS -g -fno-inline $NO_IPA_SRA"
- 
--	KERNEL_DEBUG_CFLAGS="$KERNEL_DEBUG_CFLAGS -fno-inline $NO_IPA_SRA"
-+	KERNEL_DEBUG_CFLAGS="$KERNEL_DEBUG_CFLAGS -fno-inline $KERNEL_NO_IPA_SRA"
- 	KERNEL_MAKE="$KERNEL_MAKE CONFIG_DEBUG_INFO=y"
- 
- 	DEBUGINFO_ZFS="_with_debuginfo"
-@@ -217,6 +217,7 @@ AC_DEFUN([ZFS_AC_CONFIG_ALWAYS], [
- 	ZFS_AC_CONFIG_ALWAYS_CC_NO_FORMAT_ZERO_LENGTH
- 	ZFS_AC_CONFIG_ALWAYS_CC_NO_OMIT_FRAME_POINTER
- 	ZFS_AC_CONFIG_ALWAYS_CC_NO_IPA_SRA
-+	ZFS_AC_CONFIG_ALWAYS_KERNEL_CC_NO_IPA_SRA
- 	ZFS_AC_CONFIG_ALWAYS_CC_ASAN
- 	ZFS_AC_CONFIG_ALWAYS_TOOLCHAIN_SIMD
- 	ZFS_AC_CONFIG_ALWAYS_SYSTEM
-diff --git a/configure.ac b/configure.ac
-index 2671434af..cb339ccd4 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -222,6 +222,7 @@ AC_CONFIG_FILES([
- 	tests/zfs-tests/cmd/mmap_exec/Makefile
- 	tests/zfs-tests/cmd/mmap_libaio/Makefile
- 	tests/zfs-tests/cmd/mmap_seek/Makefile
-+	tests/zfs-tests/cmd/mmap_sync/Makefile
- 	tests/zfs-tests/cmd/mmapwrite/Makefile
- 	tests/zfs-tests/cmd/nvlist_to_lua/Makefile
- 	tests/zfs-tests/cmd/randfree_file/Makefile
-diff --git a/contrib/initramfs/scripts/zfs b/contrib/initramfs/scripts/zfs
-index 4ce739fda..3c51b53ee 100644
---- a/contrib/initramfs/scripts/zfs
-+++ b/contrib/initramfs/scripts/zfs
-@@ -326,7 +326,7 @@ mount_fs()
- 
- 	# Need the _original_ datasets mountpoint!
- 	mountpoint=$(get_fs_value "$fs" mountpoint)
--	ZFS_CMD="mount.zfs -o zfsutil"
-+	ZFS_CMD="mount -o zfsutil -t zfs"
- 	if [ "$mountpoint" = "legacy" ] || [ "$mountpoint" = "none" ]; then
- 		# Can't use the mountpoint property. Might be one of our
- 		# clones. Check the 'org.zol:mountpoint' property set in
-@@ -343,7 +343,7 @@ mount_fs()
- 			fi
- 			# Don't use mount.zfs -o zfsutils for legacy mountpoint
- 			if [ "$mountpoint" = "legacy" ]; then
--				ZFS_CMD="mount.zfs"
-+				ZFS_CMD="mount -t zfs"
- 			fi
- 			# Last hail-mary: Hope 'rootmnt' is set!
- 			mountpoint=""
-@@ -914,7 +914,7 @@ mountroot()
- 		echo "       not specified on the kernel command line."
- 		echo ""
- 		echo "Manually mount the root filesystem on $rootmnt and then exit."
--		echo "Hint: Try:  mount.zfs -o zfsutil ${ZFS_RPOOL-rpool}/ROOT/system $rootmnt"
-+		echo "Hint: Try:  mount -o zfsutil -t zfs ${ZFS_RPOOL-rpool}/ROOT/system $rootmnt"
- 		shell
- 	fi
- 
-diff --git a/contrib/pam_zfs_key/pam_zfs_key.c b/contrib/pam_zfs_key/pam_zfs_key.c
-index 0db119382..313703770 100644
---- a/contrib/pam_zfs_key/pam_zfs_key.c
-+++ b/contrib/pam_zfs_key/pam_zfs_key.c
-@@ -548,16 +548,11 @@ zfs_key_config_modify_session_counter(pam_handle_t *pamh,
- 		    errno);
- 		return (-1);
- 	}
--	size_t runtime_path_len = strlen(runtime_path);
--	size_t counter_path_len = runtime_path_len + 1 + 10;
--	char *counter_path = malloc(counter_path_len + 1);
--	if (!counter_path) {
-+
-+	char *counter_path;
-+	if (asprintf(&counter_path, "%s/%u", runtime_path, config->uid) == -1)
- 		return (-1);
--	}
--	counter_path[0] = 0;
--	strcat(counter_path, runtime_path);
--	snprintf(counter_path + runtime_path_len, counter_path_len, "/%d",
--	    config->uid);
-+
- 	const int fd = open(counter_path,
- 	    O_RDWR | O_CLOEXEC | O_CREAT | O_NOFOLLOW,
- 	    S_IRUSR | S_IWUSR);
-diff --git a/include/os/freebsd/zfs/sys/zfs_znode_impl.h b/include/os/freebsd/zfs/sys/zfs_znode_impl.h
-index 3d93525b4..120884116 100644
---- a/include/os/freebsd/zfs/sys/zfs_znode_impl.h
-+++ b/include/os/freebsd/zfs/sys/zfs_znode_impl.h
-@@ -118,7 +118,8 @@ extern minor_t zfsdev_minor_alloc(void);
- #define	Z_ISLNK(type) ((type) == VLNK)
- #define	Z_ISDIR(type) ((type) == VDIR)
- 
--#define	zn_has_cached_data(zp)		vn_has_cached_data(ZTOV(zp))
-+#define	zn_has_cached_data(zp, start, end) \
-+    vn_has_cached_data(ZTOV(zp))
- #define	zn_flush_cached_data(zp, sync)	vn_flush_cached_data(ZTOV(zp), sync)
- #define	zn_rlimit_fsize(zp, uio) \
-     vn_rlimit_fsize(ZTOV(zp), GET_UIO_STRUCT(uio), zfs_uio_td(uio))
-diff --git a/include/os/linux/kernel/linux/dcache_compat.h b/include/os/linux/kernel/linux/dcache_compat.h
-index c90135fd3..f87f1653a 100644
---- a/include/os/linux/kernel/linux/dcache_compat.h
-+++ b/include/os/linux/kernel/linux/dcache_compat.h
-@@ -39,6 +39,21 @@
- #define	d_alias			d_u.d_alias
- #endif
- 
-+/*
-+ * Starting from Linux 5.13, flush_dcache_page() becomes an inline function
-+ * and under some configurations, may indirectly referencing GPL-only
-+ * cpu_feature_keys on powerpc. Override this function when it is detected
-+ * being GPL-only.
-+ */
-+#if defined __powerpc__ && defined HAVE_FLUSH_DCACHE_PAGE_GPL_ONLY
-+#include <linux/simd_powerpc.h>
-+#define	flush_dcache_page(page)	do {					\
-+		if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE) &&	\
-+		    test_bit(PG_dcache_clean, &(page)->flags))		\
-+			clear_bit(PG_dcache_clean, &(page)->flags);	\
-+	} while (0)
-+#endif
-+
- /*
-  * 2.6.30 API change,
-  * The const keyword was added to the 'struct dentry_operations' in
-diff --git a/include/os/linux/kernel/linux/simd_powerpc.h b/include/os/linux/kernel/linux/simd_powerpc.h
-index 108cef22f..422b85af3 100644
---- a/include/os/linux/kernel/linux/simd_powerpc.h
-+++ b/include/os/linux/kernel/linux/simd_powerpc.h
-@@ -76,6 +76,17 @@
- #define	kfpu_init()		0
- #define	kfpu_fini()		((void) 0)
- 
-+/*
-+ * Linux 4.7 makes cpu_has_feature to use jump labels on powerpc if
-+ * CONFIG_JUMP_LABEL_FEATURE_CHECKS is enabled, in this case however it
-+ * references GPL-only symbol cpu_feature_keys. Therefore we overrides this
-+ * interface when it is detected being GPL-only.
-+ */
-+#if defined(CONFIG_JUMP_LABEL_FEATURE_CHECKS) && \
-+    defined(HAVE_CPU_HAS_FEATURE_GPL_ONLY)
-+#define	cpu_has_feature(feature)	early_cpu_has_feature(feature)
-+#endif
-+
- /*
-  * Check if AltiVec instruction set is available
-  */
-diff --git a/include/os/linux/kernel/linux/vfs_compat.h b/include/os/linux/kernel/linux/vfs_compat.h
-index 91e908598..e82bbf755 100644
---- a/include/os/linux/kernel/linux/vfs_compat.h
-+++ b/include/os/linux/kernel/linux/vfs_compat.h
-@@ -344,7 +344,8 @@ static inline void zfs_gid_write(struct inode *ip, gid_t gid)
-  * 4.9 API change
-  */
- #if !(defined(HAVE_SETATTR_PREPARE_NO_USERNS) || \
--    defined(HAVE_SETATTR_PREPARE_USERNS))
-+    defined(HAVE_SETATTR_PREPARE_USERNS) || \
-+    defined(HAVE_SETATTR_PREPARE_IDMAP))
- static inline int
- setattr_prepare(struct dentry *dentry, struct iattr *ia)
- {
-@@ -399,6 +400,15 @@ func(struct user_namespace *user_ns, const struct path *path,	\
- 	return (func##_impl(user_ns, path, stat, request_mask, \
- 	    query_flags));	\
- }
-+#elif defined(HAVE_IDMAP_IOPS_GETATTR)
-+#define	ZPL_GETATTR_WRAPPER(func)					\
-+static int								\
-+func(struct mnt_idmap *user_ns, const struct path *path,	\
-+    struct kstat *stat, u32 request_mask, unsigned int query_flags)	\
-+{									\
-+	return (func##_impl(user_ns, path, stat, request_mask,	\
-+	    query_flags));	\
-+}
- #else
- #error
- #endif
-@@ -450,8 +460,15 @@ zpl_is_32bit_api(void)
-  * 5.12 API change
-  * To support id-mapped mounts, generic_fillattr() was modified to
-  * accept a new struct user_namespace* as its first arg.
-+ *
-+ * 6.3 API change
-+ * generic_fillattr() first arg is changed to struct mnt_idmap *
-+ *
-  */
--#ifdef HAVE_GENERIC_FILLATTR_USERNS
-+#ifdef HAVE_GENERIC_FILLATTR_IDMAP
-+#define	zpl_generic_fillattr(idmap, ip, sp)	\
-+    generic_fillattr(idmap, ip, sp)
-+#elif defined(HAVE_GENERIC_FILLATTR_USERNS)
- #define	zpl_generic_fillattr(user_ns, ip, sp)	\
-     generic_fillattr(user_ns, ip, sp)
- #else
-diff --git a/include/os/linux/kernel/linux/xattr_compat.h b/include/os/linux/kernel/linux/xattr_compat.h
-index 30403fe87..3ffd00169 100644
---- a/include/os/linux/kernel/linux/xattr_compat.h
-+++ b/include/os/linux/kernel/linux/xattr_compat.h
-@@ -133,20 +133,35 @@ fn(const struct xattr_handler *handler, struct dentry *dentry,		\
- #error "Unsupported kernel"
- #endif
- 
-+/*
-+ * 6.3 API change,
-+ * The xattr_handler->set() callback was changed to take the
-+ * struct mnt_idmap* as the first arg, to support idmapped
-+ * mounts.
-+ */
-+#if defined(HAVE_XATTR_SET_IDMAP)
-+#define	ZPL_XATTR_SET_WRAPPER(fn)					\
-+static int								\
-+fn(const struct xattr_handler *handler, struct mnt_idmap *user_ns,	\
-+    struct dentry *dentry, struct inode *inode, const char *name,	\
-+    const void *buffer, size_t size, int flags)	\
-+{									\
-+	return (__ ## fn(user_ns, inode, name, buffer, size, flags));	\
-+}
- /*
-  * 5.12 API change,
-  * The xattr_handler->set() callback was changed to take the
-  * struct user_namespace* as the first arg, to support idmapped
-  * mounts.
-  */
--#if defined(HAVE_XATTR_SET_USERNS)
-+#elif defined(HAVE_XATTR_SET_USERNS)
- #define	ZPL_XATTR_SET_WRAPPER(fn)					\
- static int								\
- fn(const struct xattr_handler *handler, struct user_namespace *user_ns, \
-     struct dentry *dentry, struct inode *inode, const char *name,	\
-     const void *buffer, size_t size, int flags)	\
- {									\
--	return (__ ## fn(inode, name, buffer, size, flags));		\
-+	return (__ ## fn(user_ns, inode, name, buffer, size, flags));	\
- }
- /*
-  * 4.7 API change,
-@@ -160,7 +175,7 @@ fn(const struct xattr_handler *handler, struct dentry *dentry,		\
-     struct inode *inode, const char *name, const void *buffer,		\
-     size_t size, int flags)						\
- {									\
--	return (__ ## fn(inode, name, buffer, size, flags));		\
-+	return (__ ## fn(kcred->user_ns, inode, name, buffer, size, flags));\
- }
- /*
-  * 4.4 API change,
-@@ -174,7 +189,8 @@ static int								\
- fn(const struct xattr_handler *handler, struct dentry *dentry,		\
-     const char *name, const void *buffer, size_t size, int flags)	\
- {									\
--	return (__ ## fn(dentry->d_inode, name, buffer, size, flags));	\
-+	return (__ ## fn(kcred->user_ns, dentry->d_inode, name,		\
-+	    buffer, size, flags));					\
- }
- /*
-  * 2.6.33 API change,
-@@ -187,7 +203,8 @@ static int								\
- fn(struct dentry *dentry, const char *name, const void *buffer,		\
-     size_t size, int flags, int unused_handler_flags)			\
- {									\
--	return (__ ## fn(dentry->d_inode, name, buffer, size, flags));	\
-+	return (__ ## fn(kcred->user_ns, dentry->d_inode, name, buffer, \
-+	    size, flags));						\
- }
- #else
- #error "Unsupported kernel"
-diff --git a/include/os/linux/spl/sys/cred.h b/include/os/linux/spl/sys/cred.h
-index b7d3f38d7..501bd4566 100644
---- a/include/os/linux/spl/sys/cred.h
-+++ b/include/os/linux/spl/sys/cred.h
-@@ -45,6 +45,8 @@ typedef struct cred cred_t;
- #define	SGID_TO_KGID(x)		(KGIDT_INIT(x))
- #define	KGIDP_TO_SGIDP(x)	(&(x)->val)
- 
-+extern zidmap_t *zfs_get_init_idmap(void);
-+
- extern void crhold(cred_t *cr);
- extern void crfree(cred_t *cr);
- extern uid_t crgetuid(const cred_t *cr);
-diff --git a/include/os/linux/spl/sys/types.h b/include/os/linux/spl/sys/types.h
-index b44c94518..4d638efbb 100644
---- a/include/os/linux/spl/sys/types.h
-+++ b/include/os/linux/spl/sys/types.h
-@@ -54,4 +54,18 @@ typedef ulong_t			pgcnt_t;
- typedef int			major_t;
- typedef int			minor_t;
- 
-+struct user_namespace;
-+#ifdef HAVE_IOPS_CREATE_IDMAP
-+#include <linux/refcount.h>
-+struct mnt_idmap {
-+	struct user_namespace *owner;
-+	refcount_t count;
-+};
-+typedef struct mnt_idmap	zidmap_t;
-+#else
-+typedef struct user_namespace	zidmap_t;
-+#endif
-+
-+extern zidmap_t *zfs_init_idmap;
-+
- #endif	/* _SPL_TYPES_H */
-diff --git a/include/os/linux/zfs/sys/trace_acl.h b/include/os/linux/zfs/sys/trace_acl.h
-index 21bcefa4e..656552749 100644
---- a/include/os/linux/zfs/sys/trace_acl.h
-+++ b/include/os/linux/zfs/sys/trace_acl.h
-@@ -58,9 +58,10 @@ DECLARE_EVENT_CLASS(zfs_ace_class,
- 	    __field(uint64_t,		z_size)
- 	    __field(uint64_t,		z_pflags)
- 	    __field(uint32_t,		z_sync_cnt)
-+	    __field(uint32_t,		z_sync_writes_cnt)
-+	    __field(uint32_t,		z_async_writes_cnt)
- 	    __field(mode_t,		z_mode)
- 	    __field(boolean_t,		z_is_sa)
--	    __field(boolean_t,		z_is_mapped)
- 	    __field(boolean_t,		z_is_ctldir)
- 
- 	    __field(uint32_t,		i_uid)
-@@ -90,9 +91,10 @@ DECLARE_EVENT_CLASS(zfs_ace_class,
- 	    __entry->z_size		= zn->z_size;
- 	    __entry->z_pflags		= zn->z_pflags;
- 	    __entry->z_sync_cnt		= zn->z_sync_cnt;
-+	    __entry->z_sync_writes_cnt	= zn->z_sync_writes_cnt;
-+	    __entry->z_async_writes_cnt	= zn->z_async_writes_cnt;
- 	    __entry->z_mode		= zn->z_mode;
- 	    __entry->z_is_sa		= zn->z_is_sa;
--	    __entry->z_is_mapped	= zn->z_is_mapped;
- 	    __entry->z_is_ctldir	= zn->z_is_ctldir;
- 
- 	    __entry->i_uid		= KUID_TO_SUID(ZTOI(zn)->i_uid);
-@@ -114,18 +116,18 @@ DECLARE_EVENT_CLASS(zfs_ace_class,
- 	TP_printk("zn { id %llu unlinked %u atime_dirty %u "
- 	    "zn_prefetch %u blksz %u seq %u "
- 	    "mapcnt %llu size %llu pflags %llu "
--	    "sync_cnt %u mode 0x%x is_sa %d "
--	    "is_mapped %d is_ctldir %d inode { "
--	    "uid %u gid %u ino %lu nlink %u size %lli "
-+	    "sync_cnt %u sync_writes_cnt %u async_writes_cnt %u "
-+	    "mode 0x%x is_sa %d is_ctldir %d "
-+	    "inode { uid %u gid %u ino %lu nlink %u size %lli "
- 	    "blkbits %u bytes %u mode 0x%x generation %x } } "
- 	    "ace { type %u flags %u access_mask %u } mask_matched %u",
- 	    __entry->z_id, __entry->z_unlinked, __entry->z_atime_dirty,
- 	    __entry->z_zn_prefetch, __entry->z_blksz,
- 	    __entry->z_seq, __entry->z_mapcnt, __entry->z_size,
--	    __entry->z_pflags, __entry->z_sync_cnt, __entry->z_mode,
--	    __entry->z_is_sa, __entry->z_is_mapped,
--	    __entry->z_is_ctldir, __entry->i_uid,
--	    __entry->i_gid, __entry->i_ino, __entry->i_nlink,
-+	    __entry->z_pflags, __entry->z_sync_cnt,
-+	    __entry->z_sync_writes_cnt, __entry->z_async_writes_cnt,
-+	    __entry->z_mode, __entry->z_is_sa, __entry->z_is_ctldir,
-+	    __entry->i_uid, __entry->i_gid, __entry->i_ino, __entry->i_nlink,
- 	    __entry->i_size, __entry->i_blkbits,
- 	    __entry->i_bytes, __entry->i_mode, __entry->i_generation,
- 	    __entry->z_type, __entry->z_flags, __entry->z_access_mask,
-diff --git a/include/os/linux/zfs/sys/zfs_vnops_os.h b/include/os/linux/zfs/sys/zfs_vnops_os.h
-index 47f91e4a6..331f2e2bc 100644
---- a/include/os/linux/zfs/sys/zfs_vnops_os.h
-+++ b/include/os/linux/zfs/sys/zfs_vnops_os.h
-@@ -54,8 +54,7 @@ extern int zfs_mkdir(znode_t *dzp, char *dirname, vattr_t *vap,
- extern int zfs_rmdir(znode_t *dzp, char *name, znode_t *cwd,
-     cred_t *cr, int flags);
- extern int zfs_readdir(struct inode *ip, zpl_dir_context_t *ctx, cred_t *cr);
--extern int zfs_getattr_fast(struct user_namespace *, struct inode *ip,
--	struct kstat *sp);
-+extern int zfs_getattr_fast(zidmap_t *, struct inode *ip, struct kstat *sp);
- extern int zfs_setattr(znode_t *zp, vattr_t *vap, int flag, cred_t *cr);
- extern int zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp,
-     char *tnm, cred_t *cr, int flags);
-@@ -68,9 +67,9 @@ extern void zfs_inactive(struct inode *ip);
- extern int zfs_space(znode_t *zp, int cmd, flock64_t *bfp, int flag,
-     offset_t offset, cred_t *cr);
- extern int zfs_fid(struct inode *ip, fid_t *fidp);
--extern int zfs_getpage(struct inode *ip, struct page *pl[], int nr_pages);
-+extern int zfs_getpage(struct inode *ip, struct page *pp);
- extern int zfs_putpage(struct inode *ip, struct page *pp,
--    struct writeback_control *wbc);
-+    struct writeback_control *wbc, boolean_t for_sync);
- extern int zfs_dirty_inode(struct inode *ip, int flags);
- extern int zfs_map(struct inode *ip, offset_t off, caddr_t *addrp,
-     size_t len, unsigned long vm_flags);
-diff --git a/include/os/linux/zfs/sys/zfs_znode_impl.h b/include/os/linux/zfs/sys/zfs_znode_impl.h
-index de46fc8f2..9b9ac7a4f 100644
---- a/include/os/linux/zfs/sys/zfs_znode_impl.h
-+++ b/include/os/linux/zfs/sys/zfs_znode_impl.h
-@@ -47,9 +47,16 @@
- extern "C" {
- #endif
- 
-+#if defined(HAVE_FILEMAP_RANGE_HAS_PAGE)
- #define	ZNODE_OS_FIELDS			\
- 	inode_timespec_t z_btime; /* creation/birth time (cached) */ \
- 	struct inode	z_inode;
-+#else
-+#define	ZNODE_OS_FIELDS			\
-+	inode_timespec_t z_btime; /* creation/birth time (cached) */ \
-+	struct inode	z_inode;                                     \
-+	boolean_t	z_is_mapped;    /* we are mmap'ed */
-+#endif
- 
- /*
-  * Convert between znode pointers and inode pointers
-@@ -70,7 +77,14 @@ extern "C" {
- #define	Z_ISDEV(type)	(S_ISCHR(type) || S_ISBLK(type) || S_ISFIFO(type))
- #define	Z_ISDIR(type)	S_ISDIR(type)
- 
--#define	zn_has_cached_data(zp)		((zp)->z_is_mapped)
-+#if defined(HAVE_FILEMAP_RANGE_HAS_PAGE)
-+#define	zn_has_cached_data(zp, start, end) \
-+	filemap_range_has_page(ZTOI(zp)->i_mapping, start, end)
-+#else
-+#define	zn_has_cached_data(zp, start, end) \
-+	((zp)->z_is_mapped)
-+#endif
-+
- #define	zn_flush_cached_data(zp, sync)	write_inode_now(ZTOI(zp), sync)
- #define	zn_rlimit_fsize(zp, uio)	(0)
- 
-diff --git a/include/os/linux/zfs/sys/zpl.h b/include/os/linux/zfs/sys/zpl.h
-index ac9815d4e..4e08470e7 100644
---- a/include/os/linux/zfs/sys/zpl.h
-+++ b/include/os/linux/zfs/sys/zpl.h
-@@ -64,7 +64,10 @@ extern int zpl_xattr_security_init(struct inode *ip, struct inode *dip,
-     const struct qstr *qstr);
- #if defined(CONFIG_FS_POSIX_ACL)
- #if defined(HAVE_SET_ACL)
--#if defined(HAVE_SET_ACL_USERNS)
-+#if defined(HAVE_SET_ACL_IDMAP_DENTRY)
-+extern int zpl_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
-+    struct posix_acl *acl, int type);
-+#elif defined(HAVE_SET_ACL_USERNS)
- extern int zpl_set_acl(struct user_namespace *userns, struct inode *ip,
-     struct posix_acl *acl, int type);
- #elif defined(HAVE_SET_ACL_USERNS_DENTRY_ARG2)
-@@ -186,13 +189,15 @@ zpl_dir_emit_dots(struct file *file, zpl_dir_context_t *ctx)
- 
- #if defined(HAVE_INODE_OWNER_OR_CAPABLE)
- #define	zpl_inode_owner_or_capable(ns, ip)	inode_owner_or_capable(ip)
--#elif defined(HAVE_INODE_OWNER_OR_CAPABLE_IDMAPPED)
-+#elif defined(HAVE_INODE_OWNER_OR_CAPABLE_USERNS)
- #define	zpl_inode_owner_or_capable(ns, ip)	inode_owner_or_capable(ns, ip)
-+#elif defined(HAVE_INODE_OWNER_OR_CAPABLE_IDMAP)
-+#define	zpl_inode_owner_or_capable(idmap, ip) inode_owner_or_capable(idmap, ip)
- #else
- #error "Unsupported kernel"
- #endif
- 
--#ifdef HAVE_SETATTR_PREPARE_USERNS
-+#if defined(HAVE_SETATTR_PREPARE_USERNS) || defined(HAVE_SETATTR_PREPARE_IDMAP)
- #define	zpl_setattr_prepare(ns, dentry, ia)	setattr_prepare(ns, dentry, ia)
- #else
- /*
-diff --git a/include/sys/dmu.h b/include/sys/dmu.h
-index 7bdd42e8b..12bd88720 100644
---- a/include/sys/dmu.h
-+++ b/include/sys/dmu.h
-@@ -778,6 +778,9 @@ dmu_tx_t *dmu_tx_create(objset_t *os);
- void dmu_tx_hold_write(dmu_tx_t *tx, uint64_t object, uint64_t off, int len);
- void dmu_tx_hold_write_by_dnode(dmu_tx_t *tx, dnode_t *dn, uint64_t off,
-     int len);
-+void dmu_tx_hold_append(dmu_tx_t *tx, uint64_t object, uint64_t off, int len);
-+void dmu_tx_hold_append_by_dnode(dmu_tx_t *tx, dnode_t *dn, uint64_t off,
-+    int len);
- void dmu_tx_hold_free(dmu_tx_t *tx, uint64_t object, uint64_t off,
-     uint64_t len);
- void dmu_tx_hold_free_by_dnode(dmu_tx_t *tx, dnode_t *dn, uint64_t off,
-diff --git a/include/sys/dmu_objset.h b/include/sys/dmu_objset.h
-index 7ade2dc91..fffcbcfca 100644
---- a/include/sys/dmu_objset.h
-+++ b/include/sys/dmu_objset.h
-@@ -72,6 +72,10 @@ struct dmu_tx;
-  */
- #define	OBJSET_CRYPT_PORTABLE_FLAGS_MASK	(0)
- 
-+#if defined(__clang__)
-+#pragma clang diagnostic push
-+#pragma clang diagnostic ignored "-Wgnu-variable-sized-type-not-at-end"
-+#endif
- typedef struct objset_phys {
- 	dnode_phys_t os_meta_dnode;
- 	zil_header_t os_zil_header;
-@@ -88,6 +92,9 @@ typedef struct objset_phys {
- 	char os_pad1[OBJSET_PHYS_SIZE_V3 - OBJSET_PHYS_SIZE_V2 -
- 	    sizeof (dnode_phys_t)];
- } objset_phys_t;
-+#if defined(__clang__)
-+#pragma clang diagnostic pop
-+#endif
- 
- typedef int (*dmu_objset_upgrade_cb_t)(objset_t *);
- 
-diff --git a/include/sys/dmu_tx.h b/include/sys/dmu_tx.h
-index ad3f1b0e4..e8886fd4e 100644
---- a/include/sys/dmu_tx.h
-+++ b/include/sys/dmu_tx.h
-@@ -90,6 +90,7 @@ enum dmu_tx_hold_type {
- 	THT_ZAP,
- 	THT_SPACE,
- 	THT_SPILL,
-+	THT_APPEND,
- 	THT_NUMTYPES
- };
- 
-diff --git a/include/sys/dnode.h b/include/sys/dnode.h
-index 20b7c2aaf..39bbdae44 100644
---- a/include/sys/dnode.h
-+++ b/include/sys/dnode.h
-@@ -120,7 +120,11 @@ extern "C" {
- #define	DN_MAX_LEVELS	(DIV_ROUND_UP(DN_MAX_OFFSET_SHIFT - SPA_MINBLOCKSHIFT, \
- 	DN_MIN_INDBLKSHIFT - SPA_BLKPTRSHIFT) + 1)
- 
--#define	DN_BONUS(dnp)	((void*)((dnp)->dn_bonus + \
-+/*
-+ * Use the flexible array instead of the fixed length one dn_bonus
-+ * to address memcpy/memmove fortify error
-+ */
-+#define	DN_BONUS(dnp)	((void*)((dnp)->dn_bonus_flexible + \
- 	(((dnp)->dn_nblkptr - 1) * sizeof (blkptr_t))))
- #define	DN_MAX_BONUS_LEN(dnp) \
- 	((dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR) ? \
-@@ -266,6 +270,10 @@ typedef struct dnode_phys {
- 			    sizeof (blkptr_t)];
- 			blkptr_t dn_spill;
- 		};
-+		struct {
-+			blkptr_t __dn_ignore4;
-+			uint8_t dn_bonus_flexible[];
-+		};
- 	};
- } dnode_phys_t;
- 
-diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h
-index 111e70ece..84f5aee59 100644
---- a/include/sys/fs/zfs.h
-+++ b/include/sys/fs/zfs.h
-@@ -1173,6 +1173,7 @@ typedef enum pool_initialize_func {
- 	POOL_INITIALIZE_START,
- 	POOL_INITIALIZE_CANCEL,
- 	POOL_INITIALIZE_SUSPEND,
-+	POOL_INITIALIZE_UNINIT,
- 	POOL_INITIALIZE_FUNCS
- } pool_initialize_func_t;
- 
-diff --git a/include/sys/spa.h b/include/sys/spa.h
-index fedadab45..42f7fec0f 100644
---- a/include/sys/spa.h
-+++ b/include/sys/spa.h
-@@ -785,6 +785,7 @@ extern int bpobj_enqueue_free_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx);
- #define	SPA_ASYNC_L2CACHE_REBUILD		0x800
- #define	SPA_ASYNC_L2CACHE_TRIM			0x1000
- #define	SPA_ASYNC_REBUILD_DONE			0x2000
-+#define	SPA_ASYNC_DETACH_SPARE			0x4000
- 
- /* device manipulation */
- extern int spa_vdev_add(spa_t *spa, nvlist_t *nvroot);
-@@ -971,6 +972,8 @@ extern int spa_import_progress_set_state(uint64_t pool_guid,
- /* Pool configuration locks */
- extern int spa_config_tryenter(spa_t *spa, int locks, void *tag, krw_t rw);
- extern void spa_config_enter(spa_t *spa, int locks, const void *tag, krw_t rw);
-+extern void spa_config_enter_mmp(spa_t *spa, int locks, const void *tag,
-+    krw_t rw);
- extern void spa_config_exit(spa_t *spa, int locks, const void *tag);
- extern int spa_config_held(spa_t *spa, int locks, krw_t rw);
- 
-diff --git a/include/sys/vdev_initialize.h b/include/sys/vdev_initialize.h
-index 81d39ebeb..942fc71c5 100644
---- a/include/sys/vdev_initialize.h
-+++ b/include/sys/vdev_initialize.h
-@@ -33,6 +33,7 @@ extern "C" {
- #endif
- 
- extern void vdev_initialize(vdev_t *vd);
-+extern void vdev_uninitialize(vdev_t *vd);
- extern void vdev_initialize_stop(vdev_t *vd,
-     vdev_initializing_state_t tgt_state, list_t *vd_list);
- extern void vdev_initialize_stop_all(vdev_t *vd,
-diff --git a/include/sys/zfs_znode.h b/include/sys/zfs_znode.h
-index 0df8a0e4b..48dab671d 100644
---- a/include/sys/zfs_znode.h
-+++ b/include/sys/zfs_znode.h
-@@ -188,7 +188,6 @@ typedef struct znode {
- 	boolean_t	z_atime_dirty;	/* atime needs to be synced */
- 	boolean_t	z_zn_prefetch;	/* Prefetch znodes? */
- 	boolean_t	z_is_sa;	/* are we native sa? */
--	boolean_t	z_is_mapped;	/* are we mmap'ed */
- 	boolean_t	z_is_ctldir;	/* are we .zfs entry */
- 	boolean_t	z_suspended;	/* extra ref from a suspend? */
- 	uint_t		z_blksz;	/* block size in bytes */
-@@ -198,6 +197,8 @@ typedef struct znode {
- 	uint64_t	z_size;		/* file size (cached) */
- 	uint64_t	z_pflags;	/* pflags (cached) */
- 	uint32_t	z_sync_cnt;	/* synchronous open count */
-+	uint32_t	z_sync_writes_cnt; /* synchronous write count */
-+	uint32_t	z_async_writes_cnt; /* asynchronous write count */
- 	mode_t		z_mode;		/* mode (cached) */
- 	kmutex_t	z_acl_lock;	/* acl data lock */
- 	zfs_acl_t	*z_acl_cached;	/* cached acl */
-diff --git a/lib/libzfs/libzfs.abi b/lib/libzfs/libzfs.abi
-index 13ce19df9..58c2d7635 100644
---- a/lib/libzfs/libzfs.abi
-+++ b/lib/libzfs/libzfs.abi
-@@ -5410,7 +5410,8 @@
-       <enumerator name='POOL_INITIALIZE_START' value='0'/>
-       <enumerator name='POOL_INITIALIZE_CANCEL' value='1'/>
-       <enumerator name='POOL_INITIALIZE_SUSPEND' value='2'/>
--      <enumerator name='POOL_INITIALIZE_FUNCS' value='3'/>
-+      <enumerator name='POOL_INITIALIZE_UNINIT' value='3'/>
-+      <enumerator name='POOL_INITIALIZE_FUNCS' value='4'/>
-     </enum-decl>
-     <typedef-decl name='pool_initialize_func_t' type-id='5c246ad4' id='7063e1ab'/>
-     <enum-decl name='pool_trim_func' id='54ed608a'>
-diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c
-index f2219d1c3..f6d844bdf 100644
---- a/lib/libzfs/libzfs_dataset.c
-+++ b/lib/libzfs/libzfs_dataset.c
-@@ -1017,6 +1017,7 @@ zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
- 	nvlist_t *ret;
- 	int chosen_normal = -1;
- 	int chosen_utf = -1;
-+	int set_maxbs = 0;
- 
- 	if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) {
- 		(void) no_memory(hdl);
-@@ -1234,12 +1235,17 @@ zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
- 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
- 				goto error;
- 			}
-+			/* save the ZFS_PROP_RECORDSIZE during create op */
-+			if (zpool_hdl == NULL && prop == ZFS_PROP_RECORDSIZE) {
-+				set_maxbs = intval;
-+			}
- 			break;
- 		}
- 
- 		case ZFS_PROP_SPECIAL_SMALL_BLOCKS:
- 		{
--			int maxbs = SPA_OLD_MAXBLOCKSIZE;
-+			int maxbs =
-+			    set_maxbs == 0 ? SPA_OLD_MAXBLOCKSIZE : set_maxbs;
- 			char buf[64];
- 
- 			if (zpool_hdl != NULL) {
-diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c
-index 29f077841..fc6c6e8e2 100644
---- a/lib/libzfs/libzfs_pool.c
-+++ b/lib/libzfs/libzfs_pool.c
-@@ -2224,8 +2224,8 @@ xlate_init_err(int err)
- }
- 
- /*
-- * Begin, suspend, or cancel the initialization (initializing of all free
-- * blocks) for the given vdevs in the given pool.
-+ * Begin, suspend, cancel, or uninit (clear) the initialization (initializing
-+ * of all free blocks) for the given vdevs in the given pool.
-  */
- static int
- zpool_initialize_impl(zpool_handle_t *zhp, pool_initialize_func_t cmd_type,
-@@ -2251,11 +2251,16 @@ zpool_initialize_impl(zpool_handle_t *zhp, pool_initialize_func_t cmd_type,
- 	    vdev_guids, &errlist);
- 
- 	if (err != 0) {
--		if (errlist != NULL) {
--			vd_errlist = fnvlist_lookup_nvlist(errlist,
--			    ZPOOL_INITIALIZE_VDEVS);
-+		if (errlist != NULL && nvlist_lookup_nvlist(errlist,
-+		    ZPOOL_INITIALIZE_VDEVS, &vd_errlist) == 0) {
- 			goto list_errors;
- 		}
-+
-+		if (err == EINVAL && cmd_type == POOL_INITIALIZE_UNINIT) {
-+			zfs_error_aux(zhp->zpool_hdl, dgettext(TEXT_DOMAIN,
-+			    "uninitialize is not supported by kernel"));
-+		}
-+
- 		(void) zpool_standard_error(zhp->zpool_hdl, err,
- 		    dgettext(TEXT_DOMAIN, "operation failed"));
- 		goto out;
-diff --git a/lib/libzfs_core/libzfs_core.abi b/lib/libzfs_core/libzfs_core.abi
-index 1b03a5c42..7ede3e097 100644
---- a/lib/libzfs_core/libzfs_core.abi
-+++ b/lib/libzfs_core/libzfs_core.abi
-@@ -1726,7 +1726,8 @@
-       <enumerator name='POOL_INITIALIZE_START' value='0'/>
-       <enumerator name='POOL_INITIALIZE_CANCEL' value='1'/>
-       <enumerator name='POOL_INITIALIZE_SUSPEND' value='2'/>
--      <enumerator name='POOL_INITIALIZE_FUNCS' value='3'/>
-+      <enumerator name='POOL_INITIALIZE_UNINIT' value='3'/>
-+      <enumerator name='POOL_INITIALIZE_FUNCS' value='4'/>
-     </enum-decl>
-     <typedef-decl name='pool_initialize_func_t' type-id='5c246ad4' id='7063e1ab'/>
-     <enum-decl name='pool_trim_func' id='54ed608a'>
-diff --git a/man/man4/zfs.4 b/man/man4/zfs.4
-index 71a95c3bd..0c60a9c8e 100644
---- a/man/man4/zfs.4
-+++ b/man/man4/zfs.4
-@@ -1712,7 +1712,7 @@ completes in order to verify the checksums of all blocks which have been
- resilvered.
- This is enabled by default and strongly recommended.
- .
--.It Sy zfs_rebuild_vdev_limit Ns = Ns Sy 33554432 Ns B Po 32MB Pc Pq ulong
-+.It Sy zfs_rebuild_vdev_limit Ns = Ns Sy 67108864 Ns B Po 64 MiB Pc Pq ulong
- Maximum amount of I/O that can be concurrently issued for a sequential
- resilver per leaf device, given in bytes.
- .
-@@ -1831,6 +1831,13 @@ When we cross this limit from above it is because we are issuing verification I/
- In this case (unless the metadata scan is done) we stop issuing verification I/O
- and start scanning metadata again until we get to the hard limit.
- .
-+.It Sy zfs_scan_report_txgs Ns = Ns Sy 0 Ns | Ns 1 Pq uint
-+When reporting resilver throughput and estimated completion time use the
-+performance observed over roughly the last
-+.Sy zfs_scan_report_txgs
-+TXGs.
-+When set to zero performance is calculated over the time between checkpoints.
-+.
- .It Sy zfs_scan_strict_mem_lim Ns = Ns Sy 0 Ns | Ns 1 Pq int
- Enforce tight memory limits on pool scans when a sequential scan is in progress.
- When disabled, the memory limit may be exceeded by fast disks.
-@@ -1839,7 +1846,7 @@ When disabled, the memory limit may be exceeded by fast disks.
- Freezes a scrub/resilver in progress without actually pausing it.
- Intended for testing/debugging.
- .
--.It Sy zfs_scan_vdev_limit Ns = Ns Sy 4194304 Ns B Po 4MB Pc Pq int
-+.It Sy zfs_scan_vdev_limit Ns = Ns Sy 16777216 Ns B Po 16 MiB Pc Pq int
- Maximum amount of data that can be concurrently issued at once for scrubs and
- resilvers per leaf device, given in bytes.
- .
-diff --git a/man/man8/zpool-initialize.8 b/man/man8/zpool-initialize.8
-index 0a108180d..ada00bb1b 100644
---- a/man/man8/zpool-initialize.8
-+++ b/man/man8/zpool-initialize.8
-@@ -36,7 +36,7 @@
- .Sh SYNOPSIS
- .Nm zpool
- .Cm initialize
--.Op Fl c Ns | Ns Fl s
-+.Op Fl c Ns | Ns Fl s | Ns Fl u
- .Op Fl w
- .Ar pool
- .Oo Ar device Oc Ns …
-@@ -60,6 +60,14 @@ initialized, the command will fail and no suspension will occur on any device.
- Initializing can then be resumed by running
- .Nm zpool Cm initialize
- with no flags on the relevant target devices.
-+.It Fl u , -uninit
-+Clears the initialization state on the specified devices, or all eligible
-+devices if none are specified.
-+If the devices are being actively initialized the command will fail.
-+After being cleared
-+.Nm zpool Cm initialize
-+with no flags can be used to re-initialize all unallocoated regions on
-+the relevant target devices.
- .It Fl w , -wait
- Wait until the devices have finished initializing before returning.
- .El
-diff --git a/module/Kbuild.in b/module/Kbuild.in
-index 1507965c5..7675d614f 100644
---- a/module/Kbuild.in
-+++ b/module/Kbuild.in
-@@ -44,4 +44,5 @@ endif
- subdir-asflags-y := $(ZFS_MODULE_CFLAGS) $(ZFS_MODULE_CPPFLAGS)
- subdir-ccflags-y := $(ZFS_MODULE_CFLAGS) $(ZFS_MODULE_CPPFLAGS)
- 
-+
- endif
-diff --git a/module/icp/algs/edonr/edonr.c b/module/icp/algs/edonr/edonr.c
-index 7a3ba30c0..baf8bb885 100644
---- a/module/icp/algs/edonr/edonr.c
-+++ b/module/icp/algs/edonr/edonr.c
-@@ -343,9 +343,11 @@ Q256(size_t bitlen, const uint32_t *data, uint32_t *restrict p)
-  * which only goes over it by a hair (1248 bytes on ARM32).
-  */
- #include <sys/isa_defs.h>	/* for _ILP32 */
--#ifdef _ILP32   /* We're 32-bit, assume small stack frames */
-+#if defined(_ILP32)   /* We're 32-bit, assume small stack frames */
-+#if defined(__GNUC__) && !defined(__clang__)
- #pragma GCC diagnostic ignored "-Wframe-larger-than="
- #endif
-+#endif
- 
- #if defined(__IBMC__) && defined(_AIX) && defined(__64BIT__)
- static inline size_t
-diff --git a/module/icp/algs/skein/skein_block.c b/module/icp/algs/skein/skein_block.c
-index 7ba165a48..3ad52da5f 100644
---- a/module/icp/algs/skein/skein_block.c
-+++ b/module/icp/algs/skein/skein_block.c
-@@ -30,7 +30,9 @@
-  * the #pragma here to ignore the warning.
-  */
- #if defined(_ILP32) || defined(__powerpc)	/* Assume small stack */
-+#if defined(__GNUC__) && !defined(__clang__)
- #pragma GCC diagnostic ignored "-Wframe-larger-than="
-+#endif
- /*
-  * We're running on 32-bit, don't unroll loops to save stack frame space
-  *
-diff --git a/module/lua/ldo.c b/module/lua/ldo.c
-index a9835c4f5..e4abe04e9 100644
---- a/module/lua/ldo.c
-+++ b/module/lua/ldo.c
-@@ -197,7 +197,8 @@ l_noret luaD_throw (lua_State *L, int errcode) {
-   }
- }
- 
--#if defined(HAVE_INFINITE_RECURSION)
-+#if defined(__GNUC__) && !defined(__clang__) && \
-+	defined(HAVE_INFINITE_RECURSION)
- #pragma GCC diagnostic pop
- #endif
- 
-diff --git a/module/os/freebsd/zfs/zfs_ctldir.c b/module/os/freebsd/zfs/zfs_ctldir.c
-index 5bd2e1510..cfc4bab2f 100644
---- a/module/os/freebsd/zfs/zfs_ctldir.c
-+++ b/module/os/freebsd/zfs/zfs_ctldir.c
-@@ -204,6 +204,10 @@ sfs_vgetx(struct mount *mp, int flags, uint64_t parent_id, uint64_t id,
- 		return (error);
- 	}
- 
-+#if __FreeBSD_version >= 1400077
-+	vn_set_state(vp, VSTATE_CONSTRUCTED);
-+#endif
-+
- 	*vpp = vp;
- 	return (0);
- }
-@@ -675,6 +679,17 @@ zfsctl_root_readdir(struct vop_readdir_args *ap)
- 
- 	ASSERT3S(vp->v_type, ==, VDIR);
- 
-+	/*
-+	 * FIXME: this routine only ever emits 3 entries and does not tolerate
-+	 * being called with a buffer too small to handle all of them.
-+	 *
-+	 * The check below facilitates the idiom of repeating calls until the
-+	 * count to return is 0.
-+	 */
-+	if (zfs_uio_offset(&uio) == 3 * sizeof (entry)) {
-+		return (0);
-+	}
-+
- 	error = sfs_readdir_common(zfsvfs->z_root, ZFSCTL_INO_ROOT, ap, &uio,
- 	    &dots_offset);
- 	if (error != 0) {
-@@ -800,6 +815,9 @@ static struct vop_vector zfsctl_ops_root = {
- 	.vop_default =	&default_vnodeops,
- #if __FreeBSD_version >= 1300121
- 	.vop_fplookup_vexec = VOP_EAGAIN,
-+#endif
-+#if __FreeBSD_version >= 1300139
-+	.vop_fplookup_symlink = VOP_EAGAIN,
- #endif
- 	.vop_open =	zfsctl_common_open,
- 	.vop_close =	zfsctl_common_close,
-@@ -1126,6 +1144,9 @@ static struct vop_vector zfsctl_ops_snapdir = {
- 	.vop_default =	&default_vnodeops,
- #if __FreeBSD_version >= 1300121
- 	.vop_fplookup_vexec = VOP_EAGAIN,
-+#endif
-+#if __FreeBSD_version >= 1300139
-+	.vop_fplookup_symlink = VOP_EAGAIN,
- #endif
- 	.vop_open =	zfsctl_common_open,
- 	.vop_close =	zfsctl_common_close,
-@@ -1150,7 +1171,7 @@ zfsctl_snapshot_inactive(struct vop_inactive_args *ap)
- {
- 	vnode_t *vp = ap->a_vp;
- 
--	VERIFY3S(vrecycle(vp), ==, 1);
-+	vrecycle(vp);
- 	return (0);
- }
- 
-@@ -1234,6 +1255,11 @@ static struct vop_vector zfsctl_ops_snapshot = {
- #if __FreeBSD_version >= 1300121
- 	.vop_fplookup_vexec =	VOP_EAGAIN,
- #endif
-+#if __FreeBSD_version >= 1300139
-+	.vop_fplookup_symlink = VOP_EAGAIN,
-+#endif
-+	.vop_open =		zfsctl_common_open,
-+	.vop_close =		zfsctl_common_close,
- 	.vop_inactive =		zfsctl_snapshot_inactive,
- #if __FreeBSD_version >= 1300045
- 	.vop_need_inactive = vop_stdneed_inactive,
-diff --git a/module/os/freebsd/zfs/zfs_ioctl_os.c b/module/os/freebsd/zfs/zfs_ioctl_os.c
-index 7f7e2b72c..effc11518 100644
---- a/module/os/freebsd/zfs/zfs_ioctl_os.c
-+++ b/module/os/freebsd/zfs/zfs_ioctl_os.c
-@@ -59,7 +59,7 @@ zfs_vfs_ref(zfsvfs_t **zfvp)
- 	return (error);
- }
- 
--int
-+boolean_t
- zfs_vfs_held(zfsvfs_t *zfsvfs)
- {
- 	return (zfsvfs->z_vfs != NULL);
-diff --git a/module/os/freebsd/zfs/zfs_znode.c b/module/os/freebsd/zfs/zfs_znode.c
-index 1debc3ec3..92e3bdd2e 100644
---- a/module/os/freebsd/zfs/zfs_znode.c
-+++ b/module/os/freebsd/zfs/zfs_znode.c
-@@ -153,6 +153,9 @@ zfs_znode_cache_constructor(void *buf, void *arg, int kmflags)
- 	zp->z_xattr_cached = NULL;
- 	zp->z_xattr_parent = 0;
- 	zp->z_vnode = NULL;
-+	zp->z_sync_writes_cnt = 0;
-+	zp->z_async_writes_cnt = 0;
-+
- 	return (0);
- }
- 
-@@ -172,6 +175,9 @@ zfs_znode_cache_destructor(void *buf, void *arg)
- 
- 	ASSERT3P(zp->z_acl_cached, ==, NULL);
- 	ASSERT3P(zp->z_xattr_cached, ==, NULL);
-+
-+	ASSERT0(atomic_load_32(&zp->z_sync_writes_cnt));
-+	ASSERT0(atomic_load_32(&zp->z_async_writes_cnt));
- }
- 
- 
-@@ -457,6 +463,8 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz,
- 	zp->z_blksz = blksz;
- 	zp->z_seq = 0x7A4653;
- 	zp->z_sync_cnt = 0;
-+	zp->z_sync_writes_cnt = 0;
-+	zp->z_async_writes_cnt = 0;
- #if __FreeBSD_version >= 1300139
- 	atomic_store_ptr(&zp->z_cached_symlink, NULL);
- #endif
-diff --git a/module/os/linux/spl/spl-cred.c b/module/os/linux/spl/spl-cred.c
-index f81b9540a..d407fc66b 100644
---- a/module/os/linux/spl/spl-cred.c
-+++ b/module/os/linux/spl/spl-cred.c
-@@ -145,6 +145,18 @@ crgetgid(const cred_t *cr)
- 	return (KGID_TO_SGID(cr->fsgid));
- }
- 
-+/* Return the initial user ns or nop_mnt_idmap */
-+zidmap_t *
-+zfs_get_init_idmap(void)
-+{
-+#ifdef HAVE_IOPS_CREATE_IDMAP
-+	return ((zidmap_t *)&nop_mnt_idmap);
-+#else
-+	return ((zidmap_t *)&init_user_ns);
-+#endif
-+}
-+
-+EXPORT_SYMBOL(zfs_get_init_idmap);
- EXPORT_SYMBOL(crhold);
- EXPORT_SYMBOL(crfree);
- EXPORT_SYMBOL(crgetuid);
-diff --git a/module/os/linux/spl/spl-generic.c b/module/os/linux/spl/spl-generic.c
-index 508fb9d4c..2cb5251d7 100644
---- a/module/os/linux/spl/spl-generic.c
-+++ b/module/os/linux/spl/spl-generic.c
-@@ -225,8 +225,10 @@ __div_u64(uint64_t u, uint32_t v)
-  * replacements for libgcc-provided functions and will never be called
-  * directly.
-  */
-+#if defined(__GNUC__) && !defined(__clang__)
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wmissing-prototypes"
-+#endif
- 
- /*
-  * Implementation of 64-bit unsigned division for 32-bit machines.
-@@ -425,7 +427,9 @@ __aeabi_ldivmod(int64_t u, int64_t v)
- EXPORT_SYMBOL(__aeabi_ldivmod);
- #endif /* __arm || __arm__ */
- 
-+#if defined(__GNUC__) && !defined(__clang__)
- #pragma GCC diagnostic pop
-+#endif
- 
- #endif /* BITS_PER_LONG */
- 
-diff --git a/module/os/linux/spl/spl-kmem-cache.c b/module/os/linux/spl/spl-kmem-cache.c
-index 5a318e0a5..d586afa9b 100644
---- a/module/os/linux/spl/spl-kmem-cache.c
-+++ b/module/os/linux/spl/spl-kmem-cache.c
-@@ -183,8 +183,11 @@ kv_free(spl_kmem_cache_t *skc, void *ptr, int size)
- 	 * of that infrastructure we are responsible for incrementing it.
- 	 */
- 	if (current->reclaim_state)
-+#ifdef	HAVE_RECLAIM_STATE_RECLAIMED
-+		current->reclaim_state->reclaimed += size >> PAGE_SHIFT;
-+#else
- 		current->reclaim_state->reclaimed_slab += size >> PAGE_SHIFT;
--
-+#endif
- 	vfree(ptr);
- }
- 
-diff --git a/module/os/linux/zfs/arc_os.c b/module/os/linux/zfs/arc_os.c
-index f96cd1271..fc76fe0e0 100644
---- a/module/os/linux/zfs/arc_os.c
-+++ b/module/os/linux/zfs/arc_os.c
-@@ -219,7 +219,11 @@ arc_shrinker_scan(struct shrinker *shrink, struct shrink_control *sc)
- 	arc_reduce_target_size(ptob(sc->nr_to_scan));
- 	arc_wait_for_eviction(ptob(sc->nr_to_scan), B_FALSE);
- 	if (current->reclaim_state != NULL)
-+#ifdef	HAVE_RECLAIM_STATE_RECLAIMED
-+		current->reclaim_state->reclaimed += sc->nr_to_scan;
-+#else
- 		current->reclaim_state->reclaimed_slab += sc->nr_to_scan;
-+#endif
- 
- 	/*
- 	 * We are experiencing memory pressure which the arc_evict_zthr was
-diff --git a/module/os/linux/zfs/policy.c b/module/os/linux/zfs/policy.c
-index 5a52092bb..8d508bcb4 100644
---- a/module/os/linux/zfs/policy.c
-+++ b/module/os/linux/zfs/policy.c
-@@ -124,7 +124,7 @@ secpolicy_vnode_any_access(const cred_t *cr, struct inode *ip, uid_t owner)
- 	if (crgetuid(cr) == owner)
- 		return (0);
- 
--	if (zpl_inode_owner_or_capable(kcred->user_ns, ip))
-+	if (zpl_inode_owner_or_capable(zfs_init_idmap, ip))
- 		return (0);
- 
- #if defined(CONFIG_USER_NS)
-diff --git a/module/os/linux/zfs/zfs_ctldir.c b/module/os/linux/zfs/zfs_ctldir.c
-index c45644a69..743b03412 100644
---- a/module/os/linux/zfs/zfs_ctldir.c
-+++ b/module/os/linux/zfs/zfs_ctldir.c
-@@ -468,7 +468,9 @@ zfsctl_inode_alloc(zfsvfs_t *zfsvfs, uint64_t id,
- 	zp->z_atime_dirty = B_FALSE;
- 	zp->z_zn_prefetch = B_FALSE;
- 	zp->z_is_sa = B_FALSE;
-+#if !defined(HAVE_FILEMAP_RANGE_HAS_PAGE)
- 	zp->z_is_mapped = B_FALSE;
-+#endif
- 	zp->z_is_ctldir = B_TRUE;
- 	zp->z_sa_hdl = NULL;
- 	zp->z_blksz = 0;
-@@ -478,6 +480,8 @@ zfsctl_inode_alloc(zfsvfs_t *zfsvfs, uint64_t id,
- 	zp->z_pflags = 0;
- 	zp->z_mode = 0;
- 	zp->z_sync_cnt = 0;
-+	zp->z_sync_writes_cnt = 0;
-+	zp->z_async_writes_cnt = 0;
- 	ip->i_generation = 0;
- 	ip->i_ino = id;
- 	ip->i_mode = (S_IFDIR | S_IRWXUGO);
-diff --git a/module/os/linux/zfs/zfs_ioctl_os.c b/module/os/linux/zfs/zfs_ioctl_os.c
-index 79b9d777d..767d3a377 100644
---- a/module/os/linux/zfs/zfs_ioctl_os.c
-+++ b/module/os/linux/zfs/zfs_ioctl_os.c
-@@ -288,6 +288,8 @@ zfsdev_detach(void)
- #define	ZFS_DEBUG_STR	""
- #endif
- 
-+zidmap_t *zfs_init_idmap;
-+
- static int __init
- openzfs_init(void)
- {
-@@ -311,6 +313,8 @@ openzfs_init(void)
- 	printk(KERN_NOTICE "ZFS: Posix ACLs disabled by kernel\n");
- #endif /* CONFIG_FS_POSIX_ACL */
- 
-+	zfs_init_idmap = (zidmap_t *)zfs_get_init_idmap();
-+
- 	return (0);
- }
- 
-diff --git a/module/os/linux/zfs/zfs_vfsops.c b/module/os/linux/zfs/zfs_vfsops.c
-index da897f120..e620eb43a 100644
---- a/module/os/linux/zfs/zfs_vfsops.c
-+++ b/module/os/linux/zfs/zfs_vfsops.c
-@@ -1192,7 +1192,7 @@ zfs_prune_aliases(zfsvfs_t *zfsvfs, unsigned long nr_to_scan)
- 	int objects = 0;
- 	int i = 0, j = 0;
- 
--	zp_array = kmem_zalloc(max_array * sizeof (znode_t *), KM_SLEEP);
-+	zp_array = vmem_zalloc(max_array * sizeof (znode_t *), KM_SLEEP);
- 
- 	mutex_enter(&zfsvfs->z_znodes_lock);
- 	while ((zp = list_head(&zfsvfs->z_all_znodes)) != NULL) {
-@@ -1228,7 +1228,7 @@ zfs_prune_aliases(zfsvfs_t *zfsvfs, unsigned long nr_to_scan)
- 		zrele(zp);
- 	}
- 
--	kmem_free(zp_array, max_array * sizeof (znode_t *));
-+	vmem_free(zp_array, max_array * sizeof (znode_t *));
- 
- 	return (objects);
- }
-diff --git a/module/os/linux/zfs/zfs_vnops_os.c b/module/os/linux/zfs/zfs_vnops_os.c
-index ae0401e60..af0d553d5 100644
---- a/module/os/linux/zfs/zfs_vnops_os.c
-+++ b/module/os/linux/zfs/zfs_vnops_os.c
-@@ -244,43 +244,46 @@ zfs_close(struct inode *ip, int flag, cred_t *cr)
- }
- 
- #if defined(_KERNEL)
-+
-+static int zfs_fillpage(struct inode *ip, struct page *pp);
-+
- /*
-  * When a file is memory mapped, we must keep the IO data synchronized
-- * between the DMU cache and the memory mapped pages.  What this means:
-- *
-- * On Write:	If we find a memory mapped page, we write to *both*
-- *		the page and the dmu buffer.
-+ * between the DMU cache and the memory mapped pages.  Update all mapped
-+ * pages with the contents of the coresponding dmu buffer.
-  */
- void
- update_pages(znode_t *zp, int64_t start, int len, objset_t *os)
- {
--	struct inode *ip = ZTOI(zp);
--	struct address_space *mp = ip->i_mapping;
--	struct page *pp;
--	uint64_t nbytes;
--	int64_t	off;
--	void *pb;
-+	struct address_space *mp = ZTOI(zp)->i_mapping;
-+	int64_t off = start & (PAGE_SIZE - 1);
- 
--	off = start & (PAGE_SIZE-1);
- 	for (start &= PAGE_MASK; len > 0; start += PAGE_SIZE) {
--		nbytes = MIN(PAGE_SIZE - off, len);
-+		uint64_t nbytes = MIN(PAGE_SIZE - off, len);
- 
--		pp = find_lock_page(mp, start >> PAGE_SHIFT);
-+		struct page *pp = find_lock_page(mp, start >> PAGE_SHIFT);
- 		if (pp) {
- 			if (mapping_writably_mapped(mp))
- 				flush_dcache_page(pp);
- 
--			pb = kmap(pp);
--			(void) dmu_read(os, zp->z_id, start + off, nbytes,
--			    pb + off, DMU_READ_PREFETCH);
-+			void *pb = kmap(pp);
-+			int error = dmu_read(os, zp->z_id, start + off,
-+			    nbytes, pb + off, DMU_READ_PREFETCH);
- 			kunmap(pp);
- 
--			if (mapping_writably_mapped(mp))
--				flush_dcache_page(pp);
-+			if (error) {
-+				SetPageError(pp);
-+				ClearPageUptodate(pp);
-+			} else {
-+				ClearPageError(pp);
-+				SetPageUptodate(pp);
-+
-+				if (mapping_writably_mapped(mp))
-+					flush_dcache_page(pp);
-+
-+				mark_page_accessed(pp);
-+			}
- 
--			mark_page_accessed(pp);
--			SetPageUptodate(pp);
--			ClearPageError(pp);
- 			unlock_page(pp);
- 			put_page(pp);
- 		}
-@@ -291,38 +294,44 @@ update_pages(znode_t *zp, int64_t start, int len, objset_t *os)
- }
- 
- /*
-- * When a file is memory mapped, we must keep the IO data synchronized
-- * between the DMU cache and the memory mapped pages.  What this means:
-- *
-- * On Read:	We "read" preferentially from memory mapped pages,
-- *		else we default from the dmu buffer.
-- *
-- * NOTE: We will always "break up" the IO into PAGESIZE uiomoves when
-- *	 the file is memory mapped.
-+ * When a file is memory mapped, we must keep the I/O data synchronized
-+ * between the DMU cache and the memory mapped pages.  Preferentially read
-+ * from memory mapped pages, otherwise fallback to reading through the dmu.
-  */
- int
- mappedread(znode_t *zp, int nbytes, zfs_uio_t *uio)
- {
- 	struct inode *ip = ZTOI(zp);
- 	struct address_space *mp = ip->i_mapping;
--	struct page *pp;
--	int64_t	start, off;
--	uint64_t bytes;
-+	int64_t start = uio->uio_loffset;
-+	int64_t off = start & (PAGE_SIZE - 1);
- 	int len = nbytes;
- 	int error = 0;
--	void *pb;
- 
--	start = uio->uio_loffset;
--	off = start & (PAGE_SIZE-1);
- 	for (start &= PAGE_MASK; len > 0; start += PAGE_SIZE) {
--		bytes = MIN(PAGE_SIZE - off, len);
-+		uint64_t bytes = MIN(PAGE_SIZE - off, len);
- 
--		pp = find_lock_page(mp, start >> PAGE_SHIFT);
-+		struct page *pp = find_lock_page(mp, start >> PAGE_SHIFT);
- 		if (pp) {
--			ASSERT(PageUptodate(pp));
-+			/*
-+			 * If filemap_fault() retries there exists a window
-+			 * where the page will be unlocked and not up to date.
-+			 * In this case we must try and fill the page.
-+			 */
-+			if (unlikely(!PageUptodate(pp))) {
-+				error = zfs_fillpage(ip, pp);
-+				if (error) {
-+					unlock_page(pp);
-+					put_page(pp);
-+					return (error);
-+				}
-+			}
-+
-+			ASSERT(PageUptodate(pp) || PageDirty(pp));
-+
- 			unlock_page(pp);
- 
--			pb = kmap(pp);
-+			void *pb = kmap(pp);
- 			error = zfs_uiomove(pb + off, bytes, UIO_READ, uio);
- 			kunmap(pp);
- 
-@@ -338,9 +347,11 @@ mappedread(znode_t *zp, int nbytes, zfs_uio_t *uio)
- 
- 		len -= bytes;
- 		off = 0;
-+
- 		if (error)
- 			break;
- 	}
-+
- 	return (error);
- }
- #endif /* _KERNEL */
-@@ -1010,7 +1021,7 @@ top:
- 
- 	mutex_enter(&zp->z_lock);
- 	may_delete_now = atomic_read(&ZTOI(zp)->i_count) == 1 &&
--	    !(zp->z_is_mapped);
-+	    !zn_has_cached_data(zp, 0, LLONG_MAX);
- 	mutex_exit(&zp->z_lock);
- 
- 	/*
-@@ -1098,7 +1109,8 @@ top:
- 		    &xattr_obj_unlinked, sizeof (xattr_obj_unlinked));
- 		delete_now = may_delete_now && !toobig &&
- 		    atomic_read(&ZTOI(zp)->i_count) == 1 &&
--		    !(zp->z_is_mapped) && xattr_obj == xattr_obj_unlinked &&
-+		    !zn_has_cached_data(zp, 0, LLONG_MAX) &&
-+		    xattr_obj == xattr_obj_unlinked &&
- 		    zfs_external_acl(zp) == acl_obj;
- 	}
- 
-@@ -1663,8 +1675,7 @@ out:
-  */
- /* ARGSUSED */
- int
--zfs_getattr_fast(struct user_namespace *user_ns, struct inode *ip,
--    struct kstat *sp)
-+zfs_getattr_fast(zidmap_t *user_ns, struct inode *ip, struct kstat *sp)
- {
- 	znode_t *zp = ITOZ(ip);
- 	zfsvfs_t *zfsvfs = ITOZSB(ip);
-@@ -3434,21 +3445,34 @@ top:
- }
- 
- static void
--zfs_putpage_commit_cb(void *arg)
-+zfs_putpage_sync_commit_cb(void *arg)
-+{
-+	struct page *pp = arg;
-+
-+	ClearPageError(pp);
-+	end_page_writeback(pp);
-+}
-+
-+static void
-+zfs_putpage_async_commit_cb(void *arg)
- {
- 	struct page *pp = arg;
-+	znode_t *zp = ITOZ(pp->mapping->host);
- 
- 	ClearPageError(pp);
- 	end_page_writeback(pp);
-+	atomic_dec_32(&zp->z_async_writes_cnt);
- }
- 
- /*
-  * Push a page out to disk, once the page is on stable storage the
-  * registered commit callback will be run as notification of completion.
-  *
-- *	IN:	ip	- page mapped for inode.
-- *		pp	- page to push (page is locked)
-- *		wbc	- writeback control data
-+ *	IN:	ip	 - page mapped for inode.
-+ *		pp	 - page to push (page is locked)
-+ *		wbc	 - writeback control data
-+ *		for_sync - does the caller intend to wait synchronously for the
-+ *			   page writeback to complete?
-  *
-  *	RETURN:	0 if success
-  *		error code if failure
-@@ -3458,7 +3482,8 @@ zfs_putpage_commit_cb(void *arg)
-  */
- /* ARGSUSED */
- int
--zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc)
-+zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc,
-+    boolean_t for_sync)
- {
- 	znode_t		*zp = ITOZ(ip);
- 	zfsvfs_t	*zfsvfs = ITOZSB(ip);
-@@ -3556,6 +3581,16 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc)
- 		zfs_rangelock_exit(lr);
- 
- 		if (wbc->sync_mode != WB_SYNC_NONE) {
-+			/*
-+			 * Speed up any non-sync page writebacks since
-+			 * they may take several seconds to complete.
-+			 * Refer to the comment in zpl_fsync() (when
-+			 * HAVE_FSYNC_RANGE is defined) for details.
-+			 */
-+			if (atomic_load_32(&zp->z_async_writes_cnt) > 0) {
-+				zil_commit(zfsvfs->z_log, zp->z_id);
-+			}
-+
- 			if (PageWriteback(pp))
- #ifdef HAVE_PAGEMAP_FOLIO_WAIT_BIT
- 				folio_wait_bit(page_folio(pp), PG_writeback);
-@@ -3581,6 +3616,8 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc)
- 	 * was in fact not skipped and should not be counted as if it were.
- 	 */
- 	wbc->pages_skipped--;
-+	if (!for_sync)
-+		atomic_inc_32(&zp->z_async_writes_cnt);
- 	set_page_writeback(pp);
- 	unlock_page(pp);
- 
-@@ -3602,6 +3639,8 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc)
- #endif
- 		ClearPageError(pp);
- 		end_page_writeback(pp);
-+		if (!for_sync)
-+			atomic_dec_32(&zp->z_async_writes_cnt);
- 		zfs_rangelock_exit(lr);
- 		ZFS_EXIT(zfsvfs);
- 		return (err);
-@@ -3626,7 +3665,9 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc)
- 	err = sa_bulk_update(zp->z_sa_hdl, bulk, cnt, tx);
- 
- 	zfs_log_write(zfsvfs->z_log, tx, TX_WRITE, zp, pgoff, pglen, 0,
--	    zfs_putpage_commit_cb, pp);
-+	    for_sync ? zfs_putpage_sync_commit_cb :
-+	    zfs_putpage_async_commit_cb, pp);
-+
- 	dmu_tx_commit(tx);
- 
- 	zfs_rangelock_exit(lr);
-@@ -3638,6 +3679,16 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc)
- 		 * performance reasons.
- 		 */
- 		zil_commit(zfsvfs->z_log, zp->z_id);
-+	} else if (!for_sync && atomic_load_32(&zp->z_sync_writes_cnt) > 0) {
-+		/*
-+		 * If the caller does not intend to wait synchronously
-+		 * for this page writeback to complete and there are active
-+		 * synchronous calls on this file, do a commit so that
-+		 * the latter don't accidentally end up waiting for
-+		 * our writeback to complete. Refer to the comment in
-+		 * zpl_fsync() (when HAVE_FSYNC_RANGE is defined) for details.
-+		 */
-+		zil_commit(zfsvfs->z_log, zp->z_id);
- 	}
- 
- 	dataset_kstats_update_write_kstats(&zfsvfs->z_kstat, pglen);
-@@ -3766,55 +3817,45 @@ zfs_inactive(struct inode *ip)
-  * Fill pages with data from the disk.
-  */
- static int
--zfs_fillpage(struct inode *ip, struct page *pl[], int nr_pages)
-+zfs_fillpage(struct inode *ip, struct page *pp)
- {
--	znode_t *zp = ITOZ(ip);
- 	zfsvfs_t *zfsvfs = ITOZSB(ip);
--	objset_t *os;
--	struct page *cur_pp;
--	u_offset_t io_off, total;
--	size_t io_len;
--	loff_t i_size;
--	unsigned page_idx;
--	int err;
-+	loff_t i_size = i_size_read(ip);
<Skipped 3133 lines>
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/zfs.git/commitdiff/757b8d9475f8bdc5710df221acbd0c6dfcc9fca7




More information about the pld-cvs-commit mailing list