[packages/zfs] - up to 2.1.5

baggins baggins at pld-linux.org
Sat Aug 13 13:50:08 CEST 2022


commit e1ca25ecb35aa14a27802da4d7369d4ed7feb14a
Author: Jan Rękorajski <baggins at pld-linux.org>
Date:   Sat Aug 13 13:49:55 2022 +0200

    - up to 2.1.5

 zfs-2.1.5-staging.patch | 5492 -----------------------------------------------
 zfs.spec                |    8 +-
 2 files changed, 3 insertions(+), 5497 deletions(-)
---
diff --git a/zfs.spec b/zfs.spec
index 809d5e6..fe52acc 100644
--- a/zfs.spec
+++ b/zfs.spec
@@ -24,20 +24,19 @@ exit 1
 
 %define		_duplicate_files_terminate_build	0
 
-%define	rel	2
+%define	rel	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.4
+Version:	2.1.5
 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:	5ed389ab166c17e646f61856dba8c6c2
+# Source0-md5:	a1efd694cfa22522c51400b2e8731f25
 Patch0:		initdir.patch
 Patch1:		am.patch
-Patch2:		zfs-2.1.5-staging.patch
 URL:		https://zfsonlinux.org/
 BuildRequires:	autoconf >= 2.50
 BuildRequires:	automake
@@ -286,7 +285,6 @@ p=`pwd`\
 %setup -q -n %{pname}-%{version}
 %patch0 -p1
 %patch1 -p1
-%patch2 -p1
 
 %{__sed} -E -i -e '1s,#!\s*/usr/bin/env\s+python2(\s|$),#!%{__python}\1,' \
       cmd/arc_summary/arc_summary2
