]> git.pld-linux.org Git - packages/zfs.git/blob - zfs-2.1.5-staging.patch
- pull updates from 2.1.5-staging branch, rel 2
[packages/zfs.git] / zfs-2.1.5-staging.patch
1 diff --git a/Makefile.am b/Makefile.am
2 index 34fe16ce4..7e2b10b39 100644
3 --- a/Makefile.am
4 +++ b/Makefile.am
5 @@ -103,7 +103,7 @@ endif
6  endif
7  
8  PHONY += codecheck
9 -codecheck: cstyle shellcheck checkbashisms flake8 mancheck testscheck vcscheck
10 +codecheck: cstyle shellcheck checkbashisms flake8 mancheck testscheck vcscheck zstdcheck
11  
12  PHONY += checkstyle
13  checkstyle: codecheck commitcheck
14 @@ -120,6 +120,7 @@ cstyle:
15                 -o -type f -name '*.[hc]' \
16                 ! -name 'zfs_config.*' ! -name '*.mod.c' \
17                 ! -name 'opt_global.h' ! -name '*_if*.h' \
18 +               ! -name 'zstd_compat_wrapper.h' \
19                 ! -path './module/zstd/lib/*' \
20                 -exec ${top_srcdir}/scripts/cstyle.pl -cpP {} \+
21  
22 @@ -173,6 +174,10 @@ vcscheck:
23                 awk '{c++; print} END {if(c>0) exit 1}' ; \
24         fi
25  
26 +PHONY += zstdcheck
27 +zstdcheck:
28 +       @$(MAKE) -C module/zstd checksymbols
29 +
30  PHONY += lint
31  lint: cppcheck paxcheck
32  
33 diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c
34 index 9de41cef2..75688205f 100644
35 --- a/cmd/zdb/zdb.c
36 +++ b/cmd/zdb/zdb.c
37 @@ -110,6 +110,7 @@ extern int zfs_recover;
38  extern unsigned long zfs_arc_meta_min, zfs_arc_meta_limit;
39  extern int zfs_vdev_async_read_max_active;
40  extern boolean_t spa_load_verify_dryrun;
41 +extern boolean_t spa_mode_readable_spacemaps;
42  extern int zfs_reconstruct_indirect_combinations_max;
43  extern int zfs_btree_verify_intensity;
44  
45 @@ -8469,6 +8470,11 @@ main(int argc, char **argv)
46          */
47         spa_load_verify_dryrun = B_TRUE;
48  
49 +       /*
50 +        * ZDB should have ability to read spacemaps.
51 +        */
52 +       spa_mode_readable_spacemaps = B_TRUE;
53 +
54         kernel_init(SPA_MODE_READ);
55  
56         if (dump_all)
57 diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c
58 index d0bb73a72..6f0c846fd 100644
59 --- a/cmd/zfs/zfs_main.c
60 +++ b/cmd/zfs/zfs_main.c
61 @@ -6593,7 +6593,7 @@ zfs_do_holds(int argc, char **argv)
62                 /*
63                  *  1. collect holds data, set format options
64                  */
65 -               ret = zfs_for_each(argc, argv, flags, types, NULL, NULL, limit,
66 +               ret = zfs_for_each(1, argv + i, flags, types, NULL, NULL, limit,
67                     holds_callback, &cb);
68                 if (ret != 0)
69                         ++errors;
70 @@ -7672,7 +7672,7 @@ zfs_do_diff(int argc, char **argv)
71         int c;
72         struct sigaction sa;
73  
74 -       while ((c = getopt(argc, argv, "FHt")) != -1) {
75 +       while ((c = getopt(argc, argv, "FHth")) != -1) {
76                 switch (c) {
77                 case 'F':
78                         flags |= ZFS_DIFF_CLASSIFY;
79 @@ -7683,6 +7683,9 @@ zfs_do_diff(int argc, char **argv)
80                 case 't':
81                         flags |= ZFS_DIFF_TIMESTAMP;
82                         break;
83 +               case 'h':
84 +                       flags |= ZFS_DIFF_NO_MANGLE;
85 +                       break;
86                 default:
87                         (void) fprintf(stderr,
88                             gettext("invalid option '%c'\n"), optopt);
89 diff --git a/cmd/zvol_wait/zvol_wait b/cmd/zvol_wait/zvol_wait
90 index 2aa929b0c..f1fa42e27 100755
91 --- a/cmd/zvol_wait/zvol_wait
92 +++ b/cmd/zvol_wait/zvol_wait
93 @@ -28,15 +28,17 @@ filter_out_deleted_zvols() {
94  list_zvols() {
95         read -r default_volmode < /sys/module/zfs/parameters/zvol_volmode
96         zfs list -t volume -H -o \
97 -           name,volmode,receive_resume_token,redact_snaps |
98 -           while IFS=" " read -r name volmode token redacted; do # IFS=\t here!
99 +           name,volmode,receive_resume_token,redact_snaps,keystatus |
100 +           while IFS=" " read -r name volmode token redacted keystatus; do # IFS=\t here!
101  
102 -               # /dev links are not created for zvols with volmode = "none"
103 -               # or for redacted zvols.
104 +               # /dev links are not created for zvols with volmode = "none",
105 +               # redacted zvols, or encrypted zvols for which the key has not
106 +               # been loaded.
107                 [ "$volmode" = "none" ] && continue
108                 [ "$volmode" = "default" ] && [ "$default_volmode" = "3" ] &&
109                     continue
110                 [ "$redacted" = "-" ] || continue
111 +               [ "$keystatus" = "unavailable" ] && continue
112  
113                 # We also ignore partially received zvols if it is
114                 # not an incremental receive, as those won't even have a block
115 diff --git a/config/ax_python_devel.m4 b/config/ax_python_devel.m4
116 index fcf73dc20..7adcf01a0 100644
117 --- a/config/ax_python_devel.m4
118 +++ b/config/ax_python_devel.m4
119 @@ -224,7 +224,7 @@ EOD`
120                                 ac_python_version=$PYTHON_VERSION
121                         else
122                                 ac_python_version=`$PYTHON -c "import sys; \
123 -                                       print (sys.version[[:3]])"`
124 +                                       print ('.'.join(sys.version.split('.')[[:2]]))"`
125                         fi
126                 fi
127  
128 diff --git a/config/kernel-add-disk.m4 b/config/kernel-add-disk.m4
129 index 5d1779eb4..44a8a5fd2 100644
130 --- a/config/kernel-add-disk.m4
131 +++ b/config/kernel-add-disk.m4
132 @@ -3,16 +3,15 @@ dnl # 5.16 API change
133  dnl # add_disk grew a must-check return code
134  dnl #
135  AC_DEFUN([ZFS_AC_KERNEL_SRC_ADD_DISK], [
136 -
137         ZFS_LINUX_TEST_SRC([add_disk_ret], [
138 -               #include <linux/genhd.h>
139 +               #include <linux/blkdev.h>
140         ], [
141                 struct gendisk *disk = NULL;
142                 int err = add_disk(disk);
143                 err = err;
144         ])
145 -
146  ])
147 +
148  AC_DEFUN([ZFS_AC_KERNEL_ADD_DISK], [
149         AC_MSG_CHECKING([whether add_disk() returns int])
150         ZFS_LINUX_TEST_RESULT([add_disk_ret],
151 diff --git a/config/kernel-bio.m4 b/config/kernel-bio.m4
152 index d088d7023..b5d254481 100644
153 --- a/config/kernel-bio.m4
154 +++ b/config/kernel-bio.m4
155 @@ -474,6 +474,41 @@ AC_DEFUN([ZFS_AC_KERNEL_BLK_CGROUP_HEADER], [
156         ])
157  ])
158  
159 +dnl #
160 +dnl # Linux 5.18 API
161 +dnl #
162 +dnl # In 07888c665b405b1cd3577ddebfeb74f4717a84c4 ("block: pass a block_device and opf to bio_alloc")
163 +dnl #   bio_alloc(gfp_t gfp_mask, unsigned short nr_iovecs)
164 +dnl # became
165 +dnl #   bio_alloc(struct block_device *bdev, unsigned short nr_vecs, unsigned int opf, gfp_t gfp_mask)
166 +dnl # however
167 +dnl # > NULL/0 can be passed, both for the
168 +dnl # > passthrough case on a raw request_queue and to temporarily avoid
169 +dnl # > refactoring some nasty code.
170 +dnl #
171 +AC_DEFUN([ZFS_AC_KERNEL_SRC_BIO_ALLOC_4ARG], [
172 +       ZFS_LINUX_TEST_SRC([bio_alloc_4arg], [
173 +               #include <linux/bio.h>
174 +       ],[
175 +               gfp_t gfp_mask = 0;
176 +               unsigned short nr_iovecs = 0;
177 +               struct block_device *bdev = NULL;
178 +               unsigned int opf = 0;
179 +
180 +               struct bio *__attribute__((unused)) allocated = bio_alloc(bdev, nr_iovecs, opf, gfp_mask);
181 +       ])
182 +])
183 +
184 +AC_DEFUN([ZFS_AC_KERNEL_BIO_ALLOC_4ARG], [
185 +       AC_MSG_CHECKING([for 4-argument bio_alloc()])
186 +       ZFS_LINUX_TEST_RESULT([bio_alloc_4arg],[
187 +               AC_MSG_RESULT(yes)
188 +               AC_DEFINE([HAVE_BIO_ALLOC_4ARG], 1, [bio_alloc() takes 4 arguments])
189 +       ],[
190 +               AC_MSG_RESULT(no)
191 +       ])
192 +])
193 +
194  AC_DEFUN([ZFS_AC_KERNEL_SRC_BIO], [
195         ZFS_AC_KERNEL_SRC_REQ
196         ZFS_AC_KERNEL_SRC_BIO_OPS
197 @@ -488,6 +523,7 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BIO], [
198         ZFS_AC_KERNEL_SRC_BDEV_SUBMIT_BIO_RETURNS_VOID
199         ZFS_AC_KERNEL_SRC_BIO_SET_DEV_MACRO
200         ZFS_AC_KERNEL_SRC_BLK_CGROUP_HEADER
201 +       ZFS_AC_KERNEL_SRC_BIO_ALLOC_4ARG
202  ])
203  
204  AC_DEFUN([ZFS_AC_KERNEL_BIO], [
205 @@ -512,4 +548,5 @@ AC_DEFUN([ZFS_AC_KERNEL_BIO], [
206         ZFS_AC_KERNEL_BIO_BDEV_DISK
207         ZFS_AC_KERNEL_BDEV_SUBMIT_BIO_RETURNS_VOID
208         ZFS_AC_KERNEL_BLK_CGROUP_HEADER
209 +       ZFS_AC_KERNEL_BIO_ALLOC_4ARG
210  ])
211 diff --git a/config/kernel-blk-queue.m4 b/config/kernel-blk-queue.m4
212 index ff5d2d370..091952f57 100644
213 --- a/config/kernel-blk-queue.m4
214 +++ b/config/kernel-blk-queue.m4
215 @@ -93,8 +93,10 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLK_QUEUE_DISCARD], [
216         ZFS_LINUX_TEST_SRC([blk_queue_discard], [
217                 #include <linux/blkdev.h>
218         ],[
219 -               struct request_queue *q __attribute__ ((unused)) = NULL;
220 +               struct request_queue r;
221 +               struct request_queue *q = &r;
222                 int value __attribute__ ((unused));
223 +               memset(q, 0, sizeof(r));
224                 value = blk_queue_discard(q);
225         ])
226  ])
227 @@ -119,16 +121,20 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_BLK_QUEUE_SECURE_ERASE], [
228         ZFS_LINUX_TEST_SRC([blk_queue_secure_erase], [
229                 #include <linux/blkdev.h>
230         ],[
231 -               struct request_queue *q __attribute__ ((unused)) = NULL;
232 +               struct request_queue r;
233 +               struct request_queue *q = &r;
234                 int value __attribute__ ((unused));
235 +               memset(q, 0, sizeof(r));
236                 value = blk_queue_secure_erase(q);
237         ])
238  
239         ZFS_LINUX_TEST_SRC([blk_queue_secdiscard], [
240                 #include <linux/blkdev.h>
241         ],[
242 -               struct request_queue *q __attribute__ ((unused)) = NULL;
243 +               struct request_queue r;
244 +               struct request_queue *q = &r;
245                 int value __attribute__ ((unused));
246 +               memset(q, 0, sizeof(r));
247                 value = blk_queue_secdiscard(q);
248         ])
249  ])
250 diff --git a/config/kernel-config-defined.m4 b/config/kernel-config-defined.m4
251 index c7d18b49b..54837d728 100644
252 --- a/config/kernel-config-defined.m4
253 +++ b/config/kernel-config-defined.m4
254 @@ -19,19 +19,48 @@ AC_DEFUN([ZFS_AC_KERNEL_CONFIG_DEFINED], [
255                 ])
256         ])
257  
258 +       ZFS_AC_KERNEL_SRC_CONFIG_MODULES
259 +       ZFS_AC_KERNEL_SRC_CONFIG_BLOCK
260         ZFS_AC_KERNEL_SRC_CONFIG_DEBUG_LOCK_ALLOC
261         ZFS_AC_KERNEL_SRC_CONFIG_TRIM_UNUSED_KSYMS
262 -       ZFS_AC_KERNEL_SRC_CONFIG_ZLIB_INFLATE
263         ZFS_AC_KERNEL_SRC_CONFIG_ZLIB_DEFLATE
264 +       ZFS_AC_KERNEL_SRC_CONFIG_ZLIB_INFLATE
265  
266         AC_MSG_CHECKING([for kernel config option compatibility])
267         ZFS_LINUX_TEST_COMPILE_ALL([config])
268         AC_MSG_RESULT([done])
269  
270 +       ZFS_AC_KERNEL_CONFIG_MODULES
271 +       ZFS_AC_KERNEL_CONFIG_BLOCK
272         ZFS_AC_KERNEL_CONFIG_DEBUG_LOCK_ALLOC
273         ZFS_AC_KERNEL_CONFIG_TRIM_UNUSED_KSYMS
274 -       ZFS_AC_KERNEL_CONFIG_ZLIB_INFLATE
275         ZFS_AC_KERNEL_CONFIG_ZLIB_DEFLATE
276 +       ZFS_AC_KERNEL_CONFIG_ZLIB_INFLATE
277 +])
278 +
279 +dnl #
280 +dnl # Check CONFIG_BLOCK
281 +dnl #
282 +dnl # Verify the kernel has CONFIG_BLOCK support enabled.
283 +dnl #
284 +AC_DEFUN([ZFS_AC_KERNEL_SRC_CONFIG_BLOCK], [
285 +       ZFS_LINUX_TEST_SRC([config_block], [
286 +               #if !defined(CONFIG_BLOCK)
287 +               #error CONFIG_BLOCK not defined
288 +               #endif
289 +       ],[])
290 +])
291 +
292 +AC_DEFUN([ZFS_AC_KERNEL_CONFIG_BLOCK], [
293 +       AC_MSG_CHECKING([whether CONFIG_BLOCK is defined])
294 +       ZFS_LINUX_TEST_RESULT([config_block], [
295 +               AC_MSG_RESULT([yes])
296 +       ],[
297 +               AC_MSG_RESULT([no])
298 +               AC_MSG_ERROR([
299 +       *** This kernel does not include the required block device support.
300 +       *** Rebuild the kernel with CONFIG_BLOCK=y set.])
301 +       ])
302  ])
303  
304  dnl #
305 @@ -72,6 +101,61 @@ AC_DEFUN([ZFS_AC_KERNEL_CONFIG_DEBUG_LOCK_ALLOC], [
306         ])
307  ])
308  
309 +dnl #
310 +dnl # Check CONFIG_MODULES
311 +dnl #
312 +dnl # Verify the kernel has CONFIG_MODULES support enabled.
313 +dnl #
314 +AC_DEFUN([ZFS_AC_KERNEL_SRC_CONFIG_MODULES], [
315 +       ZFS_LINUX_TEST_SRC([config_modules], [
316 +               #if !defined(CONFIG_MODULES)
317 +               #error CONFIG_MODULES not defined
318 +               #endif
319 +       ],[])
320 +])
321 +
322 +AC_DEFUN([ZFS_AC_KERNEL_CONFIG_MODULES], [
323 +       AC_MSG_CHECKING([whether CONFIG_MODULES is defined])
324 +       AS_IF([test "x$enable_linux_builtin" != xyes], [
325 +               ZFS_LINUX_TEST_RESULT([config_modules], [
326 +                       AC_MSG_RESULT([yes])
327 +               ],[
328 +                       AC_MSG_RESULT([no])
329 +                       AC_MSG_ERROR([
330 +               *** This kernel does not include the required loadable module
331 +               *** support!
332 +               ***
333 +               *** To build OpenZFS as a loadable Linux kernel module
334 +               *** enable loadable module support by setting
335 +               *** `CONFIG_MODULES=y` in the kernel configuration and run
336 +               *** `make modules_prepare` in the Linux source tree.
337 +               ***
338 +               *** If you don't intend to enable loadable kernel module
339 +               *** support, please compile OpenZFS as a Linux kernel built-in.
340 +               ***
341 +               *** Prepare the Linux source tree by running `make prepare`,
342 +               *** use the OpenZFS `--enable-linux-builtin` configure option,
343 +               *** copy the OpenZFS sources into the Linux source tree using
344 +               *** `./copy-builtin <linux source directory>`,
345 +               *** set `CONFIG_ZFS=y` in the kernel configuration and compile
346 +               *** kernel as usual.
347 +                       ])
348 +               ])
349 +       ], [
350 +               ZFS_LINUX_TRY_COMPILE([], [], [
351 +                       AC_MSG_RESULT([not needed])
352 +               ],[
353 +                       AC_MSG_RESULT([error])
354 +                       AC_MSG_ERROR([
355 +               *** This kernel is unable to compile object files.
356 +               ***
357 +               *** Please make sure you prepared the Linux source tree
358 +               *** by running `make prepare` there.
359 +                       ])
360 +               ])
361 +       ])
362 +])
363 +
364  dnl #
365  dnl # Check CONFIG_TRIM_UNUSED_KSYMS
366  dnl #
367 diff --git a/config/kernel-copy-from-user-inatomic.m4 b/config/kernel-copy-from-user-inatomic.m4
368 new file mode 100644
369 index 000000000..fec354b2f
370 --- /dev/null
371 +++ b/config/kernel-copy-from-user-inatomic.m4
372 @@ -0,0 +1,29 @@
373 +dnl #
374 +dnl # On certain architectures `__copy_from_user_inatomic`
375 +dnl # is a GPL exported variable and cannot be used by OpenZFS.
376 +dnl #
377 +
378 +dnl #
379 +dnl # Checking if `__copy_from_user_inatomic` is available.
380 +dnl #
381 +AC_DEFUN([ZFS_AC_KERNEL_SRC___COPY_FROM_USER_INATOMIC], [
382 +       ZFS_LINUX_TEST_SRC([__copy_from_user_inatomic], [
383 +               #include <linux/uaccess.h>
384 +       ], [
385 +               int result __attribute__ ((unused)) = __copy_from_user_inatomic(NULL, NULL, 0);
386 +       ], [], [ZFS_META_LICENSE])
387 +])
388 +
389 +AC_DEFUN([ZFS_AC_KERNEL___COPY_FROM_USER_INATOMIC], [
390 +       AC_MSG_CHECKING([whether __copy_from_user_inatomic is available])
391 +       ZFS_LINUX_TEST_RESULT([__copy_from_user_inatomic_license], [
392 +               AC_MSG_RESULT(yes)
393 +       ], [
394 +               AC_MSG_RESULT(no)
395 +               AC_MSG_ERROR([
396 +       *** The `__copy_from_user_inatomic()` Linux kernel function is
397 +       *** incompatible with the CDDL license and will prevent the module
398 +       *** linking stage from succeeding.  OpenZFS cannot be compiled.
399 +               ])
400 +       ])
401 +])
402 diff --git a/config/kernel-genhd-flags.m4 b/config/kernel-genhd-flags.m4
403 new file mode 100644
404 index 000000000..af6a8a086
405 --- /dev/null
406 +++ b/config/kernel-genhd-flags.m4
407 @@ -0,0 +1,58 @@
408 +dnl #
409 +dnl # 5.17 API change,
410 +dnl #
411 +dnl # GENHD_FL_EXT_DEVT flag removed
412 +dnl # GENHD_FL_NO_PART_SCAN renamed GENHD_FL_NO_PART
413 +dnl #
414 +AC_DEFUN([ZFS_AC_KERNEL_SRC_GENHD_FLAGS], [
415 +
416 +       ZFS_LINUX_TEST_SRC([genhd_fl_ext_devt], [
417 +               #include <linux/blkdev.h>
418 +       ], [
419 +               int flags __attribute__ ((unused)) = GENHD_FL_EXT_DEVT;
420 +       ])
421 +
422 +       ZFS_LINUX_TEST_SRC([genhd_fl_no_part], [
423 +               #include <linux/blkdev.h>
424 +       ], [
425 +               int flags __attribute__ ((unused)) = GENHD_FL_NO_PART;
426 +       ])
427 +
428 +       ZFS_LINUX_TEST_SRC([genhd_fl_no_part_scan], [
429 +               #include <linux/blkdev.h>
430 +       ], [
431 +               int flags __attribute__ ((unused)) = GENHD_FL_NO_PART_SCAN;
432 +       ])
433 +])
434 +
435 +AC_DEFUN([ZFS_AC_KERNEL_GENHD_FLAGS], [
436 +
437 +       AC_MSG_CHECKING([whether GENHD_FL_EXT_DEVT flag is available])
438 +       ZFS_LINUX_TEST_RESULT([genhd_fl_ext_devt], [
439 +               AC_MSG_RESULT(yes)
440 +               AC_DEFINE(ZFS_GENHD_FL_EXT_DEVT, GENHD_FL_EXT_DEVT,
441 +                   [GENHD_FL_EXT_DEVT flag is available])
442 +       ], [
443 +               AC_MSG_RESULT(no)
444 +               AC_DEFINE(ZFS_GENHD_FL_EXT_DEVT, 0,
445 +                   [GENHD_FL_EXT_DEVT flag is not available])
446 +       ])
447 +
448 +       AC_MSG_CHECKING([whether GENHD_FL_NO_PART flag is available])
449 +       ZFS_LINUX_TEST_RESULT([genhd_fl_no_part], [
450 +               AC_MSG_RESULT(yes)
451 +               AC_DEFINE(ZFS_GENHD_FL_NO_PART, GENHD_FL_NO_PART,
452 +                   [GENHD_FL_NO_PART flag is available])
453 +       ], [
454 +               AC_MSG_RESULT(no)
455 +
456 +               AC_MSG_CHECKING([whether GENHD_FL_NO_PART_SCAN flag is available])
457 +               ZFS_LINUX_TEST_RESULT([genhd_fl_no_part_scan], [
458 +                       AC_MSG_RESULT(yes)
459 +                       AC_DEFINE(ZFS_GENHD_FL_NO_PART, GENHD_FL_NO_PART_SCAN,
460 +                           [GENHD_FL_NO_PART_SCAN flag is available])
461 +               ], [
462 +                       ZFS_LINUX_TEST_ERROR([GENHD_FL_NO_PART|GENHD_FL_NO_PART_SCAN])
463 +               ])
464 +       ])
465 +])
466 diff --git a/config/kernel-group-info.m4 b/config/kernel-group-info.m4
467 index 0fee1d36d..6941d62da 100644
468 --- a/config/kernel-group-info.m4
469 +++ b/config/kernel-group-info.m4
470 @@ -6,8 +6,8 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_GROUP_INFO_GID], [
471         ZFS_LINUX_TEST_SRC([group_info_gid], [
472                 #include <linux/cred.h>
473         ],[
474 -               struct group_info *gi = groups_alloc(1);
475 -               gi->gid[0] = KGIDT_INIT(0);
476 +               struct group_info gi __attribute__ ((unused)) = {};
477 +               gi.gid[0] = KGIDT_INIT(0);
478         ])
479  ])
480  
481 diff --git a/config/kernel-mkdir.m4 b/config/kernel-mkdir.m4
482 index a162bcd88..6667ed04f 100644
483 --- a/config/kernel-mkdir.m4
484 +++ b/config/kernel-mkdir.m4
485 @@ -53,6 +53,8 @@ AC_DEFUN([ZFS_AC_KERNEL_MKDIR], [
486                 AC_DEFINE(HAVE_IOPS_MKDIR_USERNS, 1,
487                     [iops->mkdir() takes struct user_namespace*])
488         ],[
489 +               AC_MSG_RESULT(no)
490 +
491                 AC_MSG_CHECKING([whether iops->mkdir() takes umode_t])
492                 ZFS_LINUX_TEST_RESULT([inode_operations_mkdir], [
493                         AC_MSG_RESULT(yes)
494 diff --git a/config/kernel-readpages.m4 b/config/kernel-readpages.m4
495 new file mode 100644
496 index 000000000..0bf67ffd9
497 --- /dev/null
498 +++ b/config/kernel-readpages.m4
499 @@ -0,0 +1,25 @@
500 +dnl #
501 +dnl # Linux 5.18 removes address_space_operations ->readpages in favour of
502 +dnl # ->readahead
503 +dnl #
504 +AC_DEFUN([ZFS_AC_KERNEL_SRC_VFS_READPAGES], [
505 +       ZFS_LINUX_TEST_SRC([vfs_has_readpages], [
506 +               #include <linux/fs.h>
507 +
508 +               static const struct address_space_operations
509 +                   aops __attribute__ ((unused)) = {
510 +                       .readpages = NULL,
511 +               };
512 +       ],[])
513 +])
514 +
515 +AC_DEFUN([ZFS_AC_KERNEL_VFS_READPAGES], [
516 +       AC_MSG_CHECKING([address_space_operations->readpages exists])
517 +       ZFS_LINUX_TEST_RESULT([vfs_has_readpages], [
518 +               AC_MSG_RESULT([yes])
519 +               AC_DEFINE(HAVE_VFS_READPAGES, 1,
520 +                       [address_space_operations->readpages exists])
521 +       ],[
522 +               AC_MSG_RESULT([no])
523 +       ])
524 +])
525 diff --git a/config/kernel-revalidate-disk-size.m4 b/config/kernel-revalidate-disk-size.m4
526 index a7d0cb3cd..13cb92a17 100644
527 --- a/config/kernel-revalidate-disk-size.m4
528 +++ b/config/kernel-revalidate-disk-size.m4
529 @@ -8,14 +8,14 @@ dnl #
530  AC_DEFUN([ZFS_AC_KERNEL_SRC_REVALIDATE_DISK], [
531  
532         ZFS_LINUX_TEST_SRC([revalidate_disk_size], [
533 -               #include <linux/genhd.h>
534 +               #include <linux/blkdev.h>
535         ], [
536                 struct gendisk *disk = NULL;
537                 (void) revalidate_disk_size(disk, false);
538         ])
539  
540         ZFS_LINUX_TEST_SRC([revalidate_disk], [
541 -               #include <linux/genhd.h>
542 +               #include <linux/blkdev.h>
543         ], [
544                 struct gendisk *disk = NULL;
545                 (void) revalidate_disk(disk);
546 diff --git a/config/kernel-sysfs.m4 b/config/kernel-sysfs.m4
547 new file mode 100644
548 index 000000000..668def5fe
549 --- /dev/null
550 +++ b/config/kernel-sysfs.m4
551 @@ -0,0 +1,37 @@
552 +dnl #
553 +dnl # Linux 5.2/5.18 API
554 +dnl #
555 +dnl # In cdb4f26a63c391317e335e6e683a614358e70aeb ("kobject: kobj_type: remove default_attrs")
556 +dnl #  struct kobj_type.default_attrs
557 +dnl # was finally removed in favour of
558 +dnl #  struct kobj_type.default_groups
559 +dnl #
560 +dnl # This was added in aa30f47cf666111f6bbfd15f290a27e8a7b9d854 ("kobject: Add support for default attribute groups to kobj_type"),
561 +dnl # if both are present (5.2-5.17), we prefer default_groups; they're otherwise equivalent
562 +dnl #
563 +AC_DEFUN([ZFS_AC_KERNEL_SRC_SYSFS_DEFAULT_GROUPS], [
564 +       ZFS_LINUX_TEST_SRC([sysfs_default_groups], [
565 +               #include <linux/kobject.h>
566 +       ],[
567 +               struct kobj_type __attribute__ ((unused)) kt = {
568 +                       .default_groups = (const struct attribute_group **)NULL };
569 +       ])
570 +])
571 +
572 +AC_DEFUN([ZFS_AC_KERNEL_SYSFS_DEFAULT_GROUPS], [
573 +       AC_MSG_CHECKING([for struct kobj_type.default_groups])
574 +       ZFS_LINUX_TEST_RESULT([sysfs_default_groups],[
575 +               AC_MSG_RESULT(yes)
576 +               AC_DEFINE([HAVE_SYSFS_DEFAULT_GROUPS], 1, [struct kobj_type has default_groups])
577 +       ],[
578 +               AC_MSG_RESULT(no)
579 +       ])
580 +])
581 +
582 +AC_DEFUN([ZFS_AC_KERNEL_SRC_SYSFS], [
583 +       ZFS_AC_KERNEL_SRC_SYSFS_DEFAULT_GROUPS
584 +])
585 +
586 +AC_DEFUN([ZFS_AC_KERNEL_SYSFS], [
587 +       ZFS_AC_KERNEL_SYSFS_DEFAULT_GROUPS
588 +])
589 diff --git a/config/kernel-vfs-filemap_dirty_folio.m4 b/config/kernel-vfs-filemap_dirty_folio.m4
590 new file mode 100644
591 index 000000000..872879002
592 --- /dev/null
593 +++ b/config/kernel-vfs-filemap_dirty_folio.m4
594 @@ -0,0 +1,30 @@
595 +dnl #
596 +dnl # Linux 5.18 uses filemap_dirty_folio in lieu of
597 +dnl # ___set_page_dirty_nobuffers
598 +dnl #
599 +AC_DEFUN([ZFS_AC_KERNEL_SRC_VFS_FILEMAP_DIRTY_FOLIO], [
600 +       ZFS_LINUX_TEST_SRC([vfs_has_filemap_dirty_folio], [
601 +               #include <linux/pagemap.h>
602 +               #include <linux/writeback.h>
603 +
604 +               static const struct address_space_operations
605 +                   aops __attribute__ ((unused)) = {
606 +                       .dirty_folio    = filemap_dirty_folio,
607 +               };
608 +       ],[])
609 +])
610 +
611 +AC_DEFUN([ZFS_AC_KERNEL_VFS_FILEMAP_DIRTY_FOLIO], [
612 +       dnl #
613 +       dnl # Linux 5.18 uses filemap_dirty_folio in lieu of
614 +       dnl # ___set_page_dirty_nobuffers
615 +       dnl #
616 +       AC_MSG_CHECKING([filemap_dirty_folio exists])
617 +       ZFS_LINUX_TEST_RESULT([vfs_has_filemap_dirty_folio], [
618 +               AC_MSG_RESULT([yes])
619 +               AC_DEFINE(HAVE_VFS_FILEMAP_DIRTY_FOLIO, 1,
620 +                       [filemap_dirty_folio exists])
621 +       ],[
622 +               AC_MSG_RESULT([no])
623 +       ])
624 +])
625 diff --git a/config/kernel-zero_page.m4 b/config/kernel-zero_page.m4
626 new file mode 100644
627 index 000000000..1461781ac
628 --- /dev/null
629 +++ b/config/kernel-zero_page.m4
630 @@ -0,0 +1,27 @@
631 +dnl #
632 +dnl # ZERO_PAGE() is an alias for emtpy_zero_page. On certain architectures
633 +dnl # this is a GPL exported variable.
634 +dnl #
635 +
636 +dnl #
637 +dnl # Checking if ZERO_PAGE is exported GPL-only
638 +dnl #
639 +AC_DEFUN([ZFS_AC_KERNEL_SRC_ZERO_PAGE], [
640 +       ZFS_LINUX_TEST_SRC([zero_page], [
641 +               #include <asm/pgtable.h>
642 +       ], [
643 +               struct page *p __attribute__ ((unused));
644 +               p = ZERO_PAGE(0);
645 +       ], [], [ZFS_META_LICENSE])
646 +])
647 +
648 +AC_DEFUN([ZFS_AC_KERNEL_ZERO_PAGE], [
649 +       AC_MSG_CHECKING([whether ZERO_PAGE() is GPL-only])
650 +       ZFS_LINUX_TEST_RESULT([zero_page_license], [
651 +               AC_MSG_RESULT(no)
652 +       ], [
653 +               AC_MSG_RESULT(yes)
654 +               AC_DEFINE(HAVE_ZERO_PAGE_GPL_ONLY, 1,
655 +                   [ZERO_PAGE() is GPL-only])
656 +       ])
657 +])
658 diff --git a/config/kernel.m4 b/config/kernel.m4
659 index 3122e9dba..25df16a90 100644
660 --- a/config/kernel.m4
661 +++ b/config/kernel.m4
662 @@ -8,8 +8,8 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [
663                 ZFS_AC_QAT
664  
665                 dnl # Sanity checks for module building and CONFIG_* defines
666 -               ZFS_AC_KERNEL_TEST_MODULE
667                 ZFS_AC_KERNEL_CONFIG_DEFINED
668 +               ZFS_AC_MODULE_SYMVERS
669  
670                 dnl # Sequential ZFS_LINUX_TRY_COMPILE tests
671                 ZFS_AC_KERNEL_FPU_HEADER
672 @@ -61,6 +61,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
673         ZFS_AC_KERNEL_SRC_BIO
674         ZFS_AC_KERNEL_SRC_BLKDEV
675         ZFS_AC_KERNEL_SRC_BLK_QUEUE
676 +       ZFS_AC_KERNEL_SRC_GENHD_FLAGS
677         ZFS_AC_KERNEL_SRC_REVALIDATE_DISK
678         ZFS_AC_KERNEL_SRC_GET_DISK_RO
679         ZFS_AC_KERNEL_SRC_GENERIC_READLINK_GLOBAL
680 @@ -99,6 +100,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
681         ZFS_AC_KERNEL_SRC_SET_NLINK
682         ZFS_AC_KERNEL_SRC_SGET
683         ZFS_AC_KERNEL_SRC_LSEEK_EXECUTE
684 +       ZFS_AC_KERNEL_SRC_VFS_FILEMAP_DIRTY_FOLIO
685         ZFS_AC_KERNEL_SRC_VFS_GETATTR
686         ZFS_AC_KERNEL_SRC_VFS_FSYNC_2ARGS
687         ZFS_AC_KERNEL_SRC_VFS_ITERATE
688 @@ -131,12 +133,16 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
689         ZFS_AC_KERNEL_SRC_BIO_MAX_SEGS
690         ZFS_AC_KERNEL_SRC_SIGNAL_STOP
691         ZFS_AC_KERNEL_SRC_SIGINFO
692 +       ZFS_AC_KERNEL_SRC_SYSFS
693         ZFS_AC_KERNEL_SRC_SET_SPECIAL_STATE
694 +       ZFS_AC_KERNEL_SRC_VFS_READPAGES
695         ZFS_AC_KERNEL_SRC_VFS_SET_PAGE_DIRTY_NOBUFFERS
696         ZFS_AC_KERNEL_SRC_STANDALONE_LINUX_STDARG
697         ZFS_AC_KERNEL_SRC_PAGEMAP_FOLIO_WAIT_BIT
698         ZFS_AC_KERNEL_SRC_ADD_DISK
699         ZFS_AC_KERNEL_SRC_KTHREAD
700 +       ZFS_AC_KERNEL_SRC_ZERO_PAGE
701 +       ZFS_AC_KERNEL_SRC___COPY_FROM_USER_INATOMIC
702  
703         AC_MSG_CHECKING([for available kernel interfaces])
704         ZFS_LINUX_TEST_COMPILE_ALL([kabi])
705 @@ -171,6 +177,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
706         ZFS_AC_KERNEL_BIO
707         ZFS_AC_KERNEL_BLKDEV
708         ZFS_AC_KERNEL_BLK_QUEUE
709 +       ZFS_AC_KERNEL_GENHD_FLAGS
710         ZFS_AC_KERNEL_REVALIDATE_DISK
711         ZFS_AC_KERNEL_GET_DISK_RO
712         ZFS_AC_KERNEL_GENERIC_READLINK_GLOBAL
713 @@ -209,6 +216,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
714         ZFS_AC_KERNEL_SET_NLINK
715         ZFS_AC_KERNEL_SGET
716         ZFS_AC_KERNEL_LSEEK_EXECUTE
717 +       ZFS_AC_KERNEL_VFS_FILEMAP_DIRTY_FOLIO
718         ZFS_AC_KERNEL_VFS_GETATTR
719         ZFS_AC_KERNEL_VFS_FSYNC_2ARGS
720         ZFS_AC_KERNEL_VFS_ITERATE
721 @@ -241,12 +249,16 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
722         ZFS_AC_KERNEL_BIO_MAX_SEGS
723         ZFS_AC_KERNEL_SIGNAL_STOP
724         ZFS_AC_KERNEL_SIGINFO
725 +       ZFS_AC_KERNEL_SYSFS
726         ZFS_AC_KERNEL_SET_SPECIAL_STATE
727 +       ZFS_AC_KERNEL_VFS_READPAGES
728         ZFS_AC_KERNEL_VFS_SET_PAGE_DIRTY_NOBUFFERS
729         ZFS_AC_KERNEL_STANDALONE_LINUX_STDARG
730         ZFS_AC_KERNEL_PAGEMAP_FOLIO_WAIT_BIT
731         ZFS_AC_KERNEL_ADD_DISK
732         ZFS_AC_KERNEL_KTHREAD
733 +       ZFS_AC_KERNEL_ZERO_PAGE
734 +       ZFS_AC_KERNEL___COPY_FROM_USER_INATOMIC
735  ])
736  
737  dnl #
738 @@ -435,8 +447,6 @@ AC_DEFUN([ZFS_AC_KERNEL], [
739         AC_SUBST(LINUX)
740         AC_SUBST(LINUX_OBJ)
741         AC_SUBST(LINUX_VERSION)
742 -
743 -       ZFS_AC_MODULE_SYMVERS
744  ])
745  
746  dnl #
747 @@ -531,27 +541,6 @@ AC_DEFUN([ZFS_AC_QAT], [
748         ])
749  ])
750  
751 -dnl #
752 -dnl # Basic toolchain sanity check.
753 -dnl #
754 -AC_DEFUN([ZFS_AC_KERNEL_TEST_MODULE], [
755 -       AC_MSG_CHECKING([whether modules can be built])
756 -       ZFS_LINUX_TRY_COMPILE([], [], [
757 -               AC_MSG_RESULT([yes])
758 -       ],[
759 -               AC_MSG_RESULT([no])
760 -               if test "x$enable_linux_builtin" != xyes; then
761 -                       AC_MSG_ERROR([
762 -       *** Unable to build an empty module.
763 -                       ])
764 -               else
765 -                       AC_MSG_ERROR([
766 -       *** Unable to build an empty module.
767 -       *** Please run 'make scripts' inside the kernel source tree.])
768 -               fi
769 -       ])
770 -])
771 -
772  dnl #
773  dnl # ZFS_LINUX_CONFTEST_H
774  dnl #
775 @@ -654,8 +643,10 @@ AC_DEFUN([ZFS_LINUX_COMPILE], [
776                 build kernel modules with LLVM/CLANG toolchain])
777         AC_TRY_COMMAND([
778             KBUILD_MODPOST_NOFINAL="$5" KBUILD_MODPOST_WARN="$6"
779 -           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
780 -           M=$PWD/$1 >$1/build.log 2>&1])
781 +           make modules -k -j$TEST_JOBS ${KERNEL_CC:+CC=$KERNEL_CC}
782 +           ${KERNEL_LD:+LD=$KERNEL_LD} ${KERNEL_LLVM:+LLVM=$KERNEL_LLVM}
783 +           CONFIG_MODULES=y CFLAGS_MODULE=-DCONFIG_MODULES
784 +           -C $LINUX_OBJ $ARCH_UM M=$PWD/$1 >$1/build.log 2>&1])
785         AS_IF([AC_TRY_COMMAND([$2])], [$3], [$4])
786  ])
787  
788 diff --git a/contrib/dracut/90zfs/export-zfs.sh.in b/contrib/dracut/90zfs/export-zfs.sh.in
789 index 892650383..9e05ee03a 100755
790 --- a/contrib/dracut/90zfs/export-zfs.sh.in
791 +++ b/contrib/dracut/90zfs/export-zfs.sh.in
792 @@ -1,14 +1,12 @@
793  #!/bin/sh
794  
795 -. /lib/dracut-zfs-lib.sh
796 -
797  _do_zpool_export() {
798         ret=0
799         errs=""
800         final="${1}"
801  
802         info "ZFS: Exporting ZFS storage pools..."
803 -       errs=$(export_all -F 2>&1)
804 +       errs=$(zpool export -aF 2>&1)
805         ret=$?
806         [ -z "${errs}" ] || echo "${errs}" | vwarn
807         if [ "x${ret}" != "x0" ]; then
808 diff --git a/contrib/dracut/90zfs/module-setup.sh.in b/contrib/dracut/90zfs/module-setup.sh.in
809 index fbf32b658..7c01f125e 100755
810 --- a/contrib/dracut/90zfs/module-setup.sh.in
811 +++ b/contrib/dracut/90zfs/module-setup.sh.in
812 @@ -6,8 +6,8 @@ check() {
813         [ "${1}" = "-d" ] && return 0
814  
815         # Verify the zfs tool chain
816 -       for tool in "@sbindir@/zgenhostid" "@sbindir@/zpool" "@sbindir@/zfs" "@mounthelperdir@/mount.zfs" ; do
817 -               test -x "$tool" || return 1
818 +       for tool in "zgenhostid" "zpool" "zfs" "mount.zfs"; do
819 +               command -v "${tool}" >/dev/null || return 1
820         done
821  
822         return 0
823 @@ -19,125 +19,86 @@ depends() {
824  }
825  
826  installkernel() {
827 -       instmods zfs
828 -       instmods zcommon
829 -       instmods znvpair
830 -       instmods zavl
831 -       instmods zunicode
832 -       instmods zlua
833 -       instmods icp
834 -       instmods spl
835 -       instmods zlib_deflate
836 -       instmods zlib_inflate
837 +       instmods -c zfs
838  }
839  
840  install() {
841 -       inst_rules @udevruledir@/90-zfs.rules
842 -       inst_rules @udevruledir@/69-vdev.rules
843 -       inst_rules @udevruledir@/60-zvol.rules
844 -       dracut_install hostid
845 -       dracut_install grep
846 -       dracut_install @sbindir@/zgenhostid
847 -       dracut_install @sbindir@/zfs
848 -       dracut_install @sbindir@/zpool
849 -       # Workaround for https://github.com/openzfs/zfs/issues/4749 by
850 -       # ensuring libgcc_s.so(.1) is included
851 -       if ldd @sbindir@/zpool | grep -qF 'libgcc_s.so'; then
852 -               # Dracut will have already tracked and included it
853 -               :;
854 -       elif command -v gcc-config >/dev/null 2>&1; then
855 -               # On systems with gcc-config (Gentoo, Funtoo, etc.):
856 -               # Use the current profile to resolve the appropriate path
857 -               s="$(gcc-config -c)"
858 -               dracut_install "/usr/lib/gcc/${s%-*}/${s##*-}/libgcc_s.so"*
859 -       elif [ "$(echo /usr/lib/libgcc_s.so*)" != "/usr/lib/libgcc_s.so*" ]; then
860 -               # Try a simple path first
861 -               dracut_install /usr/lib/libgcc_s.so*
862 -       elif [ "$(echo /lib*/libgcc_s.so*)" != "/lib*/libgcc_s.so*" ]; then
863 -               # SUSE
864 -               dracut_install /lib*/libgcc_s.so*
865 -       else
866 -               # Fallback: Guess the path and include all matches
867 -               dracut_install /usr/lib*/gcc/**/libgcc_s.so*
868 -       fi
869 -       # shellcheck disable=SC2050
870 -       if [ @LIBFETCH_DYNAMIC@ -gt 0 ]; then
871 -               for d in $libdirs; do
872 -                       [ -e "$d/@LIBFETCH_SONAME@" ] && dracut_install "$d/@LIBFETCH_SONAME@"
873 -               done
874 +       inst_rules 90-zfs.rules 69-vdev.rules 60-zvol.rules
875 +
876 +       inst_multiple \
877 +               zgenhostid \
878 +               zfs \
879 +               zpool \
880 +               mount.zfs \
881 +               hostid \
882 +               grep \
883 +               awk \
884 +               tr \
885 +               cut \
886 +               head ||
887 +               { dfatal "Failed to install essential binaries"; exit 1; }
888 +
889 +       # Adapted from https://github.com/zbm-dev/zfsbootmenu
890 +       if ! ldd "$(command -v zpool)" | grep -qF 'libgcc_s.so'; then
891 +               # On systems with gcc-config (Gentoo, Funtoo, etc.), use it to find libgcc_s
892 +               if command -v gcc-config >/dev/null; then
893 +                       inst_simple "/usr/lib/gcc/$(s=$(gcc-config -c); echo "${s%-*}/${s##*-}")/libgcc_s.so.1" ||
894 +                               { dfatal "Unable to install libgcc_s.so"; exit 1; }
895 +                       # Otherwise, use dracut's library installation function to find the right one
896 +               elif ! inst_libdir_file "libgcc_s.so*"; then
897 +                       # If all else fails, just try looking for some gcc arch directory
898 +                       inst_simple /usr/lib/gcc/*/*/libgcc_s.so* ||
899 +                               { dfatal "Unable to install libgcc_s.so"; exit 1; }
900 +               fi
901         fi
902 -       dracut_install @mounthelperdir@/mount.zfs
903 -       dracut_install @udevdir@/vdev_id
904 -       dracut_install awk
905 -       dracut_install cut
906 -       dracut_install tr
907 -       dracut_install head
908 -       dracut_install @udevdir@/zvol_id
909 +
910         inst_hook cmdline 95 "${moddir}/parse-zfs.sh"
911 -       if [ -n "$systemdutildir" ] ; then
912 -               inst_script "${moddir}/zfs-generator.sh" "$systemdutildir"/system-generators/dracut-zfs-generator
913 +       if [ -n "${systemdutildir}" ]; then
914 +               inst_script "${moddir}/zfs-generator.sh" "${systemdutildir}/system-generators/dracut-zfs-generator"
915         fi
916         inst_hook pre-mount 90 "${moddir}/zfs-load-key.sh"
917         inst_hook mount 98 "${moddir}/mount-zfs.sh"
918         inst_hook cleanup 99 "${moddir}/zfs-needshutdown.sh"
919         inst_hook shutdown 20 "${moddir}/export-zfs.sh"
920  
921 -       inst_simple "${moddir}/zfs-lib.sh" "/lib/dracut-zfs-lib.sh"
922 -       if [ -e @sysconfdir@/zfs/zpool.cache ]; then
923 -               inst @sysconfdir@/zfs/zpool.cache
924 -               type mark_hostonly >/dev/null 2>&1 && mark_hostonly @sysconfdir@/zfs/zpool.cache
925 -       fi
926 +       inst_script "${moddir}/zfs-lib.sh" "/lib/dracut-zfs-lib.sh"
927  
928 -       if [ -e @sysconfdir@/zfs/vdev_id.conf ]; then
929 -               inst @sysconfdir@/zfs/vdev_id.conf
930 -               type mark_hostonly >/dev/null 2>&1 && mark_hostonly @sysconfdir@/zfs/vdev_id.conf
931 -       fi
932 +       # -H ensures they are marked host-only
933 +       # -o ensures there is no error upon absence of these files
934 +       inst_multiple -o -H \
935 +               "@sysconfdir@/zfs/zpool.cache" \
936 +               "@sysconfdir@/zfs/vdev_id.conf"
937  
938         # Synchronize initramfs and system hostid
939 -       if [ -f @sysconfdir@/hostid ]; then
940 -               inst @sysconfdir@/hostid
941 -               type mark_hostonly >/dev/null 2>&1 && mark_hostonly @sysconfdir@/hostid
942 -       elif HOSTID="$(hostid 2>/dev/null)" && [ "${HOSTID}" != "00000000" ]; then
943 -               zgenhostid -o "${initdir}@sysconfdir@/hostid" "${HOSTID}"
944 -               type mark_hostonly >/dev/null 2>&1 && mark_hostonly @sysconfdir@/hostid
945 +       if ! inst_simple -H @sysconfdir@/hostid; then
946 +               if HOSTID="$(hostid 2>/dev/null)" && [ "${HOSTID}" != "00000000" ]; then
947 +                       zgenhostid -o "${initdir}@sysconfdir@/hostid" "${HOSTID}"
948 +                       mark_hostonly @sysconfdir@/hostid
949 +               fi
950         fi
951  
952         if dracut_module_included "systemd"; then
953 -               mkdir -p "${initdir}/$systemdsystemunitdir/zfs-import.target.wants"
954 -               for _service in "zfs-import-scan.service" "zfs-import-cache.service" ; do
955 -                       dracut_install "@systemdunitdir@/$_service"
956 -                       if ! [ -L "${initdir}/$systemdsystemunitdir/zfs-import.target.wants/$_service" ]; then
957 -                               ln -sf ../$_service "${initdir}/$systemdsystemunitdir/zfs-import.target.wants/$_service"
958 -                               type mark_hostonly >/dev/null 2>&1 && mark_hostonly "@systemdunitdir@/$_service"
959 -                       fi
960 -               done
961 +               inst_simple "${systemdsystemunitdir}/zfs-import.target"
962 +               systemctl -q --root "${initdir}" add-wants initrd.target zfs-import.target
963  
964 -               inst "${moddir}"/zfs-env-bootfs.service "${systemdsystemunitdir}"/zfs-env-bootfs.service
965 -               ln -s ../zfs-env-bootfs.service "${initdir}/${systemdsystemunitdir}/zfs-import.target.wants"/zfs-env-bootfs.service
966 -               type mark_hostonly >/dev/null 2>&1 && mark_hostonly @systemdunitdir@/zfs-env-bootfs.service
967 +               inst_simple "${moddir}/zfs-env-bootfs.service" "${systemdsystemunitdir}/zfs-env-bootfs.service"
968 +               systemctl -q --root "${initdir}" add-wants zfs-import.target zfs-env-bootfs.service
969  
970 -               dracut_install systemd-ask-password
971 -               dracut_install systemd-tty-ask-password-agent
972 -
973 -               mkdir -p "${initdir}/$systemdsystemunitdir/initrd.target.wants"
974 -               dracut_install @systemdunitdir@/zfs-import.target
975 -               if ! [ -L "${initdir}/$systemdsystemunitdir/initrd.target.wants"/zfs-import.target ]; then
976 -                       ln -s ../zfs-import.target "${initdir}/$systemdsystemunitdir/initrd.target.wants"/zfs-import.target
977 -                       type mark_hostonly >/dev/null 2>&1 && mark_hostonly @systemdunitdir@/zfs-import.target
978 -               fi
979 +               for _service in \
980 +                       "zfs-import-scan.service" \
981 +                       "zfs-import-cache.service" \
982 +                       "zfs-load-module.service"; do
983 +                       inst_simple "${systemdsystemunitdir}/${_service}"
984 +                       systemctl -q --root "${initdir}" add-wants zfs-import.target "${_service}"
985 +               done
986  
987 -               for _service in zfs-snapshot-bootfs.service zfs-rollback-bootfs.service ; do
988 -                       inst "${moddir}/$_service" "${systemdsystemunitdir}/$_service"
989 -                       if ! [ -L "${initdir}/$systemdsystemunitdir/initrd.target.wants/$_service" ]; then
990 -                               ln -s "../$_service" "${initdir}/$systemdsystemunitdir/initrd.target.wants/$_service"
991 -                       fi
992 +               for _service in \
993 +                       "zfs-snapshot-bootfs.service" \
994 +                       "zfs-rollback-bootfs.service"; do
995 +                       inst_simple "${moddir}/${_service}" "${systemdsystemunitdir}/${_service}"
996 +                       systemctl -q --root "${initdir}" add-wants initrd.target "${_service}"
997                 done
998  
999 -               # There isn't a pkg-config variable for this,
1000 -               # and dracut doesn't automatically resolve anything this'd be next to
1001 -               local systemdsystemenvironmentgeneratordir
1002 -               systemdsystemenvironmentgeneratordir="$(pkg-config --variable=prefix systemd || echo "/usr")/lib/systemd/system-environment-generators"
1003 -               mkdir -p "${initdir}/${systemdsystemenvironmentgeneratordir}"
1004 -               inst "${moddir}"/import-opts-generator.sh "${systemdsystemenvironmentgeneratordir}"/zfs-import-opts.sh
1005 +               inst_simple "${moddir}/import-opts-generator.sh" "${systemdutildir}/system-environment-generators/zfs-import-opts.sh"
1006         fi
1007  }
1008 diff --git a/contrib/dracut/90zfs/mount-zfs.sh.in b/contrib/dracut/90zfs/mount-zfs.sh.in
1009 index 68e3f0e0d..fa9f1bb76 100755
1010 --- a/contrib/dracut/90zfs/mount-zfs.sh.in
1011 +++ b/contrib/dracut/90zfs/mount-zfs.sh.in
1012 @@ -3,48 +3,73 @@
1013  
1014  . /lib/dracut-zfs-lib.sh
1015  
1016 -ZFS_DATASET=""
1017 -ZFS_POOL=""
1018 -
1019 -case "${root}" in
1020 -       zfs:*) ;;
1021 -       *) return ;;
1022 -esac
1023 +decode_root_args || return 0
1024  
1025  GENERATOR_FILE=/run/systemd/generator/sysroot.mount
1026  GENERATOR_EXTENSION=/run/systemd/generator/sysroot.mount.d/zfs-enhancement.conf
1027  
1028 -if [ -e "$GENERATOR_FILE" ] && [ -e "$GENERATOR_EXTENSION" ] ; then
1029 -       # If the ZFS sysroot.mount flag exists, the initial RAM disk configured
1030 -       # it to mount ZFS on root.  In that case, we bail early.  This flag
1031 -       # file gets created by the zfs-generator program upon successful run.
1032 -       info "ZFS: There is a sysroot.mount and zfs-generator has extended it."
1033 -       info "ZFS: Delegating root mount to sysroot.mount."
1034 -       # Let us tell the initrd to run on shutdown.
1035 -       # We have a shutdown hook to run
1036 -       # because we imported the pool.
1037 +if [ -e "$GENERATOR_FILE" ] && [ -e "$GENERATOR_EXTENSION" ]; then
1038 +       # We're under systemd and dracut-zfs-generator ran to completion.
1039 +       info "ZFS: Delegating root mount to sysroot.mount at al."
1040 +
1041         # We now prevent Dracut from running this thing again.
1042 -       for zfsmounthook in "$hookdir"/mount/*zfs* ; do
1043 -               if [ -f "$zfsmounthook" ] ; then
1044 -                       rm -f "$zfsmounthook"
1045 -               fi
1046 -       done
1047 +       rm -f "$hookdir"/mount/*zfs*
1048         return
1049  fi
1050 +
1051  info "ZFS: No sysroot.mount exists or zfs-generator did not extend it."
1052  info "ZFS: Mounting root with the traditional mount-zfs.sh instead."
1053  
1054 +# ask_for_password tries prompt cmd
1055 +#
1056 +# Wraps around plymouth ask-for-password and adds fallback to tty password ask
1057 +# if plymouth is not present.
1058 +ask_for_password() {
1059 +    tries="$1"
1060 +    prompt="$2"
1061 +    cmd="$3"
1062 +
1063 +    {
1064 +        flock -s 9
1065 +
1066 +        # Prompt for password with plymouth, if installed and running.
1067 +        if plymouth --ping 2>/dev/null; then
1068 +            plymouth ask-for-password \
1069 +                --prompt "$prompt" --number-of-tries="$tries" | \
1070 +                eval "$cmd"
1071 +            ret=$?
1072 +        else
1073 +            i=1
1074 +            while [ "$i" -le "$tries" ]; do
1075 +                printf "%s [%i/%i]:" "$prompt" "$i" "$tries" >&2
1076 +                eval "$cmd" && ret=0 && break
1077 +                ret=$?
1078 +                i=$((i+1))
1079 +                printf '\n' >&2
1080 +            done
1081 +            unset i
1082 +        fi
1083 +    } 9>/.console_lock
1084 +
1085 +    [ "$ret" -ne 0 ] && echo "Wrong password" >&2
1086 +    return "$ret"
1087 +}
1088 +
1089 +
1090  # Delay until all required block devices are present.
1091  modprobe zfs 2>/dev/null
1092  udevadm settle
1093  
1094 +ZFS_DATASET=
1095 +ZFS_POOL=
1096 +
1097  if [ "${root}" = "zfs:AUTO" ] ; then
1098 -       if ! ZFS_DATASET="$(find_bootfs)" ; then
1099 +       if ! ZFS_DATASET="$(zpool get -Ho value bootfs | grep -m1 -vFx -)"; then
1100                 # shellcheck disable=SC2086
1101                 zpool import -N -a ${ZPOOL_IMPORT_OPTS}
1102 -               if ! ZFS_DATASET="$(find_bootfs)" ; then
1103 +               if ! ZFS_DATASET="$(zpool get -Ho value bootfs | grep -m1 -vFx -)"; then
1104                         warn "ZFS: No bootfs attribute found in importable pools."
1105 -                       export_all -F
1106 +                       zpool export -aF
1107  
1108                         rootok=0
1109                         return 1
1110 @@ -53,34 +78,43 @@ if [ "${root}" = "zfs:AUTO" ] ; then
1111         info "ZFS: Using ${ZFS_DATASET} as root."
1112  fi
1113  
1114 -ZFS_DATASET="${ZFS_DATASET:-${root#zfs:}}"
1115 +ZFS_DATASET="${ZFS_DATASET:-${root}}"
1116  ZFS_POOL="${ZFS_DATASET%%/*}"
1117  
1118 -if import_pool "${ZFS_POOL}" ; then
1119 -       # Load keys if we can or if we need to
1120 -       if [ "$(zpool list -H -o feature@encryption "${ZFS_POOL}")" = 'active' ]; then
1121 -               # if the root dataset has encryption enabled
1122 -               ENCRYPTIONROOT="$(zfs get -H -o value encryptionroot "${ZFS_DATASET}")"
1123 -               if ! [ "${ENCRYPTIONROOT}" = "-" ]; then
1124 -                       KEYSTATUS="$(zfs get -H -o value keystatus "${ENCRYPTIONROOT}")"
1125 -                       # if the key needs to be loaded
1126 -                       if [ "$KEYSTATUS" = "unavailable" ]; then
1127 -                               # decrypt them
1128 -                               ask_for_password \
1129 -                                       --tries 5 \
1130 -                                       --prompt "Encrypted ZFS password for ${ENCRYPTIONROOT}: " \
1131 -                                       --cmd "zfs load-key '${ENCRYPTIONROOT}'"
1132 -                       fi
1133 +
1134 +if ! zpool get -Ho name "${ZFS_POOL}" > /dev/null 2>&1; then
1135 +    info "ZFS: Importing pool ${ZFS_POOL}..."
1136 +    # shellcheck disable=SC2086
1137 +    if ! zpool import -N ${ZPOOL_IMPORT_OPTS} "${ZFS_POOL}"; then
1138 +        warn "ZFS: Unable to import pool ${ZFS_POOL}"
1139 +        rootok=0
1140 +        return 1
1141 +    fi
1142 +fi
1143 +
1144 +# Load keys if we can or if we need to
1145 +# TODO: for_relevant_root_children like in zfs-load-key.sh.in
1146 +if [ "$(zpool get -Ho value feature@encryption "${ZFS_POOL}")" = 'active' ]; then
1147 +       # if the root dataset has encryption enabled
1148 +       ENCRYPTIONROOT="$(zfs get -Ho value encryptionroot "${ZFS_DATASET}")"
1149 +       if ! [ "${ENCRYPTIONROOT}" = "-" ]; then
1150 +               KEYSTATUS="$(zfs get -Ho value keystatus "${ENCRYPTIONROOT}")"
1151 +               # if the key needs to be loaded
1152 +               if [ "$KEYSTATUS" = "unavailable" ]; then
1153 +                       # decrypt them
1154 +                       ask_for_password \
1155 +                               5 \
1156 +                               "Encrypted ZFS password for ${ENCRYPTIONROOT}: " \
1157 +                               "zfs load-key '${ENCRYPTIONROOT}'"
1158                 fi
1159         fi
1160 -       # Let us tell the initrd to run on shutdown.
1161 -       # We have a shutdown hook to run
1162 -       # because we imported the pool.
1163 -       info "ZFS: Mounting dataset ${ZFS_DATASET}..."
1164 -       if mount_dataset "${ZFS_DATASET}" ; then
1165 -               ROOTFS_MOUNTED=yes
1166 -               return 0
1167 -       fi
1168  fi
1169  
1170 -rootok=0
1171 +# Let us tell the initrd to run on shutdown.
1172 +# We have a shutdown hook to run
1173 +# because we imported the pool.
1174 +info "ZFS: Mounting dataset ${ZFS_DATASET}..."
1175 +if ! mount_dataset "${ZFS_DATASET}"; then
1176 +  rootok=0
1177 +  return 1
1178 +fi
1179 diff --git a/contrib/dracut/90zfs/parse-zfs.sh.in b/contrib/dracut/90zfs/parse-zfs.sh.in
1180 index 0f92f5c80..f7d1f1c5d 100755
1181 --- a/contrib/dracut/90zfs/parse-zfs.sh.in
1182 +++ b/contrib/dracut/90zfs/parse-zfs.sh.in
1183 @@ -1,7 +1,8 @@
1184  #!/bin/sh
1185  # shellcheck disable=SC2034,SC2154
1186  
1187 -. /lib/dracut-lib.sh
1188 +# shellcheck source=zfs-lib.sh.in
1189 +. /lib/dracut-zfs-lib.sh
1190  
1191  # Let the command line override our host id.
1192  spl_hostid=$(getarg spl_hostid=)
1193 @@ -15,49 +16,20 @@ else
1194         warn "ZFS: Pools may not import correctly."
1195  fi
1196  
1197 -wait_for_zfs=0
1198 -case "${root}" in
1199 -       ""|zfs|zfs:)
1200 -               # We'll take root unset, root=zfs, or root=zfs:
1201 -               # No root set, so we want to read the bootfs attribute.  We
1202 -               # can't do that until udev settles so we'll set dummy values
1203 -               # and hope for the best later on.
1204 -               root="zfs:AUTO"
1205 -               rootok=1
1206 -               wait_for_zfs=1
1207 -
1208 -               info "ZFS: Enabling autodetection of bootfs after udev settles."
1209 -               ;;
1210 -
1211 -       ZFS=*|zfs:*|FILESYSTEM=*)
1212 -               # root is explicit ZFS root.  Parse it now.  We can handle
1213 -               # a root=... param in any of the following formats:
1214 -               # root=ZFS=rpool/ROOT
1215 -               # root=zfs:rpool/ROOT
1216 -               # root=zfs:FILESYSTEM=rpool/ROOT
1217 -               # root=FILESYSTEM=rpool/ROOT
1218 -               # root=ZFS=pool+with+space/ROOT+WITH+SPACE (translates to root=ZFS=pool with space/ROOT WITH SPACE)
1219 -
1220 -               # Strip down to just the pool/fs
1221 -               root="${root#zfs:}"
1222 -               root="${root#FILESYSTEM=}"
1223 -               root="zfs:${root#ZFS=}"
1224 -               # switch + with spaces because kernel cmdline does not allow us to quote parameters
1225 -               root=$(echo "$root" | tr '+' ' ')
1226 -               rootok=1
1227 -               wait_for_zfs=1
1228 -
1229 -               info "ZFS: Set ${root} as bootfs."
1230 -               ;;
1231 -esac
1232 -
1233 -# Make sure Dracut is happy that we have a root and will wait for ZFS
1234 -# modules to settle before mounting.
1235 -if [ ${wait_for_zfs} -eq 1 ]; then
1236 -       ln -s /dev/null /dev/root 2>/dev/null
1237 -       initqueuedir="${hookdir}/initqueue/finished"
1238 -       test -d "${initqueuedir}" || {
1239 -               initqueuedir="${hookdir}/initqueue-finished"
1240 -       }
1241 -       echo '[ -e /dev/zfs ]' > "${initqueuedir}/zfs.sh"
1242 +if decode_root_args; then
1243 +       if [ "$root" = "zfs:AUTO" ]; then
1244 +               info "ZFS: Boot dataset autodetected from bootfs=."
1245 +       else
1246 +               info "ZFS: Boot dataset is ${root}."
1247 +       fi
1248 +
1249 +       rootok=1
1250 +       # Make sure Dracut is happy that we have a root and will wait for ZFS
1251 +       # modules to settle before mounting.
1252 +       if [ -n "${wait_for_zfs}" ]; then
1253 +               ln -s null /dev/root
1254 +               echo '[ -e /dev/zfs ]' > "${hookdir}/initqueue/finished/zfs.sh"
1255 +       fi
1256 +else
1257 +       info "ZFS: no ZFS-on-root."
1258  fi
1259 diff --git a/contrib/dracut/90zfs/zfs-env-bootfs.service.in b/contrib/dracut/90zfs/zfs-env-bootfs.service.in
1260 index e143cb5ec..34c88037c 100644
1261 --- a/contrib/dracut/90zfs/zfs-env-bootfs.service.in
1262 +++ b/contrib/dracut/90zfs/zfs-env-bootfs.service.in
1263 @@ -8,7 +8,7 @@ Before=zfs-import.target
1264  
1265  [Service]
1266  Type=oneshot
1267 -ExecStart=/bin/sh -c "exec systemctl set-environment BOOTFS=$(@sbindir@/zpool list -H -o bootfs | grep -m1 -v '^-$')"
1268 +ExecStart=/bin/sh -c "exec systemctl set-environment BOOTFS=$(@sbindir@/zpool list -H -o bootfs | grep -m1 -vFx -)"
1269  
1270  [Install]
1271  WantedBy=zfs-import.target
1272 diff --git a/contrib/dracut/90zfs/zfs-generator.sh.in b/contrib/dracut/90zfs/zfs-generator.sh.in
1273 index e50b9530c..56f7ca978 100755
1274 --- a/contrib/dracut/90zfs/zfs-generator.sh.in
1275 +++ b/contrib/dracut/90zfs/zfs-generator.sh.in
1276 @@ -1,5 +1,5 @@
1277  #!/bin/sh
1278 -# shellcheck disable=SC2016,SC1004
1279 +# shellcheck disable=SC2016,SC1004,SC2154
1280  
1281  grep -wq debug /proc/cmdline && debug=1
1282  [ -n "$debug" ] && echo "zfs-generator: starting" >> /dev/kmsg
1283 @@ -10,37 +10,17 @@ GENERATOR_DIR="$1"
1284      exit 1
1285  }
1286  
1287 -[ -f /lib/dracut-lib.sh ] && dracutlib=/lib/dracut-lib.sh
1288 -[ -f /usr/lib/dracut/modules.d/99base/dracut-lib.sh ] && dracutlib=/usr/lib/dracut/modules.d/99base/dracut-lib.sh
1289 -command -v getarg >/dev/null 2>&1 || {
1290 -    [ -n "$debug" ] && echo "zfs-generator: loading Dracut library from $dracutlib" >> /dev/kmsg
1291 -    . "$dracutlib"
1292 -}
1293 -
1294 +# shellcheck source=zfs-lib.sh.in
1295  . /lib/dracut-zfs-lib.sh
1296 +decode_root_args || exit 0
1297  
1298 -[ -z "$root" ]       && root=$(getarg root=)
1299 -[ -z "$rootfstype" ] && rootfstype=$(getarg rootfstype=)
1300 -[ -z "$rootflags" ]  && rootflags=$(getarg rootflags=)
1301 -
1302 -# If root is not ZFS= or zfs: or rootfstype is not zfs
1303 -# then we are not supposed to handle it.
1304 -[ "${root##zfs:}" = "${root}" ] &&
1305 -       [ "${root##ZFS=}" = "${root}" ] &&
1306 -       [ "$rootfstype" != "zfs" ] &&
1307 -       exit 0
1308 -
1309 +[ -z "${rootflags}" ] && rootflags=$(getarg rootflags=)
1310  case ",${rootflags}," in
1311         *,zfsutil,*) ;;
1312         ,,)     rootflags=zfsutil ;;
1313         *)      rootflags="zfsutil,${rootflags}" ;;
1314  esac
1315  
1316 -if [ "${root}" != "zfs:AUTO" ]; then
1317 -  root="${root##zfs:}"
1318 -  root="${root##ZFS=}"
1319 -fi
1320 -
1321  [ -n "$debug" ] && echo "zfs-generator: writing extension for sysroot.mount to $GENERATOR_DIR/sysroot.mount.d/zfs-enhancement.conf" >> /dev/kmsg
1322  
1323  
1324 @@ -89,7 +69,7 @@ else
1325    _zfs_generator_cb() {
1326        dset="${1}"
1327        mpnt="${2}"
1328 -      unit="sysroot$(echo "$mpnt" | tr '/' '-').mount"
1329 +      unit="$(systemd-escape --suffix=mount -p "/sysroot${mpnt}")"
1330  
1331        {
1332            echo "[Unit]"
1333 diff --git a/contrib/dracut/90zfs/zfs-lib.sh.in b/contrib/dracut/90zfs/zfs-lib.sh.in
1334 index defc0bfc8..a91b56ba7 100755
1335 --- a/contrib/dracut/90zfs/zfs-lib.sh.in
1336 +++ b/contrib/dracut/90zfs/zfs-lib.sh.in
1337 @@ -1,74 +1,16 @@
1338  #!/bin/sh
1339 +# shellcheck disable=SC2034
1340  
1341 -command -v getarg >/dev/null || . /lib/dracut-lib.sh
1342 -command -v getargbool >/dev/null || {
1343 -    # Compatibility with older Dracut versions.
1344 -    # With apologies to the Dracut developers.
1345 -    getargbool() {
1346 -        _default="$1"; shift
1347 -        ! _b=$(getarg "$@") && [ -z "$_b" ] && _b="$_default"
1348 -        if [ -n "$_b" ]; then
1349 -            [ "$_b" = "0" ] && return 1
1350 -            [ "$_b" = "no" ] && return 1
1351 -            [ "$_b" = "off" ] && return 1
1352 -        fi
1353 -        return 0
1354 -    }
1355 -}
1356 +command -v getarg >/dev/null || . /lib/dracut-lib.sh || . /usr/lib/dracut/modules.d/99base/dracut-lib.sh
1357  
1358 -OLDIFS="${IFS}"
1359 -NEWLINE="
1360 -"
1361  TAB="  "
1362  
1363 -ZPOOL_IMPORT_OPTS=""
1364 -if getargbool 0 zfs_force -y zfs.force -y zfsforce ; then
1365 +ZPOOL_IMPORT_OPTS=
1366 +if getargbool 0 zfs_force -y zfs.force -y zfsforce; then
1367      warn "ZFS: Will force-import pools if necessary."
1368 -    ZPOOL_IMPORT_OPTS="${ZPOOL_IMPORT_OPTS} -f"
1369 +    ZPOOL_IMPORT_OPTS=-f
1370  fi
1371  
1372 -# find_bootfs
1373 -#   returns the first dataset with the bootfs attribute.
1374 -find_bootfs() {
1375 -    IFS="${NEWLINE}"
1376 -    for dataset in $(zpool list -H -o bootfs); do
1377 -        case "${dataset}" in
1378 -            "" | "-")
1379 -                continue
1380 -                ;;
1381 -            "no pools available")
1382 -                IFS="${OLDIFS}"
1383 -                return 1
1384 -                ;;
1385 -            *)
1386 -                IFS="${OLDIFS}"
1387 -                echo "${dataset}"
1388 -                return 0
1389 -                ;;
1390 -        esac
1391 -    done
1392 -
1393 -    IFS="${OLDIFS}"
1394 -    return 1
1395 -}
1396 -
1397 -# import_pool POOL
1398 -#   imports the given zfs pool if it isn't imported already.
1399 -import_pool() {
1400 -    pool="${1}"
1401 -
1402 -    if ! zpool list -H "${pool}" > /dev/null 2>&1; then
1403 -        info "ZFS: Importing pool ${pool}..."
1404 -        # shellcheck disable=SC2086
1405 -        if ! zpool import -N ${ZPOOL_IMPORT_OPTS} "${pool}" ; then
1406 -            warn "ZFS: Unable to import pool ${pool}"
1407 -            return 1
1408 -        fi
1409 -    fi
1410 -
1411 -    return 0
1412 -}
1413 -
1414  _mount_dataset_cb() {
1415      mount -o zfsutil -t zfs "${1}" "${NEWROOT}${2}"
1416  }
1417 @@ -121,87 +63,57 @@ for_relevant_root_children() {
1418          )
1419  }
1420  
1421 -# export_all OPTS
1422 -#   exports all imported zfs pools.
1423 -export_all() {
1424 -    ret=0
1425 -
1426 -    IFS="${NEWLINE}"
1427 -    for pool in $(zpool list -H -o name) ; do
1428 -        if zpool list -H "${pool}" > /dev/null 2>&1; then
1429 -            zpool export "${pool}" "$@" || ret=$?
1430 -        fi
1431 -    done
1432 -    IFS="${OLDIFS}"
1433 -
1434 -    return ${ret}
1435 -}
1436 -
1437 -# ask_for_password
1438 +# Parse root=, rootfstype=, return them decoded and normalised to zfs:AUTO for auto, plain dset for explicit
1439 +#
1440 +# True if ZFS-on-root, false if we shouldn't
1441 +#
1442 +# Supported values:
1443 +#   root=
1444 +#   root=zfs
1445 +#   root=zfs:
1446 +#   root=zfs:AUTO
1447 +#
1448 +#   root=ZFS=data/set
1449 +#   root=zfs:data/set
1450 +#   root=zfs:ZFS=data/set (as a side-effect; allowed but undocumented)
1451  #
1452 -# Wraps around plymouth ask-for-password and adds fallback to tty password ask
1453 -# if plymouth is not present.
1454 +#   rootfstype=zfs AND root=data/set <=> root=data/set
1455 +#   rootfstype=zfs AND root=         <=> root=zfs:AUTO
1456  #
1457 -# --cmd command
1458 -#   Command to execute. Required.
1459 -# --prompt prompt
1460 -#   Password prompt. Note that function already adds ':' at the end.
1461 -#   Recommended.
1462 -# --tries n
1463 -#   How many times repeat command on its failure.  Default is 3.
1464 -# --ply-[cmd|prompt|tries]
1465 -#   Command/prompt/tries specific for plymouth password ask only.
1466 -# --tty-[cmd|prompt|tries]
1467 -#   Command/prompt/tries specific for tty password ask only.
1468 -# --tty-echo-off
1469 -#   Turn off input echo before tty command is executed and turn on after.
1470 -#   It's useful when password is read from stdin.
1471 -ask_for_password() {
1472 -    ply_tries=3
1473 -    tty_tries=3
1474 -    while [ "$#" -gt 0 ]; do
1475 -        case "$1" in
1476 -            --cmd) ply_cmd="$2"; tty_cmd="$2"; shift;;
1477 -            --ply-cmd) ply_cmd="$2"; shift;;
1478 -            --tty-cmd) tty_cmd="$2"; shift;;
1479 -            --prompt) ply_prompt="$2"; tty_prompt="$2"; shift;;
1480 -            --ply-prompt) ply_prompt="$2"; shift;;
1481 -            --tty-prompt) tty_prompt="$2"; shift;;
1482 -            --tries) ply_tries="$2"; tty_tries="$2"; shift;;
1483 -            --ply-tries) ply_tries="$2"; shift;;
1484 -            --tty-tries) tty_tries="$2"; shift;;
1485 -            --tty-echo-off) tty_echo_off=yes;;
1486 +# '+'es in explicit dataset decoded to ' 's.
1487 +decode_root_args() {
1488 +    if [ -n "$rootfstype" ]; then
1489 +        [ "$rootfstype" = zfs ]
1490 +        return
1491 +    fi
1492 +
1493 +    root=$(getarg root=)
1494 +    rootfstype=$(getarg rootfstype=)
1495 +
1496 +    # shellcheck disable=SC2249
1497 +    case "$root" in
1498 +        ""|zfs|zfs:|zfs:AUTO)
1499 +            root=zfs:AUTO
1500 +            rootfstype=zfs
1501 +            return 0
1502 +            ;;
1503 +
1504 +        ZFS=*|zfs:*)
1505 +            root="${root#zfs:}"
1506 +            root="${root#ZFS=}"
1507 +            root=$(echo "$root" | tr '+' ' ')
1508 +            rootfstype=zfs
1509 +            return 0
1510 +            ;;
1511 +    esac
1512 +
1513 +    if [ "$rootfstype" = "zfs" ]; then
1514 +        case "$root" in
1515 +            "") root=zfs:AUTO ;;
1516 +            *)  root=$(echo "$root" | tr '+' ' ') ;;
1517          esac
1518 -        shift
1519 -    done
1520 -
1521 -    { flock -s 9;
1522 -        # Prompt for password with plymouth, if installed and running.
1523 -        if plymouth --ping 2>/dev/null; then
1524 -            plymouth ask-for-password \
1525 -                --prompt "$ply_prompt" --number-of-tries="$ply_tries" | \
1526 -                eval "$ply_cmd"
1527 -            ret=$?
1528 -        else
1529 -            if [ "$tty_echo_off" = yes ]; then
1530 -                stty_orig="$(stty -g)"
1531 -                stty -echo
1532 -            fi
1533 -
1534 -            i=1
1535 -            while [ "$i" -le "$tty_tries" ]; do
1536 -                [ -n "$tty_prompt" ] && \
1537 -                    printf "%s [%i/%i]:" "$tty_prompt" "$i" "$tty_tries" >&2
1538 -                eval "$tty_cmd" && ret=0 && break
1539 -                ret=$?
1540 -                i=$((i+1))
1541 -                [ -n "$tty_prompt" ] && printf '\n' >&2
1542 -            done
1543 -            unset i
1544 -            [ "$tty_echo_off" = yes ] && stty "$stty_orig"
1545 -        fi
1546 -    } 9>/.console_lock
1547 +        return 0
1548 +    fi
1549  
1550 -    [ $ret -ne 0 ] && echo "Wrong password" >&2
1551 -    return $ret
1552 +    return 1
1553  }
1554 diff --git a/contrib/dracut/90zfs/zfs-load-key.sh.in b/contrib/dracut/90zfs/zfs-load-key.sh.in
1555 index c974b3d9e..d916f43b4 100755
1556 --- a/contrib/dracut/90zfs/zfs-load-key.sh.in
1557 +++ b/contrib/dracut/90zfs/zfs-load-key.sh.in
1558 @@ -4,70 +4,61 @@
1559  # only run this on systemd systems, we handle the decrypt in mount-zfs.sh in the mount hook otherwise
1560  [ -e /bin/systemctl ] || [ -e /usr/bin/systemctl ] || return 0
1561  
1562 -# This script only gets executed on systemd systems, see mount-zfs.sh for non-systemd systems
1563 +# shellcheck source=zfs-lib.sh.in
1564 +. /lib/dracut-zfs-lib.sh
1565  
1566 -# import the libs now that we know the pool imported
1567 -[ -f /lib/dracut-lib.sh ] && dracutlib=/lib/dracut-lib.sh
1568 -[ -f /usr/lib/dracut/modules.d/99base/dracut-lib.sh ] && dracutlib=/usr/lib/dracut/modules.d/99base/dracut-lib.sh
1569 -# shellcheck source=./lib-zfs.sh.in
1570 -. "$dracutlib"
1571 -
1572 -# load the kernel command line vars
1573 -[ -z "$root" ] && root="$(getarg root=)"
1574 -# If root is not ZFS= or zfs: or rootfstype is not zfs then we are not supposed to handle it.
1575 -[ "${root##zfs:}" = "${root}" ] && [ "${root##ZFS=}" = "${root}" ] && [ "$rootfstype" != "zfs" ] && exit 0
1576 +decode_root_args || return 0
1577  
1578  # There is a race between the zpool import and the pre-mount hooks, so we wait for a pool to be imported
1579 -while [ "$(zpool list -H)" = "" ]; do
1580 -    systemctl is-failed --quiet zfs-import-cache.service zfs-import-scan.service && exit 1
1581 +while ! systemctl is-active --quiet zfs-import.target; do
1582 +    systemctl is-failed --quiet zfs-import-cache.service zfs-import-scan.service && return 1
1583      sleep 0.1s
1584  done
1585  
1586 -# run this after import as zfs-import-cache/scan service is confirmed good
1587 -# we do not overwrite the ${root} variable, but create a new one, BOOTFS, to hold the dataset
1588 -if [ "${root}" = "zfs:AUTO" ] ; then
1589 -    BOOTFS="$(zpool list -H -o bootfs | awk '$1 != "-" {print; exit}')"
1590 -else
1591 -    BOOTFS="${root##zfs:}"
1592 -    BOOTFS="${BOOTFS##ZFS=}"
1593 +BOOTFS="$root"
1594 +if [ "$BOOTFS" = "zfs:AUTO" ]; then
1595 +    BOOTFS="$(zpool get -Ho value bootfs | grep -m1 -vFx -)"
1596  fi
1597  
1598 -# if pool encryption is active and the zfs command understands '-o encryption'
1599 -if [ "$(zpool list -H -o feature@encryption "${BOOTFS%%/*}")" = 'active' ]; then
1600 -    # if the root dataset has encryption enabled
1601 -    ENCRYPTIONROOT="$(zfs get -H -o value encryptionroot "${BOOTFS}")"
1602 -    if ! [ "${ENCRYPTIONROOT}" = "-" ]; then
1603 -        KEYSTATUS="$(zfs get -H -o value keystatus "${ENCRYPTIONROOT}")"
1604 -        # continue only if the key needs to be loaded
1605 -        [ "$KEYSTATUS" = "unavailable" ] || exit 0
1606 +[ "$(zpool get -Ho value feature@encryption "${BOOTFS%%/*}")" = 'active' ] || return 0
1607 +
1608 +_load_key_cb() {
1609 +    dataset="$1"
1610 +
1611 +    ENCRYPTIONROOT="$(zfs get -Ho value encryptionroot "${dataset}")"
1612 +    [ "${ENCRYPTIONROOT}" = "-" ] && return 0
1613  
1614 -        KEYLOCATION="$(zfs get -H -o value keylocation "${ENCRYPTIONROOT}")"
1615 -        case "${KEYLOCATION%%://*}" in
1616 -            prompt)
1617 -                for _ in 1 2 3; do
1618 -                    systemd-ask-password --no-tty "Encrypted ZFS password for ${BOOTFS}" | zfs load-key "${ENCRYPTIONROOT}" && break
1619 +    [ "$(zfs get -Ho value keystatus "${ENCRYPTIONROOT}")" = "unavailable" ] || return 0
1620 +
1621 +    KEYLOCATION="$(zfs get -Ho value keylocation "${ENCRYPTIONROOT}")"
1622 +    case "${KEYLOCATION%%://*}" in
1623 +        prompt)
1624 +            for _ in 1 2 3; do
1625 +                systemd-ask-password --no-tty "Encrypted ZFS password for ${dataset}" | zfs load-key "${ENCRYPTIONROOT}" && break
1626 +            done
1627 +            ;;
1628 +        http*)
1629 +            systemctl start network-online.target
1630 +            zfs load-key "${ENCRYPTIONROOT}"
1631 +            ;;
1632 +        file)
1633 +            KEYFILE="${KEYLOCATION#file://}"
1634 +            [ -r "${KEYFILE}" ] || udevadm settle
1635 +            [ -r "${KEYFILE}" ] || {
1636 +                info "ZFS: Waiting for key ${KEYFILE} for ${ENCRYPTIONROOT}..."
1637 +                for _ in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do
1638 +                    sleep 0.5s
1639 +                    [ -r "${KEYFILE}" ] && break
1640                  done
1641 -                ;;
1642 -            http*)
1643 -                systemctl start network-online.target
1644 -                zfs load-key "${ENCRYPTIONROOT}"
1645 -                ;;
1646 -            file)
1647 -                KEYFILE="${KEYLOCATION#file://}"
1648 -                [ -r "${KEYFILE}" ] || udevadm settle
1649 -                [ -r "${KEYFILE}" ] || {
1650 -                    info "Waiting for key ${KEYFILE} for ${ENCRYPTIONROOT}..."
1651 -                    for _ in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do
1652 -                        sleep 0.5s
1653 -                        [ -r "${KEYFILE}" ] && break
1654 -                    done
1655 -                }
1656 -                [ -r "${KEYFILE}" ] || warn "Key ${KEYFILE} for ${ENCRYPTIONROOT} hasn't appeared. Trying anyway."
1657 -                zfs load-key "${ENCRYPTIONROOT}"
1658 -                ;;
1659 -            *)
1660 -                zfs load-key "${ENCRYPTIONROOT}"
1661 -                ;;
1662 -        esac
1663 -    fi
1664 -fi
1665 +            }
1666 +            [ -r "${KEYFILE}" ] || warn "ZFS: Key ${KEYFILE} for ${ENCRYPTIONROOT} hasn't appeared. Trying anyway."
1667 +            zfs load-key "${ENCRYPTIONROOT}"
1668 +            ;;
1669 +        *)
1670 +            zfs load-key "${ENCRYPTIONROOT}"
1671 +            ;;
1672 +    esac
1673 +}
1674 +
1675 +_load_key_cb "$BOOTFS"
1676 +for_relevant_root_children "$BOOTFS" _load_key_cb
1677 diff --git a/contrib/dracut/90zfs/zfs-needshutdown.sh.in b/contrib/dracut/90zfs/zfs-needshutdown.sh.in
1678 index dd6de30c2..7fb825bc9 100755
1679 --- a/contrib/dracut/90zfs/zfs-needshutdown.sh.in
1680 +++ b/contrib/dracut/90zfs/zfs-needshutdown.sh.in
1681 @@ -2,7 +2,7 @@
1682  
1683  command -v getarg >/dev/null 2>&1 || . /lib/dracut-lib.sh
1684  
1685 -if zpool list 2>&1 | grep -q 'no pools available' ; then
1686 +if [ -z "$(zpool get -Ho value name)" ]; then
1687      info "ZFS: No active pools, no need to export anything."
1688  else
1689      info "ZFS: There is an active pool, will export it."
1690 diff --git a/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in b/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in
1691 index bdc246943..b4f570751 100644
1692 --- a/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in
1693 +++ b/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in
1694 @@ -1,14 +1,12 @@
1695  [Unit]
1696  Description=Rollback bootfs just before it is mounted
1697  Requisite=zfs-import.target
1698 -After=zfs-import.target zfs-snapshot-bootfs.service
1699 +After=zfs-import.target dracut-pre-mount.service zfs-snapshot-bootfs.service
1700  Before=dracut-mount.service
1701  DefaultDependencies=no
1702  ConditionKernelCommandLine=bootfs.rollback
1703  
1704  [Service]
1705 -# ${BOOTFS} should have been set by zfs-env-bootfs.service
1706  Type=oneshot
1707 -ExecStartPre=/bin/sh -c 'test -n "${BOOTFS}"'
1708 -ExecStart=/bin/sh -c '. /lib/dracut-lib.sh; SNAPNAME="$(getarg bootfs.rollback)"; exec @sbindir@/zfs rollback -Rf "${BOOTFS}@${SNAPNAME:-%v}"'
1709 +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}"'
1710  RemainAfterExit=yes
1711 diff --git a/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in b/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in
1712 index 6ea13850c..afdba2c9d 100644
1713 --- a/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in
1714 +++ b/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in
1715 @@ -1,14 +1,12 @@
1716  [Unit]
1717  Description=Snapshot bootfs just before it is mounted
1718  Requisite=zfs-import.target
1719 -After=zfs-import.target
1720 +After=zfs-import.target dracut-pre-mount.service
1721  Before=dracut-mount.service
1722  DefaultDependencies=no
1723  ConditionKernelCommandLine=bootfs.snapshot
1724  
1725  [Service]
1726 -# ${BOOTFS} should have been set by zfs-env-bootfs.service
1727  Type=oneshot
1728 -ExecStartPre=/bin/sh -c 'test -n "${BOOTFS}"'
1729 -ExecStart=-/bin/sh -c '. /lib/dracut-lib.sh; SNAPNAME="$(getarg bootfs.snapshot)"; exec @sbindir@/zfs snapshot "${BOOTFS}@${SNAPNAME:-%v}"'
1730 +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}"'
1731  RemainAfterExit=yes
1732 diff --git a/contrib/dracut/README.dracut.markdown b/contrib/dracut/README.dracut.markdown
1733 index f31543c3c..b7cd8c812 100644
1734 --- a/contrib/dracut/README.dracut.markdown
1735 +++ b/contrib/dracut/README.dracut.markdown
1736 @@ -1,225 +1,50 @@
1737 -How to setup a zfs root filesystem using dracut
1738 ------------------------------------------------
1739 +## Basic setup
1740 +1. Install `zfs-dracut`
1741 +2. Set `mountpoint=/` for your root dataset (for compatibility, `legacy` also works, but is not recommended for new installations):
1742 +    ```sh
1743 +    zfs set mountpoint=/ pool/dataset
1744 +    ```
1745 +3. Either (a) set `bootfs=` on the pool to the dataset:
1746 +    ```sh
1747 +    zpool set bootfs=pool/dataset pool
1748 +    ```
1749 +4. Or (b) append `root=zfs:pool/dataset` to your kernel cmdline.
1750 +5. Re-generate your initrd and update it in your boot bundle
1751  
1752 -1) Install the zfs-dracut package.  This package adds a zfs dracut module
1753 -to the /usr/share/dracut/modules.d/ directory which allows dracut to
1754 -create an initramfs which is zfs aware.
1755 +Encrypted datasets have keys loaded automatically or prompted for.
1756  
1757 -2) Set the bootfs property for the bootable dataset in the pool.  Then set
1758 -the dataset mountpoint property to '/'.
1759 +If the root dataset contains children with `mountpoint=`s of `/etc`, `/bin`, `/lib*`, or `/usr`, they're mounted too.
1760  
1761 -    $ zpool set bootfs=pool/dataset pool
1762 -    $ zfs set mountpoint=/ pool/dataset
1763 +For complete documentation, see `dracut.zfs(7)`.
1764  
1765 -Alternately, legacy mountpoints can be used by setting the 'root=' option
1766 -on the kernel line of your grub.conf/menu.lst configuration file.  Then
1767 -set the dataset mountpoint property to 'legacy'.
1768 +## cmdline
1769 +1. `root=`                    | Root dataset is…                                         |
1770 +   ---------------------------|----------------------------------------------------------|
1771 +   *(empty)*                  | the first `bootfs=` after `zpool import -aN`             |
1772 +   `zfs:AUTO`, `zfs:`, `zfs`  | *(as above, but overriding other autoselection methods)* |
1773 +   `ZFS=pool/dataset`         | `pool/dataset`                                           |
1774 +   `zfs:pool/dataset`         | *(as above)*                                             |
1775  
1776 -    $ grub.conf/menu.lst: kernel ... root=ZFS=pool/dataset
1777 -    $ zfs set mountpoint=legacy pool/dataset
1778 +   All `+`es are replaced with spaces (i.e. to boot from `root pool/data set`, pass `root=zfs:root+pool/data+set`).
1779  
1780 -3) To set zfs module options put them in /etc/modprobe.d/zfs.conf file.
1781 -The complete list of zfs module options is available by running the
1782 -_modinfo zfs_ command.  Commonly set options include: zfs_arc_min,
1783 -zfs_arc_max, zfs_prefetch_disable, and zfs_vdev_max_pending.
1784 +   The dataset can be at any depth, including being the pool's root dataset (i.e. `root=zfs:pool`).
1785  
1786 -4) Finally, create your new initramfs by running dracut.
1787 +   `rootfstype=zfs` is equivalent to `root=zfs:AUTO`, `rootfstype=zfs root=pool/dataset` is equivalent to `root=zfs:pool/dataset`.
1788  
1789 -    $ dracut --force /path/to/initramfs kernel_version
1790 +2. `spl_hostid`: passed to `zgenhostid -f`, useful to override the `/etc/hostid` file baked into the initrd.
1791  
1792 -Kernel Command Line
1793 --------------------
1794 +3. `bootfs.snapshot`, `bootfs.snapshot=snapshot-name`: enables `zfs-snapshot-bootfs.service`,
1795 +   which creates a snapshot `$root_dataset@$(uname -r)` (or, in the second form, `$root_dataset@snapshot-name`)
1796 +   after pool import but before the rootfs is mounted.
1797 +   Failure to create the snapshot is noted, but booting continues.
1798  
1799 -The initramfs' behavior is influenced by the following kernel command line
1800 -parameters passed in from the boot loader:
1801 +4. `bootfs.rollback`, `bootfs.rollback=snapshot-name`: enables `zfs-snapshot-bootfs.service`,
1802 +   which `-Rf` rolls back to `$root_dataset@$(uname -r)` (or, in the second form, `$root_dataset@snapshot-name`)
1803 +   after pool import but before the rootfs is mounted.
1804 +   Failure to roll back will fall down to the rescue shell.
1805 +   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.
1806  
1807 -* `root=...`: If not set, importable pools are searched for a bootfs
1808 -attribute.  If an explicitly set root is desired, you may use
1809 -`root=ZFS:pool/dataset`
1810 +5. If both `bootfs.snapshot` and `bootfs.rollback` are set, `bootfs.rollback` is ordered *after* `bootfs.snapshot`.
1811  
1812 -* `zfs_force=0`: If set to 1, the initramfs will run `zpool import -f` when
1813 -attempting to import pools if the required pool isn't automatically imported
1814 -by the zfs module.  This can save you a trip to a bootcd if hostid has
1815 -changed, but is dangerous and can lead to zpool corruption, particularly in
1816 -cases where storage is on a shared fabric such as iSCSI where multiple hosts
1817 -can access storage devices concurrently.  _Please understand the implications
1818 -of force-importing a pool before enabling this option!_
1819 -
1820 -* `spl_hostid`: By default, the hostid used by the SPL module is read from
1821 -/etc/hostid inside the initramfs.  This file is placed there from the host
1822 -system when the initramfs is built which effectively ties the ramdisk to the
1823 -host which builds it.  If a different hostid is desired, one may be set in
1824 -this attribute and will override any file present in the ramdisk.  The
1825 -format should be hex exactly as found in the `/etc/hostid` file, IE
1826 -`spl_hostid=0x00bab10c`.
1827 -
1828 -Note that changing the hostid between boots will most likely lead to an
1829 -un-importable pool since the last importing hostid won't match.  In order
1830 -to recover from this, you may use the `zfs_force` option or boot from a
1831 -different filesystem and `zpool import -f` then `zpool export` the pool
1832 -before rebooting with the new hostid.
1833 -
1834 -* `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.
1835 -
1836 -    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.
1837 -
1838 -        #!/usr/bin/sh
1839 -
1840 -        if [[ "$1" == "remove" ]] && grep -q "\bbootfs.snapshot\b" /proc/cmdline; then
1841 -           zfs destroy $(findmnt -n -o source /)@$2 &> /dev/null
1842 -        fi
1843 -
1844 -        exit 0
1845 -
1846 -    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:
1847 -
1848 -        $ chmod +x /etc/kernel/install.d/99-zfs-cleanup.install
1849 -
1850 -    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.
1851 -
1852 -* `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. 
1853 -
1854 -* `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).
1855 -
1856 -* `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.
1857 -
1858 -How it Works
1859 -============
1860 -
1861 -The Dracut module consists of the following files (less Makefile's):
1862 -
1863 -* `module-setup.sh`: Script run by the initramfs builder to create the
1864 -ramdisk.  Contains instructions on which files are required by the modules
1865 -and z* programs.  Also triggers inclusion of `/etc/hostid` and the zpool
1866 -cache.  This file is not included in the initramfs.
1867 -
1868 -* `90-zfs.rules`: udev rules which trigger loading of the ZFS modules at boot.
1869 -
1870 -* `zfs-lib.sh`: Utility functions used by the other files.
1871 -
1872 -* `parse-zfs.sh`: Run early in the initramfs boot process to parse kernel
1873 -command line and determine if ZFS is the active root filesystem.
1874 -
1875 -* `mount-zfs.sh`: Run later in initramfs boot process after udev has settled
1876 -to mount the root dataset.
1877 -
1878 -* `export-zfs.sh`: Run on shutdown after dracut has restored the initramfs
1879 -and pivoted to it, allowing for a clean unmount and export of the ZFS root.
1880 -
1881 -`zfs-lib.sh`
1882 -------------
1883 -
1884 -This file provides a few handy functions for working with ZFS. Those
1885 -functions are used by the `mount-zfs.sh` and `export-zfs.sh` files.
1886 -However, they could be used by any other file as well, as long as the file
1887 -sources `/lib/dracut-zfs-lib.sh`.
1888 -
1889 -`module-setup.sh`
1890 ------------------
1891 -
1892 -This file is run by the Dracut script within the live system, not at boot
1893 -time.  It's not included in the final initramfs.  Functions in this script
1894 -describe which files are needed by ZFS at boot time.
1895 -
1896 -Currently all the various z* and spl modules are included, a dependency is
1897 -asserted on udev-rules, and the various zfs, zpool, etc. helpers are included.
1898 -Dracut provides library functions which automatically gather the shared libs
1899 -necessary to run each of these binaries, so statically built binaries are
1900 -not required.
1901 -
1902 -The zpool and zvol udev rules files are copied from where they are
1903 -installed by the ZFS build.  __PACKAGERS TAKE NOTE__: If you move
1904 -`/etc/udev/rules/60-z*.rules`, you'll need to update this file to match.
1905 -
1906 -Currently this file also includes `/etc/hostid` and `/etc/zfs/zpool.cache`
1907 -which means the generated ramdisk is specific to the host system which built
1908 -it.  If a generic initramfs is required, it may be preferable to omit these
1909 -files and specify the `spl_hostid` from the boot loader instead.
1910 -
1911 -`parse-zfs.sh`
1912 ---------------
1913 -
1914 -Run during the cmdline phase of the initramfs boot process, this script
1915 -performs some basic sanity checks on kernel command line parameters to
1916 -determine if booting from ZFS is likely to be what is desired.  Dracut
1917 -requires this script to adjust the `root` variable if required and to set
1918 -`rootok=1` if a mountable root filesystem is available.  Unfortunately this
1919 -script must run before udev is settled and kernel modules are known to be
1920 -loaded, so accessing the zpool and zfs commands is unsafe.
1921 -
1922 -If the root=ZFS... parameter is set on the command line, then it's at least
1923 -certain that ZFS is what is desired, though this script is unable to
1924 -determine if ZFS is in fact available.  This script will alter the `root`
1925 -parameter to replace several historical forms of specifying the pool and
1926 -dataset name with the canonical form of `zfs:pool/dataset`.
1927 -
1928 -If no root= parameter is set, the best this script can do is guess that
1929 -ZFS is desired.  At present, no other known filesystems will work with no
1930 -root= parameter, though this might possibly interfere with using the
1931 -compiled-in default root in the kernel image.  It's considered unlikely
1932 -that would ever be the case when an initramfs is in use, so this script
1933 -sets `root=zfs:AUTO` and hopes for the best.
1934 -
1935 -Once the root=... (or lack thereof) parameter is parsed, a dummy symlink
1936 -is created from `/dev/root` -> `/dev/null` to satisfy parts of the Dracut
1937 -process which check for presence of a single root device node.
1938 -
1939 -Finally, an initqueue/finished hook is registered which causes the initqueue
1940 -phase of Dracut to wait for `/dev/zfs` to become available before attempting
1941 -to mount anything.
1942 -
1943 -`mount-zfs.sh`
1944 ---------------
1945 -
1946 -This script is run after udev has settled and all tasks in the initqueue
1947 -have succeeded.  This ensures that `/dev/zfs` is available and that the
1948 -various ZFS modules are successfully loaded.  As it is now safe to call
1949 -zpool and friends, we can proceed to find the bootfs attribute if necessary.
1950 -
1951 -If the root parameter was explicitly set on the command line, no parsing is
1952 -necessary.  The list of imported pools is checked to see if the desired pool
1953 -is already imported.  If it's not, and attempt is made to import the pool
1954 -explicitly, though no force is attempted.  Finally the specified dataset
1955 -is mounted on `$NEWROOT`, first using the `-o zfsutil` option to handle
1956 -non-legacy mounts, then if that fails, without zfsutil to handle legacy
1957 -mount points.
1958 -
1959 -If no root parameter was specified, this script attempts to find a pool with
1960 -its bootfs attribute set.  First, already-imported pools are scanned and if
1961 -an appropriate pool is found, no additional pools are imported.  If no pool
1962 -with bootfs is found, any additional pools in the system are imported with
1963 -`zpool import -N -a`, and the scan for bootfs is tried again.  If no bootfs
1964 -is found with all pools imported, all pools are re-exported, and boot fails.
1965 -Assuming a bootfs is found, an attempt is made to mount it to `$NEWROOT`,
1966 -first with, then without the zfsutil option as above.
1967 -
1968 -Ordinarily pools are imported _without_ the force option which may cause
1969 -boot to fail if the hostid has changed or a pool has been physically moved
1970 -between servers.  The `zfs_force` kernel parameter is provided which when
1971 -set to `1` causes `zpool import` to be run with the `-f` flag.  Forcing pool
1972 -import can lead to serious data corruption and loss of pools, so this option
1973 -should be used with extreme caution.  Note that even with this flag set, if
1974 -the required zpool was auto-imported by the kernel module, no additional
1975 -`zpool import` commands are run, so nothing is forced.
1976 -
1977 -`export-zfs.sh`
1978 ----------------
1979 -
1980 -Normally the zpool containing the root dataset cannot be exported on
1981 -shutdown as it is still in use by the init process. To work around this,
1982 -Dracut is able to restore the initramfs on shutdown and pivot to it.
1983 -All remaining process are then running from a ramdisk, allowing for a
1984 -clean unmount and export of the ZFS root. The theory of operation is
1985 -described in detail in the [Dracut manual](https://www.kernel.org/pub/linux/utils/boot/dracut/dracut.html#_dracut_on_shutdown).
1986 -
1987 -This script will try to export all remaining zpools after Dracut has
1988 -pivoted to the initramfs. If an initial regular export is not successful,
1989 -Dracut will call this script once more with the `final` option,
1990 -in which case a forceful export is attempted.
1991 -
1992 -Other Dracut modules include similar shutdown scripts and Dracut
1993 -invokes these scripts round-robin until they succeed. In particular,
1994 -the `90dm` module installs a script which tries to close and remove
1995 -all device mapper targets. Thus, if there are ZVOLs containing
1996 -dm-crypt volumes or if the zpool itself is backed by a dm-crypt
1997 -volume, the shutdown scripts will try to untangle this.
1998 +6. `zfs_force`, `zfs.force`, `zfsforce`: add `-f` to all `zpool import` invocations.
1999 +   May be useful. Use with caution.
2000 diff --git a/etc/default/Makefile.am b/etc/default/Makefile.am
2001 index b88eb5494..f061692c3 100644
2002 --- a/etc/default/Makefile.am
2003 +++ b/etc/default/Makefile.am
2004 @@ -1,9 +1,10 @@
2005  include $(top_srcdir)/config/Substfiles.am
2006  include $(top_srcdir)/config/Shellcheck.am
2007  
2008 -initconf_SCRIPTS = zfs
2009 +initconf_DATA = zfs
2010  
2011 -SUBSTFILES += $(initconf_SCRIPTS)
2012 +SUBSTFILES += $(initconf_DATA)
2013  
2014 +SHELLCHECKSCRIPTS = $(initconf_DATA)
2015  SHELLCHECK_SHELL = sh
2016  SHELLCHECK_IGNORE = ,SC2034
2017 diff --git a/etc/systemd/system-generators/zfs-mount-generator.c b/etc/systemd/system-generators/zfs-mount-generator.c
2018 index b806339de..f4c6c26a0 100644
2019 --- a/etc/systemd/system-generators/zfs-mount-generator.c
2020 +++ b/etc/systemd/system-generators/zfs-mount-generator.c
2021 @@ -27,9 +27,6 @@
2022  #include <sys/types.h>
2023  #include <sys/time.h>
2024  #include <sys/stat.h>
2025 -#include <sys/wait.h>
2026 -#include <sys/mman.h>
2027 -#include <semaphore.h>
2028  #include <stdbool.h>
2029  #include <unistd.h>
2030  #include <fcntl.h>
2031 @@ -44,25 +41,16 @@
2032  #include <errno.h>
2033  #include <libzfs.h>
2034  
2035 -#define        STRCMP ((int(*)(const void *, const void *))&strcmp)
2036 -#define        PID_T_CMP ((int(*)(const void *, const void *))&pid_t_cmp)
2037 -
2038 -static int
2039 -pid_t_cmp(const pid_t *lhs, const pid_t *rhs)
2040 -{
2041 -       /*
2042 -        * This is always valid, quoth sys_types.h(7posix):
2043 -        * > blksize_t, pid_t, and ssize_t shall be signed integer types.
2044 -        */
2045 -       return (*lhs - *rhs);
2046 -}
2047 +/*
2048 + * For debugging only.
2049 + *
2050 + * Free statics with trivial life-times,
2051 + * but saved line filenames are replaced with a static string.
2052 + */
2053 +#define        FREE_STATICS false
2054  
2055 -#define        EXIT_ENOMEM() \
2056 -       do { \
2057 -               fprintf(stderr, PROGNAME "[%d]: " \
2058 -                   "not enough memory (L%d)!\n", getpid(), __LINE__); \
2059 -               _exit(1); \
2060 -       } while (0)
2061 +#define        nitems(arr) (sizeof (arr) / sizeof (*arr))
2062 +#define        STRCMP ((int(*)(const void *, const void *))&strcmp)
2063  
2064  
2065  #define        PROGNAME "zfs-mount-generator"
2066 @@ -80,20 +68,11 @@ pid_t_cmp(const pid_t *lhs, const pid_t *rhs)
2067  #define        URI_REGEX_S "^\\([A-Za-z][A-Za-z0-9+.\\-]*\\):\\/\\/\\(.*\\)$"
2068  static regex_t uri_regex;
2069  
2070 -static char *argv0;
2071 -
2072  static const char *destdir = "/tmp";
2073  static int destdir_fd = -1;
2074  
2075  static void *known_pools = NULL; /* tsearch() of C strings */
2076 -static struct {
2077 -       sem_t noauto_not_on_sem;
2078 -
2079 -       sem_t noauto_names_sem;
2080 -       size_t noauto_names_len;
2081 -       size_t noauto_names_max;
2082 -       char noauto_names[][NAME_MAX];
2083 -} *noauto_files;
2084 +static void *noauto_files = NULL; /* tsearch() of C strings */
2085  
2086  
2087  static char *
2088 @@ -103,8 +82,12 @@ systemd_escape(const char *input, const char *prepend, const char *append)
2089         size_t applen = strlen(append);
2090         size_t prelen = strlen(prepend);
2091         char *ret = malloc(4 * len + prelen + applen + 1);
2092 -       if (!ret)
2093 -               EXIT_ENOMEM();
2094 +       if (!ret) {
2095 +               fprintf(stderr, PROGNAME "[%d]: "
2096 +                   "out of memory to escape \"%s%s%s\"!\n",
2097 +                   getpid(), prepend, input, append);
2098 +               return (NULL);
2099 +       }
2100  
2101         memcpy(ret, prepend, prelen);
2102         char *out = ret + prelen;
2103 @@ -166,8 +149,12 @@ systemd_escape_path(char *input, const char *prepend, const char *append)
2104  {
2105         if (strcmp(input, "/") == 0) {
2106                 char *ret;
2107 -               if (asprintf(&ret, "%s-%s", prepend, append) == -1)
2108 -                       EXIT_ENOMEM();
2109 +               if (asprintf(&ret, "%s-%s", prepend, append) == -1) {
2110 +                       fprintf(stderr, PROGNAME "[%d]: "
2111 +                           "out of memory to escape \"%s%s%s\"!\n",
2112 +                           getpid(), prepend, input, append);
2113 +                       ret = NULL;
2114 +               }
2115                 return (ret);
2116         } else {
2117                 /*
2118 @@ -209,6 +196,10 @@ fopenat(int dirfd, const char *pathname, int flags,
2119  static int
2120  line_worker(char *line, const char *cachefile)
2121  {
2122 +       int ret = 0;
2123 +       void *tofree_all[8];
2124 +       void **tofree = tofree_all;
2125 +
2126         char *toktmp;
2127         /* BEGIN CSTYLED */
2128         const char *dataset                     = strtok_r(line, "\t", &toktmp);
2129 @@ -240,11 +231,9 @@ line_worker(char *line, const char *cachefile)
2130         if (p_nbmand == NULL) {
2131                 fprintf(stderr, PROGNAME "[%d]: %s: not enough tokens!\n",
2132                     getpid(), dataset);
2133 -               return (1);
2134 +               goto err;
2135         }
2136  
2137 -       strncpy(argv0, dataset, strlen(argv0));
2138 -
2139         /* Minimal pre-requisites to mount a ZFS dataset */
2140         const char *after = "zfs-import.target";
2141         const char *wants = "zfs-import.target";
2142 @@ -280,28 +269,31 @@ line_worker(char *line, const char *cachefile)
2143  
2144  
2145         if (strcmp(p_encroot, "-") != 0) {
2146 -               char *keyloadunit =
2147 +               char *keyloadunit = *(tofree++) =
2148                     systemd_escape(p_encroot, "zfs-load-key@", ".service");
2149 +               if (keyloadunit == NULL)
2150 +                       goto err;
2151  
2152                 if (strcmp(dataset, p_encroot) == 0) {
2153                         const char *keymountdep = NULL;
2154                         bool is_prompt = false;
2155 +                       bool need_network = false;
2156  
2157                         regmatch_t uri_matches[3];
2158                         if (regexec(&uri_regex, p_keyloc,
2159 -                           sizeof (uri_matches) / sizeof (*uri_matches),
2160 -                           uri_matches, 0) == 0) {
2161 +                           nitems(uri_matches), uri_matches, 0) == 0) {
2162 +                               p_keyloc[uri_matches[1].rm_eo] = '\0';
2163                                 p_keyloc[uri_matches[2].rm_eo] = '\0';
2164 +                               const char *scheme =
2165 +                                   &p_keyloc[uri_matches[1].rm_so];
2166                                 const char *path =
2167                                     &p_keyloc[uri_matches[2].rm_so];
2168  
2169 -                               /*
2170 -                                * Assumes all URI keylocations need
2171 -                                * the mount for their path;
2172 -                                * http://, for example, wouldn't
2173 -                                * (but it'd need network-online.target et al.)
2174 -                                */
2175 -                               keymountdep = path;
2176 +                               if (strcmp(scheme, "https") == 0 ||
2177 +                                   strcmp(scheme, "http") == 0)
2178 +                                       need_network = true;
2179 +                               else
2180 +                                       keymountdep = path;
2181                         } else {
2182                                 if (strcmp(p_keyloc, "prompt") != 0)
2183                                         fprintf(stderr, PROGNAME "[%d]: %s: "
2184 @@ -321,7 +313,7 @@ line_worker(char *line, const char *cachefile)
2185                                     "couldn't open %s under %s: %s\n",
2186                                     getpid(), dataset, keyloadunit, destdir,
2187                                     strerror(errno));
2188 -                               return (1);
2189 +                               goto err;
2190                         }
2191  
2192                         fprintf(keyloadunit_f,
2193 @@ -335,20 +327,22 @@ line_worker(char *line, const char *cachefile)
2194                             "After=%s\n",
2195                             dataset, cachefile, wants, after);
2196  
2197 +                       if (need_network)
2198 +                               fprintf(keyloadunit_f,
2199 +                                   "Wants=network-online.target\n"
2200 +                                   "After=network-online.target\n");
2201 +
2202                         if (p_systemd_requires)
2203                                 fprintf(keyloadunit_f,
2204                                     "Requires=%s\n", p_systemd_requires);
2205  
2206 -                       if (p_systemd_requiresmountsfor || keymountdep) {
2207 -                               fprintf(keyloadunit_f, "RequiresMountsFor=");
2208 -                               if (p_systemd_requiresmountsfor)
2209 -                                       fprintf(keyloadunit_f,
2210 -                                           "%s ", p_systemd_requiresmountsfor);
2211 -                               if (keymountdep)
2212 -                                       fprintf(keyloadunit_f,
2213 -                                           "'%s'", keymountdep);
2214 -                               fprintf(keyloadunit_f, "\n");
2215 -                       }
2216 +                       if (p_systemd_requiresmountsfor)
2217 +                               fprintf(keyloadunit_f,
2218 +                                   "RequiresMountsFor=%s\n",
2219 +                                   p_systemd_requiresmountsfor);
2220 +                       if (keymountdep)
2221 +                               fprintf(keyloadunit_f,
2222 +                                   "RequiresMountsFor='%s'\n", keymountdep);
2223  
2224                         /* BEGIN CSTYLED */
2225                         fprintf(keyloadunit_f,
2226 @@ -393,9 +387,13 @@ line_worker(char *line, const char *cachefile)
2227                 if (after[0] == '\0')
2228                         after = keyloadunit;
2229                 else if (asprintf(&toktmp, "%s %s", after, keyloadunit) != -1)
2230 -                       after = toktmp;
2231 -               else
2232 -                       EXIT_ENOMEM();
2233 +                       after = *(tofree++) = toktmp;
2234 +               else {
2235 +                       fprintf(stderr, PROGNAME "[%d]: %s: "
2236 +                           "out of memory to generate after=\"%s %s\"!\n",
2237 +                           getpid(), dataset, after, keyloadunit);
2238 +                       goto err;
2239 +               }
2240         }
2241  
2242  
2243 @@ -404,12 +402,12 @@ line_worker(char *line, const char *cachefile)
2244             strcmp(p_systemd_ignore, "off") == 0) {
2245                 /* ok */
2246         } else if (strcmp(p_systemd_ignore, "on") == 0)
2247 -               return (0);
2248 +               goto end;
2249         else {
2250                 fprintf(stderr, PROGNAME "[%d]: %s: "
2251                     "invalid org.openzfs.systemd:ignore=%s\n",
2252                     getpid(), dataset, p_systemd_ignore);
2253 -               return (1);
2254 +               goto err;
2255         }
2256  
2257         /* Check for canmount */
2258 @@ -418,21 +416,21 @@ line_worker(char *line, const char *cachefile)
2259         } else if (strcmp(p_canmount, "noauto") == 0)
2260                 noauto = true;
2261         else if (strcmp(p_canmount, "off") == 0)
2262 -               return (0);
2263 +               goto end;
2264         else {
2265                 fprintf(stderr, PROGNAME "[%d]: %s: invalid canmount=%s\n",
2266                     getpid(), dataset, p_canmount);
2267 -               return (1);
2268 +               goto err;
2269         }
2270  
2271         /* Check for legacy and blank mountpoints */
2272         if (strcmp(p_mountpoint, "legacy") == 0 ||
2273             strcmp(p_mountpoint, "none") == 0)
2274 -               return (0);
2275 +               goto end;
2276         else if (p_mountpoint[0] != '/') {
2277                 fprintf(stderr, PROGNAME "[%d]: %s: invalid mountpoint=%s\n",
2278                     getpid(), dataset, p_mountpoint);
2279 -               return (1);
2280 +               goto err;
2281         }
2282  
2283         /* Escape the mountpoint per systemd policy */
2284 @@ -442,7 +440,7 @@ line_worker(char *line, const char *cachefile)
2285                 fprintf(stderr,
2286                     PROGNAME "[%d]: %s: abnormal simplified mountpoint: %s\n",
2287                     getpid(), dataset, p_mountpoint);
2288 -               return (1);
2289 +               goto err;
2290         }
2291  
2292  
2293 @@ -552,8 +550,7 @@ line_worker(char *line, const char *cachefile)
2294          *      files if we're sure they were created by us. (see 5.)
2295          * 2.   We handle files differently based on canmount.
2296          *      Units with canmount=on always have precedence over noauto.
2297 -        *      This is enforced by the noauto_not_on_sem semaphore,
2298 -        *      which is only unlocked when the last canmount=on process exits.
2299 +        *      This is enforced by processing these units before all others.
2300          *      It is important to use p_canmount and not noauto here,
2301          *      since we categorise by canmount while other properties,
2302          *      e.g. org.openzfs.systemd:wanted-by, also modify noauto.
2303 @@ -561,7 +558,7 @@ line_worker(char *line, const char *cachefile)
2304          *      Additionally, we use noauto_files to track the unit file names
2305          *      (which are the systemd-escaped mountpoints) of all (exclusively)
2306          *      noauto datasets that had a file created.
2307 -        * 4.   If the file to be created is found in the tracking array,
2308 +        * 4.   If the file to be created is found in the tracking tree,
2309          *      we do NOT create it.
2310          * 5.   If a file exists for a noauto dataset,
2311          *      we check whether the file name is in the array.
2312 @@ -571,29 +568,14 @@ line_worker(char *line, const char *cachefile)
2313          *      further noauto datasets creating a file for this path again.
2314          */
2315  
2316 -       {
2317 -               sem_t *our_sem = (strcmp(p_canmount, "on") == 0) ?
2318 -                   &noauto_files->noauto_names_sem :
2319 -                   &noauto_files->noauto_not_on_sem;
2320 -               while (sem_wait(our_sem) == -1 && errno == EINTR)
2321 -                       ;
2322 -       }
2323 -
2324         struct stat stbuf;
2325         bool already_exists = fstatat(destdir_fd, mountfile, &stbuf, 0) == 0;
2326 +       bool is_known = tfind(mountfile, &noauto_files, STRCMP) != NULL;
2327  
2328 -       bool is_known = false;
2329 -       for (size_t i = 0; i < noauto_files->noauto_names_len; ++i) {
2330 -               if (strncmp(
2331 -                   noauto_files->noauto_names[i], mountfile, NAME_MAX) == 0) {
2332 -                       is_known = true;
2333 -                       break;
2334 -               }
2335 -       }
2336 -
2337 +       *(tofree++) = (void *)mountfile;
2338         if (already_exists) {
2339                 if (is_known) {
2340 -                       /* If it's in $noauto_files, we must be noauto too */
2341 +                       /* If it's in noauto_files, we must be noauto too */
2342  
2343                         /* See 5 */
2344                         errno = 0;
2345 @@ -614,43 +596,31 @@ line_worker(char *line, const char *cachefile)
2346                 }
2347  
2348                 /* File exists: skip current dataset */
2349 -               if (strcmp(p_canmount, "on") == 0)
2350 -                       sem_post(&noauto_files->noauto_names_sem);
2351 -               return (0);
2352 +               goto end;
2353         } else {
2354                 if (is_known) {
2355                         /* See 4 */
2356 -                       if (strcmp(p_canmount, "on") == 0)
2357 -                               sem_post(&noauto_files->noauto_names_sem);
2358 -                       return (0);
2359 +                       goto end;
2360                 } else if (strcmp(p_canmount, "noauto") == 0) {
2361 -                       if (noauto_files->noauto_names_len ==
2362 -                           noauto_files->noauto_names_max)
2363 +                       if (tsearch(mountfile, &noauto_files, STRCMP) == NULL)
2364                                 fprintf(stderr, PROGNAME "[%d]: %s: "
2365 -                                   "noauto dataset limit (%zu) reached! "
2366 -                                   "Not tracking %s. Please report this to "
2367 -                                   "https://github.com/openzfs/zfs\n",
2368 -                                   getpid(), dataset,
2369 -                                   noauto_files->noauto_names_max, mountfile);
2370 -                       else {
2371 -                               strncpy(noauto_files->noauto_names[
2372 -                                   noauto_files->noauto_names_len],
2373 -                                   mountfile, NAME_MAX);
2374 -                               ++noauto_files->noauto_names_len;
2375 -                       }
2376 +                                   "out of memory for noauto datasets! "
2377 +                                   "Not tracking %s.\n",
2378 +                                   getpid(), dataset, mountfile);
2379 +                       else
2380 +                               /* mountfile escaped to noauto_files */
2381 +                               *(--tofree) = NULL;
2382                 }
2383         }
2384  
2385  
2386         FILE *mountfile_f = fopenat(destdir_fd, mountfile,
2387             O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, "w", 0644);
2388 -       if (strcmp(p_canmount, "on") == 0)
2389 -               sem_post(&noauto_files->noauto_names_sem);
2390         if (!mountfile_f) {
2391                 fprintf(stderr,
2392                     PROGNAME "[%d]: %s: couldn't open %s under %s: %s\n",
2393                     getpid(), dataset, mountfile, destdir, strerror(errno));
2394 -               return (1);
2395 +               goto err;
2396         }
2397  
2398         fprintf(mountfile_f,
2399 @@ -699,12 +669,17 @@ line_worker(char *line, const char *cachefile)
2400         (void) fclose(mountfile_f);
2401  
2402         if (!requiredby && !wantedby)
2403 -               return (0);
2404 +               goto end;
2405  
2406         /* Finally, create the appropriate dependencies */
2407         char *linktgt;
2408 -       if (asprintf(&linktgt, "../%s", mountfile) == -1)
2409 -               EXIT_ENOMEM();
2410 +       if (asprintf(&linktgt, "../%s", mountfile) == -1) {
2411 +               fprintf(stderr, PROGNAME "[%d]: %s: "
2412 +                   "out of memory for dependents of %s!\n",
2413 +                   getpid(), dataset, mountfile);
2414 +               goto err;
2415 +       }
2416 +       *(tofree++) = linktgt;
2417  
2418         char *dependencies[][2] = {
2419                 {"wants", wantedby},
2420 @@ -719,8 +694,14 @@ line_worker(char *line, const char *cachefile)
2421                     reqby;
2422                     reqby = strtok_r(NULL, " ", &toktmp)) {
2423                         char *depdir;
2424 -                       if (asprintf(&depdir, "%s.%s", reqby, (*dep)[0]) == -1)
2425 -                               EXIT_ENOMEM();
2426 +                       if (asprintf(
2427 +                           &depdir, "%s.%s", reqby, (*dep)[0]) == -1) {
2428 +                               fprintf(stderr, PROGNAME "[%d]: %s: "
2429 +                                   "out of memory for dependent dir name "
2430 +                                   "\"%s.%s\"!\n",
2431 +                                   getpid(), dataset, reqby, (*dep)[0]);
2432 +                               continue;
2433 +                       }
2434  
2435                         (void) mkdirat(destdir_fd, depdir, 0755);
2436                         int depdir_fd = openat(destdir_fd, depdir,
2437 @@ -746,7 +727,24 @@ line_worker(char *line, const char *cachefile)
2438                 }
2439         }
2440  
2441 -       return (0);
2442 +end:
2443 +       if (tofree >= tofree_all + nitems(tofree_all)) {
2444 +               /*
2445 +                * This won't happen as-is:
2446 +                * we've got 8 slots and allocate 4 things at most.
2447 +                */
2448 +               fprintf(stderr,
2449 +                   PROGNAME "[%d]: %s: need to free %zu > %zu!\n",
2450 +                   getpid(), dataset, tofree - tofree_all, nitems(tofree_all));
2451 +               ret = tofree - tofree_all;
2452 +       }
2453 +
2454 +       while (tofree-- != tofree_all)
2455 +               free(*tofree);
2456 +       return (ret);
2457 +err:
2458 +       ret = 1;
2459 +       goto end;
2460  }
2461  
2462  
2463 @@ -780,12 +778,11 @@ main(int argc, char **argv)
2464                 if (kmfd >= 0) {
2465                         (void) dup2(kmfd, STDERR_FILENO);
2466                         (void) close(kmfd);
2467 +
2468 +                       setlinebuf(stderr);
2469                 }
2470         }
2471  
2472 -       uint8_t debug = 0;
2473 -
2474 -       argv0 = argv[0];
2475         switch (argc) {
2476         case 1:
2477                 /* Use default */
2478 @@ -844,33 +841,9 @@ main(int argc, char **argv)
2479                 }
2480         }
2481  
2482 -       {
2483 -               /*
2484 -                * We could just get a gigabyte here and Not Care,
2485 -                * but if vm.overcommit_memory=2, then MAP_NORESERVE is ignored
2486 -                * and we'd try (and likely fail) to rip it out of swap
2487 -                */
2488 -               noauto_files = mmap(NULL, 4 * 1024 * 1024,
2489 -                   PROT_READ | PROT_WRITE,
2490 -                   MAP_SHARED | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
2491 -               if (noauto_files == MAP_FAILED) {
2492 -                       fprintf(stderr,
2493 -                           PROGNAME "[%d]: couldn't allocate IPC region: %s\n",
2494 -                           getpid(), strerror(errno));
2495 -                       _exit(1);
2496 -               }
2497 -
2498 -               sem_init(&noauto_files->noauto_not_on_sem, true, 0);
2499 -               sem_init(&noauto_files->noauto_names_sem, true, 1);
2500 -               noauto_files->noauto_names_len = 0;
2501 -               /* Works out to 16447ish, *well* enough */
2502 -               noauto_files->noauto_names_max =
2503 -                   (4 * 1024 * 1024 - sizeof (*noauto_files)) / NAME_MAX;
2504 -       }
2505 -
2506 +       bool debug = false;
2507         char *line = NULL;
2508         size_t linelen = 0;
2509 -       struct timespec time_start = {};
2510         {
2511                 const char *dbgenv = getenv("ZFS_DEBUG");
2512                 if (dbgenv)
2513 @@ -879,7 +852,7 @@ main(int argc, char **argv)
2514                         FILE *cmdline = fopen("/proc/cmdline", "re");
2515                         if (cmdline != NULL) {
2516                                 if (getline(&line, &linelen, cmdline) >= 0)
2517 -                                       debug = strstr(line, "debug") ? 2 : 0;
2518 +                                       debug = strstr(line, "debug");
2519                                 (void) fclose(cmdline);
2520                         }
2521                 }
2522 @@ -888,19 +861,17 @@ main(int argc, char **argv)
2523                         dup2(STDERR_FILENO, STDOUT_FILENO);
2524         }
2525  
2526 -       size_t forked_canmount_on = 0;
2527 -       size_t forked_canmount_not_on = 0;
2528 -       size_t canmount_on_pids_len = 128;
2529 -       pid_t *canmount_on_pids =
2530 -           malloc(canmount_on_pids_len * sizeof (*canmount_on_pids));
2531 -       if (canmount_on_pids == NULL)
2532 -               canmount_on_pids_len = 0;
2533 -
2534 +       struct timespec time_start = {};
2535         if (debug)
2536                 clock_gettime(CLOCK_MONOTONIC_RAW, &time_start);
2537  
2538 -       ssize_t read;
2539 -       pid_t pid;
2540 +       struct line {
2541 +               char *line;
2542 +               const char *fname;
2543 +               struct line *next;
2544 +       } *lines_canmount_not_on = NULL;
2545 +
2546 +       int ret = 0;
2547         struct dirent *cachent;
2548         while ((cachent = readdir(fslist_dir)) != NULL) {
2549                 if (strcmp(cachent->d_name, ".") == 0 ||
2550 @@ -916,129 +887,67 @@ main(int argc, char **argv)
2551                         continue;
2552                 }
2553  
2554 +               const char *filename = FREE_STATICS ? "(elided)" : NULL;
2555 +
2556 +               ssize_t read;
2557                 while ((read = getline(&line, &linelen, cachefile)) >= 0) {
2558                         line[read - 1] = '\0'; /* newline */
2559  
2560 -                       switch (pid = fork()) {
2561 -                       case -1:
2562 -                               fprintf(stderr,
2563 -                                   PROGNAME "[%d]: couldn't fork for %s: %s\n",
2564 -                                   getpid(), line, strerror(errno));
2565 -                               break;
2566 -                       case 0: /* child */
2567 -                               _exit(line_worker(line, cachent->d_name));
2568 -                       default: { /* parent */
2569 -                               char *tmp;
2570 -                               char *dset = strtok_r(line, "\t", &tmp);
2571 -                               strtok_r(NULL, "\t", &tmp);
2572 -                               char *canmount = strtok_r(NULL, "\t", &tmp);
2573 -                               bool canmount_on =
2574 -                                   canmount && strncmp(canmount, "on", 2) == 0;
2575 -
2576 -                               if (debug >= 2)
2577 -                                       printf(PROGNAME ": forked %d, "
2578 -                                           "canmount_on=%d, dataset=%s\n",
2579 -                                           (int)pid, canmount_on, dset);
2580 -
2581 -                               if (canmount_on &&
2582 -                                   forked_canmount_on ==
2583 -                                   canmount_on_pids_len) {
2584 -                                       size_t new_len =
2585 -                                           (canmount_on_pids_len ?: 16) * 2;
2586 -                                       void *new_pidlist =
2587 -                                           realloc(canmount_on_pids,
2588 -                                           new_len *
2589 -                                           sizeof (*canmount_on_pids));
2590 -                                       if (!new_pidlist) {
2591 -                                               fprintf(stderr,
2592 -                                                   PROGNAME "[%d]: "
2593 -                                                   "out of memory! "
2594 -                                                   "Mount ordering may be "
2595 -                                                   "affected.\n", getpid());
2596 -                                               continue;
2597 -                                       }
2598 -
2599 -                                       canmount_on_pids = new_pidlist;
2600 -                                       canmount_on_pids_len = new_len;
2601 -                               }
2602 +                       char *canmount = line;
2603 +                       canmount += strcspn(canmount, "\t");
2604 +                       canmount += strspn(canmount, "\t");
2605 +                       canmount += strcspn(canmount, "\t");
2606 +                       canmount += strspn(canmount, "\t");
2607 +                       bool canmount_on = strncmp(canmount, "on", 2) == 0;
2608  
2609 -                               if (canmount_on) {
2610 -                                       canmount_on_pids[forked_canmount_on] =
2611 -                                           pid;
2612 -                                       ++forked_canmount_on;
2613 -                               } else
2614 -                                       ++forked_canmount_not_on;
2615 -                               break;
2616 -                       }
2617 +                       if (canmount_on)
2618 +                               ret |= line_worker(line, cachent->d_name);
2619 +                       else {
2620 +                               if (filename == NULL)
2621 +                                       filename =
2622 +                                           strdup(cachent->d_name) ?: "(?)";
2623 +
2624 +                               struct line *l = calloc(1, sizeof (*l));
2625 +                               char *nl = strdup(line);
2626 +                               if (l == NULL || nl == NULL) {
2627 +                                       fprintf(stderr, PROGNAME "[%d]: "
2628 +                                           "out of memory for \"%s\" in %s\n",
2629 +                                           getpid(), line, cachent->d_name);
2630 +                                       free(l);
2631 +                                       free(nl);
2632 +                                       continue;
2633 +                               }
2634 +                               l->line = nl;
2635 +                               l->fname = filename;
2636 +                               l->next = lines_canmount_not_on;
2637 +                               lines_canmount_not_on = l;
2638                         }
2639                 }
2640  
2641 -               (void) fclose(cachefile);
2642 +               fclose(cachefile);
2643         }
2644         free(line);
2645  
2646 -       if (forked_canmount_on == 0) {
2647 -               /* No canmount=on processes to finish, so don't deadlock here */
2648 -               for (size_t i = 0; i < forked_canmount_not_on; ++i)
2649 -                       sem_post(&noauto_files->noauto_not_on_sem);
2650 -       } else {
2651 -               /* Likely a no-op, since we got these from a narrow fork loop */
2652 -               qsort(canmount_on_pids, forked_canmount_on,
2653 -                   sizeof (*canmount_on_pids), PID_T_CMP);
2654 -       }
2655 +       while (lines_canmount_not_on) {
2656 +               struct line *l = lines_canmount_not_on;
2657 +               lines_canmount_not_on = l->next;
2658  
2659 -       int status, ret = 0;
2660 -       struct rusage usage;
2661 -       size_t forked_canmount_on_max = forked_canmount_on;
2662 -       while ((pid = wait4(-1, &status, 0, &usage)) != -1) {
2663 -               ret |= WEXITSTATUS(status) | WTERMSIG(status);
2664 -
2665 -               if (forked_canmount_on != 0) {
2666 -                       if (bsearch(&pid, canmount_on_pids,
2667 -                           forked_canmount_on_max, sizeof (*canmount_on_pids),
2668 -                           PID_T_CMP))
2669 -                               --forked_canmount_on;
2670 -
2671 -                       if (forked_canmount_on == 0) {
2672 -                               /*
2673 -                                * All canmount=on processes have finished,
2674 -                                * let all the lower-priority ones finish now
2675 -                                */
2676 -                               for (size_t i = 0;
2677 -                                   i < forked_canmount_not_on; ++i)
2678 -                                       sem_post(
2679 -                                           &noauto_files->noauto_not_on_sem);
2680 -                       }
2681 +               ret |= line_worker(l->line, l->fname);
2682 +               if (FREE_STATICS) {
2683 +                       free(l->line);
2684 +                       free(l);
2685                 }
2686 -
2687 -               if (debug >= 2)
2688 -                       printf(PROGNAME ": %d done, user=%llu.%06us, "
2689 -                           "system=%llu.%06us, maxrss=%ldB, ex=0x%x\n",
2690 -                           (int)pid,
2691 -                           (unsigned long long) usage.ru_utime.tv_sec,
2692 -                           (unsigned int) usage.ru_utime.tv_usec,
2693 -                           (unsigned long long) usage.ru_stime.tv_sec,
2694 -                           (unsigned int) usage.ru_stime.tv_usec,
2695 -                           usage.ru_maxrss * 1024, status);
2696         }
2697  
2698         if (debug) {
2699                 struct timespec time_end = {};
2700                 clock_gettime(CLOCK_MONOTONIC_RAW, &time_end);
2701  
2702 +               struct rusage usage;
2703                 getrusage(RUSAGE_SELF, &usage);
2704                 printf(
2705                     "\n"
2706 -                   PROGNAME ": self    : "
2707 -                   "user=%llu.%06us, system=%llu.%06us, maxrss=%ldB\n",
2708 -                   (unsigned long long) usage.ru_utime.tv_sec,
2709 -                   (unsigned int) usage.ru_utime.tv_usec,
2710 -                   (unsigned long long) usage.ru_stime.tv_sec,
2711 -                   (unsigned int) usage.ru_stime.tv_usec,
2712 -                   usage.ru_maxrss * 1024);
2713 -
2714 -               getrusage(RUSAGE_CHILDREN, &usage);
2715 -               printf(PROGNAME ": children: "
2716 +                   PROGNAME ": "
2717                     "user=%llu.%06us, system=%llu.%06us, maxrss=%ldB\n",
2718                     (unsigned long long) usage.ru_utime.tv_sec,
2719                     (unsigned int) usage.ru_utime.tv_usec,
2720 @@ -1068,7 +977,7 @@ main(int argc, char **argv)
2721                     time_init.tv_nsec / 1000000000;
2722                 time_init.tv_nsec %= 1000000000;
2723  
2724 -               printf(PROGNAME ": wall    : "
2725 +               printf(PROGNAME ": "
2726                     "total=%llu.%09llus = "
2727                     "init=%llu.%09llus + real=%llu.%09llus\n",
2728                     (unsigned long long) time_init.tv_sec,
2729 @@ -1077,7 +986,15 @@ main(int argc, char **argv)
2730                     (unsigned long long) time_start.tv_nsec,
2731                     (unsigned long long) time_end.tv_sec,
2732                     (unsigned long long) time_end.tv_nsec);
2733 +
2734 +               fflush(stdout);
2735         }
2736  
2737 +       if (FREE_STATICS) {
2738 +               closedir(fslist_dir);
2739 +               tdestroy(noauto_files, free);
2740 +               tdestroy(known_pools, free);
2741 +               regfree(&uri_regex);
2742 +       }
2743         _exit(ret);
2744  }
2745 diff --git a/etc/zfs/Makefile.am b/etc/zfs/Makefile.am
2746 index 3dee81c75..1fc57e158 100644
2747 --- a/etc/zfs/Makefile.am
2748 +++ b/etc/zfs/Makefile.am
2749 @@ -10,9 +10,10 @@ dist_pkgsysconf_DATA = \
2750         vdev_id.conf.multipath.example \
2751         vdev_id.conf.scsi.example
2752  
2753 -pkgsysconf_SCRIPTS = \
2754 +pkgsysconf_DATA = \
2755         zfs-functions
2756  
2757 -SUBSTFILES += $(pkgsysconf_SCRIPTS)
2758 +SUBSTFILES += $(pkgsysconf_DATA)
2759  
2760 +SHELLCHECKSCRIPTS = $(pkgsysconf_DATA)
2761  SHELLCHECK_SHELL = dash # local variables
2762 diff --git a/include/libzfs.h b/include/libzfs.h
2763 index eeb4daae7..d55e3f2e7 100644
2764 --- a/include/libzfs.h
2765 +++ b/include/libzfs.h
2766 @@ -795,9 +795,10 @@ extern int zfs_receive(libzfs_handle_t *, const char *, nvlist_t *,
2767      recvflags_t *, int, avl_tree_t *);
2768  
2769  typedef enum diff_flags {
2770 -       ZFS_DIFF_PARSEABLE = 0x1,
2771 -       ZFS_DIFF_TIMESTAMP = 0x2,
2772 -       ZFS_DIFF_CLASSIFY = 0x4
2773 +       ZFS_DIFF_PARSEABLE = 1 << 0,
2774 +       ZFS_DIFF_TIMESTAMP = 1 << 1,
2775 +       ZFS_DIFF_CLASSIFY = 1 << 2,
2776 +       ZFS_DIFF_NO_MANGLE = 1 << 3
2777  } diff_flags_t;
2778  
2779  extern int zfs_show_diffs(zfs_handle_t *, int, const char *, const char *,
2780 diff --git a/include/libzfs_impl.h b/include/libzfs_impl.h
2781 index 96b11dad1..043ff9cd7 100644
2782 --- a/include/libzfs_impl.h
2783 +++ b/include/libzfs_impl.h
2784 @@ -234,6 +234,7 @@ typedef struct differ_info {
2785         boolean_t scripted;
2786         boolean_t classify;
2787         boolean_t timestamped;
2788 +       boolean_t no_mangle;
2789         uint64_t shares;
2790         int zerr;
2791         int cleanupfd;
2792 diff --git a/include/os/freebsd/zfs/sys/zfs_znode_impl.h b/include/os/freebsd/zfs/sys/zfs_znode_impl.h
2793 index edb28d041..3d93525b4 100644
2794 --- a/include/os/freebsd/zfs/sys/zfs_znode_impl.h
2795 +++ b/include/os/freebsd/zfs/sys/zfs_znode_impl.h
2796 @@ -123,25 +123,29 @@ extern minor_t zfsdev_minor_alloc(void);
2797  #define        zn_rlimit_fsize(zp, uio) \
2798      vn_rlimit_fsize(ZTOV(zp), GET_UIO_STRUCT(uio), zfs_uio_td(uio))
2799  
2800 +#define        ZFS_ENTER_ERROR(zfsvfs, error) do {                     \
2801 +       ZFS_TEARDOWN_ENTER_READ((zfsvfs), FTAG);                \
2802 +       if (__predict_false((zfsvfs)->z_unmounted)) {           \
2803 +               ZFS_TEARDOWN_EXIT_READ(zfsvfs, FTAG);           \
2804 +               return (error);                                 \
2805 +       }                                                       \
2806 +} while (0)
2807 +
2808  /* Called on entry to each ZFS vnode and vfs operation  */
2809 -#define        ZFS_ENTER(zfsvfs) \
2810 -       { \
2811 -               ZFS_TEARDOWN_ENTER_READ((zfsvfs), FTAG); \
2812 -               if (__predict_false((zfsvfs)->z_unmounted)) { \
2813 -                       ZFS_TEARDOWN_EXIT_READ(zfsvfs, FTAG); \
2814 -                       return (EIO); \
2815 -               } \
2816 -       }
2817 +#define        ZFS_ENTER(zfsvfs)       ZFS_ENTER_ERROR(zfsvfs, EIO)
2818  
2819  /* Must be called before exiting the vop */
2820 -#define        ZFS_EXIT(zfsvfs) ZFS_TEARDOWN_EXIT_READ(zfsvfs, FTAG)
2821 +#define        ZFS_EXIT(zfsvfs)        ZFS_TEARDOWN_EXIT_READ(zfsvfs, FTAG)
2822 +
2823 +#define        ZFS_VERIFY_ZP_ERROR(zp, error) do {                     \
2824 +       if (__predict_false((zp)->z_sa_hdl == NULL)) {          \
2825 +               ZFS_EXIT((zp)->z_zfsvfs);                       \
2826 +               return (error);                                 \
2827 +       }                                                       \
2828 +} while (0)
2829  
2830  /* Verifies the znode is valid */
2831 -#define        ZFS_VERIFY_ZP(zp) \
2832 -       if (__predict_false((zp)->z_sa_hdl == NULL)) { \
2833 -               ZFS_EXIT((zp)->z_zfsvfs); \
2834 -               return (EIO); \
2835 -       } \
2836 +#define        ZFS_VERIFY_ZP(zp)       ZFS_VERIFY_ZP_ERROR(zp, EIO)
2837  
2838  /*
2839   * Macros for dealing with dmu_buf_hold
2840 diff --git a/include/sys/dbuf.h b/include/sys/dbuf.h
2841 index d2c175af6..e7289c0fe 100644
2842 --- a/include/sys/dbuf.h
2843 +++ b/include/sys/dbuf.h
2844 @@ -321,13 +321,12 @@ typedef struct dmu_buf_impl {
2845         uint8_t db_dirtycnt;
2846  } dmu_buf_impl_t;
2847  
2848 -/* Note: the dbuf hash table is exposed only for the mdb module */
2849 -#define        DBUF_MUTEXES 2048
2850 -#define        DBUF_HASH_MUTEX(h, idx) (&(h)->hash_mutexes[(idx) & (DBUF_MUTEXES-1)])
2851 +#define        DBUF_RWLOCKS 8192
2852 +#define        DBUF_HASH_RWLOCK(h, idx) (&(h)->hash_rwlocks[(idx) & (DBUF_RWLOCKS-1)])
2853  typedef struct dbuf_hash_table {
2854         uint64_t hash_table_mask;
2855         dmu_buf_impl_t **hash_table;
2856 -       kmutex_t hash_mutexes[DBUF_MUTEXES] ____cacheline_aligned;
2857 +       krwlock_t hash_rwlocks[DBUF_RWLOCKS] ____cacheline_aligned;
2858  } dbuf_hash_table_t;
2859  
2860  typedef void (*dbuf_prefetch_fn)(void *, boolean_t);
2861 diff --git a/include/sys/spa_impl.h b/include/sys/spa_impl.h
2862 index cb2c49e58..c8987e2e6 100644
2863 --- a/include/sys/spa_impl.h
2864 +++ b/include/sys/spa_impl.h
2865 @@ -370,6 +370,7 @@ struct spa {
2866         boolean_t       spa_is_root;            /* pool is root */
2867         int             spa_minref;             /* num refs when first opened */
2868         spa_mode_t      spa_mode;               /* SPA_MODE_{READ|WRITE} */
2869 +       boolean_t       spa_read_spacemaps;     /* spacemaps available if ro */
2870         spa_log_state_t spa_log_state;          /* log state */
2871         uint64_t        spa_autoexpand;         /* lun expansion on/off */
2872         ddt_t           *spa_ddt[ZIO_CHECKSUM_FUNCTIONS]; /* in-core DDTs */
2873 diff --git a/lib/libzfs/libzfs_diff.c b/lib/libzfs/libzfs_diff.c
2874 index d46e23a2f..57a7c1556 100644
2875 --- a/lib/libzfs/libzfs_diff.c
2876 +++ b/lib/libzfs/libzfs_diff.c
2877 @@ -122,9 +122,9 @@ stream_bytes(FILE *fp, const char *string)
2878  
2879         while ((c = *string++) != '\0') {
2880                 if (c > ' ' && c != '\\' && c < '\177') {
2881 -                       (void) fprintf(fp, "%c", c);
2882 +                       (void) fputc(c, fp);
2883                 } else {
2884 -                       (void) fprintf(fp, "\\%04o", (uint8_t)c);
2885 +                       (void) fprintf(fp, "\\%04hho", (uint8_t)c);
2886                 }
2887         }
2888  }
2889 @@ -176,8 +176,13 @@ print_what(FILE *fp, mode_t what)
2890  static void
2891  print_cmn(FILE *fp, differ_info_t *di, const char *file)
2892  {
2893 -       stream_bytes(fp, di->dsmnt);
2894 -       stream_bytes(fp, file);
2895 +       if (!di->no_mangle) {
2896 +               stream_bytes(fp, di->dsmnt);
2897 +               stream_bytes(fp, file);
2898 +       } else {
2899 +               (void) fputs(di->dsmnt, fp);
2900 +               (void) fputs(file, fp);
2901 +       }
2902  }
2903  
2904  static void
2905 @@ -752,6 +757,7 @@ zfs_show_diffs(zfs_handle_t *zhp, int outfd, const char *fromsnap,
2906         di.scripted = (flags & ZFS_DIFF_PARSEABLE);
2907         di.classify = (flags & ZFS_DIFF_CLASSIFY);
2908         di.timestamped = (flags & ZFS_DIFF_TIMESTAMP);
2909 +       di.no_mangle = (flags & ZFS_DIFF_NO_MANGLE);
2910  
2911         di.outputfd = outfd;
2912         di.datafd = pipefd[0];
2913 diff --git a/lib/libzfs/libzfs_import.c b/lib/libzfs/libzfs_import.c
2914 index 64fa31c67..ddaa5de5d 100644
2915 --- a/lib/libzfs/libzfs_import.c
2916 +++ b/lib/libzfs/libzfs_import.c
2917 @@ -146,10 +146,10 @@ zpool_clear_label(int fd)
2918         struct stat64 statbuf;
2919         int l;
2920         vdev_label_t *label;
2921 -       l2arc_dev_hdr_phys_t *l2dhdr;
2922 +       l2arc_dev_hdr_phys_t *l2dhdr = NULL;
2923         uint64_t size;
2924 -       int labels_cleared = 0, header_cleared = 0;
2925 -       boolean_t clear_l2arc_header = B_FALSE;
2926 +       int labels_cleared = 0;
2927 +       boolean_t clear_l2arc_header = B_FALSE, header_cleared = B_FALSE;
2928  
2929         if (fstat64_blk(fd, &statbuf) == -1)
2930                 return (0);
2931 @@ -219,13 +219,10 @@ zpool_clear_label(int fd)
2932         }
2933  
2934         /* Clear the L2ARC header. */
2935 -       if (clear_l2arc_header) {
2936 -               memset(l2dhdr, 0, sizeof (l2arc_dev_hdr_phys_t));
2937 -               if (pwrite64(fd, l2dhdr, sizeof (l2arc_dev_hdr_phys_t),
2938 -                   VDEV_LABEL_START_SIZE) == sizeof (l2arc_dev_hdr_phys_t)) {
2939 -                       header_cleared++;
2940 -               }
2941 -       }
2942 +       if (clear_l2arc_header &&
2943 +           pwrite64(fd, l2dhdr, sizeof (l2arc_dev_hdr_phys_t),
2944 +           VDEV_LABEL_START_SIZE) == sizeof (l2arc_dev_hdr_phys_t))
2945 +                       header_cleared = B_TRUE;
2946  
2947         free(label);
2948         free(l2dhdr);
2949 @@ -233,6 +230,9 @@ zpool_clear_label(int fd)
2950         if (labels_cleared == 0)
2951                 return (-1);
2952  
2953 +       if (clear_l2arc_header && !header_cleared)
2954 +               return (-1);
2955 +
2956         return (0);
2957  }
2958  
2959 diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c
2960 index b67c9b30c..a944cc164 100644
2961 --- a/lib/libzfs/libzfs_sendrecv.c
2962 +++ b/lib/libzfs/libzfs_sendrecv.c
2963 @@ -2133,7 +2133,6 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
2964         avl_tree_t *fsavl = NULL;
2965         static uint64_t holdseq;
2966         int spa_version;
2967 -       int featureflags = 0;
2968         FILE *fout;
2969  
2970         (void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
2971 @@ -2145,17 +2144,6 @@ zfs_send(zfs_handle_t *zhp, const char *fromsnap, const char *tosnap,
2972                 return (zfs_error(zhp->zfs_hdl, EZFS_NOENT, errbuf));
2973         }
2974  
2975 -       if (zhp->zfs_type == ZFS_TYPE_FILESYSTEM) {
2976 -               uint64_t version;
2977 -               version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION);
2978 -               if (version >= ZPL_VERSION_SA) {
2979 -                       featureflags |= DMU_BACKUP_FEATURE_SA_SPILL;
2980 -               }
2981 -       }
2982 -
2983 -       if (flags->holds)
2984 -               featureflags |= DMU_BACKUP_FEATURE_HOLDS;
2985 -
2986         if (flags->replicate || flags->doall || flags->props ||
2987             flags->holds || flags->backup) {
2988                 char full_tosnap_name[ZFS_MAX_DATASET_NAME_LEN];
2989 @@ -2522,8 +2510,7 @@ zfs_send_one(zfs_handle_t *zhp, const char *from, int fd, sendflags_t *flags,
2990  
2991         if (flags->progress) {
2992                 void *status = NULL;
2993 -               if (err != 0)
2994 -                       (void) pthread_cancel(ptid);
2995 +               (void) pthread_cancel(ptid);
2996                 (void) pthread_join(ptid, &status);
2997                 int error = (int)(uintptr_t)status;
2998                 if (error != 0 && status != PTHREAD_CANCELED)
2999 diff --git a/lib/libzutil/zutil_import.c b/lib/libzutil/zutil_import.c
3000 index d91953813..f6f125e7a 100644
3001 --- a/lib/libzutil/zutil_import.c
3002 +++ b/lib/libzutil/zutil_import.c
3003 @@ -1791,16 +1791,13 @@ zpool_find_config(void *hdl, const char *target, nvlist_t **configp,
3004         nvlist_t *match = NULL;
3005         nvlist_t *config = NULL;
3006         char *sepp = NULL;
3007 -       char sep = '\0';
3008         int count = 0;
3009         char *targetdup = strdup(target);
3010  
3011         *configp = NULL;
3012  
3013 -       if ((sepp = strpbrk(targetdup, "/@")) != NULL) {
3014 -               sep = *sepp;
3015 +       if ((sepp = strpbrk(targetdup, "/@")) != NULL)
3016                 *sepp = '\0';
3017 -       }
3018  
3019         pools = zpool_search_import(hdl, args, pco);
3020  
3021 diff --git a/man/Makefile.am b/man/Makefile.am
3022 index 8ab1b7572..64650c2b9 100644
3023 --- a/man/Makefile.am
3024 +++ b/man/Makefile.am
3025 @@ -15,6 +15,7 @@ dist_man_MANS = \
3026         man4/spl.4 \
3027         man4/zfs.4 \
3028         \
3029 +       man7/dracut.zfs.7 \
3030         man7/zpool-features.7 \
3031         man7/zfsconcepts.7 \
3032         man7/zfsprops.7 \
3033 diff --git a/man/man4/zfs.4 b/man/man4/zfs.4
3034 index 657afc616..3eeed8f43 100644
3035 --- a/man/man4/zfs.4
3036 +++ b/man/man4/zfs.4
3037 @@ -1581,12 +1581,12 @@ Allow no-operation writes.
3038  The occurrence of nopwrites will further depend on other pool properties
3039  .Pq i.a. the checksumming and compression algorithms .
3040  .
3041 -.It Sy zfs_dmu_offset_next_sync Ns = Ns Sy 0 Ns | Ns 1 Pq int
3042 +.It Sy zfs_dmu_offset_next_sync Ns = Ns Sy 1 Ns | Ns 0 Pq int
3043  Enable forcing TXG sync to find holes.
3044 -When enabled forces ZFS to act like prior versions when
3045 +When enabled forces ZFS to sync data when
3046  .Sy SEEK_HOLE No or Sy SEEK_DATA
3047 -flags are used, which, when a dnode is dirty,
3048 -causes TXGs to be synced so that this data can be found.
3049 +flags are used allowing holes in a file to be accurately reported.
3050 +When disabled holes will not be reported in recently dirtied files.
3051  .
3052  .It Sy zfs_pd_bytes_max Ns = Ns Sy 52428800 Ns B Po 50MB Pc Pq int
3053  The number of bytes which should be prefetched during a pool traversal, like
3054 diff --git a/man/man7/dracut.zfs.7 b/man/man7/dracut.zfs.7
3055 new file mode 100644
3056 index 000000000..0f446fe2f
3057 --- /dev/null
3058 +++ b/man/man7/dracut.zfs.7
3059 @@ -0,0 +1,278 @@
3060 +.\" SPDX-License-Identifier: 0BSD
3061 +.\"
3062 +.Dd April 4, 2022
3063 +.Dt DRACUT.ZFS 7
3064 +.Os
3065 +.
3066 +.Sh NAME
3067 +.Nm dracut.zfs
3068 +.Nd overview of ZFS dracut hooks
3069 +.
3070 +.Sh SYNOPSIS
3071 +.Bd -literal -compact
3072 +                      parse-zfs.sh \(-> dracut-cmdline.service
3073 +                          |                     \(da
3074 +                          |                     …
3075 +                          |                     \(da
3076 +                          \e\(em\(em\(em\(em\(em\(em\(em\(em\(-> dracut-initqueue.service
3077 +                                                |                      zfs-import-opts.sh
3078 +   zfs-load-module.service                      \(da                          |       |
3079 +     |                  |                sysinit.target                    \(da       |
3080 +     \(da                  |                       |        zfs-import-scan.service   \(da
3081 +zfs-import-scan.service \(da                       \(da           | zfs-import-cache.service
3082 +     |   zfs-import-cache.service         basic.target      |     |
3083 +     \e__________________|                       |           \(da     \(da
3084 +                        \(da                       |     zfs-load-key.sh
3085 +     zfs-env-bootfs.service                     |         |
3086 +                        \(da                       \(da         \(da
3087 +                 zfs-import.target \(-> dracut-pre-mount.service
3088 +                        |          \(ua            |
3089 +                        | dracut-zfs-generator  |
3090 +                        |  ____________________/|
3091 +                        |/                      \(da
3092 +                        |                   sysroot.mount \(<-\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em dracut-zfs-generator
3093 +                        |                       |                                        \(da   |
3094 +                        |                       \(da            sysroot-{usr,etc,lib,&c.}.mount |
3095 +                        |             initrd-root-fs.target \(<-\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em\(em or                 \(da
3096 +                        |                       |              zfs-nonroot-necessities.service
3097 +                        |                       \(da                                 |
3098 +                        \(da             dracut-mount.service                        |
3099 +       zfs-snapshot-bootfs.service              |                                 |
3100 +                        |                       \(da                                 |
3101 +                        \(da                       …                                 |
3102 +       zfs-rollback-bootfs.service              |                                 |
3103 +                        |                       \(da                                 |
3104 +                        |               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/
3105 +                        |                       |
3106 +                        |                       \(da
3107 +                        |                initrd-fs.target
3108 +                        \e______________________ |
3109 +                                               \e|
3110 +                                                \(da
3111 +        export-zfs.sh                      initrd.target
3112 +              |                                 |
3113 +              \(da                                 \(da
3114 +   dracut-shutdown.service                      …
3115 +                                                |
3116 +                                                \(da
3117 +                 zfs-needshutdown.sh \(-> initrd-cleanup.service
3118 +.Ed
3119 +.Pp
3120 +Compare
3121 +.Xr dracut.bootup 7
3122 +for the full flowchart.
3123 +.
3124 +.Sh DESCRIPTION
3125 +Under dracut, booting with
3126 +.No ZFS-on- Ns Pa /
3127 +is facilitated by a number of hooks in the
3128 +.Nm 90zfs
3129 +module.
3130 +.Pp
3131 +Booting into a ZFS dataset requires
3132 +.Sy mountpoint Ns = Ns Pa /
3133 +to be set on the dataset containing the root filesystem (henceforth "the boot dataset") and at the very least either the
3134 +.Sy bootfs
3135 +property to be set to that dataset, or the
3136 +.Sy root=
3137 +kernel cmdline (or dracut drop-in) argument to specify it.
3138 +.Pp
3139 +All children of the boot dataset with
3140 +.Sy canmount Ns = Ns Sy on
3141 +with
3142 +.Sy mountpoint Ns s
3143 +matching
3144 +.Pa /etc , /bin , /lib , /lib?? , /libx32 , No and Pa /usr
3145 +globs are deemed essential and will be mounted as well.
3146 +.Pp
3147 +.Xr zfs-mount-generator 8
3148 +is recommended for proper functioning of the system afterward (correct mount properties, remounting, &c.).
3149 +.
3150 +.Sh CMDLINE
3151 +.Ss Standard
3152 +.Bl -tag -compact -width ".Sy root=zfs:AUTO , root=zfs: , root=zfs , Op Sy root="
3153 +.It Sy root=zfs:\& Ns Ar dataset , Sy root=ZFS= Ns Ar dataset
3154 +Use
3155 +.Ar dataset
3156 +as the boot dataset.
3157 +All pluses
3158 +.Pq Sq +
3159 +are replaced with spaces
3160 +.Pq Sq \  .
3161 +.
3162 +.It Sy root=zfs:AUTO , root=zfs:\& , root=zfs , Op Sy root=
3163 +After import, search for the first pool with the
3164 +.Sy bootfs
3165 +property set, use its value as-if specified as the
3166 +.Ar dataset
3167 +above.
3168 +.
3169 +.It Sy rootfstype=zfs root= Ns Ar dataset
3170 +Equivalent to
3171 +.Sy root=zfs:\& Ns Ar dataset .
3172 +.
3173 +.It Sy rootfstype=zfs Op Sy root=
3174 +Equivalent to
3175 +.Sy root=zfs:AUTO .
3176 +.
3177 +.It Sy rootflags= Ns Ar flags
3178 +Mount the boot dataset with
3179 +.Fl o Ar flags ;
3180 +cf.\&
3181 +.Sx Temporary Mount Point Properties
3182 +in
3183 +.Xr zfsprops 7 .
3184 +These properties will not last, since all filesystems will be re-mounted from the real root.
3185 +.
3186 +.It Sy debug
3187 +If specified,
3188 +.Nm dracut-zfs-generator
3189 +logs to the journal.
3190 +.El
3191 +.Pp
3192 +Be careful about setting neither
3193 +.Sy rootfstype=zfs
3194 +nor
3195 +.Sy root=zfs:\& Ns Ar dataset
3196 +\(em other automatic boot selection methods, like
3197 +.Nm systemd-gpt-auto-generator
3198 +and
3199 +.Nm systemd-fstab-generator
3200 +might take precedent.
3201 +.
3202 +.Ss ZFS-specific
3203 +.Bl -tag -compact -width ".Sy bootfs.snapshot Ns Op Sy = Ns Ar snapshot-name"
3204 +.It Sy bootfs.snapshot Ns Op Sy = Ns Ar snapshot-name
3205 +Execute
3206 +.Nm zfs Cm snapshot Ar boot-dataset Ns Sy @ Ns Ar snapshot-name
3207 +before pivoting to the real root.
3208 +.Ar snapshot-name
3209 +defaults to the current kernel release.
3210 +.
3211 +.It Sy bootfs.rollback Ns Op Sy = Ns Ar snapshot-name
3212 +Execute
3213 +.Nm zfs Cm snapshot Fl Rf Ar boot-dataset Ns Sy @ Ns Ar snapshot-name
3214 +before pivoting to the real root.
3215 +.Ar snapshot-name
3216 +defaults to the current kernel release.
3217 +.
3218 +.It Sy spl_hostid= Ns Ar host-id
3219 +Use
3220 +.Xr zgenhostid 8
3221 +to set the host ID to
3222 +.Ar host-id ;
3223 +otherwise,
3224 +.Pa /etc/hostid
3225 +inherited from the real root is used.
3226 +.
3227 +.It Sy zfs_force , zfs.force , zfsforce
3228 +Appends
3229 +.Fl f
3230 +to all
3231 +.Nm zpool Cm import
3232 +invocations; primarily useful in conjunction with
3233 +.Sy spl_hostid= ,
3234 +or if no host ID was inherited.
3235 +.El
3236 +.
3237 +.Sh FILES
3238 +.Bl -tag -width 0
3239 +.It Pa parse-zfs.sh Pq Sy cmdline
3240 +Processes
3241 +.Sy spl_hostid= .
3242 +If
3243 +.Sy root=
3244 +matches a known pattern, above, provides
3245 +.Pa /dev/root
3246 +and delays the initqueue until
3247 +.Xr zfs 4
3248 +is loaded,
3249 +.
3250 +.It Pa zfs-import-opts.sh Pq Nm systemd No environment generator
3251 +Turns
3252 +.Sy zfs_force , zfs.force , No or Sy zfsforce
3253 +into
3254 +.Ev ZPOOL_IMPORT_OPTS Ns = Ns Fl f
3255 +for
3256 +.Pa zfs-import-scan.service
3257 +or
3258 +.Pa zfs-import-cache.service .
3259 +.
3260 +.It Pa zfs-load-key.sh Pq Sy pre-mount
3261 +Loads encryption keys for the boot dataset and its essential descendants.
3262 +.Bl -tag -compact -offset 4n -width ".Sy keylocation Ns = Ns Sy https:// Ns Ar URL , Sy keylocation Ns = Ns Sy http:// Ns Ar URL"
3263 +.It Sy keylocation Ns = Ns Sy prompt
3264 +Is prompted for via
3265 +.Nm systemd-ask-password
3266 +thrice.
3267 +.
3268 +.It Sy keylocation Ns = Ns Sy https:// Ns Ar URL , Sy keylocation Ns = Ns Sy http:// Ns Ar URL
3269 +.Pa network-online.target
3270 +is started before loading.
3271 +.
3272 +.It Sy keylocation Ns = Ns Sy file:// Ns Ar path
3273 +If
3274 +.Ar path
3275 +doesn't exist,
3276 +.Nm udevadm No is Cm settle Ns d .
3277 +If it still doesn't, it's waited for for up to
3278 +.Sy 10 Ns s .
3279 +.El
3280 +.
3281 +.It Pa zfs-env-bootfs.service Pq Nm systemd No service
3282 +After pool import, sets
3283 +.Ev BOOTFS Ns =
3284 +in the systemd environment to the first non-null
3285 +.Sy bootfs
3286 +value in iteration order.
3287 +.
3288 +.It Pa dracut-zfs-generator Pq Nm systemd No generator
3289 +Generates
3290 +.Pa sysroot.mount Pq using Sy rootflags= , No if any .
3291 +If an explicit boot dataset was specified, also generates essential mountpoints
3292 +.Pq Pa sysroot-etc.mount , sysroot-bin.mount , No &c.\& ,
3293 +otherwise generates
3294 +.Pa zfs-nonroot-necessities.service
3295 +which mounts them explicitly after
3296 +.Pa /sysroot
3297 +using
3298 +.Ev BOOTFS Ns = .
3299 +.
3300 +.It Pa zfs-snapshot-bootfs.service , zfs-rollback-bootfs.service Pq Nm systemd No services
3301 +Consume
3302 +.Sy bootfs.snapshot
3303 +and
3304 +.Sy bootfs.rollback
3305 +as described in
3306 +.Sx CMDLINE  .
3307 +Use
3308 +.Ev BOOTFS Ns =
3309 +if no explicit boot dataset was specified.
3310 +.
3311 +.It Pa zfs-needshutdown.sh Pq Sy cleanup
3312 +If any pools were imported, signals that shutdown hooks are required.
3313 +.
3314 +.It Pa export-zfs.sh Pq Sy shutdown
3315 +Forcibly exports all pools.
3316 +.
3317 +.It Pa /etc/hostid , /etc/zfs/zpool.cache , /etc/zfs/vdev_id.conf Pq regular files
3318 +Included verbatim, hostonly.
3319 +.
3320 +.It Pa mount-zfs.sh Pq Sy mount
3321 +Does nothing on
3322 +.Nm systemd
3323 +systems
3324 +.Pq if Pa dracut-zfs-generator No succeeded .
3325 +Otherwise, loads encryption key for the boot dataset from the console or via plymouth.
3326 +It may not work at all!
3327 +.El
3328 +.
3329 +.Sh SEE ALSO
3330 +.Xr dracut.bootup 7 ,
3331 +.Xr zfsprops 7 ,
3332 +.Xr zpoolprops 7 ,
3333 +.Xr dracut-shutdown.service 8 ,
3334 +.Xr systemd-fstab-generator 8 ,
3335 +.Xr systemd-gpt-auto-generator 8 ,
3336 +.Xr zfs-mount-generator 8 ,
3337 +.Xr zgenhostid 8
3338 diff --git a/man/man8/zfs-diff.8 b/man/man8/zfs-diff.8
3339 index 49443bf47..a347f3252 100644
3340 --- a/man/man8/zfs-diff.8
3341 +++ b/man/man8/zfs-diff.8
3342 @@ -39,7 +39,7 @@
3343  .Sh SYNOPSIS
3344  .Nm zfs
3345  .Cm diff
3346 -.Op Fl FHt
3347 +.Op Fl FHth
3348  .Ar snapshot Ar snapshot Ns | Ns Ar filesystem
3349  .
3350  .Sh DESCRIPTION
3351 @@ -92,6 +92,10 @@ Give more parsable tab-separated output, without header lines and without
3352  arrows.
3353  .It Fl t
3354  Display the path's inode change time as the first column of output.
3355 +.It Fl h
3356 +Do not
3357 +.Sy \e0 Ns Ar ooo Ns -escape
3358 +non-ASCII paths.
3359  .El
3360  .
3361  .Sh SEE ALSO
3362 diff --git a/man/man8/zfs-mount-generator.8.in b/man/man8/zfs-mount-generator.8.in
3363 index 7aa332ba8..ae8937038 100644
3364 --- a/man/man8/zfs-mount-generator.8.in
3365 +++ b/man/man8/zfs-mount-generator.8.in
3366 @@ -142,22 +142,11 @@ ZEDLET, if enabled
3367  .Pq see Xr zed 8 .
3368  .
3369  .Sh ENVIRONMENT
3370 -The
3371 +If the
3372  .Sy ZFS_DEBUG
3373 -environment variable can either be
3374 -.Sy 0
3375 -(default),
3376 -.Sy 1
3377 -(print summary accounting information at the end), or at least
3378 -.Sy 2
3379 -(print accounting information for each subprocess as it finishes).
3380 -.
3381 -If not present,
3382 -.Pa /proc/cmdline
3383 -is additionally checked for
3384 -.Qq debug ,
3385 -in which case the debug level is set to
3386 -.Sy 2 .
3387 +environment variable is nonzero
3388 +.Pq or unset and Pa /proc/cmdline No contains Qq Sy debug ,
3389 +print summary accounting information at the end.
3390  .
3391  .Sh EXAMPLES
3392  To begin, enable tracking for the pool:
3393 diff --git a/man/man8/zfs-set.8 b/man/man8/zfs-set.8
3394 index a3588cc26..ccd90f091 100644
3395 --- a/man/man8/zfs-set.8
3396 +++ b/man/man8/zfs-set.8
3397 @@ -170,8 +170,9 @@ inherited.
3398  .It Fl r
3399  Recursively inherit the given property for all children.
3400  .It Fl S
3401 -Revert the property to the received value if one exists; otherwise operate as
3402 -if the
3403 +Revert the property to the received value, if one exists;
3404 +otherwise, for non-inheritable properties, to the default;
3405 +otherwise, operate as if the
3406  .Fl S
3407  option was not specified.
3408  .El
3409 diff --git a/man/man8/zpool-import.8 b/man/man8/zpool-import.8
3410 index 39b0e17ef..5462e4ebd 100644
3411 --- a/man/man8/zpool-import.8
3412 +++ b/man/man8/zpool-import.8
3413 @@ -71,7 +71,8 @@
3414  .Xc
3415  Lists pools available to import.
3416  If the
3417 -.Fl d or
3418 +.Fl d
3419 +or
3420  .Fl c
3421  options are not specified, this command searches for devices using libblkid
3422  on Linux and geom on
3423 diff --git a/module/icp/algs/modes/gcm.c b/module/icp/algs/modes/gcm.c
3424 index 7332834cb..dc8dd929f 100644
3425 --- a/module/icp/algs/modes/gcm.c
3426 +++ b/module/icp/algs/modes/gcm.c
3427 @@ -798,7 +798,7 @@ static gcm_impl_ops_t *gcm_supp_impl[ARRAY_SIZE(gcm_all_impl)];
3428   * fallback to the fastest generic implementation.
3429   */
3430  const gcm_impl_ops_t *
3431 -gcm_impl_get_ops()
3432 +gcm_impl_get_ops(void)
3433  {
3434         if (!kfpu_allowed())
3435                 return (&gcm_generic_impl);
3436 diff --git a/module/os/freebsd/zfs/abd_os.c b/module/os/freebsd/zfs/abd_os.c
3437 index 41ceed1dc..ddd6d68b3 100644
3438 --- a/module/os/freebsd/zfs/abd_os.c
3439 +++ b/module/os/freebsd/zfs/abd_os.c
3440 @@ -113,7 +113,6 @@ static kstat_t *abd_ksp;
3441   * memory by only using a single zero buffer for the scatter chunks.
3442   */
3443  abd_t *abd_zero_scatter = NULL;
3444 -static char *abd_zero_buf = NULL;
3445  
3446  static uint_t
3447  abd_chunkcnt_for_bytes(size_t size)
3448 @@ -241,18 +240,16 @@ abd_free_struct_impl(abd_t *abd)
3449  
3450  /*
3451   * Allocate scatter ABD of size SPA_MAXBLOCKSIZE, where
3452 - * each chunk in the scatterlist will be set to abd_zero_buf.
3453 + * each chunk in the scatterlist will be set to the same area.
3454   */
3455 +_Static_assert(ZERO_REGION_SIZE >= PAGE_SIZE, "zero_region too small");
3456  static void
3457  abd_alloc_zero_scatter(void)
3458  {
3459         uint_t i, n;
3460  
3461         n = abd_chunkcnt_for_bytes(SPA_MAXBLOCKSIZE);
3462 -       abd_zero_buf = kmem_cache_alloc(abd_chunk_cache, KM_PUSHPAGE);
3463 -       bzero(abd_zero_buf, PAGE_SIZE);
3464         abd_zero_scatter = abd_alloc_struct(SPA_MAXBLOCKSIZE);
3465 -
3466         abd_zero_scatter->abd_flags |= ABD_FLAG_OWNER | ABD_FLAG_ZEROS;
3467         abd_zero_scatter->abd_size = SPA_MAXBLOCKSIZE;
3468  
3469 @@ -260,7 +257,7 @@ abd_alloc_zero_scatter(void)
3470  
3471         for (i = 0; i < n; i++) {
3472                 ABD_SCATTER(abd_zero_scatter).abd_chunks[i] =
3473 -                   abd_zero_buf;
3474 +                   __DECONST(void *, zero_region);
3475         }
3476  
3477         ABDSTAT_BUMP(abdstat_scatter_cnt);
3478 @@ -275,7 +272,6 @@ abd_free_zero_scatter(void)
3479  
3480         abd_free_struct(abd_zero_scatter);
3481         abd_zero_scatter = NULL;
3482 -       kmem_cache_free(abd_chunk_cache, abd_zero_buf);
3483  }
3484  
3485  static int
3486 diff --git a/module/os/freebsd/zfs/spa_os.c b/module/os/freebsd/zfs/spa_os.c
3487 index 070e7a5b9..d5f851a30 100644
3488 --- a/module/os/freebsd/zfs/spa_os.c
3489 +++ b/module/os/freebsd/zfs/spa_os.c
3490 @@ -183,7 +183,6 @@ spa_import_rootpool(const char *name, bool checkpointrewind)
3491         spa_t *spa;
3492         vdev_t *rvd;
3493         nvlist_t *config, *nvtop;
3494 -       uint64_t txg;
3495         char *pname;
3496         int error;
3497  
3498 @@ -196,7 +195,6 @@ spa_import_rootpool(const char *name, bool checkpointrewind)
3499         if (config != NULL) {
3500                 pname = fnvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME);
3501                 VERIFY0(strcmp(name, pname));
3502 -               txg = fnvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_TXG);
3503  
3504                 if ((spa = spa_lookup(pname)) != NULL) {
3505                         /*
3506 diff --git a/module/os/freebsd/zfs/vdev_geom.c b/module/os/freebsd/zfs/vdev_geom.c
3507 index 2ef4811a8..5447eb922 100644
3508 --- a/module/os/freebsd/zfs/vdev_geom.c
3509 +++ b/module/os/freebsd/zfs/vdev_geom.c
3510 @@ -1132,8 +1132,12 @@ vdev_geom_fill_unmap_cb(void *buf, size_t len, void *priv)
3511         vm_offset_t addr = (vm_offset_t)buf;
3512         vm_offset_t end = addr + len;
3513  
3514 -       if (bp->bio_ma_n == 0)
3515 +       if (bp->bio_ma_n == 0) {
3516                 bp->bio_ma_offset = addr & PAGE_MASK;
3517 +               addr &= ~PAGE_MASK;
3518 +       } else {
3519 +               ASSERT0(P2PHASE(addr, PAGE_SIZE));
3520 +       }
3521         do {
3522                 bp->bio_ma[bp->bio_ma_n++] =
3523                     PHYS_TO_VM_PAGE(pmap_kextract(addr));
3524 diff --git a/module/os/freebsd/zfs/zfs_vnops_os.c b/module/os/freebsd/zfs/zfs_vnops_os.c
3525 index b2cc3d063..f6bc9c0c6 100644
3526 --- a/module/os/freebsd/zfs/zfs_vnops_os.c
3527 +++ b/module/os/freebsd/zfs/zfs_vnops_os.c
3528 @@ -97,6 +97,10 @@
3529  
3530  VFS_SMR_DECLARE;
3531  
3532 +#if __FreeBSD_version < 1300103
3533 +#define        NDFREE_PNBUF(ndp)       NDFREE((ndp), NDF_ONLY_PNBUF)
3534 +#endif
3535 +
3536  #if __FreeBSD_version >= 1300047
3537  #define        vm_page_wire_lock(pp)
3538  #define        vm_page_wire_unlock(pp)
3539 @@ -4058,8 +4062,8 @@ zfs_getpages(struct vnode *vp, vm_page_t *ma, int count, int *rbehind,
3540         int pgsin_b, pgsin_a;
3541         int error;
3542  
3543 -       ZFS_ENTER(zfsvfs);
3544 -       ZFS_VERIFY_ZP(zp);
3545 +       ZFS_ENTER_ERROR(zfsvfs, zfs_vm_pagerret_error);
3546 +       ZFS_VERIFY_ZP_ERROR(zp, zfs_vm_pagerret_error);
3547  
3548         start = IDX_TO_OFF(ma[0]->pindex);
3549         end = IDX_TO_OFF(ma[count - 1]->pindex + 1);
3550 @@ -4183,19 +4187,18 @@ zfs_putpages(struct vnode *vp, vm_page_t *ma, size_t len, int flags,
3551         int             err;
3552         int             i;
3553  
3554 -       ZFS_ENTER(zfsvfs);
3555 -       ZFS_VERIFY_ZP(zp);
3556 -
3557         object = vp->v_object;
3558 -       pcount = btoc(len);
3559 -       ncount = pcount;
3560 -
3561         KASSERT(ma[0]->object == object, ("mismatching object"));
3562         KASSERT(len > 0 && (len & PAGE_MASK) == 0, ("unexpected length"));
3563  
3564 +       pcount = btoc(len);
3565 +       ncount = pcount;
3566         for (i = 0; i < pcount; i++)
3567                 rtvals[i] = zfs_vm_pagerret_error;
3568  
3569 +       ZFS_ENTER_ERROR(zfsvfs, zfs_vm_pagerret_error);
3570 +       ZFS_VERIFY_ZP_ERROR(zp, zfs_vm_pagerret_error);
3571 +
3572         off = IDX_TO_OFF(ma[0]->pindex);
3573         blksz = zp->z_blksz;
3574         lo_off = rounddown(off, blksz);
3575 @@ -5234,6 +5237,11 @@ zfs_freebsd_pathconf(struct vop_pathconf_args *ap)
3576         case _PC_NAME_MAX:
3577                 *ap->a_retval = NAME_MAX;
3578                 return (0);
3579 +#if __FreeBSD_version >= 1400032
3580 +       case _PC_DEALLOC_PRESENT:
3581 +               *ap->a_retval = 1;
3582 +               return (0);
3583 +#endif
3584         case _PC_PIPE_BUF:
3585                 if (ap->a_vp->v_type == VDIR || ap->a_vp->v_type == VFIFO) {
3586                         *ap->a_retval = PIPE_BUF;
3587 @@ -5357,7 +5365,7 @@ zfs_getextattr_dir(struct vop_getextattr_args *ap, const char *attrname)
3588  #endif
3589         error = vn_open_cred(&nd, &flags, 0, VN_OPEN_INVFS, ap->a_cred, NULL);
3590         vp = nd.ni_vp;
3591 -       NDFREE(&nd, NDF_ONLY_PNBUF);
3592 +       NDFREE_PNBUF(&nd);
3593         if (error != 0)
3594                 return (error);
3595  
3596 @@ -5430,7 +5438,7 @@ zfs_getextattr(struct vop_getextattr_args *ap)
3597  
3598         error = ENOENT;
3599         ZFS_ENTER(zfsvfs);
3600 -       ZFS_VERIFY_ZP(zp)
3601 +       ZFS_VERIFY_ZP(zp);
3602         rw_enter(&zp->z_xattr_lock, RW_READER);
3603         if (zfsvfs->z_use_sa && zp->z_is_sa)
3604                 error = zfs_getextattr_sa(ap, attrname);
3605 @@ -5475,12 +5483,12 @@ zfs_deleteextattr_dir(struct vop_deleteextattr_args *ap, const char *attrname)
3606         error = namei(&nd);
3607         vp = nd.ni_vp;
3608         if (error != 0) {
3609 -               NDFREE(&nd, NDF_ONLY_PNBUF);
3610 +               NDFREE_PNBUF(&nd);
3611                 return (error);
3612         }
3613  
3614         error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd);
3615 -       NDFREE(&nd, NDF_ONLY_PNBUF);
3616 +       NDFREE_PNBUF(&nd);
3617  
3618         vput(nd.ni_dvp);
3619         if (vp == nd.ni_dvp)
3620 @@ -5605,7 +5613,7 @@ zfs_setextattr_dir(struct vop_setextattr_args *ap, const char *attrname)
3621         error = vn_open_cred(&nd, &flags, 0600, VN_OPEN_INVFS, ap->a_cred,
3622             NULL);
3623         vp = nd.ni_vp;
3624 -       NDFREE(&nd, NDF_ONLY_PNBUF);
3625 +       NDFREE_PNBUF(&nd);
3626         if (error != 0)
3627                 return (error);
3628  
3629 @@ -5760,7 +5768,7 @@ zfs_listextattr_dir(struct vop_listextattr_args *ap, const char *attrprefix)
3630  #endif
3631         error = namei(&nd);
3632         vp = nd.ni_vp;
3633 -       NDFREE(&nd, NDF_ONLY_PNBUF);
3634 +       NDFREE_PNBUF(&nd);
3635         if (error != 0)
3636                 return (error);
3637  
3638 @@ -6073,6 +6081,55 @@ zfs_vptocnp(struct vop_vptocnp_args *ap)
3639         return (error);
3640  }
3641  
3642 +#if __FreeBSD_version >= 1400032
3643 +static int
3644 +zfs_deallocate(struct vop_deallocate_args *ap)
3645 +{
3646 +       znode_t *zp = VTOZ(ap->a_vp);
3647 +       zfsvfs_t *zfsvfs = zp->z_zfsvfs;
3648 +       zilog_t *zilog;
3649 +       off_t off, len, file_sz;
3650 +       int error;
3651 +
3652 +       ZFS_ENTER(zfsvfs);
3653 +       ZFS_VERIFY_ZP(zp);
3654 +
3655 +       /*
3656 +        * Callers might not be able to detect properly that we are read-only,
3657 +        * so check it explicitly here.
3658 +        */
3659 +       if (zfs_is_readonly(zfsvfs)) {
3660 +               ZFS_EXIT(zfsvfs);
3661 +               return (SET_ERROR(EROFS));
3662 +       }
3663 +
3664 +       zilog = zfsvfs->z_log;
3665 +       off = *ap->a_offset;
3666 +       len = *ap->a_len;
3667 +       file_sz = zp->z_size;
3668 +       if (off + len > file_sz)
3669 +               len = file_sz - off;
3670 +       /* Fast path for out-of-range request. */
3671 +       if (len <= 0) {
3672 +               *ap->a_len = 0;
3673 +               ZFS_EXIT(zfsvfs);
3674 +               return (0);
3675 +       }
3676 +
3677 +       error = zfs_freesp(zp, off, len, O_RDWR, TRUE);
3678 +       if (error == 0) {
3679 +               if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS ||
3680 +                   (ap->a_ioflag & IO_SYNC) != 0)
3681 +                       zil_commit(zilog, zp->z_id);
3682 +               *ap->a_offset = off + len;
3683 +               *ap->a_len = 0;
3684 +       }
3685 +
3686 +       ZFS_EXIT(zfsvfs);
3687 +       return (error);
3688 +}
3689 +#endif
3690 +
3691  struct vop_vector zfs_vnodeops;
3692  struct vop_vector zfs_fifoops;
3693  struct vop_vector zfs_shareops;
3694 @@ -6092,6 +6149,9 @@ struct vop_vector zfs_vnodeops = {
3695  #endif
3696         .vop_access =           zfs_freebsd_access,
3697         .vop_allocate =         VOP_EINVAL,
3698 +#if __FreeBSD_version >= 1400032
3699 +       .vop_deallocate =       zfs_deallocate,
3700 +#endif
3701         .vop_lookup =           zfs_cache_lookup,
3702         .vop_cachedlookup =     zfs_freebsd_cachedlookup,
3703         .vop_getattr =          zfs_freebsd_getattr,
3704 diff --git a/module/os/freebsd/zfs/zfs_znode.c b/module/os/freebsd/zfs/zfs_znode.c
3705 index e4a1d2db7..bbc45fda8 100644
3706 --- a/module/os/freebsd/zfs/zfs_znode.c
3707 +++ b/module/os/freebsd/zfs/zfs_znode.c
3708 @@ -575,7 +575,6 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr,
3709         dmu_buf_t       *db;
3710         timestruc_t     now;
3711         uint64_t        gen, obj;
3712 -       int             err;
3713         int             bonuslen;
3714         int             dnodesize;
3715         sa_handle_t     *sa_hdl;
3716 @@ -815,12 +814,11 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr,
3717                 VERIFY0(zfs_aclset_common(*zpp, acl_ids->z_aclp, cr, tx));
3718         }
3719         if (!(flag & IS_ROOT_NODE)) {
3720 -               vnode_t *vp;
3721 -
3722 -               vp = ZTOV(*zpp);
3723 +               vnode_t *vp = ZTOV(*zpp);
3724                 vp->v_vflag |= VV_FORCEINSMQ;
3725 -               err = insmntque(vp, zfsvfs->z_vfs);
3726 +               int err = insmntque(vp, zfsvfs->z_vfs);
3727                 vp->v_vflag &= ~VV_FORCEINSMQ;
3728 +               (void) err;
3729                 KASSERT(err == 0, ("insmntque() failed: error %d", err));
3730         }
3731         kmem_free(sa_attrs, sizeof (sa_bulk_attr_t) * ZPL_END);
3732 @@ -934,11 +932,9 @@ zfs_zget(zfsvfs_t *zfsvfs, uint64_t obj_num, znode_t **zpp)
3733         znode_t         *zp;
3734         vnode_t         *vp;
3735         sa_handle_t     *hdl;
3736 -       struct thread   *td;
3737         int locked;
3738         int err;
3739  
3740 -       td = curthread;
3741         getnewvnode_reserve_();
3742  again:
3743         *zpp = NULL;
3744 @@ -964,7 +960,7 @@ again:
3745  
3746         hdl = dmu_buf_get_user(db);
3747         if (hdl != NULL) {
3748 -               zp  = sa_get_userdata(hdl);
3749 +               zp = sa_get_userdata(hdl);
3750  
3751                 /*
3752                  * Since "SA" does immediate eviction we
3753 @@ -1491,12 +1487,16 @@ zfs_free_range(znode_t *zp, uint64_t off, uint64_t len)
3754         error = dmu_free_long_range(zfsvfs->z_os, zp->z_id, off, len);
3755  
3756         if (error == 0) {
3757 +#if __FreeBSD_version >= 1400032
3758 +               vnode_pager_purge_range(ZTOV(zp), off, off + len);
3759 +#else
3760                 /*
3761 -                * In FreeBSD we cannot free block in the middle of a file,
3762 -                * but only at the end of a file, so this code path should
3763 -                * never happen.
3764 +                * Before __FreeBSD_version 1400032 we cannot free block in the
3765 +                * middle of a file, but only at the end of a file, so this code
3766 +                * path should never happen.
3767                  */
3768                 vnode_pager_setsize(ZTOV(zp), off);
3769 +#endif
3770         }
3771  
3772         zfs_rangelock_exit(lr);
3773 diff --git a/module/os/freebsd/zfs/zvol_os.c b/module/os/freebsd/zfs/zvol_os.c
3774 index 0b347e7f9..09c35b371 100644
3775 --- a/module/os/freebsd/zfs/zvol_os.c
3776 +++ b/module/os/freebsd/zfs/zvol_os.c
3777 @@ -1063,7 +1063,7 @@ zvol_cdev_ioctl(struct cdev *dev, ulong_t cmd, caddr_t data,
3778         zvol_state_t *zv;
3779         zfs_locked_range_t *lr;
3780         off_t offset, length;
3781 -       int i, error;
3782 +       int error;
3783         boolean_t sync;
3784  
3785         zv = dev->si_drv2;
3786 @@ -1072,7 +1072,6 @@ zvol_cdev_ioctl(struct cdev *dev, ulong_t cmd, caddr_t data,
3787         KASSERT(zv->zv_open_count > 0,
3788             ("Device with zero access count in %s", __func__));
3789  
3790 -       i = IOCPARM_LEN(cmd);
3791         switch (cmd) {
3792         case DIOCGSECTORSIZE:
3793                 *(uint32_t *)data = DEV_BSIZE;
3794 diff --git a/module/os/linux/spl/spl-kmem-cache.c b/module/os/linux/spl/spl-kmem-cache.c
3795 index 2151ef008..5a318e0a5 100644
3796 --- a/module/os/linux/spl/spl-kmem-cache.c
3797 +++ b/module/os/linux/spl/spl-kmem-cache.c
3798 @@ -1421,7 +1421,7 @@ EXPORT_SYMBOL(spl_kmem_cache_reap_now);
3799   * it should do no harm.
3800   */
3801  int
3802 -spl_kmem_cache_reap_active()
3803 +spl_kmem_cache_reap_active(void)
3804  {
3805         return (0);
3806  }
3807 diff --git a/module/os/linux/zfs/abd_os.c b/module/os/linux/zfs/abd_os.c
3808 index d1d238a4e..8afa222de 100644
3809 --- a/module/os/linux/zfs/abd_os.c
3810 +++ b/module/os/linux/zfs/abd_os.c
3811 @@ -184,8 +184,11 @@ abd_t *abd_zero_scatter = NULL;
3812  
3813  struct page;
3814  /*
3815 - * abd_zero_page we will be an allocated zero'd PAGESIZE buffer, which is
3816 - * assigned to set each of the pages of abd_zero_scatter.
3817 + * _KERNEL   - Will point to ZERO_PAGE if it is available or it will be
3818 + *             an allocated zero'd PAGESIZE buffer.
3819 + * Userspace - Will be an allocated zero'ed PAGESIZE buffer.
3820 + *
3821 + * abd_zero_page is assigned to each of the pages of abd_zero_scatter.
3822   */
3823  static struct page *abd_zero_page = NULL;
3824  
3825 @@ -465,15 +468,19 @@ abd_alloc_zero_scatter(void)
3826         struct scatterlist *sg = NULL;
3827         struct sg_table table;
3828         gfp_t gfp = __GFP_NOWARN | GFP_NOIO;
3829 -       gfp_t gfp_zero_page = gfp | __GFP_ZERO;
3830         int nr_pages = abd_chunkcnt_for_bytes(SPA_MAXBLOCKSIZE);
3831         int i = 0;
3832  
3833 +#if defined(HAVE_ZERO_PAGE_GPL_ONLY)
3834 +       gfp_t gfp_zero_page = gfp | __GFP_ZERO;
3835         while ((abd_zero_page = __page_cache_alloc(gfp_zero_page)) == NULL) {
3836                 ABDSTAT_BUMP(abdstat_scatter_page_alloc_retry);
3837                 schedule_timeout_interruptible(1);
3838         }
3839         abd_mark_zfs_page(abd_zero_page);
3840 +#else
3841 +       abd_zero_page = ZERO_PAGE(0);
3842 +#endif /* HAVE_ZERO_PAGE_GPL_ONLY */
3843  
3844         while (sg_alloc_table(&table, nr_pages, gfp)) {
3845                 ABDSTAT_BUMP(abdstat_scatter_sg_table_retry);
3846 @@ -612,7 +619,6 @@ abd_alloc_zero_scatter(void)
3847         ABD_SCATTER(abd_zero_scatter).abd_offset = 0;
3848         ABD_SCATTER(abd_zero_scatter).abd_nents = nr_pages;
3849         abd_zero_scatter->abd_size = SPA_MAXBLOCKSIZE;
3850 -       zfs_refcount_create(&abd_zero_scatter->abd_children);
3851         ABD_SCATTER(abd_zero_scatter).abd_sgl = vmem_alloc(nr_pages *
3852             sizeof (struct scatterlist), KM_SLEEP);
3853  
3854 @@ -694,8 +700,10 @@ abd_free_zero_scatter(void)
3855         abd_zero_scatter = NULL;
3856         ASSERT3P(abd_zero_page, !=, NULL);
3857  #if defined(_KERNEL)
3858 +#if defined(HAVE_ZERO_PAGE_GPL_ONLY)
3859         abd_unmark_zfs_page(abd_zero_page);
3860         __free_page(abd_zero_page);
3861 +#endif /* HAVE_ZERO_PAGE_GPL_ONLY */
3862  #else
3863         umem_free(abd_zero_page, PAGESIZE);
3864  #endif /* _KERNEL */
3865 diff --git a/module/os/linux/zfs/vdev_disk.c b/module/os/linux/zfs/vdev_disk.c
3866 index 581a79086..2708535b3 100644
3867 --- a/module/os/linux/zfs/vdev_disk.c
3868 +++ b/module/os/linux/zfs/vdev_disk.c
3869 @@ -467,8 +467,11 @@ vdev_submit_bio_impl(struct bio *bio)
3870   * blkg_tryget() to use rcu_read_lock() instead of rcu_read_lock_sched().
3871   * As a side effect the function was converted to GPL-only.  Define our
3872   * own version when needed which uses rcu_read_lock_sched().
3873 + *
3874 + * The Linux 5.17 kernel split linux/blk-cgroup.h into a private and a public
3875 + * part, moving blkg_tryget into the private one. Define our own version.
3876   */
3877 -#if defined(HAVE_BLKG_TRYGET_GPL_ONLY)
3878 +#if defined(HAVE_BLKG_TRYGET_GPL_ONLY) || !defined(HAVE_BLKG_TRYGET)
3879  static inline bool
3880  vdev_blkg_tryget(struct blkcg_gq *blkg)
3881  {
3882 @@ -493,7 +496,7 @@ vdev_blkg_tryget(struct blkcg_gq *blkg)
3883  
3884         return (rc);
3885  }
3886 -#elif defined(HAVE_BLKG_TRYGET)
3887 +#else
3888  #define        vdev_blkg_tryget(bg)    blkg_tryget(bg)
3889  #endif
3890  #ifdef HAVE_BIO_SET_DEV_MACRO
3891 @@ -563,6 +566,10 @@ vdev_submit_bio(struct bio *bio)
3892         current->bio_list = bio_list;
3893  }
3894  
3895 +#ifdef HAVE_BIO_ALLOC_4ARG
3896 +#define        bio_alloc(gfp_mask, nr_iovecs) bio_alloc(NULL, nr_iovecs, 0, gfp_mask)
3897 +#endif
3898 +
3899  static int
3900  __vdev_disk_physio(struct block_device *bdev, zio_t *zio,
3901      size_t io_size, uint64_t io_offset, int rw, int flags)
3902 diff --git a/module/os/linux/zfs/zfs_sysfs.c b/module/os/linux/zfs/zfs_sysfs.c
3903 index fb7c68987..e73b34a2f 100644
3904 --- a/module/os/linux/zfs/zfs_sysfs.c
3905 +++ b/module/os/linux/zfs/zfs_sysfs.c
3906 @@ -65,16 +65,15 @@
3907  /*
3908   * A zfs_mod_kobj_t represents a zfs kobject under '/sys/module/zfs'
3909   */
3910 -struct zfs_mod_kobj;
3911  typedef struct zfs_mod_kobj zfs_mod_kobj_t;
3912 -
3913  struct zfs_mod_kobj {
3914         struct kobject          zko_kobj;
3915         struct kobj_type        zko_kobj_type;
3916         struct sysfs_ops        zko_sysfs_ops;
3917         size_t                  zko_attr_count;
3918         struct attribute        *zko_attr_list;         /* allocated */
3919 -       struct attribute        **zko_default_attrs;    /* allocated */
3920 +       struct attribute_group  zko_default_group;      /* .attrs allocated */
3921 +       const struct attribute_group    *zko_default_groups[2];
3922         size_t                  zko_child_count;
3923         zfs_mod_kobj_t          *zko_children;          /* allocated */
3924  };
3925 @@ -126,10 +125,10 @@ zfs_kobj_release(struct kobject *kobj)
3926                 zkobj->zko_attr_list = NULL;
3927         }
3928  
3929 -       if (zkobj->zko_default_attrs != NULL) {
3930 -               kmem_free(zkobj->zko_default_attrs,
3931 +       if (zkobj->zko_default_group.attrs != NULL) {
3932 +               kmem_free(zkobj->zko_default_group.attrs,
3933                     DEFAULT_ATTR_SIZE(zkobj->zko_attr_count));
3934 -               zkobj->zko_default_attrs = NULL;
3935 +               zkobj->zko_default_group.attrs = NULL;
3936         }
3937  
3938         if (zkobj->zko_child_count != 0) {
3939 @@ -153,11 +152,12 @@ zfs_kobj_add_attr(zfs_mod_kobj_t *zkobj, int attr_num, const char *attr_name)
3940  {
3941         VERIFY3U(attr_num, <, zkobj->zko_attr_count);
3942         ASSERT(zkobj->zko_attr_list);
3943 -       ASSERT(zkobj->zko_default_attrs);
3944 +       ASSERT(zkobj->zko_default_group.attrs);
3945  
3946         zkobj->zko_attr_list[attr_num].name = attr_name;
3947         zkobj->zko_attr_list[attr_num].mode = 0444;
3948 -       zkobj->zko_default_attrs[attr_num] = &zkobj->zko_attr_list[attr_num];
3949 +       zkobj->zko_default_group.attrs[attr_num] =
3950 +           &zkobj->zko_attr_list[attr_num];
3951         sysfs_attr_init(&zkobj->zko_attr_list[attr_num]);
3952  }
3953  
3954 @@ -175,9 +175,9 @@ zfs_kobj_init(zfs_mod_kobj_t *zkobj, int attr_cnt, int child_cnt,
3955                         return (ENOMEM);
3956         }
3957         /* this will always have at least one slot for NULL termination */
3958 -       zkobj->zko_default_attrs = kmem_zalloc(DEFAULT_ATTR_SIZE(attr_cnt),
3959 -           KM_SLEEP);
3960 -       if (zkobj->zko_default_attrs == NULL) {
3961 +       zkobj->zko_default_group.attrs =
3962 +           kmem_zalloc(DEFAULT_ATTR_SIZE(attr_cnt), KM_SLEEP);
3963 +       if (zkobj->zko_default_group.attrs == NULL) {
3964                 if (zkobj->zko_attr_list != NULL) {
3965                         kmem_free(zkobj->zko_attr_list,
3966                             ATTR_TABLE_SIZE(attr_cnt));
3967 @@ -185,14 +185,19 @@ zfs_kobj_init(zfs_mod_kobj_t *zkobj, int attr_cnt, int child_cnt,
3968                 return (ENOMEM);
3969         }
3970         zkobj->zko_attr_count = attr_cnt;
3971 -       zkobj->zko_kobj_type.default_attrs = zkobj->zko_default_attrs;
3972 +       zkobj->zko_default_groups[0] = &zkobj->zko_default_group;
3973 +#ifdef HAVE_SYSFS_DEFAULT_GROUPS
3974 +       zkobj->zko_kobj_type.default_groups = zkobj->zko_default_groups;
3975 +#else
3976 +       zkobj->zko_kobj_type.default_attrs = zkobj->zko_default_group.attrs;
3977 +#endif
3978  
3979         if (child_cnt > 0) {
3980                 zkobj->zko_children = kmem_zalloc(CHILD_TABLE_SIZE(child_cnt),
3981                     KM_SLEEP);
3982                 if (zkobj->zko_children == NULL) {
3983 -                       if (zkobj->zko_default_attrs != NULL) {
3984 -                               kmem_free(zkobj->zko_default_attrs,
3985 +                       if (zkobj->zko_default_group.attrs != NULL) {
3986 +                               kmem_free(zkobj->zko_default_group.attrs,
3987                                     DEFAULT_ATTR_SIZE(attr_cnt));
3988                         }
3989                         if (zkobj->zko_attr_list != NULL) {
3990 @@ -214,9 +219,9 @@ zfs_kobj_init(zfs_mod_kobj_t *zkobj, int attr_cnt, int child_cnt,
3991  static int
3992  zfs_kobj_add(zfs_mod_kobj_t *zkobj, struct kobject *parent, const char *name)
3993  {
3994 -       /* zko_default_attrs must be NULL terminated */
3995 -       ASSERT(zkobj->zko_default_attrs != NULL);
3996 -       ASSERT(zkobj->zko_default_attrs[zkobj->zko_attr_count] == NULL);
3997 +       /* zko_default_group.attrs must be NULL terminated */
3998 +       ASSERT(zkobj->zko_default_group.attrs != NULL);
3999 +       ASSERT(zkobj->zko_default_group.attrs[zkobj->zko_attr_count] == NULL);
4000  
4001         kobject_init(&zkobj->zko_kobj, &zkobj->zko_kobj_type);
4002         return (kobject_add(&zkobj->zko_kobj, parent, name));
4003 diff --git a/module/os/linux/zfs/zfs_uio.c b/module/os/linux/zfs/zfs_uio.c
4004 index a3d5d5f83..11cd62f5f 100644
4005 --- a/module/os/linux/zfs/zfs_uio.c
4006 +++ b/module/os/linux/zfs/zfs_uio.c
4007 @@ -248,7 +248,7 @@ zfs_uio_prefaultpages(ssize_t n, zfs_uio_t *uio)
4008                         /* touch each page in this segment. */
4009                         p = iov->iov_base + skip;
4010                         while (cnt) {
4011 -                               if (get_user(tmp, (uint8_t *)p))
4012 +                               if (copy_from_user(&tmp, p, 1))
4013                                         return (EFAULT);
4014                                 ulong_t incr = MIN(cnt, PAGESIZE);
4015                                 p += incr;
4016 @@ -256,7 +256,7 @@ zfs_uio_prefaultpages(ssize_t n, zfs_uio_t *uio)
4017                         }
4018                         /* touch the last byte in case it straddles a page. */
4019                         p--;
4020 -                       if (get_user(tmp, (uint8_t *)p))
4021 +                       if (copy_from_user(&tmp, p, 1))
4022                                 return (EFAULT);
4023                 }
4024         }
4025 diff --git a/module/os/linux/zfs/zfs_vnops_os.c b/module/os/linux/zfs/zfs_vnops_os.c
4026 index 2958439ac..796a86c25 100644
4027 --- a/module/os/linux/zfs/zfs_vnops_os.c
4028 +++ b/module/os/linux/zfs/zfs_vnops_os.c
4029 @@ -3594,7 +3594,11 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc)
4030                         dmu_tx_wait(tx);
4031  
4032                 dmu_tx_abort(tx);
4033 +#ifdef HAVE_VFS_FILEMAP_DIRTY_FOLIO
4034 +               filemap_dirty_folio(page_mapping(pp), page_folio(pp));
4035 +#else
4036                 __set_page_dirty_nobuffers(pp);
4037 +#endif
4038                 ClearPageError(pp);
4039                 end_page_writeback(pp);
4040                 zfs_rangelock_exit(lr);
4041 diff --git a/module/os/linux/zfs/zpl_file.c b/module/os/linux/zfs/zpl_file.c
4042 index f1241c443..626e7f79d 100644
4043 --- a/module/os/linux/zfs/zpl_file.c
4044 +++ b/module/os/linux/zfs/zpl_file.c
4045 @@ -33,9 +33,13 @@
4046  #include <sys/zfs_vfsops.h>
4047  #include <sys/zfs_vnops.h>
4048  #include <sys/zfs_project.h>
4049 -#ifdef HAVE_VFS_SET_PAGE_DIRTY_NOBUFFERS
4050 +#if defined(HAVE_VFS_SET_PAGE_DIRTY_NOBUFFERS) || \
4051 +    defined(HAVE_VFS_FILEMAP_DIRTY_FOLIO)
4052  #include <linux/pagemap.h>
4053  #endif
4054 +#ifdef HAVE_VFS_FILEMAP_DIRTY_FOLIO
4055 +#include <linux/writeback.h>
4056 +#endif
4057  
4058  /*
4059   * When using fallocate(2) to preallocate space, inflate the requested
4060 @@ -413,6 +417,8 @@ zpl_aio_write(struct kiocb *kiocb, const struct iovec *iov,
4061         if (ret)
4062                 return (ret);
4063  
4064 +       kiocb->ki_pos = pos;
4065 +
4066         zfs_uio_t uio;
4067         zfs_uio_iovec_init(&uio, iov, nr_segs, kiocb->ki_pos, UIO_USERSPACE,
4068             count, 0);
4069 @@ -647,12 +653,29 @@ zpl_readpage_filler(void *data, struct page *pp)
4070   * paging.  For simplicity, the code relies on read_cache_pages() to
4071   * correctly lock each page for IO and call zpl_readpage().
4072   */
4073 +#ifdef HAVE_VFS_READPAGES
4074  static int
4075  zpl_readpages(struct file *filp, struct address_space *mapping,
4076      struct list_head *pages, unsigned nr_pages)
4077  {
4078         return (read_cache_pages(mapping, pages, zpl_readpage_filler, NULL));
4079  }
4080 +#else
4081 +static void
4082 +zpl_readahead(struct readahead_control *ractl)
4083 +{
4084 +       struct page *page;
4085 +
4086 +       while ((page = readahead_page(ractl)) != NULL) {
4087 +               int ret;
4088 +
4089 +               ret = zpl_readpage_filler(NULL, page);
4090 +               put_page(page);
4091 +               if (ret)
4092 +                       break;
4093 +       }
4094 +}
4095 +#endif
4096  
4097  static int
4098  zpl_putpage(struct page *pp, struct writeback_control *wbc, void *data)
4099 @@ -764,11 +787,13 @@ zpl_fallocate_common(struct inode *ip, int mode, loff_t offset, loff_t len)
4100         if (mode & (test_mode)) {
4101                 flock64_t bf;
4102  
4103 -               if (offset > olen)
4104 -                       goto out_unmark;
4105 +               if (mode & FALLOC_FL_KEEP_SIZE) {
4106 +                       if (offset > olen)
4107 +                               goto out_unmark;
4108  
4109 -               if (offset + len > olen)
4110 -                       len = olen - offset;
4111 +                       if (offset + len > olen)
4112 +                               len = olen - offset;
4113 +               }
4114                 bf.l_type = F_WRLCK;
4115                 bf.l_whence = SEEK_SET;
4116                 bf.l_start = offset;
4117 @@ -1027,7 +1052,11 @@ zpl_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
4118  
4119  
4120  const struct address_space_operations zpl_address_space_operations = {
4121 +#ifdef HAVE_VFS_READPAGES
4122         .readpages      = zpl_readpages,
4123 +#else
4124 +       .readahead      = zpl_readahead,
4125 +#endif
4126         .readpage       = zpl_readpage,
4127         .writepage      = zpl_writepage,
4128         .writepages     = zpl_writepages,
4129 @@ -1035,6 +1064,9 @@ const struct address_space_operations zpl_address_space_operations = {
4130  #ifdef HAVE_VFS_SET_PAGE_DIRTY_NOBUFFERS
4131         .set_page_dirty = __set_page_dirty_nobuffers,
4132  #endif
4133 +#ifdef HAVE_VFS_FILEMAP_DIRTY_FOLIO
4134 +       .dirty_folio    = filemap_dirty_folio,
4135 +#endif
4136  };
4137  
4138  const struct file_operations zpl_file_operations = {
4139 diff --git a/module/os/linux/zfs/zvol_os.c b/module/os/linux/zfs/zvol_os.c
4140 index 7a979eb91..5c509a06a 100644
4141 --- a/module/os/linux/zfs/zvol_os.c
4142 +++ b/module/os/linux/zfs/zvol_os.c
4143 @@ -903,22 +903,17 @@ zvol_alloc(dev_t dev, const char *name)
4144         zso->zvo_disk->major = zvol_major;
4145         zso->zvo_disk->events = DISK_EVENT_MEDIA_CHANGE;
4146  
4147 +       /*
4148 +        * Setting ZFS_VOLMODE_DEV disables partitioning on ZVOL devices.
4149 +        * This is accomplished by limiting the number of minors for the
4150 +        * device to one and explicitly disabling partition scanning.
4151 +        */
4152         if (volmode == ZFS_VOLMODE_DEV) {
4153 -               /*
4154 -                * ZFS_VOLMODE_DEV disable partitioning on ZVOL devices: set
4155 -                * gendisk->minors = 1 as noted in include/linux/genhd.h.
4156 -                * Also disable extended partition numbers (GENHD_FL_EXT_DEVT)
4157 -                * and suppresses partition scanning (GENHD_FL_NO_PART_SCAN)
4158 -                * setting gendisk->flags accordingly.
4159 -                */
4160                 zso->zvo_disk->minors = 1;
4161 -#if defined(GENHD_FL_EXT_DEVT)
4162 -               zso->zvo_disk->flags &= ~GENHD_FL_EXT_DEVT;
4163 -#endif
4164 -#if defined(GENHD_FL_NO_PART_SCAN)
4165 -               zso->zvo_disk->flags |= GENHD_FL_NO_PART_SCAN;
4166 -#endif
4167 +               zso->zvo_disk->flags &= ~ZFS_GENHD_FL_EXT_DEVT;
4168 +               zso->zvo_disk->flags |= ZFS_GENHD_FL_NO_PART;
4169         }
4170 +
4171         zso->zvo_disk->first_minor = (dev & MINORMASK);
4172         zso->zvo_disk->fops = &zvol_ops;
4173         zso->zvo_disk->private_data = zv;
4174 diff --git a/module/zfs/arc.c b/module/zfs/arc.c
4175 index 47b58b6c2..8acb5d5ef 100644
4176 --- a/module/zfs/arc.c
4177 +++ b/module/zfs/arc.c
4178 @@ -3430,7 +3430,6 @@ arc_hdr_realloc_crypt(arc_buf_hdr_t *hdr, boolean_t need_crypt)
4179         arc_buf_hdr_t *nhdr;
4180         arc_buf_t *buf;
4181         kmem_cache_t *ncache, *ocache;
4182 -       unsigned nsize, osize;
4183  
4184         /*
4185          * This function requires that hdr is in the arc_anon state.
4186 @@ -3447,14 +3446,10 @@ arc_hdr_realloc_crypt(arc_buf_hdr_t *hdr, boolean_t need_crypt)
4187  
4188         if (need_crypt) {
4189                 ncache = hdr_full_crypt_cache;
4190 -               nsize = sizeof (hdr->b_crypt_hdr);
4191                 ocache = hdr_full_cache;
4192 -               osize = HDR_FULL_SIZE;
4193         } else {
4194                 ncache = hdr_full_cache;
4195 -               nsize = HDR_FULL_SIZE;
4196                 ocache = hdr_full_crypt_cache;
4197 -               osize = sizeof (hdr->b_crypt_hdr);
4198         }
4199  
4200         nhdr = kmem_cache_alloc(ncache, KM_PUSHPAGE);
4201 diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c
4202 index d61724be8..247eeddb6 100644
4203 --- a/module/zfs/dbuf.c
4204 +++ b/module/zfs/dbuf.c
4205 @@ -338,18 +338,18 @@ dbuf_find(objset_t *os, uint64_t obj, uint8_t level, uint64_t blkid)
4206         hv = dbuf_hash(os, obj, level, blkid);
4207         idx = hv & h->hash_table_mask;
4208  
4209 -       mutex_enter(DBUF_HASH_MUTEX(h, idx));
4210 +       rw_enter(DBUF_HASH_RWLOCK(h, idx), RW_READER);
4211         for (db = h->hash_table[idx]; db != NULL; db = db->db_hash_next) {
4212                 if (DBUF_EQUAL(db, os, obj, level, blkid)) {
4213                         mutex_enter(&db->db_mtx);
4214                         if (db->db_state != DB_EVICTING) {
4215 -                               mutex_exit(DBUF_HASH_MUTEX(h, idx));
4216 +                               rw_exit(DBUF_HASH_RWLOCK(h, idx));
4217                                 return (db);
4218                         }
4219                         mutex_exit(&db->db_mtx);
4220                 }
4221         }
4222 -       mutex_exit(DBUF_HASH_MUTEX(h, idx));
4223 +       rw_exit(DBUF_HASH_RWLOCK(h, idx));
4224         return (NULL);
4225  }
4226  
4227 @@ -392,13 +392,13 @@ dbuf_hash_insert(dmu_buf_impl_t *db)
4228         hv = dbuf_hash(os, obj, level, blkid);
4229         idx = hv & h->hash_table_mask;
4230  
4231 -       mutex_enter(DBUF_HASH_MUTEX(h, idx));
4232 +       rw_enter(DBUF_HASH_RWLOCK(h, idx), RW_WRITER);
4233         for (dbf = h->hash_table[idx], i = 0; dbf != NULL;
4234             dbf = dbf->db_hash_next, i++) {
4235                 if (DBUF_EQUAL(dbf, os, obj, level, blkid)) {
4236                         mutex_enter(&dbf->db_mtx);
4237                         if (dbf->db_state != DB_EVICTING) {
4238 -                               mutex_exit(DBUF_HASH_MUTEX(h, idx));
4239 +                               rw_exit(DBUF_HASH_RWLOCK(h, idx));
4240                                 return (dbf);
4241                         }
4242                         mutex_exit(&dbf->db_mtx);
4243 @@ -416,7 +416,7 @@ dbuf_hash_insert(dmu_buf_impl_t *db)
4244         mutex_enter(&db->db_mtx);
4245         db->db_hash_next = h->hash_table[idx];
4246         h->hash_table[idx] = db;
4247 -       mutex_exit(DBUF_HASH_MUTEX(h, idx));
4248 +       rw_exit(DBUF_HASH_RWLOCK(h, idx));
4249         uint64_t he = atomic_inc_64_nv(&dbuf_stats.hash_elements.value.ui64);
4250         DBUF_STAT_MAX(hash_elements_max, he);
4251  
4252 @@ -473,13 +473,13 @@ dbuf_hash_remove(dmu_buf_impl_t *db)
4253  
4254         /*
4255          * We mustn't hold db_mtx to maintain lock ordering:
4256 -        * DBUF_HASH_MUTEX > db_mtx.
4257 +        * DBUF_HASH_RWLOCK > db_mtx.
4258          */
4259         ASSERT(zfs_refcount_is_zero(&db->db_holds));
4260         ASSERT(db->db_state == DB_EVICTING);
4261         ASSERT(!MUTEX_HELD(&db->db_mtx));
4262  
4263 -       mutex_enter(DBUF_HASH_MUTEX(h, idx));
4264 +       rw_enter(DBUF_HASH_RWLOCK(h, idx), RW_WRITER);
4265         dbp = &h->hash_table[idx];
4266         while ((dbf = *dbp) != db) {
4267                 dbp = &dbf->db_hash_next;
4268 @@ -490,7 +490,7 @@ dbuf_hash_remove(dmu_buf_impl_t *db)
4269         if (h->hash_table[idx] &&
4270             h->hash_table[idx]->db_hash_next == NULL)
4271                 DBUF_STAT_BUMPDOWN(hash_chains);
4272 -       mutex_exit(DBUF_HASH_MUTEX(h, idx));
4273 +       rw_exit(DBUF_HASH_RWLOCK(h, idx));
4274         atomic_dec_64(&dbuf_stats.hash_elements.value.ui64);
4275  }
4276  
4277 @@ -851,8 +851,8 @@ retry:
4278             sizeof (dmu_buf_impl_t),
4279             0, dbuf_cons, dbuf_dest, NULL, NULL, NULL, 0);
4280  
4281 -       for (i = 0; i < DBUF_MUTEXES; i++)
4282 -               mutex_init(&h->hash_mutexes[i], NULL, MUTEX_DEFAULT, NULL);
4283 +       for (i = 0; i < DBUF_RWLOCKS; i++)
4284 +               rw_init(&h->hash_rwlocks[i], NULL, RW_DEFAULT, NULL);
4285  
4286         dbuf_stats_init(h);
4287  
4288 @@ -918,8 +918,8 @@ dbuf_fini(void)
4289  
4290         dbuf_stats_destroy();
4291  
4292 -       for (i = 0; i < DBUF_MUTEXES; i++)
4293 -               mutex_destroy(&h->hash_mutexes[i]);
4294 +       for (i = 0; i < DBUF_RWLOCKS; i++)
4295 +               rw_destroy(&h->hash_rwlocks[i]);
4296  #if defined(_KERNEL)
4297         /*
4298          * Large allocations which do not require contiguous pages
4299 @@ -1465,10 +1465,8 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags,
4300         zbookmark_phys_t zb;
4301         uint32_t aflags = ARC_FLAG_NOWAIT;
4302         int err, zio_flags;
4303 -       boolean_t bonus_read;
4304  
4305         err = zio_flags = 0;
4306 -       bonus_read = B_FALSE;
4307         DB_DNODE_ENTER(db);
4308         dn = DB_DNODE(db);
4309         ASSERT(!zfs_refcount_is_zero(&db->db_holds));
4310 @@ -3886,7 +3884,7 @@ dmu_buf_get_user(dmu_buf_t *db_fake)
4311  }
4312  
4313  void
4314 -dmu_buf_user_evict_wait()
4315 +dmu_buf_user_evict_wait(void)
4316  {
4317         taskq_wait(dbu_evict_taskq);
4318  }
4319 diff --git a/module/zfs/dbuf_stats.c b/module/zfs/dbuf_stats.c
4320 index 12bb568a0..037190a81 100644
4321 --- a/module/zfs/dbuf_stats.c
4322 +++ b/module/zfs/dbuf_stats.c
4323 @@ -137,7 +137,7 @@ dbuf_stats_hash_table_data(char *buf, size_t size, void *data)
4324         if (size)
4325                 buf[0] = 0;
4326  
4327 -       mutex_enter(DBUF_HASH_MUTEX(h, dsh->idx));
4328 +       rw_enter(DBUF_HASH_RWLOCK(h, dsh->idx), RW_READER);
4329         for (db = h->hash_table[dsh->idx]; db != NULL; db = db->db_hash_next) {
4330                 /*
4331                  * Returning ENOMEM will cause the data and header functions
4332 @@ -158,7 +158,7 @@ dbuf_stats_hash_table_data(char *buf, size_t size, void *data)
4333  
4334                 mutex_exit(&db->db_mtx);
4335         }
4336 -       mutex_exit(DBUF_HASH_MUTEX(h, dsh->idx));
4337 +       rw_exit(DBUF_HASH_RWLOCK(h, dsh->idx));
4338  
4339         return (error);
4340  }
4341 diff --git a/module/zfs/dmu.c b/module/zfs/dmu.c
4342 index 0c528f68c..4e7127bd1 100644
4343 --- a/module/zfs/dmu.c
4344 +++ b/module/zfs/dmu.c
4345 @@ -73,9 +73,13 @@ int zfs_nopwrite_enabled = 1;
4346  unsigned long zfs_per_txg_dirty_frees_percent = 5;
4347  
4348  /*
4349 - * Enable/disable forcing txg sync when dirty in dmu_offset_next.
4350 + * Enable/disable forcing txg sync when dirty checking for holes with lseek().
4351 + * By default this is enabled to ensure accurate hole reporting, it can result
4352 + * in a significant performance penalty for lseek(SEEK_HOLE) heavy workloads.
4353 + * Disabling this option will result in holes never being reported in dirty
4354 + * files which is always safe.
4355   */
4356 -int zfs_dmu_offset_next_sync = 0;
4357 +int zfs_dmu_offset_next_sync = 1;
4358  
4359  /*
4360   * Limit the amount we can prefetch with one call to this amount.  This
4361 @@ -2110,8 +2114,8 @@ restart:
4362                  * If the zfs_dmu_offset_next_sync module option is enabled
4363                  * then strict hole reporting has been requested.  Dirty
4364                  * dnodes must be synced to disk to accurately report all
4365 -                * holes.  When disabled (the default) dirty dnodes are
4366 -                * reported to not have any holes which is always safe.
4367 +                * holes.  When disabled dirty dnodes are reported to not
4368 +                * have any holes which is always safe.
4369                  *
4370                  * When called by zfs_holey_common() the zp->z_rangelock
4371                  * is held to prevent zfs_write() and mmap writeback from
4372 diff --git a/module/zfs/metaslab.c b/module/zfs/metaslab.c
4373 index f367bea98..9e216c38d 100644
4374 --- a/module/zfs/metaslab.c
4375 +++ b/module/zfs/metaslab.c
4376 @@ -2659,7 +2659,8 @@ metaslab_init(metaslab_group_t *mg, uint64_t id, uint64_t object,
4377  
4378         /*
4379          * We only open space map objects that already exist. All others
4380 -        * will be opened when we finally allocate an object for it.
4381 +        * will be opened when we finally allocate an object for it. For
4382 +        * readonly pools there is no need to open the space map object.
4383          *
4384          * Note:
4385          * When called from vdev_expand(), we can't call into the DMU as
4386 @@ -2668,7 +2669,8 @@ metaslab_init(metaslab_group_t *mg, uint64_t id, uint64_t object,
4387          * that case, the object parameter is zero though, so we won't
4388          * call into the DMU.
4389          */
4390 -       if (object != 0) {
4391 +       if (object != 0 && !(spa->spa_mode == SPA_MODE_READ &&
4392 +           !spa->spa_read_spacemaps)) {
4393                 error = space_map_open(&ms->ms_sm, mos, object, ms->ms_start,
4394                     ms->ms_size, vd->vdev_ashift);
4395  
4396 diff --git a/module/zfs/refcount.c b/module/zfs/refcount.c
4397 index 354e021d9..35a379dde 100644
4398 --- a/module/zfs/refcount.c
4399 +++ b/module/zfs/refcount.c
4400 @@ -318,6 +318,14 @@ zfs_refcount_not_held(zfs_refcount_t *rc, const void *holder)
4401         return (B_TRUE);
4402  }
4403  
4404 +EXPORT_SYMBOL(zfs_refcount_create);
4405 +EXPORT_SYMBOL(zfs_refcount_destroy);
4406 +EXPORT_SYMBOL(zfs_refcount_is_zero);
4407 +EXPORT_SYMBOL(zfs_refcount_count);
4408 +EXPORT_SYMBOL(zfs_refcount_add);
4409 +EXPORT_SYMBOL(zfs_refcount_remove);
4410 +EXPORT_SYMBOL(zfs_refcount_held);
4411 +
4412  /* BEGIN CSTYLED */
4413  ZFS_MODULE_PARAM(zfs, ,reference_tracking_enable, INT, ZMOD_RW,
4414         "Track reference holders to refcount_t objects");
4415 diff --git a/module/zfs/spa.c b/module/zfs/spa.c
4416 index 7c49ced99..dfa73483a 100644
4417 --- a/module/zfs/spa.c
4418 +++ b/module/zfs/spa.c
4419 @@ -180,6 +180,12 @@ boolean_t  spa_create_process = B_TRUE;    /* no process ==> no sysdc */
4420   */
4421  boolean_t      spa_load_verify_dryrun = B_FALSE;
4422  
4423 +/*
4424 + * Allow read spacemaps in case of readonly import (spa_mode == SPA_MODE_READ).
4425 + * This is used by zdb for spacemaps verification.
4426 + */
4427 +boolean_t      spa_mode_readable_spacemaps = B_FALSE;
4428 +
4429  /*
4430   * This (illegal) pool name is used when temporarily importing a spa_t in order
4431   * to get the vdev stats associated with the imported devices.
4432 @@ -1241,6 +1247,7 @@ spa_activate(spa_t *spa, spa_mode_t mode)
4433  
4434         spa->spa_state = POOL_STATE_ACTIVE;
4435         spa->spa_mode = mode;
4436 +       spa->spa_read_spacemaps = spa_mode_readable_spacemaps;
4437  
4438         spa->spa_normal_class = metaslab_class_create(spa, zfs_metaslab_ops);
4439         spa->spa_log_class = metaslab_class_create(spa, zfs_metaslab_ops);
4440 diff --git a/module/zfs/vdev.c b/module/zfs/vdev.c
4441 index 57dcfe723..a323b90a2 100644
4442 --- a/module/zfs/vdev.c
4443 +++ b/module/zfs/vdev.c
4444 @@ -3147,6 +3147,12 @@ vdev_dtl_load(vdev_t *vd)
4445         if (vd->vdev_ops->vdev_op_leaf && vd->vdev_dtl_object != 0) {
4446                 ASSERT(vdev_is_concrete(vd));
4447  
4448 +               /*
4449 +                * If the dtl cannot be sync'd there is no need to open it.
4450 +                */
4451 +               if (spa->spa_mode == SPA_MODE_READ && !spa->spa_read_spacemaps)
4452 +                       return (0);
4453 +
4454                 error = space_map_open(&vd->vdev_dtl_sm, mos,
4455                     vd->vdev_dtl_object, 0, -1ULL, 0);
4456                 if (error)
4457 diff --git a/module/zfs/vdev_indirect.c b/module/zfs/vdev_indirect.c
4458 index b541058d9..8762855d4 100644
4459 --- a/module/zfs/vdev_indirect.c
4460 +++ b/module/zfs/vdev_indirect.c
4461 @@ -1423,11 +1423,6 @@ vdev_indirect_repair(zio_t *zio)
4462  {
4463         indirect_vsd_t *iv = zio->io_vsd;
4464  
4465 -       enum zio_flag flags = ZIO_FLAG_IO_REPAIR;
4466 -
4467 -       if (!(zio->io_flags & (ZIO_FLAG_SCRUB | ZIO_FLAG_RESILVER)))
4468 -               flags |= ZIO_FLAG_SELF_HEAL;
4469 -
4470         if (!spa_writeable(zio->io_spa))
4471                 return;
4472  
4473 diff --git a/module/zfs/vdev_removal.c b/module/zfs/vdev_removal.c
4474 index b51d862f6..d7385cdf2 100644
4475 --- a/module/zfs/vdev_removal.c
4476 +++ b/module/zfs/vdev_removal.c
4477 @@ -1517,10 +1517,6 @@ spa_vdev_remove_thread(void *arg)
4478                          * specified by zfs_removal_suspend_progress. We do this
4479                          * solely from the test suite or during debugging.
4480                          */
4481 -                       uint64_t bytes_copied =
4482 -                           spa->spa_removing_phys.sr_copied;
4483 -                       for (int i = 0; i < TXG_SIZE; i++)
4484 -                               bytes_copied += svr->svr_bytes_done[i];
4485                         while (zfs_removal_suspend_progress &&
4486                             !svr->svr_thread_exit)
4487                                 delay(hz);
4488 diff --git a/module/zfs/zfs_fm.c b/module/zfs/zfs_fm.c
4489 index 87f793cb4..a05ff7330 100644
4490 --- a/module/zfs/zfs_fm.c
4491 +++ b/module/zfs/zfs_fm.c
4492 @@ -825,9 +825,6 @@ annotate_ecksum(nvlist_t *ereport, zio_bad_cksum_t *info,
4493         const uint64_t *good;
4494         const uint64_t *bad;
4495  
4496 -       uint64_t allset = 0;
4497 -       uint64_t allcleared = 0;
4498 -
4499         size_t nui64s = size / sizeof (uint64_t);
4500  
4501         size_t inline_size;
4502 @@ -929,9 +926,6 @@ annotate_ecksum(nvlist_t *ereport, zio_bad_cksum_t *info,
4503                         // bits set in good, but not in bad
4504                         cleared = (good[idx] & (~bad[idx]));
4505  
4506 -                       allset |= set;
4507 -                       allcleared |= cleared;
4508 -
4509                         if (!no_inline) {
4510                                 ASSERT3U(offset, <, inline_size);
4511                                 eip->zei_bits_set[offset] = set;
4512 diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c
4513 index 721a7b4b8..59b05b4b0 100644
4514 --- a/module/zfs/zvol.c
4515 +++ b/module/zfs/zvol.c
4516 @@ -1353,13 +1353,12 @@ static void
4517  zvol_rename_minors_impl(const char *oldname, const char *newname)
4518  {
4519         zvol_state_t *zv, *zv_next;
4520 -       int oldnamelen, newnamelen;
4521 +       int oldnamelen;
4522  
4523         if (zvol_inhibit_dev)
4524                 return;
4525  
4526         oldnamelen = strlen(oldname);
4527 -       newnamelen = strlen(newname);
4528  
4529         rw_enter(&zvol_state_lock, RW_READER);
4530  
4531 diff --git a/module/zstd/Makefile.in b/module/zstd/Makefile.in
4532 index 091f7cea3..598409ca1 100644
4533 --- a/module/zstd/Makefile.in
4534 +++ b/module/zstd/Makefile.in
4535 @@ -37,3 +37,9 @@ $(MODULE)-objs += zstd_sparc.o
4536  
4537  all:
4538         mkdir -p lib
4539 +
4540 +gensymbols:
4541 +       @OBJDUMP@ -t lib/zstd.o | awk '$$2 == "g" && !/ zfs_/ {print "#define\t" $$6 " zfs_" $$6}' | sort >> include/zstd_compat_wrapper.h
4542 +
4543 +checksymbols:
4544 +       @OBJDUMP@ -t lib/zstd.o | awk '/file format/ {print}  $$2 == "g" && !/ zfs_/ {++ret; print}  END {exit ret}'
4545 diff --git a/module/zstd/include/zstd_compat_wrapper.h b/module/zstd/include/zstd_compat_wrapper.h
4546 index 339713590..5d20623a7 100644
4547 --- a/module/zstd/include/zstd_compat_wrapper.h
4548 +++ b/module/zstd/include/zstd_compat_wrapper.h
4549 @@ -36,333 +36,273 @@
4550   * This wrapper fixes a problem, in case the ZFS filesystem driver, is compiled
4551   * statically into the kernel.
4552   * This will cause a symbol collision with the older in-kernel zstd library.
4553 - * The following macros will simply rename all local zstd symbols and references
4554   *
4555 - * Note: if the zstd library for zfs is updated to a newer version, this macro
4556 - * list usually needs to be updated.
4557 - * this can be done with some hand crafting of the output of the following
4558 - * script
4559 - * nm zstd.o | awk '{print "#define "$3 " zfs_" $3}' > macrotable
4560 + * On update, truncate this file at the scissor line, rebuild the module,
4561 + * and make gensymbols.
4562   */
4563  
4564  #define        BIT_initDStream zfs_BIT_initDStream
4565  #define        BIT_mask zfs_BIT_mask
4566  #define        BIT_reloadDStream zfs_BIT_reloadDStream
4567 +
4568 +
4569 +/* -- >8 -- */
4570  #define        ERR_getErrorString zfs_ERR_getErrorString
4571 -#define        FSE_NCountWriteBound zfs_FSE_NCountWriteBound
4572 -#define        FSE_buildCTable zfs_FSE_buildCTable
4573  #define        FSE_buildCTable_raw zfs_FSE_buildCTable_raw
4574  #define        FSE_buildCTable_rle zfs_FSE_buildCTable_rle
4575  #define        FSE_buildCTable_wksp zfs_FSE_buildCTable_wksp
4576 -#define        FSE_buildDTable zfs_FSE_buildDTable
4577 +#define        FSE_buildCTable zfs_FSE_buildCTable
4578  #define        FSE_buildDTable_raw zfs_FSE_buildDTable_raw
4579  #define        FSE_buildDTable_rle zfs_FSE_buildDTable_rle
4580 -#define        FSE_compress zfs_FSE_compress
4581 +#define        FSE_buildDTable zfs_FSE_buildDTable
4582  #define        FSE_compress2 zfs_FSE_compress2
4583  #define        FSE_compressBound zfs_FSE_compressBound
4584  #define        FSE_compress_usingCTable zfs_FSE_compress_usingCTable
4585 -#define        FSE_compress_usingCTable_generic zfs_FSE_compress_usingCTable_generic
4586  #define        FSE_compress_wksp zfs_FSE_compress_wksp
4587 +#define        FSE_compress zfs_FSE_compress
4588  #define        FSE_createCTable zfs_FSE_createCTable
4589  #define        FSE_createDTable zfs_FSE_createDTable
4590 -#define        FSE_decompress zfs_FSE_decompress
4591  #define        FSE_decompress_usingDTable zfs_FSE_decompress_usingDTable
4592  #define        FSE_decompress_wksp zfs_FSE_decompress_wksp
4593 +#define        FSE_decompress zfs_FSE_decompress
4594  #define        FSE_freeCTable zfs_FSE_freeCTable
4595  #define        FSE_freeDTable zfs_FSE_freeDTable
4596  #define        FSE_getErrorName zfs_FSE_getErrorName
4597 +#define        FSE_isError zfs_FSE_isError
4598 +#define        FSE_NCountWriteBound zfs_FSE_NCountWriteBound
4599  #define        FSE_normalizeCount zfs_FSE_normalizeCount
4600 -#define        FSE_optimalTableLog zfs_FSE_optimalTableLog
4601  #define        FSE_optimalTableLog_internal zfs_FSE_optimalTableLog_internal
4602 +#define        FSE_optimalTableLog zfs_FSE_optimalTableLog
4603  #define        FSE_readNCount zfs_FSE_readNCount
4604  #define        FSE_versionNumber zfs_FSE_versionNumber
4605  #define        FSE_writeNCount zfs_FSE_writeNCount
4606 -#define        HIST_count zfs_HIST_count
4607 -#define        HIST_countFast zfs_HIST_countFast
4608 +#define        g_debuglevel zfs_g_debuglevel
4609  #define        HIST_countFast_wksp zfs_HIST_countFast_wksp
4610 -#define        HIST_count_parallel_wksp zfs_HIST_count_parallel_wksp
4611 +#define        HIST_countFast zfs_HIST_countFast
4612  #define        HIST_count_simple zfs_HIST_count_simple
4613  #define        HIST_count_wksp zfs_HIST_count_wksp
4614 -#define        HUF_buildCTable zfs_HUF_buildCTable
4615 +#define        HIST_count zfs_HIST_count
4616 +#define        HIST_isError zfs_HIST_isError
4617  #define        HUF_buildCTable_wksp zfs_HUF_buildCTable_wksp
4618 -#define        HUF_compress zfs_HUF_compress
4619 -#define        HUF_compress1X zfs_HUF_compress1X
4620 +#define        HUF_buildCTable zfs_HUF_buildCTable
4621  #define        HUF_compress1X_repeat zfs_HUF_compress1X_repeat
4622  #define        HUF_compress1X_usingCTable zfs_HUF_compress1X_usingCTable
4623  #define        HUF_compress1X_wksp zfs_HUF_compress1X_wksp
4624 +#define        HUF_compress1X zfs_HUF_compress1X
4625  #define        HUF_compress2 zfs_HUF_compress2
4626  #define        HUF_compress4X_repeat zfs_HUF_compress4X_repeat
4627  #define        HUF_compress4X_usingCTable zfs_HUF_compress4X_usingCTable
4628  #define        HUF_compress4X_wksp zfs_HUF_compress4X_wksp
4629  #define        HUF_compressBound zfs_HUF_compressBound
4630 -#define        HUF_compressWeights zfs_HUF_compressWeights
4631 -#define        HUF_decompress zfs_HUF_decompress
4632 -#define        HUF_decompress1X1 zfs_HUF_decompress1X1
4633 -#define        HUF_decompress1X1_DCtx zfs_HUF_decompress1X1_DCtx
4634 -#define        HUF_decompress1X1_DCtx_wksp zfs_HUF_decompress1X1_DCtx_wksp
4635 +#define        HUF_compress zfs_HUF_compress
4636  #define        HUF_decompress1X1_DCtx_wksp_bmi2 zfs_HUF_decompress1X1_DCtx_wksp_bmi2
4637 +#define        HUF_decompress1X1_DCtx_wksp zfs_HUF_decompress1X1_DCtx_wksp
4638 +#define        HUF_decompress1X1_DCtx zfs_HUF_decompress1X1_DCtx
4639  #define        HUF_decompress1X1_usingDTable zfs_HUF_decompress1X1_usingDTable
4640 -#define        HUF_decompress1X2 zfs_HUF_decompress1X2
4641 -#define        HUF_decompress1X2_DCtx zfs_HUF_decompress1X2_DCtx
4642 +#define        HUF_decompress1X1 zfs_HUF_decompress1X1
4643  #define        HUF_decompress1X2_DCtx_wksp zfs_HUF_decompress1X2_DCtx_wksp
4644 +#define        HUF_decompress1X2_DCtx zfs_HUF_decompress1X2_DCtx
4645  #define        HUF_decompress1X2_usingDTable zfs_HUF_decompress1X2_usingDTable
4646 -#define        HUF_decompress1X_DCtx zfs_HUF_decompress1X_DCtx
4647 +#define        HUF_decompress1X2 zfs_HUF_decompress1X2
4648  #define        HUF_decompress1X_DCtx_wksp zfs_HUF_decompress1X_DCtx_wksp
4649 -#define        HUF_decompress1X_usingDTable zfs_HUF_decompress1X_usingDTable
4650 +#define        HUF_decompress1X_DCtx zfs_HUF_decompress1X_DCtx
4651  #define        HUF_decompress1X_usingDTable_bmi2 zfs_HUF_decompress1X_usingDTable_bmi2
4652 -#define        HUF_decompress4X1 zfs_HUF_decompress4X1
4653 -#define        HUF_decompress4X1_DCtx zfs_HUF_decompress4X1_DCtx
4654 +#define        HUF_decompress1X_usingDTable zfs_HUF_decompress1X_usingDTable
4655  #define        HUF_decompress4X1_DCtx_wksp zfs_HUF_decompress4X1_DCtx_wksp
4656 +#define        HUF_decompress4X1_DCtx zfs_HUF_decompress4X1_DCtx
4657  #define        HUF_decompress4X1_usingDTable zfs_HUF_decompress4X1_usingDTable
4658 -#define        HUF_decompress4X2 zfs_HUF_decompress4X2
4659 -#define        HUF_decompress4X2_DCtx zfs_HUF_decompress4X2_DCtx
4660 +#define        HUF_decompress4X1 zfs_HUF_decompress4X1
4661  #define        HUF_decompress4X2_DCtx_wksp zfs_HUF_decompress4X2_DCtx_wksp
4662 +#define        HUF_decompress4X2_DCtx zfs_HUF_decompress4X2_DCtx
4663  #define        HUF_decompress4X2_usingDTable zfs_HUF_decompress4X2_usingDTable
4664 +#define        HUF_decompress4X2 zfs_HUF_decompress4X2
4665  #define        HUF_decompress4X_DCtx zfs_HUF_decompress4X_DCtx
4666 -#define        HUF_decompress4X_hufOnly zfs_HUF_decompress4X_hufOnly
4667 +#define        HUF_decompress4X_hufOnly_wksp_bmi2 zfs_HUF_decompress4X_hufOnly_wksp_bmi2
4668  #define        HUF_decompress4X_hufOnly_wksp zfs_HUF_decompress4X_hufOnly_wksp
4669 -#define        HUF_decompress4X_hufOnly_wksp_bmi2 \
4670 -       zfs_HUF_decompress4X_hufOnly_wksp_bmi2
4671 -#define        HUF_decompress4X_usingDTable zfs_HUF_decompress4X_usingDTable
4672 +#define        HUF_decompress4X_hufOnly zfs_HUF_decompress4X_hufOnly
4673  #define        HUF_decompress4X_usingDTable_bmi2 zfs_HUF_decompress4X_usingDTable_bmi2
4674 +#define        HUF_decompress4X_usingDTable zfs_HUF_decompress4X_usingDTable
4675 +#define        HUF_decompress zfs_HUF_decompress
4676  #define        HUF_estimateCompressedSize zfs_HUF_estimateCompressedSize
4677 -#define        HUF_fillDTableX2Level2 zfs_HUF_fillDTableX2Level2
4678  #define        HUF_getErrorName zfs_HUF_getErrorName
4679  #define        HUF_getNbBits zfs_HUF_getNbBits
4680 +#define        HUF_isError zfs_HUF_isError
4681  #define        HUF_optimalTableLog zfs_HUF_optimalTableLog
4682  #define        HUF_readCTable zfs_HUF_readCTable
4683 -#define        HUF_readDTableX1 zfs_HUF_readDTableX1
4684  #define        HUF_readDTableX1_wksp zfs_HUF_readDTableX1_wksp
4685 -#define        HUF_readDTableX2 zfs_HUF_readDTableX2
4686 +#define        HUF_readDTableX1 zfs_HUF_readDTableX1
4687  #define        HUF_readDTableX2_wksp zfs_HUF_readDTableX2_wksp
4688 +#define        HUF_readDTableX2 zfs_HUF_readDTableX2
4689  #define        HUF_readStats zfs_HUF_readStats
4690  #define        HUF_selectDecoder zfs_HUF_selectDecoder
4691 -#define        HUF_setMaxHeight zfs_HUF_setMaxHeight
4692  #define        HUF_validateCTable zfs_HUF_validateCTable
4693  #define        HUF_writeCTable zfs_HUF_writeCTable
4694 -#define        LL_base zfs_LL_base
4695 -#define        LL_bits zfs_LL_bits
4696 -#define        LL_defaultDTable zfs_LL_defaultDTable
4697 -#define        LL_defaultNorm zfs_LL_defaultNorm
4698 -#define        ML_base zfs_ML_base
4699 -#define        ML_bits zfs_ML_bits
4700 -#define        ML_defaultDTable zfs_ML_defaultDTable
4701 -#define        ML_defaultNorm zfs_ML_defaultNorm
4702 -#define        OF_base zfs_OF_base
4703 -#define        OF_bits zfs_OF_bits
4704 -#define        OF_defaultDTable zfs_OF_defaultDTable
4705 -#define        OF_defaultNorm zfs_OF_defaultNorm
4706  #define        POOL_add zfs_POOL_add
4707 -#define        POOL_create zfs_POOL_create
4708  #define        POOL_create_advanced zfs_POOL_create_advanced
4709 +#define        POOL_create zfs_POOL_create
4710  #define        POOL_free zfs_POOL_free
4711  #define        POOL_resize zfs_POOL_resize
4712  #define        POOL_sizeof zfs_POOL_sizeof
4713  #define        POOL_tryAdd zfs_POOL_tryAdd
4714 +#define        ZSTD_adjustCParams zfs_ZSTD_adjustCParams
4715 +#define        ZSTD_buildCTable zfs_ZSTD_buildCTable
4716 +#define        ZSTD_buildFSETable zfs_ZSTD_buildFSETable
4717 +#define        ZSTD_calloc zfs_ZSTD_calloc
4718 +#define        ZSTD_CCtx_getParameter zfs_ZSTD_CCtx_getParameter
4719 +#define        ZSTD_CCtx_loadDictionary_advanced zfs_ZSTD_CCtx_loadDictionary_advanced
4720 +#define        ZSTD_CCtx_loadDictionary_byReference zfs_ZSTD_CCtx_loadDictionary_byReference
4721 +#define        ZSTD_CCtx_loadDictionary zfs_ZSTD_CCtx_loadDictionary
4722  #define        ZSTD_CCtxParams_getParameter zfs_ZSTD_CCtxParams_getParameter
4723 -#define        ZSTD_CCtxParams_init zfs_ZSTD_CCtxParams_init
4724  #define        ZSTD_CCtxParams_init_advanced zfs_ZSTD_CCtxParams_init_advanced
4725 +#define        ZSTD_CCtxParams_init zfs_ZSTD_CCtxParams_init
4726  #define        ZSTD_CCtxParams_reset zfs_ZSTD_CCtxParams_reset
4727  #define        ZSTD_CCtxParams_setParameter zfs_ZSTD_CCtxParams_setParameter
4728 -#define        ZSTD_CCtx_getParameter zfs_ZSTD_CCtx_getParameter
4729 -#define        ZSTD_CCtx_loadDictionary zfs_ZSTD_CCtx_loadDictionary
4730 -#define        ZSTD_CCtx_loadDictionary_advanced zfs_ZSTD_CCtx_loadDictionary_advanced
4731 -#define        ZSTD_CCtx_loadDictionary_byReference \
4732 -       zfs_ZSTD_CCtx_loadDictionary_byReference
4733  #define        ZSTD_CCtx_refCDict zfs_ZSTD_CCtx_refCDict
4734 -#define        ZSTD_CCtx_refPrefix zfs_ZSTD_CCtx_refPrefix
4735  #define        ZSTD_CCtx_refPrefix_advanced zfs_ZSTD_CCtx_refPrefix_advanced
4736 +#define        ZSTD_CCtx_refPrefix zfs_ZSTD_CCtx_refPrefix
4737  #define        ZSTD_CCtx_reset zfs_ZSTD_CCtx_reset
4738 +#define        ZSTD_CCtx_setParametersUsingCCtxParams zfs_ZSTD_CCtx_setParametersUsingCCtxParams
4739  #define        ZSTD_CCtx_setParameter zfs_ZSTD_CCtx_setParameter
4740 -#define        ZSTD_CCtx_setParametersUsingCCtxParams \
4741 -       zfs_ZSTD_CCtx_setParametersUsingCCtxParams
4742  #define        ZSTD_CCtx_setPledgedSrcSize zfs_ZSTD_CCtx_setPledgedSrcSize
4743 -#define        ZSTD_CStreamInSize zfs_ZSTD_CStreamInSize
4744 -#define        ZSTD_CStreamOutSize zfs_ZSTD_CStreamOutSize
4745 -#define        ZSTD_DCtx_loadDictionary zfs_ZSTD_DCtx_loadDictionary
4746 -#define        ZSTD_DCtx_loadDictionary_advanced zfs_ZSTD_DCtx_loadDictionary_advanced
4747 -#define        ZSTD_DCtx_loadDictionary_byReference \
4748 -       zfs_ZSTD_DCtx_loadDictionary_byReference
4749 -#define        ZSTD_DCtx_refDDict zfs_ZSTD_DCtx_refDDict
4750 -#define        ZSTD_DCtx_refPrefix zfs_ZSTD_DCtx_refPrefix
4751 -#define        ZSTD_DCtx_refPrefix_advanced zfs_ZSTD_DCtx_refPrefix_advanced
4752 -#define        ZSTD_DCtx_reset zfs_ZSTD_DCtx_reset
4753 -#define        ZSTD_DCtx_setFormat zfs_ZSTD_DCtx_setFormat
4754 -#define        ZSTD_DCtx_setMaxWindowSize zfs_ZSTD_DCtx_setMaxWindowSize
4755 -#define        ZSTD_DCtx_setParameter zfs_ZSTD_DCtx_setParameter
4756 -#define        ZSTD_DDict_dictContent zfs_ZSTD_DDict_dictContent
4757 -#define        ZSTD_DDict_dictSize zfs_ZSTD_DDict_dictSize
4758 -#define        ZSTD_DStreamInSize zfs_ZSTD_DStreamInSize
4759 -#define        ZSTD_DStreamOutSize zfs_ZSTD_DStreamOutSize
4760 -#define        ZSTD_DUBT_findBestMatch zfs_ZSTD_DUBT_findBestMatch
4761 -#define        ZSTD_NCountCost zfs_ZSTD_NCountCost
4762 -#define        ZSTD_XXH64_digest zfs_ZSTD_XXH64_digest
4763 -#define        ZSTD_adjustCParams zfs_ZSTD_adjustCParams
4764 -#define        ZSTD_assignParamsToCCtxParams zfs_ZSTD_assignParamsToCCtxParams
4765 -#define        ZSTD_buildCTable zfs_ZSTD_buildCTable
4766 -#define        ZSTD_buildFSETable zfs_ZSTD_buildFSETable
4767 -#define        ZSTD_buildSeqStore zfs_ZSTD_buildSeqStore
4768 -#define        ZSTD_buildSeqTable zfs_ZSTD_buildSeqTable
4769 -#define        ZSTD_cParam_getBounds zfs_ZSTD_cParam_getBounds
4770 -#define        ZSTD_cParam_withinBounds zfs_ZSTD_cParam_withinBounds
4771 -#define        ZSTD_calloc zfs_ZSTD_calloc
4772 -#define        ZSTD_checkCParams zfs_ZSTD_checkCParams
4773  #define        ZSTD_checkContinuity zfs_ZSTD_checkContinuity
4774 -#define        ZSTD_compress zfs_ZSTD_compress
4775 +#define        ZSTD_checkCParams zfs_ZSTD_checkCParams
4776  #define        ZSTD_compress2 zfs_ZSTD_compress2
4777 -#define        ZSTD_compressBegin zfs_ZSTD_compressBegin
4778 +#define        ZSTD_compress_advanced_internal zfs_ZSTD_compress_advanced_internal
4779 +#define        ZSTD_compress_advanced zfs_ZSTD_compress_advanced
4780 +#define        ZSTD_compressBegin_advanced_internal zfs_ZSTD_compressBegin_advanced_internal
4781  #define        ZSTD_compressBegin_advanced zfs_ZSTD_compressBegin_advanced
4782 -#define        ZSTD_compressBegin_advanced_internal \
4783 -       zfs_ZSTD_compressBegin_advanced_internal
4784 +#define        ZSTD_compressBegin_usingCDict_advanced zfs_ZSTD_compressBegin_usingCDict_advanced
4785  #define        ZSTD_compressBegin_usingCDict zfs_ZSTD_compressBegin_usingCDict
4786 -#define        ZSTD_compressBegin_usingCDict_advanced \
4787 -       zfs_ZSTD_compressBegin_usingCDict_advanced
4788  #define        ZSTD_compressBegin_usingDict zfs_ZSTD_compressBegin_usingDict
4789 -#define        ZSTD_compressBlock zfs_ZSTD_compressBlock
4790 +#define        ZSTD_compressBegin zfs_ZSTD_compressBegin
4791 +#define        ZSTD_compressBlock_btlazy2_dictMatchState zfs_ZSTD_compressBlock_btlazy2_dictMatchState
4792 +#define        ZSTD_compressBlock_btlazy2_extDict zfs_ZSTD_compressBlock_btlazy2_extDict
4793  #define        ZSTD_compressBlock_btlazy2 zfs_ZSTD_compressBlock_btlazy2
4794 -#define        ZSTD_compressBlock_btlazy2_dictMatchState \
4795 -       zfs_ZSTD_compressBlock_btlazy2_dictMatchState
4796 -#define        ZSTD_compressBlock_btlazy2_extDict \
4797 -       zfs_ZSTD_compressBlock_btlazy2_extDict
4798 -#define        ZSTD_compressBlock_btopt zfs_ZSTD_compressBlock_btopt
4799 -#define        ZSTD_compressBlock_btopt_dictMatchState \
4800 -       zfs_ZSTD_compressBlock_btopt_dictMatchState
4801 +#define        ZSTD_compressBlock_btopt_dictMatchState zfs_ZSTD_compressBlock_btopt_dictMatchState
4802  #define        ZSTD_compressBlock_btopt_extDict zfs_ZSTD_compressBlock_btopt_extDict
4803 -#define        ZSTD_compressBlock_btultra zfs_ZSTD_compressBlock_btultra
4804 +#define        ZSTD_compressBlock_btopt zfs_ZSTD_compressBlock_btopt
4805  #define        ZSTD_compressBlock_btultra2 zfs_ZSTD_compressBlock_btultra2
4806 -#define        ZSTD_compressBlock_btultra_dictMatchState \
4807 -       zfs_ZSTD_compressBlock_btultra_dictMatchState
4808 -#define        ZSTD_compressBlock_btultra_extDict \
4809 -       zfs_ZSTD_compressBlock_btultra_extDict
4810 +#define        ZSTD_compressBlock_btultra_dictMatchState zfs_ZSTD_compressBlock_btultra_dictMatchState
4811 +#define        ZSTD_compressBlock_btultra_extDict zfs_ZSTD_compressBlock_btultra_extDict
4812 +#define        ZSTD_compressBlock_btultra zfs_ZSTD_compressBlock_btultra
4813 +#define        ZSTD_compressBlock_doubleFast_dictMatchState zfs_ZSTD_compressBlock_doubleFast_dictMatchState
4814 +#define        ZSTD_compressBlock_doubleFast_extDict zfs_ZSTD_compressBlock_doubleFast_extDict
4815  #define        ZSTD_compressBlock_doubleFast zfs_ZSTD_compressBlock_doubleFast
4816 -#define        ZSTD_compressBlock_doubleFast_dictMatchState \
4817 -       zfs_ZSTD_compressBlock_doubleFast_dictMatchState
4818 -#define        ZSTD_compressBlock_doubleFast_extDict \
4819 -       zfs_ZSTD_compressBlock_doubleFast_extDict
4820 -#define        ZSTD_compressBlock_doubleFast_extDict_generic \
4821 -       zfs_ZSTD_compressBlock_doubleFast_extDict_generic
4822 -#define        ZSTD_compressBlock_fast zfs_ZSTD_compressBlock_fast
4823 -#define        ZSTD_compressBlock_fast_dictMatchState \
4824 -       zfs_ZSTD_compressBlock_fast_dictMatchState
4825 +#define        ZSTD_compressBlock_fast_dictMatchState zfs_ZSTD_compressBlock_fast_dictMatchState
4826  #define        ZSTD_compressBlock_fast_extDict zfs_ZSTD_compressBlock_fast_extDict
4827 -#define        ZSTD_compressBlock_fast_extDict_generic \
4828 -       zfs_ZSTD_compressBlock_fast_extDict_generic
4829 -#define        ZSTD_compressBlock_greedy zfs_ZSTD_compressBlock_greedy
4830 -#define        ZSTD_compressBlock_greedy_dictMatchState \
4831 -       zfs_ZSTD_compressBlock_greedy_dictMatchState
4832 +#define        ZSTD_compressBlock_fast zfs_ZSTD_compressBlock_fast
4833 +#define        ZSTD_compressBlock_greedy_dictMatchState zfs_ZSTD_compressBlock_greedy_dictMatchState
4834  #define        ZSTD_compressBlock_greedy_extDict zfs_ZSTD_compressBlock_greedy_extDict
4835 -#define        ZSTD_compressBlock_internal zfs_ZSTD_compressBlock_internal
4836 -#define        ZSTD_compressBlock_lazy zfs_ZSTD_compressBlock_lazy
4837 -#define        ZSTD_compressBlock_lazy2 zfs_ZSTD_compressBlock_lazy2
4838 -#define        ZSTD_compressBlock_lazy2_dictMatchState \
4839 -       zfs_ZSTD_compressBlock_lazy2_dictMatchState
4840 +#define        ZSTD_compressBlock_greedy zfs_ZSTD_compressBlock_greedy
4841 +#define        ZSTD_compressBlock_lazy2_dictMatchState zfs_ZSTD_compressBlock_lazy2_dictMatchState
4842  #define        ZSTD_compressBlock_lazy2_extDict zfs_ZSTD_compressBlock_lazy2_extDict
4843 -#define        ZSTD_compressBlock_lazy_dictMatchState \
4844 -       zfs_ZSTD_compressBlock_lazy_dictMatchState
4845 +#define        ZSTD_compressBlock_lazy2 zfs_ZSTD_compressBlock_lazy2
4846 +#define        ZSTD_compressBlock_lazy_dictMatchState zfs_ZSTD_compressBlock_lazy_dictMatchState
4847  #define        ZSTD_compressBlock_lazy_extDict zfs_ZSTD_compressBlock_lazy_extDict
4848 +#define        ZSTD_compressBlock_lazy zfs_ZSTD_compressBlock_lazy
4849 +#define        ZSTD_compressBlock zfs_ZSTD_compressBlock
4850  #define        ZSTD_compressBound zfs_ZSTD_compressBound
4851  #define        ZSTD_compressCCtx zfs_ZSTD_compressCCtx
4852  #define        ZSTD_compressContinue zfs_ZSTD_compressContinue
4853 -#define        ZSTD_compressContinue_internal zfs_ZSTD_compressContinue_internal
4854  #define        ZSTD_compressEnd zfs_ZSTD_compressEnd
4855  #define        ZSTD_compressLiterals zfs_ZSTD_compressLiterals
4856  #define        ZSTD_compressRleLiteralsBlock zfs_ZSTD_compressRleLiteralsBlock
4857 -#define        ZSTD_compressStream zfs_ZSTD_compressStream
4858 -#define        ZSTD_compressStream2 zfs_ZSTD_compressStream2
4859  #define        ZSTD_compressStream2_simpleArgs zfs_ZSTD_compressStream2_simpleArgs
4860 +#define        ZSTD_compressStream2 zfs_ZSTD_compressStream2
4861 +#define        ZSTD_compressStream zfs_ZSTD_compressStream
4862  #define        ZSTD_compressSuperBlock zfs_ZSTD_compressSuperBlock
4863 -#define        ZSTD_compress_advanced zfs_ZSTD_compress_advanced
4864 -#define        ZSTD_compress_advanced_internal zfs_ZSTD_compress_advanced_internal
4865 -#define        ZSTD_compress_internal zfs_ZSTD_compress_internal
4866 -#define        ZSTD_compress_usingCDict zfs_ZSTD_compress_usingCDict
4867  #define        ZSTD_compress_usingCDict_advanced zfs_ZSTD_compress_usingCDict_advanced
4868 +#define        ZSTD_compress_usingCDict zfs_ZSTD_compress_usingCDict
4869  #define        ZSTD_compress_usingDict zfs_ZSTD_compress_usingDict
4870 +#define        ZSTD_compress zfs_ZSTD_compress
4871  #define        ZSTD_copyCCtx zfs_ZSTD_copyCCtx
4872  #define        ZSTD_copyDCtx zfs_ZSTD_copyDCtx
4873  #define        ZSTD_copyDDictParameters zfs_ZSTD_copyDDictParameters
4874 -#define        ZSTD_count zfs_ZSTD_count
4875 -#define        ZSTD_count_2segments zfs_ZSTD_count_2segments
4876 -#define        ZSTD_createCCtx zfs_ZSTD_createCCtx
4877 -#define        ZSTD_createCCtxParams zfs_ZSTD_createCCtxParams
4878 +#define        ZSTD_cParam_getBounds zfs_ZSTD_cParam_getBounds
4879  #define        ZSTD_createCCtx_advanced zfs_ZSTD_createCCtx_advanced
4880 -#define        ZSTD_createCDict zfs_ZSTD_createCDict
4881 +#define        ZSTD_createCCtxParams zfs_ZSTD_createCCtxParams
4882 +#define        ZSTD_createCCtx zfs_ZSTD_createCCtx
4883  #define        ZSTD_createCDict_advanced zfs_ZSTD_createCDict_advanced
4884  #define        ZSTD_createCDict_byReference zfs_ZSTD_createCDict_byReference
4885 -#define        ZSTD_createCStream zfs_ZSTD_createCStream
4886 +#define        ZSTD_createCDict zfs_ZSTD_createCDict
4887  #define        ZSTD_createCStream_advanced zfs_ZSTD_createCStream_advanced
4888 -#define        ZSTD_createDCtx zfs_ZSTD_createDCtx
4889 +#define        ZSTD_createCStream zfs_ZSTD_createCStream
4890  #define        ZSTD_createDCtx_advanced zfs_ZSTD_createDCtx_advanced
4891 -#define        ZSTD_createDDict zfs_ZSTD_createDDict
4892 +#define        ZSTD_createDCtx zfs_ZSTD_createDCtx
4893  #define        ZSTD_createDDict_advanced zfs_ZSTD_createDDict_advanced
4894  #define        ZSTD_createDDict_byReference zfs_ZSTD_createDDict_byReference
4895 -#define        ZSTD_createDStream zfs_ZSTD_createDStream
4896 +#define        ZSTD_createDDict zfs_ZSTD_createDDict
4897  #define        ZSTD_createDStream_advanced zfs_ZSTD_createDStream_advanced
4898 +#define        ZSTD_createDStream zfs_ZSTD_createDStream
4899  #define        ZSTD_crossEntropyCost zfs_ZSTD_crossEntropyCost
4900 +#define        ZSTD_CStreamInSize zfs_ZSTD_CStreamInSize
4901 +#define        ZSTD_CStreamOutSize zfs_ZSTD_CStreamOutSize
4902  #define        ZSTD_cycleLog zfs_ZSTD_cycleLog
4903 -#define        ZSTD_dParam_getBounds zfs_ZSTD_dParam_getBounds
4904 +#define        ZSTD_DCtx_loadDictionary_advanced zfs_ZSTD_DCtx_loadDictionary_advanced
4905 +#define        ZSTD_DCtx_loadDictionary_byReference zfs_ZSTD_DCtx_loadDictionary_byReference
4906 +#define        ZSTD_DCtx_loadDictionary zfs_ZSTD_DCtx_loadDictionary
4907 +#define        ZSTD_DCtx_refDDict zfs_ZSTD_DCtx_refDDict
4908 +#define        ZSTD_DCtx_refPrefix_advanced zfs_ZSTD_DCtx_refPrefix_advanced
4909 +#define        ZSTD_DCtx_refPrefix zfs_ZSTD_DCtx_refPrefix
4910 +#define        ZSTD_DCtx_reset zfs_ZSTD_DCtx_reset
4911 +#define        ZSTD_DCtx_setFormat zfs_ZSTD_DCtx_setFormat
4912 +#define        ZSTD_DCtx_setMaxWindowSize zfs_ZSTD_DCtx_setMaxWindowSize
4913 +#define        ZSTD_DCtx_setParameter zfs_ZSTD_DCtx_setParameter
4914 +#define        ZSTD_DDict_dictContent zfs_ZSTD_DDict_dictContent
4915 +#define        ZSTD_DDict_dictSize zfs_ZSTD_DDict_dictSize
4916  #define        ZSTD_decodeLiteralsBlock zfs_ZSTD_decodeLiteralsBlock
4917  #define        ZSTD_decodeSeqHeaders zfs_ZSTD_decodeSeqHeaders
4918  #define        ZSTD_decodingBufferSize_min zfs_ZSTD_decodingBufferSize_min
4919 -#define        ZSTD_decompress zfs_ZSTD_decompress
4920 -#define        ZSTD_decompressBegin zfs_ZSTD_decompressBegin
4921  #define        ZSTD_decompressBegin_usingDDict zfs_ZSTD_decompressBegin_usingDDict
4922  #define        ZSTD_decompressBegin_usingDict zfs_ZSTD_decompressBegin_usingDict
4923 -#define        ZSTD_decompressBlock zfs_ZSTD_decompressBlock
4924 +#define        ZSTD_decompressBegin zfs_ZSTD_decompressBegin
4925  #define        ZSTD_decompressBlock_internal zfs_ZSTD_decompressBlock_internal
4926 +#define        ZSTD_decompressBlock zfs_ZSTD_decompressBlock
4927  #define        ZSTD_decompressBound zfs_ZSTD_decompressBound
4928  #define        ZSTD_decompressContinue zfs_ZSTD_decompressContinue
4929 -#define        ZSTD_decompressContinueStream zfs_ZSTD_decompressContinueStream
4930  #define        ZSTD_decompressDCtx zfs_ZSTD_decompressDCtx
4931 -#define        ZSTD_decompressMultiFrame zfs_ZSTD_decompressMultiFrame
4932 -#define        ZSTD_decompressStream zfs_ZSTD_decompressStream
4933  #define        ZSTD_decompressStream_simpleArgs zfs_ZSTD_decompressStream_simpleArgs
4934 +#define        ZSTD_decompressStream zfs_ZSTD_decompressStream
4935  #define        ZSTD_decompress_usingDDict zfs_ZSTD_decompress_usingDDict
4936  #define        ZSTD_decompress_usingDict zfs_ZSTD_decompress_usingDict
4937 -#define        ZSTD_defaultCParameters zfs_ZSTD_defaultCParameters
4938 -#define        ZSTD_did_fieldSize zfs_ZSTD_did_fieldSize
4939 +#define        ZSTD_decompress zfs_ZSTD_decompress
4940 +#define        ZSTD_dParam_getBounds zfs_ZSTD_dParam_getBounds
4941 +#define        ZSTD_DStreamInSize zfs_ZSTD_DStreamInSize
4942 +#define        ZSTD_DStreamOutSize zfs_ZSTD_DStreamOutSize
4943  #define        ZSTD_encodeSequences zfs_ZSTD_encodeSequences
4944 -#define        ZSTD_encodeSequences_default zfs_ZSTD_encodeSequences_default
4945  #define        ZSTD_endStream zfs_ZSTD_endStream
4946 +#define        ZSTD_estimateCCtxSize_usingCCtxParams zfs_ZSTD_estimateCCtxSize_usingCCtxParams
4947 +#define        ZSTD_estimateCCtxSize_usingCParams zfs_ZSTD_estimateCCtxSize_usingCParams
4948  #define        ZSTD_estimateCCtxSize zfs_ZSTD_estimateCCtxSize
4949 -#define        ZSTD_estimateCCtxSize_usingCCtxParams \
4950 -       zfs_ZSTD_estimateCCtxSize_usingCCtxParams
4951 -#define        ZSTD_estimateCCtxSize_usingCParams \
4952 -       zfs_ZSTD_estimateCCtxSize_usingCParams
4953 -#define        ZSTD_estimateCDictSize zfs_ZSTD_estimateCDictSize
4954  #define        ZSTD_estimateCDictSize_advanced zfs_ZSTD_estimateCDictSize_advanced
4955 +#define        ZSTD_estimateCDictSize zfs_ZSTD_estimateCDictSize
4956 +#define        ZSTD_estimateCStreamSize_usingCCtxParams zfs_ZSTD_estimateCStreamSize_usingCCtxParams
4957 +#define        ZSTD_estimateCStreamSize_usingCParams zfs_ZSTD_estimateCStreamSize_usingCParams
4958  #define        ZSTD_estimateCStreamSize zfs_ZSTD_estimateCStreamSize
4959 -#define        ZSTD_estimateCStreamSize_usingCCtxParams \
4960 -       zfs_ZSTD_estimateCStreamSize_usingCCtxParams
4961 -#define        ZSTD_estimateCStreamSize_usingCParams \
4962 -       zfs_ZSTD_estimateCStreamSize_usingCParams
4963  #define        ZSTD_estimateDCtxSize zfs_ZSTD_estimateDCtxSize
4964  #define        ZSTD_estimateDDictSize zfs_ZSTD_estimateDDictSize
4965 +#define        ZSTD_estimateDStreamSize_fromFrame zfs_ZSTD_estimateDStreamSize_fromFrame
4966  #define        ZSTD_estimateDStreamSize zfs_ZSTD_estimateDStreamSize
4967 -#define        ZSTD_estimateDStreamSize_fromFrame \
4968 -       zfs_ZSTD_estimateDStreamSize_fromFrame
4969 -#define        ZSTD_fcs_fieldSize zfs_ZSTD_fcs_fieldSize
4970  #define        ZSTD_fillDoubleHashTable zfs_ZSTD_fillDoubleHashTable
4971  #define        ZSTD_fillHashTable zfs_ZSTD_fillHashTable
4972  #define        ZSTD_findDecompressedSize zfs_ZSTD_findDecompressedSize
4973  #define        ZSTD_findFrameCompressedSize zfs_ZSTD_findFrameCompressedSize
4974 -#define        ZSTD_findFrameSizeInfo zfs_ZSTD_findFrameSizeInfo
4975  #define        ZSTD_flushStream zfs_ZSTD_flushStream
4976  #define        ZSTD_frameHeaderSize zfs_ZSTD_frameHeaderSize
4977 -#define        ZSTD_free zfs_ZSTD_free
4978 -#define        ZSTD_freeCCtx zfs_ZSTD_freeCCtx
4979  #define        ZSTD_freeCCtxParams zfs_ZSTD_freeCCtxParams
4980 +#define        ZSTD_freeCCtx zfs_ZSTD_freeCCtx
4981  #define        ZSTD_freeCDict zfs_ZSTD_freeCDict
4982  #define        ZSTD_freeCStream zfs_ZSTD_freeCStream
4983  #define        ZSTD_freeDCtx zfs_ZSTD_freeDCtx
4984  #define        ZSTD_freeDDict zfs_ZSTD_freeDDict
4985  #define        ZSTD_freeDStream zfs_ZSTD_freeDStream
4986 +#define        ZSTD_free zfs_ZSTD_free
4987  #define        ZSTD_fseBitCost zfs_ZSTD_fseBitCost
4988  #define        ZSTD_getBlockSize zfs_ZSTD_getBlockSize
4989 -#define        ZSTD_getCParams zfs_ZSTD_getCParams
4990 +#define        ZSTD_getcBlockSize zfs_ZSTD_getcBlockSize
4991  #define        ZSTD_getCParamsFromCCtxParams zfs_ZSTD_getCParamsFromCCtxParams
4992  #define        ZSTD_getCParamsFromCDict zfs_ZSTD_getCParamsFromCDict
4993 -#define        ZSTD_getCParams_internal zfs_ZSTD_getCParams_internal
4994 -#define        ZSTD_getDDict zfs_ZSTD_getDDict
4995 +#define        ZSTD_getCParams zfs_ZSTD_getCParams
4996  #define        ZSTD_getDecompressedSize zfs_ZSTD_getDecompressedSize
4997  #define        ZSTD_getDictID_fromDDict zfs_ZSTD_getDictID_fromDDict
4998  #define        ZSTD_getDictID_fromDict zfs_ZSTD_getDictID_fromDict
4999 @@ -371,39 +311,29 @@
5000  #define        ZSTD_getErrorName zfs_ZSTD_getErrorName
5001  #define        ZSTD_getErrorString zfs_ZSTD_getErrorString
5002  #define        ZSTD_getFrameContentSize zfs_ZSTD_getFrameContentSize
5003 -#define        ZSTD_getFrameHeader zfs_ZSTD_getFrameHeader
5004  #define        ZSTD_getFrameHeader_advanced zfs_ZSTD_getFrameHeader_advanced
5005 +#define        ZSTD_getFrameHeader zfs_ZSTD_getFrameHeader
5006  #define        ZSTD_getFrameProgression zfs_ZSTD_getFrameProgression
5007  #define        ZSTD_getParams zfs_ZSTD_getParams
5008  #define        ZSTD_getSeqStore zfs_ZSTD_getSeqStore
5009  #define        ZSTD_getSequences zfs_ZSTD_getSequences
5010 -#define        ZSTD_getcBlockSize zfs_ZSTD_getcBlockSize
5011 -#define        ZSTD_hashPtr zfs_ZSTD_hashPtr
5012 -#define        ZSTD_initCDict_internal zfs_ZSTD_initCDict_internal
5013 -#define        ZSTD_initCStream zfs_ZSTD_initCStream
5014  #define        ZSTD_initCStream_advanced zfs_ZSTD_initCStream_advanced
5015  #define        ZSTD_initCStream_internal zfs_ZSTD_initCStream_internal
5016  #define        ZSTD_initCStream_srcSize zfs_ZSTD_initCStream_srcSize
5017 +#define        ZSTD_initCStream_usingCDict_advanced zfs_ZSTD_initCStream_usingCDict_advanced
5018  #define        ZSTD_initCStream_usingCDict zfs_ZSTD_initCStream_usingCDict
5019 -#define        ZSTD_initCStream_usingCDict_advanced \
5020 -       zfs_ZSTD_initCStream_usingCDict_advanced
5021  #define        ZSTD_initCStream_usingDict zfs_ZSTD_initCStream_usingDict
5022 -#define        ZSTD_initDDict_internal zfs_ZSTD_initDDict_internal
5023 -#define        ZSTD_initDStream zfs_ZSTD_initDStream
5024 +#define        ZSTD_initCStream zfs_ZSTD_initCStream
5025  #define        ZSTD_initDStream_usingDDict zfs_ZSTD_initDStream_usingDDict
5026  #define        ZSTD_initDStream_usingDict zfs_ZSTD_initDStream_usingDict
5027 -#define        ZSTD_initFseState zfs_ZSTD_initFseState
5028 +#define        ZSTD_initDStream zfs_ZSTD_initDStream
5029  #define        ZSTD_initStaticCCtx zfs_ZSTD_initStaticCCtx
5030  #define        ZSTD_initStaticCDict zfs_ZSTD_initStaticCDict
5031  #define        ZSTD_initStaticCStream zfs_ZSTD_initStaticCStream
5032  #define        ZSTD_initStaticDCtx zfs_ZSTD_initStaticDCtx
5033  #define        ZSTD_initStaticDDict zfs_ZSTD_initStaticDDict
5034  #define        ZSTD_initStaticDStream zfs_ZSTD_initStaticDStream
5035 -#define        ZSTD_initStats_ultra zfs_ZSTD_initStats_ultra
5036  #define        ZSTD_insertAndFindFirstIndex zfs_ZSTD_insertAndFindFirstIndex
5037 -#define        ZSTD_insertAndFindFirstIndexHash3 zfs_ZSTD_insertAndFindFirstIndexHash3
5038 -#define        ZSTD_insertAndFindFirstIndex_internal \
5039 -       zfs_ZSTD_insertAndFindFirstIndex_internal
5040  #define        ZSTD_insertBlock zfs_ZSTD_insertBlock
5041  #define        ZSTD_invalidateRepCodes zfs_ZSTD_invalidateRepCodes
5042  #define        ZSTD_isError zfs_ZSTD_isError
5043 @@ -417,8 +347,6 @@
5044  #define        ZSTD_ldm_skipSequences zfs_ZSTD_ldm_skipSequences
5045  #define        ZSTD_loadCEntropy zfs_ZSTD_loadCEntropy
5046  #define        ZSTD_loadDEntropy zfs_ZSTD_loadDEntropy
5047 -#define        ZSTD_loadDictionaryContent zfs_ZSTD_loadDictionaryContent
5048 -#define        ZSTD_makeCCtxParamsFromCParams zfs_ZSTD_makeCCtxParamsFromCParams
5049  #define        ZSTD_malloc zfs_ZSTD_malloc
5050  #define        ZSTD_maxCLevel zfs_ZSTD_maxCLevel
5051  #define        ZSTD_minCLevel zfs_ZSTD_minCLevel
5052 @@ -426,14 +354,10 @@
5053  #define        ZSTD_nextSrcSizeToDecompress zfs_ZSTD_nextSrcSizeToDecompress
5054  #define        ZSTD_noCompressLiterals zfs_ZSTD_noCompressLiterals
5055  #define        ZSTD_referenceExternalSequences zfs_ZSTD_referenceExternalSequences
5056 -#define        ZSTD_rescaleFreqs zfs_ZSTD_rescaleFreqs
5057 -#define        ZSTD_resetCCtx_internal zfs_ZSTD_resetCCtx_internal
5058 -#define        ZSTD_resetCCtx_usingCDict zfs_ZSTD_resetCCtx_usingCDict
5059 +#define        ZSTD_reset_compressedBlockState zfs_ZSTD_reset_compressedBlockState
5060  #define        ZSTD_resetCStream zfs_ZSTD_resetCStream
5061  #define        ZSTD_resetDStream zfs_ZSTD_resetDStream
5062  #define        ZSTD_resetSeqStore zfs_ZSTD_resetSeqStore
5063 -#define        ZSTD_reset_compressedBlockState zfs_ZSTD_reset_compressedBlockState
5064 -#define        ZSTD_safecopy zfs_ZSTD_safecopy
5065  #define        ZSTD_selectBlockCompressor zfs_ZSTD_selectBlockCompressor
5066  #define        ZSTD_selectEncodingType zfs_ZSTD_selectEncodingType
5067  #define        ZSTD_seqToCodes zfs_ZSTD_seqToCodes
5068 @@ -444,18 +368,7 @@
5069  #define        ZSTD_sizeof_DDict zfs_ZSTD_sizeof_DDict
5070  #define        ZSTD_sizeof_DStream zfs_ZSTD_sizeof_DStream
5071  #define        ZSTD_toFlushNow zfs_ZSTD_toFlushNow
5072 -#define        ZSTD_updateRep zfs_ZSTD_updateRep
5073 -#define        ZSTD_updateStats zfs_ZSTD_updateStats
5074  #define        ZSTD_updateTree zfs_ZSTD_updateTree
5075  #define        ZSTD_versionNumber zfs_ZSTD_versionNumber
5076  #define        ZSTD_versionString zfs_ZSTD_versionString
5077 -#define        ZSTD_writeFrameHeader zfs_ZSTD_writeFrameHeader
5078  #define        ZSTD_writeLastEmptyBlock zfs_ZSTD_writeLastEmptyBlock
5079 -#define        algoTime zfs_algoTime
5080 -#define        attachDictSizeCutoffs zfs_attachDictSizeCutoffs
5081 -#define        g_ctx zfs_g_ctx
5082 -#define        g_debuglevel zfs_g_debuglevel
5083 -#define        kInverseProbabilityLog256 zfs_kInverseProbabilityLog256
5084 -#define        repStartValue zfs_repStartValue
5085 -#define        FSE_isError zfs_FSE_isError
5086 -#define        HUF_isError zfs_HUF_isError
5087 diff --git a/module/zstd/lib/zstd.c b/module/zstd/lib/zstd.c
5088 index 2766e5b74..9dbba5b82 100644
5089 --- a/module/zstd/lib/zstd.c
5090 +++ b/module/zstd/lib/zstd.c
5091 @@ -7781,7 +7781,7 @@ size_t FSE_writeNCount (void* buffer, size_t bufferSize,
5092  
5093  FSE_CTable* FSE_createCTable (unsigned maxSymbolValue, unsigned tableLog)
5094  {
5095 -    size_t size;
5096 +    size_t size __attribute__ ((unused));
5097      if (tableLog > FSE_TABLELOG_ABSOLUTE_MAX) tableLog = FSE_TABLELOG_ABSOLUTE_MAX;
5098      size = FSE_CTABLE_SIZE_U32 (tableLog, maxSymbolValue) * sizeof(U32);
5099      return (FSE_CTable*)malloc(size);
5100 @@ -12115,7 +12115,7 @@ static size_t ZSTD_seqDecompressedSize(seqStore_t const* seqStore, const seqDef*
5101      const seqDef* const send = sequences + nbSeq;
5102      const seqDef* sp = sstart;
5103      size_t matchLengthSum = 0;
5104 -    size_t litLengthSum = 0;
5105 +    size_t litLengthSum __attribute__ ((unused)) = 0;
5106      while (send-sp > 0) {
5107          ZSTD_sequenceLength const seqLen = ZSTD_getSequenceLength(seqStore, sp);
5108          litLengthSum += seqLen.litLength;
5109 diff --git a/scripts/dkms.mkconf b/scripts/dkms.mkconf
5110 index 408322fa1..4090efa08 100755
5111 --- a/scripts/dkms.mkconf
5112 +++ b/scripts/dkms.mkconf
5113 @@ -68,7 +68,6 @@ POST_BUILD="scripts/dkms.postbuild
5114    -t \${dkms_tree}
5115  "
5116  AUTOINSTALL="yes"
5117 -REMAKE_INITRD="no"
5118  MAKE[0]="make"
5119  STRIP[0]="\$(
5120    [[ -r \${PACKAGE_CONFIG} ]] \\
5121 diff --git a/tests/runfiles/common.run b/tests/runfiles/common.run
5122 index aefcd9843..19919a00a 100644
5123 --- a/tests/runfiles/common.run
5124 +++ b/tests/runfiles/common.run
5125 @@ -178,7 +178,7 @@ tags = ['functional', 'cli_root', 'zfs_destroy']
5126  
5127  [tests/functional/cli_root/zfs_diff]
5128  tests = ['zfs_diff_changes', 'zfs_diff_cliargs', 'zfs_diff_timestamp',
5129 -    'zfs_diff_types', 'zfs_diff_encrypted']
5130 +    'zfs_diff_types', 'zfs_diff_encrypted', 'zfs_diff_mangle']
5131  tags = ['functional', 'cli_root', 'zfs_diff']
5132  
5133  [tests/functional/cli_root/zfs_get]
5134 diff --git a/tests/runfiles/linux.run b/tests/runfiles/linux.run
5135 index c01e1e3c4..94c1cbbc3 100644
5136 --- a/tests/runfiles/linux.run
5137 +++ b/tests/runfiles/linux.run
5138 @@ -94,7 +94,7 @@ tests = ['events_001_pos', 'events_002_pos', 'zed_rc_filter', 'zed_fd_spill']
5139  tags = ['functional', 'events']
5140  
5141  [tests/functional/fallocate:Linux]
5142 -tests = ['fallocate_prealloc']
5143 +tests = ['fallocate_prealloc', 'fallocate_zero-range']
5144  tags = ['functional', 'fallocate']
5145  
5146  [tests/functional/fault:Linux]
5147 diff --git a/tests/zfs-tests/cmd/file_write/file_write.c b/tests/zfs-tests/cmd/file_write/file_write.c
5148 index 60893c34f..9d2e71b67 100644
5149 --- a/tests/zfs-tests/cmd/file_write/file_write.c
5150 +++ b/tests/zfs-tests/cmd/file_write/file_write.c
5151 @@ -251,7 +251,7 @@ usage(char *prog)
5152             "\t[-s offset] [-c write_count] [-d data]\n\n"
5153             "Where [data] equal to zero causes chars "
5154             "0->%d to be repeated throughout, or [data]\n"
5155 -           "equal to 'R' for psudorandom data.\n",
5156 +           "equal to 'R' for pseudorandom data.\n",
5157             prog, DATA_RANGE);
5158  
5159         exit(1);
5160 diff --git a/tests/zfs-tests/include/libtest.shlib b/tests/zfs-tests/include/libtest.shlib
5161 index dd43b02a6..94ab7ffd2 100644
5162 --- a/tests/zfs-tests/include/libtest.shlib
5163 +++ b/tests/zfs-tests/include/libtest.shlib
5164 @@ -4236,6 +4236,22 @@ function punch_hole # offset length file
5165         esac
5166  }
5167  
5168 +function zero_range # offset length file
5169 +{
5170 +       typeset offset=$1
5171 +       typeset length=$2
5172 +       typeset file=$3
5173 +
5174 +       case "$UNAME" in
5175 +       Linux)
5176 +               fallocate --zero-range --offset $offset --length $length "$file"
5177 +               ;;
5178 +       *)
5179 +               false
5180 +               ;;
5181 +       esac
5182 +}
5183 +
5184  #
5185  # Wait for the specified arcstat to reach non-zero quiescence.
5186  # If echo is 1 echo the value after reaching quiescence, otherwise
5187 diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_diff/Makefile.am b/tests/zfs-tests/tests/functional/cli_root/zfs_diff/Makefile.am
5188 index db90e0585..bfb01dcb8 100644
5189 --- a/tests/zfs-tests/tests/functional/cli_root/zfs_diff/Makefile.am
5190 +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_diff/Makefile.am
5191 @@ -8,6 +8,7 @@ dist_pkgdata_SCRIPTS = \
5192         zfs_diff_changes.ksh \
5193         zfs_diff_cliargs.ksh \
5194         zfs_diff_encrypted.ksh \
5195 +       zfs_diff_mangle.ksh \
5196         zfs_diff_timestamp.ksh \
5197         zfs_diff_types.ksh
5198  
5199 diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_diff/zfs_diff_cliargs.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_diff/zfs_diff_cliargs.ksh
5200 index 7063bbe9c..67eb18fa4 100755
5201 --- a/tests/zfs-tests/tests/functional/cli_root/zfs_diff/zfs_diff_cliargs.ksh
5202 +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_diff/zfs_diff_cliargs.ksh
5203 @@ -39,8 +39,8 @@ function cleanup
5204  log_assert "'zfs diff' should only work with supported options."
5205  log_onexit cleanup
5206  
5207 -typeset goodopts=("" "-F" "-H" "-t" "-FH" "-Ft" "-Ht" "-FHt")
5208 -typeset badopts=("-f" "-h" "-h" "-T" "-Fx" "-Ho" "-tT" "-")
5209 +typeset goodopts=("" "-h" "-t" "-th" "-H" "-Hh" "-Ht" "-Hth" "-F" "-Fh" "-Ft" "-Fth" "-FH" "-FHh" "-FHt" "-FHth")
5210 +typeset badopts=("-f" "-T" "-Fx" "-Ho" "-tT" "-")
5211  
5212  DATASET="$TESTPOOL/$TESTFS"
5213  TESTSNAP1="$DATASET@snap1"
5214 diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_diff/zfs_diff_mangle.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_diff/zfs_diff_mangle.ksh
5215 new file mode 100755
5216 index 000000000..ffce9f068
5217 --- /dev/null
5218 +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_diff/zfs_diff_mangle.ksh
5219 @@ -0,0 +1,48 @@
5220 +#!/bin/ksh -p
5221 +#
5222 +# This file and its contents are supplied under the terms of the
5223 +# Common Development and Distribution License ("CDDL"), version 1.0.
5224 +# You may only use this file in accordance with the terms of version
5225 +# 1.0 of the CDDL.
5226 +#
5227 +# A full copy of the text of the CDDL should have accompanied this
5228 +# source.  A copy of the CDDL is also available via the Internet at
5229 +# http://www.illumos.org/license/CDDL.
5230 +#
5231 +
5232 +. $STF_SUITE/include/libtest.shlib
5233 +
5234 +#
5235 +# DESCRIPTION:
5236 +# 'zfs diff' escapes filenames as expected, 'zfs diff -h' doesn't
5237 +#
5238 +# STRATEGY:
5239 +# 1. Prepare a dataset
5240 +# 2. Create some files
5241 +# 3. verify 'zfs diff' mangles them and 'zfs diff -h' doesn't
5242 +#
5243 +
5244 +verify_runnable "both"
5245 +
5246 +function cleanup
5247 +{
5248 +       log_must zfs destroy -r "$DATASET"
5249 +}
5250 +
5251 +log_assert "'zfs diff' mangles filenames, 'zfs diff -h' doesn't"
5252 +log_onexit cleanup
5253 +
5254 +DATASET="$TESTPOOL/$TESTFS/fs"
5255 +TESTSNAP1="$DATASET@snap1"
5256 +
5257 +# 1. Prepare a dataset
5258 +log_must zfs create "$DATASET"
5259 +MNTPOINT="$(get_prop mountpoint "$DATASET")"
5260 +log_must zfs snapshot "$TESTSNAP1"
5261 +
5262 +printf '%c\t'"$MNTPOINT/"'%s\n' M '' + 'śmieszny żupan'                       + 'достопримечательности'                                                                                                                                                                                              | sort > "$MNTPOINT/śmieszny żupan"
5263 +printf '%c\t'"$MNTPOINT/"'%s\n' M '' + '\0305\0233mieszny\0040\0305\0274upan' + '\0320\0264\0320\0276\0321\0201\0321\0202\0320\0276\0320\0277\0321\0200\0320\0270\0320\0274\0320\0265\0321\0207\0320\0260\0321\0202\0320\0265\0320\0273\0321\0214\0320\0275\0320\0276\0321\0201\0321\0202\0320\0270' | sort > "$MNTPOINT/достопримечательности"
5264 +log_must diff -u <(zfs diff -h "$TESTSNAP1" | grep -vF '<xattrdir>' | sort) "$MNTPOINT/śmieszny żupan"
5265 +log_must diff -u <(zfs diff    "$TESTSNAP1" | grep -vF '<xattrdir>' | sort) "$MNTPOINT/достопримечательности"
5266 +
5267 +log_pass "'zfs diff' mangles filenames, 'zfs diff -h' doesn't"
5268 diff --git a/tests/zfs-tests/tests/functional/fallocate/Makefile.am b/tests/zfs-tests/tests/functional/fallocate/Makefile.am
5269 index 5ff366d24..86364d789 100644
5270 --- a/tests/zfs-tests/tests/functional/fallocate/Makefile.am
5271 +++ b/tests/zfs-tests/tests/functional/fallocate/Makefile.am
5272 @@ -3,4 +3,5 @@ dist_pkgdata_SCRIPTS = \
5273         setup.ksh \
5274         cleanup.ksh \
5275         fallocate_prealloc.ksh \
5276 -       fallocate_punch-hole.ksh
5277 +       fallocate_punch-hole.ksh \
5278 +       fallocate_zero-range.ksh
5279 diff --git a/tests/zfs-tests/tests/functional/fallocate/fallocate_punch-hole.ksh b/tests/zfs-tests/tests/functional/fallocate/fallocate_punch-hole.ksh
5280 index ed83561bd..92f4552f5 100755
5281 --- a/tests/zfs-tests/tests/functional/fallocate/fallocate_punch-hole.ksh
5282 +++ b/tests/zfs-tests/tests/functional/fallocate/fallocate_punch-hole.ksh
5283 @@ -60,13 +60,17 @@ function cleanup
5284         [[ -e $TESTDIR ]] && log_must rm -f $FILE
5285  }
5286  
5287 -function check_disk_size
5288 +function check_reported_size
5289  {
5290         typeset expected_size=$1
5291  
5292 -       disk_size=$(du $TESTDIR/file | awk '{print $1}')
5293 -       if [ $disk_size -ne $expected_size ]; then
5294 -               log_fail "Incorrect size: $disk_size != $expected_size"
5295 +       if ! [ -e "${FILE}" ]; then
5296 +               log_fail "$FILE does not exist"
5297 +       fi
5298 +               
5299 +       reported_size=$(du "${FILE}" | awk '{print $1}')
5300 +       if [ "$reported_size" != "$expected_size" ]; then
5301 +               log_fail "Incorrect reported size: $reported_size != $expected_size"
5302         fi
5303  }
5304  
5305 @@ -74,9 +78,9 @@ function check_apparent_size
5306  {
5307         typeset expected_size=$1
5308  
5309 -       apparent_size=$(stat_size)
5310 -       if [ $apparent_size -ne $expected_size ]; then
5311 -               log_fail "Incorrect size: $apparent_size != $expected_size"
5312 +       apparent_size=$(stat_size "${FILE}")
5313 +       if [ "$apparent_size" != "$expected_size" ]; then
5314 +               log_fail "Incorrect apparent size: $apparent_size != $expected_size"
5315         fi
5316  }
5317  
5318 @@ -86,25 +90,30 @@ log_onexit cleanup
5319  
5320  # Create a dense file and check it is the correct size.
5321  log_must file_write -o create -f $FILE -b $BLKSZ -c 8
5322 -log_must check_disk_size  $((131072 * 8))
5323 +sync_pool $TESTPOOL
5324 +log_must check_reported_size 1027
5325  
5326  # Punch a hole for the first full block.
5327  log_must punch_hole 0 $BLKSZ $FILE
5328 -log_must check_disk_size  $((131072 * 7))
5329 +sync_pool $TESTPOOL
5330 +log_must check_reported_size 899
5331  
5332  # Partially punch a hole in the second block.
5333  log_must punch_hole $BLKSZ $((BLKSZ / 2)) $FILE
5334 -log_must check_disk_size  $((131072 * 7))
5335 +sync_pool $TESTPOOL
5336 +log_must check_reported_size 899
5337  
5338 -# Punch a hole which overlaps the third and forth block.
5339 +# Punch a hole which overlaps the third and fourth block.
5340  log_must punch_hole $(((BLKSZ * 2) + (BLKSZ / 2))) $((BLKSZ)) $FILE
5341 -log_must check_disk_size  $((131072 * 7))
5342 +sync_pool $TESTPOOL
5343 +log_must check_reported_size 899
5344  
5345  # Punch a hole from the fifth block past the end of file.  The apparent
5346  # file size should not change since --keep-size is implied.
5347  apparent_size=$(stat_size $FILE)
5348  log_must punch_hole $((BLKSZ * 4)) $((BLKSZ * 10)) $FILE
5349 -log_must check_disk_size  $((131072 * 4))
5350 +sync_pool $TESTPOOL
5351 +log_must check_reported_size 387
5352  log_must check_apparent_size $apparent_size
5353  
5354  log_pass "Ensure holes can be punched in files making them sparse"
5355 diff --git a/tests/zfs-tests/tests/functional/fallocate/fallocate_zero-range.ksh b/tests/zfs-tests/tests/functional/fallocate/fallocate_zero-range.ksh
5356 new file mode 100755
5357 index 000000000..e907b0f5d
5358 --- /dev/null
5359 +++ b/tests/zfs-tests/tests/functional/fallocate/fallocate_zero-range.ksh
5360 @@ -0,0 +1,119 @@
5361 +#!/bin/ksh -p
5362 +#
5363 +# CDDL HEADER START
5364 +#
5365 +# The contents of this file are subject to the terms of the
5366 +# Common Development and Distribution License (the "License").
5367 +# You may not use this file except in compliance with the License.
5368 +#
5369 +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
5370 +# or http://www.opensolaris.org/os/licensing.
5371 +# See the License for the specific language governing permissions
5372 +# and limitations under the License.
5373 +#
5374 +# When distributing Covered Code, include this CDDL HEADER in each
5375 +# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
5376 +# If applicable, add the following below this CDDL HEADER, with the
5377 +# fields enclosed by brackets "[]" replaced with your own identifying
5378 +# information: Portions Copyright [yyyy] [name of copyright owner]
5379 +#
5380 +# CDDL HEADER END
5381 +#
5382 +
5383 +#
5384 +# Copyright (c) 2020 by Lawrence Livermore National Security, LLC.
5385 +# Copyright (c) 2021 by The FreeBSD Foundation.
5386 +#
5387 +
5388 +. $STF_SUITE/include/libtest.shlib
5389 +
5390 +#
5391 +# DESCRIPTION:
5392 +# Test FALLOC_FL_ZERO_RANGE functionality
5393 +#
5394 +# STRATEGY:
5395 +# 1. Create a dense file
5396 +# 2. Zero various ranges in the file and verify the result.
5397 +#
5398 +
5399 +verify_runnable "global"
5400 +
5401 +if is_freebsd; then
5402 +       log_unsupported "FreeBSD does not implement an analogue to ZERO_RANGE."
5403 +fi
5404 +
5405 +FILE=$TESTDIR/$TESTFILE0
5406 +BLKSZ=$(get_prop recordsize $TESTPOOL)
5407 +
5408 +function cleanup
5409 +{
5410 +       [[ -e $TESTDIR ]] && log_must rm -f $FILE
5411 +}
5412 +
5413 +# Helpfully, this function expects kilobytes, and check_apparent_size expects bytes.
5414 +function check_reported_size
5415 +{
5416 +       typeset expected_size=$1
5417 +
5418 +       if ! [ -e "${FILE}" ]; then
5419 +               log_fail "$FILE does not exist"
5420 +       fi
5421 +               
5422 +       reported_size=$(du "${FILE}" | awk '{print $1}')
5423 +       if [ "$reported_size" != "$expected_size" ]; then
5424 +               log_fail "Incorrect reported size: $reported_size != $expected_size"
5425 +       fi
5426 +}
5427 +
5428 +function check_apparent_size
5429 +{
5430 +       typeset expected_size=$1
5431 +
5432 +       apparent_size=$(stat_size "${FILE}")
5433 +       if [ "$apparent_size" != "$expected_size" ]; then
5434 +               log_fail "Incorrect apparent size: $apparent_size != $expected_size"
5435 +       fi
5436 +}
5437 +
5438 +log_assert "Ensure ranges can be zeroed in files"
5439 +
5440 +log_onexit cleanup
5441 +
5442 +# Create a dense file and check it is the correct size.
5443 +log_must file_write -o create -f $FILE -b $BLKSZ -c 8
5444 +sync_pool $TESTPOOL
5445 +log_must check_reported_size 1027
5446 +
5447 +# Zero a range covering the first full block.
5448 +log_must zero_range 0 $BLKSZ $FILE
5449 +sync_pool $TESTPOOL
5450 +log_must check_reported_size 899
5451 +
5452 +# Partially zero a range in the second block.
5453 +log_must zero_range $BLKSZ $((BLKSZ / 2)) $FILE
5454 +sync_pool $TESTPOOL
5455 +log_must check_reported_size 899
5456 +
5457 +# Zero range which overlaps the third and fourth block.
5458 +log_must zero_range $(((BLKSZ * 2) + (BLKSZ / 2))) $((BLKSZ)) $FILE
5459 +sync_pool $TESTPOOL
5460 +log_must check_reported_size 899
5461 +
5462 +# Zero range from the fifth block past the end of file, with --keep-size.
5463 +# The apparent file size must not change, since we did specify --keep-size.
5464 +apparent_size=$(stat_size $FILE)
5465 +log_must fallocate --keep-size --zero-range --offset $((BLKSZ * 4)) --length $((BLKSZ * 10)) "$FILE"
5466 +sync_pool $TESTPOOL
5467 +log_must check_reported_size 387
5468 +log_must check_apparent_size $apparent_size
5469 +
5470 +# Zero range from the fifth block past the end of file.  The apparent
5471 +# file size should change since --keep-size is not implied, unlike
5472 +# with PUNCH_HOLE.
5473 +apparent_size=$(stat_size $FILE)
5474 +log_must zero_range $((BLKSZ * 4)) $((BLKSZ * 10)) $FILE
5475 +sync_pool $TESTPOOL
5476 +log_must check_reported_size 387
5477 +log_must check_apparent_size $((BLKSZ * 14))
5478 +
5479 +log_pass "Ensure ranges can be zeroed in files"
5480 diff --git a/tests/zfs-tests/tests/functional/fallocate/setup.ksh b/tests/zfs-tests/tests/functional/fallocate/setup.ksh
5481 index 32334d396..586ac026a 100755
5482 --- a/tests/zfs-tests/tests/functional/fallocate/setup.ksh
5483 +++ b/tests/zfs-tests/tests/functional/fallocate/setup.ksh
5484 @@ -26,4 +26,7 @@
5485  . $STF_SUITE/include/libtest.shlib
5486  
5487  DISK=${DISKS%% *}
5488 -default_setup $DISK
5489 +default_setup_noexit $DISK
5490 +log_must zfs set compression=off $TESTPOOL
5491 +log_pass
5492 +
This page took 0.496582 seconds and 3 git commands to generate.