diff --git a/zfs-2.1.5-staging.patch b/zfs-2.1.5-staging.patch
deleted file mode 100644
index db7a3cc..0000000
--- a/zfs-2.1.5-staging.patch
+++ /dev/null
@@ -1,5492 +0,0 @@
-diff --git a/Makefile.am b/Makefile.am
-index 34fe16ce4..7e2b10b39 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -103,7 +103,7 @@ endif
- endif
- 
- PHONY += codecheck
--codecheck: cstyle shellcheck checkbashisms flake8 mancheck testscheck vcscheck
-+codecheck: cstyle shellcheck checkbashisms flake8 mancheck testscheck vcscheck zstdcheck
- 
- PHONY += checkstyle
- checkstyle: codecheck commitcheck
-@@ -120,6 +120,7 @@ cstyle:
- 		-o -type f -name '*.[hc]' \
- 		! -name 'zfs_config.*' ! -name '*.mod.c' \
- 		! -name 'opt_global.h' ! -name '*_if*.h' \
-+		! -name 'zstd_compat_wrapper.h' \
- 		! -path './module/zstd/lib/*' \
- 		-exec ${top_srcdir}/scripts/cstyle.pl -cpP {} \+
- 
-@@ -173,6 +174,10 @@ vcscheck:
- 		awk '{c++; print} END {if(c>0) exit 1}' ; \
- 	fi
- 
-+PHONY += zstdcheck
-+zstdcheck:
-+	@$(MAKE) -C module/zstd checksymbols
-+
- PHONY += lint
- lint: cppcheck paxcheck
- 
-diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c
-index 9de41cef2..75688205f 100644
---- a/cmd/zdb/zdb.c
-+++ b/cmd/zdb/zdb.c
-@@ -110,6 +110,7 @@ extern int zfs_recover;
- extern unsigned long zfs_arc_meta_min, zfs_arc_meta_limit;
- extern int zfs_vdev_async_read_max_active;
- extern boolean_t spa_load_verify_dryrun;
-+extern boolean_t spa_mode_readable_spacemaps;
- extern int zfs_reconstruct_indirect_combinations_max;
- extern int zfs_btree_verify_intensity;
- 
-@@ -8469,6 +8470,11 @@ main(int argc, char **argv)
- 	 */
- 	spa_load_verify_dryrun = B_TRUE;
- 
-+	/*
-+	 * ZDB should have ability to read spacemaps.
-+	 */
-+	spa_mode_readable_spacemaps = B_TRUE;
-+
- 	kernel_init(SPA_MODE_READ);
- 
- 	if (dump_all)
-diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c
-index d0bb73a72..6f0c846fd 100644
---- a/cmd/zfs/zfs_main.c
-+++ b/cmd/zfs/zfs_main.c
-@@ -6593,7 +6593,7 @@ zfs_do_holds(int argc, char **argv)
- 		/*
- 		 *  1. collect holds data, set format options
- 		 */
--		ret = zfs_for_each(argc, argv, flags, types, NULL, NULL, limit,
-+		ret = zfs_for_each(1, argv + i, flags, types, NULL, NULL, limit,
- 		    holds_callback, &cb);
- 		if (ret != 0)
- 			++errors;
-@@ -7672,7 +7672,7 @@ zfs_do_diff(int argc, char **argv)
- 	int c;
- 	struct sigaction sa;
- 
--	while ((c = getopt(argc, argv, "FHt")) != -1) {
-+	while ((c = getopt(argc, argv, "FHth")) != -1) {
- 		switch (c) {
- 		case 'F':
- 			flags |= ZFS_DIFF_CLASSIFY;
-@@ -7683,6 +7683,9 @@ zfs_do_diff(int argc, char **argv)
- 		case 't':
- 			flags |= ZFS_DIFF_TIMESTAMP;
- 			break;
-+		case 'h':
-+			flags |= ZFS_DIFF_NO_MANGLE;
-+			break;
- 		default:
- 			(void) fprintf(stderr,
- 			    gettext("invalid option '%c'\n"), optopt);
-diff --git a/cmd/zvol_wait/zvol_wait b/cmd/zvol_wait/zvol_wait
-index 2aa929b0c..f1fa42e27 100755
---- a/cmd/zvol_wait/zvol_wait
-+++ b/cmd/zvol_wait/zvol_wait
-@@ -28,15 +28,17 @@ filter_out_deleted_zvols() {
- list_zvols() {
- 	read -r default_volmode < /sys/module/zfs/parameters/zvol_volmode
- 	zfs list -t volume -H -o \
--	    name,volmode,receive_resume_token,redact_snaps |
--	    while IFS="	" read -r name volmode token redacted; do # IFS=\t here!
-+	    name,volmode,receive_resume_token,redact_snaps,keystatus |
-+	    while IFS="	" read -r name volmode token redacted keystatus; do # IFS=\t here!
- 
--		# /dev links are not created for zvols with volmode = "none"
--		# or for redacted zvols.
-+		# /dev links are not created for zvols with volmode = "none",
-+		# redacted zvols, or encrypted zvols for which the key has not
-+		# been loaded.
- 		[ "$volmode" = "none" ] && continue
- 		[ "$volmode" = "default" ] && [ "$default_volmode" = "3" ] &&
- 		    continue
- 		[ "$redacted" = "-" ] || continue
-+		[ "$keystatus" = "unavailable" ] && continue
- 
- 		# We also ignore partially received zvols if it is
- 		# not an incremental receive, as those won't even have a block
-diff --git a/config/ax_python_devel.m4 b/config/ax_python_devel.m4
-index fcf73dc20..7adcf01a0 100644
---- a/config/ax_python_devel.m4
-+++ b/config/ax_python_devel.m4
-@@ -224,7 +224,7 @@ EOD`
- 				ac_python_version=$PYTHON_VERSION
- 			else
- 				ac_python_version=`$PYTHON -c "import sys; \
--					print (sys.version[[:3]])"`
-+					print ('.'.join(sys.version.split('.')[[:2]]))"`
- 			fi
- 		fi
- 
-diff --git a/config/kernel-add-disk.m4 b/config/kernel-add-disk.m4
-index 5d1779eb4..44a8a5fd2 100644
---- a/config/kernel-add-disk.m4
-+++ b/config/kernel-add-disk.m4
-@@ -3,16 +3,15 @@ dnl # 5.16 API change
- dnl # add_disk grew a must-check return code
- dnl #
- AC_DEFUN([ZFS_AC_KERNEL_SRC_ADD_DISK], [
--
- 	ZFS_LINUX_TEST_SRC([add_disk_ret], [
--		#include <linux/genhd.h>
-+		#include <linux/blkdev.h>
- 	], [
- 		struct gendisk *disk = NULL;
- 		int err = add_disk(disk);
- 		err = err;
- 	])
--
- ])
-+
- AC_DEFUN([ZFS_AC_KERNEL_ADD_DISK], [
- 	AC_MSG_CHECKING([whether add_disk() returns int])
- 	ZFS_LINUX_TEST_RESULT([add_disk_ret],
-diff --git a/config/kernel-bio.m4 b/config/kernel-bio.m4
-index d088d7023..b5d254481 100644
---- a/config/kernel-bio.m4
-+++ b/config/kernel-bio.m4
-@@ -474,6 +474,41 @@ AC_DEFUN([ZFS_AC_KERNEL_BLK_CGROUP_HEADER], [
- 	])
- ])
- 
-+dnl #
-+dnl # Linux 5.18 API
-+dnl #
-+dnl # In 07888c665b405b1cd3577ddebfeb74f4717a84c4 ("block: pass a block_device and opf to bio_alloc")
-+dnl #   bio_alloc(gfp_t gfp_mask, unsigned short nr_iovecs)
-+dnl # became
-+dnl #   bio_alloc(struct block_device *bdev, unsigned short nr_vecs, unsigned int opf, gfp_t gfp_mask)
-+dnl # however
-+dnl # > NULL/0 can be passed, both for the
-+dnl # > passthrough case on a raw request_queue and to temporarily avoid
-+dnl # > refactoring some nasty code.
-+dnl #
-+AC_DEFUN([ZFS_AC_KERNEL_SRC_BIO_ALLOC_4ARG], [
-+	ZFS_LINUX_TEST_SRC([bio_alloc_4arg], [
-+		#include <linux/bio.h>
-+	],[
-+		gfp_t gfp_mask = 0;
-+		unsigned short nr_iovecs = 0;
-+		struct block_device *bdev = NULL;
-+		unsigned int opf = 0;
-+
-+		struct bio *__attribute__((unused)) allocated = bio_alloc(bdev, nr_iovecs, opf, gfp_mask);
-+	])
-+])
-+
-+AC_DEFUN([ZFS_AC_KERNEL_BIO_ALLOC_4ARG], [
-+	AC_MSG_CHECKING([for 4-argument bio_alloc()])
-+	ZFS_LINUX_TEST_RESULT([bio_alloc_4arg],[
-+		AC_MSG_RESULT(yes)
-+		AC_DEFINE([HAVE_BIO_ALLOC_4ARG], 1, [bio_alloc() takes 4 arguments])
-+	],[
-+		AC_MSG_RESULT(no)
-+	])
-+])
-+
- AC_DEFUN([ZFS_AC_KERNEL_SRC_BIO], [
- 	ZFS_AC_KERNEL_SRC_REQ
- 	ZFS_AC_KERNEL_SRC_BIO_OPS
-@@ -488,6 +523,7 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BIO], [
- 	ZFS_AC_KERNEL_SRC_BDEV_SUBMIT_BIO_RETURNS_VOID
- 	ZFS_AC_KERNEL_SRC_BIO_SET_DEV_MACRO
- 	ZFS_AC_KERNEL_SRC_BLK_CGROUP_HEADER
-+	ZFS_AC_KERNEL_SRC_BIO_ALLOC_4ARG
- ])
- 
- AC_DEFUN([ZFS_AC_KERNEL_BIO], [
-@@ -512,4 +548,5 @@ AC_DEFUN([ZFS_AC_KERNEL_BIO], [
- 	ZFS_AC_KERNEL_BIO_BDEV_DISK
- 	ZFS_AC_KERNEL_BDEV_SUBMIT_BIO_RETURNS_VOID
- 	ZFS_AC_KERNEL_BLK_CGROUP_HEADER
-+	ZFS_AC_KERNEL_BIO_ALLOC_4ARG
- ])
-diff --git a/config/kernel-blk-queue.m4 b/config/kernel-blk-queue.m4
-index ff5d2d370..091952f57 100644
---- a/config/kernel-blk-queue.m4
-+++ b/config/kernel-blk-queue.m4
-@@ -93,8 +93,10 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLK_QUEUE_DISCARD], [
- 	ZFS_LINUX_TEST_SRC([blk_queue_discard], [
- 		#include <linux/blkdev.h>
- 	],[
--		struct request_queue *q __attribute__ ((unused)) = NULL;
-+		struct request_queue r;
-+		struct request_queue *q = &r;
- 		int value __attribute__ ((unused));
-+		memset(q, 0, sizeof(r));
- 		value = blk_queue_discard(q);
- 	])
- ])
-@@ -119,16 +121,20 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLK_QUEUE_SECURE_ERASE], [
- 	ZFS_LINUX_TEST_SRC([blk_queue_secure_erase], [
- 		#include <linux/blkdev.h>
- 	],[
--		struct request_queue *q __attribute__ ((unused)) = NULL;
-+		struct request_queue r;
-+		struct request_queue *q = &r;
- 		int value __attribute__ ((unused));
-+		memset(q, 0, sizeof(r));
- 		value = blk_queue_secure_erase(q);
- 	])
- 
- 	ZFS_LINUX_TEST_SRC([blk_queue_secdiscard], [
- 		#include <linux/blkdev.h>
- 	],[
--		struct request_queue *q __attribute__ ((unused)) = NULL;
-+		struct request_queue r;
-+		struct request_queue *q = &r;
- 		int value __attribute__ ((unused));
-+		memset(q, 0, sizeof(r));
- 		value = blk_queue_secdiscard(q);
- 	])
- ])
-diff --git a/config/kernel-config-defined.m4 b/config/kernel-config-defined.m4
-index c7d18b49b..54837d728 100644
---- a/config/kernel-config-defined.m4
-+++ b/config/kernel-config-defined.m4
-@@ -19,19 +19,48 @@ AC_DEFUN([ZFS_AC_KERNEL_CONFIG_DEFINED], [
- 		])
- 	])
- 
-+	ZFS_AC_KERNEL_SRC_CONFIG_MODULES
-+	ZFS_AC_KERNEL_SRC_CONFIG_BLOCK
- 	ZFS_AC_KERNEL_SRC_CONFIG_DEBUG_LOCK_ALLOC
- 	ZFS_AC_KERNEL_SRC_CONFIG_TRIM_UNUSED_KSYMS
--	ZFS_AC_KERNEL_SRC_CONFIG_ZLIB_INFLATE
- 	ZFS_AC_KERNEL_SRC_CONFIG_ZLIB_DEFLATE
-+	ZFS_AC_KERNEL_SRC_CONFIG_ZLIB_INFLATE
- 
- 	AC_MSG_CHECKING([for kernel config option compatibility])
- 	ZFS_LINUX_TEST_COMPILE_ALL([config])
- 	AC_MSG_RESULT([done])
- 
-+	ZFS_AC_KERNEL_CONFIG_MODULES
-+	ZFS_AC_KERNEL_CONFIG_BLOCK
- 	ZFS_AC_KERNEL_CONFIG_DEBUG_LOCK_ALLOC
- 	ZFS_AC_KERNEL_CONFIG_TRIM_UNUSED_KSYMS
--	ZFS_AC_KERNEL_CONFIG_ZLIB_INFLATE
- 	ZFS_AC_KERNEL_CONFIG_ZLIB_DEFLATE
-+	ZFS_AC_KERNEL_CONFIG_ZLIB_INFLATE
-+])
-+
-+dnl #
-+dnl # Check CONFIG_BLOCK
-+dnl #
-+dnl # Verify the kernel has CONFIG_BLOCK support enabled.
-+dnl #
-+AC_DEFUN([ZFS_AC_KERNEL_SRC_CONFIG_BLOCK], [
-+	ZFS_LINUX_TEST_SRC([config_block], [
-+		#if !defined(CONFIG_BLOCK)
-+		#error CONFIG_BLOCK not defined
-+		#endif
-+	],[])
-+])
-+
-+AC_DEFUN([ZFS_AC_KERNEL_CONFIG_BLOCK], [
-+	AC_MSG_CHECKING([whether CONFIG_BLOCK is defined])
-+	ZFS_LINUX_TEST_RESULT([config_block], [
-+		AC_MSG_RESULT([yes])
-+	],[
-+		AC_MSG_RESULT([no])
-+		AC_MSG_ERROR([
-+	*** This kernel does not include the required block device support.
-+	*** Rebuild the kernel with CONFIG_BLOCK=y set.])
-+	])
- ])
- 
- dnl #
-@@ -72,6 +101,61 @@ AC_DEFUN([ZFS_AC_KERNEL_CONFIG_DEBUG_LOCK_ALLOC], [
- 	])
- ])
- 
-+dnl #
-+dnl # Check CONFIG_MODULES
-+dnl #
-+dnl # Verify the kernel has CONFIG_MODULES support enabled.
-+dnl #
-+AC_DEFUN([ZFS_AC_KERNEL_SRC_CONFIG_MODULES], [
-+	ZFS_LINUX_TEST_SRC([config_modules], [
-+		#if !defined(CONFIG_MODULES)
-+		#error CONFIG_MODULES not defined
-+		#endif
-+	],[])
-+])
-+
-+AC_DEFUN([ZFS_AC_KERNEL_CONFIG_MODULES], [
-+	AC_MSG_CHECKING([whether CONFIG_MODULES is defined])
-+	AS_IF([test "x$enable_linux_builtin" != xyes], [
-+		ZFS_LINUX_TEST_RESULT([config_modules], [
-+			AC_MSG_RESULT([yes])
-+		],[
-+			AC_MSG_RESULT([no])
-+			AC_MSG_ERROR([
-+		*** This kernel does not include the required loadable module
-+		*** support!
-+		***
-+		*** To build OpenZFS as a loadable Linux kernel module
-+		*** enable loadable module support by setting
-+		*** `CONFIG_MODULES=y` in the kernel configuration and run
-+		*** `make modules_prepare` in the Linux source tree.
-+		***
-+		*** If you don't intend to enable loadable kernel module
-+		*** support, please compile OpenZFS as a Linux kernel built-in.
-+		***
-+		*** Prepare the Linux source tree by running `make prepare`,
-+		*** use the OpenZFS `--enable-linux-builtin` configure option,
-+		*** copy the OpenZFS sources into the Linux source tree using
-+		*** `./copy-builtin <linux source directory>`,
-+		*** set `CONFIG_ZFS=y` in the kernel configuration and compile
-+		*** kernel as usual.
-+			])
-+		])
-+	], [
-+		ZFS_LINUX_TRY_COMPILE([], [], [
-+			AC_MSG_RESULT([not needed])
-+		],[
-+			AC_MSG_RESULT([error])
-+			AC_MSG_ERROR([
-+		*** This kernel is unable to compile object files.
-+		***
-+		*** Please make sure you prepared the Linux source tree
-+		*** by running `make prepare` there.
-+			])
-+		])
-+	])
-+])
-+
- dnl #
- dnl # Check CONFIG_TRIM_UNUSED_KSYMS
- dnl #
-diff --git a/config/kernel-copy-from-user-inatomic.m4 b/config/kernel-copy-from-user-inatomic.m4
-new file mode 100644
-index 000000000..fec354b2f
---- /dev/null
-+++ b/config/kernel-copy-from-user-inatomic.m4
-@@ -0,0 +1,29 @@
-+dnl #
-+dnl # On certain architectures `__copy_from_user_inatomic`
-+dnl # is a GPL exported variable and cannot be used by OpenZFS.
-+dnl #
-+
-+dnl #
-+dnl # Checking if `__copy_from_user_inatomic` is available.
-+dnl #
-+AC_DEFUN([ZFS_AC_KERNEL_SRC___COPY_FROM_USER_INATOMIC], [
-+	ZFS_LINUX_TEST_SRC([__copy_from_user_inatomic], [
-+		#include <linux/uaccess.h>
-+	], [
-+		int result __attribute__ ((unused)) = __copy_from_user_inatomic(NULL, NULL, 0);
-+	], [], [ZFS_META_LICENSE])
-+])
-+
-+AC_DEFUN([ZFS_AC_KERNEL___COPY_FROM_USER_INATOMIC], [
-+	AC_MSG_CHECKING([whether __copy_from_user_inatomic is available])
-+	ZFS_LINUX_TEST_RESULT([__copy_from_user_inatomic_license], [
-+		AC_MSG_RESULT(yes)
-+	], [
-+		AC_MSG_RESULT(no)
-+		AC_MSG_ERROR([
-+	*** The `__copy_from_user_inatomic()` Linux kernel function is
-+	*** incompatible with the CDDL license and will prevent the module
-+	*** linking stage from succeeding.  OpenZFS cannot be compiled.
-+		])
-+	])
-+])
-diff --git a/config/kernel-genhd-flags.m4 b/config/kernel-genhd-flags.m4
-new file mode 100644
-index 000000000..af6a8a086
---- /dev/null
-+++ b/config/kernel-genhd-flags.m4
-@@ -0,0 +1,58 @@
-+dnl #
-+dnl # 5.17 API change,
-+dnl #
-+dnl # GENHD_FL_EXT_DEVT flag removed
-+dnl # GENHD_FL_NO_PART_SCAN renamed GENHD_FL_NO_PART
-+dnl #
-+AC_DEFUN([ZFS_AC_KERNEL_SRC_GENHD_FLAGS], [
-+
-+	ZFS_LINUX_TEST_SRC([genhd_fl_ext_devt], [
-+		#include <linux/blkdev.h>
-+	], [
-+		int flags __attribute__ ((unused)) = GENHD_FL_EXT_DEVT;
-+	])
-+
-+	ZFS_LINUX_TEST_SRC([genhd_fl_no_part], [
-+		#include <linux/blkdev.h>
-+	], [
-+		int flags __attribute__ ((unused)) = GENHD_FL_NO_PART;
-+	])
-+
-+	ZFS_LINUX_TEST_SRC([genhd_fl_no_part_scan], [
-+		#include <linux/blkdev.h>
-+	], [
-+		int flags __attribute__ ((unused)) = GENHD_FL_NO_PART_SCAN;
-+	])
-+])
-+
-+AC_DEFUN([ZFS_AC_KERNEL_GENHD_FLAGS], [
-+
-+	AC_MSG_CHECKING([whether GENHD_FL_EXT_DEVT flag is available])
-+	ZFS_LINUX_TEST_RESULT([genhd_fl_ext_devt], [
-+		AC_MSG_RESULT(yes)
-+		AC_DEFINE(ZFS_GENHD_FL_EXT_DEVT, GENHD_FL_EXT_DEVT,
-+		    [GENHD_FL_EXT_DEVT flag is available])
-+	], [
-+		AC_MSG_RESULT(no)
-+		AC_DEFINE(ZFS_GENHD_FL_EXT_DEVT, 0,
-+		    [GENHD_FL_EXT_DEVT flag is not available])
-+	])
-+
-+	AC_MSG_CHECKING([whether GENHD_FL_NO_PART flag is available])
-+	ZFS_LINUX_TEST_RESULT([genhd_fl_no_part], [
-+		AC_MSG_RESULT(yes)
-+		AC_DEFINE(ZFS_GENHD_FL_NO_PART, GENHD_FL_NO_PART,
-+		    [GENHD_FL_NO_PART flag is available])
-+	], [
-+		AC_MSG_RESULT(no)
-+
-+		AC_MSG_CHECKING([whether GENHD_FL_NO_PART_SCAN flag is available])
-+		ZFS_LINUX_TEST_RESULT([genhd_fl_no_part_scan], [
-+			AC_MSG_RESULT(yes)
-+			AC_DEFINE(ZFS_GENHD_FL_NO_PART, GENHD_FL_NO_PART_SCAN,
-+			    [GENHD_FL_NO_PART_SCAN flag is available])
-+		], [
-+			ZFS_LINUX_TEST_ERROR([GENHD_FL_NO_PART|GENHD_FL_NO_PART_SCAN])
-+		])
-+	])
-+])
-diff --git a/config/kernel-group-info.m4 b/config/kernel-group-info.m4
-index 0fee1d36d..6941d62da 100644
---- a/config/kernel-group-info.m4
-+++ b/config/kernel-group-info.m4
-@@ -6,8 +6,8 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_GROUP_INFO_GID], [
- 	ZFS_LINUX_TEST_SRC([group_info_gid], [
- 		#include <linux/cred.h>
- 	],[
--		struct group_info *gi = groups_alloc(1);
--		gi->gid[0] = KGIDT_INIT(0);
-+		struct group_info gi __attribute__ ((unused)) = {};
-+		gi.gid[0] = KGIDT_INIT(0);
- 	])
- ])
- 
-diff --git a/config/kernel-mkdir.m4 b/config/kernel-mkdir.m4
-index a162bcd88..6667ed04f 100644
---- a/config/kernel-mkdir.m4
-+++ b/config/kernel-mkdir.m4
-@@ -53,6 +53,8 @@ AC_DEFUN([ZFS_AC_KERNEL_MKDIR], [
- 		AC_DEFINE(HAVE_IOPS_MKDIR_USERNS, 1,
- 		    [iops->mkdir() takes struct user_namespace*])
- 	],[
-+		AC_MSG_RESULT(no)
-+
- 		AC_MSG_CHECKING([whether iops->mkdir() takes umode_t])
- 		ZFS_LINUX_TEST_RESULT([inode_operations_mkdir], [
- 			AC_MSG_RESULT(yes)
-diff --git a/config/kernel-readpages.m4 b/config/kernel-readpages.m4
-new file mode 100644
-index 000000000..0bf67ffd9
---- /dev/null
-+++ b/config/kernel-readpages.m4
-@@ -0,0 +1,25 @@
-+dnl #
-+dnl # Linux 5.18 removes address_space_operations ->readpages in favour of
-+dnl # ->readahead
-+dnl #
-+AC_DEFUN([ZFS_AC_KERNEL_SRC_VFS_READPAGES], [
-+	ZFS_LINUX_TEST_SRC([vfs_has_readpages], [
-+		#include <linux/fs.h>
-+
-+		static const struct address_space_operations
-+		    aops __attribute__ ((unused)) = {
-+			.readpages = NULL,
-+		};
-+	],[])
-+])
-+
-+AC_DEFUN([ZFS_AC_KERNEL_VFS_READPAGES], [
-+	AC_MSG_CHECKING([address_space_operations->readpages exists])
-+	ZFS_LINUX_TEST_RESULT([vfs_has_readpages], [
-+		AC_MSG_RESULT([yes])
-+		AC_DEFINE(HAVE_VFS_READPAGES, 1,
-+			[address_space_operations->readpages exists])
-+	],[
-+		AC_MSG_RESULT([no])
-+	])
-+])
-diff --git a/config/kernel-revalidate-disk-size.m4 b/config/kernel-revalidate-disk-size.m4
-index a7d0cb3cd..13cb92a17 100644
---- a/config/kernel-revalidate-disk-size.m4
-+++ b/config/kernel-revalidate-disk-size.m4
-@@ -8,14 +8,14 @@ dnl #
- AC_DEFUN([ZFS_AC_KERNEL_SRC_REVALIDATE_DISK], [
- 
- 	ZFS_LINUX_TEST_SRC([revalidate_disk_size], [
--		#include <linux/genhd.h>
-+		#include <linux/blkdev.h>
- 	], [
- 		struct gendisk *disk = NULL;
- 		(void) revalidate_disk_size(disk, false);
- 	])
- 
- 	ZFS_LINUX_TEST_SRC([revalidate_disk], [
--		#include <linux/genhd.h>
-+		#include <linux/blkdev.h>
- 	], [
- 		struct gendisk *disk = NULL;
- 		(void) revalidate_disk(disk);
-diff --git a/config/kernel-sysfs.m4 b/config/kernel-sysfs.m4
-new file mode 100644
-index 000000000..668def5fe
---- /dev/null
-+++ b/config/kernel-sysfs.m4
-@@ -0,0 +1,37 @@
-+dnl #
-+dnl # Linux 5.2/5.18 API
-+dnl #
-+dnl # In cdb4f26a63c391317e335e6e683a614358e70aeb ("kobject: kobj_type: remove default_attrs")
-+dnl # 	struct kobj_type.default_attrs
-+dnl # was finally removed in favour of
-+dnl # 	struct kobj_type.default_groups
-+dnl #
-+dnl # This was added in aa30f47cf666111f6bbfd15f290a27e8a7b9d854 ("kobject: Add support for default attribute groups to kobj_type"),
-+dnl # if both are present (5.2-5.17), we prefer default_groups; they're otherwise equivalent
-+dnl #
-+AC_DEFUN([ZFS_AC_KERNEL_SRC_SYSFS_DEFAULT_GROUPS], [
-+	ZFS_LINUX_TEST_SRC([sysfs_default_groups], [
-+		#include <linux/kobject.h>
-+	],[
-+		struct kobj_type __attribute__ ((unused)) kt = {
-+			.default_groups = (const struct attribute_group **)NULL };
-+	])
-+])
-+
-+AC_DEFUN([ZFS_AC_KERNEL_SYSFS_DEFAULT_GROUPS], [
-+	AC_MSG_CHECKING([for struct kobj_type.default_groups])
-+	ZFS_LINUX_TEST_RESULT([sysfs_default_groups],[
-+		AC_MSG_RESULT(yes)
-+		AC_DEFINE([HAVE_SYSFS_DEFAULT_GROUPS], 1, [struct kobj_type has default_groups])
-+	],[
-+		AC_MSG_RESULT(no)
-+	])
-+])
-+
-+AC_DEFUN([ZFS_AC_KERNEL_SRC_SYSFS], [
-+	ZFS_AC_KERNEL_SRC_SYSFS_DEFAULT_GROUPS
-+])
-+
-+AC_DEFUN([ZFS_AC_KERNEL_SYSFS], [
-+	ZFS_AC_KERNEL_SYSFS_DEFAULT_GROUPS
-+])
-diff --git a/config/kernel-vfs-filemap_dirty_folio.m4 b/config/kernel-vfs-filemap_dirty_folio.m4
-new file mode 100644
-index 000000000..872879002
---- /dev/null
-+++ b/config/kernel-vfs-filemap_dirty_folio.m4
-@@ -0,0 +1,30 @@
-+dnl #
-+dnl # Linux 5.18 uses filemap_dirty_folio in lieu of
-+dnl # ___set_page_dirty_nobuffers
-+dnl #
-+AC_DEFUN([ZFS_AC_KERNEL_SRC_VFS_FILEMAP_DIRTY_FOLIO], [
-+	ZFS_LINUX_TEST_SRC([vfs_has_filemap_dirty_folio], [
-+		#include <linux/pagemap.h>
-+		#include <linux/writeback.h>
-+
-+		static const struct address_space_operations
-+		    aops __attribute__ ((unused)) = {
-+			.dirty_folio	= filemap_dirty_folio,
-+		};
-+	],[])
-+])
-+
-+AC_DEFUN([ZFS_AC_KERNEL_VFS_FILEMAP_DIRTY_FOLIO], [
-+	dnl #
-+	dnl # Linux 5.18 uses filemap_dirty_folio in lieu of
-+	dnl # ___set_page_dirty_nobuffers
-+	dnl #
-+	AC_MSG_CHECKING([filemap_dirty_folio exists])
-+	ZFS_LINUX_TEST_RESULT([vfs_has_filemap_dirty_folio], [
-+		AC_MSG_RESULT([yes])
-+		AC_DEFINE(HAVE_VFS_FILEMAP_DIRTY_FOLIO, 1,
-+			[filemap_dirty_folio exists])
-+	],[
-+		AC_MSG_RESULT([no])
-+	])
-+])
-diff --git a/config/kernel-zero_page.m4 b/config/kernel-zero_page.m4
-new file mode 100644
-index 000000000..1461781ac
---- /dev/null
-+++ b/config/kernel-zero_page.m4
-@@ -0,0 +1,27 @@
-+dnl #
-+dnl # ZERO_PAGE() is an alias for emtpy_zero_page. On certain architectures
-+dnl # this is a GPL exported variable.
-+dnl #
-+
-+dnl #
-+dnl # Checking if ZERO_PAGE is exported GPL-only
-+dnl #
-+AC_DEFUN([ZFS_AC_KERNEL_SRC_ZERO_PAGE], [
-+	ZFS_LINUX_TEST_SRC([zero_page], [
-+		#include <asm/pgtable.h>
-+	], [
-+		struct page *p __attribute__ ((unused));
-+		p = ZERO_PAGE(0);
-+	], [], [ZFS_META_LICENSE])
-+])
-+
-+AC_DEFUN([ZFS_AC_KERNEL_ZERO_PAGE], [
-+	AC_MSG_CHECKING([whether ZERO_PAGE() is GPL-only])
-+	ZFS_LINUX_TEST_RESULT([zero_page_license], [
-+		AC_MSG_RESULT(no)
-+	], [
-+		AC_MSG_RESULT(yes)
-+		AC_DEFINE(HAVE_ZERO_PAGE_GPL_ONLY, 1,
-+		    [ZERO_PAGE() is GPL-only])
-+	])
-+])
-diff --git a/config/kernel.m4 b/config/kernel.m4
-index 3122e9dba..25df16a90 100644
---- a/config/kernel.m4
-+++ b/config/kernel.m4
-@@ -8,8 +8,8 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
- 		ZFS_AC_QAT
- 
- 		dnl # Sanity checks for module building and CONFIG_* defines
--		ZFS_AC_KERNEL_TEST_MODULE
- 		ZFS_AC_KERNEL_CONFIG_DEFINED
-+		ZFS_AC_MODULE_SYMVERS
- 
- 		dnl # Sequential ZFS_LINUX_TRY_COMPILE tests
- 		ZFS_AC_KERNEL_FPU_HEADER
-@@ -61,6 +61,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
- 	ZFS_AC_KERNEL_SRC_BIO
- 	ZFS_AC_KERNEL_SRC_BLKDEV
- 	ZFS_AC_KERNEL_SRC_BLK_QUEUE
-+	ZFS_AC_KERNEL_SRC_GENHD_FLAGS
- 	ZFS_AC_KERNEL_SRC_REVALIDATE_DISK
- 	ZFS_AC_KERNEL_SRC_GET_DISK_RO
- 	ZFS_AC_KERNEL_SRC_GENERIC_READLINK_GLOBAL
-@@ -99,6 +100,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
- 	ZFS_AC_KERNEL_SRC_SET_NLINK
- 	ZFS_AC_KERNEL_SRC_SGET
- 	ZFS_AC_KERNEL_SRC_LSEEK_EXECUTE
-+	ZFS_AC_KERNEL_SRC_VFS_FILEMAP_DIRTY_FOLIO
- 	ZFS_AC_KERNEL_SRC_VFS_GETATTR
- 	ZFS_AC_KERNEL_SRC_VFS_FSYNC_2ARGS
- 	ZFS_AC_KERNEL_SRC_VFS_ITERATE
-@@ -131,12 +133,16 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
- 	ZFS_AC_KERNEL_SRC_BIO_MAX_SEGS
- 	ZFS_AC_KERNEL_SRC_SIGNAL_STOP
- 	ZFS_AC_KERNEL_SRC_SIGINFO
-+	ZFS_AC_KERNEL_SRC_SYSFS
- 	ZFS_AC_KERNEL_SRC_SET_SPECIAL_STATE
-+	ZFS_AC_KERNEL_SRC_VFS_READPAGES
- 	ZFS_AC_KERNEL_SRC_VFS_SET_PAGE_DIRTY_NOBUFFERS
- 	ZFS_AC_KERNEL_SRC_STANDALONE_LINUX_STDARG
- 	ZFS_AC_KERNEL_SRC_PAGEMAP_FOLIO_WAIT_BIT
- 	ZFS_AC_KERNEL_SRC_ADD_DISK
- 	ZFS_AC_KERNEL_SRC_KTHREAD
-+	ZFS_AC_KERNEL_SRC_ZERO_PAGE
-+	ZFS_AC_KERNEL_SRC___COPY_FROM_USER_INATOMIC
- 
- 	AC_MSG_CHECKING([for available kernel interfaces])
- 	ZFS_LINUX_TEST_COMPILE_ALL([kabi])
-@@ -171,6 +177,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
- 	ZFS_AC_KERNEL_BIO
- 	ZFS_AC_KERNEL_BLKDEV
- 	ZFS_AC_KERNEL_BLK_QUEUE
-+	ZFS_AC_KERNEL_GENHD_FLAGS
- 	ZFS_AC_KERNEL_REVALIDATE_DISK
- 	ZFS_AC_KERNEL_GET_DISK_RO
- 	ZFS_AC_KERNEL_GENERIC_READLINK_GLOBAL
-@@ -209,6 +216,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
- 	ZFS_AC_KERNEL_SET_NLINK
- 	ZFS_AC_KERNEL_SGET
- 	ZFS_AC_KERNEL_LSEEK_EXECUTE
-+	ZFS_AC_KERNEL_VFS_FILEMAP_DIRTY_FOLIO
- 	ZFS_AC_KERNEL_VFS_GETATTR
- 	ZFS_AC_KERNEL_VFS_FSYNC_2ARGS
- 	ZFS_AC_KERNEL_VFS_ITERATE
-@@ -241,12 +249,16 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
- 	ZFS_AC_KERNEL_BIO_MAX_SEGS
- 	ZFS_AC_KERNEL_SIGNAL_STOP
- 	ZFS_AC_KERNEL_SIGINFO
-+	ZFS_AC_KERNEL_SYSFS
- 	ZFS_AC_KERNEL_SET_SPECIAL_STATE
-+	ZFS_AC_KERNEL_VFS_READPAGES
- 	ZFS_AC_KERNEL_VFS_SET_PAGE_DIRTY_NOBUFFERS
- 	ZFS_AC_KERNEL_STANDALONE_LINUX_STDARG
- 	ZFS_AC_KERNEL_PAGEMAP_FOLIO_WAIT_BIT
- 	ZFS_AC_KERNEL_ADD_DISK
- 	ZFS_AC_KERNEL_KTHREAD
-+	ZFS_AC_KERNEL_ZERO_PAGE
-+	ZFS_AC_KERNEL___COPY_FROM_USER_INATOMIC
- ])
- 
- dnl #
-@@ -435,8 +447,6 @@ AC_DEFUN([ZFS_AC_KERNEL], [
- 	AC_SUBST(LINUX)
- 	AC_SUBST(LINUX_OBJ)
- 	AC_SUBST(LINUX_VERSION)
--
--	ZFS_AC_MODULE_SYMVERS
- ])
- 
- dnl #
-@@ -531,27 +541,6 @@ AC_DEFUN([ZFS_AC_QAT], [
- 	])
- ])
- 
--dnl #
--dnl # Basic toolchain sanity check.
--dnl #
--AC_DEFUN([ZFS_AC_KERNEL_TEST_MODULE], [
--	AC_MSG_CHECKING([whether modules can be built])
--	ZFS_LINUX_TRY_COMPILE([], [], [
--		AC_MSG_RESULT([yes])
--	],[
--		AC_MSG_RESULT([no])
--		if test "x$enable_linux_builtin" != xyes; then
--			AC_MSG_ERROR([
--	*** Unable to build an empty module.
--			])
--		else
--			AC_MSG_ERROR([
--	*** Unable to build an empty module.
--	*** Please run 'make scripts' inside the kernel source tree.])
--		fi
--	])
--])
--
- dnl #
- dnl # ZFS_LINUX_CONFTEST_H
- dnl #
-@@ -654,8 +643,10 @@ AC_DEFUN([ZFS_LINUX_COMPILE], [
- 		build kernel modules with LLVM/CLANG toolchain])
- 	AC_TRY_COMMAND([
- 	    KBUILD_MODPOST_NOFINAL="$5" KBUILD_MODPOST_WARN="$6"
--	    make modules -k -j$TEST_JOBS ${KERNEL_CC:+CC=$KERNEL_CC} ${KERNEL_LD:+LD=$KERNEL_LD} ${KERNEL_LLVM:+LLVM=$KERNEL_LLVM} -C $LINUX_OBJ $ARCH_UM
--	    M=$PWD/$1 >$1/build.log 2>&1])
-+	    make modules -k -j$TEST_JOBS ${KERNEL_CC:+CC=$KERNEL_CC}
-+	    ${KERNEL_LD:+LD=$KERNEL_LD} ${KERNEL_LLVM:+LLVM=$KERNEL_LLVM}
-+	    CONFIG_MODULES=y CFLAGS_MODULE=-DCONFIG_MODULES
-+	    -C $LINUX_OBJ $ARCH_UM M=$PWD/$1 >$1/build.log 2>&1])
- 	AS_IF([AC_TRY_COMMAND([$2])], [$3], [$4])
- ])
- 
-diff --git a/contrib/dracut/90zfs/export-zfs.sh.in b/contrib/dracut/90zfs/export-zfs.sh.in
-index 892650383..9e05ee03a 100755
---- a/contrib/dracut/90zfs/export-zfs.sh.in
-+++ b/contrib/dracut/90zfs/export-zfs.sh.in
-@@ -1,14 +1,12 @@
- #!/bin/sh
- 
--. /lib/dracut-zfs-lib.sh
--
- _do_zpool_export() {
- 	ret=0
- 	errs=""
- 	final="${1}"
- 
- 	info "ZFS: Exporting ZFS storage pools..."
--	errs=$(export_all -F 2>&1)
-+	errs=$(zpool export -aF 2>&1)
- 	ret=$?
- 	[ -z "${errs}" ] || echo "${errs}" | vwarn
- 	if [ "x${ret}" != "x0" ]; then
-diff --git a/contrib/dracut/90zfs/module-setup.sh.in b/contrib/dracut/90zfs/module-setup.sh.in
-index fbf32b658..7c01f125e 100755
---- a/contrib/dracut/90zfs/module-setup.sh.in
-+++ b/contrib/dracut/90zfs/module-setup.sh.in
-@@ -6,8 +6,8 @@ check() {
- 	[ "${1}" = "-d" ] && return 0
- 
- 	# Verify the zfs tool chain
--	for tool in "@sbindir@/zgenhostid" "@sbindir@/zpool" "@sbindir@/zfs" "@mounthelperdir@/mount.zfs" ; do
--		test -x "$tool" || return 1
-+	for tool in "zgenhostid" "zpool" "zfs" "mount.zfs"; do
-+		command -v "${tool}" >/dev/null || return 1
- 	done
- 
- 	return 0
-@@ -19,125 +19,86 @@ depends() {
- }
- 
- installkernel() {
--	instmods zfs
--	instmods zcommon
--	instmods znvpair
--	instmods zavl
--	instmods zunicode
--	instmods zlua
--	instmods icp
--	instmods spl
--	instmods zlib_deflate
--	instmods zlib_inflate
-+	instmods -c zfs
- }
- 
- install() {
--	inst_rules @udevruledir@/90-zfs.rules
--	inst_rules @udevruledir@/69-vdev.rules
--	inst_rules @udevruledir@/60-zvol.rules
--	dracut_install hostid
--	dracut_install grep
--	dracut_install @sbindir@/zgenhostid
--	dracut_install @sbindir@/zfs
--	dracut_install @sbindir@/zpool
--	# Workaround for https://github.com/openzfs/zfs/issues/4749 by
--	# ensuring libgcc_s.so(.1) is included
--	if ldd @sbindir@/zpool | grep -qF 'libgcc_s.so'; then
--		# Dracut will have already tracked and included it
--		:;
--	elif command -v gcc-config >/dev/null 2>&1; then
--		# On systems with gcc-config (Gentoo, Funtoo, etc.):
--		# Use the current profile to resolve the appropriate path
--		s="$(gcc-config -c)"
--		dracut_install "/usr/lib/gcc/${s%-*}/${s##*-}/libgcc_s.so"*
--	elif [ "$(echo /usr/lib/libgcc_s.so*)" != "/usr/lib/libgcc_s.so*" ]; then
--		# Try a simple path first
--		dracut_install /usr/lib/libgcc_s.so*
--	elif [ "$(echo /lib*/libgcc_s.so*)" != "/lib*/libgcc_s.so*" ]; then
--		# SUSE
--		dracut_install /lib*/libgcc_s.so*
--	else
--		# Fallback: Guess the path and include all matches
--		dracut_install /usr/lib*/gcc/**/libgcc_s.so*
--	fi
--	# shellcheck disable=SC2050
--	if [ @LIBFETCH_DYNAMIC@ -gt 0 ]; then
--		for d in $libdirs; do
--			[ -e "$d/@LIBFETCH_SONAME@" ] && dracut_install "$d/@LIBFETCH_SONAME@"
--		done
-+	inst_rules 90-zfs.rules 69-vdev.rules 60-zvol.rules
-+
-+	inst_multiple \
-+		zgenhostid \
-+		zfs \
-+		zpool \
-+		mount.zfs \
-+		hostid \
-+		grep \
-+		awk \
-+		tr \
-+		cut \
-+		head ||
-+		{ dfatal "Failed to install essential binaries"; exit 1; }
-+
-+	# Adapted from https://github.com/zbm-dev/zfsbootmenu
-+	if ! ldd "$(command -v zpool)" | grep -qF 'libgcc_s.so'; then
-+		# On systems with gcc-config (Gentoo, Funtoo, etc.), use it to find libgcc_s
-+		if command -v gcc-config >/dev/null; then
-+			inst_simple "/usr/lib/gcc/$(s=$(gcc-config -c); echo "${s%-*}/${s##*-}")/libgcc_s.so.1" ||
-+				{ dfatal "Unable to install libgcc_s.so"; exit 1; }
-+			# Otherwise, use dracut's library installation function to find the right one
-+		elif ! inst_libdir_file "libgcc_s.so*"; then
-+			# If all else fails, just try looking for some gcc arch directory
-+			inst_simple /usr/lib/gcc/*/*/libgcc_s.so* ||
-+				{ dfatal "Unable to install libgcc_s.so"; exit 1; }
-+		fi
- 	fi
--	dracut_install @mounthelperdir@/mount.zfs
--	dracut_install @udevdir@/vdev_id
--	dracut_install awk
--	dracut_install cut
--	dracut_install tr
--	dracut_install head
--	dracut_install @udevdir@/zvol_id
-+
- 	inst_hook cmdline 95 "${moddir}/parse-zfs.sh"
--	if [ -n "$systemdutildir" ] ; then
--		inst_script "${moddir}/zfs-generator.sh" "$systemdutildir"/system-generators/dracut-zfs-generator
-+	if [ -n "${systemdutildir}" ]; then
-+		inst_script "${moddir}/zfs-generator.sh" "${systemdutildir}/system-generators/dracut-zfs-generator"
- 	fi
- 	inst_hook pre-mount 90 "${moddir}/zfs-load-key.sh"
- 	inst_hook mount 98 "${moddir}/mount-zfs.sh"
- 	inst_hook cleanup 99 "${moddir}/zfs-needshutdown.sh"
- 	inst_hook shutdown 20 "${moddir}/export-zfs.sh"
- 
--	inst_simple "${moddir}/zfs-lib.sh" "/lib/dracut-zfs-lib.sh"
--	if [ -e @sysconfdir@/zfs/zpool.cache ]; then
--		inst @sysconfdir@/zfs/zpool.cache
--		type mark_hostonly >/dev/null 2>&1 && mark_hostonly @sysconfdir@/zfs/zpool.cache
--	fi
-+	inst_script "${moddir}/zfs-lib.sh" "/lib/dracut-zfs-lib.sh"
- 
--	if [ -e @sysconfdir@/zfs/vdev_id.conf ]; then
--		inst @sysconfdir@/zfs/vdev_id.conf
--		type mark_hostonly >/dev/null 2>&1 && mark_hostonly @sysconfdir@/zfs/vdev_id.conf
--	fi
-+	# -H ensures they are marked host-only
-+	# -o ensures there is no error upon absence of these files
-+	inst_multiple -o -H \
-+		"@sysconfdir@/zfs/zpool.cache" \
-+		"@sysconfdir@/zfs/vdev_id.conf"
- 
- 	# Synchronize initramfs and system hostid
--	if [ -f @sysconfdir@/hostid ]; then
--		inst @sysconfdir@/hostid
--		type mark_hostonly >/dev/null 2>&1 && mark_hostonly @sysconfdir@/hostid
--	elif HOSTID="$(hostid 2>/dev/null)" && [ "${HOSTID}" != "00000000" ]; then
--		zgenhostid -o "${initdir}@sysconfdir@/hostid" "${HOSTID}"
--		type mark_hostonly >/dev/null 2>&1 && mark_hostonly @sysconfdir@/hostid
-+	if ! inst_simple -H @sysconfdir@/hostid; then
-+		if HOSTID="$(hostid 2>/dev/null)" && [ "${HOSTID}" != "00000000" ]; then
-+			zgenhostid -o "${initdir}@sysconfdir@/hostid" "${HOSTID}"
-+			mark_hostonly @sysconfdir@/hostid
-+		fi
- 	fi
- 
- 	if dracut_module_included "systemd"; then
--		mkdir -p "${initdir}/$systemdsystemunitdir/zfs-import.target.wants"
--		for _service in "zfs-import-scan.service" "zfs-import-cache.service" ; do
--			dracut_install "@systemdunitdir@/$_service"
--			if ! [ -L "${initdir}/$systemdsystemunitdir/zfs-import.target.wants/$_service" ]; then
--				ln -sf ../$_service "${initdir}/$systemdsystemunitdir/zfs-import.target.wants/$_service"
--				type mark_hostonly >/dev/null 2>&1 && mark_hostonly "@systemdunitdir@/$_service"
--			fi
--		done
-+		inst_simple "${systemdsystemunitdir}/zfs-import.target"
-+		systemctl -q --root "${initdir}" add-wants initrd.target zfs-import.target
- 
--		inst "${moddir}"/zfs-env-bootfs.service "${systemdsystemunitdir}"/zfs-env-bootfs.service
--		ln -s ../zfs-env-bootfs.service "${initdir}/${systemdsystemunitdir}/zfs-import.target.wants"/zfs-env-bootfs.service
--		type mark_hostonly >/dev/null 2>&1 && mark_hostonly @systemdunitdir@/zfs-env-bootfs.service
-+		inst_simple "${moddir}/zfs-env-bootfs.service" "${systemdsystemunitdir}/zfs-env-bootfs.service"
-+		systemctl -q --root "${initdir}" add-wants zfs-import.target zfs-env-bootfs.service
- 
--		dracut_install systemd-ask-password
--		dracut_install systemd-tty-ask-password-agent
--
--		mkdir -p "${initdir}/$systemdsystemunitdir/initrd.target.wants"
--		dracut_install @systemdunitdir@/zfs-import.target
--		if ! [ -L "${initdir}/$systemdsystemunitdir/initrd.target.wants"/zfs-import.target ]; then
--			ln -s ../zfs-import.target "${initdir}/$systemdsystemunitdir/initrd.target.wants"/zfs-import.target
--			type mark_hostonly >/dev/null 2>&1 && mark_hostonly @systemdunitdir@/zfs-import.target
--		fi
-+		for _service in \
-+			"zfs-import-scan.service" \
-+			"zfs-import-cache.service" \
-+			"zfs-load-module.service"; do
-+			inst_simple "${systemdsystemunitdir}/${_service}"
-+			systemctl -q --root "${initdir}" add-wants zfs-import.target "${_service}"
-+		done
- 
--		for _service in zfs-snapshot-bootfs.service zfs-rollback-bootfs.service ; do
--			inst "${moddir}/$_service" "${systemdsystemunitdir}/$_service"
--			if ! [ -L "${initdir}/$systemdsystemunitdir/initrd.target.wants/$_service" ]; then
--				ln -s "../$_service" "${initdir}/$systemdsystemunitdir/initrd.target.wants/$_service"
--			fi
-+		for _service in \
-+			"zfs-snapshot-bootfs.service" \
-+			"zfs-rollback-bootfs.service"; do
-+			inst_simple "${moddir}/${_service}" "${systemdsystemunitdir}/${_service}"
-+			systemctl -q --root "${initdir}" add-wants initrd.target "${_service}"
- 		done
- 
--		# There isn't a pkg-config variable for this,
--		# and dracut doesn't automatically resolve anything this'd be next to
--		local systemdsystemenvironmentgeneratordir
--		systemdsystemenvironmentgeneratordir="$(pkg-config --variable=prefix systemd || echo "/usr")/lib/systemd/system-environment-generators"
--		mkdir -p "${initdir}/${systemdsystemenvironmentgeneratordir}"
--		inst "${moddir}"/import-opts-generator.sh "${systemdsystemenvironmentgeneratordir}"/zfs-import-opts.sh
-+		inst_simple "${moddir}/import-opts-generator.sh" "${systemdutildir}/system-environment-generators/zfs-import-opts.sh"
- 	fi
- }
-diff --git a/contrib/dracut/90zfs/mount-zfs.sh.in b/contrib/dracut/90zfs/mount-zfs.sh.in
-index 68e3f0e0d..fa9f1bb76 100755
---- a/contrib/dracut/90zfs/mount-zfs.sh.in
-+++ b/contrib/dracut/90zfs/mount-zfs.sh.in
-@@ -3,48 +3,73 @@
- 
- . /lib/dracut-zfs-lib.sh
- 
--ZFS_DATASET=""
--ZFS_POOL=""
--
--case "${root}" in
--	zfs:*) ;;
--	*) return ;;
--esac
-+decode_root_args || return 0
- 
- GENERATOR_FILE=/run/systemd/generator/sysroot.mount
- GENERATOR_EXTENSION=/run/systemd/generator/sysroot.mount.d/zfs-enhancement.conf
- 
--if [ -e "$GENERATOR_FILE" ] && [ -e "$GENERATOR_EXTENSION" ] ; then
--	# If the ZFS sysroot.mount flag exists, the initial RAM disk configured
--	# it to mount ZFS on root.  In that case, we bail early.  This flag
--	# file gets created by the zfs-generator program upon successful run.
--	info "ZFS: There is a sysroot.mount and zfs-generator has extended it."
--	info "ZFS: Delegating root mount to sysroot.mount."
--	# Let us tell the initrd to run on shutdown.
--	# We have a shutdown hook to run
--	# because we imported the pool.
-+if [ -e "$GENERATOR_FILE" ] && [ -e "$GENERATOR_EXTENSION" ]; then
-+	# We're under systemd and dracut-zfs-generator ran to completion.
-+	info "ZFS: Delegating root mount to sysroot.mount at al."
-+
- 	# We now prevent Dracut from running this thing again.
--	for zfsmounthook in "$hookdir"/mount/*zfs* ; do
--		if [ -f "$zfsmounthook" ] ; then
--			rm -f "$zfsmounthook"
--		fi
--	done
-+	rm -f "$hookdir"/mount/*zfs*
- 	return
- fi
-+
- info "ZFS: No sysroot.mount exists or zfs-generator did not extend it."
- info "ZFS: Mounting root with the traditional mount-zfs.sh instead."
- 
-+# ask_for_password tries prompt cmd
-+#
-+# Wraps around plymouth ask-for-password and adds fallback to tty password ask
-+# if plymouth is not present.
-+ask_for_password() {
-+    tries="$1"
-+    prompt="$2"
-+    cmd="$3"
-+
-+    {
-+        flock -s 9
-+
-+        # Prompt for password with plymouth, if installed and running.
-+        if plymouth --ping 2>/dev/null; then
-+            plymouth ask-for-password \
-+                --prompt "$prompt" --number-of-tries="$tries" | \
-+                eval "$cmd"
-+            ret=$?
-+        else
-+            i=1
-+            while [ "$i" -le "$tries" ]; do
-+                printf "%s [%i/%i]:" "$prompt" "$i" "$tries" >&2
-+                eval "$cmd" && ret=0 && break
-+                ret=$?
-+                i=$((i+1))
-+                printf '\n' >&2
-+            done
-+            unset i
-+        fi
-+    } 9>/.console_lock
-+
-+    [ "$ret" -ne 0 ] && echo "Wrong password" >&2
-+    return "$ret"
-+}
-+
-+
- # Delay until all required block devices are present.
- modprobe zfs 2>/dev/null
- udevadm settle
- 
-+ZFS_DATASET=
-+ZFS_POOL=
-+
- if [ "${root}" = "zfs:AUTO" ] ; then
--	if ! ZFS_DATASET="$(find_bootfs)" ; then
-+	if ! ZFS_DATASET="$(zpool get -Ho value bootfs | grep -m1 -vFx -)"; then
- 		# shellcheck disable=SC2086
- 		zpool import -N -a ${ZPOOL_IMPORT_OPTS}
--		if ! ZFS_DATASET="$(find_bootfs)" ; then
-+		if ! ZFS_DATASET="$(zpool get -Ho value bootfs | grep -m1 -vFx -)"; then
- 			warn "ZFS: No bootfs attribute found in importable pools."
--			export_all -F
-+			zpool export -aF
- 
- 			rootok=0
- 			return 1
-@@ -53,34 +78,43 @@ if [ "${root}" = "zfs:AUTO" ] ; then
- 	info "ZFS: Using ${ZFS_DATASET} as root."
- fi
- 
--ZFS_DATASET="${ZFS_DATASET:-${root#zfs:}}"
-+ZFS_DATASET="${ZFS_DATASET:-${root}}"
- ZFS_POOL="${ZFS_DATASET%%/*}"
- 
--if import_pool "${ZFS_POOL}" ; then
--	# Load keys if we can or if we need to
--	if [ "$(zpool list -H -o feature at encryption "${ZFS_POOL}")" = 'active' ]; then
--		# if the root dataset has encryption enabled
--		ENCRYPTIONROOT="$(zfs get -H -o value encryptionroot "${ZFS_DATASET}")"
--		if ! [ "${ENCRYPTIONROOT}" = "-" ]; then
--			KEYSTATUS="$(zfs get -H -o value keystatus "${ENCRYPTIONROOT}")"
--			# if the key needs to be loaded
--			if [ "$KEYSTATUS" = "unavailable" ]; then
--				# decrypt them
--				ask_for_password \
--					--tries 5 \
--					--prompt "Encrypted ZFS password for ${ENCRYPTIONROOT}: " \
--					--cmd "zfs load-key '${ENCRYPTIONROOT}'"
--			fi
-+
-+if ! zpool get -Ho name "${ZFS_POOL}" > /dev/null 2>&1; then
-+    info "ZFS: Importing pool ${ZFS_POOL}..."
-+    # shellcheck disable=SC2086
-+    if ! zpool import -N ${ZPOOL_IMPORT_OPTS} "${ZFS_POOL}"; then
-+        warn "ZFS: Unable to import pool ${ZFS_POOL}"
-+        rootok=0
-+        return 1
-+    fi
-+fi
-+
-+# Load keys if we can or if we need to
-+# TODO: for_relevant_root_children like in zfs-load-key.sh.in
-+if [ "$(zpool get -Ho value feature at encryption "${ZFS_POOL}")" = 'active' ]; then
-+	# if the root dataset has encryption enabled
-+	ENCRYPTIONROOT="$(zfs get -Ho value encryptionroot "${ZFS_DATASET}")"
-+	if ! [ "${ENCRYPTIONROOT}" = "-" ]; then
-+		KEYSTATUS="$(zfs get -Ho value keystatus "${ENCRYPTIONROOT}")"
-+		# if the key needs to be loaded
-+		if [ "$KEYSTATUS" = "unavailable" ]; then
-+			# decrypt them
-+			ask_for_password \
-+				5 \
-+				"Encrypted ZFS password for ${ENCRYPTIONROOT}: " \
-+				"zfs load-key '${ENCRYPTIONROOT}'"
- 		fi
- 	fi
--	# Let us tell the initrd to run on shutdown.
--	# We have a shutdown hook to run
--	# because we imported the pool.
--	info "ZFS: Mounting dataset ${ZFS_DATASET}..."
--	if mount_dataset "${ZFS_DATASET}" ; then
--		ROOTFS_MOUNTED=yes
--		return 0
--	fi
- fi
- 
--rootok=0
-+# Let us tell the initrd to run on shutdown.
-+# We have a shutdown hook to run
-+# because we imported the pool.
-+info "ZFS: Mounting dataset ${ZFS_DATASET}..."
-+if ! mount_dataset "${ZFS_DATASET}"; then
-+  rootok=0
-+  return 1
-+fi
-diff --git a/contrib/dracut/90zfs/parse-zfs.sh.in b/contrib/dracut/90zfs/parse-zfs.sh.in
-index 0f92f5c80..f7d1f1c5d 100755
---- a/contrib/dracut/90zfs/parse-zfs.sh.in
-+++ b/contrib/dracut/90zfs/parse-zfs.sh.in
-@@ -1,7 +1,8 @@
- #!/bin/sh
- # shellcheck disable=SC2034,SC2154
- 
--. /lib/dracut-lib.sh
-+# shellcheck source=zfs-lib.sh.in
-+. /lib/dracut-zfs-lib.sh
- 
- # Let the command line override our host id.
- spl_hostid=$(getarg spl_hostid=)
-@@ -15,49 +16,20 @@ else
- 	warn "ZFS: Pools may not import correctly."
- fi
- 
--wait_for_zfs=0
--case "${root}" in
--	""|zfs|zfs:)
--		# We'll take root unset, root=zfs, or root=zfs:
--		# No root set, so we want to read the bootfs attribute.  We
--		# can't do that until udev settles so we'll set dummy values
--		# and hope for the best later on.
--		root="zfs:AUTO"
--		rootok=1
--		wait_for_zfs=1
--
--		info "ZFS: Enabling autodetection of bootfs after udev settles."
--		;;
--
--	ZFS=*|zfs:*|FILESYSTEM=*)
--		# root is explicit ZFS root.  Parse it now.  We can handle
--		# a root=... param in any of the following formats:
--		# root=ZFS=rpool/ROOT
--		# root=zfs:rpool/ROOT
--		# root=zfs:FILESYSTEM=rpool/ROOT
--		# root=FILESYSTEM=rpool/ROOT
--		# root=ZFS=pool+with+space/ROOT+WITH+SPACE (translates to root=ZFS=pool with space/ROOT WITH SPACE)
--
--		# Strip down to just the pool/fs
--		root="${root#zfs:}"
--		root="${root#FILESYSTEM=}"
--		root="zfs:${root#ZFS=}"
--		# switch + with spaces because kernel cmdline does not allow us to quote parameters
--		root=$(echo "$root" | tr '+' ' ')
--		rootok=1
--		wait_for_zfs=1
--
--		info "ZFS: Set ${root} as bootfs."
--		;;
--esac
--
--# Make sure Dracut is happy that we have a root and will wait for ZFS
--# modules to settle before mounting.
--if [ ${wait_for_zfs} -eq 1 ]; then
--	ln -s /dev/null /dev/root 2>/dev/null
--	initqueuedir="${hookdir}/initqueue/finished"
--	test -d "${initqueuedir}" || {
--		initqueuedir="${hookdir}/initqueue-finished"
--	}
--	echo '[ -e /dev/zfs ]' > "${initqueuedir}/zfs.sh"
-+if decode_root_args; then
-+	if [ "$root" = "zfs:AUTO" ]; then
-+		info "ZFS: Boot dataset autodetected from bootfs=."
-+	else
-+		info "ZFS: Boot dataset is ${root}."
-+	fi
-+
-+	rootok=1
-+	# Make sure Dracut is happy that we have a root and will wait for ZFS
-+	# modules to settle before mounting.
-+	if [ -n "${wait_for_zfs}" ]; then
-+		ln -s null /dev/root
-+		echo '[ -e /dev/zfs ]' > "${hookdir}/initqueue/finished/zfs.sh"
-+	fi
-+else
-+	info "ZFS: no ZFS-on-root."
- fi
-diff --git a/contrib/dracut/90zfs/zfs-env-bootfs.service.in b/contrib/dracut/90zfs/zfs-env-bootfs.service.in
-index e143cb5ec..34c88037c 100644
---- a/contrib/dracut/90zfs/zfs-env-bootfs.service.in
-+++ b/contrib/dracut/90zfs/zfs-env-bootfs.service.in
-@@ -8,7 +8,7 @@ Before=zfs-import.target
- 
- [Service]
- Type=oneshot
--ExecStart=/bin/sh -c "exec systemctl set-environment BOOTFS=$(@sbindir@/zpool list -H -o bootfs | grep -m1 -v '^-$')"
-+ExecStart=/bin/sh -c "exec systemctl set-environment BOOTFS=$(@sbindir@/zpool list -H -o bootfs | grep -m1 -vFx -)"
- 
- [Install]
- WantedBy=zfs-import.target
-diff --git a/contrib/dracut/90zfs/zfs-generator.sh.in b/contrib/dracut/90zfs/zfs-generator.sh.in
-index e50b9530c..56f7ca978 100755
---- a/contrib/dracut/90zfs/zfs-generator.sh.in
-+++ b/contrib/dracut/90zfs/zfs-generator.sh.in
-@@ -1,5 +1,5 @@
- #!/bin/sh
--# shellcheck disable=SC2016,SC1004
-+# shellcheck disable=SC2016,SC1004,SC2154
- 
- grep -wq debug /proc/cmdline && debug=1
- [ -n "$debug" ] && echo "zfs-generator: starting" >> /dev/kmsg
-@@ -10,37 +10,17 @@ GENERATOR_DIR="$1"
-     exit 1
- }
- 
--[ -f /lib/dracut-lib.sh ] && dracutlib=/lib/dracut-lib.sh
--[ -f /usr/lib/dracut/modules.d/99base/dracut-lib.sh ] && dracutlib=/usr/lib/dracut/modules.d/99base/dracut-lib.sh
--command -v getarg >/dev/null 2>&1 || {
--    [ -n "$debug" ] && echo "zfs-generator: loading Dracut library from $dracutlib" >> /dev/kmsg
--    . "$dracutlib"
--}
--
-+# shellcheck source=zfs-lib.sh.in
- . /lib/dracut-zfs-lib.sh
-+decode_root_args || exit 0
- 
--[ -z "$root" ]       && root=$(getarg root=)
--[ -z "$rootfstype" ] && rootfstype=$(getarg rootfstype=)
--[ -z "$rootflags" ]  && rootflags=$(getarg rootflags=)
--
--# If root is not ZFS= or zfs: or rootfstype is not zfs
--# then we are not supposed to handle it.
--[ "${root##zfs:}" = "${root}" ] &&
--	[ "${root##ZFS=}" = "${root}" ] &&
--	[ "$rootfstype" != "zfs" ] &&
--	exit 0
--
-+[ -z "${rootflags}" ] && rootflags=$(getarg rootflags=)
- case ",${rootflags}," in
- 	*,zfsutil,*) ;;
- 	,,)	rootflags=zfsutil ;;
- 	*)	rootflags="zfsutil,${rootflags}" ;;
- esac
- 
--if [ "${root}" != "zfs:AUTO" ]; then
--  root="${root##zfs:}"
--  root="${root##ZFS=}"
--fi
--
- [ -n "$debug" ] && echo "zfs-generator: writing extension for sysroot.mount to $GENERATOR_DIR/sysroot.mount.d/zfs-enhancement.conf" >> /dev/kmsg
- 
- 
-@@ -89,7 +69,7 @@ else
-   _zfs_generator_cb() {
-       dset="${1}"
-       mpnt="${2}"
--      unit="sysroot$(echo "$mpnt" | tr '/' '-').mount"
-+      unit="$(systemd-escape --suffix=mount -p "/sysroot${mpnt}")"
- 
-       {
-           echo "[Unit]"
-diff --git a/contrib/dracut/90zfs/zfs-lib.sh.in b/contrib/dracut/90zfs/zfs-lib.sh.in
-index defc0bfc8..a91b56ba7 100755
---- a/contrib/dracut/90zfs/zfs-lib.sh.in
-+++ b/contrib/dracut/90zfs/zfs-lib.sh.in
-@@ -1,74 +1,16 @@
- #!/bin/sh
-+# shellcheck disable=SC2034
- 
--command -v getarg >/dev/null || . /lib/dracut-lib.sh
--command -v getargbool >/dev/null || {
--    # Compatibility with older Dracut versions.
--    # With apologies to the Dracut developers.
--    getargbool() {
--        _default="$1"; shift
--        ! _b=$(getarg "$@") && [ -z "$_b" ] && _b="$_default"
--        if [ -n "$_b" ]; then
--            [ "$_b" = "0" ] && return 1
--            [ "$_b" = "no" ] && return 1
--            [ "$_b" = "off" ] && return 1
--        fi
--        return 0
--    }
--}
-+command -v getarg >/dev/null || . /lib/dracut-lib.sh || . /usr/lib/dracut/modules.d/99base/dracut-lib.sh
- 
--OLDIFS="${IFS}"
--NEWLINE="
--"
- TAB="	"
- 
--ZPOOL_IMPORT_OPTS=""
--if getargbool 0 zfs_force -y zfs.force -y zfsforce ; then
-+ZPOOL_IMPORT_OPTS=
-+if getargbool 0 zfs_force -y zfs.force -y zfsforce; then
-     warn "ZFS: Will force-import pools if necessary."
--    ZPOOL_IMPORT_OPTS="${ZPOOL_IMPORT_OPTS} -f"
-+    ZPOOL_IMPORT_OPTS=-f
- fi
- 
--# find_bootfs
--#   returns the first dataset with the bootfs attribute.
--find_bootfs() {
--    IFS="${NEWLINE}"
--    for dataset in $(zpool list -H -o bootfs); do
--        case "${dataset}" in
--            "" | "-")
--                continue
--                ;;
--            "no pools available")
--                IFS="${OLDIFS}"
--                return 1
--                ;;
--            *)
--                IFS="${OLDIFS}"
--                echo "${dataset}"
--                return 0
--                ;;
--        esac
--    done
--
--    IFS="${OLDIFS}"
--    return 1
--}
--
--# import_pool POOL
--#   imports the given zfs pool if it isn't imported already.
--import_pool() {
--    pool="${1}"
--
--    if ! zpool list -H "${pool}" > /dev/null 2>&1; then
--        info "ZFS: Importing pool ${pool}..."
--        # shellcheck disable=SC2086
--        if ! zpool import -N ${ZPOOL_IMPORT_OPTS} "${pool}" ; then
--            warn "ZFS: Unable to import pool ${pool}"
--            return 1
--        fi
--    fi
--
--    return 0
--}
--
- _mount_dataset_cb() {
-     mount -o zfsutil -t zfs "${1}" "${NEWROOT}${2}"
- }
-@@ -121,87 +63,57 @@ for_relevant_root_children() {
-         )
- }
- 
--# export_all OPTS
--#   exports all imported zfs pools.
--export_all() {
--    ret=0
--
--    IFS="${NEWLINE}"
--    for pool in $(zpool list -H -o name) ; do
--        if zpool list -H "${pool}" > /dev/null 2>&1; then
--            zpool export "${pool}" "$@" || ret=$?
--        fi
--    done
--    IFS="${OLDIFS}"
--
--    return ${ret}
--}
--
--# ask_for_password
-+# Parse root=, rootfstype=, return them decoded and normalised to zfs:AUTO for auto, plain dset for explicit
-+#
-+# True if ZFS-on-root, false if we shouldn't
-+#
-+# Supported values:
-+#   root=
-+#   root=zfs
-+#   root=zfs:
-+#   root=zfs:AUTO
-+#
-+#   root=ZFS=data/set
-+#   root=zfs:data/set
-+#   root=zfs:ZFS=data/set (as a side-effect; allowed but undocumented)
- #
--# Wraps around plymouth ask-for-password and adds fallback to tty password ask
--# if plymouth is not present.
-+#   rootfstype=zfs AND root=data/set <=> root=data/set
-+#   rootfstype=zfs AND root=         <=> root=zfs:AUTO
- #
--# --cmd command
--#   Command to execute. Required.
--# --prompt prompt
--#   Password prompt. Note that function already adds ':' at the end.
--#   Recommended.
--# --tries n
--#   How many times repeat command on its failure.  Default is 3.
--# --ply-[cmd|prompt|tries]
--#   Command/prompt/tries specific for plymouth password ask only.
--# --tty-[cmd|prompt|tries]
--#   Command/prompt/tries specific for tty password ask only.
--# --tty-echo-off
--#   Turn off input echo before tty command is executed and turn on after.
--#   It's useful when password is read from stdin.
--ask_for_password() {
--    ply_tries=3
--    tty_tries=3
--    while [ "$#" -gt 0 ]; do
--        case "$1" in
--            --cmd) ply_cmd="$2"; tty_cmd="$2"; shift;;
--            --ply-cmd) ply_cmd="$2"; shift;;
--            --tty-cmd) tty_cmd="$2"; shift;;
--            --prompt) ply_prompt="$2"; tty_prompt="$2"; shift;;
--            --ply-prompt) ply_prompt="$2"; shift;;
--            --tty-prompt) tty_prompt="$2"; shift;;
--            --tries) ply_tries="$2"; tty_tries="$2"; shift;;
--            --ply-tries) ply_tries="$2"; shift;;
--            --tty-tries) tty_tries="$2"; shift;;
--            --tty-echo-off) tty_echo_off=yes;;
-+# '+'es in explicit dataset decoded to ' 's.
-+decode_root_args() {
-+    if [ -n "$rootfstype" ]; then
-+        [ "$rootfstype" = zfs ]
-+        return
-+    fi
-+
-+    root=$(getarg root=)
-+    rootfstype=$(getarg rootfstype=)
-+
-+    # shellcheck disable=SC2249
-+    case "$root" in
-+        ""|zfs|zfs:|zfs:AUTO)
-+            root=zfs:AUTO
-+            rootfstype=zfs
-+            return 0
-+            ;;
-+
-+        ZFS=*|zfs:*)
-+            root="${root#zfs:}"
-+            root="${root#ZFS=}"
-+            root=$(echo "$root" | tr '+' ' ')
-+            rootfstype=zfs
-+            return 0
-+            ;;
-+    esac
-+
-+    if [ "$rootfstype" = "zfs" ]; then
-+        case "$root" in
-+            "") root=zfs:AUTO ;;
-+            *)  root=$(echo "$root" | tr '+' ' ') ;;
-         esac
--        shift
--    done
--
--    { flock -s 9;
--        # Prompt for password with plymouth, if installed and running.
--        if plymouth --ping 2>/dev/null; then
--            plymouth ask-for-password \
--                --prompt "$ply_prompt" --number-of-tries="$ply_tries" | \
--                eval "$ply_cmd"
--            ret=$?
--        else
--            if [ "$tty_echo_off" = yes ]; then
--                stty_orig="$(stty -g)"
--                stty -echo
--            fi
--
--            i=1
--            while [ "$i" -le "$tty_tries" ]; do
--                [ -n "$tty_prompt" ] && \
--                    printf "%s [%i/%i]:" "$tty_prompt" "$i" "$tty_tries" >&2
--                eval "$tty_cmd" && ret=0 && break
--                ret=$?
--                i=$((i+1))
--                [ -n "$tty_prompt" ] && printf '\n' >&2
--            done
--            unset i
--            [ "$tty_echo_off" = yes ] && stty "$stty_orig"
--        fi
--    } 9>/.console_lock
-+        return 0
-+    fi
- 
--    [ $ret -ne 0 ] && echo "Wrong password" >&2
--    return $ret
-+    return 1
- }
-diff --git a/contrib/dracut/90zfs/zfs-load-key.sh.in b/contrib/dracut/90zfs/zfs-load-key.sh.in
-index c974b3d9e..d916f43b4 100755
---- a/contrib/dracut/90zfs/zfs-load-key.sh.in
-+++ b/contrib/dracut/90zfs/zfs-load-key.sh.in
-@@ -4,70 +4,61 @@
- # only run this on systemd systems, we handle the decrypt in mount-zfs.sh in the mount hook otherwise
- [ -e /bin/systemctl ] || [ -e /usr/bin/systemctl ] || return 0
- 
--# This script only gets executed on systemd systems, see mount-zfs.sh for non-systemd systems
-+# shellcheck source=zfs-lib.sh.in
-+. /lib/dracut-zfs-lib.sh
- 
--# import the libs now that we know the pool imported
--[ -f /lib/dracut-lib.sh ] && dracutlib=/lib/dracut-lib.sh
--[ -f /usr/lib/dracut/modules.d/99base/dracut-lib.sh ] && dracutlib=/usr/lib/dracut/modules.d/99base/dracut-lib.sh
--# shellcheck source=./lib-zfs.sh.in
--. "$dracutlib"
--
--# load the kernel command line vars
--[ -z "$root" ] && root="$(getarg root=)"
--# If root is not ZFS= or zfs: or rootfstype is not zfs then we are not supposed to handle it.
--[ "${root##zfs:}" = "${root}" ] && [ "${root##ZFS=}" = "${root}" ] && [ "$rootfstype" != "zfs" ] && exit 0
-+decode_root_args || return 0
- 
- # There is a race between the zpool import and the pre-mount hooks, so we wait for a pool to be imported
--while [ "$(zpool list -H)" = "" ]; do
--    systemctl is-failed --quiet zfs-import-cache.service zfs-import-scan.service && exit 1
-+while ! systemctl is-active --quiet zfs-import.target; do
-+    systemctl is-failed --quiet zfs-import-cache.service zfs-import-scan.service && return 1
-     sleep 0.1s
- done
- 
--# run this after import as zfs-import-cache/scan service is confirmed good
--# we do not overwrite the ${root} variable, but create a new one, BOOTFS, to hold the dataset
--if [ "${root}" = "zfs:AUTO" ] ; then
--    BOOTFS="$(zpool list -H -o bootfs | awk '$1 != "-" {print; exit}')"
--else
--    BOOTFS="${root##zfs:}"
--    BOOTFS="${BOOTFS##ZFS=}"
-+BOOTFS="$root"
-+if [ "$BOOTFS" = "zfs:AUTO" ]; then
-+    BOOTFS="$(zpool get -Ho value bootfs | grep -m1 -vFx -)"
- fi
- 
--# if pool encryption is active and the zfs command understands '-o encryption'
--if [ "$(zpool list -H -o feature at encryption "${BOOTFS%%/*}")" = 'active' ]; then
--    # if the root dataset has encryption enabled
--    ENCRYPTIONROOT="$(zfs get -H -o value encryptionroot "${BOOTFS}")"
--    if ! [ "${ENCRYPTIONROOT}" = "-" ]; then
--        KEYSTATUS="$(zfs get -H -o value keystatus "${ENCRYPTIONROOT}")"
--        # continue only if the key needs to be loaded
--        [ "$KEYSTATUS" = "unavailable" ] || exit 0
-+[ "$(zpool get -Ho value feature at encryption "${BOOTFS%%/*}")" = 'active' ] || return 0
-+
-+_load_key_cb() {
-+    dataset="$1"
-+
-+    ENCRYPTIONROOT="$(zfs get -Ho value encryptionroot "${dataset}")"
-+    [ "${ENCRYPTIONROOT}" = "-" ] && return 0
- 
--        KEYLOCATION="$(zfs get -H -o value keylocation "${ENCRYPTIONROOT}")"
--        case "${KEYLOCATION%%://*}" in
--            prompt)
--                for _ in 1 2 3; do
--                    systemd-ask-password --no-tty "Encrypted ZFS password for ${BOOTFS}" | zfs load-key "${ENCRYPTIONROOT}" && break
-+    [ "$(zfs get -Ho value keystatus "${ENCRYPTIONROOT}")" = "unavailable" ] || return 0
-+
-+    KEYLOCATION="$(zfs get -Ho value keylocation "${ENCRYPTIONROOT}")"
-+    case "${KEYLOCATION%%://*}" in
-+        prompt)
-+            for _ in 1 2 3; do
-+                systemd-ask-password --no-tty "Encrypted ZFS password for ${dataset}" | zfs load-key "${ENCRYPTIONROOT}" && break
-+            done
-+            ;;
-+        http*)
-+            systemctl start network-online.target
-+            zfs load-key "${ENCRYPTIONROOT}"
-+            ;;
-+        file)
-+            KEYFILE="${KEYLOCATION#file://}"
-+            [ -r "${KEYFILE}" ] || udevadm settle
-+            [ -r "${KEYFILE}" ] || {
-+                info "ZFS: Waiting for key ${KEYFILE} for ${ENCRYPTIONROOT}..."
-+                for _ in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do
-+                    sleep 0.5s
-+                    [ -r "${KEYFILE}" ] && break
-                 done
--                ;;
--            http*)
--                systemctl start network-online.target
--                zfs load-key "${ENCRYPTIONROOT}"
--                ;;
--            file)
--                KEYFILE="${KEYLOCATION#file://}"
--                [ -r "${KEYFILE}" ] || udevadm settle
--                [ -r "${KEYFILE}" ] || {
--                    info "Waiting for key ${KEYFILE} for ${ENCRYPTIONROOT}..."
--                    for _ in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do
--                        sleep 0.5s
--                        [ -r "${KEYFILE}" ] && break
--                    done
--                }
--                [ -r "${KEYFILE}" ] || warn "Key ${KEYFILE} for ${ENCRYPTIONROOT} hasn't appeared. Trying anyway."
--                zfs load-key "${ENCRYPTIONROOT}"
--                ;;
--            *)
--                zfs load-key "${ENCRYPTIONROOT}"
--                ;;
--        esac
--    fi
--fi
-+            }
-+            [ -r "${KEYFILE}" ] || warn "ZFS: Key ${KEYFILE} for ${ENCRYPTIONROOT} hasn't appeared. Trying anyway."
-+            zfs load-key "${ENCRYPTIONROOT}"
-+            ;;
-+        *)
-+            zfs load-key "${ENCRYPTIONROOT}"
-+            ;;
-+    esac
-+}
-+
-+_load_key_cb "$BOOTFS"
-+for_relevant_root_children "$BOOTFS" _load_key_cb
-diff --git a/contrib/dracut/90zfs/zfs-needshutdown.sh.in b/contrib/dracut/90zfs/zfs-needshutdown.sh.in
-index dd6de30c2..7fb825bc9 100755
---- a/contrib/dracut/90zfs/zfs-needshutdown.sh.in
-+++ b/contrib/dracut/90zfs/zfs-needshutdown.sh.in
-@@ -2,7 +2,7 @@
- 
- command -v getarg >/dev/null 2>&1 || . /lib/dracut-lib.sh
- 
--if zpool list 2>&1 | grep -q 'no pools available' ; then
-+if [ -z "$(zpool get -Ho value name)" ]; then
-     info "ZFS: No active pools, no need to export anything."
- else
-     info "ZFS: There is an active pool, will export it."
-diff --git a/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in b/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in
-index bdc246943..b4f570751 100644
---- a/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in
-+++ b/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in
-@@ -1,14 +1,12 @@
- [Unit]
- Description=Rollback bootfs just before it is mounted
- Requisite=zfs-import.target
--After=zfs-import.target zfs-snapshot-bootfs.service
-+After=zfs-import.target dracut-pre-mount.service zfs-snapshot-bootfs.service
- Before=dracut-mount.service
- DefaultDependencies=no
- ConditionKernelCommandLine=bootfs.rollback
- 
- [Service]
--# ${BOOTFS} should have been set by zfs-env-bootfs.service
- Type=oneshot
--ExecStartPre=/bin/sh -c 'test -n "${BOOTFS}"'
--ExecStart=/bin/sh -c '. /lib/dracut-lib.sh; SNAPNAME="$(getarg bootfs.rollback)"; exec @sbindir@/zfs rollback -Rf "${BOOTFS}@${SNAPNAME:-%v}"'
-+ExecStart=/bin/sh -c '. /lib/dracut-zfs-lib.sh; decode_root_args || exit; [ "$root" = "zfs:AUTO" ] && root="$BOOTFS" SNAPNAME="$(getarg bootfs.rollback)"; exec @sbindir@/zfs rollback -Rf "$root@${SNAPNAME:-%v}"'
- RemainAfterExit=yes
-diff --git a/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in b/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in
-index 6ea13850c..afdba2c9d 100644
---- a/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in
-+++ b/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in
-@@ -1,14 +1,12 @@
- [Unit]
- Description=Snapshot bootfs just before it is mounted
- Requisite=zfs-import.target
--After=zfs-import.target
-+After=zfs-import.target dracut-pre-mount.service
- Before=dracut-mount.service
- DefaultDependencies=no
- ConditionKernelCommandLine=bootfs.snapshot
- 
- [Service]
--# ${BOOTFS} should have been set by zfs-env-bootfs.service
- Type=oneshot
--ExecStartPre=/bin/sh -c 'test -n "${BOOTFS}"'
--ExecStart=-/bin/sh -c '. /lib/dracut-lib.sh; SNAPNAME="$(getarg bootfs.snapshot)"; exec @sbindir@/zfs snapshot "${BOOTFS}@${SNAPNAME:-%v}"'
-+ExecStart=/bin/sh -c '. /lib/dracut-zfs-lib.sh; decode_root_args || exit; [ "$root" = "zfs:AUTO" ] && root="$BOOTFS" SNAPNAME="$(getarg bootfs.snapshot)"; exec @sbindir@/zfs snapshot "$root@${SNAPNAME:-%v}"'
- RemainAfterExit=yes
-diff --git a/contrib/dracut/README.dracut.markdown b/contrib/dracut/README.dracut.markdown
-index f31543c3c..b7cd8c812 100644
---- a/contrib/dracut/README.dracut.markdown
-+++ b/contrib/dracut/README.dracut.markdown
-@@ -1,225 +1,50 @@
--How to setup a zfs root filesystem using dracut
-------------------------------------------------
-+## Basic setup
-+1. Install `zfs-dracut`
-+2. Set `mountpoint=/` for your root dataset (for compatibility, `legacy` also works, but is not recommended for new installations):
-+    ```sh
-+    zfs set mountpoint=/ pool/dataset
-+    ```
-+3. Either (a) set `bootfs=` on the pool to the dataset:
-+    ```sh
-+    zpool set bootfs=pool/dataset pool
-+    ```
-+4. Or (b) append `root=zfs:pool/dataset` to your kernel cmdline.
-+5. Re-generate your initrd and update it in your boot bundle
- 
--1) Install the zfs-dracut package.  This package adds a zfs dracut module
--to the /usr/share/dracut/modules.d/ directory which allows dracut to
--create an initramfs which is zfs aware.
-+Encrypted datasets have keys loaded automatically or prompted for.
- 
--2) Set the bootfs property for the bootable dataset in the pool.  Then set
--the dataset mountpoint property to '/'.
-+If the root dataset contains children with `mountpoint=`s of `/etc`, `/bin`, `/lib*`, or `/usr`, they're mounted too.
- 
--    $ zpool set bootfs=pool/dataset pool
--    $ zfs set mountpoint=/ pool/dataset
-+For complete documentation, see `dracut.zfs(7)`.
- 
--Alternately, legacy mountpoints can be used by setting the 'root=' option
--on the kernel line of your grub.conf/menu.lst configuration file.  Then
--set the dataset mountpoint property to 'legacy'.
-+## cmdline
-+1. `root=`                    | Root dataset is…                                         |
-+   ---------------------------|----------------------------------------------------------|
-+   *(empty)*                  | the first `bootfs=` after `zpool import -aN`             |
-+   `zfs:AUTO`, `zfs:`, `zfs`  | *(as above, but overriding other autoselection methods)* |
-+   `ZFS=pool/dataset`         | `pool/dataset`                                           |
-+   `zfs:pool/dataset`         | *(as above)*                                             |
- 
--    $ grub.conf/menu.lst: kernel ... root=ZFS=pool/dataset
--    $ zfs set mountpoint=legacy pool/dataset
-+   All `+`es are replaced with spaces (i.e. to boot from `root pool/data set`, pass `root=zfs:root+pool/data+set`).
- 
--3) To set zfs module options put them in /etc/modprobe.d/zfs.conf file.
--The complete list of zfs module options is available by running the
--_modinfo zfs_ command.  Commonly set options include: zfs_arc_min,
--zfs_arc_max, zfs_prefetch_disable, and zfs_vdev_max_pending.
-+   The dataset can be at any depth, including being the pool's root dataset (i.e. `root=zfs:pool`).
- 
--4) Finally, create your new initramfs by running dracut.
-+   `rootfstype=zfs` is equivalent to `root=zfs:AUTO`, `rootfstype=zfs root=pool/dataset` is equivalent to `root=zfs:pool/dataset`.
- 
--    $ dracut --force /path/to/initramfs kernel_version
-+2. `spl_hostid`: passed to `zgenhostid -f`, useful to override the `/etc/hostid` file baked into the initrd.
- 
--Kernel Command Line
---------------------
-+3. `bootfs.snapshot`, `bootfs.snapshot=snapshot-name`: enables `zfs-snapshot-bootfs.service`,
-+   which creates a snapshot `$root_dataset@$(uname -r)` (or, in the second form, `$root_dataset at snapshot-name`)
-+   after pool import but before the rootfs is mounted.
-+   Failure to create the snapshot is noted, but booting continues.
- 
--The initramfs' behavior is influenced by the following kernel command line
--parameters passed in from the boot loader:
-+4. `bootfs.rollback`, `bootfs.rollback=snapshot-name`: enables `zfs-snapshot-bootfs.service`,
-+   which `-Rf` rolls back to `$root_dataset@$(uname -r)` (or, in the second form, `$root_dataset at snapshot-name`)
-+   after pool import but before the rootfs is mounted.
-+   Failure to roll back will fall down to the rescue shell.
-+   This has obvious potential for data loss: make sure your persistent data is not below the rootfs and you don't care about any intermediate snapshots.
- 
--* `root=...`: If not set, importable pools are searched for a bootfs
--attribute.  If an explicitly set root is desired, you may use
--`root=ZFS:pool/dataset`
-+5. If both `bootfs.snapshot` and `bootfs.rollback` are set, `bootfs.rollback` is ordered *after* `bootfs.snapshot`.
- 
--* `zfs_force=0`: If set to 1, the initramfs will run `zpool import -f` when
--attempting to import pools if the required pool isn't automatically imported
--by the zfs module.  This can save you a trip to a bootcd if hostid has
--changed, but is dangerous and can lead to zpool corruption, particularly in
--cases where storage is on a shared fabric such as iSCSI where multiple hosts
--can access storage devices concurrently.  _Please understand the implications
--of force-importing a pool before enabling this option!_
--
--* `spl_hostid`: By default, the hostid used by the SPL module is read from
--/etc/hostid inside the initramfs.  This file is placed there from the host
--system when the initramfs is built which effectively ties the ramdisk to the
--host which builds it.  If a different hostid is desired, one may be set in
--this attribute and will override any file present in the ramdisk.  The
--format should be hex exactly as found in the `/etc/hostid` file, IE
--`spl_hostid=0x00bab10c`.
--
--Note that changing the hostid between boots will most likely lead to an
--un-importable pool since the last importing hostid won't match.  In order
--to recover from this, you may use the `zfs_force` option or boot from a
--different filesystem and `zpool import -f` then `zpool export` the pool
--before rebooting with the new hostid.
--
--* `bootfs.snapshot`: If listed, enables the zfs-snapshot-bootfs service on a Dracut system. The zfs-snapshot-bootfs service simply runs `zfs snapshot $BOOTFS@%v` after the pool has been imported but before the bootfs is mounted. `$BOOTFS` is substituted with the value of the bootfs setting on the pool. `%v` is substituted with the version string of the kernel currently being booted (e.g. 5.6.6-200.fc31.x86\_64). Failure to create the snapshot (e.g. because one with the same name already exists) will be logged, but will not otherwise interrupt the boot process.
--
--    It is safe to leave the bootfs.snapshot flag set persistently on your kernel command line so that a new snapshot of your bootfs will be created on every kernel update. If you leave bootfs.snapshot set persistently on your kernel command line, you may find the below script helpful for automatically removing old snapshots of the bootfs along with their associated kernel.
--
--        #!/usr/bin/sh
--
--        if [[ "$1" == "remove" ]] && grep -q "\bbootfs.snapshot\b" /proc/cmdline; then
--           zfs destroy $(findmnt -n -o source /)@$2 &> /dev/null
--        fi
--
--        exit 0
--
--    To use the above script place it in a plain text file named /etc/kernel/install.d/99-zfs-cleanup.install and mark it executable with the following command:
--
--        $ chmod +x /etc/kernel/install.d/99-zfs-cleanup.install
--
--    On Red Hat based systems, you can change the value of `installonly_limit` in /etc/dnf/dnf.conf to adjust the number of kernels and their associated snapshots that are kept.
--
--* `bootfs.snapshot=<snapname>`: Is identical to the bootfs.snapshot parameter explained above except that the value substituted for \<snapname\> will be used when creating the snapshot instead of the version string of the kernel currently being booted. 
--
--* `bootfs.rollback`: If listed, enables the zfs-rollback-bootfs service on a Dracut system. The zfs-rollback-bootfs service simply runs `zfs rollback -Rf $BOOTFS@%v` after the pool has been imported but before the bootfs is mounted. If the rollback operation fails, the boot process will be interrupted with a Dracut rescue shell. __Use this parameter with caution. Intermediate snapshots of the bootfs will be destroyed!__ TIP: Keep your user data (e.g. /home) on separate file systems (it can be in the same pool though).
--
--* `bootfs.rollback=<snapname>`: Is identical to the bootfs.rollback parameter explained above except that the value substituted for \<snapname\> will be used when rolling back the bootfs instead of the version string of the kernel currently being booted. If you use this form, choose a snapshot that is new enough to contain the needed kernel modules under /lib/modules or use a kernel that has all the needed modules built-in.
--
--How it Works
--============
--
--The Dracut module consists of the following files (less Makefile's):
--
--* `module-setup.sh`: Script run by the initramfs builder to create the
--ramdisk.  Contains instructions on which files are required by the modules
--and z* programs.  Also triggers inclusion of `/etc/hostid` and the zpool
--cache.  This file is not included in the initramfs.
--
--* `90-zfs.rules`: udev rules which trigger loading of the ZFS modules at boot.
--
--* `zfs-lib.sh`: Utility functions used by the other files.
--
--* `parse-zfs.sh`: Run early in the initramfs boot process to parse kernel
--command line and determine if ZFS is the active root filesystem.
--
--* `mount-zfs.sh`: Run later in initramfs boot process after udev has settled
--to mount the root dataset.
--
--* `export-zfs.sh`: Run on shutdown after dracut has restored the initramfs
--and pivoted to it, allowing for a clean unmount and export of the ZFS root.
--
--`zfs-lib.sh`
--------------
--
--This file provides a few handy functions for working with ZFS. Those
--functions are used by the `mount-zfs.sh` and `export-zfs.sh` files.
--However, they could be used by any other file as well, as long as the file
--sources `/lib/dracut-zfs-lib.sh`.
--
--`module-setup.sh`
-------------------
--
--This file is run by the Dracut script within the live system, not at boot
--time.  It's not included in the final initramfs.  Functions in this script
--describe which files are needed by ZFS at boot time.
--
--Currently all the various z* and spl modules are included, a dependency is
--asserted on udev-rules, and the various zfs, zpool, etc. helpers are included.
--Dracut provides library functions which automatically gather the shared libs
--necessary to run each of these binaries, so statically built binaries are
--not required.
--
--The zpool and zvol udev rules files are copied from where they are
--installed by the ZFS build.  __PACKAGERS TAKE NOTE__: If you move
--`/etc/udev/rules/60-z*.rules`, you'll need to update this file to match.
--
--Currently this file also includes `/etc/hostid` and `/etc/zfs/zpool.cache`
--which means the generated ramdisk is specific to the host system which built
--it.  If a generic initramfs is required, it may be preferable to omit these
--files and specify the `spl_hostid` from the boot loader instead.
--
--`parse-zfs.sh`
----------------
--
--Run during the cmdline phase of the initramfs boot process, this script
--performs some basic sanity checks on kernel command line parameters to
--determine if booting from ZFS is likely to be what is desired.  Dracut
--requires this script to adjust the `root` variable if required and to set
--`rootok=1` if a mountable root filesystem is available.  Unfortunately this
--script must run before udev is settled and kernel modules are known to be
--loaded, so accessing the zpool and zfs commands is unsafe.
--
--If the root=ZFS... parameter is set on the command line, then it's at least
--certain that ZFS is what is desired, though this script is unable to
--determine if ZFS is in fact available.  This script will alter the `root`
--parameter to replace several historical forms of specifying the pool and
--dataset name with the canonical form of `zfs:pool/dataset`.
--
--If no root= parameter is set, the best this script can do is guess that
--ZFS is desired.  At present, no other known filesystems will work with no
--root= parameter, though this might possibly interfere with using the
--compiled-in default root in the kernel image.  It's considered unlikely
--that would ever be the case when an initramfs is in use, so this script
--sets `root=zfs:AUTO` and hopes for the best.
--
--Once the root=... (or lack thereof) parameter is parsed, a dummy symlink
--is created from `/dev/root` -> `/dev/null` to satisfy parts of the Dracut
--process which check for presence of a single root device node.
--
--Finally, an initqueue/finished hook is registered which causes the initqueue
--phase of Dracut to wait for `/dev/zfs` to become available before attempting
--to mount anything.
--
--`mount-zfs.sh`
----------------
--
--This script is run after udev has settled and all tasks in the initqueue
--have succeeded.  This ensures that `/dev/zfs` is available and that the
--various ZFS modules are successfully loaded.  As it is now safe to call
--zpool and friends, we can proceed to find the bootfs attribute if necessary.
--
--If the root parameter was explicitly set on the command line, no parsing is
--necessary.  The list of imported pools is checked to see if the desired pool
--is already imported.  If it's not, and attempt is made to import the pool
--explicitly, though no force is attempted.  Finally the specified dataset
--is mounted on `$NEWROOT`, first using the `-o zfsutil` option to handle
--non-legacy mounts, then if that fails, without zfsutil to handle legacy
--mount points.
--
--If no root parameter was specified, this script attempts to find a pool with
--its bootfs attribute set.  First, already-imported pools are scanned and if
--an appropriate pool is found, no additional pools are imported.  If no pool
--with bootfs is found, any additional pools in the system are imported with
--`zpool import -N -a`, and the scan for bootfs is tried again.  If no bootfs
--is found with all pools imported, all pools are re-exported, and boot fails.
--Assuming a bootfs is found, an attempt is made to mount it to `$NEWROOT`,
--first with, then without the zfsutil option as above.
--
--Ordinarily pools are imported _without_ the force option which may cause
--boot to fail if the hostid has changed or a pool has been physically moved
--between servers.  The `zfs_force` kernel parameter is provided which when
--set to `1` causes `zpool import` to be run with the `-f` flag.  Forcing pool
--import can lead to serious data corruption and loss of pools, so this option
--should be used with extreme caution.  Note that even with this flag set, if
--the required zpool was auto-imported by the kernel module, no additional
--`zpool import` commands are run, so nothing is forced.
--
--`export-zfs.sh`
-----------------
--
--Normally the zpool containing the root dataset cannot be exported on
--shutdown as it is still in use by the init process. To work around this,
--Dracut is able to restore the initramfs on shutdown and pivot to it.
--All remaining process are then running from a ramdisk, allowing for a
--clean unmount and export of the ZFS root. The theory of operation is
--described in detail in the [Dracut manual](https://www.kernel.org/pub/linux/utils/boot/dracut/dracut.html#_dracut_on_shutdown).
--
--This script will try to export all remaining zpools after Dracut has
--pivoted to the initramfs. If an initial regular export is not successful,
--Dracut will call this script once more with the `final` option,
--in which case a forceful export is attempted.
--
--Other Dracut modules include similar shutdown scripts and Dracut
--invokes these scripts round-robin until they succeed. In particular,
--the `90dm` module installs a script which tries to close and remove
--all device mapper targets. Thus, if there are ZVOLs containing
--dm-crypt volumes or if the zpool itself is backed by a dm-crypt
--volume, the shutdown scripts will try to untangle this.
-+6. `zfs_force`, `zfs.force`, `zfsforce`: add `-f` to all `zpool import` invocations.
-+   May be useful. Use with caution.
-diff --git a/etc/default/Makefile.am b/etc/default/Makefile.am
-index b88eb5494..f061692c3 100644
---- a/etc/default/Makefile.am
-+++ b/etc/default/Makefile.am
-@@ -1,9 +1,10 @@
- include $(top_srcdir)/config/Substfiles.am
- include $(top_srcdir)/config/Shellcheck.am
- 
--initconf_SCRIPTS = zfs
-+initconf_DATA = zfs
- 
--SUBSTFILES += $(initconf_SCRIPTS)
-+SUBSTFILES += $(initconf_DATA)
- 
-+SHELLCHECKSCRIPTS = $(initconf_DATA)
- SHELLCHECK_SHELL = sh
- SHELLCHECK_IGNORE = ,SC2034
-diff --git a/etc/systemd/system-generators/zfs-mount-generator.c b/etc/systemd/system-generators/zfs-mount-generator.c
-index b806339de..f4c6c26a0 100644
---- a/etc/systemd/system-generators/zfs-mount-generator.c
-+++ b/etc/systemd/system-generators/zfs-mount-generator.c
-@@ -27,9 +27,6 @@
- #include <sys/types.h>
- #include <sys/time.h>
- #include <sys/stat.h>
--#include <sys/wait.h>
--#include <sys/mman.h>
--#include <semaphore.h>
- #include <stdbool.h>
- #include <unistd.h>
- #include <fcntl.h>
-@@ -44,25 +41,16 @@
- #include <errno.h>
- #include <libzfs.h>
- 
--#define	STRCMP ((int(*)(const void *, const void *))&strcmp)
--#define	PID_T_CMP ((int(*)(const void *, const void *))&pid_t_cmp)
--
--static int
--pid_t_cmp(const pid_t *lhs, const pid_t *rhs)
--{
--	/*
--	 * This is always valid, quoth sys_types.h(7posix):
--	 * > blksize_t, pid_t, and ssize_t shall be signed integer types.
--	 */
--	return (*lhs - *rhs);
--}
-+/*
-+ * For debugging only.
-+ *
-+ * Free statics with trivial life-times,
-+ * but saved line filenames are replaced with a static string.
-+ */
-+#define	FREE_STATICS false
- 
--#define	EXIT_ENOMEM() \
--	do { \
--		fprintf(stderr, PROGNAME "[%d]: " \
--		    "not enough memory (L%d)!\n", getpid(), __LINE__); \
--		_exit(1); \
--	} while (0)
-+#define	nitems(arr) (sizeof (arr) / sizeof (*arr))
-+#define	STRCMP ((int(*)(const void *, const void *))&strcmp)
- 
- 
- #define	PROGNAME "zfs-mount-generator"
-@@ -80,20 +68,11 @@ pid_t_cmp(const pid_t *lhs, const pid_t *rhs)
- #define	URI_REGEX_S "^\\([A-Za-z][A-Za-z0-9+.\\-]*\\):\\/\\/\\(.*\\)$"
- static regex_t uri_regex;
- 
--static char *argv0;
--
- static const char *destdir = "/tmp";
- static int destdir_fd = -1;
- 
- static void *known_pools = NULL; /* tsearch() of C strings */
--static struct {
--	sem_t noauto_not_on_sem;
--
--	sem_t noauto_names_sem;
--	size_t noauto_names_len;
--	size_t noauto_names_max;
--	char noauto_names[][NAME_MAX];
--} *noauto_files;
-+static void *noauto_files = NULL; /* tsearch() of C strings */
- 
- 
- static char *
-@@ -103,8 +82,12 @@ systemd_escape(const char *input, const char *prepend, const char *append)
- 	size_t applen = strlen(append);
- 	size_t prelen = strlen(prepend);
- 	char *ret = malloc(4 * len + prelen + applen + 1);
--	if (!ret)
--		EXIT_ENOMEM();
-+	if (!ret) {
-+		fprintf(stderr, PROGNAME "[%d]: "
-+		    "out of memory to escape \"%s%s%s\"!\n",
-+		    getpid(), prepend, input, append);
-+		return (NULL);
-+	}
- 
- 	memcpy(ret, prepend, prelen);
- 	char *out = ret + prelen;
-@@ -166,8 +149,12 @@ systemd_escape_path(char *input, const char *prepend, const char *append)
- {
- 	if (strcmp(input, "/") == 0) {
- 		char *ret;
--		if (asprintf(&ret, "%s-%s", prepend, append) == -1)
--			EXIT_ENOMEM();
-+		if (asprintf(&ret, "%s-%s", prepend, append) == -1) {
-+			fprintf(stderr, PROGNAME "[%d]: "
-+			    "out of memory to escape \"%s%s%s\"!\n",
-+			    getpid(), prepend, input, append);
-+			ret = NULL;
-+		}
- 		return (ret);
- 	} else {
- 		/*
-@@ -209,6 +196,10 @@ fopenat(int dirfd, const char *pathname, int flags,
- static int
- line_worker(char *line, const char *cachefile)
- {
-+	int ret = 0;
-+	void *tofree_all[8];
-+	void **tofree = tofree_all;
-+
- 	char *toktmp;
- 	/* BEGIN CSTYLED */
- 	const char *dataset                     = strtok_r(line, "\t", &toktmp);
-@@ -240,11 +231,9 @@ line_worker(char *line, const char *cachefile)
- 	if (p_nbmand == NULL) {
- 		fprintf(stderr, PROGNAME "[%d]: %s: not enough tokens!\n",
- 		    getpid(), dataset);
--		return (1);
-+		goto err;
- 	}
- 
--	strncpy(argv0, dataset, strlen(argv0));
--
- 	/* Minimal pre-requisites to mount a ZFS dataset */
- 	const char *after = "zfs-import.target";
- 	const char *wants = "zfs-import.target";
-@@ -280,28 +269,31 @@ line_worker(char *line, const char *cachefile)
- 
- 
- 	if (strcmp(p_encroot, "-") != 0) {
--		char *keyloadunit =
-+		char *keyloadunit = *(tofree++) =
- 		    systemd_escape(p_encroot, "zfs-load-key@", ".service");
-+		if (keyloadunit == NULL)
-+			goto err;
- 
- 		if (strcmp(dataset, p_encroot) == 0) {
- 			const char *keymountdep = NULL;
- 			bool is_prompt = false;
-+			bool need_network = false;
- 
- 			regmatch_t uri_matches[3];
- 			if (regexec(&uri_regex, p_keyloc,
--			    sizeof (uri_matches) / sizeof (*uri_matches),
--			    uri_matches, 0) == 0) {
-+			    nitems(uri_matches), uri_matches, 0) == 0) {
-+				p_keyloc[uri_matches[1].rm_eo] = '\0';
- 				p_keyloc[uri_matches[2].rm_eo] = '\0';
-+				const char *scheme =
-+				    &p_keyloc[uri_matches[1].rm_so];
- 				const char *path =
- 				    &p_keyloc[uri_matches[2].rm_so];
- 
--				/*
--				 * Assumes all URI keylocations need
--				 * the mount for their path;
--				 * http://, for example, wouldn't
--				 * (but it'd need network-online.target et al.)
--				 */
--				keymountdep = path;
-+				if (strcmp(scheme, "https") == 0 ||
-+				    strcmp(scheme, "http") == 0)
-+					need_network = true;
-+				else
-+					keymountdep = path;
- 			} else {
- 				if (strcmp(p_keyloc, "prompt") != 0)
- 					fprintf(stderr, PROGNAME "[%d]: %s: "
-@@ -321,7 +313,7 @@ line_worker(char *line, const char *cachefile)
- 				    "couldn't open %s under %s: %s\n",
- 				    getpid(), dataset, keyloadunit, destdir,
- 				    strerror(errno));
--				return (1);
-+				goto err;
- 			}
- 
- 			fprintf(keyloadunit_f,
-@@ -335,20 +327,22 @@ line_worker(char *line, const char *cachefile)
- 			    "After=%s\n",
- 			    dataset, cachefile, wants, after);
- 
-+			if (need_network)
-+				fprintf(keyloadunit_f,
-+				    "Wants=network-online.target\n"
-+				    "After=network-online.target\n");
-+
- 			if (p_systemd_requires)
- 				fprintf(keyloadunit_f,
- 				    "Requires=%s\n", p_systemd_requires);
- 
--			if (p_systemd_requiresmountsfor || keymountdep) {
--				fprintf(keyloadunit_f, "RequiresMountsFor=");
--				if (p_systemd_requiresmountsfor)
--					fprintf(keyloadunit_f,
--					    "%s ", p_systemd_requiresmountsfor);
--				if (keymountdep)
--					fprintf(keyloadunit_f,
--					    "'%s'", keymountdep);
--				fprintf(keyloadunit_f, "\n");
--			}
-+			if (p_systemd_requiresmountsfor)
-+				fprintf(keyloadunit_f,
-+				    "RequiresMountsFor=%s\n",
-+				    p_systemd_requiresmountsfor);
-+			if (keymountdep)
-+				fprintf(keyloadunit_f,
-+				    "RequiresMountsFor='%s'\n", keymountdep);
- 
- 			/* BEGIN CSTYLED */
- 			fprintf(keyloadunit_f,
-@@ -393,9 +387,13 @@ line_worker(char *line, const char *cachefile)
- 		if (after[0] == '\0')
- 			after = keyloadunit;
- 		else if (asprintf(&toktmp, "%s %s", after, keyloadunit) != -1)
--			after = toktmp;
--		else
--			EXIT_ENOMEM();
-+			after = *(tofree++) = toktmp;
-+		else {
-+			fprintf(stderr, PROGNAME "[%d]: %s: "
-+			    "out of memory to generate after=\"%s %s\"!\n",
-+			    getpid(), dataset, after, keyloadunit);
-+			goto err;
-+		}
- 	}
- 
- 
-@@ -404,12 +402,12 @@ line_worker(char *line, const char *cachefile)
- 	    strcmp(p_systemd_ignore, "off") == 0) {
- 		/* ok */
- 	} else if (strcmp(p_systemd_ignore, "on") == 0)
--		return (0);
-+		goto end;
- 	else {
- 		fprintf(stderr, PROGNAME "[%d]: %s: "
- 		    "invalid org.openzfs.systemd:ignore=%s\n",
- 		    getpid(), dataset, p_systemd_ignore);
--		return (1);
-+		goto err;
- 	}
- 
- 	/* Check for canmount */
-@@ -418,21 +416,21 @@ line_worker(char *line, const char *cachefile)
- 	} else if (strcmp(p_canmount, "noauto") == 0)
- 		noauto = true;
- 	else if (strcmp(p_canmount, "off") == 0)
--		return (0);
-+		goto end;
- 	else {
- 		fprintf(stderr, PROGNAME "[%d]: %s: invalid canmount=%s\n",
- 		    getpid(), dataset, p_canmount);
--		return (1);
-+		goto err;
- 	}
- 
- 	/* Check for legacy and blank mountpoints */
- 	if (strcmp(p_mountpoint, "legacy") == 0 ||
- 	    strcmp(p_mountpoint, "none") == 0)
--		return (0);
-+		goto end;
- 	else if (p_mountpoint[0] != '/') {
- 		fprintf(stderr, PROGNAME "[%d]: %s: invalid mountpoint=%s\n",
- 		    getpid(), dataset, p_mountpoint);
--		return (1);
-+		goto err;
- 	}
- 
- 	/* Escape the mountpoint per systemd policy */
-@@ -442,7 +440,7 @@ line_worker(char *line, const char *cachefile)
- 		fprintf(stderr,
- 		    PROGNAME "[%d]: %s: abnormal simplified mountpoint: %s\n",
- 		    getpid(), dataset, p_mountpoint);
--		return (1);
-+		goto err;
- 	}
- 
- 
-@@ -552,8 +550,7 @@ line_worker(char *line, const char *cachefile)
- 	 * 	files if we're sure they were created by us. (see 5.)
- 	 * 2.	We handle files differently based on canmount.
- 	 * 	Units with canmount=on always have precedence over noauto.
--	 * 	This is enforced by the noauto_not_on_sem semaphore,
--	 * 	which is only unlocked when the last canmount=on process exits.
-+	 * 	This is enforced by processing these units before all others.
- 	 * 	It is important to use p_canmount and not noauto here,
- 	 * 	since we categorise by canmount while other properties,
- 	 * 	e.g. org.openzfs.systemd:wanted-by, also modify noauto.
-@@ -561,7 +558,7 @@ line_worker(char *line, const char *cachefile)
- 	 * 	Additionally, we use noauto_files to track the unit file names
- 	 * 	(which are the systemd-escaped mountpoints) of all (exclusively)
- 	 * 	noauto datasets that had a file created.
--	 * 4.	If the file to be created is found in the tracking array,
-+	 * 4.	If the file to be created is found in the tracking tree,
- 	 * 	we do NOT create it.
- 	 * 5.	If a file exists for a noauto dataset,
- 	 * 	we check whether the file name is in the array.
-@@ -571,29 +568,14 @@ line_worker(char *line, const char *cachefile)
- 	 * 	further noauto datasets creating a file for this path again.
- 	 */
- 
--	{
--		sem_t *our_sem = (strcmp(p_canmount, "on") == 0) ?
--		    &noauto_files->noauto_names_sem :
--		    &noauto_files->noauto_not_on_sem;
--		while (sem_wait(our_sem) == -1 && errno == EINTR)
--			;
--	}
--
- 	struct stat stbuf;
- 	bool already_exists = fstatat(destdir_fd, mountfile, &stbuf, 0) == 0;
-+	bool is_known = tfind(mountfile, &noauto_files, STRCMP) != NULL;
- 
--	bool is_known = false;
--	for (size_t i = 0; i < noauto_files->noauto_names_len; ++i) {
--		if (strncmp(
--		    noauto_files->noauto_names[i], mountfile, NAME_MAX) == 0) {
--			is_known = true;
--			break;
--		}
--	}
--
-+	*(tofree++) = (void *)mountfile;
- 	if (already_exists) {
- 		if (is_known) {
--			/* If it's in $noauto_files, we must be noauto too */
-+			/* If it's in noauto_files, we must be noauto too */
- 
- 			/* See 5 */
- 			errno = 0;
-@@ -614,43 +596,31 @@ line_worker(char *line, const char *cachefile)
- 		}
- 
- 		/* File exists: skip current dataset */
--		if (strcmp(p_canmount, "on") == 0)
--			sem_post(&noauto_files->noauto_names_sem);
--		return (0);
-+		goto end;
- 	} else {
- 		if (is_known) {
- 			/* See 4 */
--			if (strcmp(p_canmount, "on") == 0)
--				sem_post(&noauto_files->noauto_names_sem);
--			return (0);
-+			goto end;
- 		} else if (strcmp(p_canmount, "noauto") == 0) {
--			if (noauto_files->noauto_names_len ==
--			    noauto_files->noauto_names_max)
-+			if (tsearch(mountfile, &noauto_files, STRCMP) == NULL)
- 				fprintf(stderr, PROGNAME "[%d]: %s: "
--				    "noauto dataset limit (%zu) reached! "
--				    "Not tracking %s. Please report this to "
--				    "https://github.com/openzfs/zfs\n",
--				    getpid(), dataset,
--				    noauto_files->noauto_names_max, mountfile);
--			else {
--				strncpy(noauto_files->noauto_names[
--				    noauto_files->noauto_names_len],
--				    mountfile, NAME_MAX);
--				++noauto_files->noauto_names_len;
--			}
-+				    "out of memory for noauto datasets! "
-+				    "Not tracking %s.\n",
-+				    getpid(), dataset, mountfile);
-+			else
-+				/* mountfile escaped to noauto_files */
-+				*(--tofree) = NULL;
- 		}
- 	}
- 
- 
- 	FILE *mountfile_f = fopenat(destdir_fd, mountfile,
- 	    O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, "w", 0644);
--	if (strcmp(p_canmount, "on") == 0)
--		sem_post(&noauto_files->noauto_names_sem);
- 	if (!mountfile_f) {
- 		fprintf(stderr,
- 		    PROGNAME "[%d]: %s: couldn't open %s under %s: %s\n",
- 		    getpid(), dataset, mountfile, destdir, strerror(errno));
--		return (1);
-+		goto err;
- 	}
- 
- 	fprintf(mountfile_f,
-@@ -699,12 +669,17 @@ line_worker(char *line, const char *cachefile)
- 	(void) fclose(mountfile_f);
- 
- 	if (!requiredby && !wantedby)
--		return (0);
-+		goto end;
- 
- 	/* Finally, create the appropriate dependencies */
- 	char *linktgt;
--	if (asprintf(&linktgt, "../%s", mountfile) == -1)
--		EXIT_ENOMEM();
-+	if (asprintf(&linktgt, "../%s", mountfile) == -1) {
-+		fprintf(stderr, PROGNAME "[%d]: %s: "
-+		    "out of memory for dependents of %s!\n",
-+		    getpid(), dataset, mountfile);
-+		goto err;
-+	}
-+	*(tofree++) = linktgt;
- 
- 	char *dependencies[][2] = {
- 		{"wants", wantedby},
-@@ -719,8 +694,14 @@ line_worker(char *line, const char *cachefile)
- 		    reqby;
- 		    reqby = strtok_r(NULL, " ", &toktmp)) {
- 			char *depdir;
--			if (asprintf(&depdir, "%s.%s", reqby, (*dep)[0]) == -1)
--				EXIT_ENOMEM();
-+			if (asprintf(
-+			    &depdir, "%s.%s", reqby, (*dep)[0]) == -1) {
-+				fprintf(stderr, PROGNAME "[%d]: %s: "
-+				    "out of memory for dependent dir name "
-+				    "\"%s.%s\"!\n",
-+				    getpid(), dataset, reqby, (*dep)[0]);
-+				continue;
-+			}
- 
- 			(void) mkdirat(destdir_fd, depdir, 0755);
- 			int depdir_fd = openat(destdir_fd, depdir,
-@@ -746,7 +727,24 @@ line_worker(char *line, const char *cachefile)
- 		}
- 	}
- 
--	return (0);
-+end:
-+	if (tofree >= tofree_all + nitems(tofree_all)) {
-+		/*
-+		 * This won't happen as-is:
-+		 * we've got 8 slots and allocate 4 things at most.
-+		 */
-+		fprintf(stderr,
-+		    PROGNAME "[%d]: %s: need to free %zu > %zu!\n",
-+		    getpid(), dataset, tofree - tofree_all, nitems(tofree_all));
-+		ret = tofree - tofree_all;
-+	}
-+
-+	while (tofree-- != tofree_all)
-+		free(*tofree);
-+	return (ret);
-+err:
-+	ret = 1;
-+	goto end;
- }
- 
- 
-@@ -780,12 +778,11 @@ main(int argc, char **argv)
- 		if (kmfd >= 0) {
- 			(void) dup2(kmfd, STDERR_FILENO);
- 			(void) close(kmfd);
-+
-+			setlinebuf(stderr);
- 		}
- 	}
- 
--	uint8_t debug = 0;
--
--	argv0 = argv[0];
- 	switch (argc) {
- 	case 1:
- 		/* Use default */
-@@ -844,33 +841,9 @@ main(int argc, char **argv)
- 		}
- 	}
- 
--	{
--		/*
--		 * We could just get a gigabyte here and Not Care,
--		 * but if vm.overcommit_memory=2, then MAP_NORESERVE is ignored
--		 * and we'd try (and likely fail) to rip it out of swap
--		 */
--		noauto_files = mmap(NULL, 4 * 1024 * 1024,
--		    PROT_READ | PROT_WRITE,
--		    MAP_SHARED | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
--		if (noauto_files == MAP_FAILED) {
--			fprintf(stderr,
--			    PROGNAME "[%d]: couldn't allocate IPC region: %s\n",
--			    getpid(), strerror(errno));
--			_exit(1);
--		}
--
--		sem_init(&noauto_files->noauto_not_on_sem, true, 0);
--		sem_init(&noauto_files->noauto_names_sem, true, 1);
--		noauto_files->noauto_names_len = 0;
--		/* Works out to 16447ish, *well* enough */
--		noauto_files->noauto_names_max =
--		    (4 * 1024 * 1024 - sizeof (*noauto_files)) / NAME_MAX;
--	}
--
-+	bool debug = false;
- 	char *line = NULL;
- 	size_t linelen = 0;
--	struct timespec time_start = {};
- 	{
- 		const char *dbgenv = getenv("ZFS_DEBUG");
- 		if (dbgenv)
-@@ -879,7 +852,7 @@ main(int argc, char **argv)
- 			FILE *cmdline = fopen("/proc/cmdline", "re");
- 			if (cmdline != NULL) {
- 				if (getline(&line, &linelen, cmdline) >= 0)
--					debug = strstr(line, "debug") ? 2 : 0;
-+					debug = strstr(line, "debug");
- 				(void) fclose(cmdline);
- 			}
- 		}
-@@ -888,19 +861,17 @@ main(int argc, char **argv)
- 			dup2(STDERR_FILENO, STDOUT_FILENO);
- 	}
- 
--	size_t forked_canmount_on = 0;
--	size_t forked_canmount_not_on = 0;
--	size_t canmount_on_pids_len = 128;
--	pid_t *canmount_on_pids =
--	    malloc(canmount_on_pids_len * sizeof (*canmount_on_pids));
--	if (canmount_on_pids == NULL)
--		canmount_on_pids_len = 0;
--
-+	struct timespec time_start = {};
- 	if (debug)
- 		clock_gettime(CLOCK_MONOTONIC_RAW, &time_start);
- 
--	ssize_t read;
--	pid_t pid;
-+	struct line {
-+		char *line;
-+		const char *fname;
-+		struct line *next;
-+	} *lines_canmount_not_on = NULL;
-+
-+	int ret = 0;
- 	struct dirent *cachent;
- 	while ((cachent = readdir(fslist_dir)) != NULL) {
- 		if (strcmp(cachent->d_name, ".") == 0 ||
-@@ -916,129 +887,67 @@ main(int argc, char **argv)
- 			continue;
- 		}
- 
-+		const char *filename = FREE_STATICS ? "(elided)" : NULL;
-+
-+		ssize_t read;
- 		while ((read = getline(&line, &linelen, cachefile)) >= 0) {
- 			line[read - 1] = '\0'; /* newline */
- 
--			switch (pid = fork()) {
--			case -1:
--				fprintf(stderr,
--				    PROGNAME "[%d]: couldn't fork for %s: %s\n",
--				    getpid(), line, strerror(errno));
--				break;
--			case 0: /* child */
--				_exit(line_worker(line, cachent->d_name));
--			default: { /* parent */
--				char *tmp;
--				char *dset = strtok_r(line, "\t", &tmp);
--				strtok_r(NULL, "\t", &tmp);
--				char *canmount = strtok_r(NULL, "\t", &tmp);
--				bool canmount_on =
--				    canmount && strncmp(canmount, "on", 2) == 0;
--
--				if (debug >= 2)
--					printf(PROGNAME ": forked %d, "
--					    "canmount_on=%d, dataset=%s\n",
--					    (int)pid, canmount_on, dset);
--
--				if (canmount_on &&
--				    forked_canmount_on ==
--				    canmount_on_pids_len) {
--					size_t new_len =
--					    (canmount_on_pids_len ?: 16) * 2;
--					void *new_pidlist =
--					    realloc(canmount_on_pids,
--					    new_len *
--					    sizeof (*canmount_on_pids));
--					if (!new_pidlist) {
--						fprintf(stderr,
--						    PROGNAME "[%d]: "
--						    "out of memory! "
--						    "Mount ordering may be "
--						    "affected.\n", getpid());
--						continue;
--					}
--
--					canmount_on_pids = new_pidlist;
--					canmount_on_pids_len = new_len;
--				}
-+			char *canmount = line;
-+			canmount += strcspn(canmount, "\t");
-+			canmount += strspn(canmount, "\t");
-+			canmount += strcspn(canmount, "\t");
-+			canmount += strspn(canmount, "\t");
-+			bool canmount_on = strncmp(canmount, "on", 2) == 0;
- 
--				if (canmount_on) {
--					canmount_on_pids[forked_canmount_on] =
--					    pid;
--					++forked_canmount_on;
--				} else
--					++forked_canmount_not_on;
--				break;
--			}
-+			if (canmount_on)
-+				ret |= line_worker(line, cachent->d_name);
-+			else {
-+				if (filename == NULL)
-+					filename =
-+					    strdup(cachent->d_name) ?: "(?)";
-+
-+				struct line *l = calloc(1, sizeof (*l));
-+				char *nl = strdup(line);
-+				if (l == NULL || nl == NULL) {
-+					fprintf(stderr, PROGNAME "[%d]: "
-+					    "out of memory for \"%s\" in %s\n",
-+					    getpid(), line, cachent->d_name);
-+					free(l);
-+					free(nl);
-+					continue;
-+				}
-+				l->line = nl;
-+				l->fname = filename;
-+				l->next = lines_canmount_not_on;
-+				lines_canmount_not_on = l;
- 			}
- 		}
- 
--		(void) fclose(cachefile);
-+		fclose(cachefile);
- 	}
- 	free(line);
- 
--	if (forked_canmount_on == 0) {
--		/* No canmount=on processes to finish, so don't deadlock here */
--		for (size_t i = 0; i < forked_canmount_not_on; ++i)
--			sem_post(&noauto_files->noauto_not_on_sem);
--	} else {
--		/* Likely a no-op, since we got these from a narrow fork loop */
--		qsort(canmount_on_pids, forked_canmount_on,
--		    sizeof (*canmount_on_pids), PID_T_CMP);
--	}
-+	while (lines_canmount_not_on) {
-+		struct line *l = lines_canmount_not_on;
-+		lines_canmount_not_on = l->next;
- 
--	int status, ret = 0;
--	struct rusage usage;
--	size_t forked_canmount_on_max = forked_canmount_on;
--	while ((pid = wait4(-1, &status, 0, &usage)) != -1) {
--		ret |= WEXITSTATUS(status) | WTERMSIG(status);
--
--		if (forked_canmount_on != 0) {
--			if (bsearch(&pid, canmount_on_pids,
--			    forked_canmount_on_max, sizeof (*canmount_on_pids),
--			    PID_T_CMP))
--				--forked_canmount_on;
--
--			if (forked_canmount_on == 0) {
--				/*
--				 * All canmount=on processes have finished,
--				 * let all the lower-priority ones finish now
--				 */
--				for (size_t i = 0;
--				    i < forked_canmount_not_on; ++i)
--					sem_post(
--					    &noauto_files->noauto_not_on_sem);
--			}
-+		ret |= line_worker(l->line, l->fname);
-+		if (FREE_STATICS) {
-+			free(l->line);
-+			free(l);
- 		}
--
--		if (debug >= 2)
--			printf(PROGNAME ": %d done, user=%llu.%06us, "
--			    "system=%llu.%06us, maxrss=%ldB, ex=0x%x\n",
--			    (int)pid,
--			    (unsigned long long) usage.ru_utime.tv_sec,
--			    (unsigned int) usage.ru_utime.tv_usec,
--			    (unsigned long long) usage.ru_stime.tv_sec,
--			    (unsigned int) usage.ru_stime.tv_usec,
--			    usage.ru_maxrss * 1024, status);
- 	}
- 
- 	if (debug) {
- 		struct timespec time_end = {};
- 		clock_gettime(CLOCK_MONOTONIC_RAW, &time_end);
- 
-+		struct rusage usage;
- 		getrusage(RUSAGE_SELF, &usage);
- 		printf(
- 		    "\n"
--		    PROGNAME ": self    : "
--		    "user=%llu.%06us, system=%llu.%06us, maxrss=%ldB\n",
--		    (unsigned long long) usage.ru_utime.tv_sec,
--		    (unsigned int) usage.ru_utime.tv_usec,
--		    (unsigned long long) usage.ru_stime.tv_sec,
--		    (unsigned int) usage.ru_stime.tv_usec,
--		    usage.ru_maxrss * 1024);
--
--		getrusage(RUSAGE_CHILDREN, &usage);
--		printf(PROGNAME ": children: "
-+		    PROGNAME ": "
- 		    "user=%llu.%06us, system=%llu.%06us, maxrss=%ldB\n",
- 		    (unsigned long long) usage.ru_utime.tv_sec,
- 		    (unsigned int) usage.ru_utime.tv_usec,
-@@ -1068,7 +977,7 @@ main(int argc, char **argv)
- 		    time_init.tv_nsec / 1000000000;
- 		time_init.tv_nsec %= 1000000000;
- 
--		printf(PROGNAME ": wall    : "
-+		printf(PROGNAME ": "
- 		    "total=%llu.%09llus = "
- 		    "init=%llu.%09llus + real=%llu.%09llus\n",
- 		    (unsigned long long) time_init.tv_sec,
-@@ -1077,7 +986,15 @@ main(int argc, char **argv)
- 		    (unsigned long long) time_start.tv_nsec,
- 		    (unsigned long long) time_end.tv_sec,
- 		    (unsigned long long) time_end.tv_nsec);
-+
-+		fflush(stdout);
- 	}
- 
-+	if (FREE_STATICS) {
-+		closedir(fslist_dir);
-+		tdestroy(noauto_files, free);
-+		tdestroy(known_pools, free);
-+		regfree(&uri_regex);
-+	}
- 	_exit(ret);
- }
-diff --git a/etc/zfs/Makefile.am b/etc/zfs/Makefile.am
-index 3dee81c75..1fc57e158 100644
---- a/etc/zfs/Makefile.am
-+++ b/etc/zfs/Makefile.am
-@@ -10,9 +10,10 @@ dist_pkgsysconf_DATA = \
- 	vdev_id.conf.multipath.example \
- 	vdev_id.conf.scsi.example
- 
--pkgsysconf_SCRIPTS = \
-+pkgsysconf_DATA = \
- 	zfs-functions
- 
--SUBSTFILES += $(pkgsysconf_SCRIPTS)
-+SUBSTFILES += $(pkgsysconf_DATA)
- 
-+SHELLCHECKSCRIPTS = $(pkgsysconf_DATA)
- SHELLCHECK_SHELL = dash # local variables
-diff --git a/include/libzfs.h b/include/libzfs.h
-index eeb4daae7..d55e3f2e7 100644
---- a/include/libzfs.h
-+++ b/include/libzfs.h
-@@ -795,9 +795,10 @@ extern int zfs_receive(libzfs_handle_t *, const char *, nvlist_t *,
-     recvflags_t *, int, avl_tree_t *);
- 
- typedef enum diff_flags {
--	ZFS_DIFF_PARSEABLE = 0x1,
--	ZFS_DIFF_TIMESTAMP = 0x2,
--	ZFS_DIFF_CLASSIFY = 0x4
-+	ZFS_DIFF_PARSEABLE = 1 << 0,
-+	ZFS_DIFF_TIMESTAMP = 1 << 1,
-+	ZFS_DIFF_CLASSIFY = 1 << 2,
-+	ZFS_DIFF_NO_MANGLE = 1 << 3
- } diff_flags_t;
- 
- extern int zfs_show_diffs(zfs_handle_t *, int, const char *, const char *,
-diff --git a/include/libzfs_impl.h b/include/libzfs_impl.h
-index 96b11dad1..043ff9cd7 100644
---- a/include/libzfs_impl.h
-+++ b/include/libzfs_impl.h
-@@ -234,6 +234,7 @@ typedef struct differ_info {
- 	boolean_t scripted;
- 	boolean_t classify;
- 	boolean_t timestamped;
-+	boolean_t no_mangle;
- 	uint64_t shares;
- 	int zerr;
- 	int cleanupfd;
-diff --git a/include/os/freebsd/zfs/sys/zfs_znode_impl.h b/include/os/freebsd/zfs/sys/zfs_znode_impl.h
-index edb28d041..3d93525b4 100644
---- a/include/os/freebsd/zfs/sys/zfs_znode_impl.h
-+++ b/include/os/freebsd/zfs/sys/zfs_znode_impl.h
-@@ -123,25 +123,29 @@ extern minor_t zfsdev_minor_alloc(void);
- #define	zn_rlimit_fsize(zp, uio) \
-     vn_rlimit_fsize(ZTOV(zp), GET_UIO_STRUCT(uio), zfs_uio_td(uio))
- 
-+#define	ZFS_ENTER_ERROR(zfsvfs, error) do {			\
-+	ZFS_TEARDOWN_ENTER_READ((zfsvfs), FTAG);		\
-+	if (__predict_false((zfsvfs)->z_unmounted)) {		\
-+		ZFS_TEARDOWN_EXIT_READ(zfsvfs, FTAG);		\
-+		return (error);					\
-+	}							\
-+} while (0)
-+
- /* Called on entry to each ZFS vnode and vfs operation  */
--#define	ZFS_ENTER(zfsvfs) \
--	{ \
--		ZFS_TEARDOWN_ENTER_READ((zfsvfs), FTAG); \
--		if (__predict_false((zfsvfs)->z_unmounted)) { \
--			ZFS_TEARDOWN_EXIT_READ(zfsvfs, FTAG); \
--			return (EIO); \
--		} \
--	}
-+#define	ZFS_ENTER(zfsvfs)	ZFS_ENTER_ERROR(zfsvfs, EIO)
- 
- /* Must be called before exiting the vop */
--#define	ZFS_EXIT(zfsvfs) ZFS_TEARDOWN_EXIT_READ(zfsvfs, FTAG)
-+#define	ZFS_EXIT(zfsvfs)	ZFS_TEARDOWN_EXIT_READ(zfsvfs, FTAG)
-+
-+#define	ZFS_VERIFY_ZP_ERROR(zp, error) do {			\
-+	if (__predict_false((zp)->z_sa_hdl == NULL)) {		\
-+		ZFS_EXIT((zp)->z_zfsvfs);			\
-+		return (error);					\
-+	}							\
-+} while (0)
- 
- /* Verifies the znode is valid */
--#define	ZFS_VERIFY_ZP(zp) \
--	if (__predict_false((zp)->z_sa_hdl == NULL)) { \
--		ZFS_EXIT((zp)->z_zfsvfs); \
--		return (EIO); \
--	} \
-+#define	ZFS_VERIFY_ZP(zp)	ZFS_VERIFY_ZP_ERROR(zp, EIO)
- 
- /*
-  * Macros for dealing with dmu_buf_hold
-diff --git a/include/sys/dbuf.h b/include/sys/dbuf.h
-index d2c175af6..e7289c0fe 100644
---- a/include/sys/dbuf.h
-+++ b/include/sys/dbuf.h
-@@ -321,13 +321,12 @@ typedef struct dmu_buf_impl {
- 	uint8_t db_dirtycnt;
- } dmu_buf_impl_t;
- 
--/* Note: the dbuf hash table is exposed only for the mdb module */
--#define	DBUF_MUTEXES 2048
--#define	DBUF_HASH_MUTEX(h, idx) (&(h)->hash_mutexes[(idx) & (DBUF_MUTEXES-1)])
-+#define	DBUF_RWLOCKS 8192
-+#define	DBUF_HASH_RWLOCK(h, idx) (&(h)->hash_rwlocks[(idx) & (DBUF_RWLOCKS-1)])
- typedef struct dbuf_hash_table {
- 	uint64_t hash_table_mask;
- 	dmu_buf_impl_t **hash_table;
--	kmutex_t hash_mutexes[DBUF_MUTEXES] ____cacheline_aligned;
-+	krwlock_t hash_rwlocks[DBUF_RWLOCKS] ____cacheline_aligned;
- } dbuf_hash_table_t;
- 
- typedef void (*dbuf_prefetch_fn)(void *, boolean_t);
-diff --git a/include/sys/spa_impl.h b/include/sys/spa_impl.h
-index cb2c49e58..c8987e2e6 100644
---- a/include/sys/spa_impl.h
-+++ b/include/sys/spa_impl.h
-@@ -370,6 +370,7 @@ struct spa {
- 	boolean_t	spa_is_root;		/* pool is root */
- 	int		spa_minref;		/* num refs when first opened */
- 	spa_mode_t	spa_mode;		/* SPA_MODE_{READ|WRITE} */
-+	boolean_t	spa_read_spacemaps;	/* spacemaps available if ro */
- 	spa_log_state_t spa_log_state;		/* log state */
- 	uint64_t	spa_autoexpand;		/* lun expansion on/off */
- 	ddt_t		*spa_ddt[ZIO_CHECKSUM_FUNCTIONS]; /* in-core DDTs */
-diff --git a/lib/libzfs/libzfs_diff.c b/lib/libzfs/libzfs_diff.c
-index d46e23a2f..57a7c1556 100644
---- a/lib/libzfs/libzfs_diff.c
-+++ b/lib/libzfs/libzfs_diff.c
-@@ -122,9 +122,9 @@ stream_bytes(FILE *fp, const char *string)
- 
- 	while ((c = *string++) != '\0') {
- 		if (c > ' ' && c != '\\' && c < '\177') {
--			(void) fprintf(fp, "%c", c);
-+			(void) fputc(c, fp);
- 		} else {
--			(void) fprintf(fp, "\\%04o", (uint8_t)c);
-+			(void) fprintf(fp, "\\%04hho", (uint8_t)c);
- 		}
- 	}
- }
-@@ -176,8 +176,13 @@ print_what(FILE *fp, mode_t what)
- static void
- print_cmn(FILE *fp, differ_info_t *di, const char *file)
- {
--	stream_bytes(fp, di->dsmnt);
--	stream_bytes(fp, file);
-+	if (!di->no_mangle) {
-+		stream_bytes(fp, di->dsmnt);
-+		stream_bytes(fp, file);
-+	} else {
-+		(void) fputs(di->dsmnt, fp);
-+		(void) fputs(file, fp);
-+	}
- }
- 
- static void
-@@ -752,6 +757,7 @@ zfs_show_diffs(zfs_handle_t *zhp, int outfd, const char *fromsnap,
- 	di.scripted = (flags & ZFS_DIFF_PARSEABLE);
- 	di.classify = (flags & ZFS_DIFF_CLASSIFY);
- 	di.timestamped = (flags & ZFS_DIFF_TIMESTAMP);
-+	di.no_mangle = (flags & ZFS_DIFF_NO_MANGLE);
- 
- 	di.outputfd = outfd;
- 	di.datafd = pipefd[0];
-diff --git a/lib/libzfs/libzfs_import.c b/lib/libzfs/libzfs_import.c
-index 64fa31c67..ddaa5de5d 100644
---- a/lib/libzfs/libzfs_import.c
-+++ b/lib/libzfs/libzfs_import.c
-@@ -146,10 +146,10 @@ zpool_clear_label(int fd)
- 	struct stat64 statbuf;
- 	int l;
- 	vdev_label_t *label;
--	l2arc_dev_hdr_phys_t *l2dhdr;
-+	l2arc_dev_hdr_phys_t *l2dhdr = NULL;
- 	uint64_t size;
--	int labels_cleared = 0, header_cleared = 0;
--	boolean_t clear_l2arc_header = B_FALSE;
-+	int labels_cleared = 0;
-+	boolean_t clear_l2arc_header = B_FALSE, header_cleared = B_FALSE;
- 
- 	if (fstat64_blk(fd, &statbuf) == -1)
- 		return (0);
-@@ -219,13 +219,10 @@ zpool_clear_label(int fd)
- 	}
- 
- 	/* Clear the L2ARC header. */
--	if (clear_l2arc_header) {
--		memset(l2dhdr, 0, sizeof (l2arc_dev_hdr_phys_t));
--		if (pwrite64(fd, l2dhdr, sizeof (l2arc_dev_hdr_phys_t),
--		    VDEV_LABEL_START_SIZE) == sizeof (l2arc_dev_hdr_phys_t)) {
--			header_cleared++;
--		}
--	}
-+	if (clear_l2arc_header &&
-+	    pwrite64(fd, l2dhdr, sizeof (l2arc_dev_hdr_phys_t),
-+	    VDEV_LABEL_START_SIZE) == sizeof (l2arc_dev_hdr_phys_t))
-+			header_cleared = B_TRUE;
- 
- 	free(label);
- 	free(l2dhdr);
-@@ -233,6 +230,9 @@ zpool_clear_label(int fd)
- 	if (labels_cleared == 0)
- 		return (-1);
- 
-+	if (clear_l2arc_header && !header_cleared)
-+		return (-1);
-+
- 	return (0);
- }
- 
-diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c
-index b67c9b30c..a944cc164 100644
---- a/lib/libzfs/libzfs_sendrecv.c
-+++ b/lib/libzfs/libzfs_sendrecv.c
-@@ -2133,7 +2133,6 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
- 	avl_tree_t *fsavl = NULL;
- 	static uint64_t holdseq;
- 	int spa_version;
--	int featureflags = 0;
- 	FILE *fout;
- 
- 	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
-@@ -2145,17 +2144,6 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
- 		return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf));
- 	}
- 
--	if (zhp->zfs_type == ZFS_TYPE_FILESYSTEM) {
--		uint64_t version;
--		version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
--		if (version >= ZPL_VERSION_SA) {
--			featureflags |= DMU_BACKUP_FEATURE_SA_SPILL;
--		}
--	}
--
--	if (flags->holds)
--		featureflags |= DMU_BACKUP_FEATURE_HOLDS;
--
- 	if (flags->replicate || flags->doall || flags->props ||
- 	    flags->holds || flags->backup) {
- 		char full_tosnap_name[ZFS_MAX_DATASET_NAME_LEN];
-@@ -2522,8 +2510,7 @@ zfs_send_one(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,
- 
- 	if (flags->progress) {
- 		void *status = NULL;
--		if (err != 0)
--			(void) pthread_cancel(ptid);
-+		(void) pthread_cancel(ptid);
- 		(void) pthread_join(ptid, &status);
- 		int error = (int)(uintptr_t)status;
- 		if (error != 0 && status != PTHREAD_CANCELED)
-diff --git a/lib/libzutil/zutil_import.c b/lib/libzutil/zutil_import.c
-index d91953813..f6f125e7a 100644
---- a/lib/libzutil/zutil_import.c
-+++ b/lib/libzutil/zutil_import.c
-@@ -1791,16 +1791,13 @@ zpool_find_config(void *hdl, const char *target, nvlist_t **configp,
- 	nvlist_t *match = NULL;
- 	nvlist_t *config = NULL;
- 	char *sepp = NULL;
--	char sep = '\0';
- 	int count = 0;
- 	char *targetdup = strdup(target);
- 
- 	*configp = NULL;
- 
--	if ((sepp = strpbrk(targetdup, "/@")) != NULL) {
--		sep = *sepp;
-+	if ((sepp = strpbrk(targetdup, "/@")) != NULL)
- 		*sepp = '\0';
--	}
- 
- 	pools = zpool_search_import(hdl, args, pco);
- 
-diff --git a/man/Makefile.am b/man/Makefile.am
-index 8ab1b7572..64650c2b9 100644
---- a/man/Makefile.am
-+++ b/man/Makefile.am
-@@ -15,6 +15,7 @@ dist_man_MANS = \
- 	man4/spl.4 \
- 	man4/zfs.4 \
- 	\
-+	man7/dracut.zfs.7 \
- 	man7/zpool-features.7 \
- 	man7/zfsconcepts.7 \
- 	man7/zfsprops.7 \
-diff --git a/man/man4/zfs.4 b/man/man4/zfs.4
-index 657afc616..3eeed8f43 100644
---- a/man/man4/zfs.4
-+++ b/man/man4/zfs.4
-@@ -1581,12 +1581,12 @@ Allow no-operation writes.
- The occurrence of nopwrites will further depend on other pool properties
- .Pq i.a. the checksumming and compression algorithms .
- .
--.It Sy zfs_dmu_offset_next_sync Ns = Ns Sy 0 Ns | Ns 1 Pq int
-+.It Sy zfs_dmu_offset_next_sync Ns = Ns Sy 1 Ns | Ns 0 Pq int
- Enable forcing TXG sync to find holes.
--When enabled forces ZFS to act like prior versions when
-+When enabled forces ZFS to sync data when
- .Sy SEEK_HOLE No or Sy SEEK_DATA
--flags are used, which, when a dnode is dirty,
--causes TXGs to be synced so that this data can be found.
-+flags are used allowing holes in a file to be accurately reported.
-+When disabled holes will not be reported in recently dirtied files.
- .
- .It Sy zfs_pd_bytes_max Ns = Ns Sy 52428800 Ns B Po 50MB Pc Pq int
- The number of bytes which should be prefetched during a pool traversal, like
-diff --git a/man/man7/dracut.zfs.7 b/man/man7/dracut.zfs.7
-new file mode 100644
-index 000000000..0f446fe2f
---- /dev/null
-+++ b/man/man7/dracut.zfs.7
-@@ -0,0 +1,278 @@
-+.\" SPDX-License-Identifier: 0BSD
-+.\"
-+.Dd April 4, 2022
-+.Dt DRACUT.ZFS 7
-+.Os
-+.
-+.Sh NAME
-+.Nm dracut.zfs
-+.Nd overview of ZFS dracut hooks
-+.
-+.Sh SYNOPSIS
-+.Bd -literal -compact
-+                      parse-zfs.sh \(-> dracut-cmdline.service
-+                          |                     \(da
-+                          |                     …
-+                          |                     \(da
-+                          \e\(em\(em\(em\(em\(em\(em\(em\(em\(-> dracut-initqueue.service
-+                                                |                      zfs-import-opts.sh
-+   zfs-load-module.service                      \(da                          |       |
-+     |                  |                sysinit.target                    \(da       |
-+     \(da                  |                       |        zfs-import-scan.service   \(da
-+zfs-import-scan.service \(da                       \(da           | zfs-import-cache.service
-+     |   zfs-import-cache.service         basic.target      |     |
-+     \e__________________|                       |           \(da     \(da
-+                        \(da                       |     zfs-load-key.sh
-+     zfs-env-bootfs.service                     |         |
-+                        \(da                       \(da         \(da
-+                 zfs-import.target \(-> dracut-pre-mount.service
-+                        |          \(ua            |
-+                        | dracut-zfs-generator  |
-+                        |  ____________________/|
-+                        |/                      \(da
-+                        |                   sysroot.mount \(<-\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em dracut-zfs-generator
-+                        |                       |                                        \(da   |
-+                        |                       \(da            sysroot-{usr,etc,lib,&c.}.mount |
-+                        |             initrd-root-fs.target \(<-\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em or                 \(da
-+                        |                       |              zfs-nonroot-necessities.service
-+                        |                       \(da                                 |
-+                        \(da             dracut-mount.service                        |
-+       zfs-snapshot-bootfs.service              |                                 |
-+                        |                       \(da                                 |
-+                        \(da                       …                                 |
-+       zfs-rollback-bootfs.service              |                                 |
-+                        |                       \(da                                 |
-+                        |               sysroot-usr.mount \(<-\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em/
-+                        |                       |
-+                        |                       \(da
-+                        |                initrd-fs.target
-+                        \e______________________ |
-+                                               \e|
-+                                                \(da
-+        export-zfs.sh                      initrd.target
-+              |                                 |
-+              \(da                                 \(da
-+   dracut-shutdown.service                      …
-+                                                |
-+                                                \(da
-+                 zfs-needshutdown.sh \(-> initrd-cleanup.service
-+.Ed
-+.Pp
-+Compare
-+.Xr dracut.bootup 7
-+for the full flowchart.
-+.
-+.Sh DESCRIPTION
-+Under dracut, booting with
-+.No ZFS-on- Ns Pa /
-+is facilitated by a number of hooks in the
-+.Nm 90zfs
-+module.
-+.Pp
-+Booting into a ZFS dataset requires
-+.Sy mountpoint Ns = Ns Pa /
-+to be set on the dataset containing the root filesystem (henceforth "the boot dataset") and at the very least either the
-+.Sy bootfs
-+property to be set to that dataset, or the
-+.Sy root=
-+kernel cmdline (or dracut drop-in) argument to specify it.
-+.Pp
-+All children of the boot dataset with
-+.Sy canmount Ns = Ns Sy on
-+with
-+.Sy mountpoint Ns s
-+matching
-+.Pa /etc , /bin , /lib , /lib?? , /libx32 , No and Pa /usr
-+globs are deemed essential and will be mounted as well.
-+.Pp
-+.Xr zfs-mount-generator 8
-+is recommended for proper functioning of the system afterward (correct mount properties, remounting, &c.).
-+.
-+.Sh CMDLINE
-+.Ss Standard
-+.Bl -tag -compact -width ".Sy root=zfs:AUTO , root=zfs: , root=zfs , Op Sy root="
-+.It Sy root=zfs:\& Ns Ar dataset , Sy root=ZFS= Ns Ar dataset
-+Use
-+.Ar dataset
-+as the boot dataset.
-+All pluses
-+.Pq Sq +
-+are replaced with spaces
-+.Pq Sq \  .
-+.
-+.It Sy root=zfs:AUTO , root=zfs:\& , root=zfs , Op Sy root=
-+After import, search for the first pool with the
-+.Sy bootfs
-+property set, use its value as-if specified as the
-+.Ar dataset
-+above.
-+.
-+.It Sy rootfstype=zfs root= Ns Ar dataset
-+Equivalent to
-+.Sy root=zfs:\& Ns Ar dataset .
-+.
-+.It Sy rootfstype=zfs Op Sy root=
-+Equivalent to
-+.Sy root=zfs:AUTO .
-+.
-+.It Sy rootflags= Ns Ar flags
-+Mount the boot dataset with
-+.Fl o Ar flags ;
-+cf.\&
-+.Sx Temporary Mount Point Properties
-+in
-+.Xr zfsprops 7 .
-+These properties will not last, since all filesystems will be re-mounted from the real root.
-+.
-+.It Sy debug
-+If specified,
-+.Nm dracut-zfs-generator
-+logs to the journal.
-+.El
-+.Pp
-+Be careful about setting neither
-+.Sy rootfstype=zfs
-+nor
-+.Sy root=zfs:\& Ns Ar dataset
-+\(em other automatic boot selection methods, like
-+.Nm systemd-gpt-auto-generator
-+and
-+.Nm systemd-fstab-generator
-+might take precedent.
-+.
-+.Ss ZFS-specific
-+.Bl -tag -compact -width ".Sy bootfs.snapshot Ns Op Sy = Ns Ar snapshot-name"
-+.It Sy bootfs.snapshot Ns Op Sy = Ns Ar snapshot-name
-+Execute
-+.Nm zfs Cm snapshot Ar boot-dataset Ns Sy @ Ns Ar snapshot-name
-+before pivoting to the real root.
-+.Ar snapshot-name
-+defaults to the current kernel release.
-+.
-+.It Sy bootfs.rollback Ns Op Sy = Ns Ar snapshot-name
-+Execute
-+.Nm zfs Cm snapshot Fl Rf Ar boot-dataset Ns Sy @ Ns Ar snapshot-name
-+before pivoting to the real root.
-+.Ar snapshot-name
-+defaults to the current kernel release.
-+.
-+.It Sy spl_hostid= Ns Ar host-id
-+Use
-+.Xr zgenhostid 8
-+to set the host ID to
-+.Ar host-id ;
-+otherwise,
-+.Pa /etc/hostid
-+inherited from the real root is used.
-+.
-+.It Sy zfs_force , zfs.force , zfsforce
-+Appends
-+.Fl f
-+to all
-+.Nm zpool Cm import
-+invocations; primarily useful in conjunction with
-+.Sy spl_hostid= ,
-+or if no host ID was inherited.
-+.El
-+.
-+.Sh FILES
-+.Bl -tag -width 0
-+.It Pa parse-zfs.sh Pq Sy cmdline
-+Processes
-+.Sy spl_hostid= .
-+If
-+.Sy root=
-+matches a known pattern, above, provides
-+.Pa /dev/root
-+and delays the initqueue until
-+.Xr zfs 4
-+is loaded,
-+.
-+.It Pa zfs-import-opts.sh Pq Nm systemd No environment generator
-+Turns
-+.Sy zfs_force , zfs.force , No or Sy zfsforce
-+into
-+.Ev ZPOOL_IMPORT_OPTS Ns = Ns Fl f
-+for
-+.Pa zfs-import-scan.service
-+or
-+.Pa zfs-import-cache.service .
-+.
-+.It Pa zfs-load-key.sh Pq Sy pre-mount
-+Loads encryption keys for the boot dataset and its essential descendants.
-+.Bl -tag -compact -offset 4n -width ".Sy keylocation Ns = Ns Sy https:// Ns Ar URL , Sy keylocation Ns = Ns Sy http:// Ns Ar URL"
-+.It Sy keylocation Ns = Ns Sy prompt
-+Is prompted for via
-+.Nm systemd-ask-password
-+thrice.
-+.
-+.It Sy keylocation Ns = Ns Sy https:// Ns Ar URL , Sy keylocation Ns = Ns Sy http:// Ns Ar URL
-+.Pa network-online.target
-+is started before loading.
-+.
-+.It Sy keylocation Ns = Ns Sy file:// Ns Ar path
-+If
-+.Ar path
-+doesn't exist,
-+.Nm udevadm No is Cm settle Ns d .
-+If it still doesn't, it's waited for for up to
-+.Sy 10 Ns s .
-+.El
-+.
-+.It Pa zfs-env-bootfs.service Pq Nm systemd No service
-+After pool import, sets
-+.Ev BOOTFS Ns =
-+in the systemd environment to the first non-null
-+.Sy bootfs
-+value in iteration order.
-+.
-+.It Pa dracut-zfs-generator Pq Nm systemd No generator
-+Generates
-+.Pa sysroot.mount Pq using Sy rootflags= , No if any .
-+If an explicit boot dataset was specified, also generates essential mountpoints
-+.Pq Pa sysroot-etc.mount , sysroot-bin.mount , No &c.\& ,
-+otherwise generates
-+.Pa zfs-nonroot-necessities.service
-+which mounts them explicitly after
-+.Pa /sysroot
-+using
-+.Ev BOOTFS Ns = .
-+.
-+.It Pa zfs-snapshot-bootfs.service , zfs-rollback-bootfs.service Pq Nm systemd No services
-+Consume
-+.Sy bootfs.snapshot
-+and
-+.Sy bootfs.rollback
-+as described in
-+.Sx CMDLINE  .
-+Use
-+.Ev BOOTFS Ns =
-+if no explicit boot dataset was specified.
-+.
-+.It Pa zfs-needshutdown.sh Pq Sy cleanup
-+If any pools were imported, signals that shutdown hooks are required.
-+.
-+.It Pa export-zfs.sh Pq Sy shutdown
-+Forcibly exports all pools.
-+.
-+.It Pa /etc/hostid , /etc/zfs/zpool.cache , /etc/zfs/vdev_id.conf Pq regular files
-+Included verbatim, hostonly.
-+.
-+.It Pa mount-zfs.sh Pq Sy mount
-+Does nothing on
-+.Nm systemd
-+systems
-+.Pq if Pa dracut-zfs-generator No succeeded .
-+Otherwise, loads encryption key for the boot dataset from the console or via plymouth.
-+It may not work at all!
-+.El
-+.
-+.Sh SEE ALSO
-+.Xr dracut.bootup 7 ,
-+.Xr zfsprops 7 ,
-+.Xr zpoolprops 7 ,
-+.Xr dracut-shutdown.service 8 ,
-+.Xr systemd-fstab-generator 8 ,
-+.Xr systemd-gpt-auto-generator 8 ,
-+.Xr zfs-mount-generator 8 ,
-+.Xr zgenhostid 8
-diff --git a/man/man8/zfs-diff.8 b/man/man8/zfs-diff.8
-index 49443bf47..a347f3252 100644
---- a/man/man8/zfs-diff.8
-+++ b/man/man8/zfs-diff.8
-@@ -39,7 +39,7 @@
- .Sh SYNOPSIS
- .Nm zfs
- .Cm diff
--.Op Fl FHt
-+.Op Fl FHth
- .Ar snapshot Ar snapshot Ns | Ns Ar filesystem
- .
- .Sh DESCRIPTION
-@@ -92,6 +92,10 @@ Give more parsable tab-separated output, without header lines and without
- arrows.
- .It Fl t
- Display the path's inode change time as the first column of output.
-+.It Fl h
-+Do not
-+.Sy \e0 Ns Ar ooo Ns -escape
-+non-ASCII paths.
- .El
- .
- .Sh SEE ALSO
-diff --git a/man/man8/zfs-mount-generator.8.in b/man/man8/zfs-mount-generator.8.in
-index 7aa332ba8..ae8937038 100644
---- a/man/man8/zfs-mount-generator.8.in
-+++ b/man/man8/zfs-mount-generator.8.in
-@@ -142,22 +142,11 @@ ZEDLET, if enabled
- .Pq see Xr zed 8 .
- .
- .Sh ENVIRONMENT
--The
-+If the
- .Sy ZFS_DEBUG
--environment variable can either be
--.Sy 0
--(default),
--.Sy 1
--(print summary accounting information at the end), or at least
--.Sy 2
--(print accounting information for each subprocess as it finishes).
--.
--If not present,
--.Pa /proc/cmdline
--is additionally checked for
--.Qq debug ,
--in which case the debug level is set to
--.Sy 2 .
-+environment variable is nonzero
-+.Pq or unset and Pa /proc/cmdline No contains Qq Sy debug ,
-+print summary accounting information at the end.
- .
- .Sh EXAMPLES
- To begin, enable tracking for the pool:
-diff --git a/man/man8/zfs-set.8 b/man/man8/zfs-set.8
-index a3588cc26..ccd90f091 100644
---- a/man/man8/zfs-set.8
-+++ b/man/man8/zfs-set.8
-@@ -170,8 +170,9 @@ inherited.
- .It Fl r
- Recursively inherit the given property for all children.
- .It Fl S
--Revert the property to the received value if one exists; otherwise operate as
--if the
-+Revert the property to the received value, if one exists;
-+otherwise, for non-inheritable properties, to the default;
-+otherwise, operate as if the
- .Fl S
- option was not specified.
- .El
-diff --git a/man/man8/zpool-import.8 b/man/man8/zpool-import.8
-index 39b0e17ef..5462e4ebd 100644
---- a/man/man8/zpool-import.8
-+++ b/man/man8/zpool-import.8
-@@ -71,7 +71,8 @@
- .Xc
- Lists pools available to import.
- If the
--.Fl d or
-+.Fl d
-+or
- .Fl c
- options are not specified, this command searches for devices using libblkid
- on Linux and geom on
-diff --git a/module/icp/algs/modes/gcm.c b/module/icp/algs/modes/gcm.c
-index 7332834cb..dc8dd929f 100644
---- a/module/icp/algs/modes/gcm.c
-+++ b/module/icp/algs/modes/gcm.c
-@@ -798,7 +798,7 @@ static gcm_impl_ops_t *gcm_supp_impl[ARRAY_SIZE(gcm_all_impl)];
-  * fallback to the fastest generic implementation.
-  */
- const gcm_impl_ops_t *
--gcm_impl_get_ops()
-+gcm_impl_get_ops(void)
- {
- 	if (!kfpu_allowed())
- 		return (&gcm_generic_impl);
-diff --git a/module/os/freebsd/zfs/abd_os.c b/module/os/freebsd/zfs/abd_os.c
-index 41ceed1dc..ddd6d68b3 100644
---- a/module/os/freebsd/zfs/abd_os.c
-+++ b/module/os/freebsd/zfs/abd_os.c
-@@ -113,7 +113,6 @@ static kstat_t *abd_ksp;
-  * memory by only using a single zero buffer for the scatter chunks.
-  */
- abd_t *abd_zero_scatter = NULL;
--static char *abd_zero_buf = NULL;
- 
- static uint_t
- abd_chunkcnt_for_bytes(size_t size)
-@@ -241,18 +240,16 @@ abd_free_struct_impl(abd_t *abd)
- 
- /*
-  * Allocate scatter ABD of size SPA_MAXBLOCKSIZE, where
-- * each chunk in the scatterlist will be set to abd_zero_buf.
-+ * each chunk in the scatterlist will be set to the same area.
-  */
-+_Static_assert(ZERO_REGION_SIZE >= PAGE_SIZE, "zero_region too small");
- static void
- abd_alloc_zero_scatter(void)
- {
- 	uint_t i, n;
- 
- 	n = abd_chunkcnt_for_bytes(SPA_MAXBLOCKSIZE);
--	abd_zero_buf = kmem_cache_alloc(abd_chunk_cache, KM_PUSHPAGE);
--	bzero(abd_zero_buf, PAGE_SIZE);
- 	abd_zero_scatter = abd_alloc_struct(SPA_MAXBLOCKSIZE);
--
- 	abd_zero_scatter->abd_flags |= ABD_FLAG_OWNER | ABD_FLAG_ZEROS;
- 	abd_zero_scatter->abd_size = SPA_MAXBLOCKSIZE;
- 
-@@ -260,7 +257,7 @@ abd_alloc_zero_scatter(void)
- 
- 	for (i = 0; i < n; i++) {
- 		ABD_SCATTER(abd_zero_scatter).abd_chunks[i] =
--		    abd_zero_buf;
-+		    __DECONST(void *, zero_region);
- 	}
- 
- 	ABDSTAT_BUMP(abdstat_scatter_cnt);
-@@ -275,7 +272,6 @@ abd_free_zero_scatter(void)
- 
- 	abd_free_struct(abd_zero_scatter);
- 	abd_zero_scatter = NULL;
--	kmem_cache_free(abd_chunk_cache, abd_zero_buf);
- }
- 
- static int
-diff --git a/module/os/freebsd/zfs/spa_os.c b/module/os/freebsd/zfs/spa_os.c
-index 070e7a5b9..d5f851a30 100644
---- a/module/os/freebsd/zfs/spa_os.c
-+++ b/module/os/freebsd/zfs/spa_os.c
-@@ -183,7 +183,6 @@ spa_import_rootpool(const char *name, bool checkpointrewind)
- 	spa_t *spa;
- 	vdev_t *rvd;
- 	nvlist_t *config, *nvtop;
--	uint64_t txg;
- 	char *pname;
- 	int error;
- 
-@@ -196,7 +195,6 @@ spa_import_rootpool(const char *name, bool checkpointrewind)
- 	if (config != NULL) {
- 		pname = fnvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME);
- 		VERIFY0(strcmp(name, pname));
--		txg = fnvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_TXG);
- 
- 		if ((spa = spa_lookup(pname)) != NULL) {
- 			/*
-diff --git a/module/os/freebsd/zfs/vdev_geom.c b/module/os/freebsd/zfs/vdev_geom.c
-index 2ef4811a8..5447eb922 100644
---- a/module/os/freebsd/zfs/vdev_geom.c
-+++ b/module/os/freebsd/zfs/vdev_geom.c
-@@ -1132,8 +1132,12 @@ vdev_geom_fill_unmap_cb(void *buf, size_t len, void *priv)
- 	vm_offset_t addr = (vm_offset_t)buf;
- 	vm_offset_t end = addr + len;
- 
--	if (bp->bio_ma_n == 0)
-+	if (bp->bio_ma_n == 0) {
- 		bp->bio_ma_offset = addr & PAGE_MASK;
-+		addr &= ~PAGE_MASK;
-+	} else {
-+		ASSERT0(P2PHASE(addr, PAGE_SIZE));
-+	}
- 	do {
- 		bp->bio_ma[bp->bio_ma_n++] =
- 		    PHYS_TO_VM_PAGE(pmap_kextract(addr));
-diff --git a/module/os/freebsd/zfs/zfs_vnops_os.c b/module/os/freebsd/zfs/zfs_vnops_os.c
-index b2cc3d063..f6bc9c0c6 100644
---- a/module/os/freebsd/zfs/zfs_vnops_os.c
-+++ b/module/os/freebsd/zfs/zfs_vnops_os.c
-@@ -97,6 +97,10 @@
- 
- VFS_SMR_DECLARE;
- 
-+#if __FreeBSD_version < 1300103
-+#define	NDFREE_PNBUF(ndp)	NDFREE((ndp), NDF_ONLY_PNBUF)
-+#endif
-+
- #if __FreeBSD_version >= 1300047
- #define	vm_page_wire_lock(pp)
- #define	vm_page_wire_unlock(pp)
-@@ -4058,8 +4062,8 @@ zfs_getpages(struct vnode *vp, vm_page_t *ma, int count, int *rbehind,
- 	int pgsin_b, pgsin_a;
- 	int error;
- 
--	ZFS_ENTER(zfsvfs);
--	ZFS_VERIFY_ZP(zp);
-+	ZFS_ENTER_ERROR(zfsvfs, zfs_vm_pagerret_error);
-+	ZFS_VERIFY_ZP_ERROR(zp, zfs_vm_pagerret_error);
- 
- 	start = IDX_TO_OFF(ma[0]->pindex);
- 	end = IDX_TO_OFF(ma[count - 1]->pindex + 1);
-@@ -4183,19 +4187,18 @@ zfs_putpages(struct vnode *vp, vm_page_t *ma, size_t len, int flags,
- 	int		err;
- 	int		i;
- 
--	ZFS_ENTER(zfsvfs);
--	ZFS_VERIFY_ZP(zp);
--
- 	object = vp->v_object;
--	pcount = btoc(len);
--	ncount = pcount;
--
- 	KASSERT(ma[0]->object == object, ("mismatching object"));
- 	KASSERT(len > 0 && (len & PAGE_MASK) == 0, ("unexpected length"));
- 
-+	pcount = btoc(len);
-+	ncount = pcount;
- 	for (i = 0; i < pcount; i++)
- 		rtvals[i] = zfs_vm_pagerret_error;
- 
-+	ZFS_ENTER_ERROR(zfsvfs, zfs_vm_pagerret_error);
-+	ZFS_VERIFY_ZP_ERROR(zp, zfs_vm_pagerret_error);
-+
- 	off = IDX_TO_OFF(ma[0]->pindex);
- 	blksz = zp->z_blksz;
- 	lo_off = rounddown(off, blksz);
-@@ -5234,6 +5237,11 @@ zfs_freebsd_pathconf(struct vop_pathconf_args *ap)
- 	case _PC_NAME_MAX:
- 		*ap->a_retval = NAME_MAX;
- 		return (0);
-+#if __FreeBSD_version >= 1400032
-+	case _PC_DEALLOC_PRESENT:
-+		*ap->a_retval = 1;
-+		return (0);
-+#endif
- 	case _PC_PIPE_BUF:
- 		if (ap->a_vp->v_type == VDIR || ap->a_vp->v_type == VFIFO) {
- 			*ap->a_retval = PIPE_BUF;
-@@ -5357,7 +5365,7 @@ zfs_getextattr_dir(struct vop_getextattr_args *ap, const char *attrname)
- #endif
- 	error = vn_open_cred(&nd, &flags, 0, VN_OPEN_INVFS, ap->a_cred, NULL);
- 	vp = nd.ni_vp;
--	NDFREE(&nd, NDF_ONLY_PNBUF);
-+	NDFREE_PNBUF(&nd);
- 	if (error != 0)
- 		return (error);
- 
-@@ -5430,7 +5438,7 @@ zfs_getextattr(struct vop_getextattr_args *ap)
- 
- 	error = ENOENT;
- 	ZFS_ENTER(zfsvfs);
--	ZFS_VERIFY_ZP(zp)
-+	ZFS_VERIFY_ZP(zp);
- 	rw_enter(&zp->z_xattr_lock, RW_READER);
- 	if (zfsvfs->z_use_sa && zp->z_is_sa)
- 		error = zfs_getextattr_sa(ap, attrname);
-@@ -5475,12 +5483,12 @@ zfs_deleteextattr_dir(struct vop_deleteextattr_args *ap, const char *attrname)
- 	error = namei(&nd);
- 	vp = nd.ni_vp;
- 	if (error != 0) {
--		NDFREE(&nd, NDF_ONLY_PNBUF);
-+		NDFREE_PNBUF(&nd);
- 		return (error);
- 	}
- 
- 	error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd);
--	NDFREE(&nd, NDF_ONLY_PNBUF);
-+	NDFREE_PNBUF(&nd);
- 
- 	vput(nd.ni_dvp);
- 	if (vp == nd.ni_dvp)
-@@ -5605,7 +5613,7 @@ zfs_setextattr_dir(struct vop_setextattr_args *ap, const char *attrname)
- 	error = vn_open_cred(&nd, &flags, 0600, VN_OPEN_INVFS, ap->a_cred,
- 	    NULL);
- 	vp = nd.ni_vp;
--	NDFREE(&nd, NDF_ONLY_PNBUF);
-+	NDFREE_PNBUF(&nd);
- 	if (error != 0)
- 		return (error);
- 
-@@ -5760,7 +5768,7 @@ zfs_listextattr_dir(struct vop_listextattr_args *ap, const char *attrprefix)
- #endif
- 	error = namei(&nd);
- 	vp = nd.ni_vp;
--	NDFREE(&nd, NDF_ONLY_PNBUF);
-+	NDFREE_PNBUF(&nd);
- 	if (error != 0)
- 		return (error);
- 
-@@ -6073,6 +6081,55 @@ zfs_vptocnp(struct vop_vptocnp_args *ap)
- 	return (error);
- }
- 
-+#if __FreeBSD_version >= 1400032
-+static int
-+zfs_deallocate(struct vop_deallocate_args *ap)
-+{
-+	znode_t *zp = VTOZ(ap->a_vp);
-+	zfsvfs_t *zfsvfs = zp->z_zfsvfs;
-+	zilog_t *zilog;
-+	off_t off, len, file_sz;
-+	int error;
-+
-+	ZFS_ENTER(zfsvfs);
-+	ZFS_VERIFY_ZP(zp);
-+
-+	/*
-+	 * Callers might not be able to detect properly that we are read-only,
-+	 * so check it explicitly here.
-+	 */
-+	if (zfs_is_readonly(zfsvfs)) {
-+		ZFS_EXIT(zfsvfs);
-+		return (SET_ERROR(EROFS));
-+	}
-+
-+	zilog = zfsvfs->z_log;
-+	off = *ap->a_offset;
-+	len = *ap->a_len;
-+	file_sz = zp->z_size;
-+	if (off + len > file_sz)
-+		len = file_sz - off;
-+	/* Fast path for out-of-range request. */
-+	if (len <= 0) {
-+		*ap->a_len = 0;
-+		ZFS_EXIT(zfsvfs);
-+		return (0);
-+	}
-+
-+	error = zfs_freesp(zp, off, len, O_RDWR, TRUE);
-+	if (error == 0) {
-+		if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS ||
-+		    (ap->a_ioflag & IO_SYNC) != 0)
-+			zil_commit(zilog, zp->z_id);
-+		*ap->a_offset = off + len;
-+		*ap->a_len = 0;
-+	}
-+
-+	ZFS_EXIT(zfsvfs);
-+	return (error);
-+}
-+#endif
-+
- struct vop_vector zfs_vnodeops;
- struct vop_vector zfs_fifoops;
- struct vop_vector zfs_shareops;
-@@ -6092,6 +6149,9 @@ struct vop_vector zfs_vnodeops = {
- #endif
- 	.vop_access =		zfs_freebsd_access,
- 	.vop_allocate =		VOP_EINVAL,
-+#if __FreeBSD_version >= 1400032
-+	.vop_deallocate =	zfs_deallocate,
-+#endif
- 	.vop_lookup =		zfs_cache_lookup,
- 	.vop_cachedlookup =	zfs_freebsd_cachedlookup,
- 	.vop_getattr =		zfs_freebsd_getattr,
-diff --git a/module/os/freebsd/zfs/zfs_znode.c b/module/os/freebsd/zfs/zfs_znode.c
-index e4a1d2db7..bbc45fda8 100644
---- a/module/os/freebsd/zfs/zfs_znode.c
-+++ b/module/os/freebsd/zfs/zfs_znode.c
-@@ -575,7 +575,6 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr,
- 	dmu_buf_t	*db;
- 	timestruc_t	now;
- 	uint64_t	gen, obj;
--	int		err;
- 	int		bonuslen;
- 	int		dnodesize;
- 	sa_handle_t	*sa_hdl;
-@@ -815,12 +814,11 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr,
- 		VERIFY0(zfs_aclset_common(*zpp, acl_ids->z_aclp, cr, tx));
- 	}
- 	if (!(flag & IS_ROOT_NODE)) {
--		vnode_t *vp;
--
--		vp = ZTOV(*zpp);
-+		vnode_t *vp = ZTOV(*zpp);
- 		vp->v_vflag |= VV_FORCEINSMQ;
--		err = insmntque(vp, zfsvfs->z_vfs);
-+		int err = insmntque(vp, zfsvfs->z_vfs);
- 		vp->v_vflag &= ~VV_FORCEINSMQ;
-+		(void) err;
- 		KASSERT(err == 0, ("insmntque() failed: error %d", err));
- 	}
- 	kmem_free(sa_attrs, sizeof (sa_bulk_attr_t) * ZPL_END);
-@@ -934,11 +932,9 @@ zfs_zget(zfsvfs_t *zfsvfs, uint64_t obj_num, znode_t **zpp)
- 	znode_t		*zp;
- 	vnode_t		*vp;
- 	sa_handle_t	*hdl;
--	struct thread	*td;
- 	int locked;
- 	int err;
- 
--	td = curthread;
- 	getnewvnode_reserve_();
- again:
- 	*zpp = NULL;
-@@ -964,7 +960,7 @@ again:
- 
- 	hdl = dmu_buf_get_user(db);
- 	if (hdl != NULL) {
--		zp  = sa_get_userdata(hdl);
-+		zp = sa_get_userdata(hdl);
- 
- 		/*
- 		 * Since "SA" does immediate eviction we
-@@ -1491,12 +1487,16 @@ zfs_free_range(znode_t *zp, uint64_t off, uint64_t len)
- 	error = dmu_free_long_range(zfsvfs->z_os, zp->z_id, off, len);
- 
- 	if (error == 0) {
-+#if __FreeBSD_version >= 1400032
-+		vnode_pager_purge_range(ZTOV(zp), off, off + len);
-+#else
- 		/*
--		 * In FreeBSD we cannot free block in the middle of a file,
--		 * but only at the end of a file, so this code path should
--		 * never happen.
-+		 * Before __FreeBSD_version 1400032 we cannot free block in the
-+		 * middle of a file, but only at the end of a file, so this code
-+		 * path should never happen.
- 		 */
- 		vnode_pager_setsize(ZTOV(zp), off);
-+#endif
- 	}
- 
- 	zfs_rangelock_exit(lr);
-diff --git a/module/os/freebsd/zfs/zvol_os.c b/module/os/freebsd/zfs/zvol_os.c
-index 0b347e7f9..09c35b371 100644
---- a/module/os/freebsd/zfs/zvol_os.c
-+++ b/module/os/freebsd/zfs/zvol_os.c
-@@ -1063,7 +1063,7 @@ zvol_cdev_ioctl(struct cdev *dev, ulong_t cmd, caddr_t data,
- 	zvol_state_t *zv;
- 	zfs_locked_range_t *lr;
- 	off_t offset, length;
--	int i, error;
-+	int error;
- 	boolean_t sync;
- 
- 	zv = dev->si_drv2;
-@@ -1072,7 +1072,6 @@ zvol_cdev_ioctl(struct cdev *dev, ulong_t cmd, caddr_t data,
- 	KASSERT(zv->zv_open_count > 0,
- 	    ("Device with zero access count in %s", __func__));
- 
--	i = IOCPARM_LEN(cmd);
- 	switch (cmd) {
- 	case DIOCGSECTORSIZE:
- 		*(uint32_t *)data = DEV_BSIZE;
-diff --git a/module/os/linux/spl/spl-kmem-cache.c b/module/os/linux/spl/spl-kmem-cache.c
-index 2151ef008..5a318e0a5 100644
---- a/module/os/linux/spl/spl-kmem-cache.c
-+++ b/module/os/linux/spl/spl-kmem-cache.c
-@@ -1421,7 +1421,7 @@ EXPORT_SYMBOL(spl_kmem_cache_reap_now);
-  * it should do no harm.
-  */
- int
--spl_kmem_cache_reap_active()
-+spl_kmem_cache_reap_active(void)
- {
- 	return (0);
- }
-diff --git a/module/os/linux/zfs/abd_os.c b/module/os/linux/zfs/abd_os.c
-index d1d238a4e..8afa222de 100644
---- a/module/os/linux/zfs/abd_os.c
-+++ b/module/os/linux/zfs/abd_os.c
-@@ -184,8 +184,11 @@ abd_t *abd_zero_scatter = NULL;
- 
- struct page;
- /*
-- * abd_zero_page we will be an allocated zero'd PAGESIZE buffer, which is
-- * assigned to set each of the pages of abd_zero_scatter.
-+ * _KERNEL   - Will point to ZERO_PAGE if it is available or it will be
-+ *             an allocated zero'd PAGESIZE buffer.
-+ * Userspace - Will be an allocated zero'ed PAGESIZE buffer.
-+ *
-+ * abd_zero_page is assigned to each of the pages of abd_zero_scatter.
-  */
- static struct page *abd_zero_page = NULL;
- 
-@@ -465,15 +468,19 @@ abd_alloc_zero_scatter(void)
- 	struct scatterlist *sg = NULL;
- 	struct sg_table table;
- 	gfp_t gfp = __GFP_NOWARN | GFP_NOIO;
--	gfp_t gfp_zero_page = gfp | __GFP_ZERO;
- 	int nr_pages = abd_chunkcnt_for_bytes(SPA_MAXBLOCKSIZE);
- 	int i = 0;
- 
-+#if defined(HAVE_ZERO_PAGE_GPL_ONLY)
-+	gfp_t gfp_zero_page = gfp | __GFP_ZERO;
- 	while ((abd_zero_page = __page_cache_alloc(gfp_zero_page)) == NULL) {
- 		ABDSTAT_BUMP(abdstat_scatter_page_alloc_retry);
- 		schedule_timeout_interruptible(1);
- 	}
- 	abd_mark_zfs_page(abd_zero_page);
-+#else
-+	abd_zero_page = ZERO_PAGE(0);
-+#endif /* HAVE_ZERO_PAGE_GPL_ONLY */
- 
- 	while (sg_alloc_table(&table, nr_pages, gfp)) {
- 		ABDSTAT_BUMP(abdstat_scatter_sg_table_retry);
-@@ -612,7 +619,6 @@ abd_alloc_zero_scatter(void)
- 	ABD_SCATTER(abd_zero_scatter).abd_offset = 0;
- 	ABD_SCATTER(abd_zero_scatter).abd_nents = nr_pages;
- 	abd_zero_scatter->abd_size = SPA_MAXBLOCKSIZE;
--	zfs_refcount_create(&abd_zero_scatter->abd_children);
- 	ABD_SCATTER(abd_zero_scatter).abd_sgl = vmem_alloc(nr_pages *
- 	    sizeof (struct scatterlist), KM_SLEEP);
- 
-@@ -694,8 +700,10 @@ abd_free_zero_scatter(void)
- 	abd_zero_scatter = NULL;
- 	ASSERT3P(abd_zero_page, !=, NULL);
- #if defined(_KERNEL)
-+#if defined(HAVE_ZERO_PAGE_GPL_ONLY)
- 	abd_unmark_zfs_page(abd_zero_page);
- 	__free_page(abd_zero_page);
-+#endif /* HAVE_ZERO_PAGE_GPL_ONLY */
- #else
- 	umem_free(abd_zero_page, PAGESIZE);
- #endif /* _KERNEL */
-diff --git a/module/os/linux/zfs/vdev_disk.c b/module/os/linux/zfs/vdev_disk.c
-index 581a79086..2708535b3 100644
---- a/module/os/linux/zfs/vdev_disk.c
-+++ b/module/os/linux/zfs/vdev_disk.c
-@@ -467,8 +467,11 @@ vdev_submit_bio_impl(struct bio *bio)
-  * blkg_tryget() to use rcu_read_lock() instead of rcu_read_lock_sched().
-  * As a side effect the function was converted to GPL-only.  Define our
-  * own version when needed which uses rcu_read_lock_sched().
-+ *
-+ * The Linux 5.17 kernel split linux/blk-cgroup.h into a private and a public
-+ * part, moving blkg_tryget into the private one. Define our own version.
-  */
--#if defined(HAVE_BLKG_TRYGET_GPL_ONLY)
-+#if defined(HAVE_BLKG_TRYGET_GPL_ONLY) || !defined(HAVE_BLKG_TRYGET)
- static inline bool
- vdev_blkg_tryget(struct blkcg_gq *blkg)
- {
-@@ -493,7 +496,7 @@ vdev_blkg_tryget(struct blkcg_gq *blkg)
- 
- 	return (rc);
- }
--#elif defined(HAVE_BLKG_TRYGET)
-+#else
- #define	vdev_blkg_tryget(bg)	blkg_tryget(bg)
- #endif
- #ifdef HAVE_BIO_SET_DEV_MACRO
-@@ -563,6 +566,10 @@ vdev_submit_bio(struct bio *bio)
- 	current->bio_list = bio_list;
- }
- 
-+#ifdef HAVE_BIO_ALLOC_4ARG
-+#define	bio_alloc(gfp_mask, nr_iovecs) bio_alloc(NULL, nr_iovecs, 0, gfp_mask)
-+#endif
-+
- static int
- __vdev_disk_physio(struct block_device *bdev, zio_t *zio,
-     size_t io_size, uint64_t io_offset, int rw, int flags)
-diff --git a/module/os/linux/zfs/zfs_sysfs.c b/module/os/linux/zfs/zfs_sysfs.c
-index fb7c68987..e73b34a2f 100644
---- a/module/os/linux/zfs/zfs_sysfs.c
-+++ b/module/os/linux/zfs/zfs_sysfs.c
-@@ -65,16 +65,15 @@
- /*
-  * A zfs_mod_kobj_t represents a zfs kobject under '/sys/module/zfs'
-  */
--struct zfs_mod_kobj;
- typedef struct zfs_mod_kobj zfs_mod_kobj_t;
--
- struct zfs_mod_kobj {
- 	struct kobject		zko_kobj;
- 	struct kobj_type	zko_kobj_type;
- 	struct sysfs_ops	zko_sysfs_ops;
- 	size_t			zko_attr_count;
- 	struct attribute	*zko_attr_list;		/* allocated */
--	struct attribute	**zko_default_attrs;	/* allocated */
-+	struct attribute_group	zko_default_group;	/* .attrs allocated */
-+	const struct attribute_group	*zko_default_groups[2];
- 	size_t			zko_child_count;
- 	zfs_mod_kobj_t		*zko_children;		/* allocated */
- };
-@@ -126,10 +125,10 @@ zfs_kobj_release(struct kobject *kobj)
- 		zkobj->zko_attr_list = NULL;
- 	}
- 
--	if (zkobj->zko_default_attrs != NULL) {
--		kmem_free(zkobj->zko_default_attrs,
-+	if (zkobj->zko_default_group.attrs != NULL) {
-+		kmem_free(zkobj->zko_default_group.attrs,
- 		    DEFAULT_ATTR_SIZE(zkobj->zko_attr_count));
<Skipped 1558 lines>
================================================================

---- gitweb:

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




More information about the pld-cvs-commit mailing list